/** * Cursor 官方用量接口测试脚本 */ const https = require('https'); const TOKEN = 'user_01KCP4PQM80HPAZA7NY8RFR1V6::eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxS0NQNFBRTTgwSFBBWkE3Tlk4UkZSMVY2IiwidGltZSI6IjE3NjU5NzQ3MTEiLCJyYW5kb21uZXNzIjoiNzMyNGMwOWItZTk2ZS00Y2YzIiwiZXhwIjoxNzcxMTU4NzExLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20iLCJ0eXBlIjoid2ViIn0.oy_GRvz-3hIUj5BlXahE1QeTb5NuOrM-3pqemw_FEQw'; const COOKIE = `WorkosCursorSessionToken=${TOKEN}`; function request(options, postData = null) { return new Promise((resolve, reject) => { const req = https.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve({ status: res.statusCode, data: JSON.parse(data) }); } catch (e) { resolve({ status: res.statusCode, data: data }); } }); }); req.on('error', reject); if (postData) req.write(postData); req.end(); }); } function getHeaders(isPost = false) { const headers = { 'Cookie': COOKIE, 'accept': '*/*', 'origin': 'https://cursor.com', 'referer': 'https://cursor.com/dashboard' }; if (isPost) { headers['content-type'] = 'application/json'; } return headers; } async function testGetMe() { console.log('\n========== 1. 获取用户信息 (GET /api/dashboard/get-me) =========='); const result = await request({ hostname: 'cursor.com', path: '/api/dashboard/get-me', method: 'GET', headers: getHeaders() }); console.log('Status:', result.status); console.log('Response:', JSON.stringify(result.data, null, 2)); return result.data; } async function testUsageSummary() { console.log('\n========== 2. 获取用量摘要 (GET /api/usage-summary) =========='); const result = await request({ hostname: 'cursor.com', path: '/api/usage-summary', method: 'GET', headers: getHeaders() }); console.log('Status:', result.status); console.log('Response:', JSON.stringify(result.data, null, 2)); return result.data; } async function testBillingCycle() { console.log('\n========== 3. 获取计费周期 (POST /api/dashboard/get-current-billing-cycle) =========='); const result = await request({ hostname: 'cursor.com', path: '/api/dashboard/get-current-billing-cycle', method: 'POST', headers: getHeaders(true) }, '{}'); console.log('Status:', result.status); console.log('Response:', JSON.stringify(result.data, null, 2)); return result.data; } async function testFilteredUsage(userId, startMs, endMs) { console.log('\n========== 4. 获取使用事件 (POST /api/dashboard/get-filtered-usage-events) =========='); // 尝试不同的参数组合 const body = JSON.stringify({ startDate: startMs, endDate: endMs, userId: userId || undefined, page: 1, pageSize: 5 }); console.log('Request body:', body); const result = await request({ hostname: 'cursor.com', path: '/api/dashboard/get-filtered-usage-events', method: 'POST', headers: getHeaders(true) }, body); console.log('Status:', result.status); console.log('Response:', JSON.stringify(result.data, null, 2)); if (result.data && result.data.totalUsageEventsCount !== undefined) { console.log('\n>>> 总对话次数 (totalUsageEventsCount):', result.data.totalUsageEventsCount); } return result.data; } async function testFilteredUsageNoUser(startMs, endMs) { console.log('\n========== 4b. 获取使用事件 - 不带userId =========='); const body = JSON.stringify({ startDate: startMs, endDate: endMs, page: 1, pageSize: 5 }); console.log('Request body:', body); const result = await request({ hostname: 'cursor.com', path: '/api/dashboard/get-filtered-usage-events', method: 'POST', headers: getHeaders(true) }, body); console.log('Status:', result.status); console.log('Response:', JSON.stringify(result.data, null, 2)); if (result.data && result.data.totalUsageEventsCount !== undefined) { console.log('\n>>> 总对话次数 (totalUsageEventsCount):', result.data.totalUsageEventsCount); } return result.data; } async function testAggregatedUsage(startMs) { console.log('\n========== 5. 获取聚合用量 (POST /api/dashboard/get-aggregated-usage-events) =========='); const body = JSON.stringify({ startDate: parseInt(startMs) }); const result = await request({ hostname: 'cursor.com', path: '/api/dashboard/get-aggregated-usage-events', method: 'POST', headers: getHeaders(true) }, body); console.log('Status:', result.status); console.log('Response:', JSON.stringify(result.data, null, 2)); return result.data; } async function main() { console.log('===================================================='); console.log(' Cursor 官方用量接口测试'); console.log('===================================================='); console.log('Cookie:', COOKIE.substring(0, 50) + '...'); try { // 1. 获取用户信息 const me = await testGetMe(); const userId = me.userId; console.log('\n>>> 用户ID:', userId); console.log('>>> 邮箱:', me.email); console.log('>>> 团队ID:', me.teamId); // 2. 获取用量摘要 const summary = await testUsageSummary(); console.log('\n>>> 会员类型:', summary.membershipType); console.log('>>> 计费周期:', summary.billingCycleStart, '至', summary.billingCycleEnd); if (summary.individualUsage) { const plan = summary.individualUsage.plan; console.log('>>> 套餐用量:', plan.used, '/', plan.limit, '(剩余', plan.remaining, ')'); } // 3. 获取计费周期 const billing = await testBillingCycle(); const startMs = billing.startDateEpochMillis; const endMs = billing.endDateEpochMillis; console.log('\n>>> 计费开始:', new Date(parseInt(startMs)).toISOString()); console.log('>>> 计费结束:', new Date(parseInt(endMs)).toISOString()); // 4. 获取使用事件 - 不带 userId await testFilteredUsageNoUser(startMs, endMs); // 4b. 如果有 userId,也试试带 userId 的 if (userId) { await testFilteredUsage(userId, startMs, endMs); } // 5. 获取聚合用量 if (startMs) { await testAggregatedUsage(startMs); } console.log('\n===================================================='); console.log(' 测试完成'); console.log('===================================================='); } catch (error) { console.error('测试出错:', error.message); } } main();