@ai-billing/core 0.0.2 → 0.0.4
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 +95 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +91 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -26,15 +26,18 @@ __export(index_exports, {
|
|
|
26
26
|
AiBillingExtractorError: () => AiBillingExtractorError,
|
|
27
27
|
addCosts: () => addCosts,
|
|
28
28
|
applyDiscount: () => applyDiscount,
|
|
29
|
+
buildMeterMetadata: () => buildMeterMetadata,
|
|
29
30
|
consoleDestination: () => consoleDestination,
|
|
30
31
|
convertCostUnit: () => convertCostUnit,
|
|
31
32
|
costToNumber: () => costToNumber,
|
|
32
33
|
createBasePriceResolver: () => createBasePriceResolver,
|
|
33
34
|
createDestination: () => createDestination,
|
|
35
|
+
createNarevPriceResolver: () => createNarevPriceResolver,
|
|
34
36
|
createObjectPriceResolver: () => createObjectPriceResolver,
|
|
35
37
|
createV3BillingMiddleware: () => createV3BillingMiddleware,
|
|
36
38
|
multiplyCost: () => multiplyCost,
|
|
37
|
-
rateToCost: () => rateToCost
|
|
39
|
+
rateToCost: () => rateToCost,
|
|
40
|
+
toJSONObject: () => toJSONObject
|
|
38
41
|
});
|
|
39
42
|
module.exports = __toCommonJS(index_exports);
|
|
40
43
|
|
|
@@ -43,6 +46,38 @@ function toJSONObject(event) {
|
|
|
43
46
|
return event;
|
|
44
47
|
}
|
|
45
48
|
|
|
49
|
+
// src/event/to-meter-metadata.ts
|
|
50
|
+
function buildMeterMetadata(event) {
|
|
51
|
+
const u = event.usage ?? {};
|
|
52
|
+
const dimensions = {
|
|
53
|
+
generation_id: event.generationId,
|
|
54
|
+
model_id: event.modelId,
|
|
55
|
+
provider: event.provider
|
|
56
|
+
};
|
|
57
|
+
const addOptional = (key, value) => {
|
|
58
|
+
if (value !== void 0 && value !== null) {
|
|
59
|
+
dimensions[key] = value;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
addOptional("sub_provider_id", u.subProviderId);
|
|
63
|
+
addOptional("input_tokens", u.inputTokens);
|
|
64
|
+
addOptional("output_tokens", u.outputTokens);
|
|
65
|
+
addOptional("total_tokens", u.totalTokens);
|
|
66
|
+
addOptional("reasoning_tokens", u.reasoningTokens);
|
|
67
|
+
addOptional("cache_read_tokens", u.cacheReadTokens);
|
|
68
|
+
addOptional("cache_write_tokens", u.cacheWriteTokens);
|
|
69
|
+
addOptional("request_count", u.requestCount);
|
|
70
|
+
addOptional("raw_provider_cost", u.rawProviderCost);
|
|
71
|
+
addOptional("raw_upstream_inference_cost", u.rawUpstreamInferenceCost);
|
|
72
|
+
if (event.tags) {
|
|
73
|
+
for (const [key, value] of Object.entries(event.tags)) {
|
|
74
|
+
if (value == null) continue;
|
|
75
|
+
dimensions[`tag_${key}`] = typeof value === "object" ? JSON.stringify(value) : value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return dimensions;
|
|
79
|
+
}
|
|
80
|
+
|
|
46
81
|
// src/ai-sdk/language-model-middleware/v3/language-model-v3-base-billing-middleware.ts
|
|
47
82
|
function createV3BillingMiddleware(options) {
|
|
48
83
|
const { buildEvent, destinations, defaultTags, waitUntil, onError } = options;
|
|
@@ -66,7 +101,7 @@ function createV3BillingMiddleware(options) {
|
|
|
66
101
|
providerMetadata,
|
|
67
102
|
tags
|
|
68
103
|
});
|
|
69
|
-
if (event && destinations
|
|
104
|
+
if (event && destinations && destinations?.length > 0) {
|
|
70
105
|
const dispatchDestinationsPromise = Promise.allSettled(
|
|
71
106
|
destinations.map((d) => Promise.resolve(d(event)))
|
|
72
107
|
);
|
|
@@ -331,6 +366,60 @@ function createBasePriceResolver(handler) {
|
|
|
331
366
|
};
|
|
332
367
|
}
|
|
333
368
|
|
|
369
|
+
// src/pricing/narev-price-resolver.ts
|
|
370
|
+
function rowToModelPricing(row) {
|
|
371
|
+
return {
|
|
372
|
+
promptTokens: row["price_prompt"],
|
|
373
|
+
completionTokens: row["price_completion"],
|
|
374
|
+
...row["price_request"] != null && {
|
|
375
|
+
request: row["price_request"]
|
|
376
|
+
},
|
|
377
|
+
...row["price_input_cache_read"] != null && {
|
|
378
|
+
inputCacheReadTokens: row["price_input_cache_read"]
|
|
379
|
+
},
|
|
380
|
+
...row["price_input_cache_write"] != null && {
|
|
381
|
+
inputCacheWriteTokens: row["price_input_cache_write"]
|
|
382
|
+
},
|
|
383
|
+
...row["price_internal_reasoning"] != null && {
|
|
384
|
+
internalReasoningTokens: row["price_internal_reasoning"]
|
|
385
|
+
},
|
|
386
|
+
...row["pricing_discount"] != null && {
|
|
387
|
+
discount: row["pricing_discount"]
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function createNarevPriceResolver({
|
|
392
|
+
apiKey,
|
|
393
|
+
apiUrl = "https://narev.ai"
|
|
394
|
+
}) {
|
|
395
|
+
return createBasePriceResolver(
|
|
396
|
+
async ({
|
|
397
|
+
modelId,
|
|
398
|
+
providerId,
|
|
399
|
+
subProviderId
|
|
400
|
+
}) => {
|
|
401
|
+
const params = new URLSearchParams({ model_id: modelId });
|
|
402
|
+
if (providerId) params.set("gateway", providerId);
|
|
403
|
+
if (subProviderId) params.set("provider", subProviderId);
|
|
404
|
+
const url = `${apiUrl}/api/models/pricing?${params}`;
|
|
405
|
+
const headers = apiKey ? { Authorization: `Bearer ${apiKey}` } : {};
|
|
406
|
+
let data;
|
|
407
|
+
try {
|
|
408
|
+
const res = await fetch(url, { headers });
|
|
409
|
+
if (!res.ok) return void 0;
|
|
410
|
+
data = await res.json();
|
|
411
|
+
} catch {
|
|
412
|
+
return void 0;
|
|
413
|
+
}
|
|
414
|
+
if (!data) return void 0;
|
|
415
|
+
const rows = data[modelId];
|
|
416
|
+
const row = rows?.[0];
|
|
417
|
+
if (!row) return void 0;
|
|
418
|
+
return rowToModelPricing(row);
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
334
423
|
// src/pricing/object-price-resolver.ts
|
|
335
424
|
function createObjectPriceResolver(pricingMap) {
|
|
336
425
|
return createBasePriceResolver(({ modelId }) => {
|
|
@@ -345,14 +434,17 @@ function createObjectPriceResolver(pricingMap) {
|
|
|
345
434
|
AiBillingExtractorError,
|
|
346
435
|
addCosts,
|
|
347
436
|
applyDiscount,
|
|
437
|
+
buildMeterMetadata,
|
|
348
438
|
consoleDestination,
|
|
349
439
|
convertCostUnit,
|
|
350
440
|
costToNumber,
|
|
351
441
|
createBasePriceResolver,
|
|
352
442
|
createDestination,
|
|
443
|
+
createNarevPriceResolver,
|
|
353
444
|
createObjectPriceResolver,
|
|
354
445
|
createV3BillingMiddleware,
|
|
355
446
|
multiplyCost,
|
|
356
|
-
rateToCost
|
|
447
|
+
rateToCost,
|
|
448
|
+
toJSONObject
|
|
357
449
|
});
|
|
358
450
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/event/to-json-object.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/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';\n","import { DefaultTags, BillingEvent } from '../types/index.js';\nimport type { JSONObject } from '@ai-sdk/provider';\n\nexport function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject {\n return event as unknown as JSONObject;\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\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\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.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\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\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\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\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\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\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';\nimport { JSONObject } from '@ai-sdk/provider';\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\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\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\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\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\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\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\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\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;;;ACGO,SAAS,aAAa,OAA8C;AACzE,SAAO;AACT;;;AC0BO,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,aAAa,SAAS,GAAG;AACpC,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;;;ACrKA,IAAM,SAAS;AACf,IAAM,SAAS,OAAO,IAAI,MAAM;AAEzB,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;;;AClCA,IAAM,OAAO;AACb,IAAMC,UAAS,oBAAoB,IAAI;AACvC,IAAMC,UAAS,OAAO,IAAID,OAAM;AAEzB,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;;;ACpBA,IAAME,QAAO;AACb,IAAMC,UAAS,oBAAoBD,KAAI;AACvC,IAAME,UAAS,OAAO,IAAID,OAAM;AAEzB,IAAM,4BAAN,cAAwC,eAAe;AAAA,EAC5D,CAAkBC,OAAM,IAAI;AAAA,EAEnB;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;;;ACzBA,IAAME,QAAO;AACb,IAAMC,UAAS,oBAAoBD,KAAI;AACvC,IAAME,UAAS,OAAO,IAAID,OAAM;AAEzB,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;;;ACbO,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;;;ACbO,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;;;ACXA,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;AAEO,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;AAEO,IAAM,kBAAkB,CAAC,MAAY,eAA+B;AACzE,SAAO;AAAA,IACL,QAAQ,aAAa,MAAM,UAAU;AAAA,IACrC,UAAU,KAAK;AAAA,IACf,MAAM;AAAA,EACR;AACF;AAEO,IAAM,aAAa,CAAC,SAAiB,OAAa;AAAA,EACvD;AAAA,EACA,MAAM;AAAA,EACN,UAAU;AACZ;;;ACrCO,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;AAEO,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;AAEO,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;;;ACzCO,SAAS,wBACd,SAGe;AACf,SAAO,OAAO,YAAkC;AAC9C,WAAO,QAAQ,OAAO;AAAA,EACxB;AACF;;;ACPO,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"],"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\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\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_id', u.subProviderId);\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\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\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\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\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\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\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\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\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';\nimport { JSONObject } from '@ai-sdk/provider';\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\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\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\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\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\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\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\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 { ModelPricing, PriceResolverContext } from '../types/index.js';\n\ntype PricingRow = Record<string, number | string>;\ntype PricingMap = Record<string, PricingRow[]>;\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\nexport type NarevPriceResolverOptions = {\n apiKey: string;\n apiUrl?: string;\n};\n\nexport function createNarevPriceResolver({\n apiKey,\n apiUrl = 'https://narev.ai',\n}: NarevPriceResolverOptions): ReturnType<typeof createBasePriceResolver> {\n return createBasePriceResolver(\n async ({\n modelId,\n providerId,\n subProviderId,\n }: PriceResolverContext): Promise<ModelPricing | undefined> => {\n const params = new URLSearchParams({ model_id: modelId });\n if (providerId) params.set('gateway', providerId);\n if (subProviderId) params.set('provider', subProviderId);\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: PricingMap | null;\n try {\n const res = await fetch(url, { headers });\n if (!res.ok) return undefined;\n data = (await res.json()) as PricingMap | null;\n } catch {\n return undefined;\n }\n\n if (!data) return undefined;\n\n const rows = data[modelId];\n const row = rows?.[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\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"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -12,6 +12,7 @@ interface Usage {
|
|
|
12
12
|
readonly cacheWriteTokens?: number;
|
|
13
13
|
readonly requestCount?: number;
|
|
14
14
|
readonly rawProviderCost?: number;
|
|
15
|
+
readonly rawUpstreamInferenceCost?: number;
|
|
15
16
|
}
|
|
16
17
|
interface BillingEvent<TTags extends DefaultTags = DefaultTags> {
|
|
17
18
|
readonly generationId: string;
|
|
@@ -25,7 +26,7 @@ type EventBuilder<TPayload, TTags extends DefaultTags = DefaultTags> = (payload:
|
|
|
25
26
|
|
|
26
27
|
type DefaultTags = JSONObject;
|
|
27
28
|
interface BaseBillingMiddlewareOptions<TTags extends JSONObject = DefaultTags> {
|
|
28
|
-
destinations
|
|
29
|
+
destinations?: Destination<TTags>[];
|
|
29
30
|
defaultTags?: TTags;
|
|
30
31
|
waitUntil?: (promise: Promise<unknown>) => void;
|
|
31
32
|
onError?: (error: unknown) => void;
|
|
@@ -55,6 +56,23 @@ type PriceResolverContext = {
|
|
|
55
56
|
};
|
|
56
57
|
type PriceResolver = (context: PriceResolverContext) => Promise<ModelPricing | undefined>;
|
|
57
58
|
|
|
59
|
+
interface MeterMetadata {
|
|
60
|
+
generation_id: string;
|
|
61
|
+
model_id: string;
|
|
62
|
+
provider: string;
|
|
63
|
+
sub_provider_id?: string;
|
|
64
|
+
input_tokens?: number;
|
|
65
|
+
output_tokens?: number;
|
|
66
|
+
total_tokens?: number;
|
|
67
|
+
reasoning_tokens?: number;
|
|
68
|
+
cache_read_tokens?: number;
|
|
69
|
+
cache_write_tokens?: number;
|
|
70
|
+
request_count?: number;
|
|
71
|
+
raw_provider_cost?: number;
|
|
72
|
+
raw_upstream_inference_cost?: number;
|
|
73
|
+
[key: string]: string | number | undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
58
76
|
interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {
|
|
59
77
|
responseId: string | undefined;
|
|
60
78
|
model: LanguageModelV3;
|
|
@@ -126,6 +144,16 @@ declare const applyDiscount: (cost: Cost, discount: number) => Cost;
|
|
|
126
144
|
|
|
127
145
|
declare function createBasePriceResolver(handler: (context: PriceResolverContext) => ModelPricing | undefined | Promise<ModelPricing | undefined>): PriceResolver;
|
|
128
146
|
|
|
147
|
+
type NarevPriceResolverOptions = {
|
|
148
|
+
apiKey: string;
|
|
149
|
+
apiUrl?: string;
|
|
150
|
+
};
|
|
151
|
+
declare function createNarevPriceResolver({ apiKey, apiUrl, }: NarevPriceResolverOptions): ReturnType<typeof createBasePriceResolver>;
|
|
152
|
+
|
|
129
153
|
declare function createObjectPriceResolver(pricingMap: Record<string, ModelPricing>): PriceResolver;
|
|
130
154
|
|
|
131
|
-
|
|
155
|
+
declare function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject;
|
|
156
|
+
|
|
157
|
+
declare function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(event: BillingEvent<TTags>): MeterMetadata;
|
|
158
|
+
|
|
159
|
+
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ interface Usage {
|
|
|
12
12
|
readonly cacheWriteTokens?: number;
|
|
13
13
|
readonly requestCount?: number;
|
|
14
14
|
readonly rawProviderCost?: number;
|
|
15
|
+
readonly rawUpstreamInferenceCost?: number;
|
|
15
16
|
}
|
|
16
17
|
interface BillingEvent<TTags extends DefaultTags = DefaultTags> {
|
|
17
18
|
readonly generationId: string;
|
|
@@ -25,7 +26,7 @@ type EventBuilder<TPayload, TTags extends DefaultTags = DefaultTags> = (payload:
|
|
|
25
26
|
|
|
26
27
|
type DefaultTags = JSONObject;
|
|
27
28
|
interface BaseBillingMiddlewareOptions<TTags extends JSONObject = DefaultTags> {
|
|
28
|
-
destinations
|
|
29
|
+
destinations?: Destination<TTags>[];
|
|
29
30
|
defaultTags?: TTags;
|
|
30
31
|
waitUntil?: (promise: Promise<unknown>) => void;
|
|
31
32
|
onError?: (error: unknown) => void;
|
|
@@ -55,6 +56,23 @@ type PriceResolverContext = {
|
|
|
55
56
|
};
|
|
56
57
|
type PriceResolver = (context: PriceResolverContext) => Promise<ModelPricing | undefined>;
|
|
57
58
|
|
|
59
|
+
interface MeterMetadata {
|
|
60
|
+
generation_id: string;
|
|
61
|
+
model_id: string;
|
|
62
|
+
provider: string;
|
|
63
|
+
sub_provider_id?: string;
|
|
64
|
+
input_tokens?: number;
|
|
65
|
+
output_tokens?: number;
|
|
66
|
+
total_tokens?: number;
|
|
67
|
+
reasoning_tokens?: number;
|
|
68
|
+
cache_read_tokens?: number;
|
|
69
|
+
cache_write_tokens?: number;
|
|
70
|
+
request_count?: number;
|
|
71
|
+
raw_provider_cost?: number;
|
|
72
|
+
raw_upstream_inference_cost?: number;
|
|
73
|
+
[key: string]: string | number | undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
58
76
|
interface BuildV3EventPayload<TTags extends DefaultTags = DefaultTags> {
|
|
59
77
|
responseId: string | undefined;
|
|
60
78
|
model: LanguageModelV3;
|
|
@@ -126,6 +144,16 @@ declare const applyDiscount: (cost: Cost, discount: number) => Cost;
|
|
|
126
144
|
|
|
127
145
|
declare function createBasePriceResolver(handler: (context: PriceResolverContext) => ModelPricing | undefined | Promise<ModelPricing | undefined>): PriceResolver;
|
|
128
146
|
|
|
147
|
+
type NarevPriceResolverOptions = {
|
|
148
|
+
apiKey: string;
|
|
149
|
+
apiUrl?: string;
|
|
150
|
+
};
|
|
151
|
+
declare function createNarevPriceResolver({ apiKey, apiUrl, }: NarevPriceResolverOptions): ReturnType<typeof createBasePriceResolver>;
|
|
152
|
+
|
|
129
153
|
declare function createObjectPriceResolver(pricingMap: Record<string, ModelPricing>): PriceResolver;
|
|
130
154
|
|
|
131
|
-
|
|
155
|
+
declare function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject;
|
|
156
|
+
|
|
157
|
+
declare function buildMeterMetadata<TTags extends DefaultTags = DefaultTags>(event: BillingEvent<TTags>): MeterMetadata;
|
|
158
|
+
|
|
159
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,38 @@ function toJSONObject(event) {
|
|
|
3
3
|
return event;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
// src/event/to-meter-metadata.ts
|
|
7
|
+
function buildMeterMetadata(event) {
|
|
8
|
+
const u = event.usage ?? {};
|
|
9
|
+
const dimensions = {
|
|
10
|
+
generation_id: event.generationId,
|
|
11
|
+
model_id: event.modelId,
|
|
12
|
+
provider: event.provider
|
|
13
|
+
};
|
|
14
|
+
const addOptional = (key, value) => {
|
|
15
|
+
if (value !== void 0 && value !== null) {
|
|
16
|
+
dimensions[key] = value;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
addOptional("sub_provider_id", u.subProviderId);
|
|
20
|
+
addOptional("input_tokens", u.inputTokens);
|
|
21
|
+
addOptional("output_tokens", u.outputTokens);
|
|
22
|
+
addOptional("total_tokens", u.totalTokens);
|
|
23
|
+
addOptional("reasoning_tokens", u.reasoningTokens);
|
|
24
|
+
addOptional("cache_read_tokens", u.cacheReadTokens);
|
|
25
|
+
addOptional("cache_write_tokens", u.cacheWriteTokens);
|
|
26
|
+
addOptional("request_count", u.requestCount);
|
|
27
|
+
addOptional("raw_provider_cost", u.rawProviderCost);
|
|
28
|
+
addOptional("raw_upstream_inference_cost", u.rawUpstreamInferenceCost);
|
|
29
|
+
if (event.tags) {
|
|
30
|
+
for (const [key, value] of Object.entries(event.tags)) {
|
|
31
|
+
if (value == null) continue;
|
|
32
|
+
dimensions[`tag_${key}`] = typeof value === "object" ? JSON.stringify(value) : value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return dimensions;
|
|
36
|
+
}
|
|
37
|
+
|
|
6
38
|
// src/ai-sdk/language-model-middleware/v3/language-model-v3-base-billing-middleware.ts
|
|
7
39
|
function createV3BillingMiddleware(options) {
|
|
8
40
|
const { buildEvent, destinations, defaultTags, waitUntil, onError } = options;
|
|
@@ -26,7 +58,7 @@ function createV3BillingMiddleware(options) {
|
|
|
26
58
|
providerMetadata,
|
|
27
59
|
tags
|
|
28
60
|
});
|
|
29
|
-
if (event && destinations
|
|
61
|
+
if (event && destinations && destinations?.length > 0) {
|
|
30
62
|
const dispatchDestinationsPromise = Promise.allSettled(
|
|
31
63
|
destinations.map((d) => Promise.resolve(d(event)))
|
|
32
64
|
);
|
|
@@ -291,6 +323,60 @@ function createBasePriceResolver(handler) {
|
|
|
291
323
|
};
|
|
292
324
|
}
|
|
293
325
|
|
|
326
|
+
// src/pricing/narev-price-resolver.ts
|
|
327
|
+
function rowToModelPricing(row) {
|
|
328
|
+
return {
|
|
329
|
+
promptTokens: row["price_prompt"],
|
|
330
|
+
completionTokens: row["price_completion"],
|
|
331
|
+
...row["price_request"] != null && {
|
|
332
|
+
request: row["price_request"]
|
|
333
|
+
},
|
|
334
|
+
...row["price_input_cache_read"] != null && {
|
|
335
|
+
inputCacheReadTokens: row["price_input_cache_read"]
|
|
336
|
+
},
|
|
337
|
+
...row["price_input_cache_write"] != null && {
|
|
338
|
+
inputCacheWriteTokens: row["price_input_cache_write"]
|
|
339
|
+
},
|
|
340
|
+
...row["price_internal_reasoning"] != null && {
|
|
341
|
+
internalReasoningTokens: row["price_internal_reasoning"]
|
|
342
|
+
},
|
|
343
|
+
...row["pricing_discount"] != null && {
|
|
344
|
+
discount: row["pricing_discount"]
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
function createNarevPriceResolver({
|
|
349
|
+
apiKey,
|
|
350
|
+
apiUrl = "https://narev.ai"
|
|
351
|
+
}) {
|
|
352
|
+
return createBasePriceResolver(
|
|
353
|
+
async ({
|
|
354
|
+
modelId,
|
|
355
|
+
providerId,
|
|
356
|
+
subProviderId
|
|
357
|
+
}) => {
|
|
358
|
+
const params = new URLSearchParams({ model_id: modelId });
|
|
359
|
+
if (providerId) params.set("gateway", providerId);
|
|
360
|
+
if (subProviderId) params.set("provider", subProviderId);
|
|
361
|
+
const url = `${apiUrl}/api/models/pricing?${params}`;
|
|
362
|
+
const headers = apiKey ? { Authorization: `Bearer ${apiKey}` } : {};
|
|
363
|
+
let data;
|
|
364
|
+
try {
|
|
365
|
+
const res = await fetch(url, { headers });
|
|
366
|
+
if (!res.ok) return void 0;
|
|
367
|
+
data = await res.json();
|
|
368
|
+
} catch {
|
|
369
|
+
return void 0;
|
|
370
|
+
}
|
|
371
|
+
if (!data) return void 0;
|
|
372
|
+
const rows = data[modelId];
|
|
373
|
+
const row = rows?.[0];
|
|
374
|
+
if (!row) return void 0;
|
|
375
|
+
return rowToModelPricing(row);
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
294
380
|
// src/pricing/object-price-resolver.ts
|
|
295
381
|
function createObjectPriceResolver(pricingMap) {
|
|
296
382
|
return createBasePriceResolver(({ modelId }) => {
|
|
@@ -304,14 +390,17 @@ export {
|
|
|
304
390
|
AiBillingExtractorError,
|
|
305
391
|
addCosts,
|
|
306
392
|
applyDiscount,
|
|
393
|
+
buildMeterMetadata,
|
|
307
394
|
consoleDestination,
|
|
308
395
|
convertCostUnit,
|
|
309
396
|
costToNumber,
|
|
310
397
|
createBasePriceResolver,
|
|
311
398
|
createDestination,
|
|
399
|
+
createNarevPriceResolver,
|
|
312
400
|
createObjectPriceResolver,
|
|
313
401
|
createV3BillingMiddleware,
|
|
314
402
|
multiplyCost,
|
|
315
|
-
rateToCost
|
|
403
|
+
rateToCost,
|
|
404
|
+
toJSONObject
|
|
316
405
|
};
|
|
317
406
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/event/to-json-object.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/object-price-resolver.ts"],"sourcesContent":["import { DefaultTags, BillingEvent } from '../types/index.js';\nimport type { JSONObject } from '@ai-sdk/provider';\n\nexport function toJSONObject(event: BillingEvent<DefaultTags>): JSONObject {\n return event as unknown as JSONObject;\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\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\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.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\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\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\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\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\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\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';\nimport { JSONObject } from '@ai-sdk/provider';\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\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\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\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\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\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\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\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\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"],"sourcesContent":["import { DefaultTags, BillingEvent } from '../types/index.js';\nimport type { JSONObject } from '@ai-sdk/provider';\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\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_id', u.subProviderId);\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\nexport interface BillingMiddlewareV3Options<\n TTags extends DefaultTags = DefaultTags,\n> extends BaseBillingMiddlewareOptions<TTags> {\n buildEvent: EventBuilder<BuildV3EventPayload<TTags>, TTags>;\n}\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\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\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\nexport class AiBillingDestinationError extends AIBillingError {\n private readonly [symbol] = true;\n\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\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\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';\nimport { JSONObject } from '@ai-sdk/provider';\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\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\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\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\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\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\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\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 { ModelPricing, PriceResolverContext } from '../types/index.js';\n\ntype PricingRow = Record<string, number | string>;\ntype PricingMap = Record<string, PricingRow[]>;\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\nexport type NarevPriceResolverOptions = {\n apiKey: string;\n apiUrl?: string;\n};\n\nexport function createNarevPriceResolver({\n apiKey,\n apiUrl = 'https://narev.ai',\n}: NarevPriceResolverOptions): ReturnType<typeof createBasePriceResolver> {\n return createBasePriceResolver(\n async ({\n modelId,\n providerId,\n subProviderId,\n }: PriceResolverContext): Promise<ModelPricing | undefined> => {\n const params = new URLSearchParams({ model_id: modelId });\n if (providerId) params.set('gateway', providerId);\n if (subProviderId) params.set('provider', subProviderId);\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: PricingMap | null;\n try {\n const res = await fetch(url, { headers });\n if (!res.ok) return undefined;\n data = (await res.json()) as PricingMap | null;\n } catch {\n return undefined;\n }\n\n if (!data) return undefined;\n\n const rows = data[modelId];\n const row = rows?.[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\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-billing/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"typescript": "5.9.2",
|
|
36
36
|
"vitest": "4.1.1",
|
|
37
37
|
"@edge-runtime/vm": "^5.0.0",
|
|
38
|
-
"
|
|
38
|
+
"zod": "^4.3.6",
|
|
39
|
+
"@ai-billing/testing": "0.0.2",
|
|
39
40
|
"@ai-billing/typescript-config": "0.0.1"
|
|
40
41
|
},
|
|
41
42
|
"peerDependencies": {
|