File size: 3,853 Bytes
02d34ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/**
 * Cursor2API v2 - ๅ…ฅๅฃ
 *
 * ๅฐ† Cursor ๆ–‡ๆกฃ้กตๅ…่ดน AI ๆŽฅๅฃไปฃ็†ไธบ Anthropic Messages API
 * ้€š่ฟ‡ๆ็คบ่ฏๆณจๅ…ฅ่ฎฉ Claude Code ๆ‹ฅๆœ‰ๅฎŒๆ•ดๅทฅๅ…ท่ฐƒ็”จ่ƒฝๅŠ›
 */

import 'dotenv/config';
import express from 'express';
import { getConfig } from './config.js';
import { handleMessages, listModels, countTokens } from './handler.js';
import { handleOpenAIChatCompletions } from './openai-handler.js';

const app = express();
const config = getConfig();

// ่งฃๆž JSON body๏ผˆๅขžๅคง้™ๅˆถไปฅๆ”ฏๆŒ base64 ๅ›พ็‰‡๏ผŒๅ•ๅผ ๅ›พ็‰‡ๅฏ่พพ 10MB+๏ผ‰
app.use(express.json({ limit: '50mb' }));

// CORS
app.use((_req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.header('Access-Control-Allow-Headers', '*');
    if (_req.method === 'OPTIONS') {
        res.sendStatus(200);
        return;
    }
    next();
});

// ==================== ่ทฏ็”ฑ ====================

// Anthropic Messages API
app.post('/v1/messages', handleMessages);
app.post('/messages', handleMessages);

// OpenAI Chat Completions API๏ผˆๅ…ผๅฎน๏ผ‰
app.post('/v1/chat/completions', handleOpenAIChatCompletions);
app.post('/chat/completions', handleOpenAIChatCompletions);

// Token ่ฎกๆ•ฐ
app.post('/v1/messages/count_tokens', countTokens);
app.post('/messages/count_tokens', countTokens);

// OpenAI ๅ…ผๅฎนๆจกๅž‹ๅˆ—่กจ
app.get('/v1/models', listModels);

// ๅฅๅบทๆฃ€ๆŸฅ
app.get('/health', (_req, res) => {
    res.json({ status: 'ok', version: '2.3.2' });
});

// ๆ น่ทฏๅพ„
app.get('/', (_req, res) => {
    res.json({
        name: 'cursor2api',
        version: '2.3.2',
        description: 'Cursor Docs AI โ†’ Anthropic & OpenAI API Proxy',
        endpoints: {
            anthropic_messages: 'POST /v1/messages',
            openai_chat: 'POST /v1/chat/completions',
            models: 'GET /v1/models',
            health: 'GET /health',
        },
        usage: {
            claude_code: 'export ANTHROPIC_BASE_URL=http://localhost:' + config.port,
            openai_compatible: 'OPENAI_BASE_URL=http://localhost:' + config.port + '/v1',
        },
    });
});

// ==================== ๅฏๅŠจ ====================

app.listen(config.port, () => {
    console.log('');
    console.log('  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—');
    console.log('  โ•‘        Cursor2API v2.3.2             โ•‘');
    console.log('  โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ');
    console.log(`  โ•‘  Server:  http://localhost:${config.port}      โ•‘`);
    console.log('  โ•‘  Model:   ' + config.cursorModel.padEnd(26) + 'โ•‘');
    console.log('  โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ');
    console.log('  โ•‘  API Endpoints:                      โ•‘');
    console.log('  โ•‘  โ€ข Anthropic: /v1/messages            โ•‘');
    console.log('  โ•‘  โ€ข OpenAI:   /v1/chat/completions     โ•‘');
    console.log('  โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ');
    console.log('  โ•‘  Claude Code:                        โ•‘');
    console.log(`  โ•‘  export ANTHROPIC_BASE_URL=           โ•‘`);
    console.log(`  โ•‘    http://localhost:${config.port}              โ•‘`);
    console.log('  โ•‘  OpenAI ๅ…ผๅฎน:                        โ•‘');
    console.log(`  โ•‘  OPENAI_BASE_URL=                     โ•‘`);
    console.log(`  โ•‘    http://localhost:${config.port}/v1            โ•‘`);
    console.log('  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•');
    console.log('');
});