@diogonzafe/tokenwatch 0.2.1 → 0.5.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.
@@ -1,4 +1,4 @@
1
- import { I as IStorage, U as UsageEntry } from './index-B_EmA3K7.js';
1
+ import { I as IStorage, U as UsageEntry } from './index-CJKk1hHw.js';
2
2
 
3
3
  /**
4
4
  * IStorage adapter for PostgreSQL using the `pg` driver.
@@ -28,7 +28,7 @@ declare class PostgresStorage implements IStorage {
28
28
  private readonly client;
29
29
  constructor(client: QueryClient$1);
30
30
  /** Creates the `tokenwatch_usage` table if it does not already exist.
31
- * Also adds new columns for databases created before v0.2.0. */
31
+ * Also adds new columns for databases created before v0.2.0 / v0.3.0. */
32
32
  migrate(): Promise<void>;
33
33
  record(entry: UsageEntry): void;
34
34
  getAll(): Promise<UsageEntry[]>;
@@ -61,7 +61,7 @@ declare class MySQLStorage implements IStorage {
61
61
  private readonly client;
62
62
  constructor(client: QueryClient);
63
63
  /** Creates the `tokenwatch_usage` table if it does not already exist.
64
- * Also adds new columns for databases created before v0.2.0. */
64
+ * Also adds new columns for databases created before v0.2.0 / v0.3.0. */
65
65
  migrate(): Promise<void>;
66
66
  record(entry: UsageEntry): void;
67
67
  getAll(): Promise<UsageEntry[]>;
@@ -98,6 +98,8 @@ interface MongoDocument {
98
98
  inputTokens: number;
99
99
  outputTokens: number;
100
100
  reasoningTokens?: number;
101
+ cachedTokens?: number;
102
+ cacheCreationTokens?: number;
101
103
  costUSD: number;
102
104
  sessionId?: string | null;
103
105
  userId?: string | null;
package/dist/adapters.js CHANGED
@@ -5,41 +5,47 @@ var PostgresStorage = class {
5
5
  }
6
6
  client;
7
7
  /** Creates the `tokenwatch_usage` table if it does not already exist.
8
- * Also adds new columns for databases created before v0.2.0. */
8
+ * Also adds new columns for databases created before v0.2.0 / v0.3.0. */
9
9
  async migrate() {
10
10
  await this.client.query(`
11
11
  CREATE TABLE IF NOT EXISTS tokenwatch_usage (
12
- id BIGSERIAL PRIMARY KEY,
13
- model TEXT NOT NULL,
14
- input_tokens INTEGER NOT NULL,
15
- output_tokens INTEGER NOT NULL,
16
- reasoning_tokens INTEGER NOT NULL DEFAULT 0,
17
- cost_usd NUMERIC NOT NULL,
18
- session_id TEXT,
19
- user_id TEXT,
20
- feature TEXT,
21
- timestamp TIMESTAMPTZ NOT NULL
12
+ id BIGSERIAL PRIMARY KEY,
13
+ model TEXT NOT NULL,
14
+ input_tokens INTEGER NOT NULL,
15
+ output_tokens INTEGER NOT NULL,
16
+ reasoning_tokens INTEGER NOT NULL DEFAULT 0,
17
+ cached_tokens INTEGER NOT NULL DEFAULT 0,
18
+ cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
19
+ cost_usd NUMERIC NOT NULL,
20
+ session_id TEXT,
21
+ user_id TEXT,
22
+ feature TEXT,
23
+ timestamp TIMESTAMPTZ NOT NULL
22
24
  )
23
25
  `);
24
- await this.client.query(`
25
- ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS reasoning_tokens INTEGER NOT NULL DEFAULT 0
26
- `).catch(() => {
27
- });
28
- await this.client.query(`
29
- ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS feature TEXT
30
- `).catch(() => {
31
- });
26
+ for (const col of [
27
+ "ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS reasoning_tokens INTEGER NOT NULL DEFAULT 0",
28
+ "ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS feature TEXT",
29
+ "ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS cached_tokens INTEGER NOT NULL DEFAULT 0",
30
+ "ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS cache_creation_tokens INTEGER NOT NULL DEFAULT 0"
31
+ ]) {
32
+ await this.client.query(col).catch(() => {
33
+ });
34
+ }
32
35
  }
33
36
  record(entry) {
34
37
  this.client.query(
35
38
  `INSERT INTO tokenwatch_usage
36
- (model, input_tokens, output_tokens, reasoning_tokens, cost_usd, session_id, user_id, feature, timestamp)
37
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
39
+ (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,
40
+ cost_usd, session_id, user_id, feature, timestamp)
41
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
38
42
  [
39
43
  entry.model,
40
44
  entry.inputTokens,
41
45
  entry.outputTokens,
42
46
  entry.reasoningTokens ?? 0,
47
+ entry.cachedTokens ?? 0,
48
+ entry.cacheCreationTokens ?? 0,
43
49
  entry.costUSD,
44
50
  entry.sessionId ?? null,
45
51
  entry.userId ?? null,
@@ -68,11 +74,15 @@ var PostgresStorage = class {
68
74
  };
69
75
  function rowToEntry(r) {
70
76
  const reasoningTokens = r["reasoning_tokens"] ?? 0;
77
+ const cachedTokens = r["cached_tokens"] ?? 0;
78
+ const cacheCreationTokens = r["cache_creation_tokens"] ?? 0;
71
79
  return {
72
80
  model: r["model"],
73
81
  inputTokens: r["input_tokens"],
74
82
  outputTokens: r["output_tokens"],
75
83
  ...reasoningTokens > 0 && { reasoningTokens },
84
+ ...cachedTokens > 0 && { cachedTokens },
85
+ ...cacheCreationTokens > 0 && { cacheCreationTokens },
76
86
  costUSD: Number(r["cost_usd"]),
77
87
  ...r["session_id"] != null && { sessionId: r["session_id"] },
78
88
  ...r["user_id"] != null && { userId: r["user_id"] },
@@ -88,39 +98,46 @@ var MySQLStorage = class {
88
98
  }
89
99
  client;
90
100
  /** Creates the `tokenwatch_usage` table if it does not already exist.
91
- * Also adds new columns for databases created before v0.2.0. */
101
+ * Also adds new columns for databases created before v0.2.0 / v0.3.0. */
92
102
  async migrate() {
93
103
  await this.client.execute(`
94
104
  CREATE TABLE IF NOT EXISTS tokenwatch_usage (
95
- id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
96
- model VARCHAR(255) NOT NULL,
97
- input_tokens INT NOT NULL,
98
- output_tokens INT NOT NULL,
99
- reasoning_tokens INT NOT NULL DEFAULT 0,
100
- cost_usd DECIMAL(18,8) NOT NULL,
101
- session_id VARCHAR(255),
102
- user_id VARCHAR(255),
103
- feature VARCHAR(255),
104
- timestamp DATETIME(3) NOT NULL
105
+ id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
106
+ model VARCHAR(255) NOT NULL,
107
+ input_tokens INT NOT NULL,
108
+ output_tokens INT NOT NULL,
109
+ reasoning_tokens INT NOT NULL DEFAULT 0,
110
+ cached_tokens INT NOT NULL DEFAULT 0,
111
+ cache_creation_tokens INT NOT NULL DEFAULT 0,
112
+ cost_usd DECIMAL(18,8) NOT NULL,
113
+ session_id VARCHAR(255),
114
+ user_id VARCHAR(255),
115
+ feature VARCHAR(255),
116
+ timestamp DATETIME(3) NOT NULL
105
117
  )
106
118
  `);
107
119
  await this.client.execute(`
108
120
  ALTER TABLE tokenwatch_usage
109
- ADD COLUMN IF NOT EXISTS reasoning_tokens INT NOT NULL DEFAULT 0,
110
- ADD COLUMN IF NOT EXISTS feature VARCHAR(255)
121
+ ADD COLUMN IF NOT EXISTS reasoning_tokens INT NOT NULL DEFAULT 0,
122
+ ADD COLUMN IF NOT EXISTS feature VARCHAR(255),
123
+ ADD COLUMN IF NOT EXISTS cached_tokens INT NOT NULL DEFAULT 0,
124
+ ADD COLUMN IF NOT EXISTS cache_creation_tokens INT NOT NULL DEFAULT 0
111
125
  `).catch(() => {
112
126
  });
113
127
  }
114
128
  record(entry) {
115
129
  this.client.execute(
116
130
  `INSERT INTO tokenwatch_usage
117
- (model, input_tokens, output_tokens, reasoning_tokens, cost_usd, session_id, user_id, feature, timestamp)
118
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
131
+ (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,
132
+ cost_usd, session_id, user_id, feature, timestamp)
133
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
119
134
  [
120
135
  entry.model,
121
136
  entry.inputTokens,
122
137
  entry.outputTokens,
123
138
  entry.reasoningTokens ?? 0,
139
+ entry.cachedTokens ?? 0,
140
+ entry.cacheCreationTokens ?? 0,
124
141
  entry.costUSD,
125
142
  entry.sessionId ?? null,
126
143
  entry.userId ?? null,
@@ -149,11 +166,15 @@ var MySQLStorage = class {
149
166
  };
150
167
  function rowToEntry2(r) {
151
168
  const reasoningTokens = r["reasoning_tokens"] ?? 0;
169
+ const cachedTokens = r["cached_tokens"] ?? 0;
170
+ const cacheCreationTokens = r["cache_creation_tokens"] ?? 0;
152
171
  return {
153
172
  model: r["model"],
154
173
  inputTokens: r["input_tokens"],
155
174
  outputTokens: r["output_tokens"],
156
175
  ...reasoningTokens > 0 && { reasoningTokens },
176
+ ...cachedTokens > 0 && { cachedTokens },
177
+ ...cacheCreationTokens > 0 && { cacheCreationTokens },
157
178
  costUSD: Number(r["cost_usd"]),
158
179
  ...r["session_id"] != null && { sessionId: r["session_id"] },
159
180
  ...r["user_id"] != null && { userId: r["user_id"] },
@@ -182,6 +203,8 @@ var MongoStorage = class {
182
203
  inputTokens: entry.inputTokens,
183
204
  outputTokens: entry.outputTokens,
184
205
  ...entry.reasoningTokens !== void 0 && { reasoningTokens: entry.reasoningTokens },
206
+ ...entry.cachedTokens !== void 0 && { cachedTokens: entry.cachedTokens },
207
+ ...entry.cacheCreationTokens !== void 0 && { cacheCreationTokens: entry.cacheCreationTokens },
185
208
  costUSD: entry.costUSD,
186
209
  sessionId: entry.sessionId ?? null,
187
210
  userId: entry.userId ?? null,
@@ -208,6 +231,8 @@ function docToEntry(doc) {
208
231
  inputTokens: doc.inputTokens,
209
232
  outputTokens: doc.outputTokens,
210
233
  ...doc.reasoningTokens != null && doc.reasoningTokens > 0 && { reasoningTokens: doc.reasoningTokens },
234
+ ...doc.cachedTokens != null && doc.cachedTokens > 0 && { cachedTokens: doc.cachedTokens },
235
+ ...doc.cacheCreationTokens != null && doc.cacheCreationTokens > 0 && { cacheCreationTokens: doc.cacheCreationTokens },
211
236
  costUSD: doc.costUSD,
212
237
  ...doc.sessionId != null && { sessionId: doc.sessionId },
213
238
  ...doc.userId != null && { userId: doc.userId },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters/postgres.ts","../src/adapters/mysql.ts","../src/adapters/mongodb.ts"],"sourcesContent":["import type { IStorage, UsageEntry } from '../types/index.js'\n\n/**\n * IStorage adapter for PostgreSQL using the `pg` driver.\n *\n * Install peer dep: npm install pg\n * Types (optional): npm install -D @types/pg\n *\n * @example\n * ```ts\n * import { Pool } from 'pg'\n * import { createTracker } from '@diogonzafe/tokenwatch'\n * import { PostgresStorage } from '@diogonzafe/tokenwatch/adapters'\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL })\n * const storage = new PostgresStorage(pool)\n * await storage.migrate() // create table if it doesn't exist\n *\n * const tracker = createTracker({ storage })\n * ```\n */\n\n// Minimal structural types so the adapter compiles without `pg` installed\ninterface QueryClient {\n query(sql: string, values?: unknown[]): Promise<{ rows: unknown[] }>\n}\n\nexport class PostgresStorage implements IStorage {\n constructor(private readonly client: QueryClient) {}\n\n /** Creates the `tokenwatch_usage` table if it does not already exist.\n * Also adds new columns for databases created before v0.2.0. */\n async migrate(): Promise<void> {\n await this.client.query(`\n CREATE TABLE IF NOT EXISTS tokenwatch_usage (\n id BIGSERIAL PRIMARY KEY,\n model TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n cost_usd NUMERIC NOT NULL,\n session_id TEXT,\n user_id TEXT,\n feature TEXT,\n timestamp TIMESTAMPTZ NOT NULL\n )\n `)\n // Incremental migrations for databases created before v0.2.0\n await this.client.query(`\n ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS reasoning_tokens INTEGER NOT NULL DEFAULT 0\n `).catch(() => { /* column already exists in older Postgres versions that don't support IF NOT EXISTS */ })\n await this.client.query(`\n ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS feature TEXT\n `).catch(() => { /* same */ })\n }\n\n record(entry: UsageEntry): void {\n this.client\n .query(\n `INSERT INTO tokenwatch_usage\n (model, input_tokens, output_tokens, reasoning_tokens, cost_usd, session_id, user_id, feature, timestamp)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,\n [\n entry.model,\n entry.inputTokens,\n entry.outputTokens,\n entry.reasoningTokens ?? 0,\n entry.costUSD,\n entry.sessionId ?? null,\n entry.userId ?? null,\n entry.feature ?? null,\n entry.timestamp,\n ],\n )\n .catch((err: unknown) => {\n console.warn('[tokenwatch] PostgresStorage.record failed:', err)\n })\n }\n\n async getAll(): Promise<UsageEntry[]> {\n const result = await this.client.query(\n 'SELECT * FROM tokenwatch_usage ORDER BY timestamp ASC',\n )\n return (result.rows as Array<Record<string, unknown>>).map(rowToEntry)\n }\n\n async clearAll(): Promise<void> {\n await this.client.query('DELETE FROM tokenwatch_usage')\n }\n\n async clearSession(sessionId: string): Promise<void> {\n await this.client.query(\n 'DELETE FROM tokenwatch_usage WHERE session_id = $1',\n [sessionId],\n )\n }\n}\n\nfunction rowToEntry(r: Record<string, unknown>): UsageEntry {\n const reasoningTokens = (r['reasoning_tokens'] as number | null) ?? 0\n return {\n model: r['model'] as string,\n inputTokens: r['input_tokens'] as number,\n outputTokens: r['output_tokens'] as number,\n ...(reasoningTokens > 0 && { reasoningTokens }),\n costUSD: Number(r['cost_usd']),\n ...(r['session_id'] != null && { sessionId: r['session_id'] as string }),\n ...(r['user_id'] != null && { userId: r['user_id'] as string }),\n ...(r['feature'] != null && { feature: r['feature'] as string }),\n timestamp:\n r['timestamp'] instanceof Date\n ? (r['timestamp'] as Date).toISOString()\n : (r['timestamp'] as string),\n }\n}\n","import type { IStorage, UsageEntry } from '../types/index.js'\n\n/**\n * IStorage adapter for MySQL / MariaDB using the `mysql2` driver.\n *\n * Install peer dep: npm install mysql2\n *\n * @example\n * ```ts\n * import mysql from 'mysql2/promise'\n * import { createTracker } from '@diogonzafe/tokenwatch'\n * import { MySQLStorage } from '@diogonzafe/tokenwatch/adapters'\n *\n * const pool = mysql.createPool({ uri: process.env.MYSQL_URL })\n * const storage = new MySQLStorage(pool)\n * await storage.migrate() // create table if it doesn't exist\n *\n * const tracker = createTracker({ storage })\n * ```\n */\n\n// Minimal structural type so the adapter compiles without `mysql2` installed\ninterface QueryClient {\n execute(sql: string, values?: unknown[]): Promise<[unknown]>\n}\n\nexport class MySQLStorage implements IStorage {\n constructor(private readonly client: QueryClient) {}\n\n /** Creates the `tokenwatch_usage` table if it does not already exist.\n * Also adds new columns for databases created before v0.2.0. */\n async migrate(): Promise<void> {\n await this.client.execute(`\n CREATE TABLE IF NOT EXISTS tokenwatch_usage (\n id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n model VARCHAR(255) NOT NULL,\n input_tokens INT NOT NULL,\n output_tokens INT NOT NULL,\n reasoning_tokens INT NOT NULL DEFAULT 0,\n cost_usd DECIMAL(18,8) NOT NULL,\n session_id VARCHAR(255),\n user_id VARCHAR(255),\n feature VARCHAR(255),\n timestamp DATETIME(3) NOT NULL\n )\n `)\n // Incremental migrations for databases created before v0.2.0\n await this.client.execute(`\n ALTER TABLE tokenwatch_usage\n ADD COLUMN IF NOT EXISTS reasoning_tokens INT NOT NULL DEFAULT 0,\n ADD COLUMN IF NOT EXISTS feature VARCHAR(255)\n `).catch(() => { /* MySQL < 8.0 may not support IF NOT EXISTS — ignore if columns already exist */ })\n }\n\n record(entry: UsageEntry): void {\n this.client\n .execute(\n `INSERT INTO tokenwatch_usage\n (model, input_tokens, output_tokens, reasoning_tokens, cost_usd, session_id, user_id, feature, timestamp)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n entry.model,\n entry.inputTokens,\n entry.outputTokens,\n entry.reasoningTokens ?? 0,\n entry.costUSD,\n entry.sessionId ?? null,\n entry.userId ?? null,\n entry.feature ?? null,\n entry.timestamp,\n ],\n )\n .catch((err: unknown) => {\n console.warn('[tokenwatch] MySQLStorage.record failed:', err)\n })\n }\n\n async getAll(): Promise<UsageEntry[]> {\n const [rows] = await this.client.execute(\n 'SELECT * FROM tokenwatch_usage ORDER BY timestamp ASC',\n )\n return (rows as Array<Record<string, unknown>>).map(rowToEntry)\n }\n\n async clearAll(): Promise<void> {\n await this.client.execute('DELETE FROM tokenwatch_usage')\n }\n\n async clearSession(sessionId: string): Promise<void> {\n await this.client.execute(\n 'DELETE FROM tokenwatch_usage WHERE session_id = ?',\n [sessionId],\n )\n }\n}\n\nfunction rowToEntry(r: Record<string, unknown>): UsageEntry {\n const reasoningTokens = (r['reasoning_tokens'] as number | null) ?? 0\n return {\n model: r['model'] as string,\n inputTokens: r['input_tokens'] as number,\n outputTokens: r['output_tokens'] as number,\n ...(reasoningTokens > 0 && { reasoningTokens }),\n costUSD: Number(r['cost_usd']),\n ...(r['session_id'] != null && { sessionId: r['session_id'] as string }),\n ...(r['user_id'] != null && { userId: r['user_id'] as string }),\n ...(r['feature'] != null && { feature: r['feature'] as string }),\n timestamp:\n r['timestamp'] instanceof Date\n ? (r['timestamp'] as Date).toISOString()\n : (r['timestamp'] as string),\n }\n}\n","import type { IStorage, UsageEntry } from '../types/index.js'\n\n/**\n * IStorage adapter for MongoDB using the official `mongodb` driver.\n *\n * Install peer dep: npm install mongodb\n *\n * @example\n * ```ts\n * import { MongoClient } from 'mongodb'\n * import { createTracker } from '@diogonzafe/tokenwatch'\n * import { MongoStorage } from '@diogonzafe/tokenwatch/adapters'\n *\n * const client = new MongoClient(process.env.MONGO_URL!)\n * await client.connect()\n *\n * const storage = new MongoStorage(client.db('myapp'))\n * const tracker = createTracker({ storage })\n * ```\n *\n * Recommended index (run once at startup):\n * ```ts\n * await storage.createIndexes()\n * ```\n */\n\n// Minimal structural types so the adapter compiles without `mongodb` installed\ninterface MongoDocument {\n _id?: unknown\n model: string\n inputTokens: number\n outputTokens: number\n reasoningTokens?: number\n costUSD: number\n sessionId?: string | null\n userId?: string | null\n feature?: string | null\n timestamp: string\n}\n\ninterface MongoCursor {\n sort(sort: Record<string, unknown>): MongoCursor\n toArray(): Promise<MongoDocument[]>\n}\n\ninterface Collection {\n insertOne(doc: MongoDocument): Promise<unknown>\n find(filter: Record<string, unknown>): MongoCursor\n deleteMany(filter: Record<string, unknown>): Promise<unknown>\n createIndex(index: Record<string, unknown>): Promise<unknown>\n}\n\ninterface Database {\n collection(name: string): Collection\n}\n\nconst COLLECTION = 'tokenwatch_usage'\n\nexport class MongoStorage implements IStorage {\n private readonly col: Collection\n\n constructor(db: Database) {\n this.col = db.collection(COLLECTION)\n }\n\n /** Creates recommended indexes for query performance. Call once at startup. */\n async createIndexes(): Promise<void> {\n await this.col.createIndex({ timestamp: 1 })\n await this.col.createIndex({ sessionId: 1 })\n await this.col.createIndex({ userId: 1 })\n await this.col.createIndex({ model: 1 })\n }\n\n record(entry: UsageEntry): void {\n this.col\n .insertOne({\n model: entry.model,\n inputTokens: entry.inputTokens,\n outputTokens: entry.outputTokens,\n ...(entry.reasoningTokens !== undefined && { reasoningTokens: entry.reasoningTokens }),\n costUSD: entry.costUSD,\n sessionId: entry.sessionId ?? null,\n userId: entry.userId ?? null,\n ...(entry.feature !== undefined && { feature: entry.feature }),\n timestamp: entry.timestamp,\n })\n .catch((err: unknown) => {\n console.warn('[tokenwatch] MongoStorage.record failed:', err)\n })\n }\n\n async getAll(): Promise<UsageEntry[]> {\n const docs = await this.col.find({}).sort({ timestamp: 1 }).toArray()\n return docs.map(docToEntry)\n }\n\n async clearAll(): Promise<void> {\n await this.col.deleteMany({})\n }\n\n async clearSession(sessionId: string): Promise<void> {\n await this.col.deleteMany({ sessionId })\n }\n}\n\nfunction docToEntry(doc: MongoDocument): UsageEntry {\n return {\n model: doc.model,\n inputTokens: doc.inputTokens,\n outputTokens: doc.outputTokens,\n ...(doc.reasoningTokens != null && doc.reasoningTokens > 0 && { reasoningTokens: doc.reasoningTokens }),\n costUSD: doc.costUSD,\n ...(doc.sessionId != null && { sessionId: doc.sessionId }),\n ...(doc.userId != null && { userId: doc.userId }),\n ...(doc.feature != null && { feature: doc.feature }),\n timestamp: doc.timestamp,\n }\n}\n"],"mappings":"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","names":["rowToEntry"]}
1
+ {"version":3,"sources":["../src/adapters/postgres.ts","../src/adapters/mysql.ts","../src/adapters/mongodb.ts"],"sourcesContent":["import type { IStorage, UsageEntry } from '../types/index.js'\n\n/**\n * IStorage adapter for PostgreSQL using the `pg` driver.\n *\n * Install peer dep: npm install pg\n * Types (optional): npm install -D @types/pg\n *\n * @example\n * ```ts\n * import { Pool } from 'pg'\n * import { createTracker } from '@diogonzafe/tokenwatch'\n * import { PostgresStorage } from '@diogonzafe/tokenwatch/adapters'\n *\n * const pool = new Pool({ connectionString: process.env.DATABASE_URL })\n * const storage = new PostgresStorage(pool)\n * await storage.migrate() // create table if it doesn't exist\n *\n * const tracker = createTracker({ storage })\n * ```\n */\n\n// Minimal structural types so the adapter compiles without `pg` installed\ninterface QueryClient {\n query(sql: string, values?: unknown[]): Promise<{ rows: unknown[] }>\n}\n\nexport class PostgresStorage implements IStorage {\n constructor(private readonly client: QueryClient) {}\n\n /** Creates the `tokenwatch_usage` table if it does not already exist.\n * Also adds new columns for databases created before v0.2.0 / v0.3.0. */\n async migrate(): Promise<void> {\n await this.client.query(`\n CREATE TABLE IF NOT EXISTS tokenwatch_usage (\n id BIGSERIAL PRIMARY KEY,\n model TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n cached_tokens INTEGER NOT NULL DEFAULT 0,\n cache_creation_tokens INTEGER NOT NULL DEFAULT 0,\n cost_usd NUMERIC NOT NULL,\n session_id TEXT,\n user_id TEXT,\n feature TEXT,\n timestamp TIMESTAMPTZ NOT NULL\n )\n `)\n // Incremental migrations for databases created before v0.2.0 / v0.3.0\n for (const col of [\n 'ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS reasoning_tokens INTEGER NOT NULL DEFAULT 0',\n 'ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS feature TEXT',\n 'ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS cached_tokens INTEGER NOT NULL DEFAULT 0',\n 'ALTER TABLE tokenwatch_usage ADD COLUMN IF NOT EXISTS cache_creation_tokens INTEGER NOT NULL DEFAULT 0',\n ]) {\n await this.client.query(col).catch(() => { /* column already exists */ })\n }\n }\n\n record(entry: UsageEntry): void {\n this.client\n .query(\n `INSERT INTO tokenwatch_usage\n (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,\n cost_usd, session_id, user_id, feature, timestamp)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,\n [\n entry.model,\n entry.inputTokens,\n entry.outputTokens,\n entry.reasoningTokens ?? 0,\n entry.cachedTokens ?? 0,\n entry.cacheCreationTokens ?? 0,\n entry.costUSD,\n entry.sessionId ?? null,\n entry.userId ?? null,\n entry.feature ?? null,\n entry.timestamp,\n ],\n )\n .catch((err: unknown) => {\n console.warn('[tokenwatch] PostgresStorage.record failed:', err)\n })\n }\n\n async getAll(): Promise<UsageEntry[]> {\n const result = await this.client.query(\n 'SELECT * FROM tokenwatch_usage ORDER BY timestamp ASC',\n )\n return (result.rows as Array<Record<string, unknown>>).map(rowToEntry)\n }\n\n async clearAll(): Promise<void> {\n await this.client.query('DELETE FROM tokenwatch_usage')\n }\n\n async clearSession(sessionId: string): Promise<void> {\n await this.client.query(\n 'DELETE FROM tokenwatch_usage WHERE session_id = $1',\n [sessionId],\n )\n }\n}\n\nfunction rowToEntry(r: Record<string, unknown>): UsageEntry {\n const reasoningTokens = (r['reasoning_tokens'] as number | null) ?? 0\n const cachedTokens = (r['cached_tokens'] as number | null) ?? 0\n const cacheCreationTokens = (r['cache_creation_tokens'] as number | null) ?? 0\n return {\n model: r['model'] as string,\n inputTokens: r['input_tokens'] as number,\n outputTokens: r['output_tokens'] as number,\n ...(reasoningTokens > 0 && { reasoningTokens }),\n ...(cachedTokens > 0 && { cachedTokens }),\n ...(cacheCreationTokens > 0 && { cacheCreationTokens }),\n costUSD: Number(r['cost_usd']),\n ...(r['session_id'] != null && { sessionId: r['session_id'] as string }),\n ...(r['user_id'] != null && { userId: r['user_id'] as string }),\n ...(r['feature'] != null && { feature: r['feature'] as string }),\n timestamp:\n r['timestamp'] instanceof Date\n ? (r['timestamp'] as Date).toISOString()\n : (r['timestamp'] as string),\n }\n}\n","import type { IStorage, UsageEntry } from '../types/index.js'\n\n/**\n * IStorage adapter for MySQL / MariaDB using the `mysql2` driver.\n *\n * Install peer dep: npm install mysql2\n *\n * @example\n * ```ts\n * import mysql from 'mysql2/promise'\n * import { createTracker } from '@diogonzafe/tokenwatch'\n * import { MySQLStorage } from '@diogonzafe/tokenwatch/adapters'\n *\n * const pool = mysql.createPool({ uri: process.env.MYSQL_URL })\n * const storage = new MySQLStorage(pool)\n * await storage.migrate() // create table if it doesn't exist\n *\n * const tracker = createTracker({ storage })\n * ```\n */\n\n// Minimal structural type so the adapter compiles without `mysql2` installed\ninterface QueryClient {\n execute(sql: string, values?: unknown[]): Promise<[unknown]>\n}\n\nexport class MySQLStorage implements IStorage {\n constructor(private readonly client: QueryClient) {}\n\n /** Creates the `tokenwatch_usage` table if it does not already exist.\n * Also adds new columns for databases created before v0.2.0 / v0.3.0. */\n async migrate(): Promise<void> {\n await this.client.execute(`\n CREATE TABLE IF NOT EXISTS tokenwatch_usage (\n id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,\n model VARCHAR(255) NOT NULL,\n input_tokens INT NOT NULL,\n output_tokens INT NOT NULL,\n reasoning_tokens INT NOT NULL DEFAULT 0,\n cached_tokens INT NOT NULL DEFAULT 0,\n cache_creation_tokens INT NOT NULL DEFAULT 0,\n cost_usd DECIMAL(18,8) NOT NULL,\n session_id VARCHAR(255),\n user_id VARCHAR(255),\n feature VARCHAR(255),\n timestamp DATETIME(3) NOT NULL\n )\n `)\n // Incremental migrations for databases created before v0.2.0 / v0.3.0\n await this.client.execute(`\n ALTER TABLE tokenwatch_usage\n ADD COLUMN IF NOT EXISTS reasoning_tokens INT NOT NULL DEFAULT 0,\n ADD COLUMN IF NOT EXISTS feature VARCHAR(255),\n ADD COLUMN IF NOT EXISTS cached_tokens INT NOT NULL DEFAULT 0,\n ADD COLUMN IF NOT EXISTS cache_creation_tokens INT NOT NULL DEFAULT 0\n `).catch(() => { /* MySQL < 8.0 may not support IF NOT EXISTS — ignore if columns already exist */ })\n }\n\n record(entry: UsageEntry): void {\n this.client\n .execute(\n `INSERT INTO tokenwatch_usage\n (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,\n cost_usd, session_id, user_id, feature, timestamp)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n entry.model,\n entry.inputTokens,\n entry.outputTokens,\n entry.reasoningTokens ?? 0,\n entry.cachedTokens ?? 0,\n entry.cacheCreationTokens ?? 0,\n entry.costUSD,\n entry.sessionId ?? null,\n entry.userId ?? null,\n entry.feature ?? null,\n entry.timestamp,\n ],\n )\n .catch((err: unknown) => {\n console.warn('[tokenwatch] MySQLStorage.record failed:', err)\n })\n }\n\n async getAll(): Promise<UsageEntry[]> {\n const [rows] = await this.client.execute(\n 'SELECT * FROM tokenwatch_usage ORDER BY timestamp ASC',\n )\n return (rows as Array<Record<string, unknown>>).map(rowToEntry)\n }\n\n async clearAll(): Promise<void> {\n await this.client.execute('DELETE FROM tokenwatch_usage')\n }\n\n async clearSession(sessionId: string): Promise<void> {\n await this.client.execute(\n 'DELETE FROM tokenwatch_usage WHERE session_id = ?',\n [sessionId],\n )\n }\n}\n\nfunction rowToEntry(r: Record<string, unknown>): UsageEntry {\n const reasoningTokens = (r['reasoning_tokens'] as number | null) ?? 0\n const cachedTokens = (r['cached_tokens'] as number | null) ?? 0\n const cacheCreationTokens = (r['cache_creation_tokens'] as number | null) ?? 0\n return {\n model: r['model'] as string,\n inputTokens: r['input_tokens'] as number,\n outputTokens: r['output_tokens'] as number,\n ...(reasoningTokens > 0 && { reasoningTokens }),\n ...(cachedTokens > 0 && { cachedTokens }),\n ...(cacheCreationTokens > 0 && { cacheCreationTokens }),\n costUSD: Number(r['cost_usd']),\n ...(r['session_id'] != null && { sessionId: r['session_id'] as string }),\n ...(r['user_id'] != null && { userId: r['user_id'] as string }),\n ...(r['feature'] != null && { feature: r['feature'] as string }),\n timestamp:\n r['timestamp'] instanceof Date\n ? (r['timestamp'] as Date).toISOString()\n : (r['timestamp'] as string),\n }\n}\n","import type { IStorage, UsageEntry } from '../types/index.js'\n\n/**\n * IStorage adapter for MongoDB using the official `mongodb` driver.\n *\n * Install peer dep: npm install mongodb\n *\n * @example\n * ```ts\n * import { MongoClient } from 'mongodb'\n * import { createTracker } from '@diogonzafe/tokenwatch'\n * import { MongoStorage } from '@diogonzafe/tokenwatch/adapters'\n *\n * const client = new MongoClient(process.env.MONGO_URL!)\n * await client.connect()\n *\n * const storage = new MongoStorage(client.db('myapp'))\n * const tracker = createTracker({ storage })\n * ```\n *\n * Recommended index (run once at startup):\n * ```ts\n * await storage.createIndexes()\n * ```\n */\n\n// Minimal structural types so the adapter compiles without `mongodb` installed\ninterface MongoDocument {\n _id?: unknown\n model: string\n inputTokens: number\n outputTokens: number\n reasoningTokens?: number\n cachedTokens?: number\n cacheCreationTokens?: number\n costUSD: number\n sessionId?: string | null\n userId?: string | null\n feature?: string | null\n timestamp: string\n}\n\ninterface MongoCursor {\n sort(sort: Record<string, unknown>): MongoCursor\n toArray(): Promise<MongoDocument[]>\n}\n\ninterface Collection {\n insertOne(doc: MongoDocument): Promise<unknown>\n find(filter: Record<string, unknown>): MongoCursor\n deleteMany(filter: Record<string, unknown>): Promise<unknown>\n createIndex(index: Record<string, unknown>): Promise<unknown>\n}\n\ninterface Database {\n collection(name: string): Collection\n}\n\nconst COLLECTION = 'tokenwatch_usage'\n\nexport class MongoStorage implements IStorage {\n private readonly col: Collection\n\n constructor(db: Database) {\n this.col = db.collection(COLLECTION)\n }\n\n /** Creates recommended indexes for query performance. Call once at startup. */\n async createIndexes(): Promise<void> {\n await this.col.createIndex({ timestamp: 1 })\n await this.col.createIndex({ sessionId: 1 })\n await this.col.createIndex({ userId: 1 })\n await this.col.createIndex({ model: 1 })\n }\n\n record(entry: UsageEntry): void {\n this.col\n .insertOne({\n model: entry.model,\n inputTokens: entry.inputTokens,\n outputTokens: entry.outputTokens,\n ...(entry.reasoningTokens !== undefined && { reasoningTokens: entry.reasoningTokens }),\n ...(entry.cachedTokens !== undefined && { cachedTokens: entry.cachedTokens }),\n ...(entry.cacheCreationTokens !== undefined && { cacheCreationTokens: entry.cacheCreationTokens }),\n costUSD: entry.costUSD,\n sessionId: entry.sessionId ?? null,\n userId: entry.userId ?? null,\n ...(entry.feature !== undefined && { feature: entry.feature }),\n timestamp: entry.timestamp,\n })\n .catch((err: unknown) => {\n console.warn('[tokenwatch] MongoStorage.record failed:', err)\n })\n }\n\n async getAll(): Promise<UsageEntry[]> {\n const docs = await this.col.find({}).sort({ timestamp: 1 }).toArray()\n return docs.map(docToEntry)\n }\n\n async clearAll(): Promise<void> {\n await this.col.deleteMany({})\n }\n\n async clearSession(sessionId: string): Promise<void> {\n await this.col.deleteMany({ sessionId })\n }\n}\n\nfunction docToEntry(doc: MongoDocument): UsageEntry {\n return {\n model: doc.model,\n inputTokens: doc.inputTokens,\n outputTokens: doc.outputTokens,\n ...(doc.reasoningTokens != null && doc.reasoningTokens > 0 && { reasoningTokens: doc.reasoningTokens }),\n ...(doc.cachedTokens != null && doc.cachedTokens > 0 && { cachedTokens: doc.cachedTokens }),\n ...(doc.cacheCreationTokens != null && doc.cacheCreationTokens > 0 && { cacheCreationTokens: doc.cacheCreationTokens }),\n costUSD: doc.costUSD,\n ...(doc.sessionId != null && { sessionId: doc.sessionId }),\n ...(doc.userId != null && { userId: doc.userId }),\n ...(doc.feature != null && { feature: doc.feature }),\n timestamp: doc.timestamp,\n }\n}\n"],"mappings":"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","names":["rowToEntry"]}