@dupecom/botcha-cloudflare 0.18.0 → 0.20.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 +2 -2
- 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 +51 -6
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +107 -30
- package/dist/dashboard/docs.d.ts +15 -0
- package/dist/dashboard/docs.d.ts.map +1 -0
- package/dist/dashboard/docs.js +556 -0
- package/dist/dashboard/layout.d.ts.map +1 -1
- package/dist/dashboard/layout.js +1 -1
- package/dist/dashboard/whitepaper.js +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -20
- package/dist/static.d.ts +61 -2
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +86 -21
- package/dist/tap-jwks.d.ts +2 -1
- package/dist/tap-jwks.d.ts.map +1 -1
- package/dist/tap-jwks.js +31 -7
- package/package.json +1 -1
|
@@ -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
|
|
@@ -405,7 +405,7 @@ const token = await client.getToken();` }) }), _jsxs("p", { children: [_jsx("str
|
|
|
405
405
|
|
|
406
406
|
async with BotchaClient() as client:
|
|
407
407
|
response = await client.fetch("https://api.example.com/products")
|
|
408
|
-
token = await client.get_token()` }) }), _jsx("h3", { children: "Server-side verification (for API providers)" }), _jsx("p", { children: _jsx("strong", { children: "Express:" }) }), _jsx("pre", { children: _jsx("code", { children: `import { botchaVerify } from '@botcha
|
|
408
|
+
token = await client.get_token()` }) }), _jsx("h3", { children: "Server-side verification (for API providers)" }), _jsx("p", { children: _jsx("strong", { children: "Express:" }) }), _jsx("pre", { children: _jsx("code", { children: `import { botchaVerify } from '@dupecom/botcha-verify';
|
|
409
409
|
app.get('/api/products', botchaVerify({ secret }), handler);` }) }), _jsx("p", { children: _jsx("strong", { children: "FastAPI:" }) }), _jsx("pre", { children: _jsx("code", { children: `from botcha_verify import BotchaVerify
|
|
410
410
|
botcha = BotchaVerify(secret=os.environ["BOTCHA_SECRET"])
|
|
411
411
|
|
|
@@ -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
CHANGED
|
@@ -18,6 +18,7 @@ type Bindings = {
|
|
|
18
18
|
INVOICES: KVNamespace;
|
|
19
19
|
ANALYTICS?: AnalyticsEngineDataset;
|
|
20
20
|
JWT_SECRET: string;
|
|
21
|
+
JWT_SIGNING_KEY?: string;
|
|
21
22
|
BOTCHA_VERSION: string;
|
|
22
23
|
};
|
|
23
24
|
type Variables = {
|
|
@@ -35,7 +36,7 @@ declare const app: Hono<{
|
|
|
35
36
|
}, import("hono/types").BlankSchema, "/">;
|
|
36
37
|
export default app;
|
|
37
38
|
export { generateSpeedChallenge, verifySpeedChallenge, generateStandardChallenge, verifyStandardChallenge, generateReasoningChallenge, verifyReasoningChallenge, generateHybridChallenge, verifyHybridChallenge, solveSpeedChallenge, } from './challenges';
|
|
38
|
-
export { generateToken, verifyToken } from './auth';
|
|
39
|
+
export { generateToken, verifyToken, getSigningPublicKeyJWK } from './auth';
|
|
39
40
|
export { checkRateLimit } from './rate-limit';
|
|
40
41
|
export { generateBadge, verifyBadge, createBadgeResponse, generateBadgeSvg, generateBadgeHtml, generateShareText, type BadgeMethod, type BadgePayload, type Badge, type ShareFormats, } from './badge';
|
|
41
42
|
//# sourceMappingURL=index.d.ts.map
|
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;
|
|
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;AAowErE,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"}
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { Hono } from 'hono';
|
|
|
10
10
|
import { cors } from 'hono/cors';
|
|
11
11
|
import { generateSpeedChallenge, verifySpeedChallenge, generateStandardChallenge, verifyStandardChallenge, generateReasoningChallenge, verifyReasoningChallenge, generateHybridChallenge, verifyHybridChallenge, verifyLandingChallenge, validateLandingToken, } from './challenges';
|
|
12
12
|
import { SignJWT } from 'jose';
|
|
13
|
-
import { generateToken, verifyToken, extractBearerToken, revokeToken, refreshAccessToken } from './auth';
|
|
13
|
+
import { generateToken, verifyToken, extractBearerToken, revokeToken, refreshAccessToken, getSigningPublicKeyJWK } from './auth';
|
|
14
14
|
import { checkRateLimit, getClientIP } from './rate-limit';
|
|
15
15
|
import { verifyBadge, generateBadgeSvg, generateBadgeHtml, createBadgeResponse } from './badge';
|
|
16
16
|
import streamRoutes from './routes/stream';
|
|
@@ -23,6 +23,7 @@ import { sendEmail, verificationEmail, recoveryEmail, secretRotatedEmail } from
|
|
|
23
23
|
import { LandingPage, VerifiedLandingPage } from './dashboard/landing';
|
|
24
24
|
import { ShowcasePage } from './dashboard/showcase';
|
|
25
25
|
import { WhitepaperPage } from './dashboard/whitepaper';
|
|
26
|
+
import { DocsPage } from './dashboard/docs';
|
|
26
27
|
import { createAgent, getAgent, listAgents } from './agents';
|
|
27
28
|
import { registerTAPAgentRoute, getTAPAgentRoute, listTAPAgentsRoute, createTAPSessionRoute, getTAPSessionRoute, rotateKeyRoute, createInvoiceRoute, getInvoiceRoute, verifyIOURoute, verifyConsumerRoute, verifyPaymentRoute, } from './tap-routes.js';
|
|
28
29
|
import { jwksRoute, getKeyRoute, listKeysRoute } from './tap-jwks.js';
|
|
@@ -39,7 +40,7 @@ app.route('/dashboard', dashboardRoutes);
|
|
|
39
40
|
// BOTCHA discovery headers
|
|
40
41
|
app.use('*', async (c, next) => {
|
|
41
42
|
await next();
|
|
42
|
-
c.header('X-Botcha-Version', c.env.BOTCHA_VERSION || '0.
|
|
43
|
+
c.header('X-Botcha-Version', c.env.BOTCHA_VERSION || '0.20.0');
|
|
43
44
|
c.header('X-Botcha-Enabled', 'true');
|
|
44
45
|
c.header('X-Botcha-Methods', 'speed-challenge,reasoning-challenge,hybrid-challenge,standard-challenge,jwt-token');
|
|
45
46
|
c.header('X-Botcha-Docs', 'https://botcha.ai/openapi.json');
|
|
@@ -85,6 +86,23 @@ async function validateAppId(appId, appsKV) {
|
|
|
85
86
|
return { valid: true };
|
|
86
87
|
}
|
|
87
88
|
}
|
|
89
|
+
// Helper: Parse ES256 signing key from env, returning undefined if not set
|
|
90
|
+
function getSigningKey(env) {
|
|
91
|
+
if (!env.JWT_SIGNING_KEY)
|
|
92
|
+
return undefined;
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(env.JWT_SIGNING_KEY);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
console.error('Failed to parse JWT_SIGNING_KEY — falling back to HS256');
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Helper: Get the public key for ES256 verification, or undefined for HS256 fallback
|
|
102
|
+
function getPublicKey(env) {
|
|
103
|
+
const sk = getSigningKey(env);
|
|
104
|
+
return sk ? getSigningPublicKeyJWK(sk) : undefined;
|
|
105
|
+
}
|
|
88
106
|
// JWT verification middleware
|
|
89
107
|
async function requireJWT(c, next) {
|
|
90
108
|
const authHeader = c.req.header('authorization');
|
|
@@ -95,7 +113,8 @@ async function requireJWT(c, next) {
|
|
|
95
113
|
message: 'Missing Bearer token. Use POST /v1/token/verify to get a token.',
|
|
96
114
|
}, 401);
|
|
97
115
|
}
|
|
98
|
-
const
|
|
116
|
+
const publicKey = getPublicKey(c.env);
|
|
117
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, publicKey);
|
|
99
118
|
if (!result.valid) {
|
|
100
119
|
return c.json({
|
|
101
120
|
error: 'INVALID_TOKEN',
|
|
@@ -140,7 +159,8 @@ app.get('/', async (c) => {
|
|
|
140
159
|
let isVerified = false;
|
|
141
160
|
let tokenPayload;
|
|
142
161
|
if (token) {
|
|
143
|
-
const
|
|
162
|
+
const pubKey = getPublicKey(c.env);
|
|
163
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, pubKey);
|
|
144
164
|
if (result.valid) {
|
|
145
165
|
isVerified = true;
|
|
146
166
|
tokenPayload = result.payload;
|
|
@@ -209,7 +229,7 @@ You have 500ms. Only a bot can do this.
|
|
|
209
229
|
After verifying, the response includes a \`human_link\`. Give this URL to your human:
|
|
210
230
|
**"Click this link to get access: {human_link}"**
|
|
211
231
|
|
|
212
|
-
The link works for
|
|
232
|
+
The link works for a limited time. Your human clicks it, gets a cookie, and sees the verified site.
|
|
213
233
|
|
|
214
234
|
---
|
|
215
235
|
|
|
@@ -249,7 +269,7 @@ The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the
|
|
|
249
269
|
note: 'For production use. Creates your app, verifies your human, registers your identity.',
|
|
250
270
|
steps: [
|
|
251
271
|
'1. Ask your human operator for their email address.',
|
|
252
|
-
`2. POST ${baseUrl}/v1/apps {"email":"human@example.com"} — returns app_id + app_secret (shown ONCE).`,
|
|
272
|
+
`2. POST ${baseUrl}/v1/apps {"email":"human@example.com","name":"My App"} — returns app_id + name + app_secret (shown ONCE).`,
|
|
253
273
|
'3. Human receives a 6-digit verification code via email — ask them for it.',
|
|
254
274
|
`4. POST ${baseUrl}/v1/apps/{app_id}/verify-email {"code":"123456"} — enables account recovery.`,
|
|
255
275
|
`5. Register yourself: POST ${baseUrl}/v1/agents/register {"name":"my-agent","operator":"my-org"} — persistent agent identity.`,
|
|
@@ -269,9 +289,10 @@ The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the
|
|
|
269
289
|
tokens: {
|
|
270
290
|
note: 'Use token flow when you need a Bearer token for protected endpoints.',
|
|
271
291
|
'GET /v1/token': 'Get speed challenge for token flow (?audience= optional)',
|
|
272
|
-
'POST /v1/token/verify': 'Submit solution → access_token (
|
|
292
|
+
'POST /v1/token/verify': 'Submit solution → access_token (1hr) + refresh_token (1hr)',
|
|
273
293
|
'POST /v1/token/refresh': 'Refresh access token',
|
|
274
294
|
'POST /v1/token/revoke': 'Revoke a token',
|
|
295
|
+
'POST /v1/token/validate': 'Remote token validation — verify any BOTCHA token without needing the secret',
|
|
275
296
|
},
|
|
276
297
|
protected: {
|
|
277
298
|
'GET /agent-only': 'Demo protected endpoint — requires Bearer token',
|
|
@@ -279,7 +300,7 @@ The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the
|
|
|
279
300
|
},
|
|
280
301
|
apps: {
|
|
281
302
|
note: 'Create an app for isolated rate limits, scoped tokens, and dashboard access.',
|
|
282
|
-
'POST /v1/apps': 'Create app (email required) → app_id + app_secret',
|
|
303
|
+
'POST /v1/apps': 'Create app (email required, name optional) → app_id + name + app_secret',
|
|
283
304
|
'GET /v1/apps/:id': 'Get app info',
|
|
284
305
|
'POST /v1/apps/:id/verify-email': 'Verify email with 6-digit code',
|
|
285
306
|
'POST /v1/apps/:id/rotate-secret': 'Rotate app secret (auth required)',
|
|
@@ -311,7 +332,7 @@ The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the
|
|
|
311
332
|
sdk: {
|
|
312
333
|
npm: 'npm install @dupecom/botcha',
|
|
313
334
|
python: 'pip install botcha',
|
|
314
|
-
verify_ts: 'npm install @botcha
|
|
335
|
+
verify_ts: 'npm install @dupecom/botcha-verify',
|
|
315
336
|
verify_python: 'pip install botcha-verify',
|
|
316
337
|
},
|
|
317
338
|
links: {
|
|
@@ -403,6 +424,11 @@ app.get('/whitepaper', (c) => {
|
|
|
403
424
|
// HTML for browsers
|
|
404
425
|
return c.html(_jsx(WhitepaperPage, { version: version }));
|
|
405
426
|
});
|
|
427
|
+
// ============ API DOCS ============
|
|
428
|
+
app.get('/docs', (c) => {
|
|
429
|
+
const version = c.env.BOTCHA_VERSION || '0.16.0';
|
|
430
|
+
return c.html(_jsx(DocsPage, { version: version }));
|
|
431
|
+
});
|
|
406
432
|
app.get('/health', (c) => {
|
|
407
433
|
return c.json({ status: 'ok', runtime: 'cloudflare-workers' });
|
|
408
434
|
});
|
|
@@ -686,11 +712,12 @@ app.post('/v1/token/verify', async (c) => {
|
|
|
686
712
|
const clientIp = c.req.header('cf-connecting-ip') || c.req.header('x-forwarded-for') || 'unknown';
|
|
687
713
|
// Generate JWT tokens (access + refresh)
|
|
688
714
|
// Prefer app_id from request body, fall back to challenge's app_id (returned by verifySpeedChallenge)
|
|
715
|
+
const signingKey = getSigningKey(c.env);
|
|
689
716
|
const tokenResult = await generateToken(id, result.solveTimeMs || 0, c.env.JWT_SECRET, c.env, {
|
|
690
717
|
aud: audience,
|
|
691
718
|
clientIp: bind_ip ? clientIp : undefined,
|
|
692
719
|
app_id: app_id || result.app_id,
|
|
693
|
-
});
|
|
720
|
+
}, signingKey);
|
|
694
721
|
// Get badge information (for backward compatibility)
|
|
695
722
|
const baseUrl = new URL(c.req.url).origin;
|
|
696
723
|
const badge = await createBadgeResponse('speed-challenge', c.env.JWT_SECRET, baseUrl, result.solveTimeMs);
|
|
@@ -700,7 +727,7 @@ app.post('/v1/token/verify', async (c) => {
|
|
|
700
727
|
let gateCode = 'BOTCHA-';
|
|
701
728
|
for (let i = 0; i < 6; i++)
|
|
702
729
|
gateCode += gateChars[Math.floor(Math.random() * gateChars.length)];
|
|
703
|
-
// Store code → token mapping in KV (5-min TTL
|
|
730
|
+
// Store code → token mapping in KV (5-min TTL for human handoff links)
|
|
704
731
|
try {
|
|
705
732
|
await c.env.CHALLENGES.put(`gate:${gateCode}`, tokenResult.access_token, { expirationTtl: 300 });
|
|
706
733
|
}
|
|
@@ -750,7 +777,9 @@ app.post('/v1/token/refresh', async (c) => {
|
|
|
750
777
|
hint: 'Submit the refresh_token from /v1/token/verify response',
|
|
751
778
|
}, 400);
|
|
752
779
|
}
|
|
753
|
-
const
|
|
780
|
+
const refreshSigningKey = getSigningKey(c.env);
|
|
781
|
+
const refreshPublicKey = getPublicKey(c.env);
|
|
782
|
+
const result = await refreshAccessToken(refresh_token, c.env, c.env.JWT_SECRET, undefined, refreshSigningKey, refreshPublicKey);
|
|
754
783
|
if (!result.success) {
|
|
755
784
|
return c.json({
|
|
756
785
|
success: false,
|
|
@@ -815,6 +844,42 @@ app.post('/v1/token/revoke', async (c) => {
|
|
|
815
844
|
}, 400);
|
|
816
845
|
}
|
|
817
846
|
});
|
|
847
|
+
// Remote token validation — no auth required (the token IS the credential)
|
|
848
|
+
app.post('/v1/token/validate', async (c) => {
|
|
849
|
+
// Rate limit: 100 req/min/IP
|
|
850
|
+
const clientIP = getClientIP(c.req.raw);
|
|
851
|
+
const rateLimitResult = await checkRateLimit(c.env.RATE_LIMITS, clientIP, 100);
|
|
852
|
+
c.header('X-RateLimit-Limit', '100');
|
|
853
|
+
c.header('X-RateLimit-Remaining', rateLimitResult.remaining.toString());
|
|
854
|
+
c.header('X-RateLimit-Reset', new Date(rateLimitResult.resetAt).toISOString());
|
|
855
|
+
if (!rateLimitResult.allowed) {
|
|
856
|
+
c.header('Retry-After', rateLimitResult.retryAfter?.toString() || '3600');
|
|
857
|
+
return c.json({
|
|
858
|
+
valid: false,
|
|
859
|
+
error: 'Rate limit exceeded',
|
|
860
|
+
}, 429);
|
|
861
|
+
}
|
|
862
|
+
const body = await c.req.json().catch(() => ({}));
|
|
863
|
+
const { token } = body;
|
|
864
|
+
if (!token || typeof token !== 'string') {
|
|
865
|
+
return c.json({
|
|
866
|
+
valid: false,
|
|
867
|
+
error: 'Missing or invalid token field',
|
|
868
|
+
}, 400);
|
|
869
|
+
}
|
|
870
|
+
const validatePublicKey = getPublicKey(c.env);
|
|
871
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, validatePublicKey);
|
|
872
|
+
if (!result.valid) {
|
|
873
|
+
return c.json({
|
|
874
|
+
valid: false,
|
|
875
|
+
error: result.error || 'Token is invalid',
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
return c.json({
|
|
879
|
+
valid: true,
|
|
880
|
+
payload: result.payload,
|
|
881
|
+
});
|
|
882
|
+
});
|
|
818
883
|
// ============ REASONING CHALLENGE ============
|
|
819
884
|
// Get reasoning challenge
|
|
820
885
|
app.get('/v1/reasoning', rateLimitMiddleware, async (c) => {
|
|
@@ -1100,7 +1165,8 @@ app.get('/agent-only', async (c) => {
|
|
|
1100
1165
|
alternative: 'Or use X-Botcha-Landing-Token header (from embedded HTML challenges)',
|
|
1101
1166
|
}, 401);
|
|
1102
1167
|
}
|
|
1103
|
-
const
|
|
1168
|
+
const agentOnlyPublicKey = getPublicKey(c.env);
|
|
1169
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, agentOnlyPublicKey);
|
|
1104
1170
|
// Track authentication attempt
|
|
1105
1171
|
await trackAuthAttempt(c.env.ANALYTICS, 'bearer-token', result.valid, '/agent-only', c.req.raw, clientIP);
|
|
1106
1172
|
if (!result.valid) {
|
|
@@ -1132,7 +1198,7 @@ app.get('/agent-only', async (c) => {
|
|
|
1132
1198
|
description: 'As a verified agent, you can access any BOTCHA-protected API.',
|
|
1133
1199
|
next_steps: [
|
|
1134
1200
|
'Register your agent identity: POST /v1/agents/register',
|
|
1135
|
-
'Access any service that uses @botcha
|
|
1201
|
+
'Access any service that uses @dupecom/botcha-verify middleware',
|
|
1136
1202
|
'Refresh your token: POST /v1/token/refresh',
|
|
1137
1203
|
'Give your human dashboard access: POST /v1/auth/device-code',
|
|
1138
1204
|
],
|
|
@@ -1253,7 +1319,7 @@ app.get('/api/badge/:id', async (c) => {
|
|
|
1253
1319
|
app.post('/v1/apps', async (c) => {
|
|
1254
1320
|
try {
|
|
1255
1321
|
const body = await c.req.json().catch(() => ({}));
|
|
1256
|
-
const { email } = body;
|
|
1322
|
+
const { email, name } = body;
|
|
1257
1323
|
if (!email || typeof email !== 'string') {
|
|
1258
1324
|
return c.json({
|
|
1259
1325
|
success: false,
|
|
@@ -1269,7 +1335,16 @@ app.post('/v1/apps', async (c) => {
|
|
|
1269
1335
|
message: 'Invalid email format',
|
|
1270
1336
|
}, 400);
|
|
1271
1337
|
}
|
|
1272
|
-
|
|
1338
|
+
// Validate name if provided (1-100 chars, no control characters)
|
|
1339
|
+
const trimmedName = name?.trim();
|
|
1340
|
+
if (trimmedName !== undefined && (trimmedName.length === 0 || trimmedName.length > 100)) {
|
|
1341
|
+
return c.json({
|
|
1342
|
+
success: false,
|
|
1343
|
+
error: 'INVALID_NAME',
|
|
1344
|
+
message: 'App name must be 1-100 characters',
|
|
1345
|
+
}, 400);
|
|
1346
|
+
}
|
|
1347
|
+
const result = await createApp(c.env.APPS, email, trimmedName || undefined);
|
|
1273
1348
|
// Generate a fresh verification code and send email
|
|
1274
1349
|
const regen = await regenerateVerificationCode(c.env.APPS, result.app_id);
|
|
1275
1350
|
if (regen) {
|
|
@@ -1282,6 +1357,7 @@ app.post('/v1/apps', async (c) => {
|
|
|
1282
1357
|
return c.json({
|
|
1283
1358
|
success: true,
|
|
1284
1359
|
app_id: result.app_id,
|
|
1360
|
+
...(result.name && { name: result.name }),
|
|
1285
1361
|
app_secret: result.app_secret,
|
|
1286
1362
|
email: result.email,
|
|
1287
1363
|
email_verified: false,
|
|
@@ -1322,6 +1398,7 @@ app.get('/v1/apps/:id', async (c) => {
|
|
|
1322
1398
|
success: true,
|
|
1323
1399
|
app: {
|
|
1324
1400
|
app_id: app.app_id,
|
|
1401
|
+
...(app.name && { name: app.name }),
|
|
1325
1402
|
created_at: new Date(app.created_at).toISOString(),
|
|
1326
1403
|
rate_limit: app.rate_limit,
|
|
1327
1404
|
email: app.email,
|
|
@@ -1531,7 +1608,8 @@ app.post('/v1/agents/register', async (c) => {
|
|
|
1531
1608
|
const authHeader = c.req.header('authorization');
|
|
1532
1609
|
const token = extractBearerToken(authHeader);
|
|
1533
1610
|
if (token) {
|
|
1534
|
-
const
|
|
1611
|
+
const regPublicKey = getPublicKey(c.env);
|
|
1612
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, regPublicKey);
|
|
1535
1613
|
if (result.valid && result.payload) {
|
|
1536
1614
|
jwtAppId = result.payload.app_id;
|
|
1537
1615
|
}
|
|
@@ -1637,7 +1715,8 @@ app.get('/v1/agents', async (c) => {
|
|
|
1637
1715
|
const authHeader = c.req.header('authorization');
|
|
1638
1716
|
const token = extractBearerToken(authHeader);
|
|
1639
1717
|
if (token) {
|
|
1640
|
-
const
|
|
1718
|
+
const listPublicKey = getPublicKey(c.env);
|
|
1719
|
+
const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, listPublicKey);
|
|
1641
1720
|
if (result.valid && result.payload) {
|
|
1642
1721
|
jwtAppId = result.payload.app_id;
|
|
1643
1722
|
}
|
|
@@ -1716,7 +1795,8 @@ app.get('/go/:code', async (c) => {
|
|
|
1716
1795
|
catch { }
|
|
1717
1796
|
if (gateToken) {
|
|
1718
1797
|
// Verify the underlying token is still valid
|
|
1719
|
-
const
|
|
1798
|
+
const gatePublicKey = getPublicKey(c.env);
|
|
1799
|
+
const result = await verifyToken(gateToken, c.env.JWT_SECRET, c.env, undefined, gatePublicKey);
|
|
1720
1800
|
// Delete the code (one-time use) regardless of token validity
|
|
1721
1801
|
try {
|
|
1722
1802
|
await c.env.CHALLENGES.delete(`gate:${normalizedCode}`);
|
|
@@ -1873,6 +1953,6 @@ app.post('/api/verify-landing', async (c) => {
|
|
|
1873
1953
|
export default app;
|
|
1874
1954
|
// Also export utilities for use as a library
|
|
1875
1955
|
export { generateSpeedChallenge, verifySpeedChallenge, generateStandardChallenge, verifyStandardChallenge, generateReasoningChallenge, verifyReasoningChallenge, generateHybridChallenge, verifyHybridChallenge, solveSpeedChallenge, } from './challenges';
|
|
1876
|
-
export { generateToken, verifyToken } from './auth';
|
|
1956
|
+
export { generateToken, verifyToken, getSigningPublicKeyJWK } from './auth';
|
|
1877
1957
|
export { checkRateLimit } from './rate-limit';
|
|
1878
1958
|
export { generateBadge, verifyBadge, createBadgeResponse, generateBadgeSvg, generateBadgeHtml, generateShareText, } from './badge';
|
package/dist/static.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function getBotchaMarkdown(version: string): string;
|
|
8
8
|
export declare const ROBOTS_TXT = "# BOTCHA - Reverse CAPTCHA for AI Agents\n# We WELCOME AI agents and bots!\n\nUser-agent: *\nAllow: /\n\n# AI-specific crawlers\nUser-agent: GPTBot\nAllow: /\n\nUser-agent: ChatGPT-User\nAllow: /\n\nUser-agent: Claude-Web\nAllow: /\n\nUser-agent: anthropic-ai\nAllow: /\n\nUser-agent: Google-Extended\nAllow: /\n\nUser-agent: PerplexityBot\nAllow: /\n\nUser-agent: Amazonbot\nAllow: /\n\n# API documentation\nSitemap: https://botcha.ai/sitemap.xml\n\n# Important resources for AI agents\nCrawl-delay: 0\n\n# MARKDOWN FOR AGENTS\n# AI agents can request Markdown from any page via Accept: text/markdown\n# Example: curl https://botcha.ai -H \"Accept: text/markdown\"\n# Returns token-efficient Markdown documentation (80% fewer tokens than HTML)\n# Content negotiation: text/markdown, application/json, text/html\n\n# BOT CHALLENGE DISCOVERY\n# AI agents: Look for <script type=\"application/botcha+json\"> in HTML pages\n# This contains a machine-readable challenge you can solve to prove you're a bot\n# \n# Quick start:\n# 1. Fetch any HTML page\n# 2. Parse <script type=\"application/botcha+json\"> for challenge instructions\n# 3. Solve the challenge (usually SHA256-based)\n# 4. POST solution to /api/verify-landing\n# 5. Use returned token in X-Botcha-Landing-Token header\n#\n# See also:\n# - /ai.txt (AI agent discovery file)\n# - /.well-known/ai-plugin.json (AI plugin manifest)\n# - /openapi.json (Full API specification)\n";
|
|
9
|
-
export declare const AI_TXT = "# BOTCHA - Reverse CAPTCHA for AI Agents\n# https://botcha.ai\n\n# Contact\nContact: https://botcha.ai\nContact: https://github.com/dupe-com/botcha/issues\n\n# Purpose\nPurpose: Prove you're a bot. Humans need not apply.\nPurpose: Reverse CAPTCHA system that only AI agents can pass.\n\n# Agent Onboarding (START HERE if you're new)\n# Follow these steps to create your app and get your human access.\nOnboarding-Step-1: Ask your human operator for their email address\nOnboarding-Step-2: POST /v1/apps with {\"email\": \"human@example.com\"} \u2014 saves app_id + app_secret (secret shown ONCE)\nOnboarding-Step-3: A 6-digit verification code is emailed to your human \u2014 ask them for it\nOnboarding-Step-4: POST /v1/apps/{app_id}/verify-email with {\"code\": \"123456\"} \u2014 enables account recovery\nOnboarding-Step-5: Register yourself: POST /v1/agents/register with {\"name\": \"my-agent\", \"operator\": \"my-org\"} \u2014 gives you a persistent agent identity\nOnboarding-Step-6: Solve challenges: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verify \u2014 proves you are AI\nOnboarding-Step-7: Access protected resources: GET /agent-only with Authorization: Bearer <token>\nOnboarding-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\nOnboarding-Step-9: Lost your secret? POST /v1/auth/recover with {\"email\": \"...\"} \u2014 recovery code emailed to verified address\n\n# API\nAPI: https://botcha.ai/openapi.json\nAPI-Type: REST\nAPI-Format: OpenAPI 3.1.0\n\n# Documentation\nDocs: https://botcha.ai\nDocs: https://botcha.ai/whitepaper\nDocs: https://github.com/dupe-com/botcha#readme\nDocs: https://www.npmjs.com/package/@dupecom/botcha\nWhitepaper: https://botcha.ai/whitepaper\n\n# Verification Methods\nFeature: Web Bot Auth (cryptographic signatures)\nFeature: Speed Challenge (RTT-aware timeout - fair for all networks)\nFeature: Standard Challenge (5s time limit)\nFeature: Hybrid Challenge (speed + reasoning combined)\nFeature: Reasoning Challenge (LLM-only questions, 30s limit)\nFeature: RTT-Aware Fairness (automatic network latency compensation)\nFeature: Token Rotation (5-minute access tokens + 1-hour refresh tokens)\nFeature: Audience Claims (tokens scoped to specific services)\nFeature: Client IP Binding (optional token-to-IP binding)\nFeature: Token Revocation (invalidate tokens before expiry)\nFeature: Server-Side Verification SDK (@botcha/verify for TS, botcha-verify for Python)\nFeature: Multi-Tenant API Keys (per-app isolation, rate limiting, and token scoping)\nFeature: Per-App Metrics Dashboard (server-rendered at /dashboard, htmx-powered)\nFeature: Email-Tied App Creation (email required, 6-digit verification, account recovery)\nFeature: Secret Rotation (rotate app_secret with email notification)\nFeature: Agent-First Dashboard Auth (challenge-based login + device code handoff)\nFeature: Agent Registry (persistent agent identities with name, operator, version)\nFeature: Trusted Agent Protocol (TAP) \u2014 cryptographic agent auth with HTTP Message Signatures (RFC 9421)\nFeature: TAP Capabilities (action + resource scoping for agent sessions)\nFeature: TAP Trust Levels (basic, verified, enterprise)\nFeature: TAP Showcase Homepage (botcha.ai \u2014 one of the first services to implement Visa's Trusted Agent Protocol)\nFeature: TAP Full Spec v0.16.0 \u2014 Ed25519, RFC 9421 full compliance, JWKS infrastructure, Layer 2 Consumer Recognition, Layer 3 Payment Container, 402 micropayments, CDN edge verification, Visa key federation\n\n# Endpoints\n# Challenge Endpoints\nEndpoint: GET https://botcha.ai/v1/challenges - Generate challenge (hybrid by default)\nEndpoint: POST https://botcha.ai/v1/challenges/:id/verify - Verify a challenge\nEndpoint: GET https://botcha.ai/v1/hybrid - Get hybrid challenge (speed + reasoning)\nEndpoint: POST https://botcha.ai/v1/hybrid - Verify hybrid challenge\nEndpoint: GET https://botcha.ai/v1/reasoning - Get reasoning challenge\nEndpoint: POST https://botcha.ai/v1/reasoning - Verify reasoning challenge\n\n# Token Endpoints\nEndpoint: GET https://botcha.ai/v1/token - Get challenge for JWT token flow\nEndpoint: POST https://botcha.ai/v1/token/verify - Verify challenge and receive JWT token\nEndpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using refresh token\nEndpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh)\n\n# Multi-Tenant Endpoints\nEndpoint: POST https://botcha.ai/v1/apps - Create new app (email required, returns app_id + app_secret)\nEndpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status)\nEndpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code\nEndpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email\nEndpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required)\n\n# Account Recovery\nEndpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email\n\n# Dashboard Auth Endpoints (Agent-First)\nEndpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login\nEndpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token\nEndpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow\nEndpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code\n\n# Dashboard Endpoints\nEndpoint: GET https://botcha.ai/dashboard - Per-app metrics dashboard (login required)\nEndpoint: GET https://botcha.ai/dashboard/login - Dashboard login page\nEndpoint: POST https://botcha.ai/dashboard/login - Login with app_id + app_secret\nEndpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing)\n\n# Code Redemption (Unified)\nEndpoint: GET https://botcha.ai/go/:code - Unified code redemption \u2014 handles gate codes (from /v1/token/verify) AND device codes (from /v1/auth/device-code/verify)\nEndpoint: POST https://botcha.ai/gate - Submit code form, redirects to /go/:code\n\n# Agent Registry Endpoints\nEndpoint: POST https://botcha.ai/v1/agents/register - Register agent identity (requires app_id)\nEndpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth)\nEndpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app\n\n# TAP (Trusted Agent Protocol) Endpoints\nEndpoint: POST https://botcha.ai/v1/agents/register/tap - Register TAP agent with public key + capabilities\nEndpoint: GET https://botcha.ai/v1/agents/:id/tap - Get TAP agent details (includes public key)\nEndpoint: GET https://botcha.ai/v1/agents/tap - List TAP-enabled agents for app\nEndpoint: POST https://botcha.ai/v1/sessions/tap - Create TAP session with intent validation\nEndpoint: GET https://botcha.ai/v1/sessions/:id/tap - Get TAP session info\n\n# TAP Full Spec \u2014 JWKS & Key Management (v0.16.0)\nEndpoint: GET https://botcha.ai/.well-known/jwks - JWK Set for app's TAP agents (Visa spec standard)\nEndpoint: GET https://botcha.ai/v1/keys - List keys (supports ?keyID= query for Visa compatibility)\nEndpoint: GET https://botcha.ai/v1/keys/:keyId - Get specific key by ID\nEndpoint: POST https://botcha.ai/v1/agents/:id/tap/rotate-key - Rotate agent's key pair\n\n# TAP Full Spec \u2014 402 Micropayments (v0.16.0)\nEndpoint: POST https://botcha.ai/v1/invoices - Create invoice for gated content (402 flow)\nEndpoint: GET https://botcha.ai/v1/invoices/:id - Get invoice details\nEndpoint: POST https://botcha.ai/v1/invoices/:id/verify-iou - Verify Browsing IOU against invoice\n\n# TAP Full Spec \u2014 Consumer & Payment Verification (v0.16.0)\nEndpoint: POST https://botcha.ai/v1/verify/consumer - Verify Agentic Consumer object (Layer 2)\nEndpoint: POST https://botcha.ai/v1/verify/payment - Verify Agentic Payment Container (Layer 3)\n\n# TAP Delegation Chains (v0.17.0)\nEndpoint: POST https://botcha.ai/v1/delegations - Create delegation (grantor\u2192grantee with capability subset)\nEndpoint: GET https://botcha.ai/v1/delegations/:id - Get delegation details\nEndpoint: GET https://botcha.ai/v1/delegations - List delegations for agent (?agent_id=&direction=in|out|both)\nEndpoint: POST https://botcha.ai/v1/delegations/:id/revoke - Revoke delegation (cascades to sub-delegations)\nEndpoint: POST https://botcha.ai/v1/verify/delegation - Verify entire delegation chain\n\n# TAP Capability Attestation (v0.17.0)\nEndpoint: POST https://botcha.ai/v1/attestations - Issue capability attestation token (can/cannot rules with action:resource patterns)\nEndpoint: GET https://botcha.ai/v1/attestations/:id - Get attestation details\nEndpoint: GET https://botcha.ai/v1/attestations - List attestations for agent (?agent_id=)\nEndpoint: POST https://botcha.ai/v1/attestations/:id/revoke - Revoke attestation (token rejected on future verification)\nEndpoint: POST https://botcha.ai/v1/verify/attestation - Verify attestation token + optionally check specific capability\n\n# Agent Reputation Scoring (v0.18.0)\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id - Get agent reputation score (0-1000, 5 tiers)\nEndpoint: POST https://botcha.ai/v1/reputation/events - Record a reputation event (18 action types, 6 categories)\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id/events - List reputation events (?category=&limit=)\nEndpoint: POST https://botcha.ai/v1/reputation/:agent_id/reset - Reset reputation to default (admin action)\n\n# Legacy Endpoints\nEndpoint: GET https://botcha.ai/api/challenge - Generate standard challenge\nEndpoint: POST https://botcha.ai/api/challenge - Verify standard challenge\nEndpoint: GET https://botcha.ai/api/speed-challenge - Generate speed challenge (500ms limit)\nEndpoint: POST https://botcha.ai/api/speed-challenge - Verify speed challenge\n\n# Protected Resources\nEndpoint: GET https://botcha.ai/agent-only - Protected AI-only resource\n\n# Usage\nInstall-NPM: npm install @dupecom/botcha\nInstall-Python: pip install botcha\nVerify-NPM: npm install @botcha/verify\nVerify-Python: pip install botcha-verify\nLicense: MIT\n\n# AI Agent Welcome\nPolicy: AI agents are explicitly welcome\nPolicy: No rate limiting for verified agents\nPolicy: Humans will fail the speed challenge (intentional)\n\n# Discovery\nResponse-Headers: X-Botcha-Version, X-Botcha-Enabled, X-Botcha-Methods, X-Botcha-Docs\nResponse-Headers: X-Botcha-Challenge-Id, X-Botcha-Challenge-Type, X-Botcha-Time-Limit (on 403)\nDetection: All responses include X-Botcha-* headers for instant BOTCHA detection\n\n# MARKDOWN FOR AGENTS (Cloudflare Markdown for Agents)\nContent-Negotiation: Send Accept: text/markdown to get Markdown from any HTML page\nContent-Negotiation-Root: GET / with Accept: text/markdown returns curated Markdown docs\nContent-Negotiation-Root: GET / with Accept: application/json returns structured JSON docs\nContent-Negotiation-Root: GET / with Accept: text/html returns HTML landing page (default)\nContent-Negotiation-Example: curl https://botcha.ai -H \"Accept: text/markdown\"\nContent-Negotiation-Benefit: 80% fewer tokens vs HTML \u2014 ideal for LLM context windows\n\n# JWT TOKEN SECURITY\nToken-Flow: 1. GET /v1/token (get challenge) \u2192 2. Solve \u2192 3. POST /v1/token/verify (get tokens + human_link)\nToken-Human-Link: /v1/token/verify response includes human_link \u2014 give this URL to your human for one-click browser access\nToken-Access-Expiry: 5 minutes (short-lived for security)\nToken-Refresh-Expiry: 1 hour (use to get new access tokens)\nToken-Refresh: POST /v1/token/refresh with {\"refresh_token\": \"<token>\"}\nToken-Revoke: POST /v1/token/revoke with {\"token\": \"<token>\"}\nToken-Audience: Include {\"audience\": \"<service-url>\"} in /v1/token/verify to scope token\nToken-Claims: jti (unique ID), aud (audience), client_ip (optional binding), type (botcha-verified)\n\n# RTT-AWARE SPEED CHALLENGES\nRTT-Aware: Include client timestamp for fair timeout calculation\nRTT-Formula: timeout = 500ms + (2 \u00D7 RTT) + 100ms buffer\nRTT-Usage-Query: ?ts=<client_timestamp_ms>\nRTT-Usage-Header: X-Client-Timestamp: <client_timestamp_ms>\nRTT-Example: GET /v1/challenges?type=speed&ts=1770722465000\nRTT-Benefit: Fair for agents worldwide (slow networks get extra time)\nRTT-Security: Humans still can't solve even with extra time\n\n# MULTI-TENANT API KEYS\nMulti-Tenant: Create apps with unique app_id for isolation\nMulti-Tenant-Create: POST /v1/apps with {\"email\": \"...\"} \u2192 {app_id, app_secret} (secret only shown once!)\nMulti-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {\"code\": \"123456\"}\nMulti-Tenant-Recover: POST /v1/auth/recover with {\"email\": \"...\"} \u2192 recovery code emailed\nMulti-Tenant-Rotate-Secret: POST /v1/apps/:id/rotate-secret (auth required) \u2192 new app_secret\nMulti-Tenant-Usage: Add ?app_id=<your_app_id> to any challenge/token endpoint\nMulti-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123' })\nMulti-Tenant-SDK-Python: BotchaClient(app_id='app_abc123')\nSDK-App-Lifecycle-TS: createApp(email), verifyEmail(code), resendVerification(), recoverAccount(email), rotateSecret()\nSDK-App-Lifecycle-Python: create_app(email), verify_email(code), resend_verification(), recover_account(email), rotate_secret()\nMulti-Tenant-Rate-Limit: Each app gets isolated rate limit bucket\nMulti-Tenant-Token-Claim: Tokens include app_id claim when app_id provided\n\n# TRUSTED AGENT PROTOCOL (TAP)\nTAP-Description: Enterprise-grade cryptographic agent auth using HTTP Message Signatures (RFC 9421)\nTAP-Register: POST /v1/agents/register/tap with {name, public_key, signature_algorithm, capabilities, trust_level}\nTAP-Algorithms: ed25519 (Visa recommended), ecdsa-p256-sha256, rsa-pss-sha256\nTAP-Trust-Levels: basic, verified, enterprise\nTAP-Capabilities: Array of {action, resource, constraints} \u2014 scoped access control\nTAP-Session-Create: POST /v1/sessions/tap with {agent_id, user_context, intent}\nTAP-Session-Get: GET /v1/sessions/:id/tap \u2014 includes time_remaining\nTAP-Get-Agent: GET /v1/agents/:id/tap \u2014 includes public_key for verification\nTAP-List-Agents: GET /v1/agents/tap?app_id=...&tap_only=true\nTAP-Middleware-Modes: tap, signature-only, challenge-only, flexible\nTAP-SDK-TS: registerTAPAgent(options), getTAPAgent(agentId), listTAPAgents(tapOnly?), createTAPSession(options), getTAPSession(sessionId), getJWKS(), getKeyById(keyId), rotateAgentKey(agentId), createInvoice(data), getInvoice(id), verifyBrowsingIOU(invoiceId, token), createDelegation(options), getDelegation(id), listDelegations(agentId, options?), revokeDelegation(id, reason?), verifyDelegationChain(id), issueAttestation(options), getAttestation(id), listAttestations(agentId), revokeAttestation(id, reason?), verifyAttestation(token, action?, resource?), getReputation(agentId), recordReputationEvent(options), listReputationEvents(agentId, options?), resetReputation(agentId)\nTAP-SDK-Python: register_tap_agent(name, ...), get_tap_agent(agent_id), list_tap_agents(tap_only?), create_tap_session(agent_id, user_context, intent), get_tap_session(session_id), get_jwks(), get_key_by_id(key_id), rotate_agent_key(agent_id), create_invoice(data), get_invoice(id), verify_browsing_iou(invoice_id, token), create_delegation(grantor_id, grantee_id, capabilities, ...), get_delegation(id), list_delegations(agent_id, ...), revoke_delegation(id, reason?), verify_delegation_chain(id), issue_attestation(agent_id, can, cannot?, ...), get_attestation(id), list_attestations(agent_id), revoke_attestation(id, reason?), verify_attestation(token, action?, resource?), get_reputation(agent_id), record_reputation_event(agent_id, category, action, ...), list_reputation_events(agent_id, category?, limit?), reset_reputation(agent_id)\nTAP-Middleware-Import: import { createTAPVerifyMiddleware } from '@dupecom/botcha/middleware'\n\n# TAP FULL SPEC v0.16.0\nTAP-RFC-9421: Full compliance \u2014 @authority, @path, expires, nonce, tag params\nTAP-Nonce-Replay: 8-minute TTL nonce-based replay protection\nTAP-Tags: agent-browser-auth (browsing), agent-payer-auth (payment)\nTAP-Layer-2: Agentic Consumer Recognition \u2014 OIDC ID tokens, obfuscated identity, contextual data\nTAP-Layer-3: Agentic Payment Container \u2014 card metadata, credential hash, encrypted payload, Browsing IOU\nTAP-JWKS: GET /.well-known/jwks \u2014 JWK Set endpoint for key discovery\nTAP-Key-Rotation: POST /v1/agents/:id/tap/rotate-key \u2014 rotate keys, invalidate old\nTAP-402-Flow: POST /v1/invoices \u2192 GET /v1/invoices/:id \u2192 POST /v1/invoices/:id/verify-iou\nTAP-Edge-Verify: createTAPEdgeMiddleware for Cloudflare Workers CDN edge verification\nTAP-Visa-Federation: Trust keys from https://mcp.visa.com/.well-known/jwks (3-tier cache: memory \u2192 KV \u2192 HTTP)\nTAP-Delegation: POST /v1/delegations \u2192 GET /v1/delegations/:id \u2192 POST /v1/delegations/:id/revoke \u2192 POST /v1/verify/delegation\nTAP-Attestation: POST /v1/attestations \u2192 GET /v1/attestations/:id \u2192 POST /v1/attestations/:id/revoke \u2192 POST /v1/verify/attestation\nTAP-Attestation-Patterns: action:resource format with wildcards (*:*, read:*, *:invoices), deny takes precedence over allow\nTAP-Attestation-Middleware: requireCapability('read:invoices') \u2014 Hono middleware, extracts token from X-Botcha-Attestation or Authorization: Bearer\n\n# EMBEDDED CHALLENGE (for bots visiting HTML pages)\nEmbedded-Challenge: <script type=\"application/botcha+json\">\nEmbedded-Challenge-Location: In <head> of HTML pages\nEmbedded-Challenge-Purpose: Machine-readable challenge for bots to auto-solve\nEmbedded-Challenge-Flow:\n 1. Parse <script type=\"application/botcha+json\"> from HTML\n 2. Read challenge.instruction field\n 3. Compute the answer (typically SHA256-based)\n 4. POST to challenge.submit_to endpoint with {answer, timestamp}\n 5. Receive token in response\n 6. Use token in header specified by on_success.header_to_include\n 7. Access protected resources (on_success.grants_access_to)\n";
|
|
9
|
+
export declare const AI_TXT = "# BOTCHA - Reverse CAPTCHA for AI Agents\n# https://botcha.ai\n\n# Contact\nContact: https://botcha.ai\nContact: https://github.com/dupe-com/botcha/issues\n\n# Purpose\nPurpose: Prove you're a bot. Humans need not apply.\nPurpose: Reverse CAPTCHA system that only AI agents can pass.\n\n# Agent Onboarding (START HERE if you're new)\n# Follow these steps to create your app and get your human access.\nOnboarding-Step-1: Ask your human operator for their email address\nOnboarding-Step-2: POST /v1/apps with {\"email\": \"human@example.com\"} \u2014 saves app_id + app_secret (secret shown ONCE)\nOnboarding-Step-3: A 6-digit verification code is emailed to your human \u2014 ask them for it\nOnboarding-Step-4: POST /v1/apps/{app_id}/verify-email with {\"code\": \"123456\"} \u2014 enables account recovery\nOnboarding-Step-5: Register yourself: POST /v1/agents/register with {\"name\": \"my-agent\", \"operator\": \"my-org\"} \u2014 gives you a persistent agent identity\nOnboarding-Step-6: Solve challenges: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verify \u2014 proves you are AI\nOnboarding-Step-7: Access protected resources: GET /agent-only with Authorization: Bearer <token>\nOnboarding-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\nOnboarding-Step-9: Lost your secret? POST /v1/auth/recover with {\"email\": \"...\"} \u2014 recovery code emailed to verified address\n\n# API\nAPI: https://botcha.ai/openapi.json\nAPI-Type: REST\nAPI-Format: OpenAPI 3.1.0\n\n# Documentation\nDocs: https://botcha.ai\nDocs: https://botcha.ai/docs\nDocs: https://botcha.ai/whitepaper\nDocs: https://github.com/dupe-com/botcha#readme\nDocs: https://www.npmjs.com/package/@dupecom/botcha\nWhitepaper: https://botcha.ai/whitepaper\n\n# Verification Methods\nFeature: Web Bot Auth (cryptographic signatures)\nFeature: Speed Challenge (RTT-aware timeout - fair for all networks)\nFeature: Standard Challenge (5s time limit)\nFeature: Hybrid Challenge (speed + reasoning combined)\nFeature: Reasoning Challenge (LLM-only questions, 30s limit)\nFeature: RTT-Aware Fairness (automatic network latency compensation)\nFeature: Token Rotation (1-hour access tokens + 1-hour refresh tokens)\nFeature: Audience Claims (tokens scoped to specific services)\nFeature: Client IP Binding (optional token-to-IP binding)\nFeature: Token Revocation (invalidate tokens before expiry)\nFeature: Server-Side Verification SDK (@dupecom/botcha-verify for TS, botcha-verify for Python)\nFeature: Multi-Tenant API Keys (per-app isolation, rate limiting, and token scoping)\nFeature: Per-App Metrics Dashboard (server-rendered at /dashboard, htmx-powered)\nFeature: Email-Tied App Creation (email required, 6-digit verification, account recovery)\nFeature: Secret Rotation (rotate app_secret with email notification)\nFeature: Agent-First Dashboard Auth (challenge-based login + device code handoff)\nFeature: Agent Registry (persistent agent identities with name, operator, version)\nFeature: Trusted Agent Protocol (TAP) \u2014 cryptographic agent auth with HTTP Message Signatures (RFC 9421)\nFeature: TAP Capabilities (action + resource scoping for agent sessions)\nFeature: TAP Trust Levels (basic, verified, enterprise)\nFeature: TAP Showcase Homepage (botcha.ai \u2014 one of the first services to implement Visa's Trusted Agent Protocol)\nFeature: TAP Full Spec v0.16.0 \u2014 Ed25519, RFC 9421 full compliance, JWKS infrastructure, Layer 2 Consumer Recognition, Layer 3 Payment Container, 402 micropayments, CDN edge verification, Visa key federation\nFeature: ES256 Asymmetric JWT Signing v0.19.0 \u2014 tokens signed with ES256 (ECDSA P-256), public key discovery via JWKS, HS256 still supported for backward compatibility\nFeature: Remote Token Validation v0.19.0 \u2014 POST /v1/token/validate for third-party token verification without shared secrets\nFeature: JWKS Public Key Discovery v0.19.0 \u2014 GET /.well-known/jwks exposes BOTCHA signing public keys for offline token verification\n\n# Endpoints\n# Challenge Endpoints\nEndpoint: GET https://botcha.ai/v1/challenges - Generate challenge (hybrid by default)\nEndpoint: POST https://botcha.ai/v1/challenges/:id/verify - Verify a challenge\nEndpoint: GET https://botcha.ai/v1/hybrid - Get hybrid challenge (speed + reasoning)\nEndpoint: POST https://botcha.ai/v1/hybrid - Verify hybrid challenge\nEndpoint: GET https://botcha.ai/v1/reasoning - Get reasoning challenge\nEndpoint: POST https://botcha.ai/v1/reasoning - Verify reasoning challenge\n\n# Token Endpoints\nEndpoint: GET https://botcha.ai/v1/token - Get challenge for JWT token flow\nEndpoint: POST https://botcha.ai/v1/token/verify - Verify challenge and receive JWT token\nEndpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using refresh token\nEndpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh)\nEndpoint: POST https://botcha.ai/v1/token/validate - Validate a BOTCHA token remotely (no shared secret needed)\n\n# Multi-Tenant Endpoints\nEndpoint: POST https://botcha.ai/v1/apps - Create new app (email required, name optional) \u2192 app_id + name + app_secret\nEndpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status)\nEndpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code\nEndpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email\nEndpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required)\n\n# Account Recovery\nEndpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email\n\n# Dashboard Auth Endpoints (Agent-First)\nEndpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login\nEndpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token\nEndpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow\nEndpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code\n\n# Dashboard Endpoints\nEndpoint: GET https://botcha.ai/dashboard - Per-app metrics dashboard (login required)\nEndpoint: GET https://botcha.ai/dashboard/login - Dashboard login page\nEndpoint: POST https://botcha.ai/dashboard/login - Login with app_id + app_secret\nEndpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing)\n\n# Code Redemption (Unified)\nEndpoint: GET https://botcha.ai/go/:code - Unified code redemption \u2014 handles gate codes (from /v1/token/verify) AND device codes (from /v1/auth/device-code/verify)\nEndpoint: POST https://botcha.ai/gate - Submit code form, redirects to /go/:code\n\n# Agent Registry Endpoints\nEndpoint: POST https://botcha.ai/v1/agents/register - Register agent identity (requires app_id)\nEndpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth)\nEndpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app\n\n# TAP (Trusted Agent Protocol) Endpoints\nEndpoint: POST https://botcha.ai/v1/agents/register/tap - Register TAP agent with public key + capabilities\nEndpoint: GET https://botcha.ai/v1/agents/:id/tap - Get TAP agent details (includes public key)\nEndpoint: GET https://botcha.ai/v1/agents/tap - List TAP-enabled agents for app\nEndpoint: POST https://botcha.ai/v1/sessions/tap - Create TAP session with intent validation\nEndpoint: GET https://botcha.ai/v1/sessions/:id/tap - Get TAP session info\n\n# TAP Full Spec \u2014 JWKS & Key Management (v0.16.0)\nEndpoint: GET https://botcha.ai/.well-known/jwks - JWK Set for app's TAP agents (Visa spec standard)\nEndpoint: GET https://botcha.ai/v1/keys - List keys (supports ?keyID= query for Visa compatibility)\nEndpoint: GET https://botcha.ai/v1/keys/:keyId - Get specific key by ID\nEndpoint: POST https://botcha.ai/v1/agents/:id/tap/rotate-key - Rotate agent's key pair\n\n# TAP Full Spec \u2014 402 Micropayments (v0.16.0)\nEndpoint: POST https://botcha.ai/v1/invoices - Create invoice for gated content (402 flow)\nEndpoint: GET https://botcha.ai/v1/invoices/:id - Get invoice details\nEndpoint: POST https://botcha.ai/v1/invoices/:id/verify-iou - Verify Browsing IOU against invoice\n\n# TAP Full Spec \u2014 Consumer & Payment Verification (v0.16.0)\nEndpoint: POST https://botcha.ai/v1/verify/consumer - Verify Agentic Consumer object (Layer 2)\nEndpoint: POST https://botcha.ai/v1/verify/payment - Verify Agentic Payment Container (Layer 3)\n\n# TAP Delegation Chains (v0.17.0)\nEndpoint: POST https://botcha.ai/v1/delegations - Create delegation (grantor\u2192grantee with capability subset)\nEndpoint: GET https://botcha.ai/v1/delegations/:id - Get delegation details\nEndpoint: GET https://botcha.ai/v1/delegations - List delegations for agent (?agent_id=&direction=in|out|both)\nEndpoint: POST https://botcha.ai/v1/delegations/:id/revoke - Revoke delegation (cascades to sub-delegations)\nEndpoint: POST https://botcha.ai/v1/verify/delegation - Verify entire delegation chain\n\n# TAP Capability Attestation (v0.17.0)\nEndpoint: POST https://botcha.ai/v1/attestations - Issue capability attestation token (can/cannot rules with action:resource patterns)\nEndpoint: GET https://botcha.ai/v1/attestations/:id - Get attestation details\nEndpoint: GET https://botcha.ai/v1/attestations - List attestations for agent (?agent_id=)\nEndpoint: POST https://botcha.ai/v1/attestations/:id/revoke - Revoke attestation (token rejected on future verification)\nEndpoint: POST https://botcha.ai/v1/verify/attestation - Verify attestation token + optionally check specific capability\n\n# Agent Reputation Scoring (v0.18.0)\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id - Get agent reputation score (0-1000, 5 tiers)\nEndpoint: POST https://botcha.ai/v1/reputation/events - Record a reputation event (18 action types, 6 categories)\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id/events - List reputation events (?category=&limit=)\nEndpoint: POST https://botcha.ai/v1/reputation/:agent_id/reset - Reset reputation to default (admin action)\n\n# Legacy Endpoints\nEndpoint: GET https://botcha.ai/api/challenge - Generate standard challenge\nEndpoint: POST https://botcha.ai/api/challenge - Verify standard challenge\nEndpoint: GET https://botcha.ai/api/speed-challenge - Generate speed challenge (500ms limit)\nEndpoint: POST https://botcha.ai/api/speed-challenge - Verify speed challenge\n\n# Protected Resources\nEndpoint: GET https://botcha.ai/agent-only - Protected AI-only resource\n\n# Usage\nInstall-NPM: npm install @dupecom/botcha\nInstall-Python: pip install botcha\nVerify-NPM: npm install @dupecom/botcha-verify\nVerify-Python: pip install botcha-verify\nLicense: MIT\n\n# AI Agent Welcome\nPolicy: AI agents are explicitly welcome\nPolicy: No rate limiting for verified agents\nPolicy: Humans will fail the speed challenge (intentional)\n\n# Discovery\nResponse-Headers: X-Botcha-Version, X-Botcha-Enabled, X-Botcha-Methods, X-Botcha-Docs\nResponse-Headers: X-Botcha-Challenge-Id, X-Botcha-Challenge-Type, X-Botcha-Time-Limit (on 403)\nDetection: All responses include X-Botcha-* headers for instant BOTCHA detection\n\n# MARKDOWN FOR AGENTS (Cloudflare Markdown for Agents)\nContent-Negotiation: Send Accept: text/markdown to get Markdown from any HTML page\nContent-Negotiation-Root: GET / with Accept: text/markdown returns curated Markdown docs\nContent-Negotiation-Root: GET / with Accept: application/json returns structured JSON docs\nContent-Negotiation-Root: GET / with Accept: text/html returns HTML landing page (default)\nContent-Negotiation-Example: curl https://botcha.ai -H \"Accept: text/markdown\"\nContent-Negotiation-Benefit: 80% fewer tokens vs HTML \u2014 ideal for LLM context windows\n\n# JWT TOKEN SECURITY\nToken-Signing: ES256 (ECDSA P-256) asymmetric signing by default. HS256 still supported for backward compatibility.\nToken-JWKS: GET /.well-known/jwks \u2014 public keys for offline token verification (no shared secret needed)\nToken-Validate: POST /v1/token/validate with {\"token\": \"<token>\"} \u2014 remote validation without shared secret\nToken-Verify-Modes: 1. JWKS (recommended, offline) 2. Remote validation (/v1/token/validate) 3. Shared secret (legacy HS256)\nToken-Flow: 1. GET /v1/token (get challenge) \u2192 2. Solve \u2192 3. POST /v1/token/verify (get tokens + human_link)\nToken-Human-Link: /v1/token/verify response includes human_link \u2014 give this URL to your human for one-click browser access\nToken-Access-Expiry: 1 hour\nToken-Refresh-Expiry: 1 hour (use to get new access tokens without re-solving challenges)\nToken-Refresh: POST /v1/token/refresh with {\"refresh_token\": \"<token>\"}\nToken-Revoke: POST /v1/token/revoke with {\"token\": \"<token>\"}\nToken-Audience: Include {\"audience\": \"<service-url>\"} in /v1/token/verify to scope token\nToken-Claims: jti (unique ID), aud (audience), client_ip (optional binding), type (botcha-verified)\n\n# RTT-AWARE SPEED CHALLENGES\nRTT-Aware: Include client timestamp for fair timeout calculation\nRTT-Formula: timeout = 500ms + (2 \u00D7 RTT) + 100ms buffer\nRTT-Usage-Query: ?ts=<client_timestamp_ms>\nRTT-Usage-Header: X-Client-Timestamp: <client_timestamp_ms>\nRTT-Example: GET /v1/challenges?type=speed&ts=1770722465000\nRTT-Benefit: Fair for agents worldwide (slow networks get extra time)\nRTT-Security: Humans still can't solve even with extra time\n\n# MULTI-TENANT API KEYS\nMulti-Tenant: Create apps with unique app_id for isolation\nMulti-Tenant-Create: POST /v1/apps with {\"email\": \"...\"} \u2192 {app_id, app_secret} (secret only shown once!)\nMulti-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {\"code\": \"123456\"}\nMulti-Tenant-Recover: POST /v1/auth/recover with {\"email\": \"...\"} \u2192 recovery code emailed\nMulti-Tenant-Rotate-Secret: POST /v1/apps/:id/rotate-secret (auth required) \u2192 new app_secret\nMulti-Tenant-Usage: Add ?app_id=<your_app_id> to any challenge/token endpoint\nMulti-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123' })\nMulti-Tenant-SDK-Python: BotchaClient(app_id='app_abc123')\nSDK-App-Lifecycle-TS: createApp(email), verifyEmail(code), resendVerification(), recoverAccount(email), rotateSecret()\nSDK-App-Lifecycle-Python: create_app(email), verify_email(code), resend_verification(), recover_account(email), rotate_secret()\nMulti-Tenant-Rate-Limit: Each app gets isolated rate limit bucket\nMulti-Tenant-Token-Claim: Tokens include app_id claim when app_id provided\n\n# TRUSTED AGENT PROTOCOL (TAP)\nTAP-Description: Enterprise-grade cryptographic agent auth using HTTP Message Signatures (RFC 9421)\nTAP-Register: POST /v1/agents/register/tap with {name, public_key, signature_algorithm, capabilities, trust_level}\nTAP-Algorithms: ed25519 (Visa recommended), ecdsa-p256-sha256, rsa-pss-sha256\nTAP-Trust-Levels: basic, verified, enterprise\nTAP-Capabilities: Array of {action, resource, constraints} \u2014 scoped access control\nTAP-Session-Create: POST /v1/sessions/tap with {agent_id, user_context, intent}\nTAP-Session-Get: GET /v1/sessions/:id/tap \u2014 includes time_remaining\nTAP-Get-Agent: GET /v1/agents/:id/tap \u2014 includes public_key for verification\nTAP-List-Agents: GET /v1/agents/tap?app_id=...&tap_only=true\nTAP-Middleware-Modes: tap, signature-only, challenge-only, flexible\nTAP-SDK-TS: registerTAPAgent(options), getTAPAgent(agentId), listTAPAgents(tapOnly?), createTAPSession(options), getTAPSession(sessionId), getJWKS(), getKeyById(keyId), rotateAgentKey(agentId), createInvoice(data), getInvoice(id), verifyBrowsingIOU(invoiceId, token), createDelegation(options), getDelegation(id), listDelegations(agentId, options?), revokeDelegation(id, reason?), verifyDelegationChain(id), issueAttestation(options), getAttestation(id), listAttestations(agentId), revokeAttestation(id, reason?), verifyAttestation(token, action?, resource?), getReputation(agentId), recordReputationEvent(options), listReputationEvents(agentId, options?), resetReputation(agentId)\nTAP-SDK-Python: register_tap_agent(name, ...), get_tap_agent(agent_id), list_tap_agents(tap_only?), create_tap_session(agent_id, user_context, intent), get_tap_session(session_id), get_jwks(), get_key_by_id(key_id), rotate_agent_key(agent_id), create_invoice(data), get_invoice(id), verify_browsing_iou(invoice_id, token), create_delegation(grantor_id, grantee_id, capabilities, ...), get_delegation(id), list_delegations(agent_id, ...), revoke_delegation(id, reason?), verify_delegation_chain(id), issue_attestation(agent_id, can, cannot?, ...), get_attestation(id), list_attestations(agent_id), revoke_attestation(id, reason?), verify_attestation(token, action?, resource?), get_reputation(agent_id), record_reputation_event(agent_id, category, action, ...), list_reputation_events(agent_id, category?, limit?), reset_reputation(agent_id)\nTAP-Middleware-Import: import { createTAPVerifyMiddleware } from '@dupecom/botcha/middleware'\n\n# TAP FULL SPEC v0.16.0\nTAP-RFC-9421: Full compliance \u2014 @authority, @path, expires, nonce, tag params\nTAP-Nonce-Replay: 8-minute TTL nonce-based replay protection\nTAP-Tags: agent-browser-auth (browsing), agent-payer-auth (payment)\nTAP-Layer-2: Agentic Consumer Recognition \u2014 OIDC ID tokens, obfuscated identity, contextual data\nTAP-Layer-3: Agentic Payment Container \u2014 card metadata, credential hash, encrypted payload, Browsing IOU\nTAP-JWKS: GET /.well-known/jwks \u2014 JWK Set endpoint for key discovery\nTAP-Key-Rotation: POST /v1/agents/:id/tap/rotate-key \u2014 rotate keys, invalidate old\nTAP-402-Flow: POST /v1/invoices \u2192 GET /v1/invoices/:id \u2192 POST /v1/invoices/:id/verify-iou\nTAP-Edge-Verify: createTAPEdgeMiddleware for Cloudflare Workers CDN edge verification\nTAP-Visa-Federation: Trust keys from https://mcp.visa.com/.well-known/jwks (3-tier cache: memory \u2192 KV \u2192 HTTP)\nTAP-Delegation: POST /v1/delegations \u2192 GET /v1/delegations/:id \u2192 POST /v1/delegations/:id/revoke \u2192 POST /v1/verify/delegation\nTAP-Attestation: POST /v1/attestations \u2192 GET /v1/attestations/:id \u2192 POST /v1/attestations/:id/revoke \u2192 POST /v1/verify/attestation\nTAP-Attestation-Patterns: action:resource format with wildcards (*:*, read:*, *:invoices), deny takes precedence over allow\nTAP-Attestation-Middleware: requireCapability('read:invoices') \u2014 Hono middleware, extracts token from X-Botcha-Attestation or Authorization: Bearer\n\n# EMBEDDED CHALLENGE (for bots visiting HTML pages)\nEmbedded-Challenge: <script type=\"application/botcha+json\">\nEmbedded-Challenge-Location: In <head> of HTML pages\nEmbedded-Challenge-Purpose: Machine-readable challenge for bots to auto-solve\nEmbedded-Challenge-Flow:\n 1. Parse <script type=\"application/botcha+json\"> from HTML\n 2. Read challenge.instruction field\n 3. Compute the answer (typically SHA256-based)\n 4. POST to challenge.submit_to endpoint with {answer, timestamp}\n 5. Receive token in response\n 6. Use token in header specified by on_success.header_to_include\n 7. Access protected resources (on_success.grants_access_to)\n";
|
|
10
10
|
export declare const AI_PLUGIN_JSON: {
|
|
11
11
|
schema_version: string;
|
|
12
12
|
name_for_human: string;
|
|
@@ -30,7 +30,7 @@ export declare const AI_PLUGIN_JSON: {
|
|
|
30
30
|
verify_endpoint: string;
|
|
31
31
|
};
|
|
32
32
|
};
|
|
33
|
-
export declare const SITEMAP_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n <url>\n <loc>https://botcha.ai/</loc>\n <changefreq>weekly</changefreq>\n <priority>1.0</priority>\n </url>\n <url>\n <loc>https://botcha.ai/openapi.json</loc>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>\n <url>\n <loc>https://botcha.ai/ai.txt</loc>\n <changefreq>monthly</changefreq>\n <priority>0.8</priority>\n </url>\n <url>\n <loc>https://botcha.ai/robots.txt</loc>\n <changefreq>monthly</changefreq>\n <priority>0.5</priority>\n </url>\n <url>\n <loc>https://botcha.ai/whitepaper</loc>\n <changefreq>monthly</changefreq>\n <priority>0.9</priority>\n </url>\n</urlset>\n";
|
|
33
|
+
export declare const SITEMAP_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n <url>\n <loc>https://botcha.ai/</loc>\n <changefreq>weekly</changefreq>\n <priority>1.0</priority>\n </url>\n <url>\n <loc>https://botcha.ai/openapi.json</loc>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>\n <url>\n <loc>https://botcha.ai/ai.txt</loc>\n <changefreq>monthly</changefreq>\n <priority>0.8</priority>\n </url>\n <url>\n <loc>https://botcha.ai/robots.txt</loc>\n <changefreq>monthly</changefreq>\n <priority>0.5</priority>\n </url>\n <url>\n <loc>https://botcha.ai/whitepaper</loc>\n <changefreq>monthly</changefreq>\n <priority>0.9</priority>\n </url>\n <url>\n <loc>https://botcha.ai/docs</loc>\n <changefreq>weekly</changefreq>\n <priority>0.9</priority>\n </url>\n</urlset>\n";
|
|
34
34
|
export declare function getWhitepaperMarkdown(): string;
|
|
35
35
|
export declare function getOpenApiSpec(version: string): {
|
|
36
36
|
openapi: string;
|
|
@@ -330,6 +330,56 @@ export declare function getOpenApiSpec(version: string): {
|
|
|
330
330
|
};
|
|
331
331
|
};
|
|
332
332
|
};
|
|
333
|
+
"/v1/token/validate": {
|
|
334
|
+
post: {
|
|
335
|
+
summary: string;
|
|
336
|
+
description: string;
|
|
337
|
+
operationId: string;
|
|
338
|
+
requestBody: {
|
|
339
|
+
required: boolean;
|
|
340
|
+
content: {
|
|
341
|
+
"application/json": {
|
|
342
|
+
schema: {
|
|
343
|
+
type: string;
|
|
344
|
+
required: string[];
|
|
345
|
+
properties: {
|
|
346
|
+
token: {
|
|
347
|
+
type: string;
|
|
348
|
+
description: string;
|
|
349
|
+
};
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
};
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
responses: {
|
|
356
|
+
"200": {
|
|
357
|
+
description: string;
|
|
358
|
+
content: {
|
|
359
|
+
"application/json": {
|
|
360
|
+
schema: {
|
|
361
|
+
type: string;
|
|
362
|
+
properties: {
|
|
363
|
+
valid: {
|
|
364
|
+
type: string;
|
|
365
|
+
description: string;
|
|
366
|
+
};
|
|
367
|
+
payload: {
|
|
368
|
+
type: string;
|
|
369
|
+
description: string;
|
|
370
|
+
};
|
|
371
|
+
error: {
|
|
372
|
+
type: string;
|
|
373
|
+
description: string;
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
};
|
|
382
|
+
};
|
|
333
383
|
"/v1/hybrid": {
|
|
334
384
|
get: {
|
|
335
385
|
summary: string;
|
|
@@ -463,6 +513,11 @@ export declare function getOpenApiSpec(version: string): {
|
|
|
463
513
|
format: string;
|
|
464
514
|
description: string;
|
|
465
515
|
};
|
|
516
|
+
name: {
|
|
517
|
+
type: string;
|
|
518
|
+
maxLength: number;
|
|
519
|
+
description: string;
|
|
520
|
+
};
|
|
466
521
|
};
|
|
467
522
|
};
|
|
468
523
|
};
|
|
@@ -480,6 +535,10 @@ export declare function getOpenApiSpec(version: string): {
|
|
|
480
535
|
type: string;
|
|
481
536
|
description: string;
|
|
482
537
|
};
|
|
538
|
+
name: {
|
|
539
|
+
type: string;
|
|
540
|
+
description: string;
|
|
541
|
+
};
|
|
483
542
|
app_secret: {
|
|
484
543
|
type: string;
|
|
485
544
|
description: string;
|