@diogonzafe/tokenwatch 0.2.0 → 0.4.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.
@@ -3,6 +3,10 @@ interface ModelPrice {
3
3
  input: number;
4
4
  /** USD per 1 million output tokens */
5
5
  output: number;
6
+ /** USD per 1 million cached-read input tokens (e.g. OpenAI: 50% of input, Anthropic: 10% of input) */
7
+ cachedInput?: number;
8
+ /** USD per 1 million cache-creation input tokens (Anthropic only, typically 125% of input) */
9
+ cacheCreationInput?: number;
6
10
  /** Maximum context window (input tokens) for this model */
7
11
  maxInputTokens?: number;
8
12
  }
@@ -12,6 +16,14 @@ interface PricesFile {
12
16
  source: string;
13
17
  models: PriceMap;
14
18
  }
19
+ interface BudgetConfig {
20
+ /** USD threshold — fires webhookUrl when per-entity cost exceeds this */
21
+ threshold: number;
22
+ /** Discord / Slack / generic webhook URL */
23
+ webhookUrl: string;
24
+ /** 'once' (default) — fire once per entity lifetime; 'always' — fire on every call that exceeds */
25
+ mode?: 'once' | 'always';
26
+ }
15
27
  interface TrackerConfig {
16
28
  /** 'memory' (default), 'sqlite', or a custom IStorage instance (e.g. PostgresStorage, MySQLStorage, MongoStorage) */
17
29
  storage?: 'memory' | 'sqlite' | IStorage;
@@ -23,15 +35,29 @@ interface TrackerConfig {
23
35
  syncPrices?: boolean;
24
36
  /** Per-model price overrides — highest priority */
25
37
  customPrices?: PriceMap;
38
+ /** Warn if bundled/remote prices are older than N hours (default: 72). Set to 0 to disable. */
39
+ warnIfStaleAfterHours?: number;
40
+ /** Per-user and per-session budget alerts */
41
+ budgets?: {
42
+ perUser?: BudgetConfig;
43
+ perSession?: BudgetConfig;
44
+ };
45
+ /** Log a hint after each call suggesting a cheaper model in the same family when savings > 50% */
46
+ suggestions?: boolean;
26
47
  }
27
48
  interface UsageEntry {
28
49
  model: string;
50
+ /** Regular (non-cached) input tokens */
29
51
  inputTokens: number;
30
52
  outputTokens: number;
31
53
  /** Reasoning/thinking tokens (OpenAI o1/o3/o4). Priced as output tokens.
32
54
  * For Anthropic, this is an approximation (thinking block chars ÷ 4) and is
33
55
  * informational only — thinking output is already included in outputTokens. */
34
56
  reasoningTokens?: number;
57
+ /** Cache-read input tokens (OpenAI: subset of prompt_tokens at 50% price; Anthropic: cache_read_input_tokens at 10% price) */
58
+ cachedTokens?: number;
59
+ /** Cache-creation input tokens (Anthropic only: cache_creation_input_tokens at 125% price) */
60
+ cacheCreationTokens?: number;
35
61
  costUSD: number;
36
62
  sessionId?: string;
37
63
  userId?: string;
@@ -46,6 +72,7 @@ interface ModelStats {
46
72
  input: number;
47
73
  output: number;
48
74
  reasoning: number;
75
+ cached: number;
49
76
  };
50
77
  }
51
78
  interface SessionStats {
@@ -60,6 +87,14 @@ interface FeatureStats {
60
87
  costUSD: number;
61
88
  calls: number;
62
89
  }
90
+ interface ReportOptions {
91
+ /** ISO string or Date — only include entries at or after this time */
92
+ since?: string | Date;
93
+ /** ISO string or Date — only include entries at or before this time */
94
+ until?: string | Date;
95
+ /** Shorthand window: '1h', '6h', '24h', '7d', '30d' — sets `since` relative to now */
96
+ last?: string;
97
+ }
63
98
  interface Report {
64
99
  totalCostUSD: number;
65
100
  totalTokens: {
@@ -74,6 +109,23 @@ interface Report {
74
109
  from: string;
75
110
  to: string;
76
111
  };
112
+ /** ISO date of the prices data in use (bundled or remote) */
113
+ pricesUpdatedAt?: string;
114
+ }
115
+ interface ForecastOptions {
116
+ /** How many recent hours to use for burn-rate calculation (default: 24) */
117
+ windowHours?: number;
118
+ }
119
+ interface CostForecast {
120
+ burnRatePerHour: number;
121
+ projectedDailyCostUSD: number;
122
+ projectedMonthlyCostUSD: number;
123
+ /** Number of hours of data the forecast is based on (may be less than windowHours if tracker is new) */
124
+ basedOnHours: number;
125
+ basedOnPeriod: {
126
+ from: string;
127
+ to: string;
128
+ } | null;
77
129
  }
78
130
  interface IStorage {
79
131
  /** Fire-and-forget — implementations may write async and swallow errors internally */
@@ -85,7 +137,8 @@ interface IStorage {
85
137
  interface Tracker {
86
138
  /** Accumulate a usage entry (called by providers) */
87
139
  track(entry: Omit<UsageEntry, 'costUSD' | 'timestamp'>): void;
88
- getReport(): Promise<Report>;
140
+ getReport(options?: ReportOptions): Promise<Report>;
141
+ getCostForecast(options?: ForecastOptions): Promise<CostForecast>;
89
142
  reset(): Promise<void>;
90
143
  resetSession(sessionId: string): Promise<void>;
91
144
  exportJSON(): Promise<string>;
@@ -93,6 +146,13 @@ interface Tracker {
93
146
  /** Returns price and context window info for a model, or null if unknown */
94
147
  getModelInfo(model: string): ModelPrice | null;
95
148
  }
149
+ interface LazyTracker extends Tracker {
150
+ /**
151
+ * Initialize the tracker with the given config. Must be called before any cost is tracked.
152
+ * Calls before init() are silent no-ops. May only be called once — subsequent calls throw.
153
+ */
154
+ init(config?: TrackerConfig): void;
155
+ }
96
156
  interface TrackingMeta {
97
157
  __sessionId?: string;
98
158
  __userId?: string;
@@ -100,4 +160,4 @@ interface TrackingMeta {
100
160
  __feature?: string;
101
161
  }
102
162
 
103
- export type { IStorage as I, ModelPrice as M, PriceMap as P, Report as R, SessionStats as S, TrackerConfig as T, UsageEntry as U, Tracker as a, TrackingMeta as b, ModelStats as c, PricesFile as d, UserStats as e };
163
+ export type { BudgetConfig as B, CostForecast as C, FeatureStats as F, IStorage as I, LazyTracker as L, ModelPrice as M, PriceMap as P, Report as R, SessionStats as S, TrackerConfig as T, UsageEntry as U, Tracker as a, TrackingMeta as b, ForecastOptions as c, ModelStats as d, PricesFile as e, ReportOptions as f, UserStats as g };