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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +346 -0
  3. package/dist/__tests__/context.test.d.ts +2 -0
  4. package/dist/__tests__/context.test.d.ts.map +1 -0
  5. package/dist/__tests__/context.test.js +94 -0
  6. package/dist/__tests__/context.test.js.map +1 -0
  7. package/dist/__tests__/elevenlabs.test.d.ts +2 -0
  8. package/dist/__tests__/elevenlabs.test.d.ts.map +1 -0
  9. package/dist/__tests__/elevenlabs.test.js +108 -0
  10. package/dist/__tests__/elevenlabs.test.js.map +1 -0
  11. package/dist/__tests__/fal.test.d.ts +2 -0
  12. package/dist/__tests__/fal.test.d.ts.map +1 -0
  13. package/dist/__tests__/fal.test.js +153 -0
  14. package/dist/__tests__/fal.test.js.map +1 -0
  15. package/dist/__tests__/pricing.test.d.ts +2 -0
  16. package/dist/__tests__/pricing.test.d.ts.map +1 -0
  17. package/dist/__tests__/pricing.test.js +76 -0
  18. package/dist/__tests__/pricing.test.js.map +1 -0
  19. package/dist/__tests__/recorder.test.d.ts +2 -0
  20. package/dist/__tests__/recorder.test.d.ts.map +1 -0
  21. package/dist/__tests__/recorder.test.js +133 -0
  22. package/dist/__tests__/recorder.test.js.map +1 -0
  23. package/dist/__tests__/storage.test.d.ts +2 -0
  24. package/dist/__tests__/storage.test.d.ts.map +1 -0
  25. package/dist/__tests__/storage.test.js +106 -0
  26. package/dist/__tests__/storage.test.js.map +1 -0
  27. package/dist/client/index.d.ts +8 -0
  28. package/dist/client/index.d.ts.map +1 -0
  29. package/dist/client/index.js +7 -0
  30. package/dist/client/index.js.map +1 -0
  31. package/dist/config.d.ts +92 -0
  32. package/dist/config.d.ts.map +1 -0
  33. package/dist/config.js +166 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/context.d.ts +80 -0
  36. package/dist/context.d.ts.map +1 -0
  37. package/dist/context.js +131 -0
  38. package/dist/context.js.map +1 -0
  39. package/dist/exporter/PostgresExporter.d.ts +82 -0
  40. package/dist/exporter/PostgresExporter.d.ts.map +1 -0
  41. package/dist/exporter/PostgresExporter.js +237 -0
  42. package/dist/exporter/PostgresExporter.js.map +1 -0
  43. package/dist/exporter/index.d.ts +8 -0
  44. package/dist/exporter/index.d.ts.map +1 -0
  45. package/dist/exporter/index.js +7 -0
  46. package/dist/exporter/index.js.map +1 -0
  47. package/dist/index.d.ts +31 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +37 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/instrumentation/proxy.d.ts +26 -0
  52. package/dist/instrumentation/proxy.d.ts.map +1 -0
  53. package/dist/instrumentation/proxy.js +337 -0
  54. package/dist/instrumentation/proxy.js.map +1 -0
  55. package/dist/instrumentation/strategies/index.d.ts +55 -0
  56. package/dist/instrumentation/strategies/index.d.ts.map +1 -0
  57. package/dist/instrumentation/strategies/index.js +429 -0
  58. package/dist/instrumentation/strategies/index.js.map +1 -0
  59. package/dist/integrations/express/index.d.ts +137 -0
  60. package/dist/integrations/express/index.d.ts.map +1 -0
  61. package/dist/integrations/express/index.js +186 -0
  62. package/dist/integrations/express/index.js.map +1 -0
  63. package/dist/integrations/inngest/index.d.ts +222 -0
  64. package/dist/integrations/inngest/index.d.ts.map +1 -0
  65. package/dist/integrations/inngest/index.js +223 -0
  66. package/dist/integrations/inngest/index.js.map +1 -0
  67. package/dist/integrations/langfuse/index.d.ts +170 -0
  68. package/dist/integrations/langfuse/index.d.ts.map +1 -0
  69. package/dist/integrations/langfuse/index.js +225 -0
  70. package/dist/integrations/langfuse/index.js.map +1 -0
  71. package/dist/integrations/next/index.d.ts +138 -0
  72. package/dist/integrations/next/index.d.ts.map +1 -0
  73. package/dist/integrations/next/index.js +170 -0
  74. package/dist/integrations/next/index.js.map +1 -0
  75. package/dist/integrations/nextjs/index.d.ts +198 -0
  76. package/dist/integrations/nextjs/index.d.ts.map +1 -0
  77. package/dist/integrations/nextjs/index.js +181 -0
  78. package/dist/integrations/nextjs/index.js.map +1 -0
  79. package/dist/integrations/vercel-ai/index.d.ts +288 -0
  80. package/dist/integrations/vercel-ai/index.d.ts.map +1 -0
  81. package/dist/integrations/vercel-ai/index.js +260 -0
  82. package/dist/integrations/vercel-ai/index.js.map +1 -0
  83. package/dist/logger.d.ts +58 -0
  84. package/dist/logger.d.ts.map +1 -0
  85. package/dist/logger.js +89 -0
  86. package/dist/logger.js.map +1 -0
  87. package/dist/pricing/catalog.d.ts +10 -0
  88. package/dist/pricing/catalog.d.ts.map +1 -0
  89. package/dist/pricing/catalog.js +297 -0
  90. package/dist/pricing/catalog.js.map +1 -0
  91. package/dist/pricing/index.d.ts +77 -0
  92. package/dist/pricing/index.d.ts.map +1 -0
  93. package/dist/pricing/index.js +251 -0
  94. package/dist/pricing/index.js.map +1 -0
  95. package/dist/pricing/manifest.d.ts +156 -0
  96. package/dist/pricing/manifest.d.ts.map +1 -0
  97. package/dist/pricing/manifest.js +381 -0
  98. package/dist/pricing/manifest.js.map +1 -0
  99. package/dist/pricing/manifest.json +12786 -0
  100. package/dist/pricing/providers/anthropic.json +253 -0
  101. package/dist/pricing/providers/bedrock.json +341 -0
  102. package/dist/pricing/providers/bfl.json +220 -0
  103. package/dist/pricing/providers/elevenlabs.json +142 -0
  104. package/dist/pricing/providers/fal.json +15866 -0
  105. package/dist/pricing/providers/google.json +346 -0
  106. package/dist/pricing/providers/openai.json +1035 -0
  107. package/dist/pricing/schema.d.ts +102 -0
  108. package/dist/pricing/schema.d.ts.map +1 -0
  109. package/dist/pricing/schema.js +56 -0
  110. package/dist/pricing/schema.js.map +1 -0
  111. package/dist/processor/TokenMeterProcessor.d.ts +55 -0
  112. package/dist/processor/TokenMeterProcessor.d.ts.map +1 -0
  113. package/dist/processor/TokenMeterProcessor.js +132 -0
  114. package/dist/processor/TokenMeterProcessor.js.map +1 -0
  115. package/dist/query/client.d.ts +61 -0
  116. package/dist/query/client.d.ts.map +1 -0
  117. package/dist/query/client.js +206 -0
  118. package/dist/query/client.js.map +1 -0
  119. package/dist/query/index.d.ts +8 -0
  120. package/dist/query/index.d.ts.map +1 -0
  121. package/dist/query/index.js +7 -0
  122. package/dist/query/index.js.map +1 -0
  123. package/dist/recorder.d.ts +74 -0
  124. package/dist/recorder.d.ts.map +1 -0
  125. package/dist/recorder.js +227 -0
  126. package/dist/recorder.js.map +1 -0
  127. package/dist/sdks/anthropic.d.ts +21 -0
  128. package/dist/sdks/anthropic.d.ts.map +1 -0
  129. package/dist/sdks/anthropic.js +258 -0
  130. package/dist/sdks/anthropic.js.map +1 -0
  131. package/dist/sdks/elevenlabs.d.ts +59 -0
  132. package/dist/sdks/elevenlabs.d.ts.map +1 -0
  133. package/dist/sdks/elevenlabs.js +192 -0
  134. package/dist/sdks/elevenlabs.js.map +1 -0
  135. package/dist/sdks/fal.d.ts +102 -0
  136. package/dist/sdks/fal.d.ts.map +1 -0
  137. package/dist/sdks/fal.js +306 -0
  138. package/dist/sdks/fal.js.map +1 -0
  139. package/dist/sdks/openai.d.ts +17 -0
  140. package/dist/sdks/openai.d.ts.map +1 -0
  141. package/dist/sdks/openai.js +191 -0
  142. package/dist/sdks/openai.js.map +1 -0
  143. package/dist/storage/interface.d.ts +15 -0
  144. package/dist/storage/interface.d.ts.map +1 -0
  145. package/dist/storage/interface.js +53 -0
  146. package/dist/storage/interface.js.map +1 -0
  147. package/dist/storage/prisma.d.ts +15 -0
  148. package/dist/storage/prisma.d.ts.map +1 -0
  149. package/dist/storage/prisma.js +135 -0
  150. package/dist/storage/prisma.js.map +1 -0
  151. package/dist/types.d.ts +206 -0
  152. package/dist/types.d.ts.map +1 -0
  153. package/dist/types.js +45 -0
  154. package/dist/types.js.map +1 -0
  155. package/dist/vercel-ai/index.d.ts +89 -0
  156. package/dist/vercel-ai/index.d.ts.map +1 -0
  157. package/dist/vercel-ai/index.js +298 -0
  158. package/dist/vercel-ai/index.js.map +1 -0
  159. package/package.json +119 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Pricing Schema Types
3
+ *
4
+ * Standardized types for provider pricing catalogs.
5
+ * These types define the structure of pricing JSON files.
6
+ */
7
+ /**
8
+ * Billing unit types supported across providers
9
+ */
10
+ export type BillingUnit = "tokens" | "characters" | "images" | "megapixels" | "seconds" | "minutes" | "requests";
11
+ /**
12
+ * A single pricing entry with an effective date
13
+ * Prices are per unit (e.g., per 1K tokens, per image)
14
+ */
15
+ export interface PricingEntry {
16
+ /** ISO 8601 date when this pricing became effective */
17
+ effectiveDate: string;
18
+ /** Cost per input unit (e.g., input tokens, characters) */
19
+ input?: number;
20
+ /** Cost per output unit (e.g., output tokens, generated images) */
21
+ output?: number;
22
+ /** Cost per cached input unit (prompt caching) */
23
+ cachedInput?: number;
24
+ /** Cost for cache creation/write (Anthropic) */
25
+ cacheWrite?: number;
26
+ /** Notes about this pricing change */
27
+ notes?: string;
28
+ }
29
+ /**
30
+ * Model definition with pricing history
31
+ */
32
+ export interface ModelPricing {
33
+ /** Display name for the model */
34
+ name?: string;
35
+ /** Billing unit for this model */
36
+ unit: BillingUnit;
37
+ /**
38
+ * Unit size - what the prices are per
39
+ * e.g., 1000 for "per 1K tokens", 1000000 for "per 1M tokens"
40
+ * Defaults to 1000 for tokens/characters, 1 for images/seconds
41
+ */
42
+ unitSize?: number;
43
+ /**
44
+ * Pricing history, sorted by effectiveDate ascending
45
+ * The last entry is the current pricing
46
+ */
47
+ pricing: PricingEntry[];
48
+ /** Model aliases that should resolve to this model */
49
+ aliases?: string[];
50
+ /** Whether this model is deprecated */
51
+ deprecated?: boolean;
52
+ /** Deprecation date if applicable */
53
+ deprecatedDate?: string;
54
+ /** Replacement model if deprecated */
55
+ replacedBy?: string;
56
+ }
57
+ /**
58
+ * Provider pricing catalog
59
+ */
60
+ export interface ProviderPricing {
61
+ /** JSON schema reference */
62
+ $schema?: string;
63
+ /** Provider identifier */
64
+ provider: string;
65
+ /** Display name for the provider */
66
+ displayName: string;
67
+ /** URL to official pricing page */
68
+ source: string;
69
+ /** ISO 8601 date when this file was last updated */
70
+ lastUpdated: string;
71
+ /** Currency for all prices (default: USD) */
72
+ currency?: string;
73
+ /** Model pricing definitions, keyed by model ID */
74
+ models: Record<string, ModelPricing>;
75
+ }
76
+ /**
77
+ * Resolved pricing for a specific model at a point in time
78
+ */
79
+ export interface ResolvedPricing {
80
+ provider: string;
81
+ model: string;
82
+ unit: BillingUnit;
83
+ unitSize: number;
84
+ input: number;
85
+ output: number;
86
+ cachedInput?: number;
87
+ cacheWrite?: number;
88
+ effectiveDate: string;
89
+ }
90
+ /**
91
+ * Get the current pricing for a model (most recent effective date)
92
+ */
93
+ export declare function getCurrentPricing(model: ModelPricing): PricingEntry | null;
94
+ /**
95
+ * Get pricing for a model at a specific date
96
+ */
97
+ export declare function getPricingAtDate(model: ModelPricing, date: Date): PricingEntry | null;
98
+ /**
99
+ * Get the default unit size for a billing unit
100
+ */
101
+ export declare function getDefaultUnitSize(unit: BillingUnit): number;
102
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/pricing/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,YAAY,GACZ,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,SAAS,GACT,UAAU,CAAC;AAEf;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAC;IAEtB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,kCAAkC;IAClC,IAAI,EAAE,WAAW,CAAC;IAElB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,OAAO,EAAE,YAAY,EAAE,CAAC;IAExB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,uCAAuC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,qCAAqC;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IAEjB,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IAEpB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IAEf,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IAEpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,GAAG,IAAI,CAM1E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,IAAI,GACT,YAAY,GAAG,IAAI,CAoBrB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAc5D"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Pricing Schema Types
3
+ *
4
+ * Standardized types for provider pricing catalogs.
5
+ * These types define the structure of pricing JSON files.
6
+ */
7
+ /**
8
+ * Get the current pricing for a model (most recent effective date)
9
+ */
10
+ export function getCurrentPricing(model) {
11
+ if (!model.pricing || model.pricing.length === 0) {
12
+ return null;
13
+ }
14
+ // Return the last entry (most recent)
15
+ return model.pricing[model.pricing.length - 1] ?? null;
16
+ }
17
+ /**
18
+ * Get pricing for a model at a specific date
19
+ */
20
+ export function getPricingAtDate(model, date) {
21
+ if (!model.pricing || model.pricing.length === 0) {
22
+ return null;
23
+ }
24
+ const targetTime = date.getTime();
25
+ // Find the most recent pricing that was effective before or on the target date
26
+ let result = null;
27
+ for (const entry of model.pricing) {
28
+ const entryTime = new Date(entry.effectiveDate).getTime();
29
+ if (entryTime <= targetTime) {
30
+ result = entry;
31
+ }
32
+ else {
33
+ break; // Entries are sorted, no need to continue
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+ /**
39
+ * Get the default unit size for a billing unit
40
+ */
41
+ export function getDefaultUnitSize(unit) {
42
+ switch (unit) {
43
+ case "tokens":
44
+ case "characters":
45
+ return 1000; // Per 1K
46
+ case "images":
47
+ case "megapixels":
48
+ case "seconds":
49
+ case "minutes":
50
+ case "requests":
51
+ return 1;
52
+ default:
53
+ return 1;
54
+ }
55
+ }
56
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/pricing/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmHH;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,sCAAsC;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAmB,EACnB,IAAU;IAEV,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAElC,+EAA+E;IAC/E,IAAI,MAAM,GAAwB,IAAI,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1D,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;YAC5B,MAAM,GAAG,KAAK,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,0CAA0C;QACnD,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAiB;IAClD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,YAAY;YACf,OAAO,IAAI,CAAC,CAAC,SAAS;QACxB,KAAK,QAAQ,CAAC;QACd,KAAK,YAAY,CAAC;QAClB,KAAK,SAAS,CAAC;QACf,KAAK,SAAS,CAAC;QACf,KAAK,UAAU;YACb,OAAO,CAAC,CAAC;QACX;YACE,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * TokenMeter Span Processor
3
+ *
4
+ * An OpenTelemetry SpanProcessor that calculates costs based on usage data
5
+ * and adds cost attributes to spans before they are exported.
6
+ */
7
+ import type { Context } from "@opentelemetry/api";
8
+ import type { SpanProcessor, ReadableSpan, Span } from "@opentelemetry/sdk-trace-base";
9
+ import type { TokenMeterProcessorConfig } from "../types.js";
10
+ /**
11
+ * TokenMeter SpanProcessor
12
+ *
13
+ * Intercepts spans on end and calculates costs based on usage attributes.
14
+ * The calculated cost is added as an attribute before the span is exported.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
19
+ * import { TokenMeterProcessor } from 'tokenmeter';
20
+ *
21
+ * const provider = new NodeTracerProvider();
22
+ * provider.addSpanProcessor(new TokenMeterProcessor());
23
+ * provider.register();
24
+ * ```
25
+ */
26
+ export declare class TokenMeterProcessor implements SpanProcessor {
27
+ private manifest;
28
+ private manifestPromise;
29
+ private config;
30
+ private pricingOverrides;
31
+ constructor(config?: TokenMeterProcessorConfig);
32
+ private loadManifestAsync;
33
+ /**
34
+ * Called when a span starts (no-op for TokenMeter)
35
+ */
36
+ onStart(span: Span, parentContext: Context): void;
37
+ /**
38
+ * Called when a span ends - this is where we calculate and add cost
39
+ */
40
+ onEnd(span: ReadableSpan): void;
41
+ /**
42
+ * Calculate cost for a span based on usage
43
+ */
44
+ private calculateSpanCost;
45
+ /**
46
+ * Shutdown the processor
47
+ */
48
+ shutdown(): Promise<void>;
49
+ /**
50
+ * Force flush (no-op for this processor)
51
+ */
52
+ forceFlush(): Promise<void>;
53
+ }
54
+ export default TokenMeterProcessor;
55
+ //# sourceMappingURL=TokenMeterProcessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenMeterProcessor.d.ts","sourceRoot":"","sources":["../../src/processor/TokenMeterProcessor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,IAAI,EACL,MAAM,+BAA+B,CAAC;AAOvC,OAAO,KAAK,EAAE,yBAAyB,EAAmB,MAAM,aAAa,CAAC;AAG9E;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IACvD,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,eAAe,CAA8B;IACrD,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,gBAAgB,CAA+B;gBAE3C,MAAM,GAAE,yBAA8B;YAQpC,iBAAiB;IAU/B;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,GAAG,IAAI;IAKjD;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAmD/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAO/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAGlC;AAED,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * TokenMeter Span Processor
3
+ *
4
+ * An OpenTelemetry SpanProcessor that calculates costs based on usage data
5
+ * and adds cost attributes to spans before they are exported.
6
+ */
7
+ import { loadManifest, getModelPricing, calculateCost, getCachedManifest, } from "../pricing/manifest.js";
8
+ import { TM_ATTRIBUTES, GEN_AI_ATTRIBUTES } from "../types.js";
9
+ /**
10
+ * TokenMeter SpanProcessor
11
+ *
12
+ * Intercepts spans on end and calculates costs based on usage attributes.
13
+ * The calculated cost is added as an attribute before the span is exported.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
18
+ * import { TokenMeterProcessor } from 'tokenmeter';
19
+ *
20
+ * const provider = new NodeTracerProvider();
21
+ * provider.addSpanProcessor(new TokenMeterProcessor());
22
+ * provider.register();
23
+ * ```
24
+ */
25
+ export class TokenMeterProcessor {
26
+ manifest = null;
27
+ manifestPromise = null;
28
+ config;
29
+ pricingOverrides;
30
+ constructor(config = {}) {
31
+ this.config = config;
32
+ this.pricingOverrides = config.pricingOverrides || {};
33
+ // Start loading manifest in background
34
+ this.manifestPromise = this.loadManifestAsync();
35
+ }
36
+ async loadManifestAsync() {
37
+ try {
38
+ this.manifest = await loadManifest({
39
+ manifestUrl: this.config.manifestUrl,
40
+ });
41
+ }
42
+ catch (error) {
43
+ console.error("[tokenmeter] Failed to load pricing manifest:", error);
44
+ }
45
+ }
46
+ /**
47
+ * Called when a span starts (no-op for TokenMeter)
48
+ */
49
+ onStart(span, parentContext) {
50
+ // We don't need to do anything when spans start
51
+ // Cost calculation happens on end
52
+ }
53
+ /**
54
+ * Called when a span ends - this is where we calculate and add cost
55
+ */
56
+ onEnd(span) {
57
+ // Get usage attributes from span
58
+ const attrs = span.attributes;
59
+ // Check if this span has usage data
60
+ const inputUnits = attrs[TM_ATTRIBUTES.INPUT_UNITS] ||
61
+ attrs[GEN_AI_ATTRIBUTES.INPUT_TOKENS];
62
+ const outputUnits = attrs[TM_ATTRIBUTES.OUTPUT_UNITS] ||
63
+ attrs[GEN_AI_ATTRIBUTES.OUTPUT_TOKENS];
64
+ // If no usage data, skip
65
+ if (inputUnits === undefined && outputUnits === undefined) {
66
+ return;
67
+ }
68
+ // Get provider and model
69
+ const provider = attrs[TM_ATTRIBUTES.PROVIDER] ||
70
+ attrs[GEN_AI_ATTRIBUTES.SYSTEM] ||
71
+ "unknown";
72
+ const model = attrs[TM_ATTRIBUTES.MODEL] ||
73
+ attrs[GEN_AI_ATTRIBUTES.MODEL] ||
74
+ "unknown";
75
+ // Calculate cost
76
+ const cost = this.calculateSpanCost(provider, model, {
77
+ inputUnits,
78
+ outputUnits,
79
+ });
80
+ // Add cost attribute to span
81
+ // Note: OTel allows modifying span attributes after end but before export
82
+ // We use a workaround by storing cost in the span's resource or via events
83
+ // For now, we'll set it directly (works with most exporters)
84
+ if (cost !== null) {
85
+ // Unfortunately, ReadableSpan doesn't allow setting attributes after end
86
+ // We need to use a custom approach - storing in a side channel or using events
87
+ // For this implementation, we'll log a warning and add via span events
88
+ // A production implementation would use a custom exporter or modify before end
89
+ // The proper way is to calculate cost BEFORE span.end() in the proxy
90
+ // This processor is for catching spans from other sources (like Vercel AI SDK)
91
+ console.debug(`[tokenmeter] Calculated cost for ${provider}/${model}: $${cost.toFixed(6)}`);
92
+ }
93
+ }
94
+ /**
95
+ * Calculate cost for a span based on usage
96
+ */
97
+ calculateSpanCost(provider, model, usage) {
98
+ // Check overrides first
99
+ if (this.pricingOverrides[provider]?.[model]) {
100
+ return calculateCost(usage, this.pricingOverrides[provider][model]);
101
+ }
102
+ // Fall back to manifest
103
+ const manifest = this.manifest || getCachedManifest();
104
+ if (!manifest) {
105
+ console.warn(`[tokenmeter] Pricing manifest not loaded, cannot calculate cost`);
106
+ return null;
107
+ }
108
+ const pricing = getModelPricing(provider, model, manifest);
109
+ if (!pricing) {
110
+ console.warn(`[tokenmeter] No pricing found for ${provider}/${model}`);
111
+ return 0; // Return 0, not null, to indicate we tried but found no pricing
112
+ }
113
+ return calculateCost(usage, pricing);
114
+ }
115
+ /**
116
+ * Shutdown the processor
117
+ */
118
+ async shutdown() {
119
+ // Wait for manifest to finish loading
120
+ if (this.manifestPromise) {
121
+ await this.manifestPromise;
122
+ }
123
+ }
124
+ /**
125
+ * Force flush (no-op for this processor)
126
+ */
127
+ async forceFlush() {
128
+ // No buffering, nothing to flush
129
+ }
130
+ }
131
+ export default TokenMeterProcessor;
132
+ //# sourceMappingURL=TokenMeterProcessor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenMeterProcessor.js","sourceRoot":"","sources":["../../src/processor/TokenMeterProcessor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Query Client
3
+ *
4
+ * Provides cost aggregation and querying capabilities.
5
+ */
6
+ import type { CostQueryOptions, CostResult } from "../types.js";
7
+ /**
8
+ * Query client configuration
9
+ */
10
+ export interface QueryClientConfig {
11
+ /** PostgreSQL connection string */
12
+ connectionString: string;
13
+ /** Table name (default: tokenmeter_events) */
14
+ tableName?: string;
15
+ }
16
+ /**
17
+ * Query client interface
18
+ */
19
+ export interface QueryClient {
20
+ /** Get costs with optional filtering and grouping */
21
+ getCosts(options?: CostQueryOptions): Promise<CostResult>;
22
+ /** Get costs for a specific user */
23
+ getCostByUser(userId: string, options?: Omit<CostQueryOptions, "userId">): Promise<CostResult>;
24
+ /** Get costs for a specific organization */
25
+ getCostByOrg(orgId: string, options?: Omit<CostQueryOptions, "organizationId">): Promise<CostResult>;
26
+ /** Get costs for a specific model */
27
+ getCostByModel(model: string, options?: Omit<CostQueryOptions, "model">): Promise<CostResult>;
28
+ /** Get costs for a specific provider */
29
+ getCostByProvider(provider: string, options?: Omit<CostQueryOptions, "provider">): Promise<CostResult>;
30
+ /** Get total cost for a workflow/trace */
31
+ getWorkflowCost(workflowId: string): Promise<CostResult>;
32
+ /** Close the database connection */
33
+ close(): Promise<void>;
34
+ }
35
+ /**
36
+ * Create a query client for cost aggregation
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * import { createQueryClient } from 'tokenmeter/query';
41
+ *
42
+ * const client = createQueryClient({
43
+ * connectionString: process.env.DATABASE_URL,
44
+ * });
45
+ *
46
+ * // Get total costs for an organization
47
+ * const orgCosts = await client.getCostByOrg('org_123', {
48
+ * from: '2024-01-01',
49
+ * to: '2024-01-31',
50
+ * groupBy: ['model'],
51
+ * });
52
+ *
53
+ * console.log(`Total: $${orgCosts.totalCost}`);
54
+ * for (const group of orgCosts.groups ?? []) {
55
+ * console.log(` ${group.key.model}: $${group.cost}`);
56
+ * }
57
+ * ```
58
+ */
59
+ export declare function createQueryClient(config: QueryClientConfig): Promise<QueryClient>;
60
+ export default createQueryClient;
61
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/query/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAUhE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,oCAAoC;IACpC,aAAa,CACX,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GACzC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,4CAA4C;IAC5C,YAAY,CACV,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,GACjD,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,qCAAqC;IACrC,cAAc,CACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,GACxC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,wCAAwC;IACxC,iBAAiB,CACf,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,GAC3C,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,0CAA0C;IAC1C,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACzD,oCAAoC;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,WAAW,CAAC,CAqOtB;AAED,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Query Client
3
+ *
4
+ * Provides cost aggregation and querying capabilities.
5
+ */
6
+ /**
7
+ * Create a query client for cost aggregation
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { createQueryClient } from 'tokenmeter/query';
12
+ *
13
+ * const client = createQueryClient({
14
+ * connectionString: process.env.DATABASE_URL,
15
+ * });
16
+ *
17
+ * // Get total costs for an organization
18
+ * const orgCosts = await client.getCostByOrg('org_123', {
19
+ * from: '2024-01-01',
20
+ * to: '2024-01-31',
21
+ * groupBy: ['model'],
22
+ * });
23
+ *
24
+ * console.log(`Total: $${orgCosts.totalCost}`);
25
+ * for (const group of orgCosts.groups ?? []) {
26
+ * console.log(` ${group.key.model}: $${group.cost}`);
27
+ * }
28
+ * ```
29
+ */
30
+ export async function createQueryClient(config) {
31
+ const tableName = config.tableName ?? "tokenmeter_events";
32
+ // Dynamic import to avoid requiring pg at load time
33
+ const { Pool } = await import("pg");
34
+ const pool = new Pool({
35
+ connectionString: config.connectionString,
36
+ });
37
+ /**
38
+ * Build WHERE clause from options
39
+ */
40
+ function buildWhereClause(options, startParamIndex = 1) {
41
+ const conditions = [];
42
+ const values = [];
43
+ let paramIndex = startParamIndex;
44
+ if (options.from) {
45
+ conditions.push(`created_at >= $${paramIndex}`);
46
+ values.push(options.from instanceof Date ? options.from : new Date(options.from));
47
+ paramIndex++;
48
+ }
49
+ if (options.to) {
50
+ conditions.push(`created_at <= $${paramIndex}`);
51
+ values.push(options.to instanceof Date ? options.to : new Date(options.to));
52
+ paramIndex++;
53
+ }
54
+ if (options.provider) {
55
+ conditions.push(`provider = $${paramIndex}`);
56
+ values.push(options.provider);
57
+ paramIndex++;
58
+ }
59
+ if (options.model) {
60
+ conditions.push(`model = $${paramIndex}`);
61
+ values.push(options.model);
62
+ paramIndex++;
63
+ }
64
+ if (options.organizationId) {
65
+ conditions.push(`organization_id = $${paramIndex}`);
66
+ values.push(options.organizationId);
67
+ paramIndex++;
68
+ }
69
+ if (options.userId) {
70
+ conditions.push(`user_id = $${paramIndex}`);
71
+ values.push(options.userId);
72
+ paramIndex++;
73
+ }
74
+ const clause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
75
+ return { clause, values, nextIndex: paramIndex };
76
+ }
77
+ /**
78
+ * Map groupBy field names to column names
79
+ */
80
+ function mapGroupByField(field) {
81
+ const fieldMap = {
82
+ provider: "provider",
83
+ model: "model",
84
+ organizationId: "organization_id",
85
+ userId: "user_id",
86
+ workflowId: "workflow_id",
87
+ };
88
+ return fieldMap[field] ?? field;
89
+ }
90
+ /**
91
+ * Execute a cost query
92
+ */
93
+ async function getCosts(options = {}) {
94
+ const { clause, values, nextIndex } = buildWhereClause(options);
95
+ const groupBy = options.groupBy?.map(mapGroupByField) ?? [];
96
+ let query;
97
+ let queryValues = values;
98
+ if (groupBy.length > 0) {
99
+ // Query with grouping
100
+ const groupByClause = groupBy.join(", ");
101
+ const selectFields = groupBy
102
+ .map((col) => {
103
+ // Map back to camelCase for the result
104
+ const keyName = col === "organization_id"
105
+ ? "organizationId"
106
+ : col === "user_id"
107
+ ? "userId"
108
+ : col === "workflow_id"
109
+ ? "workflowId"
110
+ : col;
111
+ return `${col} as "${keyName}"`;
112
+ })
113
+ .join(", ");
114
+ query = `
115
+ SELECT
116
+ ${selectFields},
117
+ COALESCE(SUM(cost_usd), 0)::numeric as cost,
118
+ COUNT(*)::int as count
119
+ FROM ${tableName}
120
+ ${clause}
121
+ GROUP BY ${groupByClause}
122
+ ORDER BY cost DESC
123
+ ${options.limit ? `LIMIT $${nextIndex}` : ""}
124
+ `;
125
+ if (options.limit) {
126
+ queryValues = [...values, options.limit];
127
+ }
128
+ const result = await pool.query(query, queryValues);
129
+ // Calculate totals
130
+ let totalCost = 0;
131
+ let totalCount = 0;
132
+ const groups = [];
133
+ for (const row of result.rows) {
134
+ const cost = parseFloat(row.cost);
135
+ const count = row.count;
136
+ totalCost += cost;
137
+ totalCount += count;
138
+ // Build key object from group fields
139
+ const key = {};
140
+ for (const field of groupBy) {
141
+ const keyName = field === "organization_id"
142
+ ? "organizationId"
143
+ : field === "user_id"
144
+ ? "userId"
145
+ : field === "workflow_id"
146
+ ? "workflowId"
147
+ : field;
148
+ key[keyName] = row[keyName] ?? "";
149
+ }
150
+ groups.push({ key, cost, count });
151
+ }
152
+ return { totalCost, count: totalCount, groups };
153
+ }
154
+ else {
155
+ // Simple aggregate query
156
+ query = `
157
+ SELECT
158
+ COALESCE(SUM(cost_usd), 0)::numeric as total_cost,
159
+ COUNT(*)::int as count
160
+ FROM ${tableName}
161
+ ${clause}
162
+ `;
163
+ const result = await pool.query(query, values);
164
+ const row = result.rows[0];
165
+ return {
166
+ totalCost: parseFloat(row.total_cost),
167
+ count: row.count,
168
+ };
169
+ }
170
+ }
171
+ return {
172
+ getCosts,
173
+ async getCostByUser(userId, options = {}) {
174
+ return getCosts({ ...options, userId });
175
+ },
176
+ async getCostByOrg(orgId, options = {}) {
177
+ return getCosts({ ...options, organizationId: orgId });
178
+ },
179
+ async getCostByModel(model, options = {}) {
180
+ return getCosts({ ...options, model });
181
+ },
182
+ async getCostByProvider(provider, options = {}) {
183
+ return getCosts({ ...options, provider });
184
+ },
185
+ async getWorkflowCost(workflowId) {
186
+ const query = `
187
+ SELECT
188
+ COALESCE(SUM(cost_usd), 0)::numeric as total_cost,
189
+ COUNT(*)::int as count
190
+ FROM ${tableName}
191
+ WHERE trace_id = $1
192
+ `;
193
+ const result = await pool.query(query, [workflowId]);
194
+ const row = result.rows[0];
195
+ return {
196
+ totalCost: parseFloat(row.total_cost),
197
+ count: row.count,
198
+ };
199
+ },
200
+ async close() {
201
+ await pool.end();
202
+ },
203
+ };
204
+ }
205
+ export default createQueryClient;
206
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/query/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Query module
3
+ *
4
+ * Provides cost aggregation and querying capabilities.
5
+ */
6
+ export { createQueryClient } from "./client.js";
7
+ export type { QueryClient, QueryClientConfig } from "./client.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Query module
3
+ *
4
+ * Provides cost aggregation and querying capabilities.
5
+ */
6
+ export { createQueryClient } from "./client.js";
7
+ //# sourceMappingURL=index.js.map