@diogonzafe/tokenwatch 0.1.8 → 0.1.9

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 (2) hide show
  1. package/README.md +107 -11
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -17,6 +17,11 @@ npm install openai # OpenAI / DeepSeek
17
17
  npm install @anthropic-ai/sdk # Anthropic
18
18
  npm install @google/generative-ai # Gemini
19
19
  npm install better-sqlite3 # optional — only for storage: 'sqlite'
20
+
21
+ # Database adapters (optional — only if using @diogonzafe/tokenwatch/adapters)
22
+ npm install pg # PostgreSQL
23
+ npm install mysql2 # MySQL / MariaDB
24
+ npm install mongodb # MongoDB
20
25
  ```
21
26
 
22
27
  ---
@@ -28,7 +33,7 @@ import { createTracker } from '@diogonzafe/tokenwatch'
28
33
 
29
34
  const tracker = createTracker({
30
35
  // All fields are optional
31
- storage: 'memory', // 'memory' (default) | 'sqlite'
36
+ storage: 'memory', // 'memory' (default) | 'sqlite' | IStorage instance
32
37
  alertThreshold: 1.00, // USD — fires webhookUrl when exceeded
33
38
  webhookUrl: 'https://...', // Discord / Slack webhook
34
39
  syncPrices: true, // fetch fresh prices from GitHub (default: true)
@@ -135,8 +140,10 @@ const res = await deepseek.chat.completions.create({
135
140
 
136
141
  ## Reports
137
142
 
143
+ All report methods are async:
144
+
138
145
  ```ts
139
- tracker.getReport()
146
+ const report = await tracker.getReport()
140
147
  // {
141
148
  // totalCostUSD: 0.087,
142
149
  // totalTokens: { input: 24000, output: 6000 },
@@ -151,12 +158,12 @@ tracker.getReport()
151
158
 
152
159
  tracker.getModelInfo('gpt-4o')
153
160
  // { input: 2.5, output: 10, maxInputTokens: 128000 }
154
- // Returns null if the model is unknown
161
+ // Returns null if the model is unknown (synchronous)
155
162
 
156
- tracker.reset() // clear all data
157
- tracker.resetSession('session_abc') // clear one session
158
- tracker.exportJSON() // full report as JSON string
159
- tracker.exportCSV() // all calls as CSV string
163
+ await tracker.reset() // clear all data
164
+ await tracker.resetSession('session_abc') // clear one session
165
+ await tracker.exportJSON() // full report as JSON string
166
+ await tracker.exportCSV() // all calls as CSV string
160
167
  ```
161
168
 
162
169
  ---
@@ -167,7 +174,7 @@ Prices are resolved in this priority order:
167
174
 
168
175
  1. **`customPrices`** — your own overrides, highest priority
169
176
  2. **Remote `prices.json`** — fetched from GitHub, cached for 24h in `~/.tokenwatch/prices.json`
170
- 3. **Bundled `prices.json`** — always-present fallback, updated weekly via GitHub Action
177
+ 3. **Bundled `prices.json`** — always-present fallback, updated daily via GitHub Action
171
178
 
172
179
  If a model is not found in any layer, cost is recorded as **$0** with a `console.warn`.
173
180
 
@@ -188,11 +195,20 @@ Prices are in **USD per 1 million tokens**.
188
195
  }
189
196
  ```
190
197
 
191
- Prices are updated every Monday via a GitHub Action that pulls from the [LiteLLM community model registry](https://github.com/BerriAI/litellm). New models are auto-discovered — no manual updates needed.
198
+ Prices are updated every day via a GitHub Action that pulls from the [LiteLLM community model registry](https://github.com/BerriAI/litellm). New models are auto-discovered — no manual updates needed.
192
199
 
193
200
  ---
194
201
 
195
- ## SQLite Storage
202
+ ## Storage
203
+
204
+ ### In-memory (default)
205
+
206
+ ```ts
207
+ const tracker = createTracker({ storage: 'memory' })
208
+ // Resets on process restart. Good for short-lived processes and testing.
209
+ ```
210
+
211
+ ### SQLite
196
212
 
197
213
  For persistent tracking across restarts:
198
214
 
@@ -205,6 +221,76 @@ const tracker = createTracker({ storage: 'sqlite' })
205
221
  // Data stored in ~/.tokenwatch/usage.db
206
222
  ```
207
223
 
224
+ ### PostgreSQL
225
+
226
+ ```bash
227
+ npm install pg
228
+ ```
229
+
230
+ ```ts
231
+ import { Pool } from 'pg'
232
+ import { createTracker } from '@diogonzafe/tokenwatch'
233
+ import { PostgresStorage } from '@diogonzafe/tokenwatch/adapters'
234
+
235
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL })
236
+ const storage = new PostgresStorage(pool)
237
+ await storage.migrate() // creates tokenwatch_usage table if it doesn't exist
238
+
239
+ const tracker = createTracker({ storage })
240
+ ```
241
+
242
+ ### MySQL / MariaDB
243
+
244
+ ```bash
245
+ npm install mysql2
246
+ ```
247
+
248
+ ```ts
249
+ import mysql from 'mysql2/promise'
250
+ import { MySQLStorage } from '@diogonzafe/tokenwatch/adapters'
251
+
252
+ const pool = mysql.createPool({ uri: process.env.MYSQL_URL })
253
+ const storage = new MySQLStorage(pool)
254
+ await storage.migrate()
255
+
256
+ const tracker = createTracker({ storage })
257
+ ```
258
+
259
+ ### MongoDB
260
+
261
+ ```bash
262
+ npm install mongodb
263
+ ```
264
+
265
+ ```ts
266
+ import { MongoClient } from 'mongodb'
267
+ import { MongoStorage } from '@diogonzafe/tokenwatch/adapters'
268
+
269
+ const client = new MongoClient(process.env.MONGO_URL!)
270
+ await client.connect()
271
+ const storage = new MongoStorage(client.db('myapp'))
272
+ await storage.createIndexes() // optional but recommended
273
+
274
+ const tracker = createTracker({ storage })
275
+ ```
276
+
277
+ ### Custom adapter
278
+
279
+ Any object that implements `IStorage` works:
280
+
281
+ ```ts
282
+ import type { IStorage, UsageEntry } from '@diogonzafe/tokenwatch'
283
+
284
+ class RedisStorage implements IStorage {
285
+ record(entry: UsageEntry): void { /* ... */ }
286
+ async getAll(): Promise<UsageEntry[]> { /* ... */ }
287
+ async clearAll(): Promise<void> { /* ... */ }
288
+ async clearSession(sessionId: string): Promise<void> { /* ... */ }
289
+ }
290
+
291
+ const tracker = createTracker({ storage: new RedisStorage() })
292
+ ```
293
+
208
294
  ---
209
295
 
210
296
  ## Alerts & Webhooks
@@ -235,13 +321,23 @@ npx tokenwatch help # show help
235
321
 
236
322
  ---
237
323
 
324
+ ## Privacy & Security
325
+
326
+ - Prompt and response **content is never read or stored** — only token counts and model names
327
+ - API keys are **never accessed** by tokenwatch — they remain solely in the provider client
328
+ - SQLite, Postgres, MySQL, and MongoDB data stays **entirely in your own infrastructure** — nothing is transmitted to external services
329
+ - The wrapper is a thin `Proxy` with **no outbound network calls** of its own (only the daily price sync script fetches external data)
330
+
331
+ ---
332
+
238
333
  ## Behaviour Guarantees
239
334
 
240
335
  - `__sessionId` and `__userId` are **stripped before** the request reaches the API
241
336
  - The response object returned is **identical** to the original SDK response
242
- - Tracking operations are **synchronous and non-blocking** — zero latency added
337
+ - `track()` is **synchronous and non-blocking** — zero latency added to API calls
243
338
  - If the API call **fails**, no cost is recorded and the original error is re-thrown unchanged
244
339
  - Streaming is fully supported — usage is accumulated from the final stream event
340
+ - Database writes from `record()` are **fire-and-forget** — a storage failure never interrupts your API call
245
341
 
246
342
  ---
247
343
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diogonzafe/tokenwatch",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Transparent wrapper to track LLM API costs in real-time by session, user and model",
5
5
  "author": "diogonzafe",
6
6
  "license": "MIT",