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.
Files changed (162) hide show
  1. package/.env.example +40 -0
  2. package/Dockerfile +17 -0
  3. package/dist/config.d.ts +48 -0
  4. package/dist/config.js +98 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/converter/request.d.ts +6 -0
  7. package/dist/converter/request.js +184 -0
  8. package/dist/converter/request.js.map +1 -0
  9. package/dist/converter/response.d.ts +6 -0
  10. package/dist/converter/response.js +76 -0
  11. package/dist/converter/response.js.map +1 -0
  12. package/dist/converter/stream.d.ts +54 -0
  13. package/dist/converter/stream.js +318 -0
  14. package/dist/converter/stream.js.map +1 -0
  15. package/dist/converter/types.d.ts +239 -0
  16. package/dist/converter/types.js +6 -0
  17. package/dist/converter/types.js.map +1 -0
  18. package/dist/data/posts.d.ts +19 -0
  19. package/dist/data/posts.js +462 -0
  20. package/dist/data/posts.js.map +1 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +233 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/middleware/api-key-auth.d.ts +6 -0
  25. package/dist/middleware/api-key-auth.js +76 -0
  26. package/dist/middleware/api-key-auth.js.map +1 -0
  27. package/dist/middleware/quota-guard.d.ts +10 -0
  28. package/dist/middleware/quota-guard.js +27 -0
  29. package/dist/middleware/quota-guard.js.map +1 -0
  30. package/dist/middleware/rate-limiter.d.ts +5 -0
  31. package/dist/middleware/rate-limiter.js +50 -0
  32. package/dist/middleware/rate-limiter.js.map +1 -0
  33. package/dist/middleware/request-logger.d.ts +6 -0
  34. package/dist/middleware/request-logger.js +37 -0
  35. package/dist/middleware/request-logger.js.map +1 -0
  36. package/dist/middleware/session-auth.d.ts +19 -0
  37. package/dist/middleware/session-auth.js +99 -0
  38. package/dist/middleware/session-auth.js.map +1 -0
  39. package/dist/providers/aliyun.d.ts +13 -0
  40. package/dist/providers/aliyun.js +20 -0
  41. package/dist/providers/aliyun.js.map +1 -0
  42. package/dist/providers/base-provider.d.ts +36 -0
  43. package/dist/providers/base-provider.js +133 -0
  44. package/dist/providers/base-provider.js.map +1 -0
  45. package/dist/providers/deepseek.d.ts +11 -0
  46. package/dist/providers/deepseek.js +18 -0
  47. package/dist/providers/deepseek.js.map +1 -0
  48. package/dist/providers/registry.d.ts +18 -0
  49. package/dist/providers/registry.js +98 -0
  50. package/dist/providers/registry.js.map +1 -0
  51. package/dist/providers/types.d.ts +17 -0
  52. package/dist/providers/types.js +3 -0
  53. package/dist/providers/types.js.map +1 -0
  54. package/dist/routes/admin.d.ts +1 -0
  55. package/dist/routes/admin.js +153 -0
  56. package/dist/routes/admin.js.map +1 -0
  57. package/dist/routes/auth.d.ts +2 -0
  58. package/dist/routes/auth.js +318 -0
  59. package/dist/routes/auth.js.map +1 -0
  60. package/dist/routes/blog.d.ts +1 -0
  61. package/dist/routes/blog.js +29 -0
  62. package/dist/routes/blog.js.map +1 -0
  63. package/dist/routes/dashboard.d.ts +1 -0
  64. package/dist/routes/dashboard.js +184 -0
  65. package/dist/routes/dashboard.js.map +1 -0
  66. package/dist/routes/messages.d.ts +1 -0
  67. package/dist/routes/messages.js +309 -0
  68. package/dist/routes/messages.js.map +1 -0
  69. package/dist/routes/models.d.ts +1 -0
  70. package/dist/routes/models.js +39 -0
  71. package/dist/routes/models.js.map +1 -0
  72. package/dist/routes/payment.d.ts +1 -0
  73. package/dist/routes/payment.js +150 -0
  74. package/dist/routes/payment.js.map +1 -0
  75. package/dist/routes/sitemap.d.ts +1 -0
  76. package/dist/routes/sitemap.js +38 -0
  77. package/dist/routes/sitemap.js.map +1 -0
  78. package/dist/services/alipay.d.ts +27 -0
  79. package/dist/services/alipay.js +106 -0
  80. package/dist/services/alipay.js.map +1 -0
  81. package/dist/services/database.d.ts +4 -0
  82. package/dist/services/database.js +170 -0
  83. package/dist/services/database.js.map +1 -0
  84. package/dist/services/health-checker.d.ts +13 -0
  85. package/dist/services/health-checker.js +95 -0
  86. package/dist/services/health-checker.js.map +1 -0
  87. package/dist/services/mailer.d.ts +3 -0
  88. package/dist/services/mailer.js +91 -0
  89. package/dist/services/mailer.js.map +1 -0
  90. package/dist/services/metrics.d.ts +56 -0
  91. package/dist/services/metrics.js +94 -0
  92. package/dist/services/metrics.js.map +1 -0
  93. package/dist/services/remote-control.d.ts +20 -0
  94. package/dist/services/remote-control.js +209 -0
  95. package/dist/services/remote-control.js.map +1 -0
  96. package/dist/services/remote-ws.d.ts +5 -0
  97. package/dist/services/remote-ws.js +143 -0
  98. package/dist/services/remote-ws.js.map +1 -0
  99. package/dist/services/usage.d.ts +13 -0
  100. package/dist/services/usage.js +39 -0
  101. package/dist/services/usage.js.map +1 -0
  102. package/dist/utils/errors.d.ts +27 -0
  103. package/dist/utils/errors.js +48 -0
  104. package/dist/utils/errors.js.map +1 -0
  105. package/dist/utils/logger.d.ts +2 -0
  106. package/dist/utils/logger.js +14 -0
  107. package/dist/utils/logger.js.map +1 -0
  108. package/docker-compose.yml +19 -0
  109. package/package.json +39 -0
  110. package/public/robots.txt +8 -0
  111. package/src/config.ts +140 -0
  112. package/src/converter/request.ts +207 -0
  113. package/src/converter/response.ts +85 -0
  114. package/src/converter/stream.ts +373 -0
  115. package/src/converter/types.ts +257 -0
  116. package/src/data/posts.ts +474 -0
  117. package/src/index.ts +219 -0
  118. package/src/middleware/api-key-auth.ts +82 -0
  119. package/src/middleware/quota-guard.ts +28 -0
  120. package/src/middleware/rate-limiter.ts +61 -0
  121. package/src/middleware/request-logger.ts +36 -0
  122. package/src/middleware/session-auth.ts +91 -0
  123. package/src/providers/aliyun.ts +16 -0
  124. package/src/providers/base-provider.ts +148 -0
  125. package/src/providers/deepseek.ts +14 -0
  126. package/src/providers/registry.ts +111 -0
  127. package/src/providers/types.ts +26 -0
  128. package/src/routes/admin.ts +169 -0
  129. package/src/routes/auth.ts +369 -0
  130. package/src/routes/blog.ts +28 -0
  131. package/src/routes/dashboard.ts +208 -0
  132. package/src/routes/messages.ts +346 -0
  133. package/src/routes/models.ts +37 -0
  134. package/src/routes/payment.ts +189 -0
  135. package/src/routes/sitemap.ts +40 -0
  136. package/src/services/alipay.ts +116 -0
  137. package/src/services/database.ts +187 -0
  138. package/src/services/health-checker.ts +115 -0
  139. package/src/services/mailer.ts +90 -0
  140. package/src/services/metrics.ts +104 -0
  141. package/src/services/remote-control.ts +226 -0
  142. package/src/services/remote-ws.ts +145 -0
  143. package/src/services/usage.ts +57 -0
  144. package/src/types/express.d.ts +46 -0
  145. package/src/utils/errors.ts +44 -0
  146. package/src/utils/logger.ts +8 -0
  147. package/tsconfig.json +17 -0
  148. package/views/pages/404.ejs +14 -0
  149. package/views/pages/admin.ejs +307 -0
  150. package/views/pages/blog-post.ejs +378 -0
  151. package/views/pages/blog.ejs +148 -0
  152. package/views/pages/dashboard.ejs +441 -0
  153. package/views/pages/docs.ejs +807 -0
  154. package/views/pages/index.ejs +416 -0
  155. package/views/pages/login.ejs +170 -0
  156. package/views/pages/orders.ejs +111 -0
  157. package/views/pages/pricing.ejs +379 -0
  158. package/views/pages/register.ejs +397 -0
  159. package/views/pages/remote.ejs +334 -0
  160. package/views/pages/settings.ejs +373 -0
  161. package/views/partials/header.ejs +70 -0
  162. package/views/partials/nav.ejs +140 -0
package/dist/index.js ADDED
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const path_1 = __importDefault(require("path"));
40
+ const express_1 = __importDefault(require("express"));
41
+ const cors_1 = __importDefault(require("cors"));
42
+ const helmet_1 = __importDefault(require("helmet"));
43
+ const config_1 = require("./config");
44
+ const database_1 = require("./services/database");
45
+ const registry_1 = require("./providers/registry");
46
+ const health_checker_1 = require("./services/health-checker");
47
+ const session_auth_1 = require("./middleware/session-auth");
48
+ const mailer_1 = require("./services/mailer");
49
+ const alipay_1 = require("./services/alipay");
50
+ const messages_1 = require("./routes/messages");
51
+ const models_1 = require("./routes/models");
52
+ const auth_1 = require("./routes/auth");
53
+ const dashboard_1 = require("./routes/dashboard");
54
+ const admin_1 = require("./routes/admin");
55
+ const payment_1 = require("./routes/payment");
56
+ const blog_1 = require("./routes/blog");
57
+ const sitemap_1 = require("./routes/sitemap");
58
+ const remote_ws_1 = require("./services/remote-ws");
59
+ const request_logger_1 = require("./middleware/request-logger");
60
+ const metrics_1 = require("./services/metrics");
61
+ const logger_1 = require("./utils/logger");
62
+ const app = (0, express_1.default)();
63
+ const config = (0, config_1.loadConfig)();
64
+ // View engine
65
+ app.set('view engine', 'ejs');
66
+ app.set('views', path_1.default.join(__dirname, '..', 'views'));
67
+ // Middleware
68
+ app.use((0, helmet_1.default)({ contentSecurityPolicy: false }));
69
+ app.use((0, cors_1.default)());
70
+ app.use(express_1.default.json({ limit: '10mb' }));
71
+ app.use(express_1.default.urlencoded({ extended: true }));
72
+ app.use(session_auth_1.cookieParser);
73
+ app.use(express_1.default.static(path_1.default.join(__dirname, '..', 'public')));
74
+ // Request logging
75
+ app.use(request_logger_1.requestLogger);
76
+ // Graceful handling of streaming disconnects
77
+ app.use((req, res, next) => {
78
+ res.on('error', (err) => {
79
+ if (['ERR_STREAM_WRITE_AFTER_END', 'EPIPE', 'ECONNRESET'].includes(err.code || '')) {
80
+ return;
81
+ }
82
+ logger_1.logger.error({ err }, 'Response stream error');
83
+ });
84
+ next();
85
+ });
86
+ // Inject viewUser for page rendering (non-blocking)
87
+ app.use(session_auth_1.optionalAuth);
88
+ // ---- API Routes ----
89
+ app.use('/v1', messages_1.messagesRouter);
90
+ app.use('/v1', models_1.modelsRouter);
91
+ app.use('/api/auth', (0, auth_1.createAuthRouter)(config.jwtSecret));
92
+ app.use('/api/dashboard', dashboard_1.dashboardRouter);
93
+ app.use('/api/admin', admin_1.adminRouter);
94
+ app.use('/api/payment', payment_1.paymentRouter);
95
+ app.use(blog_1.blogRouter);
96
+ app.use(sitemap_1.sitemapRouter);
97
+ // ---- Page Routes ----
98
+ app.get('/', (req, res) => {
99
+ res.render('pages/index', { viewUser: req.user || null });
100
+ });
101
+ app.get('/login', (req, res) => {
102
+ if (req.user)
103
+ return res.redirect('/dashboard');
104
+ res.render('pages/login', { viewUser: null });
105
+ });
106
+ app.get('/register', (req, res) => {
107
+ if (req.user)
108
+ return res.redirect('/dashboard');
109
+ res.render('pages/register', { viewUser: null });
110
+ });
111
+ app.get('/dashboard', (req, res) => {
112
+ if (!req.user)
113
+ return res.redirect('/login');
114
+ res.render('pages/dashboard', { viewUser: req.user });
115
+ });
116
+ app.get('/pricing', (req, res) => {
117
+ res.render('pages/pricing', { viewUser: req.user || null });
118
+ });
119
+ app.get('/docs', (req, res) => {
120
+ res.render('pages/docs', { viewUser: req.user || null });
121
+ });
122
+ app.get('/orders', (req, res) => {
123
+ if (!req.user)
124
+ return res.redirect('/login');
125
+ res.render('pages/orders', { viewUser: req.user });
126
+ });
127
+ app.get('/settings', (req, res) => {
128
+ if (!req.user)
129
+ return res.redirect('/login');
130
+ res.render('pages/settings', { viewUser: req.user });
131
+ });
132
+ app.get('/admin', (req, res) => {
133
+ if (!req.user || req.user.role !== 'admin')
134
+ return res.redirect('/login');
135
+ res.render('pages/admin', { viewUser: req.user });
136
+ });
137
+ app.get('/remote', (req, res) => {
138
+ res.render('pages/remote', { viewUser: req.user || null });
139
+ });
140
+ // API: fetch remote session credentials (used by remote page)
141
+ app.get('/api/remote/session/:sessionId', async (req, res) => {
142
+ try {
143
+ const { getRemoteSessionKey } = await Promise.resolve().then(() => __importStar(require('./services/remote-control')));
144
+ const result = await getRemoteSessionKey(req.params.sessionId);
145
+ if (!result) {
146
+ res.status(404).json({ success: false, error: 'Session not found or expired' });
147
+ return;
148
+ }
149
+ res.json({ success: true, ...result });
150
+ }
151
+ catch (err) {
152
+ res.status(500).json({ success: false, error: 'Internal error' });
153
+ }
154
+ });
155
+ // Health check with provider status
156
+ app.get('/health', (_req, res) => {
157
+ const providers = (0, health_checker_1.getHealthStatus)();
158
+ res.json({
159
+ status: 'ok',
160
+ timestamp: new Date().toISOString(),
161
+ providers,
162
+ });
163
+ });
164
+ // Metrics endpoint (admin use)
165
+ app.get('/metrics', (_req, res) => {
166
+ res.json(metrics_1.metrics.getSnapshot());
167
+ });
168
+ // 404
169
+ app.use((req, res) => {
170
+ res.status(404).render('pages/404', { viewUser: req.user || null });
171
+ });
172
+ // Error handler
173
+ app.use((err, _req, res, _next) => {
174
+ logger_1.logger.error({ err }, 'Unhandled error');
175
+ res.status(500).json({
176
+ type: 'error',
177
+ error: { type: 'api_error', message: 'Internal server error' },
178
+ });
179
+ });
180
+ // ---- Startup ----
181
+ async function start() {
182
+ // Initialize config-dependent services
183
+ (0, session_auth_1.setJwtSecret)(config.jwtSecret);
184
+ if (process.env.RESEND_API_KEY) {
185
+ (0, mailer_1.setMailerApiKey)(process.env.RESEND_API_KEY);
186
+ }
187
+ if (process.env.ALIPAY_APP_ID) {
188
+ (0, alipay_1.setAlipayConfig)({
189
+ appId: process.env.ALIPAY_APP_ID,
190
+ privateKey: process.env.ALIPAY_PRIVATE_KEY || '',
191
+ alipayPublicKey: process.env.ALIPAY_PUBLIC_KEY || '',
192
+ gateway: process.env.ALIPAY_GATEWAY || 'https://openapi.alipay.com/gateway.do',
193
+ notifyUrl: `${config.siteUrl}/api/payment/notify`,
194
+ });
195
+ }
196
+ // Database
197
+ await (0, database_1.initDatabase)(config.databaseUrl);
198
+ // Provider registry
199
+ (0, registry_1.initRegistry)(config);
200
+ // Health checker (check every 60s)
201
+ (0, health_checker_1.startHealthChecker)(5 * 60_000); // Every 5 min (uses zero-cost invalid model probe)
202
+ // Start server
203
+ const server = app.listen(config.port, () => {
204
+ logger_1.logger.info({
205
+ port: config.port,
206
+ providers: config.providers.map(p => p.name),
207
+ siteUrl: config.siteUrl,
208
+ }, 'LLM API v2 started');
209
+ });
210
+ // Initialize Remote Control WebSocket server
211
+ (0, remote_ws_1.initRemoteWs)(server);
212
+ // Graceful shutdown
213
+ const shutdown = (signal) => {
214
+ logger_1.logger.info({ signal }, 'Shutting down...');
215
+ (0, health_checker_1.stopHealthChecker)();
216
+ server.close(() => {
217
+ logger_1.logger.info('Server closed');
218
+ process.exit(0);
219
+ });
220
+ // Force exit after 10s
221
+ setTimeout(() => {
222
+ logger_1.logger.warn('Forced shutdown after timeout');
223
+ process.exit(1);
224
+ }, 10_000);
225
+ };
226
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
227
+ process.on('SIGINT', () => shutdown('SIGINT'));
228
+ }
229
+ start().catch((err) => {
230
+ logger_1.logger.error({ err }, 'Failed to start');
231
+ process.exit(1);
232
+ });
233
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ /**
3
+ * Authenticate requests using API key (x-api-key header or Bearer token).
4
+ * Used for /v1/messages and other API routes.
5
+ */
6
+ export declare function apiKeyAuth(req: Request, res: Response, next: NextFunction): Promise<void>;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.apiKeyAuth = apiKeyAuth;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const database_1 = require("../services/database");
9
+ const errors_1 = require("../utils/errors");
10
+ /// <reference path="../types/express.d.ts" />
11
+ /**
12
+ * Authenticate requests using API key (x-api-key header or Bearer token).
13
+ * Used for /v1/messages and other API routes.
14
+ */
15
+ async function apiKeyAuth(req, res, next) {
16
+ try {
17
+ const apiKey = extractApiKey(req);
18
+ if (!apiKey) {
19
+ throw new errors_1.AuthenticationError('Missing API key. Include it in the x-api-key header or Authorization: Bearer header.');
20
+ }
21
+ const pool = (0, database_1.getPool)();
22
+ // Lookup by prefix + SHA-256 hash
23
+ const keyPrefix = apiKey.substring(0, 12);
24
+ const keyHash = crypto_1.default.createHash('sha256').update(apiKey).digest('hex');
25
+ const [keys] = await pool.execute('SELECT * FROM api_keys WHERE key_prefix = ? AND key_hash = ? AND status = ?', [keyPrefix, keyHash, 'active']);
26
+ const matched = keys[0];
27
+ if (!matched) {
28
+ throw new errors_1.AuthenticationError('Invalid API key.');
29
+ }
30
+ // Fetch user
31
+ const [users] = await pool.execute('SELECT * FROM users WHERE id = ?', [matched.user_id]);
32
+ const user = users[0];
33
+ if (!user || user.status !== 'active') {
34
+ throw new errors_1.PermissionError('Account suspended or not found.');
35
+ }
36
+ // Fetch subscription + plan
37
+ const [subs] = await pool.execute(`
38
+ SELECT s.*, p.name as plan_name, p.token_limit_monthly, p.rate_limit_rpm
39
+ FROM subscriptions s JOIN plans p ON s.plan_id = p.id
40
+ WHERE s.user_id = ?
41
+ ORDER BY s.period_start DESC LIMIT 1
42
+ `, [user.id]);
43
+ const sub = subs[0];
44
+ // Check token quota (-1 = unlimited)
45
+ if (sub && Number(sub.token_limit_monthly) !== -1 && Number(sub.tokens_used) >= Number(sub.token_limit_monthly)) {
46
+ throw new errors_1.RateLimitError('Monthly token limit exceeded. Please upgrade your plan.');
47
+ }
48
+ // Attach to request
49
+ req.userId = user.id;
50
+ req.apiUser = user;
51
+ req.apiKey = { id: matched.id, rate_limit: matched.rate_limit };
52
+ req.subscription = sub;
53
+ next();
54
+ }
55
+ catch (err) {
56
+ if (err instanceof errors_1.AuthenticationError || err instanceof errors_1.PermissionError || err instanceof errors_1.RateLimitError) {
57
+ res.status(err.statusCode).json(err.toJSON());
58
+ }
59
+ else {
60
+ next(err);
61
+ }
62
+ }
63
+ }
64
+ function extractApiKey(req) {
65
+ // x-api-key header (Anthropic standard)
66
+ const xApiKey = req.headers['x-api-key'];
67
+ if (typeof xApiKey === 'string')
68
+ return xApiKey;
69
+ // Authorization: Bearer <key>
70
+ const auth = req.headers.authorization;
71
+ if (auth && auth.startsWith('Bearer ')) {
72
+ return auth.slice(7);
73
+ }
74
+ return null;
75
+ }
76
+ //# sourceMappingURL=api-key-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key-auth.js","sourceRoot":"","sources":["../../src/middleware/api-key-auth.ts"],"names":[],"mappings":";;;;;AAUA,gCAyDC;AAnED,oDAA4B;AAE5B,mDAA+C;AAC/C,4CAAuF;AACvF,8CAA8C;AAE9C;;;GAGG;AACI,KAAK,UAAU,UAAU,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC9E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,4BAAmB,CAAC,sFAAsF,CAAC,CAAC;QACxH,CAAC;QAED,MAAM,IAAI,GAAG,IAAA,kBAAO,GAAE,CAAC;QAEvB,kCAAkC;QAClC,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,gBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEzE,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAC/B,6EAA6E,EAC7E,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAC/B,CAAC;QACF,MAAM,OAAO,GAAI,IAAc,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,4BAAmB,CAAC,kBAAkB,CAAC,CAAC;QACpD,CAAC;QAED,aAAa;QACb,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,kCAAkC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1F,MAAM,IAAI,GAAI,KAAe,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,wBAAe,CAAC,iCAAiC,CAAC,CAAC;QAC/D,CAAC;QAED,4BAA4B;QAC5B,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC;;;;;KAKjC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACd,MAAM,GAAG,GAAI,IAAc,CAAC,CAAC,CAAC,CAAC;QAE/B,qCAAqC;QACrC,IAAI,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAChH,MAAM,IAAI,uBAAc,CAAC,yDAAyD,CAAC,CAAC;QACtF,CAAC;QAED,oBAAoB;QACpB,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;QACrB,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;QACnB,GAAG,CAAC,MAAM,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;QAChE,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC;QAEvB,IAAI,EAAE,CAAC;IACT,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,4BAAmB,IAAI,GAAG,YAAY,wBAAe,IAAI,GAAG,YAAY,uBAAc,EAAE,CAAC;YAC1G,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,GAAY;IACjC,wCAAwC;IACxC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACzC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAEhD,8BAA8B;IAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACvC,IAAI,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ /**
3
+ * Pre-request quota check. Must run after apiKeyAuth.
4
+ * Rejects requests if the user has exhausted their monthly token quota.
5
+ *
6
+ * Note: This is a soft guard — the actual deduction happens after the request
7
+ * completes (in usage.ts). Concurrent requests may slightly exceed the quota,
8
+ * which is acceptable for this use case.
9
+ */
10
+ export declare function quotaGuard(req: Request, res: Response, next: NextFunction): void;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.quotaGuard = quotaGuard;
4
+ const errors_1 = require("../utils/errors");
5
+ /**
6
+ * Pre-request quota check. Must run after apiKeyAuth.
7
+ * Rejects requests if the user has exhausted their monthly token quota.
8
+ *
9
+ * Note: This is a soft guard — the actual deduction happens after the request
10
+ * completes (in usage.ts). Concurrent requests may slightly exceed the quota,
11
+ * which is acceptable for this use case.
12
+ */
13
+ function quotaGuard(req, res, next) {
14
+ const sub = req.subscription;
15
+ if (!sub)
16
+ return next();
17
+ // -1 means unlimited (PG may return bigint as string)
18
+ if (Number(sub.token_limit_monthly) === -1)
19
+ return next();
20
+ if (Number(sub.tokens_used) >= Number(sub.token_limit_monthly)) {
21
+ const err = new errors_1.RateLimitError(`Monthly token limit exceeded (${sub.tokens_used.toLocaleString()} / ${sub.token_limit_monthly.toLocaleString()}). Please upgrade your plan.`);
22
+ res.status(err.statusCode).json(err.toJSON());
23
+ return;
24
+ }
25
+ next();
26
+ }
27
+ //# sourceMappingURL=quota-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-guard.js","sourceRoot":"","sources":["../../src/middleware/quota-guard.ts"],"names":[],"mappings":";;AAWA,gCAgBC;AA1BD,4CAAiD;AAEjD;;;;;;;GAOG;AACH,SAAgB,UAAU,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IACxE,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC;IAC7B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,EAAE,CAAC;IAExB,sDAAsD;IACtD,IAAI,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,EAAE,CAAC;IAE1D,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC/D,MAAM,GAAG,GAAG,IAAI,uBAAc,CAC5B,iCAAiC,GAAG,CAAC,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,CAAC,mBAAmB,CAAC,cAAc,EAAE,8BAA8B,CAC9I,CAAC;QACF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ /**
3
+ * Rate limit middleware. Must run after apiKeyAuth (needs req.apiKey and req.subscription).
4
+ */
5
+ export declare function rateLimiter(req: Request, res: Response, next: NextFunction): void;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rateLimiter = rateLimiter;
4
+ const errors_1 = require("../utils/errors");
5
+ /** In-memory sliding window rate limiter, keyed by API key ID. */
6
+ const windows = new Map();
7
+ const WINDOW_MS = 60_000; // 1 minute sliding window
8
+ const CLEANUP_INTERVAL = 5 * 60_000; // Clean up every 5 min
9
+ // Periodic cleanup
10
+ setInterval(() => {
11
+ const now = Date.now();
12
+ for (const [key, entry] of windows) {
13
+ entry.timestamps = entry.timestamps.filter(t => now - t < WINDOW_MS);
14
+ if (entry.timestamps.length === 0)
15
+ windows.delete(key);
16
+ }
17
+ }, CLEANUP_INTERVAL);
18
+ /**
19
+ * Rate limit middleware. Must run after apiKeyAuth (needs req.apiKey and req.subscription).
20
+ */
21
+ function rateLimiter(req, res, next) {
22
+ const keyId = req.apiKey?.id;
23
+ if (!keyId)
24
+ return next();
25
+ const limit = req.subscription?.rate_limit_rpm || req.apiKey?.rate_limit || 60;
26
+ const now = Date.now();
27
+ let entry = windows.get(keyId);
28
+ if (!entry) {
29
+ entry = { timestamps: [] };
30
+ windows.set(keyId, entry);
31
+ }
32
+ // Remove expired timestamps
33
+ entry.timestamps = entry.timestamps.filter(t => now - t < WINDOW_MS);
34
+ if (entry.timestamps.length >= limit) {
35
+ const resetTime = entry.timestamps[0] + WINDOW_MS;
36
+ res.setHeader('X-RateLimit-Limit', String(limit));
37
+ res.setHeader('X-RateLimit-Remaining', '0');
38
+ res.setHeader('X-RateLimit-Reset', String(Math.ceil(resetTime / 1000)));
39
+ res.setHeader('Retry-After', String(Math.ceil((resetTime - now) / 1000)));
40
+ const err = new errors_1.RateLimitError(`Rate limit exceeded. Max ${limit} requests per minute.`);
41
+ res.status(err.statusCode).json(err.toJSON());
42
+ return;
43
+ }
44
+ entry.timestamps.push(now);
45
+ // Set rate limit headers
46
+ res.setHeader('X-RateLimit-Limit', String(limit));
47
+ res.setHeader('X-RateLimit-Remaining', String(limit - entry.timestamps.length));
48
+ next();
49
+ }
50
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/middleware/rate-limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ /**
3
+ * Log every HTTP request with timing.
4
+ * Skips /health to avoid noise.
5
+ */
6
+ export declare function requestLogger(req: Request, res: Response, next: NextFunction): void;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requestLogger = requestLogger;
4
+ const logger_1 = require("../utils/logger");
5
+ /// <reference path="../types/express.d.ts" />
6
+ /**
7
+ * Log every HTTP request with timing.
8
+ * Skips /health to avoid noise.
9
+ */
10
+ function requestLogger(req, res, next) {
11
+ if (req.path === '/health')
12
+ return next();
13
+ const start = Date.now();
14
+ res.on('finish', () => {
15
+ const duration = Date.now() - start;
16
+ const logData = {
17
+ method: req.method,
18
+ path: req.path,
19
+ status: res.statusCode,
20
+ durationMs: duration,
21
+ ip: req.ip || req.headers['x-forwarded-for'] || req.socket.remoteAddress,
22
+ userAgent: req.headers['user-agent']?.slice(0, 100),
23
+ userId: req.userId,
24
+ };
25
+ if (res.statusCode >= 500) {
26
+ logger_1.logger.error(logData, 'Request error');
27
+ }
28
+ else if (res.statusCode >= 400) {
29
+ logger_1.logger.warn(logData, 'Request client error');
30
+ }
31
+ else {
32
+ logger_1.logger.info(logData, 'Request completed');
33
+ }
34
+ });
35
+ next();
36
+ }
37
+ //# sourceMappingURL=request-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-logger.js","sourceRoot":"","sources":["../../src/middleware/request-logger.ts"],"names":[],"mappings":";;AAQA,sCA2BC;AAlCD,4CAAyC;AACzC,8CAA8C;AAE9C;;;GAGG;AACH,SAAgB,aAAa,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC3E,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,EAAE,CAAC;IAE1C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEzB,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACpC,MAAM,OAAO,GAAG;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,UAAU;YACtB,UAAU,EAAE,QAAQ;YACpB,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa;YACxE,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;YACnD,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC;QAEF,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;YAC1B,eAAM,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;YACjC,eAAM,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,eAAM,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ export declare function setJwtSecret(secret: string): void;
3
+ /**
4
+ * Parse cookies from Cookie header (lightweight, no dependency).
5
+ */
6
+ export declare function cookieParser(req: Request, _res: Response, next: NextFunction): void;
7
+ /**
8
+ * Session-based JWT authentication for web dashboard routes.
9
+ * Reads JWT from 'token' cookie.
10
+ */
11
+ export declare function sessionAuth(req: Request, res: Response, next: NextFunction): Promise<void>;
12
+ /**
13
+ * Admin authentication. Extends sessionAuth with role check.
14
+ */
15
+ export declare function adminAuth(req: Request, res: Response, next: NextFunction): Promise<void>;
16
+ /**
17
+ * Inject user info into req.user from cookie (non-blocking, for page rendering).
18
+ */
19
+ export declare function optionalAuth(req: Request, _res: Response, next: NextFunction): Promise<void>;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setJwtSecret = setJwtSecret;
7
+ exports.cookieParser = cookieParser;
8
+ exports.sessionAuth = sessionAuth;
9
+ exports.adminAuth = adminAuth;
10
+ exports.optionalAuth = optionalAuth;
11
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
12
+ const database_1 = require("../services/database");
13
+ /// <reference path="../types/express.d.ts" />
14
+ let jwtSecret = '';
15
+ function setJwtSecret(secret) {
16
+ jwtSecret = secret;
17
+ }
18
+ /**
19
+ * Parse cookies from Cookie header (lightweight, no dependency).
20
+ */
21
+ function cookieParser(req, _res, next) {
22
+ const header = req.headers.cookie || '';
23
+ const cookies = {};
24
+ for (const pair of header.split(';')) {
25
+ const [key, ...rest] = pair.trim().split('=');
26
+ if (key)
27
+ cookies[key] = decodeURIComponent(rest.join('='));
28
+ }
29
+ req.cookies = cookies;
30
+ next();
31
+ }
32
+ /**
33
+ * Session-based JWT authentication for web dashboard routes.
34
+ * Reads JWT from 'token' cookie.
35
+ */
36
+ async function sessionAuth(req, res, next) {
37
+ const token = req.cookies?.token;
38
+ const isApi = req.path.startsWith('/api/');
39
+ const sendUnauth = () => {
40
+ if (isApi) {
41
+ res.status(401).json({ success: false, error: 'Authentication required' });
42
+ }
43
+ else {
44
+ res.redirect('/login');
45
+ }
46
+ };
47
+ if (!token) {
48
+ sendUnauth();
49
+ return;
50
+ }
51
+ try {
52
+ const decoded = jsonwebtoken_1.default.verify(token, jwtSecret);
53
+ const pool = (0, database_1.getPool)();
54
+ const [rows] = await pool.execute('SELECT id, email, name, role, status FROM users WHERE id = ?', [decoded.id]);
55
+ const user = rows[0];
56
+ if (!user || user.status !== 'active') {
57
+ res.clearCookie('token');
58
+ sendUnauth();
59
+ return;
60
+ }
61
+ req.user = user;
62
+ req.userId = user.id;
63
+ next();
64
+ }
65
+ catch {
66
+ res.clearCookie('token');
67
+ sendUnauth();
68
+ }
69
+ }
70
+ /**
71
+ * Admin authentication. Extends sessionAuth with role check.
72
+ */
73
+ async function adminAuth(req, res, next) {
74
+ await sessionAuth(req, res, () => {
75
+ if (req.user?.role === 'admin')
76
+ return next();
77
+ res.status(403).json({ success: false, error: 'Admin access required' });
78
+ });
79
+ }
80
+ /**
81
+ * Inject user info into req.user from cookie (non-blocking, for page rendering).
82
+ */
83
+ async function optionalAuth(req, _res, next) {
84
+ const token = req.cookies?.token;
85
+ if (!token) {
86
+ next();
87
+ return;
88
+ }
89
+ try {
90
+ const decoded = jsonwebtoken_1.default.verify(token, jwtSecret);
91
+ const pool = (0, database_1.getPool)();
92
+ const [rows] = await pool.execute('SELECT id, email, name, role, status FROM users WHERE id = ?', [decoded.id]);
93
+ req.user = rows[0] || undefined;
94
+ req.userId = req.user?.id;
95
+ }
96
+ catch { }
97
+ next();
98
+ }
99
+ //# sourceMappingURL=session-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-auth.js","sourceRoot":"","sources":["../../src/middleware/session-auth.ts"],"names":[],"mappings":";;;;;AAOA,oCAEC;AAKD,oCASC;AAMD,kCAiCC;AAKD,8BAKC;AAKD,oCAaC;AA1FD,gEAA+B;AAE/B,mDAA+C;AAC/C,8CAA8C;AAE9C,IAAI,SAAS,GAAG,EAAE,CAAC;AAEnB,SAAgB,YAAY,CAAC,MAAc;IACzC,SAAS,GAAG,MAAM,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IACxC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,GAAG;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACtB,IAAI,EAAE,CAAC;AACT,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,WAAW,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC/E,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC;IACjC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAE3C,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,IAAI,KAAK,EAAE,CAAC;YACV,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAC7E,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC,KAAK,EAAE,CAAC;QAAC,UAAU,EAAE,CAAC;QAAC,OAAO;IAAC,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAmB,CAAC;QAC/D,MAAM,IAAI,GAAG,IAAA,kBAAO,GAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,8DAA8D,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAChH,MAAM,IAAI,GAAI,IAAc,CAAC,CAAC,CAAC,CAAC;QAEhC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACtC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACzB,UAAU,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChB,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;QACrB,IAAI,EAAE,CAAC;IACT,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACzB,UAAU,EAAE,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,SAAS,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC7E,MAAM,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;QAC/B,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO;YAAE,OAAO,IAAI,EAAE,CAAC;QAC9C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,YAAY,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IACjF,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC;IACjC,IAAI,CAAC,KAAK,EAAE,CAAC;QAAC,IAAI,EAAE,CAAC;QAAC,OAAO;IAAC,CAAC;IAE/B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAmB,CAAC;QAC/D,MAAM,IAAI,GAAG,IAAA,kBAAO,GAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,8DAA8D,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAChH,GAAG,CAAC,IAAI,GAAI,IAAc,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;QAC3C,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { BaseProvider } from './base-provider';
2
+ /**
3
+ * Alibaba Cloud Bailian (DashScope) provider.
4
+ * Native Anthropic endpoint: https://dashscope-intl.aliyuncs.com/apps/anthropic
5
+ *
6
+ * Supports Qwen series models with full Anthropic API compatibility:
7
+ * - Streaming SSE
8
+ * - Tool calling (96.5% accuracy)
9
+ * - Context caching (automatic, reduces cost for repeated prefixes)
10
+ */
11
+ export declare class AliyunProvider extends BaseProvider {
12
+ constructor(anthropicBaseUrl: string, apiKey: string, timeout: number, openaiBaseUrl?: string);
13
+ }