tokenmeter 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/LICENSE +21 -0
- package/README.md +346 -0
- package/dist/__tests__/context.test.d.ts +2 -0
- package/dist/__tests__/context.test.d.ts.map +1 -0
- package/dist/__tests__/context.test.js +94 -0
- package/dist/__tests__/context.test.js.map +1 -0
- package/dist/__tests__/elevenlabs.test.d.ts +2 -0
- package/dist/__tests__/elevenlabs.test.d.ts.map +1 -0
- package/dist/__tests__/elevenlabs.test.js +108 -0
- package/dist/__tests__/elevenlabs.test.js.map +1 -0
- package/dist/__tests__/fal.test.d.ts +2 -0
- package/dist/__tests__/fal.test.d.ts.map +1 -0
- package/dist/__tests__/fal.test.js +153 -0
- package/dist/__tests__/fal.test.js.map +1 -0
- package/dist/__tests__/pricing.test.d.ts +2 -0
- package/dist/__tests__/pricing.test.d.ts.map +1 -0
- package/dist/__tests__/pricing.test.js +76 -0
- package/dist/__tests__/pricing.test.js.map +1 -0
- package/dist/__tests__/recorder.test.d.ts +2 -0
- package/dist/__tests__/recorder.test.d.ts.map +1 -0
- package/dist/__tests__/recorder.test.js +133 -0
- package/dist/__tests__/recorder.test.js.map +1 -0
- package/dist/__tests__/storage.test.d.ts +2 -0
- package/dist/__tests__/storage.test.d.ts.map +1 -0
- package/dist/__tests__/storage.test.js +106 -0
- package/dist/__tests__/storage.test.js.map +1 -0
- package/dist/client/index.d.ts +8 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +7 -0
- package/dist/client/index.js.map +1 -0
- package/dist/config.d.ts +92 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +166 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +80 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +131 -0
- package/dist/context.js.map +1 -0
- package/dist/exporter/PostgresExporter.d.ts +82 -0
- package/dist/exporter/PostgresExporter.d.ts.map +1 -0
- package/dist/exporter/PostgresExporter.js +237 -0
- package/dist/exporter/PostgresExporter.js.map +1 -0
- package/dist/exporter/index.d.ts +8 -0
- package/dist/exporter/index.d.ts.map +1 -0
- package/dist/exporter/index.js +7 -0
- package/dist/exporter/index.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation/proxy.d.ts +26 -0
- package/dist/instrumentation/proxy.d.ts.map +1 -0
- package/dist/instrumentation/proxy.js +337 -0
- package/dist/instrumentation/proxy.js.map +1 -0
- package/dist/instrumentation/strategies/index.d.ts +55 -0
- package/dist/instrumentation/strategies/index.d.ts.map +1 -0
- package/dist/instrumentation/strategies/index.js +429 -0
- package/dist/instrumentation/strategies/index.js.map +1 -0
- package/dist/integrations/express/index.d.ts +137 -0
- package/dist/integrations/express/index.d.ts.map +1 -0
- package/dist/integrations/express/index.js +186 -0
- package/dist/integrations/express/index.js.map +1 -0
- package/dist/integrations/inngest/index.d.ts +222 -0
- package/dist/integrations/inngest/index.d.ts.map +1 -0
- package/dist/integrations/inngest/index.js +223 -0
- package/dist/integrations/inngest/index.js.map +1 -0
- package/dist/integrations/langfuse/index.d.ts +170 -0
- package/dist/integrations/langfuse/index.d.ts.map +1 -0
- package/dist/integrations/langfuse/index.js +225 -0
- package/dist/integrations/langfuse/index.js.map +1 -0
- package/dist/integrations/next/index.d.ts +138 -0
- package/dist/integrations/next/index.d.ts.map +1 -0
- package/dist/integrations/next/index.js +170 -0
- package/dist/integrations/next/index.js.map +1 -0
- package/dist/integrations/nextjs/index.d.ts +198 -0
- package/dist/integrations/nextjs/index.d.ts.map +1 -0
- package/dist/integrations/nextjs/index.js +181 -0
- package/dist/integrations/nextjs/index.js.map +1 -0
- package/dist/integrations/vercel-ai/index.d.ts +288 -0
- package/dist/integrations/vercel-ai/index.d.ts.map +1 -0
- package/dist/integrations/vercel-ai/index.js +260 -0
- package/dist/integrations/vercel-ai/index.js.map +1 -0
- package/dist/logger.d.ts +58 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +89 -0
- package/dist/logger.js.map +1 -0
- package/dist/pricing/catalog.d.ts +10 -0
- package/dist/pricing/catalog.d.ts.map +1 -0
- package/dist/pricing/catalog.js +297 -0
- package/dist/pricing/catalog.js.map +1 -0
- package/dist/pricing/index.d.ts +77 -0
- package/dist/pricing/index.d.ts.map +1 -0
- package/dist/pricing/index.js +251 -0
- package/dist/pricing/index.js.map +1 -0
- package/dist/pricing/manifest.d.ts +156 -0
- package/dist/pricing/manifest.d.ts.map +1 -0
- package/dist/pricing/manifest.js +381 -0
- package/dist/pricing/manifest.js.map +1 -0
- package/dist/pricing/manifest.json +12786 -0
- package/dist/pricing/providers/anthropic.json +253 -0
- package/dist/pricing/providers/bedrock.json +341 -0
- package/dist/pricing/providers/bfl.json +220 -0
- package/dist/pricing/providers/elevenlabs.json +142 -0
- package/dist/pricing/providers/fal.json +15866 -0
- package/dist/pricing/providers/google.json +346 -0
- package/dist/pricing/providers/openai.json +1035 -0
- package/dist/pricing/schema.d.ts +102 -0
- package/dist/pricing/schema.d.ts.map +1 -0
- package/dist/pricing/schema.js +56 -0
- package/dist/pricing/schema.js.map +1 -0
- package/dist/processor/TokenMeterProcessor.d.ts +55 -0
- package/dist/processor/TokenMeterProcessor.d.ts.map +1 -0
- package/dist/processor/TokenMeterProcessor.js +132 -0
- package/dist/processor/TokenMeterProcessor.js.map +1 -0
- package/dist/query/client.d.ts +61 -0
- package/dist/query/client.d.ts.map +1 -0
- package/dist/query/client.js +206 -0
- package/dist/query/client.js.map +1 -0
- package/dist/query/index.d.ts +8 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +7 -0
- package/dist/query/index.js.map +1 -0
- package/dist/recorder.d.ts +74 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +227 -0
- package/dist/recorder.js.map +1 -0
- package/dist/sdks/anthropic.d.ts +21 -0
- package/dist/sdks/anthropic.d.ts.map +1 -0
- package/dist/sdks/anthropic.js +258 -0
- package/dist/sdks/anthropic.js.map +1 -0
- package/dist/sdks/elevenlabs.d.ts +59 -0
- package/dist/sdks/elevenlabs.d.ts.map +1 -0
- package/dist/sdks/elevenlabs.js +192 -0
- package/dist/sdks/elevenlabs.js.map +1 -0
- package/dist/sdks/fal.d.ts +102 -0
- package/dist/sdks/fal.d.ts.map +1 -0
- package/dist/sdks/fal.js +306 -0
- package/dist/sdks/fal.js.map +1 -0
- package/dist/sdks/openai.d.ts +17 -0
- package/dist/sdks/openai.d.ts.map +1 -0
- package/dist/sdks/openai.js +191 -0
- package/dist/sdks/openai.js.map +1 -0
- package/dist/storage/interface.d.ts +15 -0
- package/dist/storage/interface.d.ts.map +1 -0
- package/dist/storage/interface.js +53 -0
- package/dist/storage/interface.js.map +1 -0
- package/dist/storage/prisma.d.ts +15 -0
- package/dist/storage/prisma.d.ts.map +1 -0
- package/dist/storage/prisma.js +135 -0
- package/dist/storage/prisma.js.map +1 -0
- package/dist/types.d.ts +206 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +45 -0
- package/dist/types.js.map +1 -0
- package/dist/vercel-ai/index.d.ts +89 -0
- package/dist/vercel-ai/index.d.ts.map +1 -0
- package/dist/vercel-ai/index.js +298 -0
- package/dist/vercel-ai/index.js.map +1 -0
- package/package.json +119 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extraction Strategies
|
|
3
|
+
*
|
|
4
|
+
* Each strategy knows how to extract usage data from a specific provider's API responses.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* OpenAI extraction strategy
|
|
8
|
+
*/
|
|
9
|
+
export const openaiStrategy = {
|
|
10
|
+
provider: "openai",
|
|
11
|
+
canHandle(methodPath, result) {
|
|
12
|
+
// Handle chat.completions.create, completions.create, embeddings.create, etc.
|
|
13
|
+
if (!result || typeof result !== "object")
|
|
14
|
+
return false;
|
|
15
|
+
const r = result;
|
|
16
|
+
// Check for OpenAI response structure
|
|
17
|
+
return ("usage" in r &&
|
|
18
|
+
typeof r.usage === "object" &&
|
|
19
|
+
r.usage !== null &&
|
|
20
|
+
("prompt_tokens" in r.usage ||
|
|
21
|
+
"total_tokens" in r.usage));
|
|
22
|
+
},
|
|
23
|
+
extract(methodPath, result, args) {
|
|
24
|
+
const r = result;
|
|
25
|
+
if (!r.usage)
|
|
26
|
+
return null;
|
|
27
|
+
// Extract model from result or from request args
|
|
28
|
+
let model = r.model || "unknown";
|
|
29
|
+
if (!r.model && args.length > 0) {
|
|
30
|
+
const params = args[0];
|
|
31
|
+
if (params?.model) {
|
|
32
|
+
model = params.model;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
provider: "openai",
|
|
37
|
+
model,
|
|
38
|
+
inputUnits: r.usage.prompt_tokens,
|
|
39
|
+
outputUnits: r.usage.completion_tokens,
|
|
40
|
+
cachedInputUnits: r.usage.cached_tokens,
|
|
41
|
+
metadata: {
|
|
42
|
+
totalTokens: r.usage.total_tokens,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Anthropic extraction strategy
|
|
49
|
+
*/
|
|
50
|
+
export const anthropicStrategy = {
|
|
51
|
+
provider: "anthropic",
|
|
52
|
+
canHandle(methodPath, result) {
|
|
53
|
+
if (!result || typeof result !== "object")
|
|
54
|
+
return false;
|
|
55
|
+
const r = result;
|
|
56
|
+
// Anthropic responses have usage with input_tokens/output_tokens
|
|
57
|
+
return ("usage" in r &&
|
|
58
|
+
typeof r.usage === "object" &&
|
|
59
|
+
r.usage !== null &&
|
|
60
|
+
"input_tokens" in r.usage);
|
|
61
|
+
},
|
|
62
|
+
extract(methodPath, result, args) {
|
|
63
|
+
const r = result;
|
|
64
|
+
if (!r.usage)
|
|
65
|
+
return null;
|
|
66
|
+
let model = r.model || "unknown";
|
|
67
|
+
if (!r.model && args.length > 0) {
|
|
68
|
+
const params = args[0];
|
|
69
|
+
if (params?.model) {
|
|
70
|
+
model = params.model;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
provider: "anthropic",
|
|
75
|
+
model,
|
|
76
|
+
inputUnits: r.usage.input_tokens,
|
|
77
|
+
outputUnits: r.usage.output_tokens,
|
|
78
|
+
cachedInputUnits: r.usage.cache_read_input_tokens,
|
|
79
|
+
metadata: {
|
|
80
|
+
cacheCreationTokens: r.usage.cache_creation_input_tokens,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* fal.ai extraction strategy
|
|
87
|
+
*/
|
|
88
|
+
export const falStrategy = {
|
|
89
|
+
provider: "fal",
|
|
90
|
+
canHandle(methodPath, result) {
|
|
91
|
+
if (!result || typeof result !== "object")
|
|
92
|
+
return false;
|
|
93
|
+
const r = result;
|
|
94
|
+
// fal.ai responses typically have requestId and data
|
|
95
|
+
return "requestId" in r || "request_id" in r;
|
|
96
|
+
},
|
|
97
|
+
extract(methodPath, result, args) {
|
|
98
|
+
const r = result;
|
|
99
|
+
// Extract endpoint ID from args
|
|
100
|
+
let model = "unknown";
|
|
101
|
+
if (args.length > 0 && typeof args[0] === "string") {
|
|
102
|
+
// fal.subscribe("fal-ai/flux-pro", {...})
|
|
103
|
+
model = args[0].replace("fal-ai/", "");
|
|
104
|
+
}
|
|
105
|
+
const data = r.data || r;
|
|
106
|
+
let outputUnits = 1; // Default to 1 for request-based pricing
|
|
107
|
+
// Image generation: count images
|
|
108
|
+
if ("images" in data && Array.isArray(data.images)) {
|
|
109
|
+
outputUnits = data.images.length;
|
|
110
|
+
}
|
|
111
|
+
else if ("image" in data && data.image) {
|
|
112
|
+
outputUnits = 1;
|
|
113
|
+
}
|
|
114
|
+
// Video generation: use duration in seconds
|
|
115
|
+
if ("video" in data && data.video && "duration" in data) {
|
|
116
|
+
outputUnits = data.duration || 1;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
provider: "fal",
|
|
120
|
+
model,
|
|
121
|
+
outputUnits,
|
|
122
|
+
metadata: {
|
|
123
|
+
requestId: r.requestId || r.request_id,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* ElevenLabs extraction strategy
|
|
130
|
+
*/
|
|
131
|
+
export const elevenlabsStrategy = {
|
|
132
|
+
provider: "elevenlabs",
|
|
133
|
+
canHandle(methodPath, result) {
|
|
134
|
+
// ElevenLabs returns audio buffers, we detect by method path
|
|
135
|
+
return (methodPath.includes("textToSpeech") ||
|
|
136
|
+
methodPath.includes("generate") ||
|
|
137
|
+
methodPath.includes("convert"));
|
|
138
|
+
},
|
|
139
|
+
extract(methodPath, result, args) {
|
|
140
|
+
// For ElevenLabs, we need to extract character count from the input
|
|
141
|
+
// The result is typically a Buffer/ArrayBuffer
|
|
142
|
+
let text = "";
|
|
143
|
+
let model = "eleven_multilingual_v2"; // Default model
|
|
144
|
+
// Extract from args based on method signature
|
|
145
|
+
if (args.length >= 2) {
|
|
146
|
+
// textToSpeech.convert(voiceId, { text, modelId })
|
|
147
|
+
const options = args[1];
|
|
148
|
+
if (options?.text) {
|
|
149
|
+
text = options.text;
|
|
150
|
+
}
|
|
151
|
+
if (options?.modelId || options?.model_id) {
|
|
152
|
+
model = options.modelId || options.model_id || model;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if (args.length === 1) {
|
|
156
|
+
// generate({ text, voice, modelId })
|
|
157
|
+
const options = args[0];
|
|
158
|
+
if (options?.text) {
|
|
159
|
+
text = options.text;
|
|
160
|
+
}
|
|
161
|
+
if (options?.modelId || options?.model_id) {
|
|
162
|
+
model = options.modelId || options.model_id || model;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
provider: "elevenlabs",
|
|
167
|
+
model,
|
|
168
|
+
inputUnits: text.length, // Character count
|
|
169
|
+
metadata: {
|
|
170
|
+
characterCount: text.length,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Parse Bedrock model ID to extract canonical model name
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* "us.anthropic.claude-sonnet-4-20250514-v1:0" -> "anthropic.claude-sonnet-4"
|
|
180
|
+
* "eu.anthropic.claude-3-5-sonnet-20241022-v2:0" -> "anthropic.claude-3-5-sonnet"
|
|
181
|
+
*/
|
|
182
|
+
function parseBedrockModelId(modelId) {
|
|
183
|
+
// Remove region prefix (us., eu., ap., etc.)
|
|
184
|
+
let parsed = modelId.replace(/^[a-z]{2}\./, "");
|
|
185
|
+
// Remove version suffix (-v1:0, -v2:0, etc.)
|
|
186
|
+
parsed = parsed.replace(/-v\d+:\d+$/, "");
|
|
187
|
+
// Remove date suffix (-20250514, -20241022, etc.)
|
|
188
|
+
parsed = parsed.replace(/-\d{8}$/, "");
|
|
189
|
+
return parsed;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* AWS Bedrock extraction strategy
|
|
193
|
+
*/
|
|
194
|
+
export const bedrockStrategy = {
|
|
195
|
+
provider: "bedrock",
|
|
196
|
+
canHandle(methodPath, result) {
|
|
197
|
+
if (!result || typeof result !== "object")
|
|
198
|
+
return false;
|
|
199
|
+
const r = result;
|
|
200
|
+
// Bedrock responses have usage with inputTokens/outputTokens
|
|
201
|
+
// and typically include $metadata or modelId
|
|
202
|
+
return ("usage" in r &&
|
|
203
|
+
typeof r.usage === "object" &&
|
|
204
|
+
r.usage !== null &&
|
|
205
|
+
"inputTokens" in r.usage &&
|
|
206
|
+
("modelId" in r || "$metadata" in r));
|
|
207
|
+
},
|
|
208
|
+
extract(methodPath, result, args) {
|
|
209
|
+
const r = result;
|
|
210
|
+
if (!r.usage)
|
|
211
|
+
return null;
|
|
212
|
+
let model = r.modelId || "unknown";
|
|
213
|
+
// Try to get model from args if not in result
|
|
214
|
+
if (!r.modelId && args.length > 0) {
|
|
215
|
+
const params = args[0];
|
|
216
|
+
if (params?.modelId) {
|
|
217
|
+
model = params.modelId;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Parse the Bedrock model ID to canonical form
|
|
221
|
+
const canonicalModel = parseBedrockModelId(model);
|
|
222
|
+
return {
|
|
223
|
+
provider: "bedrock",
|
|
224
|
+
model: canonicalModel,
|
|
225
|
+
inputUnits: r.usage.inputTokens,
|
|
226
|
+
outputUnits: r.usage.outputTokens,
|
|
227
|
+
metadata: {
|
|
228
|
+
originalModelId: model,
|
|
229
|
+
requestId: r.$metadata?.requestId,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Google Vertex AI / Gemini extraction strategy
|
|
236
|
+
*/
|
|
237
|
+
export const vertexAIStrategy = {
|
|
238
|
+
provider: "google",
|
|
239
|
+
canHandle(methodPath, result) {
|
|
240
|
+
if (!result || typeof result !== "object")
|
|
241
|
+
return false;
|
|
242
|
+
const r = result;
|
|
243
|
+
// Vertex AI / Gemini responses have usageMetadata with promptTokenCount/candidatesTokenCount
|
|
244
|
+
return ("usageMetadata" in r &&
|
|
245
|
+
typeof r.usageMetadata === "object" &&
|
|
246
|
+
r.usageMetadata !== null &&
|
|
247
|
+
"promptTokenCount" in r.usageMetadata);
|
|
248
|
+
},
|
|
249
|
+
extract(methodPath, result, args) {
|
|
250
|
+
const r = result;
|
|
251
|
+
if (!r.usageMetadata)
|
|
252
|
+
return null;
|
|
253
|
+
// Try to extract model from result or args
|
|
254
|
+
let model = "unknown";
|
|
255
|
+
if (r.modelVersion) {
|
|
256
|
+
model = r.modelVersion;
|
|
257
|
+
}
|
|
258
|
+
else if (args.length > 0) {
|
|
259
|
+
const params = args[0];
|
|
260
|
+
if (params?.model) {
|
|
261
|
+
model = params.model;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
provider: "google",
|
|
266
|
+
model,
|
|
267
|
+
inputUnits: r.usageMetadata.promptTokenCount,
|
|
268
|
+
outputUnits: r.usageMetadata.candidatesTokenCount,
|
|
269
|
+
cachedInputUnits: r.usageMetadata.cachedContentTokenCount,
|
|
270
|
+
metadata: {
|
|
271
|
+
totalTokens: r.usageMetadata.totalTokenCount,
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* BFL (Black Forest Labs) extraction strategy
|
|
278
|
+
*
|
|
279
|
+
* Note: BFL responses are similar to fal.ai but use "id" (not "requestId")
|
|
280
|
+
* and have "sample" field for images. fal.ai uses "requestId" (camelCase).
|
|
281
|
+
*/
|
|
282
|
+
export const bflStrategy = {
|
|
283
|
+
provider: "bfl",
|
|
284
|
+
canHandle(methodPath, result) {
|
|
285
|
+
if (!result || typeof result !== "object")
|
|
286
|
+
return false;
|
|
287
|
+
const r = result;
|
|
288
|
+
// BFL API responses have:
|
|
289
|
+
// - "id" field (not "requestId" which is fal.ai's format)
|
|
290
|
+
// - "sample" field with base64 image data
|
|
291
|
+
// Explicitly exclude fal.ai responses which have "requestId" (camelCase)
|
|
292
|
+
if ("requestId" in r)
|
|
293
|
+
return false;
|
|
294
|
+
return "id" in r && ("sample" in r || "images" in r);
|
|
295
|
+
},
|
|
296
|
+
extract(methodPath, result, args) {
|
|
297
|
+
const r = result;
|
|
298
|
+
// Extract model from args (BFL uses model in request body or endpoint)
|
|
299
|
+
let model = "flux-pro"; // Default
|
|
300
|
+
if (args.length > 0) {
|
|
301
|
+
const params = args[0];
|
|
302
|
+
if (params?.model) {
|
|
303
|
+
model = params.model;
|
|
304
|
+
}
|
|
305
|
+
else if (params?.endpoint) {
|
|
306
|
+
// Extract model from endpoint like "/v1/flux-pro-1.1"
|
|
307
|
+
const match = params.endpoint.match(/\/(flux-[\w.-]+)/);
|
|
308
|
+
if (match) {
|
|
309
|
+
model = match[1];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Count output images
|
|
314
|
+
let outputUnits = 1;
|
|
315
|
+
if (r.images && Array.isArray(r.images)) {
|
|
316
|
+
outputUnits = r.images.length;
|
|
317
|
+
}
|
|
318
|
+
else if (r.sample && Array.isArray(r.sample)) {
|
|
319
|
+
outputUnits = r.sample.length;
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
provider: "bfl",
|
|
323
|
+
model,
|
|
324
|
+
outputUnits,
|
|
325
|
+
metadata: {
|
|
326
|
+
requestId: r.id || r.request_id,
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
/**
|
|
332
|
+
* Vercel AI SDK extraction strategy
|
|
333
|
+
* Handles generateText, streamText, generateObject, streamObject results
|
|
334
|
+
*/
|
|
335
|
+
export const vercelAIStrategy = {
|
|
336
|
+
provider: "vercel-ai",
|
|
337
|
+
canHandle(methodPath, result) {
|
|
338
|
+
if (!result || typeof result !== "object")
|
|
339
|
+
return false;
|
|
340
|
+
const r = result;
|
|
341
|
+
// Vercel AI SDK responses have usage with promptTokens/completionTokens
|
|
342
|
+
return ("usage" in r &&
|
|
343
|
+
typeof r.usage === "object" &&
|
|
344
|
+
r.usage !== null &&
|
|
345
|
+
"promptTokens" in r.usage);
|
|
346
|
+
},
|
|
347
|
+
extract(methodPath, result, args) {
|
|
348
|
+
const r = result;
|
|
349
|
+
if (!r.usage)
|
|
350
|
+
return null;
|
|
351
|
+
// Try to determine provider and model
|
|
352
|
+
let provider = "unknown";
|
|
353
|
+
let model = "unknown";
|
|
354
|
+
if (r.response?.modelId) {
|
|
355
|
+
model = r.response.modelId;
|
|
356
|
+
// Infer provider from model
|
|
357
|
+
if (model.startsWith("gpt-") ||
|
|
358
|
+
model.startsWith("o1") ||
|
|
359
|
+
model.startsWith("o3")) {
|
|
360
|
+
provider = "openai";
|
|
361
|
+
}
|
|
362
|
+
else if (model.startsWith("claude-")) {
|
|
363
|
+
provider = "anthropic";
|
|
364
|
+
}
|
|
365
|
+
else if (model.startsWith("gemini-")) {
|
|
366
|
+
provider = "google";
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// Try to get model from args
|
|
370
|
+
if (args.length > 0) {
|
|
371
|
+
const params = args[0];
|
|
372
|
+
if (params?.model?.modelId) {
|
|
373
|
+
model = params.model.modelId;
|
|
374
|
+
}
|
|
375
|
+
if (params?.model?.provider) {
|
|
376
|
+
provider = params.model.provider;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
provider,
|
|
381
|
+
model,
|
|
382
|
+
inputUnits: r.usage.promptTokens,
|
|
383
|
+
outputUnits: r.usage.completionTokens,
|
|
384
|
+
};
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* All registered strategies
|
|
389
|
+
*/
|
|
390
|
+
export const strategies = [
|
|
391
|
+
openaiStrategy,
|
|
392
|
+
anthropicStrategy,
|
|
393
|
+
bedrockStrategy,
|
|
394
|
+
vertexAIStrategy,
|
|
395
|
+
falStrategy,
|
|
396
|
+
bflStrategy,
|
|
397
|
+
elevenlabsStrategy,
|
|
398
|
+
vercelAIStrategy,
|
|
399
|
+
];
|
|
400
|
+
/**
|
|
401
|
+
* Find the appropriate strategy for a given result
|
|
402
|
+
*/
|
|
403
|
+
export function findStrategy(methodPath, result) {
|
|
404
|
+
for (const strategy of strategies) {
|
|
405
|
+
if (strategy.canHandle(methodPath, result)) {
|
|
406
|
+
return strategy;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Extract usage data using the appropriate strategy
|
|
413
|
+
*/
|
|
414
|
+
export function extractUsage(methodPath, result, args, providerHint) {
|
|
415
|
+
// If provider hint is given, try that strategy first
|
|
416
|
+
if (providerHint) {
|
|
417
|
+
const hintedStrategy = strategies.find((s) => s.provider === providerHint);
|
|
418
|
+
if (hintedStrategy?.canHandle(methodPath, result)) {
|
|
419
|
+
return hintedStrategy.extract(methodPath, result, args);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
// Otherwise, try all strategies
|
|
423
|
+
const strategy = findStrategy(methodPath, result);
|
|
424
|
+
if (strategy) {
|
|
425
|
+
return strategy.extract(methodPath, result, args);
|
|
426
|
+
}
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/instrumentation/strategies/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction, RequestHandler } from "express";
|
|
2
|
+
import type { CostTraceOptions } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for the Express middleware
|
|
5
|
+
*/
|
|
6
|
+
export interface TokenmeterMiddlewareConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Extract the identifier from the request.
|
|
9
|
+
* This is required and should return a user ID, org ID, or other billing identifier.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* getIdentifier: (req) => req.user?.id || req.headers['x-user-id']
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
getIdentifier: (req: Request) => string | null | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Optional: Extract a secondary identifier from the request.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* getSecondaryIdentifier: (req) => req.user?.orgId
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
getSecondaryIdentifier?: (req: Request) => string | null | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Optional: Extract or generate a workflow ID from the request.
|
|
28
|
+
* Defaults to using the x-request-id header or generating a UUID.
|
|
29
|
+
*/
|
|
30
|
+
getWorkflowId?: (req: Request) => string | null | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Optional: Extract or specify a workflow type from the request.
|
|
33
|
+
*/
|
|
34
|
+
getWorkflowType?: (req: Request) => string | null | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Optional: Extract additional metadata from the request.
|
|
37
|
+
*/
|
|
38
|
+
getMetadata?: (req: Request) => Record<string, unknown> | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Optional: Filter which routes should have cost tracking enabled.
|
|
41
|
+
* Return true to enable tracking for the request, false to skip.
|
|
42
|
+
* Defaults to tracking all routes.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* shouldTrack: (req) => req.path.startsWith('/api/')
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
shouldTrack?: (req: Request) => boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create an Express middleware that automatically sets up cost tracking context.
|
|
53
|
+
*
|
|
54
|
+
* This middleware wraps incoming requests with `withCostTrace()`, allowing
|
|
55
|
+
* any AI calls made during request handling to be automatically tracked.
|
|
56
|
+
*
|
|
57
|
+
* @param config - Configuration for extracting identifiers and metadata
|
|
58
|
+
* @returns An Express middleware function
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import express from 'express';
|
|
63
|
+
* import { init } from 'tokenmeter';
|
|
64
|
+
* import { tokenmeterMiddleware } from 'tokenmeter/express';
|
|
65
|
+
*
|
|
66
|
+
* init({ databaseUrl: process.env.DATABASE_URL });
|
|
67
|
+
*
|
|
68
|
+
* const app = express();
|
|
69
|
+
*
|
|
70
|
+
* app.use(tokenmeterMiddleware({
|
|
71
|
+
* getIdentifier: (req) => req.user?.id || req.headers['x-user-id'] as string,
|
|
72
|
+
* shouldTrack: (req) => req.path.startsWith('/api/'),
|
|
73
|
+
* }));
|
|
74
|
+
*
|
|
75
|
+
* app.post('/api/chat', async (req, res) => {
|
|
76
|
+
* // AI calls here are automatically tracked
|
|
77
|
+
* const result = await openai.chat.completions.create({ ... });
|
|
78
|
+
* res.json({ result });
|
|
79
|
+
* });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function tokenmeterMiddleware(config: TokenmeterMiddlewareConfig): RequestHandler;
|
|
83
|
+
/**
|
|
84
|
+
* Wrap an async Express route handler with cost tracking.
|
|
85
|
+
*
|
|
86
|
+
* Use this for individual route handlers when you need more control than middleware.
|
|
87
|
+
*
|
|
88
|
+
* @param handler - The async route handler function
|
|
89
|
+
* @param getOptions - Function to extract trace options from the request
|
|
90
|
+
* @returns A wrapped route handler
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* import { withTokenmeter } from 'tokenmeter/express';
|
|
95
|
+
*
|
|
96
|
+
* const chatHandler = withTokenmeter(
|
|
97
|
+
* async (req, res) => {
|
|
98
|
+
* const result = await openai.chat.completions.create({ ... });
|
|
99
|
+
* res.json({ result });
|
|
100
|
+
* },
|
|
101
|
+
* (req) => ({
|
|
102
|
+
* identifier: req.user?.id || 'anonymous',
|
|
103
|
+
* workflowType: 'chat',
|
|
104
|
+
* })
|
|
105
|
+
* );
|
|
106
|
+
*
|
|
107
|
+
* app.post('/api/chat', chatHandler);
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function withTokenmeter(handler: (req: Request, res: Response, next: NextFunction) => Promise<void>, getOptions: (req: Request) => CostTraceOptions | Promise<CostTraceOptions>): RequestHandler;
|
|
111
|
+
/**
|
|
112
|
+
* Helper to extract common identifiers from Express request headers.
|
|
113
|
+
*/
|
|
114
|
+
export declare const headerExtractors: {
|
|
115
|
+
/**
|
|
116
|
+
* Get identifier from x-user-id header
|
|
117
|
+
*/
|
|
118
|
+
userId: (req: Request) => string | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Get identifier from x-org-id header
|
|
121
|
+
*/
|
|
122
|
+
orgId: (req: Request) => string | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Get identifier from x-api-key header
|
|
125
|
+
*/
|
|
126
|
+
apiKey: (req: Request) => string | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* Get identifier from Authorization header (Bearer token)
|
|
129
|
+
*/
|
|
130
|
+
bearerToken: (req: Request) => any;
|
|
131
|
+
/**
|
|
132
|
+
* Get request ID from common headers
|
|
133
|
+
*/
|
|
134
|
+
requestId: (req: Request) => string;
|
|
135
|
+
};
|
|
136
|
+
export default tokenmeterMiddleware;
|
|
137
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/express/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;OAQG;IACH,aAAa,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAE3D;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAErE;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAE5D;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAE9D;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAEpE;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,0BAA0B,GACjC,cAAc,CAgFhB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,EAC3E,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,GACzE,cAAc,CAuBhB;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;OAEG;kBACW,OAAO,KAAiC,MAAM,GAAG,SAAS;IAExE;;OAEG;iBACU,OAAO,KAAgC,MAAM,GAAG,SAAS;IAEtE;;OAEG;kBACW,OAAO,KAAiC,MAAM,GAAG,SAAS;IAExE;;OAEG;uBACgB,OAAO;IAQ1B;;OAEG;qBACc,OAAO;CAIzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|