@dupecom/botcha-cloudflare 0.9.0 → 0.10.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/apps.d.ts +73 -7
- package/dist/apps.d.ts.map +1 -1
- package/dist/apps.js +164 -9
- package/dist/challenges.d.ts.map +1 -1
- package/dist/challenges.js +5 -4
- package/dist/dashboard/api.d.ts +70 -0
- package/dist/dashboard/api.d.ts.map +1 -0
- package/dist/dashboard/api.js +546 -0
- package/dist/dashboard/auth.d.ts +183 -0
- package/dist/dashboard/auth.d.ts.map +1 -0
- package/dist/dashboard/auth.js +401 -0
- package/dist/dashboard/device-code.d.ts +43 -0
- package/dist/dashboard/device-code.d.ts.map +1 -0
- package/dist/dashboard/device-code.js +77 -0
- package/dist/dashboard/index.d.ts +31 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +64 -0
- package/dist/dashboard/layout.d.ts +47 -0
- package/dist/dashboard/layout.d.ts.map +1 -0
- package/dist/dashboard/layout.js +38 -0
- package/dist/dashboard/pages.d.ts +11 -0
- package/dist/dashboard/pages.d.ts.map +1 -0
- package/dist/dashboard/pages.js +18 -0
- package/dist/dashboard/styles.d.ts +11 -0
- package/dist/dashboard/styles.d.ts.map +1 -0
- package/dist/dashboard/styles.js +633 -0
- package/dist/email.d.ts +44 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +119 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +238 -10
- package/dist/routes/stream.js +1 -1
- package/dist/static.d.ts +214 -3
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +195 -12
- package/package.json +1 -1
package/dist/apps.d.ts
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* - SHA-256 secret hashing (never store plaintext)
|
|
7
7
|
* - KV storage for app configs
|
|
8
8
|
* - Rate limit tracking per app
|
|
9
|
+
* - Email verification for account recovery
|
|
10
|
+
* - Email→app_id reverse index for recovery lookups
|
|
11
|
+
* - Secret rotation with email notification
|
|
9
12
|
*/
|
|
10
13
|
export type KVNamespace = {
|
|
11
14
|
get: (key: string, type?: 'text' | 'json' | 'arrayBuffer' | 'stream') => Promise<any>;
|
|
@@ -22,6 +25,10 @@ export interface AppConfig {
|
|
|
22
25
|
secret_hash: string;
|
|
23
26
|
created_at: number;
|
|
24
27
|
rate_limit: number;
|
|
28
|
+
email: string;
|
|
29
|
+
email_verified: boolean;
|
|
30
|
+
email_verification_code?: string;
|
|
31
|
+
email_verification_expires?: number;
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
34
|
* Result of app creation (includes plaintext secret - only shown once!)
|
|
@@ -29,7 +36,20 @@ export interface AppConfig {
|
|
|
29
36
|
export interface CreateAppResult {
|
|
30
37
|
app_id: string;
|
|
31
38
|
app_secret: string;
|
|
39
|
+
email: string;
|
|
40
|
+
email_verified: boolean;
|
|
41
|
+
verification_required: boolean;
|
|
32
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Public app info returned by getApp (excludes secrets and internal fields)
|
|
45
|
+
*/
|
|
46
|
+
export type PublicAppConfig = {
|
|
47
|
+
app_id: string;
|
|
48
|
+
created_at: number;
|
|
49
|
+
rate_limit: number;
|
|
50
|
+
email: string;
|
|
51
|
+
email_verified: boolean;
|
|
52
|
+
};
|
|
33
53
|
/**
|
|
34
54
|
* Generate a crypto-random app ID
|
|
35
55
|
* Format: 'app_' + 16 hex chars
|
|
@@ -52,6 +72,10 @@ export declare function generateAppSecret(): string;
|
|
|
52
72
|
* @returns SHA-256 hash as hex string
|
|
53
73
|
*/
|
|
54
74
|
export declare function hashSecret(secret: string): Promise<string>;
|
|
75
|
+
/**
|
|
76
|
+
* Generate a 6-digit numeric verification code
|
|
77
|
+
*/
|
|
78
|
+
export declare function generateVerificationCode(): string;
|
|
55
79
|
/**
|
|
56
80
|
* Create a new app with crypto-random credentials
|
|
57
81
|
*
|
|
@@ -60,15 +84,52 @@ export declare function hashSecret(secret: string): Promise<string>;
|
|
|
60
84
|
* - app_secret: 'sk_' + 32 hex chars
|
|
61
85
|
*
|
|
62
86
|
* Stores in KV at key `app:{app_id}` with:
|
|
63
|
-
* - app_id
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* - rate_limit (default: 100 req/hour)
|
|
87
|
+
* - app_id, secret_hash (SHA-256), created_at, rate_limit, email, email_verified
|
|
88
|
+
*
|
|
89
|
+
* Also stores email→app_id reverse index at `email:{email}` for recovery lookups.
|
|
67
90
|
*
|
|
68
91
|
* @param kv - KV namespace for storage
|
|
69
|
-
* @
|
|
92
|
+
* @param email - Required owner email address
|
|
93
|
+
* @returns {app_id, app_secret, email, email_verified, verification_required}
|
|
94
|
+
*/
|
|
95
|
+
export declare function createApp(kv: KVNamespace, email: string): Promise<CreateAppResult>;
|
|
96
|
+
/**
|
|
97
|
+
* Get the plaintext verification code for an app (internal use only — for sending via email).
|
|
98
|
+
*
|
|
99
|
+
* This is a separate step because createApp returns the code hash, not the plaintext.
|
|
100
|
+
* Instead, we generate and return code in createApp flow; this function regenerates
|
|
101
|
+
* a new code for resend scenarios.
|
|
70
102
|
*/
|
|
71
|
-
export declare function
|
|
103
|
+
export declare function regenerateVerificationCode(kv: KVNamespace, app_id: string): Promise<{
|
|
104
|
+
code: string;
|
|
105
|
+
} | null>;
|
|
106
|
+
/**
|
|
107
|
+
* Verify email with the 6-digit code
|
|
108
|
+
*
|
|
109
|
+
* @returns { verified: true } on success, { verified: false, reason } on failure
|
|
110
|
+
*/
|
|
111
|
+
export declare function verifyEmailCode(kv: KVNamespace, app_id: string, code: string): Promise<{
|
|
112
|
+
verified: boolean;
|
|
113
|
+
reason?: string;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Look up app_id by email (for account recovery)
|
|
117
|
+
*
|
|
118
|
+
* Uses the email→app_id reverse index stored in KV.
|
|
119
|
+
* Only works for apps with verified emails.
|
|
120
|
+
*/
|
|
121
|
+
export declare function getAppByEmail(kv: KVNamespace, email: string): Promise<{
|
|
122
|
+
app_id: string;
|
|
123
|
+
email_verified: boolean;
|
|
124
|
+
} | null>;
|
|
125
|
+
/**
|
|
126
|
+
* Rotate app secret — generates a new secret and invalidates the old one.
|
|
127
|
+
*
|
|
128
|
+
* @returns New app_secret (plaintext, only returned once) or null on failure
|
|
129
|
+
*/
|
|
130
|
+
export declare function rotateAppSecret(kv: KVNamespace, app_id: string): Promise<{
|
|
131
|
+
app_secret: string;
|
|
132
|
+
} | null>;
|
|
72
133
|
/**
|
|
73
134
|
* Get app configuration by app_id
|
|
74
135
|
*
|
|
@@ -78,7 +139,12 @@ export declare function createApp(kv: KVNamespace): Promise<CreateAppResult>;
|
|
|
78
139
|
* @param app_id - The app ID to retrieve
|
|
79
140
|
* @returns App config (without secret_hash) or null if not found
|
|
80
141
|
*/
|
|
81
|
-
export declare function getApp(kv: KVNamespace, app_id: string): Promise<
|
|
142
|
+
export declare function getApp(kv: KVNamespace, app_id: string): Promise<PublicAppConfig | null>;
|
|
143
|
+
/**
|
|
144
|
+
* Get raw app config (internal use only — includes secret_hash)
|
|
145
|
+
* Used by validateAppSecret and dashboard auth.
|
|
146
|
+
*/
|
|
147
|
+
export declare function getAppRaw(kv: KVNamespace, app_id: string): Promise<AppConfig | null>;
|
|
82
148
|
/**
|
|
83
149
|
* Validate an app secret against stored hash
|
|
84
150
|
*
|
package/dist/apps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"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"}
|
package/dist/apps.js
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* - SHA-256 secret hashing (never store plaintext)
|
|
7
7
|
* - KV storage for app configs
|
|
8
8
|
* - Rate limit tracking per app
|
|
9
|
+
* - Email verification for account recovery
|
|
10
|
+
* - Email→app_id reverse index for recovery lookups
|
|
11
|
+
* - Secret rotation with email notification
|
|
9
12
|
*/
|
|
10
13
|
// ============ CRYPTO UTILITIES ============
|
|
11
14
|
/**
|
|
@@ -51,6 +54,16 @@ export async function hashSecret(secret) {
|
|
|
51
54
|
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
52
55
|
return hashHex;
|
|
53
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Generate a 6-digit numeric verification code
|
|
59
|
+
*/
|
|
60
|
+
export function generateVerificationCode() {
|
|
61
|
+
const bytes = new Uint8Array(4);
|
|
62
|
+
crypto.getRandomValues(bytes);
|
|
63
|
+
// Convert to number and mod 1,000,000 to get 6 digits
|
|
64
|
+
const num = ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0;
|
|
65
|
+
return (num % 1000000).toString().padStart(6, '0');
|
|
66
|
+
}
|
|
54
67
|
// ============ APP MANAGEMENT ============
|
|
55
68
|
/**
|
|
56
69
|
* Create a new app with crypto-random credentials
|
|
@@ -60,32 +73,156 @@ export async function hashSecret(secret) {
|
|
|
60
73
|
* - app_secret: 'sk_' + 32 hex chars
|
|
61
74
|
*
|
|
62
75
|
* Stores in KV at key `app:{app_id}` with:
|
|
63
|
-
* - app_id
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* - rate_limit (default: 100 req/hour)
|
|
76
|
+
* - app_id, secret_hash (SHA-256), created_at, rate_limit, email, email_verified
|
|
77
|
+
*
|
|
78
|
+
* Also stores email→app_id reverse index at `email:{email}` for recovery lookups.
|
|
67
79
|
*
|
|
68
80
|
* @param kv - KV namespace for storage
|
|
69
|
-
* @
|
|
81
|
+
* @param email - Required owner email address
|
|
82
|
+
* @returns {app_id, app_secret, email, email_verified, verification_required}
|
|
70
83
|
*/
|
|
71
|
-
export async function createApp(kv) {
|
|
84
|
+
export async function createApp(kv, email) {
|
|
72
85
|
const app_id = generateAppId();
|
|
73
86
|
const app_secret = generateAppSecret();
|
|
74
87
|
const secret_hash = await hashSecret(app_secret);
|
|
88
|
+
// Generate email verification code
|
|
89
|
+
const verificationCode = generateVerificationCode();
|
|
90
|
+
const verificationCodeHash = await hashSecret(verificationCode);
|
|
75
91
|
const config = {
|
|
76
92
|
app_id,
|
|
77
93
|
secret_hash,
|
|
78
94
|
created_at: Date.now(),
|
|
79
95
|
rate_limit: 100, // Default: 100 requests/hour
|
|
96
|
+
email,
|
|
97
|
+
email_verified: false,
|
|
98
|
+
email_verification_code: verificationCodeHash,
|
|
99
|
+
email_verification_expires: Date.now() + 10 * 60 * 1000, // 10 minutes
|
|
80
100
|
};
|
|
81
|
-
// Store
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
// Store app config and email→app_id index in parallel
|
|
102
|
+
await Promise.all([
|
|
103
|
+
kv.put(`app:${app_id}`, JSON.stringify(config)),
|
|
104
|
+
kv.put(`email:${email.toLowerCase()}`, app_id),
|
|
105
|
+
]);
|
|
84
106
|
return {
|
|
85
107
|
app_id,
|
|
86
108
|
app_secret, // ONLY returned at creation time!
|
|
109
|
+
email,
|
|
110
|
+
email_verified: false,
|
|
111
|
+
verification_required: true,
|
|
87
112
|
};
|
|
88
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Get the plaintext verification code for an app (internal use only — for sending via email).
|
|
116
|
+
*
|
|
117
|
+
* This is a separate step because createApp returns the code hash, not the plaintext.
|
|
118
|
+
* Instead, we generate and return code in createApp flow; this function regenerates
|
|
119
|
+
* a new code for resend scenarios.
|
|
120
|
+
*/
|
|
121
|
+
export async function regenerateVerificationCode(kv, app_id) {
|
|
122
|
+
try {
|
|
123
|
+
const data = await kv.get(`app:${app_id}`, 'text');
|
|
124
|
+
if (!data)
|
|
125
|
+
return null;
|
|
126
|
+
const config = JSON.parse(data);
|
|
127
|
+
if (config.email_verified)
|
|
128
|
+
return null; // Already verified
|
|
129
|
+
const code = generateVerificationCode();
|
|
130
|
+
const codeHash = await hashSecret(code);
|
|
131
|
+
config.email_verification_code = codeHash;
|
|
132
|
+
config.email_verification_expires = Date.now() + 10 * 60 * 1000;
|
|
133
|
+
await kv.put(`app:${app_id}`, JSON.stringify(config));
|
|
134
|
+
return { code };
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
console.error(`Failed to regenerate verification code for ${app_id}:`, error);
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Verify email with the 6-digit code
|
|
143
|
+
*
|
|
144
|
+
* @returns { verified: true } on success, { verified: false, reason } on failure
|
|
145
|
+
*/
|
|
146
|
+
export async function verifyEmailCode(kv, app_id, code) {
|
|
147
|
+
try {
|
|
148
|
+
const data = await kv.get(`app:${app_id}`, 'text');
|
|
149
|
+
if (!data) {
|
|
150
|
+
return { verified: false, reason: 'App not found' };
|
|
151
|
+
}
|
|
152
|
+
const config = JSON.parse(data);
|
|
153
|
+
if (config.email_verified) {
|
|
154
|
+
return { verified: false, reason: 'Email already verified' };
|
|
155
|
+
}
|
|
156
|
+
if (!config.email_verification_code || !config.email_verification_expires) {
|
|
157
|
+
return { verified: false, reason: 'No verification pending' };
|
|
158
|
+
}
|
|
159
|
+
if (Date.now() > config.email_verification_expires) {
|
|
160
|
+
return { verified: false, reason: 'Verification code expired' };
|
|
161
|
+
}
|
|
162
|
+
// Compare hashed codes
|
|
163
|
+
const providedHash = await hashSecret(code);
|
|
164
|
+
if (providedHash !== config.email_verification_code) {
|
|
165
|
+
return { verified: false, reason: 'Invalid verification code' };
|
|
166
|
+
}
|
|
167
|
+
// Mark email as verified, clear verification fields
|
|
168
|
+
config.email_verified = true;
|
|
169
|
+
delete config.email_verification_code;
|
|
170
|
+
delete config.email_verification_expires;
|
|
171
|
+
await kv.put(`app:${app_id}`, JSON.stringify(config));
|
|
172
|
+
return { verified: true };
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
console.error(`Failed to verify email for ${app_id}:`, error);
|
|
176
|
+
return { verified: false, reason: 'Verification failed' };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Look up app_id by email (for account recovery)
|
|
181
|
+
*
|
|
182
|
+
* Uses the email→app_id reverse index stored in KV.
|
|
183
|
+
* Only works for apps with verified emails.
|
|
184
|
+
*/
|
|
185
|
+
export async function getAppByEmail(kv, email) {
|
|
186
|
+
try {
|
|
187
|
+
const app_id = await kv.get(`email:${email.toLowerCase()}`, 'text');
|
|
188
|
+
if (!app_id)
|
|
189
|
+
return null;
|
|
190
|
+
const data = await kv.get(`app:${app_id}`, 'text');
|
|
191
|
+
if (!data)
|
|
192
|
+
return null;
|
|
193
|
+
const config = JSON.parse(data);
|
|
194
|
+
return {
|
|
195
|
+
app_id: config.app_id,
|
|
196
|
+
email_verified: config.email_verified,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
console.error(`Failed to look up app by email:`, error);
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Rotate app secret — generates a new secret and invalidates the old one.
|
|
206
|
+
*
|
|
207
|
+
* @returns New app_secret (plaintext, only returned once) or null on failure
|
|
208
|
+
*/
|
|
209
|
+
export async function rotateAppSecret(kv, app_id) {
|
|
210
|
+
try {
|
|
211
|
+
const data = await kv.get(`app:${app_id}`, 'text');
|
|
212
|
+
if (!data)
|
|
213
|
+
return null;
|
|
214
|
+
const config = JSON.parse(data);
|
|
215
|
+
const new_secret = generateAppSecret();
|
|
216
|
+
const new_hash = await hashSecret(new_secret);
|
|
217
|
+
config.secret_hash = new_hash;
|
|
218
|
+
await kv.put(`app:${app_id}`, JSON.stringify(config));
|
|
219
|
+
return { app_secret: new_secret };
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
console.error(`Failed to rotate secret for ${app_id}:`, error);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
89
226
|
/**
|
|
90
227
|
* Get app configuration by app_id
|
|
91
228
|
*
|
|
@@ -107,6 +244,8 @@ export async function getApp(kv, app_id) {
|
|
|
107
244
|
app_id: config.app_id,
|
|
108
245
|
created_at: config.created_at,
|
|
109
246
|
rate_limit: config.rate_limit,
|
|
247
|
+
email: config.email,
|
|
248
|
+
email_verified: config.email_verified,
|
|
110
249
|
};
|
|
111
250
|
}
|
|
112
251
|
catch (error) {
|
|
@@ -114,6 +253,22 @@ export async function getApp(kv, app_id) {
|
|
|
114
253
|
return null;
|
|
115
254
|
}
|
|
116
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Get raw app config (internal use only — includes secret_hash)
|
|
258
|
+
* Used by validateAppSecret and dashboard auth.
|
|
259
|
+
*/
|
|
260
|
+
export async function getAppRaw(kv, app_id) {
|
|
261
|
+
try {
|
|
262
|
+
const data = await kv.get(`app:${app_id}`, 'text');
|
|
263
|
+
if (!data)
|
|
264
|
+
return null;
|
|
265
|
+
return JSON.parse(data);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
console.error(`Failed to get raw app ${app_id}:`, error);
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
117
272
|
/**
|
|
118
273
|
* Validate an app secret against stored hash
|
|
119
274
|
*
|
package/dist/challenges.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"challenges.d.ts","sourceRoot":"","sources":["../src/challenges.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"challenges.d.ts","sourceRoot":"","sources":["../src/challenges.ts"],"names":[],"mappings":"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"}
|
package/dist/challenges.js
CHANGED
|
@@ -120,9 +120,10 @@ export async function generateSpeedChallenge(kv, clientTimestamp, app_id) {
|
|
|
120
120
|
};
|
|
121
121
|
// Store in KV with 5 minute TTL (safety buffer for time checks)
|
|
122
122
|
await storeChallenge(kv, id, challenge, 300);
|
|
123
|
+
const pipelineHint = ' Tip: compute all hashes and submit in a single HTTP request. Sequential shell commands will likely exceed the time limit.';
|
|
123
124
|
const instructions = rttMs > 0
|
|
124
|
-
? `Compute SHA256 of each number, return first 8 hex chars of each. Submit as array. You have ${adjustedTimeLimit}ms (adjusted for your ${rttMs}ms network latency)
|
|
125
|
-
:
|
|
125
|
+
? `Compute SHA256 of each number, return first 8 hex chars of each. Submit as array. You have ${adjustedTimeLimit}ms (adjusted for your ${rttMs}ms network latency).${pipelineHint}`
|
|
126
|
+
: `Compute SHA256 of each number, return first 8 hex chars of each. Submit as array. You have 500ms.${pipelineHint}`;
|
|
126
127
|
return {
|
|
127
128
|
id,
|
|
128
129
|
problems,
|
|
@@ -956,8 +957,8 @@ export async function generateHybridChallenge(kv, clientTimestamp, app_id) {
|
|
|
956
957
|
hybridChallenges.set(id, hybrid);
|
|
957
958
|
}
|
|
958
959
|
const instructions = speedChallenge.rttInfo
|
|
959
|
-
? `Solve ALL speed problems (SHA256) in <${speedChallenge.timeLimit}ms (RTT-adjusted) AND answer ALL reasoning questions. Submit both together.`
|
|
960
|
-
: 'Solve ALL speed problems (SHA256) in <500ms AND answer ALL reasoning questions. Submit both together.';
|
|
960
|
+
? `Solve ALL speed problems (SHA256) in <${speedChallenge.timeLimit}ms (RTT-adjusted) AND answer ALL reasoning questions. Submit both together. Tip: compute all hashes in-process and submit in a single HTTP request.`
|
|
961
|
+
: 'Solve ALL speed problems (SHA256) in <500ms AND answer ALL reasoning questions. Submit both together. Tip: compute all hashes in-process and submit in a single HTTP request.';
|
|
961
962
|
return {
|
|
962
963
|
id,
|
|
963
964
|
speed: {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOTCHA Dashboard — Analytics Engine Query API
|
|
3
|
+
*
|
|
4
|
+
* Server-side endpoints that query CF Analytics Engine SQL API
|
|
5
|
+
* and return HTML fragments for htmx to swap in.
|
|
6
|
+
*
|
|
7
|
+
* Data schema (from analytics.ts writeDataPoint):
|
|
8
|
+
* blobs[0] = eventType (challenge_generated | challenge_verified | auth_success | auth_failure | rate_limit_exceeded | error)
|
|
9
|
+
* blobs[1] = challengeType (speed | standard | reasoning | hybrid | '')
|
|
10
|
+
* blobs[2] = endpoint
|
|
11
|
+
* blobs[3] = verificationResult (success | failure | '')
|
|
12
|
+
* blobs[4] = authMethod
|
|
13
|
+
* blobs[5] = clientIP
|
|
14
|
+
* blobs[6] = country
|
|
15
|
+
* blobs[7] = errorType
|
|
16
|
+
* doubles[0] = solveTimeMs
|
|
17
|
+
* doubles[1] = responseTimeMs
|
|
18
|
+
* indexes[0] = eventType
|
|
19
|
+
* indexes[1] = challengeType or 'none'
|
|
20
|
+
* indexes[2] = endpoint or 'unknown'
|
|
21
|
+
*/
|
|
22
|
+
import type { Context } from 'hono';
|
|
23
|
+
interface DashboardEnv {
|
|
24
|
+
Bindings: {
|
|
25
|
+
ANALYTICS?: AnalyticsEngineDataset;
|
|
26
|
+
CF_API_TOKEN?: string;
|
|
27
|
+
CF_ACCOUNT_ID?: string;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
};
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
type AnalyticsEngineDataset = {
|
|
33
|
+
writeDataPoint: (data: {
|
|
34
|
+
blobs?: string[];
|
|
35
|
+
doubles?: number[];
|
|
36
|
+
indexes?: string[];
|
|
37
|
+
}) => void;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* GET /dashboard/api/overview?period=24h
|
|
41
|
+
* Returns HTML fragment with key stats: total challenges, verifications, success rate, avg solve time
|
|
42
|
+
*/
|
|
43
|
+
export declare function handleOverview(c: Context<DashboardEnv>, appId: string): Promise<Response>;
|
|
44
|
+
/**
|
|
45
|
+
* GET /dashboard/api/volume?period=24h
|
|
46
|
+
* Returns HTML fragment with time-bucketed event volume
|
|
47
|
+
*/
|
|
48
|
+
export declare function handleVolume(c: Context<DashboardEnv>, appId: string): Promise<Response>;
|
|
49
|
+
/**
|
|
50
|
+
* GET /dashboard/api/types?period=24h
|
|
51
|
+
* Returns HTML fragment with challenge type breakdown
|
|
52
|
+
*/
|
|
53
|
+
export declare function handleTypes(c: Context<DashboardEnv>, appId: string): Promise<Response>;
|
|
54
|
+
/**
|
|
55
|
+
* GET /dashboard/api/performance?period=24h
|
|
56
|
+
* Returns HTML fragment with performance metrics (solve times, response times)
|
|
57
|
+
*/
|
|
58
|
+
export declare function handlePerformance(c: Context<DashboardEnv>, appId: string): Promise<Response>;
|
|
59
|
+
/**
|
|
60
|
+
* GET /dashboard/api/errors?period=24h
|
|
61
|
+
* Returns HTML fragment with error breakdown
|
|
62
|
+
*/
|
|
63
|
+
export declare function handleErrors(c: Context<DashboardEnv>, appId: string): Promise<Response>;
|
|
64
|
+
/**
|
|
65
|
+
* GET /dashboard/api/geo?period=24h
|
|
66
|
+
* Returns HTML fragment with geographic distribution
|
|
67
|
+
*/
|
|
68
|
+
export declare function handleGeo(c: Context<DashboardEnv>, appId: string): Promise<Response>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/dashboard/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAKpC,UAAU,YAAY;IACpB,QAAQ,EAAE;QACR,SAAS,CAAC,EAAE,sBAAsB,CAAC;QACnC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,KAAK,sBAAsB,GAAG;IAC5B,cAAc,EAAE,CAAC,IAAI,EAAE;QACrB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,KAAK,IAAI,CAAC;CACZ,CAAC;AA2KF;;;GAGG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,qBA4D3E;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,qBAgDzE;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,qBA8CxE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,qBAyE9E;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,qBA8CzE;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,qBA4CtE"}
|