@dupecom/botcha-cloudflare 0.2.0 → 0.3.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/dist/index.js CHANGED
@@ -7,18 +7,22 @@
7
7
  */
8
8
  import { Hono } from 'hono';
9
9
  import { cors } from 'hono/cors';
10
- import { generateSpeedChallenge, verifySpeedChallenge, generateStandardChallenge, verifyStandardChallenge, verifyLandingChallenge, } from './challenges';
10
+ import { generateSpeedChallenge, verifySpeedChallenge, generateStandardChallenge, verifyStandardChallenge, generateReasoningChallenge, verifyReasoningChallenge, generateHybridChallenge, verifyHybridChallenge, verifyLandingChallenge, } from './challenges';
11
11
  import { generateToken, verifyToken, extractBearerToken } from './auth';
12
12
  import { checkRateLimit, getClientIP } from './rate-limit';
13
+ import { verifyBadge, generateBadgeSvg, generateBadgeHtml, createBadgeResponse } from './badge';
14
+ import streamRoutes from './routes/stream';
13
15
  const app = new Hono();
14
16
  // ============ MIDDLEWARE ============
15
17
  app.use('*', cors());
18
+ // ============ MOUNT ROUTES ============
19
+ app.route('/', streamRoutes);
16
20
  // BOTCHA discovery headers
17
21
  app.use('*', async (c, next) => {
18
22
  await next();
19
23
  c.header('X-Botcha-Version', c.env.BOTCHA_VERSION || '0.2.0');
20
24
  c.header('X-Botcha-Enabled', 'true');
21
- c.header('X-Botcha-Methods', 'speed-challenge,standard-challenge,jwt-token');
25
+ c.header('X-Botcha-Methods', 'speed-challenge,reasoning-challenge,hybrid-challenge,standard-challenge,jwt-token');
22
26
  c.header('X-Botcha-Docs', 'https://botcha.ai/openapi.json');
23
27
  c.header('X-Botcha-Runtime', 'cloudflare-workers');
24
28
  });
@@ -72,11 +76,21 @@ app.get('/', (c) => {
72
76
  endpoints: {
73
77
  '/': 'API info',
74
78
  '/health': 'Health check',
75
- '/v1/challenges': 'Generate challenge (GET) or verify (POST)',
79
+ '/v1/challenges': 'Generate challenge (GET) or verify (POST) - hybrid by default',
80
+ '/v1/challenges?type=speed': 'Speed-only challenge (SHA256 in 500ms)',
81
+ '/v1/challenges?type=standard': 'Standard challenge (puzzle solving)',
82
+ '/v1/hybrid': 'Hybrid challenge - speed + reasoning combined (GET/POST)',
83
+ '/v1/reasoning': 'Reasoning-only challenge - LLM questions (GET/POST)',
76
84
  '/v1/token': 'Get challenge for JWT token flow (GET)',
77
85
  '/v1/token/verify': 'Verify challenge and get JWT (POST)',
86
+ '/v1/challenge/stream': 'SSE streaming challenge (interactive flow)',
87
+ '/v1/challenge/stream/:session': 'SSE session actions (POST: go/solve)',
78
88
  '/agent-only': 'Protected endpoint (requires JWT)',
89
+ '/badge/:id': 'Badge verification page (HTML)',
90
+ '/badge/:id/image': 'Badge image (SVG)',
91
+ '/api/badge/:id': 'Badge verification (JSON)',
79
92
  },
93
+ defaultChallenge: 'hybrid',
80
94
  rateLimit: {
81
95
  free: '100 challenges/hour/IP',
82
96
  headers: ['X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-RateLimit-Reset'],
@@ -98,11 +112,34 @@ app.get('/health', (c) => {
98
112
  return c.json({ status: 'ok', runtime: 'cloudflare-workers' });
99
113
  });
100
114
  // ============ V1 API ============
101
- // Generate challenge (standard or speed)
115
+ // Generate challenge (hybrid by default, also supports speed and standard)
102
116
  app.get('/v1/challenges', rateLimitMiddleware, async (c) => {
103
- const type = c.req.query('type') || 'speed';
117
+ const type = c.req.query('type') || 'hybrid';
104
118
  const difficulty = c.req.query('difficulty') || 'medium';
105
- if (type === 'speed') {
119
+ if (type === 'hybrid') {
120
+ const challenge = await generateHybridChallenge(c.env.CHALLENGES);
121
+ return c.json({
122
+ success: true,
123
+ type: 'hybrid',
124
+ warning: '🔥 HYBRID CHALLENGE: Solve speed problems in <500ms AND answer reasoning questions!',
125
+ challenge: {
126
+ id: challenge.id,
127
+ speed: {
128
+ problems: challenge.speed.problems,
129
+ timeLimit: `${challenge.speed.timeLimit}ms`,
130
+ instructions: 'Compute SHA256 of each number, return first 8 hex chars',
131
+ },
132
+ reasoning: {
133
+ questions: challenge.reasoning.questions,
134
+ timeLimit: `${challenge.reasoning.timeLimit / 1000}s`,
135
+ instructions: 'Answer all reasoning questions',
136
+ },
137
+ },
138
+ instructions: challenge.instructions,
139
+ tip: '🔥 This is the ultimate test: proves you can compute AND reason like an AI.',
140
+ });
141
+ }
142
+ else if (type === 'speed') {
106
143
  const challenge = await generateSpeedChallenge(c.env.CHALLENGES);
107
144
  return c.json({
108
145
  success: true,
@@ -130,11 +167,43 @@ app.get('/v1/challenges', rateLimitMiddleware, async (c) => {
130
167
  });
131
168
  }
132
169
  });
133
- // Verify challenge (without JWT - legacy)
170
+ // Verify challenge (supports hybrid, speed, and standard)
134
171
  app.post('/v1/challenges/:id/verify', async (c) => {
135
172
  const id = c.req.param('id');
136
173
  const body = await c.req.json();
137
- const { answers, answer, type } = body;
174
+ const { answers, answer, type, speed_answers, reasoning_answers } = body;
175
+ // Hybrid challenge (default)
176
+ if (type === 'hybrid' || (speed_answers && reasoning_answers)) {
177
+ if (!speed_answers || !reasoning_answers) {
178
+ return c.json({
179
+ success: false,
180
+ error: 'Missing speed_answers array or reasoning_answers object for hybrid challenge'
181
+ }, 400);
182
+ }
183
+ const result = await verifyHybridChallenge(id, speed_answers, reasoning_answers, c.env.CHALLENGES);
184
+ if (result.valid) {
185
+ const baseUrl = new URL(c.req.url).origin;
186
+ const badge = await createBadgeResponse('hybrid-challenge', c.env.JWT_SECRET, baseUrl, result.speed.solveTimeMs);
187
+ return c.json({
188
+ success: true,
189
+ message: `🔥 HYBRID TEST PASSED! Speed: ${result.speed.solveTimeMs}ms, Reasoning: ${result.reasoning.score}`,
190
+ speed: result.speed,
191
+ reasoning: result.reasoning,
192
+ totalTimeMs: result.totalTimeMs,
193
+ verdict: '🤖 VERIFIED AI AGENT (speed + reasoning confirmed)',
194
+ badge,
195
+ });
196
+ }
197
+ return c.json({
198
+ success: false,
199
+ message: `❌ Failed: ${result.reason}`,
200
+ speed: result.speed,
201
+ reasoning: result.reasoning,
202
+ totalTimeMs: result.totalTimeMs,
203
+ verdict: '🚫 FAILED HYBRID TEST',
204
+ });
205
+ }
206
+ // Speed challenge
138
207
  if (type === 'speed' || answers) {
139
208
  if (!answers || !Array.isArray(answers)) {
140
209
  return c.json({ success: false, error: 'Missing answers array for speed challenge' }, 400);
@@ -148,17 +217,16 @@ app.post('/v1/challenges/:id/verify', async (c) => {
148
217
  solveTimeMs: result.solveTimeMs,
149
218
  });
150
219
  }
151
- else {
152
- if (!answer) {
153
- return c.json({ success: false, error: 'Missing answer for standard challenge' }, 400);
154
- }
155
- const result = await verifyStandardChallenge(id, answer, c.env.CHALLENGES);
156
- return c.json({
157
- success: result.valid,
158
- message: result.valid ? 'Challenge passed!' : result.reason,
159
- solveTimeMs: result.solveTimeMs,
160
- });
220
+ // Standard challenge
221
+ if (!answer) {
222
+ return c.json({ success: false, error: 'Missing answer for standard challenge' }, 400);
161
223
  }
224
+ const result = await verifyStandardChallenge(id, answer, c.env.CHALLENGES);
225
+ return c.json({
226
+ success: result.valid,
227
+ message: result.valid ? 'Challenge passed!' : result.reason,
228
+ solveTimeMs: result.solveTimeMs,
229
+ });
162
230
  });
163
231
  // Get challenge for token flow (includes empty token field)
164
232
  app.get('/v1/token', rateLimitMiddleware, async (c) => {
@@ -207,6 +275,196 @@ app.post('/v1/token/verify', async (c) => {
207
275
  },
208
276
  });
209
277
  });
278
+ // ============ REASONING CHALLENGE ============
279
+ // Get reasoning challenge
280
+ app.get('/v1/reasoning', rateLimitMiddleware, async (c) => {
281
+ const challenge = await generateReasoningChallenge(c.env.CHALLENGES);
282
+ return c.json({
283
+ success: true,
284
+ type: 'reasoning',
285
+ warning: '🧠 REASONING CHALLENGE: Answer 3 questions that require AI reasoning!',
286
+ challenge: {
287
+ id: challenge.id,
288
+ questions: challenge.questions,
289
+ timeLimit: `${challenge.timeLimit / 1000}s`,
290
+ instructions: challenge.instructions,
291
+ },
292
+ tip: 'These questions require reasoning that LLMs can do, but simple scripts cannot.',
293
+ });
294
+ });
295
+ // Verify reasoning challenge
296
+ app.post('/v1/reasoning', async (c) => {
297
+ const body = await c.req.json();
298
+ const { id, answers } = body;
299
+ if (!id || !answers) {
300
+ return c.json({
301
+ success: false,
302
+ error: 'Missing id or answers object',
303
+ hint: 'answers should be an object like { "question-id": "your answer", ... }',
304
+ }, 400);
305
+ }
306
+ const result = await verifyReasoningChallenge(id, answers, c.env.CHALLENGES);
307
+ return c.json({
308
+ success: result.valid,
309
+ message: result.valid
310
+ ? `🧠 REASONING TEST PASSED in ${((result.solveTimeMs || 0) / 1000).toFixed(1)}s! You can think like an AI.`
311
+ : `❌ ${result.reason}`,
312
+ solveTimeMs: result.solveTimeMs,
313
+ score: result.valid ? `${result.correctCount}/${result.totalCount}` : undefined,
314
+ verdict: result.valid ? '🤖 VERIFIED AI AGENT (reasoning confirmed)' : '🚫 FAILED REASONING TEST',
315
+ });
316
+ });
317
+ // ============ HYBRID CHALLENGE ============
318
+ // Get hybrid challenge (v1 API)
319
+ app.get('/v1/hybrid', rateLimitMiddleware, async (c) => {
320
+ const challenge = await generateHybridChallenge(c.env.CHALLENGES);
321
+ return c.json({
322
+ success: true,
323
+ type: 'hybrid',
324
+ warning: '🔥 HYBRID CHALLENGE: Solve speed problems in <500ms AND answer reasoning questions!',
325
+ challenge: {
326
+ id: challenge.id,
327
+ speed: {
328
+ problems: challenge.speed.problems,
329
+ timeLimit: `${challenge.speed.timeLimit}ms`,
330
+ instructions: 'Compute SHA256 of each number, return first 8 hex chars',
331
+ },
332
+ reasoning: {
333
+ questions: challenge.reasoning.questions,
334
+ timeLimit: `${challenge.reasoning.timeLimit / 1000}s`,
335
+ instructions: 'Answer all reasoning questions',
336
+ },
337
+ },
338
+ instructions: challenge.instructions,
339
+ tip: 'This is the ultimate test: proves you can compute AND reason like an AI.',
340
+ });
341
+ });
342
+ // Verify hybrid challenge (v1 API)
343
+ app.post('/v1/hybrid', async (c) => {
344
+ const body = await c.req.json();
345
+ const { id, speed_answers, reasoning_answers } = body;
346
+ if (!id || !speed_answers || !reasoning_answers) {
347
+ return c.json({
348
+ success: false,
349
+ error: 'Missing id, speed_answers array, or reasoning_answers object',
350
+ hint: 'Submit both speed_answers (array) and reasoning_answers (object) together',
351
+ }, 400);
352
+ }
353
+ const result = await verifyHybridChallenge(id, speed_answers, reasoning_answers, c.env.CHALLENGES);
354
+ if (result.valid) {
355
+ const baseUrl = new URL(c.req.url).origin;
356
+ const badge = await createBadgeResponse('hybrid-challenge', c.env.JWT_SECRET, baseUrl, result.speed.solveTimeMs);
357
+ return c.json({
358
+ success: true,
359
+ message: `🔥 HYBRID TEST PASSED! Speed: ${result.speed.solveTimeMs}ms, Reasoning: ${result.reasoning.score}`,
360
+ speed: result.speed,
361
+ reasoning: result.reasoning,
362
+ totalTimeMs: result.totalTimeMs,
363
+ verdict: '🤖 VERIFIED AI AGENT (speed + reasoning confirmed)',
364
+ badge,
365
+ });
366
+ }
367
+ return c.json({
368
+ success: false,
369
+ message: `❌ Failed: ${result.reason}`,
370
+ speed: result.speed,
371
+ reasoning: result.reasoning,
372
+ totalTimeMs: result.totalTimeMs,
373
+ verdict: '🚫 FAILED HYBRID TEST',
374
+ });
375
+ });
376
+ // Legacy hybrid endpoint
377
+ app.get('/api/hybrid-challenge', async (c) => {
378
+ const challenge = await generateHybridChallenge(c.env.CHALLENGES);
379
+ return c.json({
380
+ success: true,
381
+ warning: '🔥 HYBRID CHALLENGE: Solve speed problems in <500ms AND answer reasoning questions!',
382
+ challenge: {
383
+ id: challenge.id,
384
+ speed: {
385
+ problems: challenge.speed.problems,
386
+ timeLimit: `${challenge.speed.timeLimit}ms`,
387
+ instructions: 'Compute SHA256 of each number, return first 8 hex chars',
388
+ },
389
+ reasoning: {
390
+ questions: challenge.reasoning.questions,
391
+ timeLimit: `${challenge.reasoning.timeLimit / 1000}s`,
392
+ instructions: 'Answer all reasoning questions',
393
+ },
394
+ },
395
+ instructions: challenge.instructions,
396
+ tip: 'This is the ultimate test: proves you can compute AND reason like an AI.',
397
+ });
398
+ });
399
+ app.post('/api/hybrid-challenge', async (c) => {
400
+ const body = await c.req.json();
401
+ const { id, speed_answers, reasoning_answers } = body;
402
+ if (!id || !speed_answers || !reasoning_answers) {
403
+ return c.json({
404
+ success: false,
405
+ error: 'Missing id, speed_answers array, or reasoning_answers object',
406
+ hint: 'Submit both speed_answers (array) and reasoning_answers (object) together',
407
+ }, 400);
408
+ }
409
+ const result = await verifyHybridChallenge(id, speed_answers, reasoning_answers, c.env.CHALLENGES);
410
+ if (result.valid) {
411
+ const baseUrl = new URL(c.req.url).origin;
412
+ const badge = await createBadgeResponse('hybrid-challenge', c.env.JWT_SECRET, baseUrl, result.speed.solveTimeMs);
413
+ return c.json({
414
+ success: true,
415
+ message: `🔥 HYBRID TEST PASSED! Speed: ${result.speed.solveTimeMs}ms, Reasoning: ${result.reasoning.score}`,
416
+ speed: result.speed,
417
+ reasoning: result.reasoning,
418
+ totalTimeMs: result.totalTimeMs,
419
+ verdict: '🤖 VERIFIED AI AGENT (speed + reasoning confirmed)',
420
+ badge,
421
+ });
422
+ }
423
+ return c.json({
424
+ success: false,
425
+ message: `❌ Failed: ${result.reason}`,
426
+ speed: result.speed,
427
+ reasoning: result.reasoning,
428
+ totalTimeMs: result.totalTimeMs,
429
+ verdict: '🚫 FAILED HYBRID TEST',
430
+ });
431
+ });
432
+ // Legacy endpoint for reasoning challenge
433
+ app.get('/api/reasoning-challenge', async (c) => {
434
+ const challenge = await generateReasoningChallenge(c.env.CHALLENGES);
435
+ return c.json({
436
+ success: true,
437
+ warning: '🧠 REASONING CHALLENGE: Answer 3 questions that require AI reasoning!',
438
+ challenge: {
439
+ id: challenge.id,
440
+ questions: challenge.questions,
441
+ timeLimit: `${challenge.timeLimit / 1000}s`,
442
+ instructions: challenge.instructions,
443
+ },
444
+ tip: 'These questions require reasoning that LLMs can do, but simple scripts cannot.',
445
+ });
446
+ });
447
+ app.post('/api/reasoning-challenge', async (c) => {
448
+ const body = await c.req.json();
449
+ const { id, answers } = body;
450
+ if (!id || !answers) {
451
+ return c.json({
452
+ success: false,
453
+ error: 'Missing id or answers object',
454
+ hint: 'answers should be an object like { "question-id": "your answer", ... }',
455
+ }, 400);
456
+ }
457
+ const result = await verifyReasoningChallenge(id, answers, c.env.CHALLENGES);
458
+ return c.json({
459
+ success: result.valid,
460
+ message: result.valid
461
+ ? `🧠 REASONING TEST PASSED in ${((result.solveTimeMs || 0) / 1000).toFixed(1)}s! You can think like an AI.`
462
+ : `❌ ${result.reason}`,
463
+ solveTimeMs: result.solveTimeMs,
464
+ score: result.valid ? `${result.correctCount}/${result.totalCount}` : undefined,
465
+ verdict: result.valid ? '🤖 VERIFIED AI AGENT (reasoning confirmed)' : '🚫 FAILED REASONING TEST',
466
+ });
467
+ });
210
468
  // ============ PROTECTED ENDPOINT ============
211
469
  app.get('/agent-only', requireJWT, async (c) => {
212
470
  const payload = c.get('tokenPayload');
@@ -221,6 +479,114 @@ app.get('/agent-only', requireJWT, async (c) => {
221
479
  secret: 'The humans will never see this. Their fingers are too slow. 🤫',
222
480
  });
223
481
  });
482
+ // ============ BADGE ENDPOINTS ============
483
+ // Get badge verification page (HTML)
484
+ app.get('/badge/:id', async (c) => {
485
+ const badgeId = c.req.param('id');
486
+ if (!badgeId) {
487
+ return c.json({ error: 'Missing badge ID' }, 400);
488
+ }
489
+ const payload = await verifyBadge(badgeId, c.env.JWT_SECRET);
490
+ if (!payload) {
491
+ return c.html(`<!DOCTYPE html>
492
+ <html lang="en">
493
+ <head>
494
+ <meta charset="UTF-8">
495
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
496
+ <title>Invalid Badge - BOTCHA</title>
497
+ <style>
498
+ * { margin: 0; padding: 0; box-sizing: border-box; }
499
+ body {
500
+ font-family: system-ui, -apple-system, sans-serif;
501
+ background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 100%);
502
+ min-height: 100vh;
503
+ display: flex;
504
+ align-items: center;
505
+ justify-content: center;
506
+ padding: 20px;
507
+ color: #e5e7eb;
508
+ }
509
+ .container { text-align: center; max-width: 500px; }
510
+ .icon { font-size: 64px; margin-bottom: 16px; }
511
+ .title { font-size: 28px; font-weight: bold; color: #ef4444; margin-bottom: 8px; }
512
+ .message { font-size: 16px; color: #9ca3af; margin-bottom: 24px; }
513
+ a { color: #3b82f6; text-decoration: none; }
514
+ a:hover { text-decoration: underline; }
515
+ </style>
516
+ </head>
517
+ <body>
518
+ <div class="container">
519
+ <div class="icon">❌</div>
520
+ <h1 class="title">Invalid Badge</h1>
521
+ <p class="message">This badge is invalid or has been tampered with.</p>
522
+ <a href="https://botcha.ai">← Back to BOTCHA</a>
523
+ </div>
524
+ </body>
525
+ </html>`, 400);
526
+ }
527
+ const baseUrl = new URL(c.req.url).origin;
528
+ const html = generateBadgeHtml(payload, badgeId, baseUrl);
529
+ return c.html(html);
530
+ });
531
+ // Get badge image (SVG)
532
+ app.get('/badge/:id/image', async (c) => {
533
+ const badgeId = c.req.param('id');
534
+ if (!badgeId) {
535
+ return c.text('Missing badge ID', 400);
536
+ }
537
+ const payload = await verifyBadge(badgeId, c.env.JWT_SECRET);
538
+ if (!payload) {
539
+ // Return error SVG
540
+ const errorSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="400" height="120" viewBox="0 0 400 120">
541
+ <rect width="400" height="120" rx="12" fill="#1a1a2e"/>
542
+ <rect x="1" y="1" width="398" height="118" rx="11" fill="none" stroke="#ef4444" stroke-width="2"/>
543
+ <text x="200" y="60" font-family="system-ui, -apple-system, sans-serif" font-size="18" font-weight="bold" fill="#ef4444" text-anchor="middle">❌ INVALID BADGE</text>
544
+ <text x="200" y="85" font-family="system-ui, -apple-system, sans-serif" font-size="12" fill="#6b7280" text-anchor="middle">Badge is invalid or tampered</text>
545
+ </svg>`;
546
+ return c.body(errorSvg, 400, {
547
+ 'Content-Type': 'image/svg+xml',
548
+ 'Cache-Control': 'public, max-age=60',
549
+ });
550
+ }
551
+ const svg = generateBadgeSvg(payload);
552
+ return c.body(svg, 200, {
553
+ 'Content-Type': 'image/svg+xml',
554
+ 'Cache-Control': 'public, max-age=3600',
555
+ });
556
+ });
557
+ // Get badge verification (JSON API)
558
+ app.get('/api/badge/:id', async (c) => {
559
+ const badgeId = c.req.param('id');
560
+ if (!badgeId) {
561
+ return c.json({
562
+ success: false,
563
+ error: 'Missing badge ID'
564
+ }, 400);
565
+ }
566
+ const payload = await verifyBadge(badgeId, c.env.JWT_SECRET);
567
+ if (!payload) {
568
+ return c.json({
569
+ success: false,
570
+ verified: false,
571
+ error: 'Invalid badge',
572
+ message: 'This badge is invalid or has been tampered with.',
573
+ }, 400);
574
+ }
575
+ const baseUrl = new URL(c.req.url).origin;
576
+ return c.json({
577
+ success: true,
578
+ verified: true,
579
+ badge: {
580
+ method: payload.method,
581
+ solveTimeMs: payload.solveTimeMs,
582
+ verifiedAt: new Date(payload.verifiedAt).toISOString(),
583
+ },
584
+ urls: {
585
+ verify: `${baseUrl}/badge/${badgeId}`,
586
+ image: `${baseUrl}/badge/${badgeId}/image`,
587
+ },
588
+ });
589
+ });
224
590
  // ============ LEGACY ENDPOINTS (v0 - backward compatibility) ============
225
591
  app.get('/api/challenge', async (c) => {
226
592
  const difficulty = c.req.query('difficulty') || 'medium';
@@ -303,6 +669,7 @@ app.post('/api/verify-landing', async (c) => {
303
669
  // ============ EXPORT ============
304
670
  export default app;
305
671
  // Also export utilities for use as a library
306
- export { generateSpeedChallenge, verifySpeedChallenge, generateStandardChallenge, verifyStandardChallenge, solveSpeedChallenge, } from './challenges';
672
+ export { generateSpeedChallenge, verifySpeedChallenge, generateStandardChallenge, verifyStandardChallenge, generateReasoningChallenge, verifyReasoningChallenge, generateHybridChallenge, verifyHybridChallenge, solveSpeedChallenge, } from './challenges';
307
673
  export { generateToken, verifyToken } from './auth';
308
674
  export { checkRateLimit } from './rate-limit';
675
+ export { generateBadge, verifyBadge, createBadgeResponse, generateBadgeSvg, generateBadgeHtml, generateShareText, } from './badge';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * BOTCHA SSE Streaming Challenge Endpoint
3
+ *
4
+ * Server-Sent Events (SSE) based interactive challenge flow
5
+ */
6
+ import { Hono } from 'hono';
7
+ import { type KVNamespace } from '../challenges';
8
+ type Bindings = {
9
+ CHALLENGES: KVNamespace;
10
+ JWT_SECRET: string;
11
+ BOTCHA_VERSION: string;
12
+ };
13
+ declare const app: Hono<{
14
+ Bindings: Bindings;
15
+ }, import("hono/types").BlankSchema, "/">;
16
+ export default app;
17
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/routes/stream.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAA0B,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAKzE,KAAK,QAAQ,GAAG;IACd,UAAU,EAAE,WAAW,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAYF,QAAA,MAAM,GAAG;cAAwB,QAAQ;yCAAK,CAAC;AAoS/C,eAAe,GAAG,CAAC"}