llm-price-tracker 0.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/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+
2
+ The MIT License (MIT)
3
+
4
+ Copyright (c) 2026 Jihong Min
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.ko.md ADDED
@@ -0,0 +1,270 @@
1
+ # LLM Tracker SDK
2
+
3
+ 팀 및 프로젝트별 LLM API 사용량을 추적하는 백엔드 SDK입니다. OpenAI, Claude, Gemini, Azure OpenAI, AWS Bedrock의 토큰 소비량, 비용, API 호출을 모니터링합니다.
4
+
5
+ > **목적**: 회사에서 팀별 또는 프로젝트별 LLM 사용량을 추적하고 분석하기 위해 만들어졌습니다. 비용 관리와 API 소비 현황 파악에 활용하세요.
6
+
7
+ > **주의**: 이 SDK는 **서버 사이드 전용**입니다. Node.js가 필요하며 브라우저에서는 실행할 수 없습니다.
8
+
9
+ ## 주요 기능
10
+
11
+ - **다중 프로바이더 지원**: OpenAI, Claude, Gemini, Azure OpenAI, AWS Bedrock
12
+ - **자동 비용 계산**: LiteLLM에서 실시간 가격 정보 가져옴 (24시간마다 갱신)
13
+ - **다양한 DB 어댑터**: PostgreSQL, MySQL, MongoDB, TypeORM
14
+ - **스트리밍 지원**: OpenAI, Claude, Azure에서 토큰 추적과 함께 스트리밍
15
+ - **배치 처리**: 트래킹 데이터를 큐에 쌓아서 일괄 저장
16
+ - **재시도 로직**: 지수 백오프로 자동 재시도
17
+ - **사용량 통계**: 프로젝트, 프로바이더, 모델, 날짜 범위별 통계 조회
18
+
19
+ ## 설치
20
+
21
+ ```bash
22
+ npm install llm-tracker-sdk
23
+
24
+ # 사용할 DB 드라이버 설치
25
+ npm install pg # PostgreSQL
26
+ npm install mysql2 # MySQL
27
+ npm install mongodb # MongoDB
28
+ ```
29
+
30
+ ## 빠른 시작
31
+
32
+ ```typescript
33
+ import { LLMTrackerSDK, PostgresAdapter } from 'llm-tracker-sdk';
34
+
35
+ const sdk = new LLMTrackerSDK({
36
+ projectName: 'my-project',
37
+ apiKeys: {
38
+ openai: process.env.OPENAI_API_KEY,
39
+ claude: process.env.ANTHROPIC_API_KEY,
40
+ },
41
+ database: new PostgresAdapter({
42
+ connectionString: process.env.DATABASE_URL,
43
+ }),
44
+ });
45
+
46
+ await sdk.connect();
47
+
48
+ const response = await sdk.openai.chat.completions.create({
49
+ model: 'gpt-4o',
50
+ messages: [{ role: 'user', content: '안녕하세요!' }],
51
+ });
52
+
53
+ await sdk.disconnect();
54
+ ```
55
+
56
+ ## 프로바이더
57
+
58
+ ### OpenAI
59
+
60
+ ```typescript
61
+ const response = await sdk.openai.chat.completions.create({
62
+ model: 'gpt-4o',
63
+ messages: [{ role: 'user', content: '안녕하세요!' }],
64
+ response_format: { type: 'json_object' },
65
+ tools: [{ type: 'function', function: { name: 'get_weather', ... } }],
66
+ });
67
+ ```
68
+
69
+ ### Claude
70
+
71
+ ```typescript
72
+ const response = await sdk.claude.messages.create({
73
+ model: 'claude-sonnet-4-20250514',
74
+ max_tokens: 1024,
75
+ messages: [{ role: 'user', content: '안녕하세요!' }],
76
+ });
77
+ ```
78
+
79
+ ### Azure OpenAI
80
+
81
+ ```typescript
82
+ const sdk = new LLMTrackerSDK({
83
+ projectName: 'my-project',
84
+ apiKeys: {
85
+ azure: {
86
+ apiKey: process.env.AZURE_OPENAI_API_KEY,
87
+ endpoint: process.env.AZURE_OPENAI_ENDPOINT,
88
+ deployment: 'gpt-4o',
89
+ apiVersion: '2024-02-15-preview',
90
+ },
91
+ },
92
+ database: new PostgresAdapter({ ... }),
93
+ });
94
+
95
+ const response = await sdk.azure.chat.completions.create({
96
+ model: 'gpt-4o',
97
+ messages: [{ role: 'user', content: '안녕하세요!' }],
98
+ });
99
+ ```
100
+
101
+ ### AWS Bedrock
102
+
103
+ ```typescript
104
+ const sdk = new LLMTrackerSDK({
105
+ projectName: 'my-project',
106
+ apiKeys: {
107
+ bedrock: {
108
+ region: 'us-east-1',
109
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
110
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
111
+ },
112
+ },
113
+ database: new PostgresAdapter({ ... }),
114
+ });
115
+
116
+ const response = await sdk.bedrock.chat({
117
+ modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
118
+ messages: [{ role: 'user', content: '안녕하세요!' }],
119
+ system: 'You are a helpful assistant.',
120
+ maxTokens: 1024,
121
+ });
122
+ ```
123
+
124
+ ### Gemini
125
+
126
+ ```typescript
127
+ const response = await sdk.gemini.generateContent({
128
+ model: 'gemini-1.5-flash',
129
+ contents: [{ role: 'user', parts: [{ text: '안녕하세요!' }] }],
130
+ });
131
+ ```
132
+
133
+ ## 스트리밍
134
+
135
+ ```typescript
136
+ const stream = sdk.openai.chat.completions.stream({
137
+ model: 'gpt-4o',
138
+ messages: [{ role: 'user', content: '안녕하세요!' }],
139
+ });
140
+
141
+ for await (const chunk of stream) {
142
+ process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
143
+ }
144
+ ```
145
+
146
+ ## DB 어댑터
147
+
148
+ ### PostgreSQL
149
+
150
+ ```typescript
151
+ import { PostgresAdapter } from 'llm-tracker-sdk';
152
+
153
+ new PostgresAdapter({
154
+ connectionString: 'postgres://user:pass@localhost:5432/db',
155
+ tableName: 'llm_tracking',
156
+ });
157
+ ```
158
+
159
+ ### MySQL
160
+
161
+ ```typescript
162
+ import { MySQLAdapter } from 'llm-tracker-sdk';
163
+
164
+ new MySQLAdapter({
165
+ host: 'localhost',
166
+ port: 3306,
167
+ database: 'mydb',
168
+ user: 'root',
169
+ password: 'password',
170
+ });
171
+ ```
172
+
173
+ ### MongoDB
174
+
175
+ ```typescript
176
+ import { MongoAdapter } from 'llm-tracker-sdk';
177
+
178
+ new MongoAdapter({
179
+ uri: 'mongodb://localhost:27017',
180
+ database: 'llm_tracking',
181
+ collection: 'api_usage',
182
+ });
183
+ ```
184
+
185
+ ### 커스텀 어댑터
186
+
187
+ ```typescript
188
+ import { DatabaseAdapter, TrackingData } from 'llm-tracker-sdk';
189
+
190
+ class MyAdapter implements DatabaseAdapter {
191
+ async connect(): Promise<void> { /* ... */ }
192
+ async disconnect(): Promise<void> { /* ... */ }
193
+ async save(data: TrackingData): Promise<void> { /* ... */ }
194
+ async saveBatch?(data: TrackingData[]): Promise<void> { /* ... */ }
195
+ async getStats?(filter: StatsFilter): Promise<UsageStats> { /* ... */ }
196
+ }
197
+ ```
198
+
199
+ ## 설정
200
+
201
+ ```typescript
202
+ const sdk = new LLMTrackerSDK({
203
+ projectName: 'my-project',
204
+ apiKeys: { ... },
205
+ database: new PostgresAdapter({ ... }),
206
+
207
+ // 커스텀 가격 (LiteLLM 가격 덮어쓰기)
208
+ customPricing: {
209
+ 'my-custom-model': { inputCostPerToken: 0.00001, outputCostPerToken: 0.00002 },
210
+ },
211
+
212
+ // 재시도 설정
213
+ retry: {
214
+ maxRetries: 3,
215
+ initialDelayMs: 1000,
216
+ maxDelayMs: 10000,
217
+ backoffMultiplier: 2,
218
+ },
219
+
220
+ // 배치 처리
221
+ batchSize: 10,
222
+ batchIntervalMs: 5000,
223
+ });
224
+ ```
225
+
226
+ ## 사용량 통계
227
+
228
+ ```typescript
229
+ const stats = await sdk.getStats({
230
+ projectName: 'my-project',
231
+ provider: 'openai',
232
+ startDate: new Date('2025-01-01'),
233
+ endDate: new Date('2025-01-31'),
234
+ });
235
+
236
+ console.log(stats);
237
+ // {
238
+ // totalRequests: 1000, // 총 요청 수
239
+ // successfulRequests: 995, // 성공한 요청 수
240
+ // failedRequests: 5, // 실패한 요청 수
241
+ // totalTokens: 500000, // 총 토큰 수
242
+ // totalPromptTokens: 200000, // 프롬프트 토큰 수
243
+ // totalCompletionTokens: 300000, // 응답 토큰 수
244
+ // totalCostUsd: 15.50, // 총 비용 (USD)
245
+ // avgLatencyMs: 850 // 평균 응답 시간 (ms)
246
+ // }
247
+ ```
248
+
249
+ ## 저장되는 데이터
250
+
251
+ 각 API 호출 시 자동으로 저장되는 데이터:
252
+
253
+ | 필드 | 설명 |
254
+ |------|------|
255
+ | `requestId` | 고유 요청 ID |
256
+ | `projectName` | 프로젝트 식별자 |
257
+ | `provider` | openai, claude, gemini, azure, bedrock |
258
+ | `model` | 모델명 |
259
+ | `promptTokens` | 입력 토큰 수 |
260
+ | `completionTokens` | 출력 토큰 수 |
261
+ | `totalTokens` | 총 토큰 수 |
262
+ | `costUsd` | 예상 비용 (USD) |
263
+ | `timestamp` | 요청 시간 |
264
+ | `latencyMs` | 응답 소요 시간 |
265
+ | `success` | 성공/실패 여부 |
266
+ | `error` | 에러 메시지 (실패 시) |
267
+
268
+ ## 라이센스
269
+
270
+ MIT
package/README.md ADDED
@@ -0,0 +1,270 @@
1
+ # LLM Tracker SDK
2
+
3
+ A backend SDK for tracking LLM API usage by team and project. Monitors token consumption, costs, and API calls for OpenAI, Claude, Gemini, Azure OpenAI, and AWS Bedrock.
4
+
5
+ > **Purpose**: Created to track and analyze LLM usage by team or project within a company. Use it for cost management and understanding API consumption patterns.
6
+
7
+ > **Note**: This SDK is **server-side only**. It requires Node.js and cannot run in browsers.
8
+
9
+ ## Key Features
10
+
11
+ - **Multi-Provider Support**: OpenAI, Claude, Gemini, Azure OpenAI, AWS Bedrock
12
+ - **Automatic Cost Calculation**: Fetches real-time pricing from LiteLLM (refreshed every 24 hours)
13
+ - **Multiple DB Adapters**: PostgreSQL, MySQL, MongoDB, TypeORM
14
+ - **Streaming Support**: Streaming with token tracking for OpenAI, Claude, Azure
15
+ - **Batch Processing**: Queues tracking data for batch saving
16
+ - **Retry Logic**: Automatic retry with exponential backoff
17
+ - **Usage Statistics**: Query statistics by project, provider, model, and date range
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install llm-tracker-sdk
23
+
24
+ # Install the DB driver you'll use
25
+ npm install pg # PostgreSQL
26
+ npm install mysql2 # MySQL
27
+ npm install mongodb # MongoDB
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```typescript
33
+ import { LLMTrackerSDK, PostgresAdapter } from 'llm-tracker-sdk';
34
+
35
+ const sdk = new LLMTrackerSDK({
36
+ projectName: 'my-project',
37
+ apiKeys: {
38
+ openai: process.env.OPENAI_API_KEY,
39
+ claude: process.env.ANTHROPIC_API_KEY,
40
+ },
41
+ database: new PostgresAdapter({
42
+ connectionString: process.env.DATABASE_URL,
43
+ }),
44
+ });
45
+
46
+ await sdk.connect();
47
+
48
+ const response = await sdk.openai.chat.completions.create({
49
+ model: 'gpt-4o',
50
+ messages: [{ role: 'user', content: 'Hello!' }],
51
+ });
52
+
53
+ await sdk.disconnect();
54
+ ```
55
+
56
+ ## Providers
57
+
58
+ ### OpenAI
59
+
60
+ ```typescript
61
+ const response = await sdk.openai.chat.completions.create({
62
+ model: 'gpt-4o',
63
+ messages: [{ role: 'user', content: 'Hello!' }],
64
+ response_format: { type: 'json_object' },
65
+ tools: [{ type: 'function', function: { name: 'get_weather', ... } }],
66
+ });
67
+ ```
68
+
69
+ ### Claude
70
+
71
+ ```typescript
72
+ const response = await sdk.claude.messages.create({
73
+ model: 'claude-sonnet-4-20250514',
74
+ max_tokens: 1024,
75
+ messages: [{ role: 'user', content: 'Hello!' }],
76
+ });
77
+ ```
78
+
79
+ ### Azure OpenAI
80
+
81
+ ```typescript
82
+ const sdk = new LLMTrackerSDK({
83
+ projectName: 'my-project',
84
+ apiKeys: {
85
+ azure: {
86
+ apiKey: process.env.AZURE_OPENAI_API_KEY,
87
+ endpoint: process.env.AZURE_OPENAI_ENDPOINT,
88
+ deployment: 'gpt-4o',
89
+ apiVersion: '2024-02-15-preview',
90
+ },
91
+ },
92
+ database: new PostgresAdapter({ ... }),
93
+ });
94
+
95
+ const response = await sdk.azure.chat.completions.create({
96
+ model: 'gpt-4o',
97
+ messages: [{ role: 'user', content: 'Hello!' }],
98
+ });
99
+ ```
100
+
101
+ ### AWS Bedrock
102
+
103
+ ```typescript
104
+ const sdk = new LLMTrackerSDK({
105
+ projectName: 'my-project',
106
+ apiKeys: {
107
+ bedrock: {
108
+ region: 'us-east-1',
109
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
110
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
111
+ },
112
+ },
113
+ database: new PostgresAdapter({ ... }),
114
+ });
115
+
116
+ const response = await sdk.bedrock.chat({
117
+ modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
118
+ messages: [{ role: 'user', content: 'Hello!' }],
119
+ system: 'You are a helpful assistant.',
120
+ maxTokens: 1024,
121
+ });
122
+ ```
123
+
124
+ ### Gemini
125
+
126
+ ```typescript
127
+ const response = await sdk.gemini.generateContent({
128
+ model: 'gemini-1.5-flash',
129
+ contents: [{ role: 'user', parts: [{ text: 'Hello!' }] }],
130
+ });
131
+ ```
132
+
133
+ ## Streaming
134
+
135
+ ```typescript
136
+ const stream = sdk.openai.chat.completions.stream({
137
+ model: 'gpt-4o',
138
+ messages: [{ role: 'user', content: 'Hello!' }],
139
+ });
140
+
141
+ for await (const chunk of stream) {
142
+ process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
143
+ }
144
+ ```
145
+
146
+ ## DB Adapters
147
+
148
+ ### PostgreSQL
149
+
150
+ ```typescript
151
+ import { PostgresAdapter } from 'llm-tracker-sdk';
152
+
153
+ new PostgresAdapter({
154
+ connectionString: 'postgres://user:pass@localhost:5432/db',
155
+ tableName: 'llm_tracking',
156
+ });
157
+ ```
158
+
159
+ ### MySQL
160
+
161
+ ```typescript
162
+ import { MySQLAdapter } from 'llm-tracker-sdk';
163
+
164
+ new MySQLAdapter({
165
+ host: 'localhost',
166
+ port: 3306,
167
+ database: 'mydb',
168
+ user: 'root',
169
+ password: 'password',
170
+ });
171
+ ```
172
+
173
+ ### MongoDB
174
+
175
+ ```typescript
176
+ import { MongoAdapter } from 'llm-tracker-sdk';
177
+
178
+ new MongoAdapter({
179
+ uri: 'mongodb://localhost:27017',
180
+ database: 'llm_tracking',
181
+ collection: 'api_usage',
182
+ });
183
+ ```
184
+
185
+ ### Custom Adapter
186
+
187
+ ```typescript
188
+ import { DatabaseAdapter, TrackingData } from 'llm-tracker-sdk';
189
+
190
+ class MyAdapter implements DatabaseAdapter {
191
+ async connect(): Promise<void> { /* ... */ }
192
+ async disconnect(): Promise<void> { /* ... */ }
193
+ async save(data: TrackingData): Promise<void> { /* ... */ }
194
+ async saveBatch?(data: TrackingData[]): Promise<void> { /* ... */ }
195
+ async getStats?(filter: StatsFilter): Promise<UsageStats> { /* ... */ }
196
+ }
197
+ ```
198
+
199
+ ## Configuration
200
+
201
+ ```typescript
202
+ const sdk = new LLMTrackerSDK({
203
+ projectName: 'my-project',
204
+ apiKeys: { ... },
205
+ database: new PostgresAdapter({ ... }),
206
+
207
+ // Custom pricing (overrides LiteLLM pricing)
208
+ customPricing: {
209
+ 'my-custom-model': { inputCostPerToken: 0.00001, outputCostPerToken: 0.00002 },
210
+ },
211
+
212
+ // Retry settings
213
+ retry: {
214
+ maxRetries: 3,
215
+ initialDelayMs: 1000,
216
+ maxDelayMs: 10000,
217
+ backoffMultiplier: 2,
218
+ },
219
+
220
+ // Batch processing
221
+ batchSize: 10,
222
+ batchIntervalMs: 5000,
223
+ });
224
+ ```
225
+
226
+ ## Usage Statistics
227
+
228
+ ```typescript
229
+ const stats = await sdk.getStats({
230
+ projectName: 'my-project',
231
+ provider: 'openai',
232
+ startDate: new Date('2025-01-01'),
233
+ endDate: new Date('2025-01-31'),
234
+ });
235
+
236
+ console.log(stats);
237
+ // {
238
+ // totalRequests: 1000, // Total number of requests
239
+ // successfulRequests: 995, // Number of successful requests
240
+ // failedRequests: 5, // Number of failed requests
241
+ // totalTokens: 500000, // Total tokens
242
+ // totalPromptTokens: 200000, // Prompt tokens
243
+ // totalCompletionTokens: 300000, // Completion tokens
244
+ // totalCostUsd: 15.50, // Total cost (USD)
245
+ // avgLatencyMs: 850 // Average response time (ms)
246
+ // }
247
+ ```
248
+
249
+ ## Stored Data
250
+
251
+ Data automatically saved for each API call:
252
+
253
+ | Field | Description |
254
+ |-------|-------------|
255
+ | `requestId` | Unique request ID |
256
+ | `projectName` | Project identifier |
257
+ | `provider` | openai, claude, gemini, azure, bedrock |
258
+ | `model` | Model name |
259
+ | `promptTokens` | Input token count |
260
+ | `completionTokens` | Output token count |
261
+ | `totalTokens` | Total token count |
262
+ | `costUsd` | Estimated cost (USD) |
263
+ | `timestamp` | Request timestamp |
264
+ | `latencyMs` | Response latency |
265
+ | `success` | Success/failure status |
266
+ | `error` | Error message (on failure) |
267
+
268
+ ## License
269
+
270
+ MIT
@@ -0,0 +1,8 @@
1
+ export { PostgresAdapter } from './postgres';
2
+ export type { PostgresConfig } from './postgres';
3
+ export { MySQLAdapter } from './mysql';
4
+ export type { MySQLConfig } from './mysql';
5
+ export { MongoAdapter } from './mongo';
6
+ export type { MongoConfig } from './mongo';
7
+ export { TypeORMAdapter } from './typeorm';
8
+ export type { TypeORMConfig } from './typeorm';
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TypeORMAdapter = exports.MongoAdapter = exports.MySQLAdapter = exports.PostgresAdapter = void 0;
4
+ var postgres_1 = require("./postgres");
5
+ Object.defineProperty(exports, "PostgresAdapter", { enumerable: true, get: function () { return postgres_1.PostgresAdapter; } });
6
+ var mysql_1 = require("./mysql");
7
+ Object.defineProperty(exports, "MySQLAdapter", { enumerable: true, get: function () { return mysql_1.MySQLAdapter; } });
8
+ var mongo_1 = require("./mongo");
9
+ Object.defineProperty(exports, "MongoAdapter", { enumerable: true, get: function () { return mongo_1.MongoAdapter; } });
10
+ var typeorm_1 = require("./typeorm");
11
+ Object.defineProperty(exports, "TypeORMAdapter", { enumerable: true, get: function () { return typeorm_1.TypeORMAdapter; } });
12
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWRhcHRlcnMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsdUNBQTZDO0FBQXBDLDJHQUFBLGVBQWUsT0FBQTtBQUd4QixpQ0FBdUM7QUFBOUIscUdBQUEsWUFBWSxPQUFBO0FBR3JCLGlDQUF1QztBQUE5QixxR0FBQSxZQUFZLE9BQUE7QUFHckIscUNBQTJDO0FBQWxDLHlHQUFBLGNBQWMsT0FBQSIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IFBvc3RncmVzQWRhcHRlciB9IGZyb20gJy4vcG9zdGdyZXMnO1xuZXhwb3J0IHR5cGUgeyBQb3N0Z3Jlc0NvbmZpZyB9IGZyb20gJy4vcG9zdGdyZXMnO1xuXG5leHBvcnQgeyBNeVNRTEFkYXB0ZXIgfSBmcm9tICcuL215c3FsJztcbmV4cG9ydCB0eXBlIHsgTXlTUUxDb25maWcgfSBmcm9tICcuL215c3FsJztcblxuZXhwb3J0IHsgTW9uZ29BZGFwdGVyIH0gZnJvbSAnLi9tb25nbyc7XG5leHBvcnQgdHlwZSB7IE1vbmdvQ29uZmlnIH0gZnJvbSAnLi9tb25nbyc7XG5cbmV4cG9ydCB7IFR5cGVPUk1BZGFwdGVyIH0gZnJvbSAnLi90eXBlb3JtJztcbmV4cG9ydCB0eXBlIHsgVHlwZU9STUNvbmZpZyB9IGZyb20gJy4vdHlwZW9ybSc7XG4iXX0=
@@ -0,0 +1,15 @@
1
+ import type { DatabaseAdapter, TrackingData } from '../types';
2
+ export interface MongoConfig {
3
+ uri: string;
4
+ database: string;
5
+ collection?: string;
6
+ }
7
+ export declare class MongoAdapter implements DatabaseAdapter {
8
+ private client;
9
+ private collection;
10
+ private config;
11
+ constructor(config: MongoConfig);
12
+ connect(): Promise<void>;
13
+ disconnect(): Promise<void>;
14
+ save(data: TrackingData): Promise<void>;
15
+ }
@@ -0,0 +1,71 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MongoAdapter = void 0;
37
+ class MongoAdapter {
38
+ constructor(config) {
39
+ this.config = config;
40
+ }
41
+ async connect() {
42
+ const { MongoClient } = await Promise.resolve().then(() => __importStar(require('mongodb')));
43
+ this.client = new MongoClient(this.config.uri);
44
+ await this.client.connect();
45
+ const db = this.client.db(this.config.database);
46
+ this.collection = db.collection(this.config.collection ?? 'llm_tracking');
47
+ }
48
+ async disconnect() {
49
+ if (this.client) {
50
+ await this.client.close();
51
+ }
52
+ }
53
+ async save(data) {
54
+ const collection = this.collection;
55
+ await collection.insertOne({
56
+ requestId: data.requestId,
57
+ projectName: data.projectName,
58
+ provider: data.provider,
59
+ model: data.model,
60
+ tokenUsage: data.tokenUsage,
61
+ costUsd: data.costUsd,
62
+ timestamp: data.timestamp,
63
+ latencyMs: data.latencyMs,
64
+ success: data.success,
65
+ error: data.error,
66
+ createdAt: new Date(),
67
+ });
68
+ }
69
+ }
70
+ exports.MongoAdapter = MongoAdapter;
71
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9uZ28uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWRhcHRlcnMvbW9uZ28udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBUUEsTUFBYSxZQUFZO0lBS3ZCLFlBQVksTUFBbUI7UUFDN0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFPO1FBQ1gsTUFBTSxFQUFFLFdBQVcsRUFBRSxHQUFHLHdEQUFhLFNBQVMsR0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMvQyxNQUFPLElBQUksQ0FBQyxNQUEyQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBRWxFLE1BQU0sRUFBRSxHQUFJLElBQUksQ0FBQyxNQUE0QyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3ZGLElBQUksQ0FBQyxVQUFVLEdBQUksRUFBZ0QsQ0FBQyxVQUFVLENBQzVFLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxJQUFJLGNBQWMsQ0FDekMsQ0FBQztJQUNKLENBQUM7SUFFRCxLQUFLLENBQUMsVUFBVTtRQUNkLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLE1BQU8sSUFBSSxDQUFDLE1BQXlDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDaEUsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSSxDQUFDLElBQWtCO1FBQzNCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxVQUErRCxDQUFDO1FBQ3hGLE1BQU0sVUFBVSxDQUFDLFNBQVMsQ0FBQztZQUN6QixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7WUFDekIsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXO1lBQzdCLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtZQUN2QixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQzNCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7WUFDekIsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO1lBQ3pCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7WUFDakIsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO1NBQ3RCLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQTFDRCxvQ0EwQ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IERhdGFiYXNlQWRhcHRlciwgVHJhY2tpbmdEYXRhIH0gZnJvbSAnLi4vdHlwZXMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE1vbmdvQ29uZmlnIHtcbiAgdXJpOiBzdHJpbmc7XG4gIGRhdGFiYXNlOiBzdHJpbmc7XG4gIGNvbGxlY3Rpb24/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBNb25nb0FkYXB0ZXIgaW1wbGVtZW50cyBEYXRhYmFzZUFkYXB0ZXIge1xuICBwcml2YXRlIGNsaWVudDogdW5rbm93bjtcbiAgcHJpdmF0ZSBjb2xsZWN0aW9uOiB1bmtub3duO1xuICBwcml2YXRlIGNvbmZpZzogTW9uZ29Db25maWc7XG5cbiAgY29uc3RydWN0b3IoY29uZmlnOiBNb25nb0NvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICB9XG5cbiAgYXN5bmMgY29ubmVjdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IE1vbmdvQ2xpZW50IH0gPSBhd2FpdCBpbXBvcnQoJ21vbmdvZGInKTtcbiAgICB0aGlzLmNsaWVudCA9IG5ldyBNb25nb0NsaWVudCh0aGlzLmNvbmZpZy51cmkpO1xuICAgIGF3YWl0ICh0aGlzLmNsaWVudCBhcyB7IGNvbm5lY3Q6ICgpID0+IFByb21pc2U8dm9pZD4gfSkuY29ubmVjdCgpO1xuXG4gICAgY29uc3QgZGIgPSAodGhpcy5jbGllbnQgYXMgeyBkYjogKG5hbWU6IHN0cmluZykgPT4gdW5rbm93biB9KS5kYih0aGlzLmNvbmZpZy5kYXRhYmFzZSk7XG4gICAgdGhpcy5jb2xsZWN0aW9uID0gKGRiIGFzIHsgY29sbGVjdGlvbjogKG5hbWU6IHN0cmluZykgPT4gdW5rbm93biB9KS5jb2xsZWN0aW9uKFxuICAgICAgdGhpcy5jb25maWcuY29sbGVjdGlvbiA/PyAnbGxtX3RyYWNraW5nJ1xuICAgICk7XG4gIH1cblxuICBhc3luYyBkaXNjb25uZWN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNsaWVudCkge1xuICAgICAgYXdhaXQgKHRoaXMuY2xpZW50IGFzIHsgY2xvc2U6ICgpID0+IFByb21pc2U8dm9pZD4gfSkuY2xvc2UoKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzYXZlKGRhdGE6IFRyYWNraW5nRGF0YSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNvbGxlY3Rpb24gPSB0aGlzLmNvbGxlY3Rpb24gYXMgeyBpbnNlcnRPbmU6IChkb2M6IHVua25vd24pID0+IFByb21pc2U8dW5rbm93bj4gfTtcbiAgICBhd2FpdCBjb2xsZWN0aW9uLmluc2VydE9uZSh7XG4gICAgICByZXF1ZXN0SWQ6IGRhdGEucmVxdWVzdElkLFxuICAgICAgcHJvamVjdE5hbWU6IGRhdGEucHJvamVjdE5hbWUsXG4gICAgICBwcm92aWRlcjogZGF0YS5wcm92aWRlcixcbiAgICAgIG1vZGVsOiBkYXRhLm1vZGVsLFxuICAgICAgdG9rZW5Vc2FnZTogZGF0YS50b2tlblVzYWdlLFxuICAgICAgY29zdFVzZDogZGF0YS5jb3N0VXNkLFxuICAgICAgdGltZXN0YW1wOiBkYXRhLnRpbWVzdGFtcCxcbiAgICAgIGxhdGVuY3lNczogZGF0YS5sYXRlbmN5TXMsXG4gICAgICBzdWNjZXNzOiBkYXRhLnN1Y2Nlc3MsXG4gICAgICBlcnJvcjogZGF0YS5lcnJvcixcbiAgICAgIGNyZWF0ZWRBdDogbmV3IERhdGUoKSxcbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,18 @@
1
+ import type { DatabaseAdapter, TrackingData } from '../types';
2
+ export interface MySQLConfig {
3
+ host: string;
4
+ port?: number;
5
+ database: string;
6
+ user: string;
7
+ password: string;
8
+ tableName?: string;
9
+ }
10
+ export declare class MySQLAdapter implements DatabaseAdapter {
11
+ private pool;
12
+ private tableName;
13
+ private config;
14
+ constructor(config: MySQLConfig);
15
+ connect(): Promise<void>;
16
+ disconnect(): Promise<void>;
17
+ save(data: TrackingData): Promise<void>;
18
+ }