llmapi-v2 2.1.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/.env.example +40 -0
- package/Dockerfile +17 -0
- package/dist/config.d.ts +48 -0
- package/dist/config.js +98 -0
- package/dist/config.js.map +1 -0
- package/dist/converter/request.d.ts +6 -0
- package/dist/converter/request.js +184 -0
- package/dist/converter/request.js.map +1 -0
- package/dist/converter/response.d.ts +6 -0
- package/dist/converter/response.js +76 -0
- package/dist/converter/response.js.map +1 -0
- package/dist/converter/stream.d.ts +54 -0
- package/dist/converter/stream.js +318 -0
- package/dist/converter/stream.js.map +1 -0
- package/dist/converter/types.d.ts +239 -0
- package/dist/converter/types.js +6 -0
- package/dist/converter/types.js.map +1 -0
- package/dist/data/posts.d.ts +19 -0
- package/dist/data/posts.js +462 -0
- package/dist/data/posts.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +233 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/api-key-auth.d.ts +6 -0
- package/dist/middleware/api-key-auth.js +76 -0
- package/dist/middleware/api-key-auth.js.map +1 -0
- package/dist/middleware/quota-guard.d.ts +10 -0
- package/dist/middleware/quota-guard.js +27 -0
- package/dist/middleware/quota-guard.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +5 -0
- package/dist/middleware/rate-limiter.js +50 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +6 -0
- package/dist/middleware/request-logger.js +37 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/middleware/session-auth.d.ts +19 -0
- package/dist/middleware/session-auth.js +99 -0
- package/dist/middleware/session-auth.js.map +1 -0
- package/dist/providers/aliyun.d.ts +13 -0
- package/dist/providers/aliyun.js +20 -0
- package/dist/providers/aliyun.js.map +1 -0
- package/dist/providers/base-provider.d.ts +36 -0
- package/dist/providers/base-provider.js +133 -0
- package/dist/providers/base-provider.js.map +1 -0
- package/dist/providers/deepseek.d.ts +11 -0
- package/dist/providers/deepseek.js +18 -0
- package/dist/providers/deepseek.js.map +1 -0
- package/dist/providers/registry.d.ts +18 -0
- package/dist/providers/registry.js +98 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +17 -0
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/routes/admin.d.ts +1 -0
- package/dist/routes/admin.js +153 -0
- package/dist/routes/admin.js.map +1 -0
- package/dist/routes/auth.d.ts +2 -0
- package/dist/routes/auth.js +318 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/blog.d.ts +1 -0
- package/dist/routes/blog.js +29 -0
- package/dist/routes/blog.js.map +1 -0
- package/dist/routes/dashboard.d.ts +1 -0
- package/dist/routes/dashboard.js +184 -0
- package/dist/routes/dashboard.js.map +1 -0
- package/dist/routes/messages.d.ts +1 -0
- package/dist/routes/messages.js +309 -0
- package/dist/routes/messages.js.map +1 -0
- package/dist/routes/models.d.ts +1 -0
- package/dist/routes/models.js +39 -0
- package/dist/routes/models.js.map +1 -0
- package/dist/routes/payment.d.ts +1 -0
- package/dist/routes/payment.js +150 -0
- package/dist/routes/payment.js.map +1 -0
- package/dist/routes/sitemap.d.ts +1 -0
- package/dist/routes/sitemap.js +38 -0
- package/dist/routes/sitemap.js.map +1 -0
- package/dist/services/alipay.d.ts +27 -0
- package/dist/services/alipay.js +106 -0
- package/dist/services/alipay.js.map +1 -0
- package/dist/services/database.d.ts +4 -0
- package/dist/services/database.js +170 -0
- package/dist/services/database.js.map +1 -0
- package/dist/services/health-checker.d.ts +13 -0
- package/dist/services/health-checker.js +95 -0
- package/dist/services/health-checker.js.map +1 -0
- package/dist/services/mailer.d.ts +3 -0
- package/dist/services/mailer.js +91 -0
- package/dist/services/mailer.js.map +1 -0
- package/dist/services/metrics.d.ts +56 -0
- package/dist/services/metrics.js +94 -0
- package/dist/services/metrics.js.map +1 -0
- package/dist/services/remote-control.d.ts +20 -0
- package/dist/services/remote-control.js +209 -0
- package/dist/services/remote-control.js.map +1 -0
- package/dist/services/remote-ws.d.ts +5 -0
- package/dist/services/remote-ws.js +143 -0
- package/dist/services/remote-ws.js.map +1 -0
- package/dist/services/usage.d.ts +13 -0
- package/dist/services/usage.js +39 -0
- package/dist/services/usage.js.map +1 -0
- package/dist/utils/errors.d.ts +27 -0
- package/dist/utils/errors.js +48 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +14 -0
- package/dist/utils/logger.js.map +1 -0
- package/docker-compose.yml +19 -0
- package/package.json +39 -0
- package/public/robots.txt +8 -0
- package/src/config.ts +140 -0
- package/src/converter/request.ts +207 -0
- package/src/converter/response.ts +85 -0
- package/src/converter/stream.ts +373 -0
- package/src/converter/types.ts +257 -0
- package/src/data/posts.ts +474 -0
- package/src/index.ts +219 -0
- package/src/middleware/api-key-auth.ts +82 -0
- package/src/middleware/quota-guard.ts +28 -0
- package/src/middleware/rate-limiter.ts +61 -0
- package/src/middleware/request-logger.ts +36 -0
- package/src/middleware/session-auth.ts +91 -0
- package/src/providers/aliyun.ts +16 -0
- package/src/providers/base-provider.ts +148 -0
- package/src/providers/deepseek.ts +14 -0
- package/src/providers/registry.ts +111 -0
- package/src/providers/types.ts +26 -0
- package/src/routes/admin.ts +169 -0
- package/src/routes/auth.ts +369 -0
- package/src/routes/blog.ts +28 -0
- package/src/routes/dashboard.ts +208 -0
- package/src/routes/messages.ts +346 -0
- package/src/routes/models.ts +37 -0
- package/src/routes/payment.ts +189 -0
- package/src/routes/sitemap.ts +40 -0
- package/src/services/alipay.ts +116 -0
- package/src/services/database.ts +187 -0
- package/src/services/health-checker.ts +115 -0
- package/src/services/mailer.ts +90 -0
- package/src/services/metrics.ts +104 -0
- package/src/services/remote-control.ts +226 -0
- package/src/services/remote-ws.ts +145 -0
- package/src/services/usage.ts +57 -0
- package/src/types/express.d.ts +46 -0
- package/src/utils/errors.ts +44 -0
- package/src/utils/logger.ts +8 -0
- package/tsconfig.json +17 -0
- package/views/pages/404.ejs +14 -0
- package/views/pages/admin.ejs +307 -0
- package/views/pages/blog-post.ejs +378 -0
- package/views/pages/blog.ejs +148 -0
- package/views/pages/dashboard.ejs +441 -0
- package/views/pages/docs.ejs +807 -0
- package/views/pages/index.ejs +416 -0
- package/views/pages/login.ejs +170 -0
- package/views/pages/orders.ejs +111 -0
- package/views/pages/pricing.ejs +379 -0
- package/views/pages/register.ejs +397 -0
- package/views/pages/remote.ejs +334 -0
- package/views/pages/settings.ejs +373 -0
- package/views/partials/header.ejs +70 -0
- package/views/partials/nav.ejs +140 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.messagesRouter = void 0;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const api_key_auth_1 = require("../middleware/api-key-auth");
|
|
6
|
+
const rate_limiter_1 = require("../middleware/rate-limiter");
|
|
7
|
+
const quota_guard_1 = require("../middleware/quota-guard");
|
|
8
|
+
const registry_1 = require("../providers/registry");
|
|
9
|
+
const usage_1 = require("../services/usage");
|
|
10
|
+
const metrics_1 = require("../services/metrics");
|
|
11
|
+
const errors_1 = require("../utils/errors");
|
|
12
|
+
const remote_control_1 = require("../services/remote-control");
|
|
13
|
+
const logger_1 = require("../utils/logger");
|
|
14
|
+
/// <reference path="../types/express.d.ts" />
|
|
15
|
+
exports.messagesRouter = (0, express_1.Router)();
|
|
16
|
+
/**
|
|
17
|
+
* POST /v1/messages
|
|
18
|
+
*
|
|
19
|
+
* Transparent proxy to provider's native Anthropic endpoint.
|
|
20
|
+
*
|
|
21
|
+
* Architecture:
|
|
22
|
+
* Claude Code -> this proxy -> provider's Anthropic endpoint -> Claude Code
|
|
23
|
+
*
|
|
24
|
+
* We do NOT convert formats. The provider handles all Anthropic protocol
|
|
25
|
+
* details. We only:
|
|
26
|
+
* 1. Authenticate the user (API key)
|
|
27
|
+
* 2. Smart-route to the best provider
|
|
28
|
+
* 3. Rewrite the model name in the request body
|
|
29
|
+
* 4. Forward the request transparently
|
|
30
|
+
* 5. Intercept the response to extract usage for billing
|
|
31
|
+
* 6. Pipe the response back to the client
|
|
32
|
+
*/
|
|
33
|
+
exports.messagesRouter.post('/messages', api_key_auth_1.apiKeyAuth, rate_limiter_1.rateLimiter, quota_guard_1.quotaGuard, async (req, res) => {
|
|
34
|
+
const startTime = Date.now();
|
|
35
|
+
// Parse just the fields we need for routing (don't fully parse the body)
|
|
36
|
+
const body = req.body;
|
|
37
|
+
// Command interception: remote control trigger
|
|
38
|
+
if ((0, remote_control_1.detectRemoteTrigger)(body)) {
|
|
39
|
+
await (0, remote_control_1.handleRemoteTrigger)(req, res);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const claudeModel = body.model || 'claude-sonnet-4-6';
|
|
43
|
+
const isStream = !!body.stream;
|
|
44
|
+
const hasTools = Array.isArray(body.tools) && body.tools.length > 0;
|
|
45
|
+
const messageCount = Array.isArray(body.messages) ? body.messages.length : 0;
|
|
46
|
+
logger_1.logger.info({
|
|
47
|
+
userId: req.userId,
|
|
48
|
+
model: claudeModel,
|
|
49
|
+
stream: isStream,
|
|
50
|
+
tools: hasTools,
|
|
51
|
+
messages: messageCount,
|
|
52
|
+
}, 'API request');
|
|
53
|
+
// Smart routing: pick the best provider based on task characteristics
|
|
54
|
+
let resolved = (0, registry_1.smartResolve)(claudeModel, hasTools, messageCount);
|
|
55
|
+
// Try smart resolution first, then fall back to priority-based routing
|
|
56
|
+
const providersToTry = [];
|
|
57
|
+
if (resolved) {
|
|
58
|
+
providersToTry.push(resolved);
|
|
59
|
+
}
|
|
60
|
+
// Always add fallback providers
|
|
61
|
+
for await (const route of (0, registry_1.resolveWithFailover)(claudeModel)) {
|
|
62
|
+
// Skip if already the smart-resolved provider
|
|
63
|
+
if (resolved && route.provider.name === resolved.provider.name)
|
|
64
|
+
continue;
|
|
65
|
+
providersToTry.push(route);
|
|
66
|
+
}
|
|
67
|
+
if (providersToTry.length === 0) {
|
|
68
|
+
const err = new errors_1.OverloadedError('No providers available for this model.');
|
|
69
|
+
res.status(err.statusCode).json(err.toJSON());
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
let lastError = null;
|
|
73
|
+
for (const { provider, backendModel } of providersToTry) {
|
|
74
|
+
try {
|
|
75
|
+
// Rewrite the model name in the request body
|
|
76
|
+
const modifiedBody = { ...body, model: backendModel };
|
|
77
|
+
const normalized = normalizeForCache(modifiedBody);
|
|
78
|
+
const payload = JSON.stringify(normalized);
|
|
79
|
+
logger_1.logger.debug({ provider: provider.name, model: backendModel, smart: !!resolved }, 'Routing to provider');
|
|
80
|
+
if (isStream) {
|
|
81
|
+
metrics_1.metrics.streamStarted();
|
|
82
|
+
}
|
|
83
|
+
// Forward to provider's native Anthropic endpoint
|
|
84
|
+
const backendRes = await provider.proxy('/v1/messages', payload, {
|
|
85
|
+
'anthropic-version': req.headers['anthropic-version'] || '2023-06-01',
|
|
86
|
+
'anthropic-beta': req.headers['anthropic-beta'] || '',
|
|
87
|
+
}, isStream);
|
|
88
|
+
// Check for error status from provider
|
|
89
|
+
if (backendRes.statusCode && backendRes.statusCode >= 400) {
|
|
90
|
+
const errorBody = await bufferResponse(backendRes);
|
|
91
|
+
const errMsg = extractErrorMessage(errorBody, backendRes.statusCode, provider.name);
|
|
92
|
+
throw new Error(errMsg);
|
|
93
|
+
}
|
|
94
|
+
provider.markHealthy();
|
|
95
|
+
if (isStream) {
|
|
96
|
+
// Streaming: pipe response directly, intercept usage from SSE
|
|
97
|
+
await pipeStreamingResponse(backendRes, res, {
|
|
98
|
+
userId: req.userId,
|
|
99
|
+
apiKeyId: req.apiKey?.id ?? null,
|
|
100
|
+
displayModel: claudeModel,
|
|
101
|
+
providerName: provider.name,
|
|
102
|
+
backendModel,
|
|
103
|
+
startTime,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Non-streaming: buffer, extract usage, forward
|
|
108
|
+
const responseBody = await bufferResponse(backendRes);
|
|
109
|
+
const parsed = JSON.parse(responseBody);
|
|
110
|
+
// Record usage from the response
|
|
111
|
+
const usage = parsed.usage || {};
|
|
112
|
+
(0, usage_1.recordUsage)(req.userId, req.apiKey?.id ?? null, claudeModel, provider.name, backendModel, {
|
|
113
|
+
inputTokens: usage.input_tokens || 0,
|
|
114
|
+
outputTokens: usage.output_tokens || 0,
|
|
115
|
+
thinkingTokens: 0,
|
|
116
|
+
ttftMs: Date.now() - startTime,
|
|
117
|
+
tokensPerSec: 0,
|
|
118
|
+
durationMs: Date.now() - startTime,
|
|
119
|
+
});
|
|
120
|
+
metrics_1.metrics.recordRequest(true, false);
|
|
121
|
+
metrics_1.metrics.recordProviderRequest(provider.name, true);
|
|
122
|
+
// Forward response with original headers
|
|
123
|
+
res.setHeader('Content-Type', 'application/json');
|
|
124
|
+
res.status(backendRes.statusCode || 200).send(responseBody);
|
|
125
|
+
}
|
|
126
|
+
return; // Success
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
lastError = err;
|
|
130
|
+
provider.markUnhealthy(lastError.message);
|
|
131
|
+
metrics_1.metrics.recordProviderRequest(provider.name, false);
|
|
132
|
+
if (isStream)
|
|
133
|
+
metrics_1.metrics.streamEnded();
|
|
134
|
+
logger_1.logger.warn({ provider: provider.name, err: lastError.message }, 'Provider failed, trying next');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// All providers failed
|
|
138
|
+
metrics_1.metrics.recordRequest(false, isStream);
|
|
139
|
+
logger_1.logger.error({ model: claudeModel, lastError: lastError?.message }, 'All providers failed');
|
|
140
|
+
const error = new errors_1.OverloadedError(lastError?.message || 'All providers unavailable.');
|
|
141
|
+
res.status(error.statusCode).json(error.toJSON());
|
|
142
|
+
});
|
|
143
|
+
/**
|
|
144
|
+
* Pipe a streaming response from the provider directly to the client.
|
|
145
|
+
* Intercept SSE events to extract usage data for billing.
|
|
146
|
+
*/
|
|
147
|
+
async function pipeStreamingResponse(backendRes, clientRes, meta) {
|
|
148
|
+
return new Promise((resolve) => {
|
|
149
|
+
// Forward headers
|
|
150
|
+
clientRes.setHeader('Content-Type', 'text/event-stream');
|
|
151
|
+
clientRes.setHeader('Cache-Control', 'no-cache');
|
|
152
|
+
clientRes.setHeader('Connection', 'keep-alive');
|
|
153
|
+
clientRes.flushHeaders();
|
|
154
|
+
let usage = { inputTokens: 0, outputTokens: 0 };
|
|
155
|
+
let firstChunkTime = 0;
|
|
156
|
+
let buffer = '';
|
|
157
|
+
// Handle client disconnect
|
|
158
|
+
clientRes.on('close', () => {
|
|
159
|
+
backendRes.destroy();
|
|
160
|
+
});
|
|
161
|
+
backendRes.setEncoding('utf8');
|
|
162
|
+
backendRes.on('data', (chunk) => {
|
|
163
|
+
if (!firstChunkTime)
|
|
164
|
+
firstChunkTime = Date.now();
|
|
165
|
+
// Write chunk directly to client (transparent proxy)
|
|
166
|
+
if (!clientRes.writableEnded) {
|
|
167
|
+
try {
|
|
168
|
+
clientRes.write(chunk);
|
|
169
|
+
}
|
|
170
|
+
catch { }
|
|
171
|
+
}
|
|
172
|
+
// Parse SSE to extract usage (for billing)
|
|
173
|
+
buffer += chunk;
|
|
174
|
+
const lines = buffer.split('\n');
|
|
175
|
+
buffer = lines.pop() || '';
|
|
176
|
+
for (const line of lines) {
|
|
177
|
+
if (!line.startsWith('data: '))
|
|
178
|
+
continue;
|
|
179
|
+
const payload = line.slice(6).trim();
|
|
180
|
+
if (payload === '[DONE]' || !payload)
|
|
181
|
+
continue;
|
|
182
|
+
try {
|
|
183
|
+
const data = JSON.parse(payload);
|
|
184
|
+
// Extract usage from message_start or message_delta events
|
|
185
|
+
if (data.type === 'message_start' && data.message?.usage) {
|
|
186
|
+
usage.inputTokens = data.message.usage.input_tokens || 0;
|
|
187
|
+
}
|
|
188
|
+
if (data.type === 'message_delta' && data.usage) {
|
|
189
|
+
usage.outputTokens = data.usage.output_tokens || 0;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch { }
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
backendRes.on('end', () => {
|
|
196
|
+
if (!clientRes.writableEnded) {
|
|
197
|
+
try {
|
|
198
|
+
clientRes.end();
|
|
199
|
+
}
|
|
200
|
+
catch { }
|
|
201
|
+
}
|
|
202
|
+
const duration = Date.now() - meta.startTime;
|
|
203
|
+
const ttft = firstChunkTime ? firstChunkTime - meta.startTime : duration;
|
|
204
|
+
const tps = duration > 0 && usage.outputTokens > 0
|
|
205
|
+
? Math.round((usage.outputTokens / (duration / 1000)) * 100) / 100
|
|
206
|
+
: 0;
|
|
207
|
+
// Record usage for billing
|
|
208
|
+
(0, usage_1.recordUsage)(meta.userId, meta.apiKeyId, meta.displayModel, meta.providerName, meta.backendModel, {
|
|
209
|
+
inputTokens: usage.inputTokens,
|
|
210
|
+
outputTokens: usage.outputTokens,
|
|
211
|
+
thinkingTokens: 0,
|
|
212
|
+
ttftMs: ttft,
|
|
213
|
+
tokensPerSec: tps,
|
|
214
|
+
durationMs: duration,
|
|
215
|
+
});
|
|
216
|
+
metrics_1.metrics.recordRequest(true, true);
|
|
217
|
+
metrics_1.metrics.recordProviderRequest(meta.providerName, true);
|
|
218
|
+
metrics_1.metrics.recordLatency(duration);
|
|
219
|
+
if (ttft > 0)
|
|
220
|
+
metrics_1.metrics.recordTTFT(ttft);
|
|
221
|
+
metrics_1.metrics.streamEnded();
|
|
222
|
+
logger_1.logger.info({
|
|
223
|
+
userId: meta.userId,
|
|
224
|
+
provider: meta.providerName,
|
|
225
|
+
model: meta.backendModel,
|
|
226
|
+
inputTokens: usage.inputTokens,
|
|
227
|
+
outputTokens: usage.outputTokens,
|
|
228
|
+
ttftMs: ttft,
|
|
229
|
+
durationMs: duration,
|
|
230
|
+
}, 'Stream completed');
|
|
231
|
+
resolve();
|
|
232
|
+
});
|
|
233
|
+
backendRes.on('error', (err) => {
|
|
234
|
+
logger_1.logger.error({ err }, 'Backend stream error');
|
|
235
|
+
if (!clientRes.writableEnded) {
|
|
236
|
+
try {
|
|
237
|
+
clientRes.end();
|
|
238
|
+
}
|
|
239
|
+
catch { }
|
|
240
|
+
}
|
|
241
|
+
metrics_1.metrics.streamEnded();
|
|
242
|
+
resolve();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Optimize request for DashScope's prompt caching:
|
|
248
|
+
* 1. Inject cache_control on system prompt blocks (explicit caching, 90% cost reduction)
|
|
249
|
+
* 2. Strip timestamps/session IDs from system prompt (maximize prefix match)
|
|
250
|
+
*
|
|
251
|
+
* DashScope explicit cache: add cache_control: {type: "ephemeral"} to cacheable blocks.
|
|
252
|
+
* When the same prefix is seen again within 5 minutes, cached tokens cost only 10%.
|
|
253
|
+
*/
|
|
254
|
+
function normalizeForCache(body) {
|
|
255
|
+
const normalized = { ...body };
|
|
256
|
+
if (typeof normalized.system === 'string') {
|
|
257
|
+
// Convert string system to array format so we can add cache_control
|
|
258
|
+
const cleanText = normalized.system
|
|
259
|
+
.replace(/\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?/g, 'DATE_PLACEHOLDER')
|
|
260
|
+
.replace(/\b\d{10,13}\b/g, 'TIMESTAMP');
|
|
261
|
+
normalized.system = [
|
|
262
|
+
{ type: 'text', text: cleanText, cache_control: { type: 'ephemeral' } },
|
|
263
|
+
];
|
|
264
|
+
}
|
|
265
|
+
else if (Array.isArray(normalized.system) && normalized.system.length > 0) {
|
|
266
|
+
normalized.system = normalized.system.map((block, i) => {
|
|
267
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
268
|
+
const cleanText = block.text
|
|
269
|
+
.replace(/\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?/g, 'DATE_PLACEHOLDER')
|
|
270
|
+
.replace(/\b\d{10,13}\b/g, 'TIMESTAMP');
|
|
271
|
+
return {
|
|
272
|
+
...block,
|
|
273
|
+
text: cleanText,
|
|
274
|
+
// Add cache_control to the last system block (marks end of cacheable prefix)
|
|
275
|
+
...(i === normalized.system.length - 1 ? { cache_control: { type: 'ephemeral' } } : {}),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return block;
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
return normalized;
|
|
282
|
+
}
|
|
283
|
+
function bufferResponse(res) {
|
|
284
|
+
return new Promise((resolve, reject) => {
|
|
285
|
+
const chunks = [];
|
|
286
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
287
|
+
res.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
288
|
+
res.on('error', reject);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
function extractErrorMessage(body, statusCode, provider) {
|
|
292
|
+
try {
|
|
293
|
+
const parsed = JSON.parse(body);
|
|
294
|
+
return parsed.error?.message || `Provider ${provider} returned ${statusCode}`;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
return `Provider ${provider} returned ${statusCode}`;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* POST /v1/messages/count_tokens
|
|
302
|
+
*/
|
|
303
|
+
exports.messagesRouter.post('/messages/count_tokens', api_key_auth_1.apiKeyAuth, (req, res) => {
|
|
304
|
+
const { messages, system } = req.body;
|
|
305
|
+
const text = JSON.stringify(messages || []) + JSON.stringify(system || '');
|
|
306
|
+
const inputTokens = Math.ceil(text.length / 4);
|
|
307
|
+
res.json({ input_tokens: inputTokens });
|
|
308
|
+
});
|
|
309
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/routes/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const modelsRouter: import("express-serve-static-core").Router;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.modelsRouter = void 0;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
exports.modelsRouter = (0, express_1.Router)();
|
|
6
|
+
/**
|
|
7
|
+
* GET /v1/models
|
|
8
|
+
*
|
|
9
|
+
* Returns the Claude model list that Claude Code expects.
|
|
10
|
+
* This makes Claude Code believe it's talking to the Anthropic API.
|
|
11
|
+
*/
|
|
12
|
+
exports.modelsRouter.get('/models', (_req, res) => {
|
|
13
|
+
res.json({
|
|
14
|
+
data: [
|
|
15
|
+
{
|
|
16
|
+
id: 'claude-sonnet-4-6',
|
|
17
|
+
display_name: 'Claude Sonnet 4.6',
|
|
18
|
+
type: 'model',
|
|
19
|
+
created_at: '2025-05-14T00:00:00Z',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'claude-opus-4-6',
|
|
23
|
+
display_name: 'Claude Opus 4.6',
|
|
24
|
+
type: 'model',
|
|
25
|
+
created_at: '2025-05-14T00:00:00Z',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'claude-haiku-4-5',
|
|
29
|
+
display_name: 'Claude Haiku 4.5',
|
|
30
|
+
type: 'model',
|
|
31
|
+
created_at: '2025-02-24T00:00:00Z',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
has_more: false,
|
|
35
|
+
first_id: 'claude-sonnet-4-6',
|
|
36
|
+
last_id: 'claude-haiku-4-5',
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/routes/models.ts"],"names":[],"mappings":";;;AAAA,qCAAiC;AAEpB,QAAA,YAAY,GAAG,IAAA,gBAAM,GAAE,CAAC;AAErC;;;;;GAKG;AACH,oBAAY,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACxC,GAAG,CAAC,IAAI,CAAC;QACP,IAAI,EAAE;YACJ;gBACE,EAAE,EAAE,mBAAmB;gBACvB,YAAY,EAAE,mBAAmB;gBACjC,IAAI,EAAE,OAAO;gBACb,UAAU,EAAE,sBAAsB;aACnC;YACD;gBACE,EAAE,EAAE,iBAAiB;gBACrB,YAAY,EAAE,iBAAiB;gBAC/B,IAAI,EAAE,OAAO;gBACb,UAAU,EAAE,sBAAsB;aACnC;YACD;gBACE,EAAE,EAAE,kBAAkB;gBACtB,YAAY,EAAE,kBAAkB;gBAChC,IAAI,EAAE,OAAO;gBACb,UAAU,EAAE,sBAAsB;aACnC;SACF;QACD,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,mBAAmB;QAC7B,OAAO,EAAE,kBAAkB;KAC5B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const paymentRouter: import("express-serve-static-core").Router;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.paymentRouter = void 0;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const database_1 = require("../services/database");
|
|
6
|
+
const session_auth_1 = require("../middleware/session-auth");
|
|
7
|
+
const alipay_1 = require("../services/alipay");
|
|
8
|
+
const logger_1 = require("../utils/logger");
|
|
9
|
+
exports.paymentRouter = (0, express_1.Router)();
|
|
10
|
+
const PLAN_PRICES = {
|
|
11
|
+
starter: 9,
|
|
12
|
+
pro: 29,
|
|
13
|
+
unlimited: 99,
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* POST /api/payment/create-order
|
|
17
|
+
* Create an order and generate Alipay QR code.
|
|
18
|
+
*/
|
|
19
|
+
exports.paymentRouter.post('/create-order', session_auth_1.sessionAuth, async (req, res) => {
|
|
20
|
+
try {
|
|
21
|
+
const { plan } = req.body;
|
|
22
|
+
const price = PLAN_PRICES[plan];
|
|
23
|
+
if (!price) {
|
|
24
|
+
res.status(400).json({ success: false, error: 'Invalid plan' });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const pool = (0, database_1.getPool)();
|
|
28
|
+
// Get plan ID
|
|
29
|
+
const [plans] = await pool.execute('SELECT id, display_name FROM plans WHERE name = ?', [plan]);
|
|
30
|
+
const planRow = plans[0];
|
|
31
|
+
if (!planRow) {
|
|
32
|
+
res.status(400).json({ success: false, error: 'Plan not found' });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Create order
|
|
36
|
+
const orderNo = `LLM${Date.now()}${Math.random().toString(36).slice(2, 6).toUpperCase()}`;
|
|
37
|
+
await pool.execute('INSERT INTO orders (order_no, user_id, plan_id, amount) VALUES (?, ?, ?, ?)', [orderNo, req.userId, planRow.id, price]);
|
|
38
|
+
// Generate Alipay QR code
|
|
39
|
+
const qrUrl = await (0, alipay_1.createQrPayment)(orderNo, String(price), `LLM API ${planRow.display_name} Monthly`);
|
|
40
|
+
if (!qrUrl) {
|
|
41
|
+
res.status(500).json({ success: false, error: 'Failed to create payment' });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Convert QR URL to data URL for frontend display
|
|
45
|
+
const QRCode = require('qrcode');
|
|
46
|
+
const qrDataUrl = await QRCode.toDataURL(qrUrl, { width: 256 });
|
|
47
|
+
res.json({ success: true, orderNo, qrCode: qrDataUrl, amount: price });
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
logger_1.logger.error({ err }, 'create order error');
|
|
51
|
+
res.status(500).json({ success: false, error: 'Internal error' });
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* POST /api/payment/notify
|
|
56
|
+
* Alipay async callback (no auth required).
|
|
57
|
+
*/
|
|
58
|
+
exports.paymentRouter.post('/notify', async (req, res) => {
|
|
59
|
+
try {
|
|
60
|
+
const params = req.body;
|
|
61
|
+
// Verify signature
|
|
62
|
+
if (!(0, alipay_1.verifyNotifySign)(params)) {
|
|
63
|
+
res.status(400).send('fail');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const orderNo = params.out_trade_no;
|
|
67
|
+
const tradeNo = params.trade_no;
|
|
68
|
+
const tradeStatus = params.trade_status;
|
|
69
|
+
if (tradeStatus !== 'TRADE_SUCCESS' && tradeStatus !== 'TRADE_FINISHED') {
|
|
70
|
+
res.send('success');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const pool = (0, database_1.getPool)();
|
|
74
|
+
// Get order
|
|
75
|
+
const [orders] = await pool.execute('SELECT * FROM orders WHERE order_no = ?', [orderNo]);
|
|
76
|
+
const order = orders[0];
|
|
77
|
+
if (!order || order.status === 'paid') {
|
|
78
|
+
res.send('success');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Mark order as paid
|
|
82
|
+
await pool.execute('UPDATE orders SET status = ?, trade_no = ?, paid_at = NOW() WHERE order_no = ?', ['paid', tradeNo, orderNo]);
|
|
83
|
+
// Upgrade user subscription
|
|
84
|
+
const [existingSub] = await pool.execute('SELECT id FROM subscriptions WHERE user_id = ?', [order.user_id]);
|
|
85
|
+
if (existingSub.length > 0) {
|
|
86
|
+
await pool.execute("UPDATE subscriptions SET plan_id = ?, tokens_used = 0, period_start = NOW(), period_end = NOW() + INTERVAL '30 days' WHERE user_id = ?", [order.plan_id, order.user_id]);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
await pool.execute("INSERT INTO subscriptions (user_id, plan_id, period_end) VALUES (?, ?, NOW() + INTERVAL '30 days')", [order.user_id, order.plan_id]);
|
|
90
|
+
}
|
|
91
|
+
logger_1.logger.info({ orderNo, userId: order.user_id, planId: order.plan_id }, 'Payment confirmed');
|
|
92
|
+
res.send('success');
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
logger_1.logger.error({ err }, 'payment notify error');
|
|
96
|
+
res.status(500).send('fail');
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* GET /api/payment/check/:orderNo
|
|
101
|
+
* Poll for payment status.
|
|
102
|
+
*/
|
|
103
|
+
exports.paymentRouter.get('/check/:orderNo', session_auth_1.sessionAuth, async (req, res) => {
|
|
104
|
+
try {
|
|
105
|
+
const pool = (0, database_1.getPool)();
|
|
106
|
+
const [orders] = await pool.execute('SELECT status, trade_no FROM orders WHERE order_no = ? AND user_id = ?', [req.params.orderNo, req.userId]);
|
|
107
|
+
const order = orders[0];
|
|
108
|
+
if (!order) {
|
|
109
|
+
res.status(404).json({ success: false, error: 'Order not found' });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (order.status === 'paid') {
|
|
113
|
+
res.json({ success: true, status: 'paid' });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Check with Alipay
|
|
117
|
+
const result = await (0, alipay_1.queryAlipayOrder)(req.params.orderNo);
|
|
118
|
+
if (result?.status === 'paid') {
|
|
119
|
+
// Update locally
|
|
120
|
+
await pool.execute('UPDATE orders SET status = ?, trade_no = ?, paid_at = NOW() WHERE order_no = ?', ['paid', result.tradeNo || '', req.params.orderNo]);
|
|
121
|
+
res.json({ success: true, status: 'paid' });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
res.json({ success: true, status: 'pending' });
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
logger_1.logger.error({ err }, 'check order error');
|
|
128
|
+
res.status(500).json({ success: false, error: 'Internal error' });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
/**
|
|
132
|
+
* GET /api/payment/orders
|
|
133
|
+
* User's order history.
|
|
134
|
+
*/
|
|
135
|
+
exports.paymentRouter.get('/orders', session_auth_1.sessionAuth, async (req, res) => {
|
|
136
|
+
try {
|
|
137
|
+
const pool = (0, database_1.getPool)();
|
|
138
|
+
const [rows] = await pool.execute(`
|
|
139
|
+
SELECT o.*, p.display_name as plan_name
|
|
140
|
+
FROM orders o JOIN plans p ON o.plan_id = p.id
|
|
141
|
+
WHERE o.user_id = ? ORDER BY o.created_at DESC LIMIT 20
|
|
142
|
+
`, [req.userId]);
|
|
143
|
+
res.json({ success: true, orders: rows });
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
logger_1.logger.error({ err }, 'list orders error');
|
|
147
|
+
res.status(500).json({ success: false, error: 'Internal error' });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=payment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment.js","sourceRoot":"","sources":["../../src/routes/payment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sitemapRouter: import("express-serve-static-core").Router;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sitemapRouter = void 0;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const posts_1 = require("../data/posts");
|
|
6
|
+
exports.sitemapRouter = (0, express_1.Router)();
|
|
7
|
+
exports.sitemapRouter.get('/sitemap.xml', (_req, res) => {
|
|
8
|
+
const baseUrl = process.env.SITE_URL || 'https://llmapi.pro';
|
|
9
|
+
const posts = (0, posts_1.getRecentPosts)(100);
|
|
10
|
+
const staticPages = [
|
|
11
|
+
{ url: '/', priority: '1.0', changefreq: 'weekly' },
|
|
12
|
+
{ url: '/pricing', priority: '0.9', changefreq: 'weekly' },
|
|
13
|
+
{ url: '/docs', priority: '0.9', changefreq: 'weekly' },
|
|
14
|
+
{ url: '/blog', priority: '0.8', changefreq: 'daily' },
|
|
15
|
+
{ url: '/login', priority: '0.3', changefreq: 'monthly' },
|
|
16
|
+
{ url: '/register', priority: '0.5', changefreq: 'monthly' },
|
|
17
|
+
];
|
|
18
|
+
const urls = staticPages.map(p => `
|
|
19
|
+
<url>
|
|
20
|
+
<loc>${baseUrl}${p.url}</loc>
|
|
21
|
+
<changefreq>${p.changefreq}</changefreq>
|
|
22
|
+
<priority>${p.priority}</priority>
|
|
23
|
+
</url>`).join('');
|
|
24
|
+
const postUrls = posts.map(p => `
|
|
25
|
+
<url>
|
|
26
|
+
<loc>${baseUrl}/blog/${p.slug}</loc>
|
|
27
|
+
<lastmod>${p.date}</lastmod>
|
|
28
|
+
<changefreq>monthly</changefreq>
|
|
29
|
+
<priority>0.7</priority>
|
|
30
|
+
</url>`).join('');
|
|
31
|
+
res.setHeader('Content-Type', 'application/xml');
|
|
32
|
+
res.send(`<?xml version="1.0" encoding="UTF-8"?>
|
|
33
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
34
|
+
${urls}
|
|
35
|
+
${postUrls}
|
|
36
|
+
</urlset>`);
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=sitemap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../../src/routes/sitemap.ts"],"names":[],"mappings":";;;AAAA,qCAAiC;AACjC,yCAA+C;AAElC,QAAA,aAAa,GAAG,IAAA,gBAAM,GAAE,CAAC;AAEtC,qBAAa,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,oBAAoB,CAAC;IAC7D,MAAM,KAAK,GAAG,IAAA,sBAAc,EAAC,GAAG,CAAC,CAAC;IAElC,MAAM,WAAW,GAAG;QAClB,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE;QACnD,EAAE,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE;QAC1D,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE;QACvD,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE;QACtD,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE;QACzD,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE;KAC7D,CAAC;IAEF,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;;WAEzB,OAAO,GAAG,CAAC,CAAC,GAAG;kBACR,CAAC,CAAC,UAAU;gBACd,CAAC,CAAC,QAAQ;SACjB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAElB,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;;WAEvB,OAAO,SAAS,CAAC,CAAC,IAAI;eAClB,CAAC,CAAC,IAAI;;;SAGZ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAElB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACjD,GAAG,CAAC,IAAI,CAAC;;EAET,IAAI;EACJ,QAAQ;UACA,CAAC,CAAC;AACZ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare function setAlipayConfig(config: {
|
|
2
|
+
appId: string;
|
|
3
|
+
privateKey: string;
|
|
4
|
+
alipayPublicKey: string;
|
|
5
|
+
gateway?: string;
|
|
6
|
+
notifyUrl: string;
|
|
7
|
+
}): void;
|
|
8
|
+
/**
|
|
9
|
+
* Create QR code payment order via Alipay trade.precreate.
|
|
10
|
+
* Returns the QR code URL string.
|
|
11
|
+
*
|
|
12
|
+
* Note: Full Alipay SDK integration requires the 'alipay-sdk' package.
|
|
13
|
+
* This is a placeholder structure - the actual signing and API call
|
|
14
|
+
* should use the SDK for proper RSA2 signature handling.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createQrPayment(orderNo: string, amount: string, subject: string): Promise<string | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Query order status from Alipay.
|
|
19
|
+
*/
|
|
20
|
+
export declare function queryAlipayOrder(orderNo: string): Promise<{
|
|
21
|
+
status: string;
|
|
22
|
+
tradeNo?: string;
|
|
23
|
+
} | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Verify Alipay notification signature.
|
|
26
|
+
*/
|
|
27
|
+
export declare function verifyNotifySign(params: Record<string, string>): boolean;
|