@ai-billing/core 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -37,7 +37,8 @@ __export(index_exports, {
37
37
  createV3BillingMiddleware: () => createV3BillingMiddleware,
38
38
  multiplyCost: () => multiplyCost,
39
39
  rateToCost: () => rateToCost,
40
- toJSONObject: () => toJSONObject
40
+ toJSONObject: () => toJSONObject,
41
+ toUsage: () => toUsage
41
42
  });
42
43
  module.exports = __toCommonJS(index_exports);
43
44
 
@@ -62,11 +63,11 @@ function buildMeterMetadata(event) {
62
63
  addOptional("sub_provider", u.subProvider);
63
64
  addOptional("input_tokens", u.inputTokens);
64
65
  addOptional("output_tokens", u.outputTokens);
65
- addOptional("total_tokens", u.totalTokens);
66
66
  addOptional("reasoning_tokens", u.reasoningTokens);
67
67
  addOptional("cache_read_tokens", u.cacheReadTokens);
68
68
  addOptional("cache_write_tokens", u.cacheWriteTokens);
69
69
  addOptional("request_count", u.requestCount);
70
+ addOptional("web_search_count", u.webSearchCount);
70
71
  addOptional("raw_provider_cost", u.rawProviderCost);
71
72
  addOptional("raw_upstream_inference_cost", u.rawUpstreamInferenceCost);
72
73
  if (event.tags) {
@@ -86,7 +87,8 @@ function createV3BillingMiddleware(options) {
86
87
  params,
87
88
  usage,
88
89
  providerMetadata,
89
- responseId
90
+ responseId,
91
+ webSearchCount
90
92
  }) => {
91
93
  try {
92
94
  const requestTags = params.providerOptions?.["ai-billing-tags"];
@@ -99,7 +101,8 @@ function createV3BillingMiddleware(options) {
99
101
  model,
100
102
  usage,
101
103
  providerMetadata,
102
- tags
104
+ tags,
105
+ webSearchCount
103
106
  });
104
107
  if (event && destinations && destinations?.length > 0) {
105
108
  const dispatchDestinationsPromise = Promise.allSettled(
@@ -118,12 +121,16 @@ function createV3BillingMiddleware(options) {
118
121
  specificationVersion: "v3",
119
122
  wrapGenerate: async ({ doGenerate, model, params }) => {
120
123
  const result = await doGenerate();
124
+ const webSearchCount = result.content.filter(
125
+ (c) => c.type === "source"
126
+ ).length;
121
127
  const event = await processEvent({
122
128
  model,
123
129
  params,
124
130
  usage: result.usage,
125
131
  providerMetadata: result.providerMetadata,
126
- responseId: result.response?.id
132
+ responseId: result.response?.id,
133
+ webSearchCount
127
134
  });
128
135
  const providerMetadataWithBilling = {
129
136
  ...result.providerMetadata
@@ -142,6 +149,7 @@ function createV3BillingMiddleware(options) {
142
149
  let usage;
143
150
  let providerMetadata;
144
151
  let finishChunk;
152
+ let webSearchCount = 0;
145
153
  const billedStream = stream.pipeThrough(
146
154
  new TransformStream({
147
155
  transform(chunk, controller) {
@@ -149,6 +157,9 @@ function createV3BillingMiddleware(options) {
149
157
  if (chunk.type === "response-metadata" && !responseId) {
150
158
  responseId = chunk.id;
151
159
  }
160
+ if (chunk.type === "source") {
161
+ webSearchCount++;
162
+ }
152
163
  if (chunk.type === "finish") {
153
164
  usage = chunk.usage;
154
165
  providerMetadata = chunk.providerMetadata;
@@ -163,7 +174,8 @@ function createV3BillingMiddleware(options) {
163
174
  params,
164
175
  usage,
165
176
  providerMetadata,
166
- responseId
177
+ responseId,
178
+ webSearchCount
167
179
  });
168
180
  const providerMetadataWithBilling = {
169
181
  ...providerMetadata
@@ -425,6 +437,18 @@ function createObjectPriceResolver(pricingMap) {
425
437
  return pricingMap[modelId];
426
438
  });
427
439
  }
440
+
441
+ // src/utils/to-usage.ts
442
+ function toUsage(inputs) {
443
+ return {
444
+ inputTokens: inputs.promptTokens,
445
+ outputTokens: inputs.completionTokens,
446
+ cacheReadTokens: inputs.cacheReadTokens,
447
+ cacheWriteTokens: inputs.cacheWriteTokens,
448
+ reasoningTokens: inputs.reasoningTokens,
449
+ webSearchCount: inputs.webSearchCount
450
+ };
451
+ }
428
452
  // Annotate the CommonJS export names for ESM import in node:
429
453
  0 && (module.exports = {
430
454
  AIBillingError,
@@ -444,6 +468,7 @@ function createObjectPriceResolver(pricingMap) {
444
468
  createV3BillingMiddleware,
445
469
  multiplyCost,
446
470
  rateToCost,
447
- toJSONObject
471
+ toJSONObject,
472
+ toUsage
448
473
  });
449
474
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/event/to-json-object.ts","../src/event/to-meter-metadata.ts","../src/ai-sdk/language-model-middleware/v3/language-model-v3-base-billing-middleware.ts","../src/error/ai-billing-error.ts","../src/error/extractor-error.ts","../src/error/destination-error.ts","../src/error/cost-error.ts","../src/destination/base-destination.ts","../src/destination/console-destination.ts","../src/cost/convert-cost.ts","../src/cost/op-cost.ts","../src/pricing/base-price-resolver.ts","../src/pricing/narev-price-resolver.ts","../src/pricing/object-price-resolver.ts"],"sourcesContent":["export * from './types/index.js';\nexport * from './ai-sdk/index.js';\nexport * from './destination/index.js';\nexport * from './error/index.js';\nexport * from './cost/index.js';\nexport * from './pricing/index.js';\nexport * from './event/index.js';\n","import { DefaultTags, BillingEvent } from '../types/index.js';\nimport type { JSONObject } from '@ai-sdk/provider';\n\n/**\n * Casts a billing event into a JSON object payload.\n * @param event - The billing event to cast.\n * @returns The billing event represented as a JSON object.\n */\nexport function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject {\n return event as unknown as JSONObject;\n}\n","import type {\n BillingEvent,\n DefaultTags,\n MeterMetadata,\n} from '../types/index.js';\n\n/**\n * Converts a billing event into a meter metadata object.\n * @param event - The billing event to convert.\n * @returns The meter metadata object.\n */\nexport function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(\n event: BillingEvent<TTags>,\n): MeterMetadata {\n const u = event.usage ?? {};\n\n // Initialize with required fields\n const dimensions: MeterMetadata = {\n generation_id: event.generationId,\n model_id: event.modelId,\n provider: event.provider,\n };\n\n const addOptional = <K extends keyof MeterMetadata>(\n key: K,\n value: MeterMetadata[K],\n ) => {\n if (value !== undefined && value !== null) {\n dimensions[key] = value;\n }\n };\n\n addOptional('sub_provider', u.subProvider);\n addOptional('input_tokens', u.inputTokens);\n addOptional('output_tokens', u.outputTokens);\n addOptional('total_tokens', u.totalTokens);\n addOptional('reasoning_tokens', u.reasoningTokens);\n addOptional('cache_read_tokens', u.cacheReadTokens);\n addOptional('cache_write_tokens', u.cacheWriteTokens);\n addOptional('request_count', u.requestCount);\n addOptional('raw_provider_cost', u.rawProviderCost);\n addOptional('raw_upstream_inference_cost', u.rawUpstreamInferenceCost);\n\n if (event.tags) {\n for (const [key, value] of Object.entries(event.tags)) {\n if (value == null) continue;\n dimensions[`tag_${key}`] =\n typeof value === 'object'\n ? JSON.stringify(value)\n : (value as string | number);\n }\n }\n\n return dimensions;\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Usage,\n LanguageModelV3GenerateResult,\n LanguageModelV3StreamPart,\n LanguageModelV3Middleware,\n SharedV3ProviderMetadata,\n} from '@ai-sdk/provider';\nimport type {\n BaseBillingMiddlewareOptions,\n EventBuilder,\n BillingEvent,\n DefaultTags,\n} from '../../../types/index.js';\nimport { toJSONObject } from '../../../event/index.js';\n\nexport interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {\n responseId: string | undefined;\n model: LanguageModelV3;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n tags: TTags;\n}\n\n/**\n * Configuration for {@link createV3BillingMiddleware}.\n *\n * Extends {@link BaseBillingMiddlewareOptions} (`destinations`, `defaultTags`, `waitUntil`, `onError`) and\n * requires an {@link EventBuilder} to construct the {@link BillingEvent}.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n */\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n /** Builds a billing event from the model response data. */\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\n\n/**\n * Creates a billing middleware for the Language Model V3 API.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n * @param options - Billing options; see {@link BillingMiddlewareV3Options}.\n * @returns The billing middleware.\n */\nexport function createV3BillingMiddleware<\n TTags extends DefaultTags = DefaultTags,\n>(options: BillingMiddlewareV3Options<TTags>): LanguageModelV3Middleware {\n const { buildEvent, destinations, defaultTags, waitUntil, onError } = options;\n\n const processEvent = async ({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n }: {\n model: LanguageModelV3;\n params: LanguageModelV3CallOptions;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n responseId: string | undefined;\n }): Promise<BillingEvent<TTags> | null> => {\n try {\n const requestTags = params.providerOptions?.['ai-billing-tags'];\n\n const tags = {\n ...(defaultTags ?? {}),\n ...(requestTags ?? {}),\n } as TTags;\n\n const event = await buildEvent({\n responseId,\n model,\n usage,\n providerMetadata,\n tags,\n });\n\n if (event && destinations && destinations?.length > 0) {\n const dispatchDestinationsPromise = Promise.allSettled(\n destinations.map(d => Promise.resolve(d(event))),\n );\n if (waitUntil) waitUntil(dispatchDestinationsPromise);\n }\n return event;\n } catch (err) {\n if (onError) onError(err);\n else console.error('[ai-billing] Core Error:', err);\n return null;\n }\n };\n\n return {\n specificationVersion: 'v3',\n\n wrapGenerate: async ({ doGenerate, model, params }) => {\n const result: LanguageModelV3GenerateResult = await doGenerate();\n\n const event = await processEvent({\n model,\n params,\n usage: result.usage,\n providerMetadata: result.providerMetadata,\n responseId: result.response?.id,\n });\n\n const providerMetadataWithBilling = {\n ...result.providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n return {\n ...result,\n providerMetadata: providerMetadataWithBilling,\n };\n },\n\n wrapStream: async ({ doStream, model, params }) => {\n const { stream, ...rest } = await doStream();\n\n let responseId: string | undefined;\n let usage: LanguageModelV3Usage | undefined;\n let providerMetadata: SharedV3ProviderMetadata | undefined;\n let finishChunk:\n | Extract<LanguageModelV3StreamPart, { type: 'finish' }>\n | undefined;\n\n const billedStream = stream.pipeThrough(\n new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform(chunk, controller) {\n if (chunk.type === 'text-start') responseId = chunk.id;\n if (chunk.type === 'response-metadata' && !responseId) {\n responseId = chunk.id;\n }\n if (chunk.type === 'finish') {\n usage = chunk.usage;\n providerMetadata = chunk.providerMetadata;\n finishChunk = chunk;\n return; // held until flush\n }\n controller.enqueue(chunk);\n },\n async flush(controller) {\n const event = await processEvent({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n });\n\n const providerMetadataWithBilling = {\n ...providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n if (finishChunk) {\n controller.enqueue({\n ...finishChunk,\n providerMetadata: providerMetadataWithBilling,\n });\n }\n },\n }),\n );\n\n return { ...rest, stream: billedStream };\n },\n };\n}\n","const marker = 'ai-billing.error';\nconst symbol = Symbol.for(marker);\n\n/** Base error type for all ai-billing package errors. */\nexport class AIBillingError extends Error {\n private readonly [symbol] = true;\n\n readonly cause?: unknown;\n\n constructor({\n name,\n message,\n cause,\n }: {\n name: string;\n message: string;\n cause?: unknown;\n }) {\n super(message);\n this.name = name;\n this.cause = cause;\n }\n\n static isInstance(error: unknown): error is AIBillingError {\n return AIBillingError.hasMarker(error, marker);\n }\n\n protected static hasMarker(error: unknown, markerString: string): boolean {\n const markerSymbol = Symbol.for(markerString);\n return (\n error != null &&\n typeof error === 'object' &&\n markerSymbol in error &&\n typeof error[markerSymbol] === 'boolean' &&\n error[markerSymbol] === true\n );\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingExtractorError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when billing data extraction fails. */\nexport class AiBillingExtractorError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({\n message = `Failed to extract billing data.`,\n cause,\n }: {\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingExtractorError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingDestinationError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Error raised when billing data processing fails for a destination.\n */\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\n /** The ID of the destination that failed to process billing data. */\n readonly destinationId?: string;\n\n constructor({\n destinationId,\n message = `Failed to process billing data for destination: '${destinationId}'.`,\n cause,\n }: {\n destinationId?: string;\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n this.destinationId = destinationId;\n }\n\n static isInstance(error: unknown): error is AiBillingDestinationError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingCostError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when a cost conversion or calculation fails. */\nexport class AiBillingCostError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({ message, cause }: { message: string; cause?: unknown }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingCostError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import type { Destination, BillingEvent, DefaultTags } from '../types/index.js';\nimport { AiBillingDestinationError } from '../error/index.js';\n\n/**\n * Creates a destination wrapper that normalizes destination handler errors.\n *\n * @param destinationId - Unique identifier for the destination.\n * @param handler - Destination implementation invoked for each billing event.\n * @returns A destination function that wraps thrown errors as AiBillingDestinationError.\n */\nexport function createDestination<TTags extends DefaultTags = DefaultTags>(\n destinationId: string,\n handler: (event: BillingEvent<TTags>) => Promise<void> | void,\n): Destination<TTags> {\n return async (event: BillingEvent<TTags>) => {\n try {\n await handler(event);\n } catch (error) {\n throw new AiBillingDestinationError({\n destinationId,\n cause: error,\n });\n }\n };\n}\n","import { createDestination } from './base-destination.js';\nimport type { DefaultTags, Destination } from '../types/index.js';\n\n/**\n * Creates a destination that logs billing events to the console.\n *\n * @returns A destination that prints each event with full depth formatting.\n */\nexport function consoleDestination<\n TTags extends DefaultTags = DefaultTags,\n>(): Destination<TTags> {\n return createDestination<TTags>('console-logger', event => {\n console.dir(event, {\n depth: null,\n colors: true,\n compact: false,\n });\n });\n}\n","import { AiBillingCostError } from '../index.js';\nimport type { Cost, CostUnit } from '../index.js';\n\nconst getNanos = (cost: Cost): number => {\n switch (cost.unit) {\n case 'base':\n return Math.round(cost.amount * 1_000_000_000);\n case 'cents':\n return Math.round(cost.amount * 10_000_000);\n case 'micros':\n return Math.round(cost.amount * 1_000);\n case 'nanos':\n return Math.round(cost.amount);\n default:\n throw new AiBillingCostError({\n message: `Failed to process cost. Unknown CostUnit: '${String(cost.unit)}'.`,\n });\n }\n};\n\n/**\n * Returns the numeric amount of `cost` expressed in `targetUnit`.\n *\n * Values are converted via an integer nanos intermediate so fractional `base` / `cents` / `micros` amounts\n * round consistently. Throws {@link AiBillingCostError} when `cost.unit` is not a known {@link CostUnit}.\n *\n * @param cost - Source {@link Cost} (amount + unit + currency).\n * @param targetUnit - Unit for the returned number (same scale as {@link Cost} amounts for that unit).\n * @returns The amount in `targetUnit`; for `nanos` this is a whole number of nanos.\n * @internal\n */\nexport const costToNumber = (cost: Cost, targetUnit: CostUnit): number => {\n const nanos = getNanos(cost);\n\n if (targetUnit === 'nanos') return nanos;\n if (targetUnit === 'micros') return nanos / 1_000;\n if (targetUnit === 'cents') return nanos / 10_000_000;\n return nanos / 1_000_000_000; // base\n};\n\n/**\n * Converts a {@link Cost} to the same amount in a different {@link CostUnit}, preserving `currency`.\n *\n * Implemented with {@link costToNumber}; the result is always a new object.\n *\n * @param cost - Source cost.\n * @param targetUnit - Desired unit for `amount` on the returned object.\n * @returns A new {@link Cost} with `unit: targetUnit` and `amount` in that unit's scale.\n * @internal\n */\nexport const convertCostUnit = (cost: Cost, targetUnit: CostUnit): Cost => {\n return {\n amount: costToNumber(cost, targetUnit),\n currency: cost.currency,\n unit: targetUnit,\n };\n};\n\n/**\n * Wraps a numeric rate as a {@link Cost} in `base` units and `USD` currency.\n *\n * Provider calculators pass per-token prices from {@link ModelPricing} here, then scale with\n * {@link multiplyCost} using token counts.\n *\n * @param amount - Rate amount in base USD units (defaults to `0` when omitted).\n * @returns A {@link Cost} with `unit: 'base'` and `currency: 'USD'`.\n * @internal\n */\nexport const rateToCost = (amount: number = 0): Cost => ({\n amount,\n unit: 'base',\n currency: 'USD',\n});\n","import { Cost } from '../types/index.js';\nimport { AiBillingCostError } from '../index.js';\nimport { convertCostUnit } from './convert-cost.js';\n\n/**\n * Scales a {@link Cost} by `multiplier` (for example token count × per-token rate).\n *\n * Converts to {@link CostUnit} `nanos`, multiplies the integer nanos amount (rounded), and returns a\n * {@link Cost} with `unit: 'nanos'` and the same `currency` as the input.\n *\n * @param cost - Base cost to scale.\n * @param multiplier - Factor applied to the nanos amount (often a non-negative token count).\n * @returns The scaled cost in nanos.\n * @internal\n */\nexport const multiplyCost = (cost: Cost, multiplier: number): Cost => {\n const nanosCost = convertCostUnit(cost, 'nanos');\n return {\n ...nanosCost,\n amount: Math.round(nanosCost.amount * multiplier),\n };\n};\n\n/**\n * Adds any number of {@link Cost} values after converting each to nanos.\n *\n * All arguments must share the same `currency`; otherwise throws {@link AiBillingCostError}. With no\n * arguments, returns a zero USD cost in nanos. With a single cost, still normalizes to nanos.\n *\n * @param costs - Costs to sum (variadic).\n * @returns The total as a {@link Cost} with `unit: 'nanos'` and the shared `currency`.\n * @internal\n */\nexport const addCosts = (...costs: Cost[]): Cost => {\n if (costs.length === 0) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const firstCost = costs[0];\n\n if (!firstCost) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const baseCurrency = firstCost.currency;\n\n const totalNanos = costs.reduce((sum, currentCost) => {\n if (currentCost.currency !== baseCurrency) {\n throw new AiBillingCostError({\n message: `Currency mismatch: Cannot add ${baseCurrency} to ${currentCost.currency}`,\n });\n }\n return sum + convertCostUnit(currentCost, 'nanos').amount;\n }, 0);\n\n return { amount: totalNanos, unit: 'nanos', currency: baseCurrency };\n};\n\n/**\n * Applies a fractional discount to `cost` in nanos: `amount * (1 - discount)`.\n *\n * If `discount` is falsy or `<= 0`, returns `cost` unchanged (same unit and amount). Otherwise converts to\n * nanos, subtracts `round(amount * discount)`, and clamps the result at zero. Typical `discount` values are\n * between `0` and `1` (for example `0.1` for 10% off).\n *\n * @param cost - Original cost.\n * @param discount - Fraction of the nanos amount to remove (not a percentage label).\n * @returns Either the original `cost` or a discounted {@link Cost} in nanos.\n * @internal\n */\nexport const applyDiscount = (cost: Cost, discount: number): Cost => {\n if (!discount || discount <= 0) return cost;\n\n const nanosCost = convertCostUnit(cost, 'nanos');\n const discountAmount = Math.round(nanosCost.amount * discount);\n\n return {\n ...nanosCost,\n amount: Math.max(0, nanosCost.amount - discountAmount),\n };\n};\n","import type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a base price resolver that wraps a handler function.\n * @param handler - The function that resolves model pricing.\n * @returns A price resolver that wraps the handler function.\n */\nexport function createBasePriceResolver(\n handler: (\n context: PriceResolverContext,\n ) => ModelPricing | undefined | Promise<ModelPricing | undefined>,\n): PriceResolver {\n return async (context: PriceResolverContext) => {\n return handler(context);\n };\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\ntype PricingRow = Record<string, number | string>;\ntype PricingEntry = { model_id: string; prices: PricingRow[] };\ntype PricingResponse = PricingEntry[];\n\nfunction rowToModelPricing(row: PricingRow): ModelPricing {\n return {\n promptTokens: row['price_prompt'] as number,\n completionTokens: row['price_completion'] as number,\n ...(row['price_request'] != null && {\n request: row['price_request'] as number,\n }),\n ...(row['price_input_cache_read'] != null && {\n inputCacheReadTokens: row['price_input_cache_read'] as number,\n }),\n ...(row['price_input_cache_write'] != null && {\n inputCacheWriteTokens: row['price_input_cache_write'] as number,\n }),\n ...(row['price_internal_reasoning'] != null && {\n internalReasoningTokens: row['price_internal_reasoning'] as number,\n }),\n ...(row['pricing_discount'] != null && {\n discount: row['pricing_discount'] as number,\n }),\n };\n}\n\n/**\n * Configuration for {@link createNarevPriceResolver}.\n */\nexport type NarevPriceResolverOptions = {\n /** API key used for authenticated pricing requests. */\n apiKey: string;\n /** Optional base URL for the Narev API. */\n apiUrl?: string;\n};\n\n/**\n * Creates a price resolver that fetches model pricing from the Narev API.\n *\n * @param options - Resolver options; see {@link NarevPriceResolverOptions}.\n * @returns A base price resolver that resolves model pricing from Narev.\n */\nexport function createNarevPriceResolver(\n options: NarevPriceResolverOptions,\n): PriceResolver {\n const { apiKey, apiUrl = 'https://narev.ai' } = options;\n\n return createBasePriceResolver(\n async ({\n modelId,\n providerId,\n subProvider,\n }: PriceResolverContext): Promise<ModelPricing | undefined> => {\n const params = new URLSearchParams({ model_id: modelId });\n if (providerId) params.set('provider', providerId);\n if (subProvider) params.set('subprovider', subProvider);\n\n const url = `${apiUrl}/api/models/pricing?${params}`;\n const headers: Record<string, string> = apiKey\n ? { Authorization: `Bearer ${apiKey}` }\n : {};\n\n let data: PricingResponse | null;\n try {\n const res = await fetch(url, { headers });\n if (!res.ok) return undefined;\n data = (await res.json()) as PricingResponse | null;\n } catch {\n return undefined;\n }\n\n if (!data) return undefined;\n\n const entry = data.find(e => e.model_id === modelId);\n const row = entry?.prices?.[0];\n if (!row) return undefined;\n\n return rowToModelPricing(row);\n },\n );\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a price resolver that uses a static pricing map.\n * @param pricingMap - A mapping of model IDs to model pricing.\n * @returns A price resolver that uses the static pricing map.\n */\nexport function createObjectPriceResolver(\n pricingMap: Record<string, ModelPricing>,\n): PriceResolver {\n return createBasePriceResolver(({ modelId }: PriceResolverContext) => {\n return pricingMap[modelId];\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,SAAS,aAAa,OAA8C;AACzE,SAAO;AACT;;;ACCO,SAAS,mBACd,OACe;AACf,QAAM,IAAI,MAAM,SAAS,CAAC;AAG1B,QAAM,aAA4B;AAAA,IAChC,eAAe,MAAM;AAAA,IACrB,UAAU,MAAM;AAAA,IAChB,UAAU,MAAM;AAAA,EAClB;AAEA,QAAM,cAAc,CAClB,KACA,UACG;AACH,QAAI,UAAU,UAAa,UAAU,MAAM;AACzC,iBAAW,GAAG,IAAI;AAAA,IACpB;AAAA,EACF;AAEA,cAAY,gBAAgB,EAAE,WAAW;AACzC,cAAY,gBAAgB,EAAE,WAAW;AACzC,cAAY,iBAAiB,EAAE,YAAY;AAC3C,cAAY,gBAAgB,EAAE,WAAW;AACzC,cAAY,oBAAoB,EAAE,eAAe;AACjD,cAAY,qBAAqB,EAAE,eAAe;AAClD,cAAY,sBAAsB,EAAE,gBAAgB;AACpD,cAAY,iBAAiB,EAAE,YAAY;AAC3C,cAAY,qBAAqB,EAAE,eAAe;AAClD,cAAY,+BAA+B,EAAE,wBAAwB;AAErE,MAAI,MAAM,MAAM;AACd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,IAAI,GAAG;AACrD,UAAI,SAAS,KAAM;AACnB,iBAAW,OAAO,GAAG,EAAE,IACrB,OAAO,UAAU,WACb,KAAK,UAAU,KAAK,IACnB;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;ACPO,SAAS,0BAEd,SAAuE;AACvE,QAAM,EAAE,YAAY,cAAc,aAAa,WAAW,QAAQ,IAAI;AAEtE,QAAM,eAAe,OAAO;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,MAM2C;AACzC,QAAI;AACF,YAAM,cAAc,OAAO,kBAAkB,iBAAiB;AAE9D,YAAM,OAAO;AAAA,QACX,GAAI,eAAe,CAAC;AAAA,QACpB,GAAI,eAAe,CAAC;AAAA,MACtB;AAEA,YAAM,QAAQ,MAAM,WAAW;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,SAAS,gBAAgB,cAAc,SAAS,GAAG;AACrD,cAAM,8BAA8B,QAAQ;AAAA,UAC1C,aAAa,IAAI,OAAK,QAAQ,QAAQ,EAAE,KAAK,CAAC,CAAC;AAAA,QACjD;AACA,YAAI,UAAW,WAAU,2BAA2B;AAAA,MACtD;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,QAAS,SAAQ,GAAG;AAAA,UACnB,SAAQ,MAAM,4BAA4B,GAAG;AAClD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,sBAAsB;AAAA,IAEtB,cAAc,OAAO,EAAE,YAAY,OAAO,OAAO,MAAM;AACrD,YAAM,SAAwC,MAAM,WAAW;AAE/D,YAAM,QAAQ,MAAM,aAAa;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,OAAO,OAAO;AAAA,QACd,kBAAkB,OAAO;AAAA,QACzB,YAAY,OAAO,UAAU;AAAA,MAC/B,CAAC;AAED,YAAM,8BAA8B;AAAA,QAClC,GAAG,OAAO;AAAA,MACZ;AAEA,UAAI,OAAO;AACT,oCAA4B,YAAY,IAAI,aAAa,KAAK;AAAA,MAChE;AAEA,aAAO;AAAA,QACL,GAAG;AAAA,QACH,kBAAkB;AAAA,MACpB;AAAA,IACF;AAAA,IAEA,YAAY,OAAO,EAAE,UAAU,OAAO,OAAO,MAAM;AACjD,YAAM,EAAE,QAAQ,GAAG,KAAK,IAAI,MAAM,SAAS;AAE3C,UAAI;AACJ,UAAI;AACJ,UAAI;AACJ,UAAI;AAIJ,YAAM,eAAe,OAAO;AAAA,QAC1B,IAAI,gBAGF;AAAA,UACA,UAAU,OAAO,YAAY;AAC3B,gBAAI,MAAM,SAAS,aAAc,cAAa,MAAM;AACpD,gBAAI,MAAM,SAAS,uBAAuB,CAAC,YAAY;AACrD,2BAAa,MAAM;AAAA,YACrB;AACA,gBAAI,MAAM,SAAS,UAAU;AAC3B,sBAAQ,MAAM;AACd,iCAAmB,MAAM;AACzB,4BAAc;AACd;AAAA,YACF;AACA,uBAAW,QAAQ,KAAK;AAAA,UAC1B;AAAA,UACA,MAAM,MAAM,YAAY;AACtB,kBAAM,QAAQ,MAAM,aAAa;AAAA,cAC/B;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF,CAAC;AAED,kBAAM,8BAA8B;AAAA,cAClC,GAAG;AAAA,YACL;AAEA,gBAAI,OAAO;AACT,0CAA4B,YAAY,IAAI,aAAa,KAAK;AAAA,YAChE;AAEA,gBAAI,aAAa;AACf,yBAAW,QAAQ;AAAA,gBACjB,GAAG;AAAA,gBACH,kBAAkB;AAAA,cACpB,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO,EAAE,GAAG,MAAM,QAAQ,aAAa;AAAA,IACzC;AAAA,EACF;AACF;;;ACrLA,IAAM,SAAS;AACf,IAAM,SAAS,OAAO,IAAI,MAAM;AAGzB,IAAM,iBAAN,MAAM,wBAAuB,MAAM;AAAA,EACxC,CAAkB,MAAM,IAAI;AAAA,EAEnB;AAAA,EAET,YAAY;AAAA,IACV,MAAAA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,UAAM,OAAO;AACb,SAAK,OAAOA;AACZ,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,OAAO,WAAW,OAAyC;AACzD,WAAO,gBAAe,UAAU,OAAO,MAAM;AAAA,EAC/C;AAAA,EAEA,OAAiB,UAAU,OAAgB,cAA+B;AACxE,UAAM,eAAe,OAAO,IAAI,YAAY;AAC5C,WACE,SAAS,QACT,OAAO,UAAU,YACjB,gBAAgB,SAChB,OAAO,MAAM,YAAY,MAAM,aAC/B,MAAM,YAAY,MAAM;AAAA,EAE5B;AACF;;;ACnCA,IAAM,OAAO;AACb,IAAMC,UAAS,oBAAoB,IAAI;AACvC,IAAMC,UAAS,OAAO,IAAID,OAAM;AAGzB,IAAM,0BAAN,cAAsC,eAAe;AAAA,EAC1D,CAAkBC,OAAM,IAAI;AAAA,EAE5B,YAAY;AAAA,IACV,UAAU;AAAA,IACV;AAAA,EACF,GAGG;AACD,UAAM,EAAE,MAAM,SAAS,MAAM,CAAC;AAAA,EAChC;AAAA,EAEA,OAAO,WAAW,OAAkD;AAClE,WAAO,eAAe,UAAU,OAAOD,OAAM;AAAA,EAC/C;AACF;;;ACrBA,IAAME,QAAO;AACb,IAAMC,UAAS,oBAAoBD,KAAI;AACvC,IAAME,UAAS,OAAO,IAAID,OAAM;AAKzB,IAAM,4BAAN,cAAwC,eAAe;AAAA,EAC5D,CAAkBC,OAAM,IAAI;AAAA;AAAA,EAGnB;AAAA,EAET,YAAY;AAAA,IACV;AAAA,IACA,UAAU,oDAAoD,aAAa;AAAA,IAC3E;AAAA,EACF,GAIG;AACD,UAAM,EAAE,MAAAF,OAAM,SAAS,MAAM,CAAC;AAC9B,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,OAAO,WAAW,OAAoD;AACpE,WAAO,eAAe,UAAU,OAAOC,OAAM;AAAA,EAC/C;AACF;;;AC7BA,IAAME,QAAO;AACb,IAAMC,UAAS,oBAAoBD,KAAI;AACvC,IAAME,UAAS,OAAO,IAAID,OAAM;AAGzB,IAAM,qBAAN,cAAiC,eAAe;AAAA,EACrD,CAAkBC,OAAM,IAAI;AAAA,EAE5B,YAAY,EAAE,SAAS,MAAM,GAAyC;AACpE,UAAM,EAAE,MAAAF,OAAM,SAAS,MAAM,CAAC;AAAA,EAChC;AAAA,EAEA,OAAO,WAAW,OAA6C;AAC7D,WAAO,eAAe,UAAU,OAAOC,OAAM;AAAA,EAC/C;AACF;;;ACPO,SAAS,kBACd,eACA,SACoB;AACpB,SAAO,OAAO,UAA+B;AAC3C,QAAI;AACF,YAAM,QAAQ,KAAK;AAAA,IACrB,SAAS,OAAO;AACd,YAAM,IAAI,0BAA0B;AAAA,QAClC;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AChBO,SAAS,qBAEQ;AACtB,SAAO,kBAAyB,kBAAkB,WAAS;AACzD,YAAQ,IAAI,OAAO;AAAA,MACjB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH,CAAC;AACH;;;ACfA,IAAM,WAAW,CAAC,SAAuB;AACvC,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,SAAS,GAAa;AAAA,IAC/C,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,SAAS,GAAU;AAAA,IAC5C,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,SAAS,GAAK;AAAA,IACvC,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,MAAM;AAAA,IAC/B;AACE,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,8CAA8C,OAAO,KAAK,IAAI,CAAC;AAAA,MAC1E,CAAC;AAAA,EACL;AACF;AAaO,IAAM,eAAe,CAAC,MAAY,eAAiC;AACxE,QAAM,QAAQ,SAAS,IAAI;AAE3B,MAAI,eAAe,QAAS,QAAO;AACnC,MAAI,eAAe,SAAU,QAAO,QAAQ;AAC5C,MAAI,eAAe,QAAS,QAAO,QAAQ;AAC3C,SAAO,QAAQ;AACjB;AAYO,IAAM,kBAAkB,CAAC,MAAY,eAA+B;AACzE,SAAO;AAAA,IACL,QAAQ,aAAa,MAAM,UAAU;AAAA,IACrC,UAAU,KAAK;AAAA,IACf,MAAM;AAAA,EACR;AACF;AAYO,IAAM,aAAa,CAAC,SAAiB,OAAa;AAAA,EACvD;AAAA,EACA,MAAM;AAAA,EACN,UAAU;AACZ;;;ACzDO,IAAM,eAAe,CAAC,MAAY,eAA6B;AACpE,QAAM,YAAY,gBAAgB,MAAM,OAAO;AAC/C,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,KAAK,MAAM,UAAU,SAAS,UAAU;AAAA,EAClD;AACF;AAYO,IAAM,WAAW,IAAI,UAAwB;AAClD,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,EAAE,QAAQ,GAAG,MAAM,SAAS,UAAU,MAAM;AAAA,EACrD;AAEA,QAAM,YAAY,MAAM,CAAC;AAEzB,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,QAAQ,GAAG,MAAM,SAAS,UAAU,MAAM;AAAA,EACrD;AAEA,QAAM,eAAe,UAAU;AAE/B,QAAM,aAAa,MAAM,OAAO,CAAC,KAAK,gBAAgB;AACpD,QAAI,YAAY,aAAa,cAAc;AACzC,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,iCAAiC,YAAY,OAAO,YAAY,QAAQ;AAAA,MACnF,CAAC;AAAA,IACH;AACA,WAAO,MAAM,gBAAgB,aAAa,OAAO,EAAE;AAAA,EACrD,GAAG,CAAC;AAEJ,SAAO,EAAE,QAAQ,YAAY,MAAM,SAAS,UAAU,aAAa;AACrE;AAcO,IAAM,gBAAgB,CAAC,MAAY,aAA2B;AACnE,MAAI,CAAC,YAAY,YAAY,EAAG,QAAO;AAEvC,QAAM,YAAY,gBAAgB,MAAM,OAAO;AAC/C,QAAM,iBAAiB,KAAK,MAAM,UAAU,SAAS,QAAQ;AAE7D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,KAAK,IAAI,GAAG,UAAU,SAAS,cAAc;AAAA,EACvD;AACF;;;ACrEO,SAAS,wBACd,SAGe;AACf,SAAO,OAAO,YAAkC;AAC9C,WAAO,QAAQ,OAAO;AAAA,EACxB;AACF;;;ACRA,SAAS,kBAAkB,KAA+B;AACxD,SAAO;AAAA,IACL,cAAc,IAAI,cAAc;AAAA,IAChC,kBAAkB,IAAI,kBAAkB;AAAA,IACxC,GAAI,IAAI,eAAe,KAAK,QAAQ;AAAA,MAClC,SAAS,IAAI,eAAe;AAAA,IAC9B;AAAA,IACA,GAAI,IAAI,wBAAwB,KAAK,QAAQ;AAAA,MAC3C,sBAAsB,IAAI,wBAAwB;AAAA,IACpD;AAAA,IACA,GAAI,IAAI,yBAAyB,KAAK,QAAQ;AAAA,MAC5C,uBAAuB,IAAI,yBAAyB;AAAA,IACtD;AAAA,IACA,GAAI,IAAI,0BAA0B,KAAK,QAAQ;AAAA,MAC7C,yBAAyB,IAAI,0BAA0B;AAAA,IACzD;AAAA,IACA,GAAI,IAAI,kBAAkB,KAAK,QAAQ;AAAA,MACrC,UAAU,IAAI,kBAAkB;AAAA,IAClC;AAAA,EACF;AACF;AAkBO,SAAS,yBACd,SACe;AACf,QAAM,EAAE,QAAQ,SAAS,mBAAmB,IAAI;AAEhD,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAA+D;AAC7D,YAAM,SAAS,IAAI,gBAAgB,EAAE,UAAU,QAAQ,CAAC;AACxD,UAAI,WAAY,QAAO,IAAI,YAAY,UAAU;AACjD,UAAI,YAAa,QAAO,IAAI,eAAe,WAAW;AAEtD,YAAM,MAAM,GAAG,MAAM,uBAAuB,MAAM;AAClD,YAAM,UAAkC,SACpC,EAAE,eAAe,UAAU,MAAM,GAAG,IACpC,CAAC;AAEL,UAAI;AACJ,UAAI;AACF,cAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,CAAC;AACxC,YAAI,CAAC,IAAI,GAAI,QAAO;AACpB,eAAQ,MAAM,IAAI,KAAK;AAAA,MACzB,QAAQ;AACN,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,KAAM,QAAO;AAElB,YAAM,QAAQ,KAAK,KAAK,OAAK,EAAE,aAAa,OAAO;AACnD,YAAM,MAAM,OAAO,SAAS,CAAC;AAC7B,UAAI,CAAC,IAAK,QAAO;AAEjB,aAAO,kBAAkB,GAAG;AAAA,IAC9B;AAAA,EACF;AACF;;;AC3EO,SAAS,0BACd,YACe;AACf,SAAO,wBAAwB,CAAC,EAAE,QAAQ,MAA4B;AACpE,WAAO,WAAW,OAAO;AAAA,EAC3B,CAAC;AACH;","names":["name","marker","symbol","name","marker","symbol","name","marker","symbol"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/event/to-json-object.ts","../src/event/to-meter-metadata.ts","../src/ai-sdk/language-model-middleware/v3/language-model-v3-base-billing-middleware.ts","../src/error/ai-billing-error.ts","../src/error/extractor-error.ts","../src/error/destination-error.ts","../src/error/cost-error.ts","../src/destination/base-destination.ts","../src/destination/console-destination.ts","../src/cost/convert-cost.ts","../src/cost/op-cost.ts","../src/pricing/base-price-resolver.ts","../src/pricing/narev-price-resolver.ts","../src/pricing/object-price-resolver.ts","../src/utils/to-usage.ts"],"sourcesContent":["export * from './types/index.js';\nexport * from './ai-sdk/index.js';\nexport * from './destination/index.js';\nexport * from './error/index.js';\nexport * from './cost/index.js';\nexport * from './pricing/index.js';\nexport * from './event/index.js';\nexport * from './utils/index.js';\n","import { DefaultTags, BillingEvent } from '../types/index.js';\nimport type { JSONObject } from '@ai-sdk/provider';\n\n/**\n * Casts a billing event into a JSON object payload.\n * @param event - The billing event to cast.\n * @returns The billing event represented as a JSON object.\n */\nexport function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject {\n return event as unknown as JSONObject;\n}\n","import type {\n BillingEvent,\n DefaultTags,\n MeterMetadata,\n} from '../types/index.js';\n\n/**\n * Converts a billing event into a meter metadata object.\n * @param event - The billing event to convert.\n * @returns The meter metadata object.\n */\nexport function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(\n event: BillingEvent<TTags>,\n): MeterMetadata {\n const u = event.usage ?? {};\n\n // Initialize with required fields\n const dimensions: MeterMetadata = {\n generation_id: event.generationId,\n model_id: event.modelId,\n provider: event.provider,\n };\n\n const addOptional = <K extends keyof MeterMetadata>(\n key: K,\n value: MeterMetadata[K],\n ) => {\n if (value !== undefined && value !== null) {\n dimensions[key] = value;\n }\n };\n\n addOptional('sub_provider', u.subProvider);\n addOptional('input_tokens', u.inputTokens);\n addOptional('output_tokens', u.outputTokens);\n addOptional('reasoning_tokens', u.reasoningTokens);\n addOptional('cache_read_tokens', u.cacheReadTokens);\n addOptional('cache_write_tokens', u.cacheWriteTokens);\n addOptional('request_count', u.requestCount);\n addOptional('web_search_count', u.webSearchCount);\n addOptional('raw_provider_cost', u.rawProviderCost);\n addOptional('raw_upstream_inference_cost', u.rawUpstreamInferenceCost);\n\n if (event.tags) {\n for (const [key, value] of Object.entries(event.tags)) {\n if (value == null) continue;\n dimensions[`tag_${key}`] =\n typeof value === 'object'\n ? JSON.stringify(value)\n : (value as string | number);\n }\n }\n\n return dimensions;\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Usage,\n LanguageModelV3GenerateResult,\n LanguageModelV3StreamPart,\n LanguageModelV3Middleware,\n SharedV3ProviderMetadata,\n} from '@ai-sdk/provider';\nimport type {\n BaseBillingMiddlewareOptions,\n EventBuilder,\n BillingEvent,\n DefaultTags,\n} from '../../../types/index.js';\nimport { toJSONObject } from '../../../event/index.js';\n\nexport interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {\n responseId: string | undefined;\n model: LanguageModelV3;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n tags: TTags;\n webSearchCount: number;\n}\n\n/**\n * Configuration for {@link createV3BillingMiddleware}.\n *\n * Extends {@link BaseBillingMiddlewareOptions} (`destinations`, `defaultTags`, `waitUntil`, `onError`) and\n * requires an {@link EventBuilder} to construct the {@link BillingEvent}.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n */\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n /** Builds a billing event from the model response data. */\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\n\n/**\n * Creates a billing middleware for the Language Model V3 API.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n * @param options - Billing options; see {@link BillingMiddlewareV3Options}.\n * @returns The billing middleware.\n */\nexport function createV3BillingMiddleware<\n TTags extends DefaultTags = DefaultTags,\n>(options: BillingMiddlewareV3Options<TTags>): LanguageModelV3Middleware {\n const { buildEvent, destinations, defaultTags, waitUntil, onError } = options;\n\n const processEvent = async ({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n webSearchCount,\n }: {\n model: LanguageModelV3;\n params: LanguageModelV3CallOptions;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n responseId: string | undefined;\n webSearchCount: number;\n }): Promise<BillingEvent<TTags> | null> => {\n try {\n const requestTags = params.providerOptions?.['ai-billing-tags'];\n\n const tags = {\n ...(defaultTags ?? {}),\n ...(requestTags ?? {}),\n } as TTags;\n\n const event = await buildEvent({\n responseId,\n model,\n usage,\n providerMetadata,\n tags,\n webSearchCount,\n });\n\n if (event && destinations && destinations?.length > 0) {\n const dispatchDestinationsPromise = Promise.allSettled(\n destinations.map(d => Promise.resolve(d(event))),\n );\n if (waitUntil) waitUntil(dispatchDestinationsPromise);\n }\n return event;\n } catch (err) {\n if (onError) onError(err);\n else console.error('[ai-billing] Core Error:', err);\n return null;\n }\n };\n\n return {\n specificationVersion: 'v3',\n\n wrapGenerate: async ({ doGenerate, model, params }) => {\n const result: LanguageModelV3GenerateResult = await doGenerate();\n\n const webSearchCount = result.content.filter(\n c => c.type === 'source',\n ).length;\n\n const event = await processEvent({\n model,\n params,\n usage: result.usage,\n providerMetadata: result.providerMetadata,\n responseId: result.response?.id,\n webSearchCount,\n });\n\n const providerMetadataWithBilling = {\n ...result.providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n return {\n ...result,\n providerMetadata: providerMetadataWithBilling,\n };\n },\n\n wrapStream: async ({ doStream, model, params }) => {\n const { stream, ...rest } = await doStream();\n\n let responseId: string | undefined;\n let usage: LanguageModelV3Usage | undefined;\n let providerMetadata: SharedV3ProviderMetadata | undefined;\n let finishChunk:\n | Extract<LanguageModelV3StreamPart, { type: 'finish' }>\n | undefined;\n let webSearchCount = 0;\n\n const billedStream = stream.pipeThrough(\n new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform(chunk, controller) {\n if (chunk.type === 'text-start') responseId = chunk.id;\n if (chunk.type === 'response-metadata' && !responseId) {\n responseId = chunk.id;\n }\n if (chunk.type === 'source') {\n webSearchCount++;\n }\n if (chunk.type === 'finish') {\n usage = chunk.usage;\n providerMetadata = chunk.providerMetadata;\n finishChunk = chunk;\n return; // held until flush\n }\n controller.enqueue(chunk);\n },\n async flush(controller) {\n const event = await processEvent({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n webSearchCount,\n });\n\n const providerMetadataWithBilling = {\n ...providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n if (finishChunk) {\n controller.enqueue({\n ...finishChunk,\n providerMetadata: providerMetadataWithBilling,\n });\n }\n },\n }),\n );\n\n return { ...rest, stream: billedStream };\n },\n };\n}\n","const marker = 'ai-billing.error';\nconst symbol = Symbol.for(marker);\n\n/** Base error type for all ai-billing package errors. */\nexport class AIBillingError extends Error {\n private readonly [symbol] = true;\n\n readonly cause?: unknown;\n\n constructor({\n name,\n message,\n cause,\n }: {\n name: string;\n message: string;\n cause?: unknown;\n }) {\n super(message);\n this.name = name;\n this.cause = cause;\n }\n\n static isInstance(error: unknown): error is AIBillingError {\n return AIBillingError.hasMarker(error, marker);\n }\n\n protected static hasMarker(error: unknown, markerString: string): boolean {\n const markerSymbol = Symbol.for(markerString);\n return (\n error != null &&\n typeof error === 'object' &&\n markerSymbol in error &&\n typeof error[markerSymbol] === 'boolean' &&\n error[markerSymbol] === true\n );\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingExtractorError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when billing data extraction fails. */\nexport class AiBillingExtractorError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({\n message = `Failed to extract billing data.`,\n cause,\n }: {\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingExtractorError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingDestinationError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Error raised when billing data processing fails for a destination.\n */\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\n /** The ID of the destination that failed to process billing data. */\n readonly destinationId?: string;\n\n constructor({\n destinationId,\n message = `Failed to process billing data for destination: '${destinationId}'.`,\n cause,\n }: {\n destinationId?: string;\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n this.destinationId = destinationId;\n }\n\n static isInstance(error: unknown): error is AiBillingDestinationError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingCostError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when a cost conversion or calculation fails. */\nexport class AiBillingCostError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({ message, cause }: { message: string; cause?: unknown }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingCostError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import type { Destination, BillingEvent, DefaultTags } from '../types/index.js';\nimport { AiBillingDestinationError } from '../error/index.js';\n\n/**\n * Creates a destination wrapper that normalizes destination handler errors.\n *\n * @param destinationId - Unique identifier for the destination.\n * @param handler - Destination implementation invoked for each billing event.\n * @returns A destination function that wraps thrown errors as AiBillingDestinationError.\n */\nexport function createDestination<TTags extends DefaultTags = DefaultTags>(\n destinationId: string,\n handler: (event: BillingEvent<TTags>) => Promise<void> | void,\n): Destination<TTags> {\n return async (event: BillingEvent<TTags>) => {\n try {\n await handler(event);\n } catch (error) {\n throw new AiBillingDestinationError({\n destinationId,\n cause: error,\n });\n }\n };\n}\n","import { createDestination } from './base-destination.js';\nimport type { DefaultTags, Destination } from '../types/index.js';\n\n/**\n * Creates a destination that logs billing events to the console.\n *\n * @returns A destination that prints each event with full depth formatting.\n */\nexport function consoleDestination<\n TTags extends DefaultTags = DefaultTags,\n>(): Destination<TTags> {\n return createDestination<TTags>('console-logger', event => {\n console.dir(event, {\n depth: null,\n colors: true,\n compact: false,\n });\n });\n}\n","import { AiBillingCostError } from '../index.js';\nimport type { Cost, CostUnit } from '../index.js';\n\nconst getNanos = (cost: Cost): number => {\n switch (cost.unit) {\n case 'base':\n return Math.round(cost.amount * 1_000_000_000);\n case 'cents':\n return Math.round(cost.amount * 10_000_000);\n case 'micros':\n return Math.round(cost.amount * 1_000);\n case 'nanos':\n return Math.round(cost.amount);\n default:\n throw new AiBillingCostError({\n message: `Failed to process cost. Unknown CostUnit: '${String(cost.unit)}'.`,\n });\n }\n};\n\n/**\n * Returns the numeric amount of `cost` expressed in `targetUnit`.\n *\n * Values are converted via an integer nanos intermediate so fractional `base` / `cents` / `micros` amounts\n * round consistently. Throws {@link AiBillingCostError} when `cost.unit` is not a known {@link CostUnit}.\n *\n * @param cost - Source {@link Cost} (amount + unit + currency).\n * @param targetUnit - Unit for the returned number (same scale as {@link Cost} amounts for that unit).\n * @returns The amount in `targetUnit`; for `nanos` this is a whole number of nanos.\n * @internal\n */\nexport const costToNumber = (cost: Cost, targetUnit: CostUnit): number => {\n const nanos = getNanos(cost);\n\n if (targetUnit === 'nanos') return nanos;\n if (targetUnit === 'micros') return nanos / 1_000;\n if (targetUnit === 'cents') return nanos / 10_000_000;\n return nanos / 1_000_000_000; // base\n};\n\n/**\n * Converts a {@link Cost} to the same amount in a different {@link CostUnit}, preserving `currency`.\n *\n * Implemented with {@link costToNumber}; the result is always a new object.\n *\n * @param cost - Source cost.\n * @param targetUnit - Desired unit for `amount` on the returned object.\n * @returns A new {@link Cost} with `unit: targetUnit` and `amount` in that unit's scale.\n * @internal\n */\nexport const convertCostUnit = (cost: Cost, targetUnit: CostUnit): Cost => {\n return {\n amount: costToNumber(cost, targetUnit),\n currency: cost.currency,\n unit: targetUnit,\n };\n};\n\n/**\n * Wraps a numeric rate as a {@link Cost} in `base` units and `USD` currency.\n *\n * Provider calculators pass per-token prices from {@link ModelPricing} here, then scale with\n * {@link multiplyCost} using token counts.\n *\n * @param amount - Rate amount in base USD units (defaults to `0` when omitted).\n * @returns A {@link Cost} with `unit: 'base'` and `currency: 'USD'`.\n * @internal\n */\nexport const rateToCost = (amount: number = 0): Cost => ({\n amount,\n unit: 'base',\n currency: 'USD',\n});\n","import { Cost } from '../types/index.js';\nimport { AiBillingCostError } from '../index.js';\nimport { convertCostUnit } from './convert-cost.js';\n\n/**\n * Scales a {@link Cost} by `multiplier` (for example token count × per-token rate).\n *\n * Converts to {@link CostUnit} `nanos`, multiplies the integer nanos amount (rounded), and returns a\n * {@link Cost} with `unit: 'nanos'` and the same `currency` as the input.\n *\n * @param cost - Base cost to scale.\n * @param multiplier - Factor applied to the nanos amount (often a non-negative token count).\n * @returns The scaled cost in nanos.\n * @internal\n */\nexport const multiplyCost = (cost: Cost, multiplier: number): Cost => {\n const nanosCost = convertCostUnit(cost, 'nanos');\n return {\n ...nanosCost,\n amount: Math.round(nanosCost.amount * multiplier),\n };\n};\n\n/**\n * Adds any number of {@link Cost} values after converting each to nanos.\n *\n * All arguments must share the same `currency`; otherwise throws {@link AiBillingCostError}. With no\n * arguments, returns a zero USD cost in nanos. With a single cost, still normalizes to nanos.\n *\n * @param costs - Costs to sum (variadic).\n * @returns The total as a {@link Cost} with `unit: 'nanos'` and the shared `currency`.\n * @internal\n */\nexport const addCosts = (...costs: Cost[]): Cost => {\n if (costs.length === 0) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const firstCost = costs[0];\n\n if (!firstCost) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const baseCurrency = firstCost.currency;\n\n const totalNanos = costs.reduce((sum, currentCost) => {\n if (currentCost.currency !== baseCurrency) {\n throw new AiBillingCostError({\n message: `Currency mismatch: Cannot add ${baseCurrency} to ${currentCost.currency}`,\n });\n }\n return sum + convertCostUnit(currentCost, 'nanos').amount;\n }, 0);\n\n return { amount: totalNanos, unit: 'nanos', currency: baseCurrency };\n};\n\n/**\n * Applies a fractional discount to `cost` in nanos: `amount * (1 - discount)`.\n *\n * If `discount` is falsy or `<= 0`, returns `cost` unchanged (same unit and amount). Otherwise converts to\n * nanos, subtracts `round(amount * discount)`, and clamps the result at zero. Typical `discount` values are\n * between `0` and `1` (for example `0.1` for 10% off).\n *\n * @param cost - Original cost.\n * @param discount - Fraction of the nanos amount to remove (not a percentage label).\n * @returns Either the original `cost` or a discounted {@link Cost} in nanos.\n * @internal\n */\nexport const applyDiscount = (cost: Cost, discount: number): Cost => {\n if (!discount || discount <= 0) return cost;\n\n const nanosCost = convertCostUnit(cost, 'nanos');\n const discountAmount = Math.round(nanosCost.amount * discount);\n\n return {\n ...nanosCost,\n amount: Math.max(0, nanosCost.amount - discountAmount),\n };\n};\n","import type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a base price resolver that wraps a handler function.\n * @param handler - The function that resolves model pricing.\n * @returns A price resolver that wraps the handler function.\n */\nexport function createBasePriceResolver(\n handler: (\n context: PriceResolverContext,\n ) => ModelPricing | undefined | Promise<ModelPricing | undefined>,\n): PriceResolver {\n return async (context: PriceResolverContext) => {\n return handler(context);\n };\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\ntype PricingRow = Record<string, number | string>;\ntype PricingEntry = { model_id: string; prices: PricingRow[] };\ntype PricingResponse = PricingEntry[];\n\nfunction rowToModelPricing(row: PricingRow): ModelPricing {\n return {\n promptTokens: row['price_prompt'] as number,\n completionTokens: row['price_completion'] as number,\n ...(row['price_request'] != null && {\n request: row['price_request'] as number,\n }),\n ...(row['price_input_cache_read'] != null && {\n inputCacheReadTokens: row['price_input_cache_read'] as number,\n }),\n ...(row['price_input_cache_write'] != null && {\n inputCacheWriteTokens: row['price_input_cache_write'] as number,\n }),\n ...(row['price_internal_reasoning'] != null && {\n internalReasoningTokens: row['price_internal_reasoning'] as number,\n }),\n ...(row['pricing_discount'] != null && {\n discount: row['pricing_discount'] as number,\n }),\n };\n}\n\n/**\n * Configuration for {@link createNarevPriceResolver}.\n */\nexport type NarevPriceResolverOptions = {\n /** API key used for authenticated pricing requests. */\n apiKey: string;\n /** Optional base URL for the Narev API. */\n apiUrl?: string;\n};\n\n/**\n * Creates a price resolver that fetches model pricing from the Narev API.\n *\n * @param options - Resolver options; see {@link NarevPriceResolverOptions}.\n * @returns A base price resolver that resolves model pricing from Narev.\n */\nexport function createNarevPriceResolver(\n options: NarevPriceResolverOptions,\n): PriceResolver {\n const { apiKey, apiUrl = 'https://narev.ai' } = options;\n\n return createBasePriceResolver(\n async ({\n modelId,\n providerId,\n subProvider,\n }: PriceResolverContext): Promise<ModelPricing | undefined> => {\n const params = new URLSearchParams({ model_id: modelId });\n if (providerId) params.set('provider', providerId);\n if (subProvider) params.set('subprovider', subProvider);\n\n const url = `${apiUrl}/api/models/pricing?${params}`;\n const headers: Record<string, string> = apiKey\n ? { Authorization: `Bearer ${apiKey}` }\n : {};\n\n let data: PricingResponse | null;\n try {\n const res = await fetch(url, { headers });\n if (!res.ok) return undefined;\n data = (await res.json()) as PricingResponse | null;\n } catch {\n return undefined;\n }\n\n if (!data) return undefined;\n\n const entry = data.find(e => e.model_id === modelId);\n const row = entry?.prices?.[0];\n if (!row) return undefined;\n\n return rowToModelPricing(row);\n },\n );\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a price resolver that uses a static pricing map.\n * @param pricingMap - A mapping of model IDs to model pricing.\n * @returns A price resolver that uses the static pricing map.\n */\nexport function createObjectPriceResolver(\n pricingMap: Record<string, ModelPricing>,\n): PriceResolver {\n return createBasePriceResolver(({ modelId }: PriceResolverContext) => {\n return pricingMap[modelId];\n });\n}\n","import type { CostInputs, Usage } from '../types/index.js';\n\n/** Maps {@link CostInputs} token counts to a {@link Usage} object. */\nexport function toUsage(inputs: CostInputs): Usage {\n return {\n inputTokens: inputs.promptTokens,\n outputTokens: inputs.completionTokens,\n cacheReadTokens: inputs.cacheReadTokens,\n cacheWriteTokens: inputs.cacheWriteTokens,\n reasoningTokens: inputs.reasoningTokens,\n webSearchCount: inputs.webSearchCount,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,SAAS,aAAa,OAA8C;AACzE,SAAO;AACT;;;ACCO,SAAS,mBACd,OACe;AACf,QAAM,IAAI,MAAM,SAAS,CAAC;AAG1B,QAAM,aAA4B;AAAA,IAChC,eAAe,MAAM;AAAA,IACrB,UAAU,MAAM;AAAA,IAChB,UAAU,MAAM;AAAA,EAClB;AAEA,QAAM,cAAc,CAClB,KACA,UACG;AACH,QAAI,UAAU,UAAa,UAAU,MAAM;AACzC,iBAAW,GAAG,IAAI;AAAA,IACpB;AAAA,EACF;AAEA,cAAY,gBAAgB,EAAE,WAAW;AACzC,cAAY,gBAAgB,EAAE,WAAW;AACzC,cAAY,iBAAiB,EAAE,YAAY;AAC3C,cAAY,oBAAoB,EAAE,eAAe;AACjD,cAAY,qBAAqB,EAAE,eAAe;AAClD,cAAY,sBAAsB,EAAE,gBAAgB;AACpD,cAAY,iBAAiB,EAAE,YAAY;AAC3C,cAAY,oBAAoB,EAAE,cAAc;AAChD,cAAY,qBAAqB,EAAE,eAAe;AAClD,cAAY,+BAA+B,EAAE,wBAAwB;AAErE,MAAI,MAAM,MAAM;AACd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,IAAI,GAAG;AACrD,UAAI,SAAS,KAAM;AACnB,iBAAW,OAAO,GAAG,EAAE,IACrB,OAAO,UAAU,WACb,KAAK,UAAU,KAAK,IACnB;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;ACNO,SAAS,0BAEd,SAAuE;AACvE,QAAM,EAAE,YAAY,cAAc,aAAa,WAAW,QAAQ,IAAI;AAEtE,QAAM,eAAe,OAAO;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,MAO2C;AACzC,QAAI;AACF,YAAM,cAAc,OAAO,kBAAkB,iBAAiB;AAE9D,YAAM,OAAO;AAAA,QACX,GAAI,eAAe,CAAC;AAAA,QACpB,GAAI,eAAe,CAAC;AAAA,MACtB;AAEA,YAAM,QAAQ,MAAM,WAAW;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,SAAS,gBAAgB,cAAc,SAAS,GAAG;AACrD,cAAM,8BAA8B,QAAQ;AAAA,UAC1C,aAAa,IAAI,OAAK,QAAQ,QAAQ,EAAE,KAAK,CAAC,CAAC;AAAA,QACjD;AACA,YAAI,UAAW,WAAU,2BAA2B;AAAA,MACtD;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,QAAS,SAAQ,GAAG;AAAA,UACnB,SAAQ,MAAM,4BAA4B,GAAG;AAClD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,sBAAsB;AAAA,IAEtB,cAAc,OAAO,EAAE,YAAY,OAAO,OAAO,MAAM;AACrD,YAAM,SAAwC,MAAM,WAAW;AAE/D,YAAM,iBAAiB,OAAO,QAAQ;AAAA,QACpC,OAAK,EAAE,SAAS;AAAA,MAClB,EAAE;AAEF,YAAM,QAAQ,MAAM,aAAa;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,OAAO,OAAO;AAAA,QACd,kBAAkB,OAAO;AAAA,QACzB,YAAY,OAAO,UAAU;AAAA,QAC7B;AAAA,MACF,CAAC;AAED,YAAM,8BAA8B;AAAA,QAClC,GAAG,OAAO;AAAA,MACZ;AAEA,UAAI,OAAO;AACT,oCAA4B,YAAY,IAAI,aAAa,KAAK;AAAA,MAChE;AAEA,aAAO;AAAA,QACL,GAAG;AAAA,QACH,kBAAkB;AAAA,MACpB;AAAA,IACF;AAAA,IAEA,YAAY,OAAO,EAAE,UAAU,OAAO,OAAO,MAAM;AACjD,YAAM,EAAE,QAAQ,GAAG,KAAK,IAAI,MAAM,SAAS;AAE3C,UAAI;AACJ,UAAI;AACJ,UAAI;AACJ,UAAI;AAGJ,UAAI,iBAAiB;AAErB,YAAM,eAAe,OAAO;AAAA,QAC1B,IAAI,gBAGF;AAAA,UACA,UAAU,OAAO,YAAY;AAC3B,gBAAI,MAAM,SAAS,aAAc,cAAa,MAAM;AACpD,gBAAI,MAAM,SAAS,uBAAuB,CAAC,YAAY;AACrD,2BAAa,MAAM;AAAA,YACrB;AACA,gBAAI,MAAM,SAAS,UAAU;AAC3B;AAAA,YACF;AACA,gBAAI,MAAM,SAAS,UAAU;AAC3B,sBAAQ,MAAM;AACd,iCAAmB,MAAM;AACzB,4BAAc;AACd;AAAA,YACF;AACA,uBAAW,QAAQ,KAAK;AAAA,UAC1B;AAAA,UACA,MAAM,MAAM,YAAY;AACtB,kBAAM,QAAQ,MAAM,aAAa;AAAA,cAC/B;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF,CAAC;AAED,kBAAM,8BAA8B;AAAA,cAClC,GAAG;AAAA,YACL;AAEA,gBAAI,OAAO;AACT,0CAA4B,YAAY,IAAI,aAAa,KAAK;AAAA,YAChE;AAEA,gBAAI,aAAa;AACf,yBAAW,QAAQ;AAAA,gBACjB,GAAG;AAAA,gBACH,kBAAkB;AAAA,cACpB,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO,EAAE,GAAG,MAAM,QAAQ,aAAa;AAAA,IACzC;AAAA,EACF;AACF;;;ACnMA,IAAM,SAAS;AACf,IAAM,SAAS,OAAO,IAAI,MAAM;AAGzB,IAAM,iBAAN,MAAM,wBAAuB,MAAM;AAAA,EACxC,CAAkB,MAAM,IAAI;AAAA,EAEnB;AAAA,EAET,YAAY;AAAA,IACV,MAAAA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,UAAM,OAAO;AACb,SAAK,OAAOA;AACZ,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,OAAO,WAAW,OAAyC;AACzD,WAAO,gBAAe,UAAU,OAAO,MAAM;AAAA,EAC/C;AAAA,EAEA,OAAiB,UAAU,OAAgB,cAA+B;AACxE,UAAM,eAAe,OAAO,IAAI,YAAY;AAC5C,WACE,SAAS,QACT,OAAO,UAAU,YACjB,gBAAgB,SAChB,OAAO,MAAM,YAAY,MAAM,aAC/B,MAAM,YAAY,MAAM;AAAA,EAE5B;AACF;;;ACnCA,IAAM,OAAO;AACb,IAAMC,UAAS,oBAAoB,IAAI;AACvC,IAAMC,UAAS,OAAO,IAAID,OAAM;AAGzB,IAAM,0BAAN,cAAsC,eAAe;AAAA,EAC1D,CAAkBC,OAAM,IAAI;AAAA,EAE5B,YAAY;AAAA,IACV,UAAU;AAAA,IACV;AAAA,EACF,GAGG;AACD,UAAM,EAAE,MAAM,SAAS,MAAM,CAAC;AAAA,EAChC;AAAA,EAEA,OAAO,WAAW,OAAkD;AAClE,WAAO,eAAe,UAAU,OAAOD,OAAM;AAAA,EAC/C;AACF;;;ACrBA,IAAME,QAAO;AACb,IAAMC,UAAS,oBAAoBD,KAAI;AACvC,IAAME,UAAS,OAAO,IAAID,OAAM;AAKzB,IAAM,4BAAN,cAAwC,eAAe;AAAA,EAC5D,CAAkBC,OAAM,IAAI;AAAA;AAAA,EAGnB;AAAA,EAET,YAAY;AAAA,IACV;AAAA,IACA,UAAU,oDAAoD,aAAa;AAAA,IAC3E;AAAA,EACF,GAIG;AACD,UAAM,EAAE,MAAAF,OAAM,SAAS,MAAM,CAAC;AAC9B,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,OAAO,WAAW,OAAoD;AACpE,WAAO,eAAe,UAAU,OAAOC,OAAM;AAAA,EAC/C;AACF;;;AC7BA,IAAME,QAAO;AACb,IAAMC,UAAS,oBAAoBD,KAAI;AACvC,IAAME,UAAS,OAAO,IAAID,OAAM;AAGzB,IAAM,qBAAN,cAAiC,eAAe;AAAA,EACrD,CAAkBC,OAAM,IAAI;AAAA,EAE5B,YAAY,EAAE,SAAS,MAAM,GAAyC;AACpE,UAAM,EAAE,MAAAF,OAAM,SAAS,MAAM,CAAC;AAAA,EAChC;AAAA,EAEA,OAAO,WAAW,OAA6C;AAC7D,WAAO,eAAe,UAAU,OAAOC,OAAM;AAAA,EAC/C;AACF;;;ACPO,SAAS,kBACd,eACA,SACoB;AACpB,SAAO,OAAO,UAA+B;AAC3C,QAAI;AACF,YAAM,QAAQ,KAAK;AAAA,IACrB,SAAS,OAAO;AACd,YAAM,IAAI,0BAA0B;AAAA,QAClC;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AChBO,SAAS,qBAEQ;AACtB,SAAO,kBAAyB,kBAAkB,WAAS;AACzD,YAAQ,IAAI,OAAO;AAAA,MACjB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH,CAAC;AACH;;;ACfA,IAAM,WAAW,CAAC,SAAuB;AACvC,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,SAAS,GAAa;AAAA,IAC/C,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,SAAS,GAAU;AAAA,IAC5C,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,SAAS,GAAK;AAAA,IACvC,KAAK;AACH,aAAO,KAAK,MAAM,KAAK,MAAM;AAAA,IAC/B;AACE,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,8CAA8C,OAAO,KAAK,IAAI,CAAC;AAAA,MAC1E,CAAC;AAAA,EACL;AACF;AAaO,IAAM,eAAe,CAAC,MAAY,eAAiC;AACxE,QAAM,QAAQ,SAAS,IAAI;AAE3B,MAAI,eAAe,QAAS,QAAO;AACnC,MAAI,eAAe,SAAU,QAAO,QAAQ;AAC5C,MAAI,eAAe,QAAS,QAAO,QAAQ;AAC3C,SAAO,QAAQ;AACjB;AAYO,IAAM,kBAAkB,CAAC,MAAY,eAA+B;AACzE,SAAO;AAAA,IACL,QAAQ,aAAa,MAAM,UAAU;AAAA,IACrC,UAAU,KAAK;AAAA,IACf,MAAM;AAAA,EACR;AACF;AAYO,IAAM,aAAa,CAAC,SAAiB,OAAa;AAAA,EACvD;AAAA,EACA,MAAM;AAAA,EACN,UAAU;AACZ;;;ACzDO,IAAM,eAAe,CAAC,MAAY,eAA6B;AACpE,QAAM,YAAY,gBAAgB,MAAM,OAAO;AAC/C,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,KAAK,MAAM,UAAU,SAAS,UAAU;AAAA,EAClD;AACF;AAYO,IAAM,WAAW,IAAI,UAAwB;AAClD,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,EAAE,QAAQ,GAAG,MAAM,SAAS,UAAU,MAAM;AAAA,EACrD;AAEA,QAAM,YAAY,MAAM,CAAC;AAEzB,MAAI,CAAC,WAAW;AACd,WAAO,EAAE,QAAQ,GAAG,MAAM,SAAS,UAAU,MAAM;AAAA,EACrD;AAEA,QAAM,eAAe,UAAU;AAE/B,QAAM,aAAa,MAAM,OAAO,CAAC,KAAK,gBAAgB;AACpD,QAAI,YAAY,aAAa,cAAc;AACzC,YAAM,IAAI,mBAAmB;AAAA,QAC3B,SAAS,iCAAiC,YAAY,OAAO,YAAY,QAAQ;AAAA,MACnF,CAAC;AAAA,IACH;AACA,WAAO,MAAM,gBAAgB,aAAa,OAAO,EAAE;AAAA,EACrD,GAAG,CAAC;AAEJ,SAAO,EAAE,QAAQ,YAAY,MAAM,SAAS,UAAU,aAAa;AACrE;AAcO,IAAM,gBAAgB,CAAC,MAAY,aAA2B;AACnE,MAAI,CAAC,YAAY,YAAY,EAAG,QAAO;AAEvC,QAAM,YAAY,gBAAgB,MAAM,OAAO;AAC/C,QAAM,iBAAiB,KAAK,MAAM,UAAU,SAAS,QAAQ;AAE7D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,KAAK,IAAI,GAAG,UAAU,SAAS,cAAc;AAAA,EACvD;AACF;;;ACrEO,SAAS,wBACd,SAGe;AACf,SAAO,OAAO,YAAkC;AAC9C,WAAO,QAAQ,OAAO;AAAA,EACxB;AACF;;;ACRA,SAAS,kBAAkB,KAA+B;AACxD,SAAO;AAAA,IACL,cAAc,IAAI,cAAc;AAAA,IAChC,kBAAkB,IAAI,kBAAkB;AAAA,IACxC,GAAI,IAAI,eAAe,KAAK,QAAQ;AAAA,MAClC,SAAS,IAAI,eAAe;AAAA,IAC9B;AAAA,IACA,GAAI,IAAI,wBAAwB,KAAK,QAAQ;AAAA,MAC3C,sBAAsB,IAAI,wBAAwB;AAAA,IACpD;AAAA,IACA,GAAI,IAAI,yBAAyB,KAAK,QAAQ;AAAA,MAC5C,uBAAuB,IAAI,yBAAyB;AAAA,IACtD;AAAA,IACA,GAAI,IAAI,0BAA0B,KAAK,QAAQ;AAAA,MAC7C,yBAAyB,IAAI,0BAA0B;AAAA,IACzD;AAAA,IACA,GAAI,IAAI,kBAAkB,KAAK,QAAQ;AAAA,MACrC,UAAU,IAAI,kBAAkB;AAAA,IAClC;AAAA,EACF;AACF;AAkBO,SAAS,yBACd,SACe;AACf,QAAM,EAAE,QAAQ,SAAS,mBAAmB,IAAI;AAEhD,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAA+D;AAC7D,YAAM,SAAS,IAAI,gBAAgB,EAAE,UAAU,QAAQ,CAAC;AACxD,UAAI,WAAY,QAAO,IAAI,YAAY,UAAU;AACjD,UAAI,YAAa,QAAO,IAAI,eAAe,WAAW;AAEtD,YAAM,MAAM,GAAG,MAAM,uBAAuB,MAAM;AAClD,YAAM,UAAkC,SACpC,EAAE,eAAe,UAAU,MAAM,GAAG,IACpC,CAAC;AAEL,UAAI;AACJ,UAAI;AACF,cAAM,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,CAAC;AACxC,YAAI,CAAC,IAAI,GAAI,QAAO;AACpB,eAAQ,MAAM,IAAI,KAAK;AAAA,MACzB,QAAQ;AACN,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,KAAM,QAAO;AAElB,YAAM,QAAQ,KAAK,KAAK,OAAK,EAAE,aAAa,OAAO;AACnD,YAAM,MAAM,OAAO,SAAS,CAAC;AAC7B,UAAI,CAAC,IAAK,QAAO;AAEjB,aAAO,kBAAkB,GAAG;AAAA,IAC9B;AAAA,EACF;AACF;;;AC3EO,SAAS,0BACd,YACe;AACf,SAAO,wBAAwB,CAAC,EAAE,QAAQ,MAA4B;AACpE,WAAO,WAAW,OAAO;AAAA,EAC3B,CAAC;AACH;;;ACfO,SAAS,QAAQ,QAA2B;AACjD,SAAO;AAAA,IACL,aAAa,OAAO;AAAA,IACpB,cAAc,OAAO;AAAA,IACrB,iBAAiB,OAAO;AAAA,IACxB,kBAAkB,OAAO;AAAA,IACzB,iBAAiB,OAAO;AAAA,IACxB,gBAAgB,OAAO;AAAA,EACzB;AACF;","names":["name","marker","symbol","name","marker","symbol","name","marker","symbol"]}
package/dist/index.d.cts CHANGED
@@ -6,11 +6,11 @@ interface Usage {
6
6
  readonly subProvider?: string;
7
7
  readonly inputTokens: number;
8
8
  readonly outputTokens: number;
9
- readonly totalTokens: number;
10
9
  readonly reasoningTokens?: number;
11
10
  readonly cacheReadTokens?: number;
12
11
  readonly cacheWriteTokens?: number;
13
12
  readonly requestCount?: number;
13
+ readonly webSearchCount?: number;
14
14
  readonly rawProviderCost?: number;
15
15
  readonly rawUpstreamInferenceCost?: number;
16
16
  }
@@ -46,6 +46,27 @@ interface Cost {
46
46
  readonly unit: CostUnit;
47
47
  }
48
48
 
49
+ /**
50
+ * Token usage passed into a provider cost calculation function.
51
+ */
52
+ interface CostInputs {
53
+ /** Number of prompt (input) tokens. */
54
+ promptTokens: number;
55
+ /** Number of completion (output) tokens. */
56
+ completionTokens: number;
57
+ /** Number of tokens served from the prompt cache. */
58
+ cacheReadTokens: number;
59
+ /** Number of tokens written to the prompt cache. */
60
+ cacheWriteTokens: number;
61
+ /**
62
+ * Number of reasoning tokens (priced with `internalReasoningTokens` when present in `ModelPricing`,
63
+ * otherwise at the completion rate).
64
+ */
65
+ reasoningTokens: number;
66
+ /** Number of web search calls (each billed at `pricing.webSearch` when set). */
67
+ webSearchCount?: number;
68
+ }
69
+
49
70
  interface ModelPricing {
50
71
  promptTokens: number;
51
72
  completionTokens: number;
@@ -53,6 +74,7 @@ interface ModelPricing {
53
74
  inputCacheWriteTokens?: number;
54
75
  internalReasoningTokens?: number;
55
76
  request?: number;
77
+ webSearch?: number;
56
78
  discount?: number;
57
79
  }
58
80
  type PriceResolverContext = {
@@ -75,6 +97,7 @@ interface MeterMetadata {
75
97
  cache_read_tokens?: number;
76
98
  cache_write_tokens?: number;
77
99
  request_count?: number;
100
+ web_search_count?: number;
78
101
  raw_provider_cost?: number;
79
102
  raw_upstream_inference_cost?: number;
80
103
  [key: string]: string | number | undefined;
@@ -86,6 +109,7 @@ interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {
86
109
  usage: LanguageModelV3Usage | undefined;
87
110
  providerMetadata: SharedV3ProviderMetadata | undefined;
88
111
  tags: TTags;
112
+ webSearchCount: number;
89
113
  }
90
114
  /**
91
115
  * Configuration for {@link createV3BillingMiddleware}.
@@ -293,4 +317,7 @@ declare function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject;
293
317
  */
294
318
  declare function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(event: BillingEvent<TTags>): MeterMetadata;
295
319
 
296
- export { AIBillingError, AiBillingCostError, AiBillingDestinationError, AiBillingExtractorError, type BaseBillingMiddlewareOptions, type BillingEvent, type BillingMiddlewareV3Options, type BuildV3EventPayload, type Cost, type CostUnit, type DefaultTags, type Destination, type EventBuilder, type MeterMetadata, type ModelPricing, type NarevPriceResolverOptions, type PriceResolver, type PriceResolverContext, type Usage, addCosts, applyDiscount, buildMeterMetadata, consoleDestination, convertCostUnit, costToNumber, createBasePriceResolver, createDestination, createNarevPriceResolver, createObjectPriceResolver, createV3BillingMiddleware, multiplyCost, rateToCost, toJSONObject };
320
+ /** Maps {@link CostInputs} token counts to a {@link Usage} object. */
321
+ declare function toUsage(inputs: CostInputs): Usage;
322
+
323
+ export { AIBillingError, AiBillingCostError, AiBillingDestinationError, AiBillingExtractorError, type BaseBillingMiddlewareOptions, type BillingEvent, type BillingMiddlewareV3Options, type BuildV3EventPayload, type Cost, type CostInputs, type CostUnit, type DefaultTags, type Destination, type EventBuilder, type MeterMetadata, type ModelPricing, type NarevPriceResolverOptions, type PriceResolver, type PriceResolverContext, type Usage, addCosts, applyDiscount, buildMeterMetadata, consoleDestination, convertCostUnit, costToNumber, createBasePriceResolver, createDestination, createNarevPriceResolver, createObjectPriceResolver, createV3BillingMiddleware, multiplyCost, rateToCost, toJSONObject, toUsage };
package/dist/index.d.ts CHANGED
@@ -6,11 +6,11 @@ interface Usage {
6
6
  readonly subProvider?: string;
7
7
  readonly inputTokens: number;
8
8
  readonly outputTokens: number;
9
- readonly totalTokens: number;
10
9
  readonly reasoningTokens?: number;
11
10
  readonly cacheReadTokens?: number;
12
11
  readonly cacheWriteTokens?: number;
13
12
  readonly requestCount?: number;
13
+ readonly webSearchCount?: number;
14
14
  readonly rawProviderCost?: number;
15
15
  readonly rawUpstreamInferenceCost?: number;
16
16
  }
@@ -46,6 +46,27 @@ interface Cost {
46
46
  readonly unit: CostUnit;
47
47
  }
48
48
 
49
+ /**
50
+ * Token usage passed into a provider cost calculation function.
51
+ */
52
+ interface CostInputs {
53
+ /** Number of prompt (input) tokens. */
54
+ promptTokens: number;
55
+ /** Number of completion (output) tokens. */
56
+ completionTokens: number;
57
+ /** Number of tokens served from the prompt cache. */
58
+ cacheReadTokens: number;
59
+ /** Number of tokens written to the prompt cache. */
60
+ cacheWriteTokens: number;
61
+ /**
62
+ * Number of reasoning tokens (priced with `internalReasoningTokens` when present in `ModelPricing`,
63
+ * otherwise at the completion rate).
64
+ */
65
+ reasoningTokens: number;
66
+ /** Number of web search calls (each billed at `pricing.webSearch` when set). */
67
+ webSearchCount?: number;
68
+ }
69
+
49
70
  interface ModelPricing {
50
71
  promptTokens: number;
51
72
  completionTokens: number;
@@ -53,6 +74,7 @@ interface ModelPricing {
53
74
  inputCacheWriteTokens?: number;
54
75
  internalReasoningTokens?: number;
55
76
  request?: number;
77
+ webSearch?: number;
56
78
  discount?: number;
57
79
  }
58
80
  type PriceResolverContext = {
@@ -75,6 +97,7 @@ interface MeterMetadata {
75
97
  cache_read_tokens?: number;
76
98
  cache_write_tokens?: number;
77
99
  request_count?: number;
100
+ web_search_count?: number;
78
101
  raw_provider_cost?: number;
79
102
  raw_upstream_inference_cost?: number;
80
103
  [key: string]: string | number | undefined;
@@ -86,6 +109,7 @@ interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {
86
109
  usage: LanguageModelV3Usage | undefined;
87
110
  providerMetadata: SharedV3ProviderMetadata | undefined;
88
111
  tags: TTags;
112
+ webSearchCount: number;
89
113
  }
90
114
  /**
91
115
  * Configuration for {@link createV3BillingMiddleware}.
@@ -293,4 +317,7 @@ declare function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject;
293
317
  */
294
318
  declare function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(event: BillingEvent<TTags>): MeterMetadata;
295
319
 
296
- export { AIBillingError, AiBillingCostError, AiBillingDestinationError, AiBillingExtractorError, type BaseBillingMiddlewareOptions, type BillingEvent, type BillingMiddlewareV3Options, type BuildV3EventPayload, type Cost, type CostUnit, type DefaultTags, type Destination, type EventBuilder, type MeterMetadata, type ModelPricing, type NarevPriceResolverOptions, type PriceResolver, type PriceResolverContext, type Usage, addCosts, applyDiscount, buildMeterMetadata, consoleDestination, convertCostUnit, costToNumber, createBasePriceResolver, createDestination, createNarevPriceResolver, createObjectPriceResolver, createV3BillingMiddleware, multiplyCost, rateToCost, toJSONObject };
320
+ /** Maps {@link CostInputs} token counts to a {@link Usage} object. */
321
+ declare function toUsage(inputs: CostInputs): Usage;
322
+
323
+ export { AIBillingError, AiBillingCostError, AiBillingDestinationError, AiBillingExtractorError, type BaseBillingMiddlewareOptions, type BillingEvent, type BillingMiddlewareV3Options, type BuildV3EventPayload, type Cost, type CostInputs, type CostUnit, type DefaultTags, type Destination, type EventBuilder, type MeterMetadata, type ModelPricing, type NarevPriceResolverOptions, type PriceResolver, type PriceResolverContext, type Usage, addCosts, applyDiscount, buildMeterMetadata, consoleDestination, convertCostUnit, costToNumber, createBasePriceResolver, createDestination, createNarevPriceResolver, createObjectPriceResolver, createV3BillingMiddleware, multiplyCost, rateToCost, toJSONObject, toUsage };
package/dist/index.js CHANGED
@@ -19,11 +19,11 @@ function buildMeterMetadata(event) {
19
19
  addOptional("sub_provider", u.subProvider);
20
20
  addOptional("input_tokens", u.inputTokens);
21
21
  addOptional("output_tokens", u.outputTokens);
22
- addOptional("total_tokens", u.totalTokens);
23
22
  addOptional("reasoning_tokens", u.reasoningTokens);
24
23
  addOptional("cache_read_tokens", u.cacheReadTokens);
25
24
  addOptional("cache_write_tokens", u.cacheWriteTokens);
26
25
  addOptional("request_count", u.requestCount);
26
+ addOptional("web_search_count", u.webSearchCount);
27
27
  addOptional("raw_provider_cost", u.rawProviderCost);
28
28
  addOptional("raw_upstream_inference_cost", u.rawUpstreamInferenceCost);
29
29
  if (event.tags) {
@@ -43,7 +43,8 @@ function createV3BillingMiddleware(options) {
43
43
  params,
44
44
  usage,
45
45
  providerMetadata,
46
- responseId
46
+ responseId,
47
+ webSearchCount
47
48
  }) => {
48
49
  try {
49
50
  const requestTags = params.providerOptions?.["ai-billing-tags"];
@@ -56,7 +57,8 @@ function createV3BillingMiddleware(options) {
56
57
  model,
57
58
  usage,
58
59
  providerMetadata,
59
- tags
60
+ tags,
61
+ webSearchCount
60
62
  });
61
63
  if (event && destinations && destinations?.length > 0) {
62
64
  const dispatchDestinationsPromise = Promise.allSettled(
@@ -75,12 +77,16 @@ function createV3BillingMiddleware(options) {
75
77
  specificationVersion: "v3",
76
78
  wrapGenerate: async ({ doGenerate, model, params }) => {
77
79
  const result = await doGenerate();
80
+ const webSearchCount = result.content.filter(
81
+ (c) => c.type === "source"
82
+ ).length;
78
83
  const event = await processEvent({
79
84
  model,
80
85
  params,
81
86
  usage: result.usage,
82
87
  providerMetadata: result.providerMetadata,
83
- responseId: result.response?.id
88
+ responseId: result.response?.id,
89
+ webSearchCount
84
90
  });
85
91
  const providerMetadataWithBilling = {
86
92
  ...result.providerMetadata
@@ -99,6 +105,7 @@ function createV3BillingMiddleware(options) {
99
105
  let usage;
100
106
  let providerMetadata;
101
107
  let finishChunk;
108
+ let webSearchCount = 0;
102
109
  const billedStream = stream.pipeThrough(
103
110
  new TransformStream({
104
111
  transform(chunk, controller) {
@@ -106,6 +113,9 @@ function createV3BillingMiddleware(options) {
106
113
  if (chunk.type === "response-metadata" && !responseId) {
107
114
  responseId = chunk.id;
108
115
  }
116
+ if (chunk.type === "source") {
117
+ webSearchCount++;
118
+ }
109
119
  if (chunk.type === "finish") {
110
120
  usage = chunk.usage;
111
121
  providerMetadata = chunk.providerMetadata;
@@ -120,7 +130,8 @@ function createV3BillingMiddleware(options) {
120
130
  params,
121
131
  usage,
122
132
  providerMetadata,
123
- responseId
133
+ responseId,
134
+ webSearchCount
124
135
  });
125
136
  const providerMetadataWithBilling = {
126
137
  ...providerMetadata
@@ -382,6 +393,18 @@ function createObjectPriceResolver(pricingMap) {
382
393
  return pricingMap[modelId];
383
394
  });
384
395
  }
396
+
397
+ // src/utils/to-usage.ts
398
+ function toUsage(inputs) {
399
+ return {
400
+ inputTokens: inputs.promptTokens,
401
+ outputTokens: inputs.completionTokens,
402
+ cacheReadTokens: inputs.cacheReadTokens,
403
+ cacheWriteTokens: inputs.cacheWriteTokens,
404
+ reasoningTokens: inputs.reasoningTokens,
405
+ webSearchCount: inputs.webSearchCount
406
+ };
407
+ }
385
408
  export {
386
409
  AIBillingError,
387
410
  AiBillingCostError,
@@ -400,6 +423,7 @@ export {
400
423
  createV3BillingMiddleware,
401
424
  multiplyCost,
402
425
  rateToCost,
403
- toJSONObject
426
+ toJSONObject,
427
+ toUsage
404
428
  };
405
429
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/event/to-json-object.ts","../src/event/to-meter-metadata.ts","../src/ai-sdk/language-model-middleware/v3/language-model-v3-base-billing-middleware.ts","../src/error/ai-billing-error.ts","../src/error/extractor-error.ts","../src/error/destination-error.ts","../src/error/cost-error.ts","../src/destination/base-destination.ts","../src/destination/console-destination.ts","../src/cost/convert-cost.ts","../src/cost/op-cost.ts","../src/pricing/base-price-resolver.ts","../src/pricing/narev-price-resolver.ts","../src/pricing/object-price-resolver.ts"],"sourcesContent":["import { DefaultTags, BillingEvent } from '../types/index.js';\nimport type { JSONObject } from '@ai-sdk/provider';\n\n/**\n * Casts a billing event into a JSON object payload.\n * @param event - The billing event to cast.\n * @returns The billing event represented as a JSON object.\n */\nexport function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject {\n return event as unknown as JSONObject;\n}\n","import type {\n BillingEvent,\n DefaultTags,\n MeterMetadata,\n} from '../types/index.js';\n\n/**\n * Converts a billing event into a meter metadata object.\n * @param event - The billing event to convert.\n * @returns The meter metadata object.\n */\nexport function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(\n event: BillingEvent<TTags>,\n): MeterMetadata {\n const u = event.usage ?? {};\n\n // Initialize with required fields\n const dimensions: MeterMetadata = {\n generation_id: event.generationId,\n model_id: event.modelId,\n provider: event.provider,\n };\n\n const addOptional = <K extends keyof MeterMetadata>(\n key: K,\n value: MeterMetadata[K],\n ) => {\n if (value !== undefined && value !== null) {\n dimensions[key] = value;\n }\n };\n\n addOptional('sub_provider', u.subProvider);\n addOptional('input_tokens', u.inputTokens);\n addOptional('output_tokens', u.outputTokens);\n addOptional('total_tokens', u.totalTokens);\n addOptional('reasoning_tokens', u.reasoningTokens);\n addOptional('cache_read_tokens', u.cacheReadTokens);\n addOptional('cache_write_tokens', u.cacheWriteTokens);\n addOptional('request_count', u.requestCount);\n addOptional('raw_provider_cost', u.rawProviderCost);\n addOptional('raw_upstream_inference_cost', u.rawUpstreamInferenceCost);\n\n if (event.tags) {\n for (const [key, value] of Object.entries(event.tags)) {\n if (value == null) continue;\n dimensions[`tag_${key}`] =\n typeof value === 'object'\n ? JSON.stringify(value)\n : (value as string | number);\n }\n }\n\n return dimensions;\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Usage,\n LanguageModelV3GenerateResult,\n LanguageModelV3StreamPart,\n LanguageModelV3Middleware,\n SharedV3ProviderMetadata,\n} from '@ai-sdk/provider';\nimport type {\n BaseBillingMiddlewareOptions,\n EventBuilder,\n BillingEvent,\n DefaultTags,\n} from '../../../types/index.js';\nimport { toJSONObject } from '../../../event/index.js';\n\nexport interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {\n responseId: string | undefined;\n model: LanguageModelV3;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n tags: TTags;\n}\n\n/**\n * Configuration for {@link createV3BillingMiddleware}.\n *\n * Extends {@link BaseBillingMiddlewareOptions} (`destinations`, `defaultTags`, `waitUntil`, `onError`) and\n * requires an {@link EventBuilder} to construct the {@link BillingEvent}.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n */\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n /** Builds a billing event from the model response data. */\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\n\n/**\n * Creates a billing middleware for the Language Model V3 API.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n * @param options - Billing options; see {@link BillingMiddlewareV3Options}.\n * @returns The billing middleware.\n */\nexport function createV3BillingMiddleware<\n TTags extends DefaultTags = DefaultTags,\n>(options: BillingMiddlewareV3Options<TTags>): LanguageModelV3Middleware {\n const { buildEvent, destinations, defaultTags, waitUntil, onError } = options;\n\n const processEvent = async ({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n }: {\n model: LanguageModelV3;\n params: LanguageModelV3CallOptions;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n responseId: string | undefined;\n }): Promise<BillingEvent<TTags> | null> => {\n try {\n const requestTags = params.providerOptions?.['ai-billing-tags'];\n\n const tags = {\n ...(defaultTags ?? {}),\n ...(requestTags ?? {}),\n } as TTags;\n\n const event = await buildEvent({\n responseId,\n model,\n usage,\n providerMetadata,\n tags,\n });\n\n if (event && destinations && destinations?.length > 0) {\n const dispatchDestinationsPromise = Promise.allSettled(\n destinations.map(d => Promise.resolve(d(event))),\n );\n if (waitUntil) waitUntil(dispatchDestinationsPromise);\n }\n return event;\n } catch (err) {\n if (onError) onError(err);\n else console.error('[ai-billing] Core Error:', err);\n return null;\n }\n };\n\n return {\n specificationVersion: 'v3',\n\n wrapGenerate: async ({ doGenerate, model, params }) => {\n const result: LanguageModelV3GenerateResult = await doGenerate();\n\n const event = await processEvent({\n model,\n params,\n usage: result.usage,\n providerMetadata: result.providerMetadata,\n responseId: result.response?.id,\n });\n\n const providerMetadataWithBilling = {\n ...result.providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n return {\n ...result,\n providerMetadata: providerMetadataWithBilling,\n };\n },\n\n wrapStream: async ({ doStream, model, params }) => {\n const { stream, ...rest } = await doStream();\n\n let responseId: string | undefined;\n let usage: LanguageModelV3Usage | undefined;\n let providerMetadata: SharedV3ProviderMetadata | undefined;\n let finishChunk:\n | Extract<LanguageModelV3StreamPart, { type: 'finish' }>\n | undefined;\n\n const billedStream = stream.pipeThrough(\n new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform(chunk, controller) {\n if (chunk.type === 'text-start') responseId = chunk.id;\n if (chunk.type === 'response-metadata' && !responseId) {\n responseId = chunk.id;\n }\n if (chunk.type === 'finish') {\n usage = chunk.usage;\n providerMetadata = chunk.providerMetadata;\n finishChunk = chunk;\n return; // held until flush\n }\n controller.enqueue(chunk);\n },\n async flush(controller) {\n const event = await processEvent({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n });\n\n const providerMetadataWithBilling = {\n ...providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n if (finishChunk) {\n controller.enqueue({\n ...finishChunk,\n providerMetadata: providerMetadataWithBilling,\n });\n }\n },\n }),\n );\n\n return { ...rest, stream: billedStream };\n },\n };\n}\n","const marker = 'ai-billing.error';\nconst symbol = Symbol.for(marker);\n\n/** Base error type for all ai-billing package errors. */\nexport class AIBillingError extends Error {\n private readonly [symbol] = true;\n\n readonly cause?: unknown;\n\n constructor({\n name,\n message,\n cause,\n }: {\n name: string;\n message: string;\n cause?: unknown;\n }) {\n super(message);\n this.name = name;\n this.cause = cause;\n }\n\n static isInstance(error: unknown): error is AIBillingError {\n return AIBillingError.hasMarker(error, marker);\n }\n\n protected static hasMarker(error: unknown, markerString: string): boolean {\n const markerSymbol = Symbol.for(markerString);\n return (\n error != null &&\n typeof error === 'object' &&\n markerSymbol in error &&\n typeof error[markerSymbol] === 'boolean' &&\n error[markerSymbol] === true\n );\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingExtractorError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when billing data extraction fails. */\nexport class AiBillingExtractorError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({\n message = `Failed to extract billing data.`,\n cause,\n }: {\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingExtractorError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingDestinationError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Error raised when billing data processing fails for a destination.\n */\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\n /** The ID of the destination that failed to process billing data. */\n readonly destinationId?: string;\n\n constructor({\n destinationId,\n message = `Failed to process billing data for destination: '${destinationId}'.`,\n cause,\n }: {\n destinationId?: string;\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n this.destinationId = destinationId;\n }\n\n static isInstance(error: unknown): error is AiBillingDestinationError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingCostError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when a cost conversion or calculation fails. */\nexport class AiBillingCostError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({ message, cause }: { message: string; cause?: unknown }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingCostError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import type { Destination, BillingEvent, DefaultTags } from '../types/index.js';\nimport { AiBillingDestinationError } from '../error/index.js';\n\n/**\n * Creates a destination wrapper that normalizes destination handler errors.\n *\n * @param destinationId - Unique identifier for the destination.\n * @param handler - Destination implementation invoked for each billing event.\n * @returns A destination function that wraps thrown errors as AiBillingDestinationError.\n */\nexport function createDestination<TTags extends DefaultTags = DefaultTags>(\n destinationId: string,\n handler: (event: BillingEvent<TTags>) => Promise<void> | void,\n): Destination<TTags> {\n return async (event: BillingEvent<TTags>) => {\n try {\n await handler(event);\n } catch (error) {\n throw new AiBillingDestinationError({\n destinationId,\n cause: error,\n });\n }\n };\n}\n","import { createDestination } from './base-destination.js';\nimport type { DefaultTags, Destination } from '../types/index.js';\n\n/**\n * Creates a destination that logs billing events to the console.\n *\n * @returns A destination that prints each event with full depth formatting.\n */\nexport function consoleDestination<\n TTags extends DefaultTags = DefaultTags,\n>(): Destination<TTags> {\n return createDestination<TTags>('console-logger', event => {\n console.dir(event, {\n depth: null,\n colors: true,\n compact: false,\n });\n });\n}\n","import { AiBillingCostError } from '../index.js';\nimport type { Cost, CostUnit } from '../index.js';\n\nconst getNanos = (cost: Cost): number => {\n switch (cost.unit) {\n case 'base':\n return Math.round(cost.amount * 1_000_000_000);\n case 'cents':\n return Math.round(cost.amount * 10_000_000);\n case 'micros':\n return Math.round(cost.amount * 1_000);\n case 'nanos':\n return Math.round(cost.amount);\n default:\n throw new AiBillingCostError({\n message: `Failed to process cost. Unknown CostUnit: '${String(cost.unit)}'.`,\n });\n }\n};\n\n/**\n * Returns the numeric amount of `cost` expressed in `targetUnit`.\n *\n * Values are converted via an integer nanos intermediate so fractional `base` / `cents` / `micros` amounts\n * round consistently. Throws {@link AiBillingCostError} when `cost.unit` is not a known {@link CostUnit}.\n *\n * @param cost - Source {@link Cost} (amount + unit + currency).\n * @param targetUnit - Unit for the returned number (same scale as {@link Cost} amounts for that unit).\n * @returns The amount in `targetUnit`; for `nanos` this is a whole number of nanos.\n * @internal\n */\nexport const costToNumber = (cost: Cost, targetUnit: CostUnit): number => {\n const nanos = getNanos(cost);\n\n if (targetUnit === 'nanos') return nanos;\n if (targetUnit === 'micros') return nanos / 1_000;\n if (targetUnit === 'cents') return nanos / 10_000_000;\n return nanos / 1_000_000_000; // base\n};\n\n/**\n * Converts a {@link Cost} to the same amount in a different {@link CostUnit}, preserving `currency`.\n *\n * Implemented with {@link costToNumber}; the result is always a new object.\n *\n * @param cost - Source cost.\n * @param targetUnit - Desired unit for `amount` on the returned object.\n * @returns A new {@link Cost} with `unit: targetUnit` and `amount` in that unit's scale.\n * @internal\n */\nexport const convertCostUnit = (cost: Cost, targetUnit: CostUnit): Cost => {\n return {\n amount: costToNumber(cost, targetUnit),\n currency: cost.currency,\n unit: targetUnit,\n };\n};\n\n/**\n * Wraps a numeric rate as a {@link Cost} in `base` units and `USD` currency.\n *\n * Provider calculators pass per-token prices from {@link ModelPricing} here, then scale with\n * {@link multiplyCost} using token counts.\n *\n * @param amount - Rate amount in base USD units (defaults to `0` when omitted).\n * @returns A {@link Cost} with `unit: 'base'` and `currency: 'USD'`.\n * @internal\n */\nexport const rateToCost = (amount: number = 0): Cost => ({\n amount,\n unit: 'base',\n currency: 'USD',\n});\n","import { Cost } from '../types/index.js';\nimport { AiBillingCostError } from '../index.js';\nimport { convertCostUnit } from './convert-cost.js';\n\n/**\n * Scales a {@link Cost} by `multiplier` (for example token count × per-token rate).\n *\n * Converts to {@link CostUnit} `nanos`, multiplies the integer nanos amount (rounded), and returns a\n * {@link Cost} with `unit: 'nanos'` and the same `currency` as the input.\n *\n * @param cost - Base cost to scale.\n * @param multiplier - Factor applied to the nanos amount (often a non-negative token count).\n * @returns The scaled cost in nanos.\n * @internal\n */\nexport const multiplyCost = (cost: Cost, multiplier: number): Cost => {\n const nanosCost = convertCostUnit(cost, 'nanos');\n return {\n ...nanosCost,\n amount: Math.round(nanosCost.amount * multiplier),\n };\n};\n\n/**\n * Adds any number of {@link Cost} values after converting each to nanos.\n *\n * All arguments must share the same `currency`; otherwise throws {@link AiBillingCostError}. With no\n * arguments, returns a zero USD cost in nanos. With a single cost, still normalizes to nanos.\n *\n * @param costs - Costs to sum (variadic).\n * @returns The total as a {@link Cost} with `unit: 'nanos'` and the shared `currency`.\n * @internal\n */\nexport const addCosts = (...costs: Cost[]): Cost => {\n if (costs.length === 0) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const firstCost = costs[0];\n\n if (!firstCost) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const baseCurrency = firstCost.currency;\n\n const totalNanos = costs.reduce((sum, currentCost) => {\n if (currentCost.currency !== baseCurrency) {\n throw new AiBillingCostError({\n message: `Currency mismatch: Cannot add ${baseCurrency} to ${currentCost.currency}`,\n });\n }\n return sum + convertCostUnit(currentCost, 'nanos').amount;\n }, 0);\n\n return { amount: totalNanos, unit: 'nanos', currency: baseCurrency };\n};\n\n/**\n * Applies a fractional discount to `cost` in nanos: `amount * (1 - discount)`.\n *\n * If `discount` is falsy or `<= 0`, returns `cost` unchanged (same unit and amount). Otherwise converts to\n * nanos, subtracts `round(amount * discount)`, and clamps the result at zero. Typical `discount` values are\n * between `0` and `1` (for example `0.1` for 10% off).\n *\n * @param cost - Original cost.\n * @param discount - Fraction of the nanos amount to remove (not a percentage label).\n * @returns Either the original `cost` or a discounted {@link Cost} in nanos.\n * @internal\n */\nexport const applyDiscount = (cost: Cost, discount: number): Cost => {\n if (!discount || discount <= 0) return cost;\n\n const nanosCost = convertCostUnit(cost, 'nanos');\n const discountAmount = Math.round(nanosCost.amount * discount);\n\n return {\n ...nanosCost,\n amount: Math.max(0, nanosCost.amount - discountAmount),\n };\n};\n","import type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a base price resolver that wraps a handler function.\n * @param handler - The function that resolves model pricing.\n * @returns A price resolver that wraps the handler function.\n */\nexport function createBasePriceResolver(\n handler: (\n context: PriceResolverContext,\n ) => ModelPricing | undefined | Promise<ModelPricing | undefined>,\n): PriceResolver {\n return async (context: PriceResolverContext) => {\n return handler(context);\n };\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\ntype PricingRow = Record<string, number | string>;\ntype PricingEntry = { model_id: string; prices: PricingRow[] };\ntype PricingResponse = PricingEntry[];\n\nfunction rowToModelPricing(row: PricingRow): ModelPricing {\n return {\n promptTokens: row['price_prompt'] as number,\n completionTokens: row['price_completion'] as number,\n ...(row['price_request'] != null && {\n request: row['price_request'] as number,\n }),\n ...(row['price_input_cache_read'] != null && {\n inputCacheReadTokens: row['price_input_cache_read'] as number,\n }),\n ...(row['price_input_cache_write'] != null && {\n inputCacheWriteTokens: row['price_input_cache_write'] as number,\n }),\n ...(row['price_internal_reasoning'] != null && {\n internalReasoningTokens: row['price_internal_reasoning'] as number,\n }),\n ...(row['pricing_discount'] != null && {\n discount: row['pricing_discount'] as number,\n }),\n };\n}\n\n/**\n * Configuration for {@link createNarevPriceResolver}.\n */\nexport type NarevPriceResolverOptions = {\n /** API key used for authenticated pricing requests. */\n apiKey: string;\n /** Optional base URL for the Narev API. */\n apiUrl?: string;\n};\n\n/**\n * Creates a price resolver that fetches model pricing from the Narev API.\n *\n * @param options - Resolver options; see {@link NarevPriceResolverOptions}.\n * @returns A base price resolver that resolves model pricing from Narev.\n */\nexport function createNarevPriceResolver(\n options: NarevPriceResolverOptions,\n): PriceResolver {\n const { apiKey, apiUrl = 'https://narev.ai' } = options;\n\n return createBasePriceResolver(\n async ({\n modelId,\n providerId,\n subProvider,\n }: PriceResolverContext): Promise<ModelPricing | undefined> => {\n const params = new URLSearchParams({ model_id: modelId });\n if (providerId) params.set('provider', providerId);\n if (subProvider) params.set('subprovider', subProvider);\n\n const url = `${apiUrl}/api/models/pricing?${params}`;\n const headers: Record<string, string> = apiKey\n ? { Authorization: `Bearer ${apiKey}` }\n : {};\n\n let data: PricingResponse | null;\n try {\n const res = await fetch(url, { headers });\n if (!res.ok) return undefined;\n data = (await res.json()) as PricingResponse | null;\n } catch {\n return undefined;\n }\n\n if (!data) return undefined;\n\n const entry = data.find(e => e.model_id === modelId);\n const row = entry?.prices?.[0];\n if (!row) return undefined;\n\n return rowToModelPricing(row);\n },\n );\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a price resolver that uses a static pricing map.\n * @param pricingMap - A mapping of model IDs to model pricing.\n * @returns A price resolver that uses the static pricing map.\n */\nexport function createObjectPriceResolver(\n pricingMap: Record<string, ModelPricing>,\n): PriceResolver {\n return createBasePriceResolver(({ modelId }: PriceResolverContext) => {\n return pricingMap[modelId];\n });\n}\n"],"mappings":"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","names":["name","marker","symbol","name","marker","symbol","name","marker","symbol"]}
1
+ {"version":3,"sources":["../src/event/to-json-object.ts","../src/event/to-meter-metadata.ts","../src/ai-sdk/language-model-middleware/v3/language-model-v3-base-billing-middleware.ts","../src/error/ai-billing-error.ts","../src/error/extractor-error.ts","../src/error/destination-error.ts","../src/error/cost-error.ts","../src/destination/base-destination.ts","../src/destination/console-destination.ts","../src/cost/convert-cost.ts","../src/cost/op-cost.ts","../src/pricing/base-price-resolver.ts","../src/pricing/narev-price-resolver.ts","../src/pricing/object-price-resolver.ts","../src/utils/to-usage.ts"],"sourcesContent":["import { DefaultTags, BillingEvent } from '../types/index.js';\nimport type { JSONObject } from '@ai-sdk/provider';\n\n/**\n * Casts a billing event into a JSON object payload.\n * @param event - The billing event to cast.\n * @returns The billing event represented as a JSON object.\n */\nexport function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject {\n return event as unknown as JSONObject;\n}\n","import type {\n BillingEvent,\n DefaultTags,\n MeterMetadata,\n} from '../types/index.js';\n\n/**\n * Converts a billing event into a meter metadata object.\n * @param event - The billing event to convert.\n * @returns The meter metadata object.\n */\nexport function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(\n event: BillingEvent<TTags>,\n): MeterMetadata {\n const u = event.usage ?? {};\n\n // Initialize with required fields\n const dimensions: MeterMetadata = {\n generation_id: event.generationId,\n model_id: event.modelId,\n provider: event.provider,\n };\n\n const addOptional = <K extends keyof MeterMetadata>(\n key: K,\n value: MeterMetadata[K],\n ) => {\n if (value !== undefined && value !== null) {\n dimensions[key] = value;\n }\n };\n\n addOptional('sub_provider', u.subProvider);\n addOptional('input_tokens', u.inputTokens);\n addOptional('output_tokens', u.outputTokens);\n addOptional('reasoning_tokens', u.reasoningTokens);\n addOptional('cache_read_tokens', u.cacheReadTokens);\n addOptional('cache_write_tokens', u.cacheWriteTokens);\n addOptional('request_count', u.requestCount);\n addOptional('web_search_count', u.webSearchCount);\n addOptional('raw_provider_cost', u.rawProviderCost);\n addOptional('raw_upstream_inference_cost', u.rawUpstreamInferenceCost);\n\n if (event.tags) {\n for (const [key, value] of Object.entries(event.tags)) {\n if (value == null) continue;\n dimensions[`tag_${key}`] =\n typeof value === 'object'\n ? JSON.stringify(value)\n : (value as string | number);\n }\n }\n\n return dimensions;\n}\n","import type {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Usage,\n LanguageModelV3GenerateResult,\n LanguageModelV3StreamPart,\n LanguageModelV3Middleware,\n SharedV3ProviderMetadata,\n} from '@ai-sdk/provider';\nimport type {\n BaseBillingMiddlewareOptions,\n EventBuilder,\n BillingEvent,\n DefaultTags,\n} from '../../../types/index.js';\nimport { toJSONObject } from '../../../event/index.js';\n\nexport interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {\n responseId: string | undefined;\n model: LanguageModelV3;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n tags: TTags;\n webSearchCount: number;\n}\n\n/**\n * Configuration for {@link createV3BillingMiddleware}.\n *\n * Extends {@link BaseBillingMiddlewareOptions} (`destinations`, `defaultTags`, `waitUntil`, `onError`) and\n * requires an {@link EventBuilder} to construct the {@link BillingEvent}.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n */\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n /** Builds a billing event from the model response data. */\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\n\n/**\n * Creates a billing middleware for the Language Model V3 API.\n *\n * @typeParam TTags - The shape of the tags object, extending {@link DefaultTags}.\n * @param options - Billing options; see {@link BillingMiddlewareV3Options}.\n * @returns The billing middleware.\n */\nexport function createV3BillingMiddleware<\n TTags extends DefaultTags = DefaultTags,\n>(options: BillingMiddlewareV3Options<TTags>): LanguageModelV3Middleware {\n const { buildEvent, destinations, defaultTags, waitUntil, onError } = options;\n\n const processEvent = async ({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n webSearchCount,\n }: {\n model: LanguageModelV3;\n params: LanguageModelV3CallOptions;\n usage: LanguageModelV3Usage | undefined;\n providerMetadata: SharedV3ProviderMetadata | undefined;\n responseId: string | undefined;\n webSearchCount: number;\n }): Promise<BillingEvent<TTags> | null> => {\n try {\n const requestTags = params.providerOptions?.['ai-billing-tags'];\n\n const tags = {\n ...(defaultTags ?? {}),\n ...(requestTags ?? {}),\n } as TTags;\n\n const event = await buildEvent({\n responseId,\n model,\n usage,\n providerMetadata,\n tags,\n webSearchCount,\n });\n\n if (event && destinations && destinations?.length > 0) {\n const dispatchDestinationsPromise = Promise.allSettled(\n destinations.map(d => Promise.resolve(d(event))),\n );\n if (waitUntil) waitUntil(dispatchDestinationsPromise);\n }\n return event;\n } catch (err) {\n if (onError) onError(err);\n else console.error('[ai-billing] Core Error:', err);\n return null;\n }\n };\n\n return {\n specificationVersion: 'v3',\n\n wrapGenerate: async ({ doGenerate, model, params }) => {\n const result: LanguageModelV3GenerateResult = await doGenerate();\n\n const webSearchCount = result.content.filter(\n c => c.type === 'source',\n ).length;\n\n const event = await processEvent({\n model,\n params,\n usage: result.usage,\n providerMetadata: result.providerMetadata,\n responseId: result.response?.id,\n webSearchCount,\n });\n\n const providerMetadataWithBilling = {\n ...result.providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n return {\n ...result,\n providerMetadata: providerMetadataWithBilling,\n };\n },\n\n wrapStream: async ({ doStream, model, params }) => {\n const { stream, ...rest } = await doStream();\n\n let responseId: string | undefined;\n let usage: LanguageModelV3Usage | undefined;\n let providerMetadata: SharedV3ProviderMetadata | undefined;\n let finishChunk:\n | Extract<LanguageModelV3StreamPart, { type: 'finish' }>\n | undefined;\n let webSearchCount = 0;\n\n const billedStream = stream.pipeThrough(\n new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform(chunk, controller) {\n if (chunk.type === 'text-start') responseId = chunk.id;\n if (chunk.type === 'response-metadata' && !responseId) {\n responseId = chunk.id;\n }\n if (chunk.type === 'source') {\n webSearchCount++;\n }\n if (chunk.type === 'finish') {\n usage = chunk.usage;\n providerMetadata = chunk.providerMetadata;\n finishChunk = chunk;\n return; // held until flush\n }\n controller.enqueue(chunk);\n },\n async flush(controller) {\n const event = await processEvent({\n model,\n params,\n usage,\n providerMetadata,\n responseId,\n webSearchCount,\n });\n\n const providerMetadataWithBilling = {\n ...providerMetadata,\n } as SharedV3ProviderMetadata;\n\n if (event) {\n providerMetadataWithBilling['ai-billing'] = toJSONObject(event);\n }\n\n if (finishChunk) {\n controller.enqueue({\n ...finishChunk,\n providerMetadata: providerMetadataWithBilling,\n });\n }\n },\n }),\n );\n\n return { ...rest, stream: billedStream };\n },\n };\n}\n","const marker = 'ai-billing.error';\nconst symbol = Symbol.for(marker);\n\n/** Base error type for all ai-billing package errors. */\nexport class AIBillingError extends Error {\n private readonly [symbol] = true;\n\n readonly cause?: unknown;\n\n constructor({\n name,\n message,\n cause,\n }: {\n name: string;\n message: string;\n cause?: unknown;\n }) {\n super(message);\n this.name = name;\n this.cause = cause;\n }\n\n static isInstance(error: unknown): error is AIBillingError {\n return AIBillingError.hasMarker(error, marker);\n }\n\n protected static hasMarker(error: unknown, markerString: string): boolean {\n const markerSymbol = Symbol.for(markerString);\n return (\n error != null &&\n typeof error === 'object' &&\n markerSymbol in error &&\n typeof error[markerSymbol] === 'boolean' &&\n error[markerSymbol] === true\n );\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingExtractorError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when billing data extraction fails. */\nexport class AiBillingExtractorError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({\n message = `Failed to extract billing data.`,\n cause,\n }: {\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingExtractorError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingDestinationError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Error raised when billing data processing fails for a destination.\n */\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\n /** The ID of the destination that failed to process billing data. */\n readonly destinationId?: string;\n\n constructor({\n destinationId,\n message = `Failed to process billing data for destination: '${destinationId}'.`,\n cause,\n }: {\n destinationId?: string;\n message?: string;\n cause?: unknown;\n }) {\n super({ name, message, cause });\n this.destinationId = destinationId;\n }\n\n static isInstance(error: unknown): error is AiBillingDestinationError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import { AIBillingError } from './ai-billing-error.js';\n\nconst name = 'AiBillingCostError';\nconst marker = `ai-billing.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/** Error thrown when a cost conversion or calculation fails. */\nexport class AiBillingCostError extends AIBillingError {\n private readonly [symbol] = true;\n\n constructor({ message, cause }: { message: string; cause?: unknown }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is AiBillingCostError {\n return AIBillingError.hasMarker(error, marker);\n }\n}\n","import type { Destination, BillingEvent, DefaultTags } from '../types/index.js';\nimport { AiBillingDestinationError } from '../error/index.js';\n\n/**\n * Creates a destination wrapper that normalizes destination handler errors.\n *\n * @param destinationId - Unique identifier for the destination.\n * @param handler - Destination implementation invoked for each billing event.\n * @returns A destination function that wraps thrown errors as AiBillingDestinationError.\n */\nexport function createDestination<TTags extends DefaultTags = DefaultTags>(\n destinationId: string,\n handler: (event: BillingEvent<TTags>) => Promise<void> | void,\n): Destination<TTags> {\n return async (event: BillingEvent<TTags>) => {\n try {\n await handler(event);\n } catch (error) {\n throw new AiBillingDestinationError({\n destinationId,\n cause: error,\n });\n }\n };\n}\n","import { createDestination } from './base-destination.js';\nimport type { DefaultTags, Destination } from '../types/index.js';\n\n/**\n * Creates a destination that logs billing events to the console.\n *\n * @returns A destination that prints each event with full depth formatting.\n */\nexport function consoleDestination<\n TTags extends DefaultTags = DefaultTags,\n>(): Destination<TTags> {\n return createDestination<TTags>('console-logger', event => {\n console.dir(event, {\n depth: null,\n colors: true,\n compact: false,\n });\n });\n}\n","import { AiBillingCostError } from '../index.js';\nimport type { Cost, CostUnit } from '../index.js';\n\nconst getNanos = (cost: Cost): number => {\n switch (cost.unit) {\n case 'base':\n return Math.round(cost.amount * 1_000_000_000);\n case 'cents':\n return Math.round(cost.amount * 10_000_000);\n case 'micros':\n return Math.round(cost.amount * 1_000);\n case 'nanos':\n return Math.round(cost.amount);\n default:\n throw new AiBillingCostError({\n message: `Failed to process cost. Unknown CostUnit: '${String(cost.unit)}'.`,\n });\n }\n};\n\n/**\n * Returns the numeric amount of `cost` expressed in `targetUnit`.\n *\n * Values are converted via an integer nanos intermediate so fractional `base` / `cents` / `micros` amounts\n * round consistently. Throws {@link AiBillingCostError} when `cost.unit` is not a known {@link CostUnit}.\n *\n * @param cost - Source {@link Cost} (amount + unit + currency).\n * @param targetUnit - Unit for the returned number (same scale as {@link Cost} amounts for that unit).\n * @returns The amount in `targetUnit`; for `nanos` this is a whole number of nanos.\n * @internal\n */\nexport const costToNumber = (cost: Cost, targetUnit: CostUnit): number => {\n const nanos = getNanos(cost);\n\n if (targetUnit === 'nanos') return nanos;\n if (targetUnit === 'micros') return nanos / 1_000;\n if (targetUnit === 'cents') return nanos / 10_000_000;\n return nanos / 1_000_000_000; // base\n};\n\n/**\n * Converts a {@link Cost} to the same amount in a different {@link CostUnit}, preserving `currency`.\n *\n * Implemented with {@link costToNumber}; the result is always a new object.\n *\n * @param cost - Source cost.\n * @param targetUnit - Desired unit for `amount` on the returned object.\n * @returns A new {@link Cost} with `unit: targetUnit` and `amount` in that unit's scale.\n * @internal\n */\nexport const convertCostUnit = (cost: Cost, targetUnit: CostUnit): Cost => {\n return {\n amount: costToNumber(cost, targetUnit),\n currency: cost.currency,\n unit: targetUnit,\n };\n};\n\n/**\n * Wraps a numeric rate as a {@link Cost} in `base` units and `USD` currency.\n *\n * Provider calculators pass per-token prices from {@link ModelPricing} here, then scale with\n * {@link multiplyCost} using token counts.\n *\n * @param amount - Rate amount in base USD units (defaults to `0` when omitted).\n * @returns A {@link Cost} with `unit: 'base'` and `currency: 'USD'`.\n * @internal\n */\nexport const rateToCost = (amount: number = 0): Cost => ({\n amount,\n unit: 'base',\n currency: 'USD',\n});\n","import { Cost } from '../types/index.js';\nimport { AiBillingCostError } from '../index.js';\nimport { convertCostUnit } from './convert-cost.js';\n\n/**\n * Scales a {@link Cost} by `multiplier` (for example token count × per-token rate).\n *\n * Converts to {@link CostUnit} `nanos`, multiplies the integer nanos amount (rounded), and returns a\n * {@link Cost} with `unit: 'nanos'` and the same `currency` as the input.\n *\n * @param cost - Base cost to scale.\n * @param multiplier - Factor applied to the nanos amount (often a non-negative token count).\n * @returns The scaled cost in nanos.\n * @internal\n */\nexport const multiplyCost = (cost: Cost, multiplier: number): Cost => {\n const nanosCost = convertCostUnit(cost, 'nanos');\n return {\n ...nanosCost,\n amount: Math.round(nanosCost.amount * multiplier),\n };\n};\n\n/**\n * Adds any number of {@link Cost} values after converting each to nanos.\n *\n * All arguments must share the same `currency`; otherwise throws {@link AiBillingCostError}. With no\n * arguments, returns a zero USD cost in nanos. With a single cost, still normalizes to nanos.\n *\n * @param costs - Costs to sum (variadic).\n * @returns The total as a {@link Cost} with `unit: 'nanos'` and the shared `currency`.\n * @internal\n */\nexport const addCosts = (...costs: Cost[]): Cost => {\n if (costs.length === 0) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const firstCost = costs[0];\n\n if (!firstCost) {\n return { amount: 0, unit: 'nanos', currency: 'USD' };\n }\n\n const baseCurrency = firstCost.currency;\n\n const totalNanos = costs.reduce((sum, currentCost) => {\n if (currentCost.currency !== baseCurrency) {\n throw new AiBillingCostError({\n message: `Currency mismatch: Cannot add ${baseCurrency} to ${currentCost.currency}`,\n });\n }\n return sum + convertCostUnit(currentCost, 'nanos').amount;\n }, 0);\n\n return { amount: totalNanos, unit: 'nanos', currency: baseCurrency };\n};\n\n/**\n * Applies a fractional discount to `cost` in nanos: `amount * (1 - discount)`.\n *\n * If `discount` is falsy or `<= 0`, returns `cost` unchanged (same unit and amount). Otherwise converts to\n * nanos, subtracts `round(amount * discount)`, and clamps the result at zero. Typical `discount` values are\n * between `0` and `1` (for example `0.1` for 10% off).\n *\n * @param cost - Original cost.\n * @param discount - Fraction of the nanos amount to remove (not a percentage label).\n * @returns Either the original `cost` or a discounted {@link Cost} in nanos.\n * @internal\n */\nexport const applyDiscount = (cost: Cost, discount: number): Cost => {\n if (!discount || discount <= 0) return cost;\n\n const nanosCost = convertCostUnit(cost, 'nanos');\n const discountAmount = Math.round(nanosCost.amount * discount);\n\n return {\n ...nanosCost,\n amount: Math.max(0, nanosCost.amount - discountAmount),\n };\n};\n","import type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a base price resolver that wraps a handler function.\n * @param handler - The function that resolves model pricing.\n * @returns A price resolver that wraps the handler function.\n */\nexport function createBasePriceResolver(\n handler: (\n context: PriceResolverContext,\n ) => ModelPricing | undefined | Promise<ModelPricing | undefined>,\n): PriceResolver {\n return async (context: PriceResolverContext) => {\n return handler(context);\n };\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\ntype PricingRow = Record<string, number | string>;\ntype PricingEntry = { model_id: string; prices: PricingRow[] };\ntype PricingResponse = PricingEntry[];\n\nfunction rowToModelPricing(row: PricingRow): ModelPricing {\n return {\n promptTokens: row['price_prompt'] as number,\n completionTokens: row['price_completion'] as number,\n ...(row['price_request'] != null && {\n request: row['price_request'] as number,\n }),\n ...(row['price_input_cache_read'] != null && {\n inputCacheReadTokens: row['price_input_cache_read'] as number,\n }),\n ...(row['price_input_cache_write'] != null && {\n inputCacheWriteTokens: row['price_input_cache_write'] as number,\n }),\n ...(row['price_internal_reasoning'] != null && {\n internalReasoningTokens: row['price_internal_reasoning'] as number,\n }),\n ...(row['pricing_discount'] != null && {\n discount: row['pricing_discount'] as number,\n }),\n };\n}\n\n/**\n * Configuration for {@link createNarevPriceResolver}.\n */\nexport type NarevPriceResolverOptions = {\n /** API key used for authenticated pricing requests. */\n apiKey: string;\n /** Optional base URL for the Narev API. */\n apiUrl?: string;\n};\n\n/**\n * Creates a price resolver that fetches model pricing from the Narev API.\n *\n * @param options - Resolver options; see {@link NarevPriceResolverOptions}.\n * @returns A base price resolver that resolves model pricing from Narev.\n */\nexport function createNarevPriceResolver(\n options: NarevPriceResolverOptions,\n): PriceResolver {\n const { apiKey, apiUrl = 'https://narev.ai' } = options;\n\n return createBasePriceResolver(\n async ({\n modelId,\n providerId,\n subProvider,\n }: PriceResolverContext): Promise<ModelPricing | undefined> => {\n const params = new URLSearchParams({ model_id: modelId });\n if (providerId) params.set('provider', providerId);\n if (subProvider) params.set('subprovider', subProvider);\n\n const url = `${apiUrl}/api/models/pricing?${params}`;\n const headers: Record<string, string> = apiKey\n ? { Authorization: `Bearer ${apiKey}` }\n : {};\n\n let data: PricingResponse | null;\n try {\n const res = await fetch(url, { headers });\n if (!res.ok) return undefined;\n data = (await res.json()) as PricingResponse | null;\n } catch {\n return undefined;\n }\n\n if (!data) return undefined;\n\n const entry = data.find(e => e.model_id === modelId);\n const row = entry?.prices?.[0];\n if (!row) return undefined;\n\n return rowToModelPricing(row);\n },\n );\n}\n","import { createBasePriceResolver } from './base-price-resolver.js';\nimport type {\n ModelPricing,\n PriceResolver,\n PriceResolverContext,\n} from '../types/index.js';\n\n/**\n * Creates a price resolver that uses a static pricing map.\n * @param pricingMap - A mapping of model IDs to model pricing.\n * @returns A price resolver that uses the static pricing map.\n */\nexport function createObjectPriceResolver(\n pricingMap: Record<string, ModelPricing>,\n): PriceResolver {\n return createBasePriceResolver(({ modelId }: PriceResolverContext) => {\n return pricingMap[modelId];\n });\n}\n","import type { CostInputs, Usage } from '../types/index.js';\n\n/** Maps {@link CostInputs} token counts to a {@link Usage} object. */\nexport function toUsage(inputs: CostInputs): Usage {\n return {\n inputTokens: inputs.promptTokens,\n outputTokens: inputs.completionTokens,\n cacheReadTokens: inputs.cacheReadTokens,\n cacheWriteTokens: inputs.cacheWriteTokens,\n reasoningTokens: inputs.reasoningTokens,\n webSearchCount: inputs.webSearchCount,\n };\n}\n"],"mappings":"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","names":["name","marker","symbol","name","marker","symbol","name","marker","symbol"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-billing/core",
3
- "version": "0.0.6",
3
+ "version": "0.1.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "repository": {
@@ -38,7 +38,7 @@
38
38
  "typescript": "5.9.2",
39
39
  "vitest": "4.1.1",
40
40
  "zod": "^4.3.6",
41
- "@ai-billing/testing": "0.0.3",
41
+ "@ai-billing/testing": "0.1.0",
42
42
  "@ai-billing/typescript-config": "0.0.1"
43
43
  },
44
44
  "peerDependencies": {