@diogonzafe/tokenwatch 0.7.0 → 0.9.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/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-D9xq0RNg.cjs';
2
- export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-D9xq0RNg.cjs';
1
+ import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-fD5QLTWg.cjs';
2
+ export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-fD5QLTWg.cjs';
3
3
 
4
4
  declare function createTracker(config?: TrackerConfig): Tracker;
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-D9xq0RNg.js';
2
- export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-D9xq0RNg.js';
1
+ import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-fD5QLTWg.js';
2
+ export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-fD5QLTWg.js';
3
3
 
4
4
  declare function createTracker(config?: TrackerConfig): Tracker;
5
5
 
package/dist/index.js CHANGED
@@ -33,6 +33,40 @@ function calculateCost(inputTokens, outputTokens, price, cachedTokens = 0, cache
33
33
  return regularInputCost + cachedReadCost + cacheCreationCost + outputCost;
34
34
  }
35
35
 
36
+ // src/exporters/cloud.ts
37
+ var DEFAULT_ENDPOINT = "https://api.tokenwatch.dev/v1/ingest";
38
+ var CloudExporter = class {
39
+ constructor(apiKey, endpoint) {
40
+ this.apiKey = apiKey;
41
+ this.endpoint = endpoint ?? DEFAULT_ENDPOINT;
42
+ }
43
+ apiKey;
44
+ endpoint;
45
+ export(entry) {
46
+ fetch(this.endpoint, {
47
+ method: "POST",
48
+ headers: {
49
+ "Content-Type": "application/json",
50
+ Authorization: `Bearer ${this.apiKey}`
51
+ },
52
+ body: JSON.stringify({
53
+ model: entry.model,
54
+ inputTokens: entry.inputTokens,
55
+ outputTokens: entry.outputTokens,
56
+ reasoningTokens: entry.reasoningTokens ?? 0,
57
+ cachedTokens: entry.cachedTokens ?? 0,
58
+ cacheCreationTokens: entry.cacheCreationTokens ?? 0,
59
+ costUSD: entry.costUSD,
60
+ sessionId: entry.sessionId,
61
+ userId: entry.userId,
62
+ feature: entry.feature,
63
+ timestamp: entry.timestamp
64
+ })
65
+ }).catch(() => {
66
+ });
67
+ }
68
+ };
69
+
36
70
  // src/core/suggestions.ts
37
71
  var PROVIDER_PREFIXES = ["gpt-", "claude-", "gemini-", "deepseek-"];
38
72
  function getProviderPrefix(model) {
@@ -122,6 +156,7 @@ var SqliteStorage = class {
122
156
  session_id TEXT,
123
157
  user_id TEXT,
124
158
  feature TEXT,
159
+ app_id TEXT,
125
160
  timestamp TEXT NOT NULL
126
161
  )
127
162
  `);
@@ -138,13 +173,16 @@ var SqliteStorage = class {
138
173
  if (!cols.includes("cache_creation_tokens")) {
139
174
  this.db.exec(`ALTER TABLE usage ADD COLUMN cache_creation_tokens INTEGER NOT NULL DEFAULT 0`);
140
175
  }
176
+ if (!cols.includes("app_id")) {
177
+ this.db.exec(`ALTER TABLE usage ADD COLUMN app_id TEXT`);
178
+ }
141
179
  }
142
180
  record(entry) {
143
181
  this.db.prepare(
144
182
  `INSERT INTO usage
145
183
  (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,
146
- cost_usd, session_id, user_id, feature, timestamp)
147
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
184
+ cost_usd, session_id, user_id, feature, app_id, timestamp)
185
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
148
186
  ).run(
149
187
  entry.model,
150
188
  entry.inputTokens,
@@ -156,6 +194,7 @@ var SqliteStorage = class {
156
194
  entry.sessionId ?? null,
157
195
  entry.userId ?? null,
158
196
  entry.feature ?? null,
197
+ entry.appId ?? null,
159
198
  entry.timestamp
160
199
  );
161
200
  }
@@ -172,6 +211,7 @@ var SqliteStorage = class {
172
211
  ...r.session_id != null && { sessionId: r.session_id },
173
212
  ...r.user_id != null && { userId: r.user_id },
174
213
  ...r.feature != null && { feature: r.feature },
214
+ ...r.app_id != null && { appId: r.app_id },
175
215
  timestamp: r.timestamp
176
216
  }));
177
217
  }
@@ -237,7 +277,7 @@ async function getRemotePrices() {
237
277
 
238
278
  // prices.json
239
279
  var prices_default = {
240
- updated_at: "2026-04-24",
280
+ updated_at: "2026-06-09",
241
281
  source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
242
282
  models: {
243
283
  "gpt-4o": {
@@ -281,14 +321,12 @@ var prices_default = {
281
321
  input: 3,
282
322
  output: 15,
283
323
  cachedInput: 0.3,
284
- cacheCreationInput: 3.75,
285
- maxInputTokens: 1e6
324
+ maxInputTokens: 2e5
286
325
  },
287
326
  "claude-haiku-4-5": {
288
327
  input: 1,
289
328
  output: 5,
290
329
  cachedInput: 0.1,
291
- cacheCreationInput: 1.25,
292
330
  maxInputTokens: 2e5
293
331
  },
294
332
  "gemini-2.5-pro": {
@@ -340,7 +378,6 @@ var prices_default = {
340
378
  input: 3,
341
379
  output: 15,
342
380
  cachedInput: 0.3,
343
- cacheCreationInput: 3.75,
344
381
  maxInputTokens: 2e5
345
382
  },
346
383
  "gpt-oss-120b": {
@@ -833,9 +870,9 @@ var prices_default = {
833
870
  maxInputTokens: 163840
834
871
  },
835
872
  "deepseek-r1": {
836
- input: 0.55,
837
- output: 2.19,
838
- maxInputTokens: 65536
873
+ input: 1.35,
874
+ output: 5.4,
875
+ maxInputTokens: 128e3
839
876
  },
840
877
  "deepseek-v3": {
841
878
  input: 0.27,
@@ -1275,7 +1312,7 @@ var prices_default = {
1275
1312
  "deepseek-r1-distill-llama-70b": {
1276
1313
  input: 0.99,
1277
1314
  output: 0.99,
1278
- maxInputTokens: 8e3
1315
+ maxInputTokens: 32768
1279
1316
  },
1280
1317
  "deepseek-llama3.3-70b": {
1281
1318
  input: 0.2,
@@ -1559,7 +1596,97 @@ var prices_default = {
1559
1596
  input: 5,
1560
1597
  output: 30,
1561
1598
  cachedInput: 0.5,
1599
+ maxInputTokens: 105e4
1600
+ },
1601
+ "gpt-5.5-2026-04-23": {
1602
+ input: 5,
1603
+ output: 30,
1604
+ cachedInput: 0.5,
1605
+ maxInputTokens: 105e4
1606
+ },
1607
+ "gpt-5.5-pro": {
1608
+ input: 30,
1609
+ output: 180,
1610
+ cachedInput: 3,
1611
+ maxInputTokens: 105e4
1612
+ },
1613
+ "gpt-5.5-pro-2026-04-23": {
1614
+ input: 30,
1615
+ output: 180,
1616
+ cachedInput: 3,
1617
+ maxInputTokens: 105e4
1618
+ },
1619
+ "gpt-5.4-mini-2026-03-17": {
1620
+ input: 0.75,
1621
+ output: 4.5,
1622
+ cachedInput: 0.075,
1623
+ maxInputTokens: 272e3
1624
+ },
1625
+ "gpt-5.4-nano-2026-03-17": {
1626
+ input: 0.2,
1627
+ output: 1.25,
1628
+ cachedInput: 0.02,
1562
1629
  maxInputTokens: 272e3
1630
+ },
1631
+ "gpt-image-2": {
1632
+ input: 5,
1633
+ output: 10,
1634
+ cachedInput: 1.25
1635
+ },
1636
+ "gpt-image-2-2026-04-21": {
1637
+ input: 5,
1638
+ output: 10,
1639
+ cachedInput: 1.25
1640
+ },
1641
+ "gpt-realtime-2": {
1642
+ input: 4,
1643
+ output: 16,
1644
+ cachedInput: 0.4,
1645
+ maxInputTokens: 32e3
1646
+ },
1647
+ "gemini-3.5-flash": {
1648
+ input: 1.5,
1649
+ output: 9,
1650
+ cachedInput: 0.15,
1651
+ maxInputTokens: 1048576
1652
+ },
1653
+ "gemini-3.1-flash-lite": {
1654
+ input: 0.25,
1655
+ output: 1.5,
1656
+ cachedInput: 0.025,
1657
+ maxInputTokens: 1048576
1658
+ },
1659
+ "claude-opus-4-8": {
1660
+ input: 5,
1661
+ output: 25,
1662
+ cachedInput: 0.5,
1663
+ cacheCreationInput: 6.25,
1664
+ maxInputTokens: 1e6
1665
+ },
1666
+ "claude-opus-4-8@default": {
1667
+ input: 5,
1668
+ output: 25,
1669
+ cachedInput: 0.5,
1670
+ cacheCreationInput: 6.25,
1671
+ maxInputTokens: 1e6
1672
+ },
1673
+ "claude-4-sonnet": {
1674
+ input: 3,
1675
+ output: 15,
1676
+ cachedInput: 0.3,
1677
+ maxInputTokens: 2e5
1678
+ },
1679
+ "claude-4-opus": {
1680
+ input: 5,
1681
+ output: 25,
1682
+ cachedInput: 0.5,
1683
+ maxInputTokens: 2e5
1684
+ },
1685
+ "claude-3-7-sonnet": {
1686
+ input: 3,
1687
+ output: 15,
1688
+ cachedInput: 0.3,
1689
+ maxInputTokens: 2e5
1563
1690
  }
1564
1691
  }
1565
1692
  };
@@ -1599,7 +1726,10 @@ var TrackerConfigSchema = z.object({
1599
1726
  windowHours: z.number().positive().optional().default(24),
1600
1727
  mode: z.enum(["once", "always"]).optional().default("once")
1601
1728
  }).optional(),
1602
- exporter: z.custom((v) => v !== null && typeof v === "object" && typeof v.export === "function").optional()
1729
+ exporter: z.custom((v) => v !== null && typeof v === "object" && typeof v.export === "function").optional(),
1730
+ appId: z.string().optional(),
1731
+ cloudApiKey: z.string().optional(),
1732
+ cloudEndpoint: z.string().url().optional()
1603
1733
  });
1604
1734
  function createTracker(config = {}) {
1605
1735
  const parsed = TrackerConfigSchema.safeParse(config);
@@ -1618,9 +1748,13 @@ ${issues}`);
1618
1748
  budgets,
1619
1749
  suggestions,
1620
1750
  anomalyDetection,
1621
- exporter
1751
+ exporter,
1752
+ appId,
1753
+ cloudApiKey,
1754
+ cloudEndpoint
1622
1755
  } = parsed.data;
1623
1756
  const storage = typeof storageOption === "object" ? storageOption : createStorage(storageOption);
1757
+ const cloudExporter = cloudApiKey ? new CloudExporter(cloudApiKey, cloudEndpoint) : null;
1624
1758
  let remotePrices;
1625
1759
  let pricesUpdatedAt = bundledUpdatedAt;
1626
1760
  if (syncPrices) {
@@ -1673,13 +1807,17 @@ ${issues}`);
1673
1807
  const full = {
1674
1808
  ...entry,
1675
1809
  costUSD,
1676
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1810
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1811
+ ...appId !== void 0 && entry.appId === void 0 && { appId }
1677
1812
  };
1678
1813
  storage.record(full);
1679
1814
  if (exporter) {
1680
1815
  Promise.resolve(exporter.export(full)).catch(() => {
1681
1816
  });
1682
1817
  }
1818
+ if (cloudExporter) {
1819
+ cloudExporter.export(full);
1820
+ }
1683
1821
  maybeFireAlerts(full);
1684
1822
  if (anomalyDetection) maybeDetectAnomaly(full);
1685
1823
  if (suggestions) {
@@ -1760,6 +1898,7 @@ ${issues}`);
1760
1898
  const bySession = {};
1761
1899
  const byUser = {};
1762
1900
  const byFeature = {};
1901
+ const byApp = {};
1763
1902
  let totalInput = 0;
1764
1903
  let totalOutput = 0;
1765
1904
  let totalCost = 0;
@@ -1796,6 +1935,11 @@ ${issues}`);
1796
1935
  f.costUSD += e.costUSD;
1797
1936
  f.calls += 1;
1798
1937
  }
1938
+ if (e.appId) {
1939
+ const a = byApp[e.appId] ??= { costUSD: 0, calls: 0 };
1940
+ a.costUSD += e.costUSD;
1941
+ a.calls += 1;
1942
+ }
1799
1943
  }
1800
1944
  if (options && entries.length > 0) {
1801
1945
  periodFrom = entries[0]?.timestamp ?? periodFrom;
@@ -1807,6 +1951,7 @@ ${issues}`);
1807
1951
  bySession,
1808
1952
  byUser,
1809
1953
  byFeature,
1954
+ byApp,
1810
1955
  period: { from: periodFrom, to: lastTimestamp },
1811
1956
  ...pricesUpdatedAt ? { pricesUpdatedAt } : {}
1812
1957
  };
@@ -1911,7 +2056,7 @@ ${issues}`);
1911
2056
  }
1912
2057
  async function exportCSV() {
1913
2058
  const entries = await Promise.resolve(storage.getAll());
1914
- const header = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature";
2059
+ const header = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature,appId";
1915
2060
  const rows = entries.map(
1916
2061
  (e) => [
1917
2062
  csvEscape(e.timestamp),
@@ -1924,7 +2069,8 @@ ${issues}`);
1924
2069
  e.costUSD.toFixed(8),
1925
2070
  csvEscape(e.sessionId ?? ""),
1926
2071
  csvEscape(e.userId ?? ""),
1927
- csvEscape(e.feature ?? "")
2072
+ csvEscape(e.feature ?? ""),
2073
+ csvEscape(e.appId ?? "")
1928
2074
  ].join(",")
1929
2075
  );
1930
2076
  return [header, ...rows].join("\n");
@@ -1985,7 +2131,7 @@ function csvEscape(value) {
1985
2131
  }
1986
2132
 
1987
2133
  // src/core/lazy-tracker.ts
1988
- var CSV_HEADER = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature";
2134
+ var CSV_HEADER = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature,appId";
1989
2135
  function emptyReport() {
1990
2136
  const now = (/* @__PURE__ */ new Date()).toISOString();
1991
2137
  return {
@@ -1995,6 +2141,7 @@ function emptyReport() {
1995
2141
  bySession: {},
1996
2142
  byUser: {},
1997
2143
  byFeature: {},
2144
+ byApp: {},
1998
2145
  period: { from: now, to: now }
1999
2146
  };
2000
2147
  }