Files
cursornew2026/test_cursor_api.js
ccdojox-crypto 73a71f198f 蜂鸟Pro v2.0.1 - 基础框架版本 (待完善)
## 当前状态
- 插件界面已完成重命名 (cursorpro → hummingbird)
- 双账号池 UI 已实现 (Auto/Pro 卡片)
- 后端已切换到 MySQL 数据库
- 添加了 Cursor 官方用量 API 文档

## 已知问题 (待修复)
1. 激活时检查账号导致无账号时激活失败
2. 未启用无感换号时不应获取账号
3. 账号用量模块不显示 (seamless 未启用时应隐藏)
4. 积分显示为 0 (后端未正确返回)
5. Auto/Pro 双密钥逻辑混乱,状态不同步
6. 账号添加后无自动分析功能

## 下一版本计划
- 重构数据模型,优化账号状态管理
- 实现 Cursor API 自动分析账号
- 修复激活流程,不依赖账号
- 启用无感时才分配账号
- 完善账号用量实时显示

## 文件说明
- docs/系统设计文档.md - 完整架构设计
- cursor 官方用量接口.md - Cursor API 文档
- 参考计费/ - Vibeviewer 开源项目参考

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 11:21:52 +08:00

200 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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();