@diogonzafe/tokenwatch 0.1.7 → 0.1.8

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/dist/index.d.ts CHANGED
@@ -1,89 +1,5 @@
1
- interface ModelPrice {
2
- /** USD per 1 million input tokens */
3
- input: number;
4
- /** USD per 1 million output tokens */
5
- output: number;
6
- /** Maximum context window (input tokens) for this model */
7
- maxInputTokens?: number;
8
- }
9
- type PriceMap = Record<string, ModelPrice>;
10
- interface PricesFile {
11
- updated_at: string;
12
- source: string;
13
- models: PriceMap;
14
- }
15
- interface TrackerConfig {
16
- /** 'memory' (default) or 'sqlite' */
17
- storage?: 'memory' | 'sqlite';
18
- /** USD threshold — fires webhookUrl when totalCostUSD exceeds this */
19
- alertThreshold?: number;
20
- /** Discord / Slack / generic webhook URL */
21
- webhookUrl?: string;
22
- /** Fetch fresh prices from remote GitHub source (default: true) */
23
- syncPrices?: boolean;
24
- /** Per-model price overrides — highest priority */
25
- customPrices?: PriceMap;
26
- }
27
- interface UsageEntry {
28
- model: string;
29
- inputTokens: number;
30
- outputTokens: number;
31
- costUSD: number;
32
- sessionId?: string;
33
- userId?: string;
34
- timestamp: string;
35
- }
36
- interface ModelStats {
37
- costUSD: number;
38
- calls: number;
39
- tokens: {
40
- input: number;
41
- output: number;
42
- };
43
- }
44
- interface SessionStats {
45
- costUSD: number;
46
- calls: number;
47
- }
48
- interface UserStats {
49
- costUSD: number;
50
- calls: number;
51
- }
52
- interface Report {
53
- totalCostUSD: number;
54
- totalTokens: {
55
- input: number;
56
- output: number;
57
- };
58
- byModel: Record<string, ModelStats>;
59
- bySession: Record<string, SessionStats>;
60
- byUser: Record<string, UserStats>;
61
- period: {
62
- from: string;
63
- to: string;
64
- };
65
- }
66
- interface IStorage {
67
- record(entry: UsageEntry): void;
68
- getAll(): UsageEntry[];
69
- clearAll(): void;
70
- clearSession(sessionId: string): void;
71
- }
72
- interface Tracker {
73
- /** Accumulate a usage entry (called by providers) */
74
- track(entry: Omit<UsageEntry, 'costUSD' | 'timestamp'>): void;
75
- getReport(): Report;
76
- reset(): void;
77
- resetSession(sessionId: string): void;
78
- exportJSON(): string;
79
- exportCSV(): string;
80
- /** Returns price and context window info for a model, or null if unknown */
81
- getModelInfo(model: string): ModelPrice | null;
82
- }
83
- interface TrackingMeta {
84
- __sessionId?: string;
85
- __userId?: string;
86
- }
1
+ import { T as TrackerConfig, a as Tracker, b as TrackingMeta } from './index-Cy_sl3FI.js';
2
+ export { I as IStorage, M as ModelPrice, c as ModelStats, P as PriceMap, d as PricesFile, R as Report, S as SessionStats, U as UsageEntry, e as UserStats } from './index-Cy_sl3FI.js';
87
3
 
88
4
  declare function createTracker(config?: TrackerConfig): Tracker;
89
5
 
@@ -167,4 +83,4 @@ interface GenAILike {
167
83
  */
168
84
  declare function wrapGemini<T extends GenAILike>(client: T, tracker: Tracker): T;
169
85
 
170
- export { type IStorage, type ModelPrice, type ModelStats, type PriceMap, type PricesFile, type Report, type SessionStats, type Tracker, type TrackerConfig, type TrackingMeta, type UsageEntry, type UserStats, createTracker, wrapAnthropic, wrapOpenAI as wrapDeepSeek, wrapGemini, wrapOpenAI };
86
+ export { Tracker, TrackerConfig, TrackingMeta, createTracker, wrapAnthropic, wrapOpenAI as wrapDeepSeek, wrapGemini, wrapOpenAI };
package/dist/index.js CHANGED
@@ -1338,7 +1338,9 @@ var ModelPriceSchema = z.object({
1338
1338
  maxInputTokens: z.number().positive().optional()
1339
1339
  });
1340
1340
  var TrackerConfigSchema = z.object({
1341
- storage: z.enum(["memory", "sqlite"]).optional().default("memory"),
1341
+ storage: z.union([z.enum(["memory", "sqlite"]), z.custom((v) => {
1342
+ return v !== null && typeof v === "object" && typeof v.record === "function" && typeof v.getAll === "function" && typeof v.clearAll === "function" && typeof v.clearSession === "function";
1343
+ })]).optional().default("memory"),
1342
1344
  alertThreshold: z.number().positive().optional(),
1343
1345
  webhookUrl: z.string().url().optional(),
1344
1346
  syncPrices: z.boolean().optional().default(true),
@@ -1352,13 +1354,13 @@ function createTracker(config = {}) {
1352
1354
  ${issues}`);
1353
1355
  }
1354
1356
  const {
1355
- storage: storageType,
1357
+ storage: storageOption,
1356
1358
  alertThreshold,
1357
1359
  webhookUrl,
1358
1360
  syncPrices,
1359
1361
  customPrices
1360
1362
  } = parsed.data;
1361
- const storage = createStorage(storageType);
1363
+ const storage = typeof storageOption === "object" ? storageOption : createStorage(storageOption);
1362
1364
  let remotePrices;
1363
1365
  if (syncPrices) {
1364
1366
  getRemotePrices().then((result) => {
@@ -1388,9 +1390,13 @@ ${issues}`);
1388
1390
  }
1389
1391
  function maybeFireAlert() {
1390
1392
  if (!alertThreshold || !webhookUrl || alertFired) return;
1391
- const total = computeTotal(storage.getAll());
1392
- if (total >= alertThreshold) {
1393
- alertFired = true;
1393
+ alertFired = true;
1394
+ Promise.resolve(storage.getAll()).then((entries) => {
1395
+ const total = computeTotal(entries);
1396
+ if (total < alertThreshold) {
1397
+ alertFired = false;
1398
+ return;
1399
+ }
1394
1400
  const payload = {
1395
1401
  text: `[tokenwatch] Alert: total cost reached $${total.toFixed(4)} USD (threshold: $${alertThreshold})`
1396
1402
  };
@@ -1400,10 +1406,12 @@ ${issues}`);
1400
1406
  body: JSON.stringify(payload)
1401
1407
  }).catch(() => {
1402
1408
  });
1403
- }
1409
+ }).catch(() => {
1410
+ alertFired = false;
1411
+ });
1404
1412
  }
1405
- function getReport() {
1406
- const entries = storage.getAll();
1413
+ async function getReport() {
1414
+ const entries = await Promise.resolve(storage.getAll());
1407
1415
  const byModel = {};
1408
1416
  const bySession = {};
1409
1417
  const byUser = {};
@@ -1441,18 +1449,18 @@ ${issues}`);
1441
1449
  period: { from: startedAt, to: lastTimestamp }
1442
1450
  };
1443
1451
  }
1444
- function reset() {
1445
- storage.clearAll();
1452
+ async function reset() {
1453
+ await Promise.resolve(storage.clearAll());
1446
1454
  alertFired = false;
1447
1455
  }
1448
- function resetSession(sessionId) {
1449
- storage.clearSession(sessionId);
1456
+ async function resetSession(sessionId) {
1457
+ await Promise.resolve(storage.clearSession(sessionId));
1450
1458
  }
1451
- function exportJSON() {
1452
- return JSON.stringify(getReport(), null, 2);
1459
+ async function exportJSON() {
1460
+ return JSON.stringify(await getReport(), null, 2);
1453
1461
  }
1454
- function exportCSV() {
1455
- const entries = storage.getAll();
1462
+ async function exportCSV() {
1463
+ const entries = await Promise.resolve(storage.getAll());
1456
1464
  const header = "timestamp,model,inputTokens,outputTokens,costUSD,sessionId,userId";
1457
1465
  const rows = entries.map(
1458
1466
  (e) => [