@usebillow/sdk 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{billing-B16zL5xU.d.cts → billing-8ug1Gw05.d.cts} +9 -9
  3. package/dist/{billing-BF4OGaLI.d.ts → billing-Bs10EcjR.d.ts} +9 -9
  4. package/dist/{billing-status-BZQN_gm7.d.cts → billing-status-DZkB0VPK.d.cts} +5 -5
  5. package/dist/{billing-status-BZQN_gm7.d.ts → billing-status-DZkB0VPK.d.ts} +5 -5
  6. package/dist/{chunk-CCG4F5FK.js → chunk-47J7FYM5.js} +2 -2
  7. package/dist/chunk-47J7FYM5.js.map +1 -0
  8. package/dist/{chunk-GT5VBLN5.js → chunk-XUFQG6EA.js} +74 -22
  9. package/dist/chunk-XUFQG6EA.js.map +1 -0
  10. package/dist/config.cjs +3 -3
  11. package/dist/config.cjs.map +1 -1
  12. package/dist/config.d.cts +9 -9
  13. package/dist/config.d.ts +9 -9
  14. package/dist/config.js +3 -3
  15. package/dist/config.js.map +1 -1
  16. package/dist/{hosted-domains-DSTQ1GZz.d.ts → hosted-domains-BrnwkHqq.d.ts} +40 -2
  17. package/dist/{hosted-domains-DwakPG4J.d.cts → hosted-domains-zWm2srOk.d.cts} +40 -2
  18. package/dist/index.cjs +72 -20
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +70 -48
  21. package/dist/index.d.ts +70 -48
  22. package/dist/index.js +2 -2
  23. package/dist/ingestion.cjs.map +1 -1
  24. package/dist/ingestion.d.cts +18 -18
  25. package/dist/ingestion.d.ts +18 -18
  26. package/dist/ingestion.js.map +1 -1
  27. package/dist/react.cjs +28 -5
  28. package/dist/react.cjs.map +1 -1
  29. package/dist/react.d.cts +6 -6
  30. package/dist/react.d.ts +6 -6
  31. package/dist/react.js +2 -2
  32. package/dist/react.js.map +1 -1
  33. package/dist/server.cjs.map +1 -1
  34. package/dist/server.d.cts +11 -11
  35. package/dist/server.d.ts +11 -11
  36. package/dist/server.js.map +1 -1
  37. package/dist/status.cjs.map +1 -1
  38. package/dist/status.d.cts +1 -1
  39. package/dist/status.d.ts +1 -1
  40. package/dist/status.js +1 -1
  41. package/dist/webhooks.cjs.map +1 -1
  42. package/dist/webhooks.d.cts +20 -15
  43. package/dist/webhooks.d.ts +20 -15
  44. package/dist/webhooks.js.map +1 -1
  45. package/package.json +1 -1
  46. package/dist/chunk-CCG4F5FK.js.map +0 -1
  47. package/dist/chunk-GT5VBLN5.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  import { f as SavedPaymentMethod, g as CreateHostedDomainInput, h as PayInvoiceInput } from './index.d-DSEYhV2c.js';
2
2
  export { i as ContractAddSubscriptionItemInput, j as ContractApplySubscriptionCouponInput, k as ContractCancelSubscriptionInput, l as ContractChangeSubscriptionPlanInput, m as ContractCreateChargeInput, n as ContractCreateCustomerInput, o as ContractCreateMerchantInitiatedChargeInput, p as ContractCreatePortalSessionInput, q as ContractCreateProductInput, r as ContractCreateSubscriptionInput, s as ContractCreateWebhookEndpointInput, M as ContractMigrateSubscribersInput, R as ContractRefundChargeInput, t as ContractResolveRefundInput, U as ContractUpdateProductInput, u as ContractUpdateSubscriptionItemInput, v as ContractUpdateWebhookEndpointInput, H as HostedDomain, w as HostedDomainList, I as InvoicePaymentResult } from './index.d-DSEYhV2c.js';
3
- import { C as ChargeStatus, P as PaymentMethodStatus, I as InvoiceStatus, R as RefundStatus, W as WebhookDeliveryStatus } from './billing-status-BZQN_gm7.js';
4
- export { a as CHARGE_STATUSES, b as INVOICE_STATUSES, c as PAYMENT_METHOD_STATUSES, d as REFUND_STATUSES, e as WEBHOOK_DELIVERY_STATUSES } from './billing-status-BZQN_gm7.js';
3
+ import { C as ChargeStatus, P as PaymentMethodStatus, I as InvoiceStatus, R as RefundStatus, W as WebhookDeliveryStatus } from './billing-status-DZkB0VPK.js';
4
+ export { a as CHARGE_STATUSES, b as INVOICE_STATUSES, c as PAYMENT_METHOD_STATUSES, d as REFUND_STATUSES, e as WEBHOOK_DELIVERY_STATUSES } from './billing-status-DZkB0VPK.js';
5
5
  import { SubscriptionStatus } from './status.js';
6
6
  export { ACTIVE_SUBSCRIPTION_STATUSES, NEVER_ACTIVATED_SUBSCRIPTION_STATUSES, SUBSCRIPTION_STATUSES, TERMINAL_SUBSCRIPTION_STATUSES, grantsAccess, isTerminal } from './status.js';
7
- import { c as TaxBehavior, d as Customer, U as UnappliedPaymentReason, e as CreateChargeInput, R as RequestOptions, f as Charge, g as CreateMerchantInitiatedChargeInput, I as IdempotentRequestOptions, h as CallOptions, C as CreateProductInput, i as UpdateProductInput, j as MigrationResult, k as CreateSubscriptionInput, B as BillowOptions, a as CreateCouponInput, l as Coupon, F as FeatureKind, M as MeterConfig, m as Feature, n as UpdateFeatureInput, o as UsageAlert, p as CreateUsageAlertInput, b as CheckResult, T as TrackResult, E as EntitlementView, A as AttachResult } from './billing-BF4OGaLI.js';
8
- export { q as ActivatedSubscriptionResult, r as BillingInterval, s as CouponDuration, t as CouponKind, u as CreateSubscriptionResult, v as EntitlementInput, w as MeterAggregation, x as MeterFilter, y as MeterRoundingMode, z as PendingSubscriptionCheckoutResult, D as PriceInput, P as Product, G as ProductEntitlement, H as ProductPrice, S as Subscription, J as SubscriptionDetail, K as SubscriptionItem, L as UpdatePriceInput, N as UsageAlertKind, O as UsageAlertMetric, Q as UsageModel, V as UsageTier } from './billing-BF4OGaLI.js';
9
- import { a as CreditThresholdLevel, e as CreditGrant, f as CreditTopUp, g as CreditIncludedWindow, h as CreateCreditGrantInput, i as CreditGrantRequestResult, j as CreditPacks, k as CreateCreditPackInput, l as CreditPack, U as UpdateCreditPackInput, m as CreateCreditIncludedRuleInput, n as CreditIncludedRule, o as UpdateCreditIncludedRuleInput, p as CreditIncludedWindowListParams, q as CreateCreditTopUpInput, r as CreditTopUpRequestResult, s as CreditTopUpListParams, t as CreditBalance, u as CreditLedgerEntry, v as CreditUsageParams, w as CreditUsage } from './hosted-domains-DSTQ1GZz.js';
10
- export { x as CreditAccountStatus, y as CreditAllocationInterval, C as CreditGrantKind, z as CreditMoney, A as CreditPackBreakdown, B as CreditPackListItem, D as CreditTopUpStatus, E as CreditTransactionType, F as CreditUsageGroupBy, G as CreditWindowState, H as HostedDomainActivatedData, d as HostedDomainDisabledData, b as HostedDomainDnsFailingData, I as HostedDomainEventBase, c as HostedDomainReassignmentPendingData, J as HostedDomainStatus, K as HostedDomainStatusReason, L as IncludedCredits, M as IncludedPeriod } from './hosted-domains-DSTQ1GZz.js';
7
+ import { c as TaxBehavior, d as Customer, U as UnappliedPaymentReason, e as CreateChargeInput, R as RequestOptions, f as Charge, g as CreateMerchantInitiatedChargeInput, I as IdempotentRequestOptions, h as CallOptions, C as CreateProductInput, i as UpdateProductInput, j as MigrationResult, k as CreateSubscriptionInput, B as BillowOptions, a as CreateCouponInput, l as Coupon, F as FeatureKind, M as MeterConfig, m as Feature, n as UpdateFeatureInput, o as UsageAlert, p as CreateUsageAlertInput, b as CheckResult, T as TrackResult, E as EntitlementView, A as AttachResult } from './billing-Bs10EcjR.js';
8
+ export { q as ActivatedSubscriptionResult, r as BillingInterval, s as CouponDuration, t as CouponKind, u as CreateSubscriptionResult, v as EntitlementInput, w as MeterAggregation, x as MeterFilter, y as MeterRoundingMode, z as PendingSubscriptionCheckoutResult, D as PriceInput, P as Product, G as ProductEntitlement, H as ProductPrice, S as Subscription, J as SubscriptionDetail, K as SubscriptionItem, L as UpdatePriceInput, N as UsageAlertKind, O as UsageAlertMetric, Q as UsageModel, V as UsageTier } from './billing-Bs10EcjR.js';
9
+ import { a as CreditThresholdLevel, e as CreditGrant, f as CreditTopUp, g as CreditIncludedWindow, h as CreateCreditGrantInput, i as CreditGrantRequestResult, j as CreditAccount, k as CreditPacks, l as CreateCreditPackInput, m as CreditPack, U as UpdateCreditPackInput, n as CreateCreditIncludedRuleInput, o as CreditIncludedRule, p as UpdateCreditIncludedRuleInput, q as CreditIncludedWindowListParams, r as CreateCreditTopUpInput, s as CreditTopUpRequestResult, t as CreditTopUpListParams, u as CreditBalance, v as CreditLedgerEntry, w as CreditUsageParams, x as CreditUsage } from './hosted-domains-BrnwkHqq.js';
10
+ export { y as CreditAccountStatus, z as CreditAllocationInterval, C as CreditGrantKind, A as CreditMoney, B as CreditPackBreakdown, D as CreditPackListItem, E as CreditTopUpStatus, F as CreditTransactionType, G as CreditUsageGroupBy, I as CreditWindowState, H as HostedDomainActivatedData, d as HostedDomainDisabledData, b as HostedDomainDnsFailingData, J as HostedDomainEventBase, c as HostedDomainReassignmentPendingData, K as HostedDomainStatus, L as HostedDomainStatusReason, M as IncludedCredits, N as IncludedPeriod } from './hosted-domains-BrnwkHqq.js';
11
11
  import 'zod';
12
12
 
13
13
  /**
14
14
  * The machine-readable error codes billow returns on `BillowApiError.code`. Mirrored from
15
- * `@billow/core`'s `BILLOW_ERROR_CODES` (the server's source of truth) — the SDK carries no
15
+ * `@billow/core`'s `BILLOW_ERROR_CODES` (the server's source of truth) - the SDK carries no
16
16
  * runtime dependency on core, so `error-codes.test.ts` asserts this list stays in lockstep.
17
17
  *
18
18
  * `switch` on these for programmatic handling (e.g. surface `rate_limited` vs `validation_error`
@@ -98,7 +98,7 @@ interface ProviderCredentialSummary {
98
98
  currency: string;
99
99
  config: Record<string, unknown>;
100
100
  }
101
- /** The editable view of one credential set — secret values are never returned. */
101
+ /** The editable view of one credential set - secret values are never returned. */
102
102
  interface CredentialSet {
103
103
  provider: string;
104
104
  currency: string;
@@ -134,7 +134,7 @@ interface BusinessProfile {
134
134
  logoUrl: string | null;
135
135
  /** Brand/accent color as `#RRGGBB` (PRD-11); null = billow's default accent. */
136
136
  brandColor: string | null;
137
- /** Org-default tax treatment (Phase E) — every taxable price inherits this. */
137
+ /** Org-default tax treatment (Phase E) - every taxable price inherits this. */
138
138
  taxEnabled: boolean;
139
139
  /** Default rate in basis points (1% = 100 bps), e.g. 1400 for Egypt's 14% VAT. */
140
140
  taxRateBps: number;
@@ -234,7 +234,7 @@ interface Paginated<T> {
234
234
  * size), so it is correct under concurrent inserts/deletes; a list that grows at its head pages
235
235
  * by cursor instead ({@link CursorListPromise}). The caller's {@link CallOptions} (`signal` /
236
236
  * `timeoutMs`) apply to EVERY page
237
- * fetch — an abort stops the walk mid-stream; `timeoutMs` is per page.
237
+ * fetch - an abort stops the walk mid-stream; `timeoutMs` is per page.
238
238
  *
239
239
  * A returned value is ONE walk: page 1 is cached on it (so `await` then `for await` on the same
240
240
  * value fetch page 1 once), which means iterating the same value again later reuses that first
@@ -353,7 +353,7 @@ interface CustomerUsage {
353
353
  allowance: number | null;
354
354
  /** Gross units used this period (sum of positive events in the period). */
355
355
  used: number;
356
- /** Units topped up this period — gross credit-backs (negative events). */
356
+ /** Units topped up this period - gross credit-backs (negative events). */
357
357
  added: number;
358
358
  /** Remaining = allowance + added − used; null = unlimited. May be negative (overage). */
359
359
  remaining: number | null;
@@ -431,7 +431,7 @@ interface SubscriptionListItem {
431
431
  scheduledChange: ScheduledSubscriptionChange | null;
432
432
  /** Renewals left before a limited-term subscription ends; null = open-ended. */
433
433
  remainingCycles: number | null;
434
- /** Failed-renewal retries run so far (PRD-06 dunning) — 0 until a renewal fails. */
434
+ /** Failed-renewal retries run so far (PRD-06 dunning) - 0 until a renewal fails. */
435
435
  dunningAttempts: number;
436
436
  /** ISO-8601 time the next dunning retry is due; null when not in dunning (PRD-09). */
437
437
  nextDunningAt: string | null;
@@ -471,7 +471,7 @@ interface EmailTemplateSetting {
471
471
  defaultSubject: string;
472
472
  /** The variables the subject/message may reference (without braces). */
473
473
  variables: string[];
474
- /** False for compliance-required templates (the receipt) — can't be disabled. */
474
+ /** False for compliance-required templates (the receipt) - can't be disabled. */
475
475
  canDisable: boolean;
476
476
  /** Subject override, or null when the default is in effect. */
477
477
  subject: string | null;
@@ -580,7 +580,7 @@ interface InvoiceListItem {
580
580
  currency: string;
581
581
  customerExternalId: string;
582
582
  subscriptionId: string | null;
583
- /** What the invoice is for — the plan name (subscriptions) or first line item. */
583
+ /** What the invoice is for - the plan name (subscriptions) or first line item. */
584
584
  reason: string | null;
585
585
  periodStart: string | null;
586
586
  periodEnd: string | null;
@@ -633,7 +633,7 @@ interface MetricsOverview {
633
633
  to: string;
634
634
  /** Monthly recurring revenue (minor units). */
635
635
  mrr: number;
636
- /** Annual recurring revenue (minor units) — `mrr × 12`. */
636
+ /** Annual recurring revenue (minor units) - `mrr × 12`. */
637
637
  arr: number;
638
638
  /** Cohort subscription churn over the window (0..1); null if none were active at its start. */
639
639
  churnRate: number | null;
@@ -697,7 +697,7 @@ interface Whoami {
697
697
  organizationId: string;
698
698
  organizationName: string | null;
699
699
  organizationSlug: string | null;
700
- /** The billing workspace the API key scopes to — what every resource belongs to. */
700
+ /** The billing workspace the API key scopes to - what every resource belongs to. */
701
701
  projectId: string;
702
702
  projectName: string | null;
703
703
  projectSlug: string | null;
@@ -925,7 +925,7 @@ interface CreatePortalSessionInput {
925
925
  customerId: string;
926
926
  /** Which surface to land on; defaults to the self-serve portal. */
927
927
  flow?: PortalSessionFlow;
928
- /** Product slug to subscribe to — required when `flow` is `checkout`. */
928
+ /** Product slug to subscribe to - required when `flow` is `checkout`. */
929
929
  productId?: string;
930
930
  /**
931
931
  * Where the surface returns the Customer when they finish or exit: an absolute `https` URL
@@ -943,7 +943,7 @@ interface PortalSession {
943
943
  id: string;
944
944
  url: string;
945
945
  flow: PortalSessionFlow;
946
- /** ISO-8601 expiry — the session (and its URL) stop working after this. */
946
+ /** ISO-8601 expiry - the session (and its URL) stop working after this. */
947
947
  expiresAt: string;
948
948
  }
949
949
  /** The single-use entry exchange's input (`BillowPortal.exchange`). */
@@ -1015,7 +1015,7 @@ interface PortalPlanChange {
1015
1015
  subscription: PortalSubscriptionStatus;
1016
1016
  /** Upgrade only: the proration invoice raised for the prorated delta, when non-zero. */
1017
1017
  prorationInvoiceId?: string;
1018
- /** Upgrade only: the proration charge's status (`succeeded`/`failed`/`processing`/`pending`) —
1018
+ /** Upgrade only: the proration charge's status (`succeeded`/`failed`/`processing`/`pending`) -
1019
1019
  * present when an immediate charge was raised, so a client can surface an unresolved payment. */
1020
1020
  chargeStatus?: string;
1021
1021
  }
@@ -1314,9 +1314,9 @@ interface WebhookEndpoint {
1314
1314
  createdAt: string;
1315
1315
  updatedAt: string;
1316
1316
  }
1317
- /** Returned once at create/rotate — carries the plaintext signing secret. */
1317
+ /** Returned once at create/rotate - carries the plaintext signing secret. */
1318
1318
  interface WebhookEndpointWithSecret extends WebhookEndpoint {
1319
- /** The HMAC signing secret — shown exactly once. Store it now; it is never listed again. */
1319
+ /** The HMAC signing secret - shown exactly once. Store it now; it is never listed again. */
1320
1320
  secret: string;
1321
1321
  }
1322
1322
  interface CreateWebhookEndpointInput {
@@ -1357,15 +1357,20 @@ declare class BillowApiError extends Error {
1357
1357
  readonly code: BillowErrorCode | (string & {});
1358
1358
  /** Structured error context from the server (e.g. per-field validation issues), when present. */
1359
1359
  readonly details?: unknown;
1360
- /** billow's per-request id (`x-request-id`) — quote it in a bug report to trace the server log. */
1360
+ /** billow's per-request id (`x-request-id`) - quote it in a bug report to trace the server log. */
1361
1361
  readonly requestId?: string | undefined;
1362
- constructor(status: number, code: BillowErrorCode | (string & {}), message: string, details?: unknown, requestId?: string);
1362
+ /**
1363
+ * How many seconds to wait before trying again, from the response's `Retry-After` header (sent
1364
+ * with a `429 rate_limited`); undefined when the response did not say.
1365
+ */
1366
+ readonly retryAfterSeconds?: number | undefined;
1367
+ constructor(status: number, code: BillowErrorCode | (string & {}), message: string, details?: unknown, requestId?: string, retryAfterSeconds?: number);
1363
1368
  }
1364
1369
  /** Everything a request needs: the transport, the base URL, the bearer, and resilience knobs. */
1365
1370
  interface RequestContext {
1366
1371
  fetch: typeof fetch;
1367
1372
  baseUrl: string;
1368
- /** The bearer — a secret/publishable API key, or a portal-session token. */
1373
+ /** The bearer - a secret/publishable API key, or a portal-session token. */
1369
1374
  bearer: string;
1370
1375
  timeoutMs: number;
1371
1376
  maxRetries: number;
@@ -1461,6 +1466,23 @@ declare function createCreditsResource(ctx: RequestContext): {
1461
1466
  */
1462
1467
  create: (input: CreateCreditGrantInput, options: IdempotentRequestOptions) => Promise<CreditGrantRequestResult>;
1463
1468
  };
1469
+ accounts: {
1470
+ /**
1471
+ * Freeze a customer's Credit Account (by external id): it takes no new reservations - a
1472
+ * reserve throws `account_frozen` (423) - until unfrozen, while holds already made still
1473
+ * commit and release, and grants, top-ups, reversals and included credits still fund it.
1474
+ * Safe to retry: freezing a frozen account changes nothing and answers `changed: false`. A
1475
+ * customer with no account yet gets one, frozen. Throws `account_closed` (409) for an erased
1476
+ * customer.
1477
+ */
1478
+ freeze: (customer: string, options?: CallOptions) => Promise<CreditAccount>;
1479
+ /**
1480
+ * Unfreeze a customer's Credit Account (by external id): it takes reservations again. Safe to
1481
+ * retry: unfreezing an account that is not frozen changes nothing and answers
1482
+ * `changed: false`.
1483
+ */
1484
+ unfreeze: (customer: string, options?: CallOptions) => Promise<CreditAccount>;
1485
+ };
1464
1486
  packs: {
1465
1487
  /**
1466
1488
  * The Credit Packs a customer can buy in `currency` (ISO 4217), cheapest first: credits and
@@ -2005,7 +2027,7 @@ declare function createInvoicesResource(ctx: RequestContext): {
2005
2027
  receipt: (id: string, options?: CallOptions) => Promise<ArrayBuffer>;
2006
2028
  };
2007
2029
 
2008
- /** The marketplace Integration catalog — install / configure / toggle / uninstall (ADR-0008). */
2030
+ /** The marketplace Integration catalog - install / configure / toggle / uninstall (ADR-0008). */
2009
2031
  declare function createMarketplaceResource(ctx: RequestContext): {
2010
2032
  /** Every available Integration with this tenant's install state (no secret values). */
2011
2033
  catalog: (options?: CallOptions) => Promise<CatalogItem[]>;
@@ -2210,7 +2232,7 @@ declare function createProductsResource(ctx: RequestContext): {
2210
2232
  };
2211
2233
 
2212
2234
  /**
2213
- * Organization settings (Phase D3, F) — the configurable dunning schedule, usage settlement grace,
2235
+ * Organization settings (Phase D3, F) - the configurable dunning schedule, usage settlement grace,
2214
2236
  * the cross-currency reporting currency + FX-rate registry (ADR-0013), and transactional email
2215
2237
  * template overrides (PRD-10). All secret-key/server-side surface.
2216
2238
  */
@@ -2229,7 +2251,7 @@ declare function createSettingsResource(ctx: RequestContext): {
2229
2251
  };
2230
2252
  /**
2231
2253
  * Usage settlement grace (hours): defers *collection* of a boundary-adjacent priced
2232
- * calendar-meter renewal past the tz month boundary until late usage settles — the billed
2254
+ * calendar-meter renewal past the tz month boundary until late usage settles - the billed
2233
2255
  * windows/amount are unchanged, only the invoice timing shifts. `0` disables it (the default);
2234
2256
  * a no-op for any subscription without a priced calendar meter. Cap 72h.
2235
2257
  */
@@ -2421,7 +2443,7 @@ declare function createSubscriptionsResource(ctx: RequestContext): {
2421
2443
  productSlug: string;
2422
2444
  productMetadata: Record<string, string>;
2423
2445
  } | null>;
2424
- /** Cancel — immediately, or at period end with `{ atPeriodEnd: true }`. */
2446
+ /** Cancel - immediately, or at period end with `{ atPeriodEnd: true }`. */
2425
2447
  cancel: (id: string, opts?: {
2426
2448
  atPeriodEnd?: boolean;
2427
2449
  }) => Promise<{
@@ -2530,7 +2552,7 @@ declare function createSubscriptionsResource(ctx: RequestContext): {
2530
2552
  couponId: string;
2531
2553
  cyclesRemaining: number | null;
2532
2554
  }>;
2533
- /** Change plan — immediate prorated upgrade, or downgrade scheduled for period end. `productId` accepts the product's id or slug. */
2555
+ /** Change plan - immediate prorated upgrade, or downgrade scheduled for period end. `productId` accepts the product's id or slug. */
2534
2556
  changePlan: (id: string, productId: string) => Promise<{
2535
2557
  id: string;
2536
2558
  status: "active" | "incomplete" | "incomplete_expired" | "trialing" | "past_due" | "paused" | "canceled" | "unpaid";
@@ -2638,14 +2660,14 @@ declare function createWebhookEndpointsResource(ctx: RequestContext): {
2638
2660
  update: (id: string, input: UpdateWebhookEndpointInput) => Promise<WebhookEndpoint>;
2639
2661
  /** Delete an endpoint and its delivery history. */
2640
2662
  delete: (id: string) => Promise<void>;
2641
- /** Rotate the signing secret — the new plaintext is returned once. */
2663
+ /** Rotate the signing secret - the new plaintext is returned once. */
2642
2664
  rotateSecret: (id: string) => Promise<WebhookEndpointWithSecret>;
2643
2665
  /** List delivery attempts for an endpoint (newest first). Auto-paginating. */
2644
2666
  deliveries: (id: string, params?: ListParams, options?: CallOptions) => ListPromise<WebhookDelivery>;
2645
2667
  };
2646
2668
 
2647
2669
  /**
2648
- * billow client SDK — the "two lines of code" surface, mirroring Autumn's shape
2670
+ * billow client SDK - the "two lines of code" surface, mirroring Autumn's shape
2649
2671
  * (CONTEXT/ARCHITECTURE §10). A thin typed wrapper over the billow REST API.
2650
2672
  *
2651
2673
  * const billow = new Billow(process.env.BILLOW_SECRET_KEY!);
@@ -2684,7 +2706,7 @@ declare class Billow {
2684
2706
  /** Custom domains for the hosted customer portal (live keys, behind a rollout flag). */
2685
2707
  hostedDomains: ReturnType<typeof createHostedDomainsResource>;
2686
2708
  /**
2687
- * Organization settings (Phase D3, F) — the configurable dunning schedule, usage settlement grace,
2709
+ * Organization settings (Phase D3, F) - the configurable dunning schedule, usage settlement grace,
2688
2710
  * and the cross-currency reporting currency + FX-rate registry (ADR-0013).
2689
2711
  */
2690
2712
  settings: ReturnType<typeof createSettingsResource>;
@@ -2692,12 +2714,12 @@ declare class Billow {
2692
2714
  coupons: {
2693
2715
  /** Define a coupon (a reusable discount template). */
2694
2716
  create: (input: CreateCouponInput) => Promise<Coupon>;
2695
- /** List coupons (secret key only — enumerates live promo codes). Auto-paginating. */
2717
+ /** List coupons (secret key only - enumerates live promo codes). Auto-paginating. */
2696
2718
  list: (params?: ListParams, options?: CallOptions) => ListPromise<Coupon>;
2697
2719
  /** Deactivate a coupon (existing discounts keep running). */
2698
2720
  deactivate: (id: string) => Promise<Coupon>;
2699
2721
  };
2700
- /** Manage developer webhook endpoints — register, rotate secrets, inspect deliveries.
2722
+ /** Manage developer webhook endpoints - register, rotate secrets, inspect deliveries.
2701
2723
  * (To VERIFY incoming deliveries, import `constructEvent` from `@usebillow/sdk/webhooks`.) */
2702
2724
  features: {
2703
2725
  /** Define a feature (a boolean access gate, or a metered feature with a meter). */
@@ -2708,7 +2730,7 @@ declare class Billow {
2708
2730
  meter?: MeterConfig;
2709
2731
  }) => Promise<Feature>;
2710
2732
  /**
2711
- * Edit a feature in place: its `name`, and — for a metered feature — its `meter`
2733
+ * Edit a feature in place: its `name`, and - for a metered feature - its `meter`
2712
2734
  * aggregation. The server refuses a meter change once usage has been recorded (it
2713
2735
  * would rewrite billed history), so set the meter right at create time or before you
2714
2736
  * start tracking. Returns the updated feature.
@@ -2742,7 +2764,7 @@ declare class Billow {
2742
2764
  * choose a credential set and `target` to probe one verify target (Paymob: a
2743
2765
  * method); pass `sampleToken` (SANDBOX ONLY) to run a functional sub-test.
2744
2766
  * This probe hits the provider's live API (mutates nothing here), so it takes a
2745
- * per-call {@link CallOptions} for a timeout / cancellation — `opts` is spread into
2767
+ * per-call {@link CallOptions} for a timeout / cancellation - `opts` is spread into
2746
2768
  * the body, so `options` stays a separate trailing arg (never merged in).
2747
2769
  */
2748
2770
  verify: (provider: string, opts?: {
@@ -2762,7 +2784,7 @@ declare class Billow {
2762
2784
  }>;
2763
2785
  };
2764
2786
  };
2765
- /** The merchant's business identity — the seller block on documents and email from-name. */
2787
+ /** The merchant's business identity - the seller block on documents and email from-name. */
2766
2788
  businessProfile: {
2767
2789
  /** The stored profile, or null if one was never saved. */
2768
2790
  get: (options?: CallOptions) => Promise<BusinessProfile | null>;
@@ -2771,11 +2793,11 @@ declare class Billow {
2771
2793
  };
2772
2794
  /**
2773
2795
  * Hosted customer surfaces (Phase G, ADR-0014). Mint a portal session for one of
2774
- * your signed-in users and redirect them to the returned `url` — the self-serve
2796
+ * your signed-in users and redirect them to the returned `url` - the self-serve
2775
2797
  * portal, or a `checkout` hand-off for `productId`. The Customer's own calls go
2776
2798
  * through {@link BillowPortal}, constructed with the session token.
2777
2799
  */
2778
- /** Identity of this key's tenant — org, environment, configured currencies. */
2800
+ /** Identity of this key's tenant - org, environment, configured currencies. */
2779
2801
  me(options?: CallOptions): Promise<Whoami>;
2780
2802
  /**
2781
2803
  * Global search (PRD-12) across customers, invoices, subscriptions, and charges
@@ -2785,7 +2807,7 @@ declare class Billow {
2785
2807
  search(q: string, limit?: number, options?: CallOptions): Promise<SearchResults>;
2786
2808
  /**
2787
2809
  * Gate access to a feature. `featureId` is the feature slug. Returns
2788
- * `{ allowed, balance }` — `balance` is `null` for unlimited/boolean features.
2810
+ * `{ allowed, balance }` - `balance` is `null` for unlimited/boolean features.
2789
2811
  */
2790
2812
  check(input: {
2791
2813
  customerId: string;
@@ -2793,14 +2815,14 @@ declare class Billow {
2793
2815
  }, options?: CallOptions): Promise<CheckResult>;
2794
2816
  /**
2795
2817
  * Record usage of a metered feature (`value` defaults to 1; negative credits
2796
- * back). Pass `idempotencyKey` to make a retried call a no-op — which also makes the call
2818
+ * back). Pass `idempotencyKey` to make a retried call a no-op - which also makes the call
2797
2819
  * safe to retry automatically when `maxRetries` is set.
2798
2820
  */
2799
2821
  track(input: {
2800
2822
  customerId: string;
2801
2823
  featureId: string;
2802
2824
  value?: number;
2803
- /** Arbitrary event properties — used by meter filters and property-based aggregations. */
2825
+ /** Arbitrary event properties - used by meter filters and property-based aggregations. */
2804
2826
  properties?: Record<string, string | number>;
2805
2827
  idempotencyKey?: string;
2806
2828
  /**
@@ -2820,7 +2842,7 @@ declare class Billow {
2820
2842
  /**
2821
2843
  * The browser-safe client: construct it with a **publishable** key (`bl_<env>_pk_…`)
2822
2844
  * to read the public catalog from any origin (CORS-enabled). It exposes ONLY public,
2823
- * project-scoped reads — products and their prices — so it is safe to ship in a
2845
+ * project-scoped reads - products and their prices - so it is safe to ship in a
2824
2846
  * frontend bundle. Customer-scoped data (entitlements, checkout) is never reachable
2825
2847
  * with a publishable key; use the server handler or a portal session for that.
2826
2848
  */
@@ -2828,7 +2850,7 @@ declare class BillowPublishable {
2828
2850
  #private;
2829
2851
  constructor(publishableKey: string, opts?: BillowOptions);
2830
2852
  products: {
2831
- /** The active catalog — products and their prices, for a pricing table. */
2853
+ /** The active catalog - products and their prices, for a pricing table. */
2832
2854
  list: (options?: CallOptions) => Promise<{
2833
2855
  id: string;
2834
2856
  slug: string;
@@ -2905,13 +2927,13 @@ declare class BillowPublishable {
2905
2927
  /**
2906
2928
  * The customer-surface client (Phase G, ADR-0014): construct it with a portal
2907
2929
  * session token (minted by your backend via `billow.portalSessions.create`) to act
2908
- * as that one Customer. It exposes only their own data — no operator/secret-key
2909
- * surface — so the token can be held by a hosted portal app safely.
2930
+ * as that one Customer. It exposes only their own data - no operator/secret-key
2931
+ * surface - so the token can be held by a hosted portal app safely.
2910
2932
  */
2911
2933
  declare class BillowPortal {
2912
2934
  #private;
2913
2935
  constructor(sessionToken: string, opts?: BillowOptions);
2914
- /** The portal shell: flow, return URL, merchant brand, and customer identity —
2936
+ /** The portal shell: flow, return URL, merchant brand, and customer identity -
2915
2937
  * the lightweight payload the hosting app frames every page with, and the
2916
2938
  * validate-and-route check at login. */
2917
2939
  session(options?: CallOptions): Promise<PortalSessionInfo>;
@@ -3002,4 +3024,4 @@ declare class BillowPortal {
3002
3024
  };
3003
3025
  }
3004
3026
 
3005
- export { AttachResult, BILLOW_ERROR_CODES, Billow, BillowApiError, type BillowErrorCode, BillowOptions, BillowPortal, BillowPublishable, type BusinessProfile, CallOptions, type CatalogItem, Charge, type ChargeListItem, type ChargeListParams, type ChargeSearchHit, ChargeStatus, CheckResult, type CheckoutMethodInfo, type ConfigField, type ConfigFieldOption, type ConfigFieldType, Coupon, CreateChargeInput, CreateCouponInput, CreateCreditGrantInput, CreateCreditIncludedRuleInput, CreateCreditPackInput, type CreateCreditQuoteInput, type CreateCreditReservationInput, CreateCreditTopUpInput, CreateHostedDomainInput, CreateMerchantInitiatedChargeInput, type CreatePortalSessionInput, CreateProductInput, CreateSubscriptionInput, CreateUsageAlertInput, type CreateWebhookEndpointInput, type CredentialSet, CreditBalance, type CreditDimensions, CreditGrant, CreditGrantRequestResult, CreditIncludedRule, CreditIncludedWindow, CreditIncludedWindowListParams, CreditLedgerEntry, type CreditLineItem, CreditPack, CreditPacks, type CreditPricedLine, type CreditQuote, type CreditRateCard, type CreditRateCardItem, type CreditReservation, type CreditReservationListParams, type CreditReservationPage, type CreditReservationRequestResult, type CreditReservationStatus, type CreditReversal, type CreditReversalRequestResult, CreditThresholdLevel, CreditTopUp, CreditTopUpListParams, CreditTopUpRequestResult, CreditUsage, CreditUsageParams, type CursorListParams, type CursorListPromise, type CursorPaginated, Customer, type CustomerAnonymizationResult, type CustomerCreditsExport, type CustomerDataExport, type CustomerListItem, type CustomerListParams, type CustomerOverview, type CustomerSearchHit, type CustomerUsage, type CustomerUsageDetail, type EmailDeliveryListItem, type EmailDeliveryListParams, type EmailDeliveryStatus, type EmailTemplateSetting, EntitlementView, type ExchangeRate, type ExportJsonValue, type ExternalPaymentMethod, type ExternalPaymentResult, Feature, FeatureKind, IdempotentRequestOptions, type InboundWebhookListItem, type InboundWebhookListParams, type InboundWebhookOutcome, type IntegrationDefinition, type IntegrationKind, type IntegrationTier, type Invoice, type InvoiceDetail, type InvoiceLineItem, type InvoiceListItem, type InvoiceListParams, type InvoiceSearchHit, InvoiceStatus, type ListParams, type ListPromise, MeterConfig, type MetricsOverview, type MetricsParams, type MetricsRollup, MigrationResult, type OutboxEventListItem, type OutboxEventListParams, type OutboxEventStatus, type Paginated, PayInvoiceInput, type PaymentMethod, PaymentMethodStatus, type PaymentProviderDefinition, type PortalCardSetupResult, type PortalCheckout, type PortalPlanChange, type PortalSession, type PortalSessionExchange, type PortalSessionExchangeInput, type PortalSessionFlow, type PortalSessionInfo, type PortalSubscriptionStatus, type PortalView, type ProviderCredentialSummary, type ProviderVerifyResult, type ProviderVerifyTarget, type ProviderVerifyTargetResult, type PublishCreditRateCardInput, type RecordExternalPaymentInput, type Refund, type RefundChargeInput, type RefundRequestResult, type RefundReviewReason, RefundStatus, RequestOptions, type ResolveRefundInput, type ReverseCreditConsumptionInput, SavedPaymentMethod, type ScheduledSubscriptionChange, type SearchResults, type SubscriptionListItem, type SubscriptionListParams, type SubscriptionSearchHit, SubscriptionStatus, TaxBehavior, type TimeseriesInterval, type TimeseriesMetric, type TimeseriesParams, type TimeseriesPoint, type TimeseriesResult, TrackResult, UnappliedPaymentReason, type UpdateBusinessProfileInput, UpdateCreditIncludedRuleInput, UpdateCreditPackInput, type UpdateEmailTemplateInput, UpdateFeatureInput, UpdateProductInput, type UpdateWebhookEndpointInput, type UpsertCredentialsInput, UsageAlert, type WebhookDelivery, WebhookDeliveryStatus, type WebhookEndpoint, type WebhookEndpointWithSecret, type Whoami, currencyExponent, formatMoney, isSecretField, toMajorUnits, toMinorUnits };
3027
+ export { AttachResult, BILLOW_ERROR_CODES, Billow, BillowApiError, type BillowErrorCode, BillowOptions, BillowPortal, BillowPublishable, type BusinessProfile, CallOptions, type CatalogItem, Charge, type ChargeListItem, type ChargeListParams, type ChargeSearchHit, ChargeStatus, CheckResult, type CheckoutMethodInfo, type ConfigField, type ConfigFieldOption, type ConfigFieldType, Coupon, CreateChargeInput, CreateCouponInput, CreateCreditGrantInput, CreateCreditIncludedRuleInput, CreateCreditPackInput, type CreateCreditQuoteInput, type CreateCreditReservationInput, CreateCreditTopUpInput, CreateHostedDomainInput, CreateMerchantInitiatedChargeInput, type CreatePortalSessionInput, CreateProductInput, CreateSubscriptionInput, CreateUsageAlertInput, type CreateWebhookEndpointInput, type CredentialSet, CreditAccount, CreditBalance, type CreditDimensions, CreditGrant, CreditGrantRequestResult, CreditIncludedRule, CreditIncludedWindow, CreditIncludedWindowListParams, CreditLedgerEntry, type CreditLineItem, CreditPack, CreditPacks, type CreditPricedLine, type CreditQuote, type CreditRateCard, type CreditRateCardItem, type CreditReservation, type CreditReservationListParams, type CreditReservationPage, type CreditReservationRequestResult, type CreditReservationStatus, type CreditReversal, type CreditReversalRequestResult, CreditThresholdLevel, CreditTopUp, CreditTopUpListParams, CreditTopUpRequestResult, CreditUsage, CreditUsageParams, type CursorListParams, type CursorListPromise, type CursorPaginated, Customer, type CustomerAnonymizationResult, type CustomerCreditsExport, type CustomerDataExport, type CustomerListItem, type CustomerListParams, type CustomerOverview, type CustomerSearchHit, type CustomerUsage, type CustomerUsageDetail, type EmailDeliveryListItem, type EmailDeliveryListParams, type EmailDeliveryStatus, type EmailTemplateSetting, EntitlementView, type ExchangeRate, type ExportJsonValue, type ExternalPaymentMethod, type ExternalPaymentResult, Feature, FeatureKind, IdempotentRequestOptions, type InboundWebhookListItem, type InboundWebhookListParams, type InboundWebhookOutcome, type IntegrationDefinition, type IntegrationKind, type IntegrationTier, type Invoice, type InvoiceDetail, type InvoiceLineItem, type InvoiceListItem, type InvoiceListParams, type InvoiceSearchHit, InvoiceStatus, type ListParams, type ListPromise, MeterConfig, type MetricsOverview, type MetricsParams, type MetricsRollup, MigrationResult, type OutboxEventListItem, type OutboxEventListParams, type OutboxEventStatus, type Paginated, PayInvoiceInput, type PaymentMethod, PaymentMethodStatus, type PaymentProviderDefinition, type PortalCardSetupResult, type PortalCheckout, type PortalPlanChange, type PortalSession, type PortalSessionExchange, type PortalSessionExchangeInput, type PortalSessionFlow, type PortalSessionInfo, type PortalSubscriptionStatus, type PortalView, type ProviderCredentialSummary, type ProviderVerifyResult, type ProviderVerifyTarget, type ProviderVerifyTargetResult, type PublishCreditRateCardInput, type RecordExternalPaymentInput, type Refund, type RefundChargeInput, type RefundRequestResult, type RefundReviewReason, RefundStatus, RequestOptions, type ResolveRefundInput, type ReverseCreditConsumptionInput, SavedPaymentMethod, type ScheduledSubscriptionChange, type SearchResults, type SubscriptionListItem, type SubscriptionListParams, type SubscriptionSearchHit, SubscriptionStatus, TaxBehavior, type TimeseriesInterval, type TimeseriesMetric, type TimeseriesParams, type TimeseriesPoint, type TimeseriesResult, TrackResult, UnappliedPaymentReason, type UpdateBusinessProfileInput, UpdateCreditIncludedRuleInput, UpdateCreditPackInput, type UpdateEmailTemplateInput, UpdateFeatureInput, UpdateProductInput, type UpdateWebhookEndpointInput, type UpsertCredentialsInput, UsageAlert, type WebhookDelivery, WebhookDeliveryStatus, type WebhookEndpoint, type WebhookEndpointWithSecret, type Whoami, currencyExponent, formatMoney, isSecretField, toMajorUnits, toMinorUnits };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { BILLOW_ERROR_CODES, Billow, BillowApiError, BillowPortal, BillowPublishable, currencyExponent, formatMoney, isSecretField, toMajorUnits, toMinorUnits } from './chunk-GT5VBLN5.js';
2
- export { ACTIVE_SUBSCRIPTION_STATUSES, CHARGE_STATUSES, INVOICE_STATUSES, NEVER_ACTIVATED_SUBSCRIPTION_STATUSES, PAYMENT_METHOD_STATUSES, REFUND_STATUSES, SUBSCRIPTION_STATUSES, TERMINAL_SUBSCRIPTION_STATUSES, WEBHOOK_DELIVERY_STATUSES, grantsAccess, isTerminal } from './chunk-CCG4F5FK.js';
1
+ export { BILLOW_ERROR_CODES, Billow, BillowApiError, BillowPortal, BillowPublishable, currencyExponent, formatMoney, isSecretField, toMajorUnits, toMinorUnits } from './chunk-XUFQG6EA.js';
2
+ export { ACTIVE_SUBSCRIPTION_STATUSES, CHARGE_STATUSES, INVOICE_STATUSES, NEVER_ACTIVATED_SUBSCRIPTION_STATUSES, PAYMENT_METHOD_STATUSES, REFUND_STATUSES, SUBSCRIPTION_STATUSES, TERMINAL_SUBSCRIPTION_STATUSES, WEBHOOK_DELIVERY_STATUSES, grantsAccess, isTerminal } from './chunk-47J7FYM5.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ingestion.ts"],"names":[],"mappings":"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","file":"ingestion.cjs","sourcesContent":["/**\n * Auto-metering (PRD-16): ingestion strategies that call billow's `track()` for you,\n * so you never hand-instrument usage.\n *\n * Two layers:\n * 1. A generic primitive — {@link createUsageMeter} + {@link meterFunction} — a\n * non-blocking, buffered, idempotent dispatcher you can point at ANY usage\n * source (an S3 upload, a job run, a DB write).\n * 2. LLM strategies built on it — {@link meterOpenAI} (OpenAI-compatible clients)\n * and {@link meterAIResult} (Vercel AI SDK) that auto-count prompt+completion\n * tokens from the provider's own response (never re-tokenizing).\n *\n * Posture (every strategy): SERVER-SIDE ONLY — a browser can't be trusted to\n * self-report usage — and NON-BLOCKING: metering is a side effect that can never\n * delay or break the wrapped call. A failed `track()` buffers and retries under an\n * idempotency key; if it ultimately fails it is dropped (via `onError`), never thrown.\n *\n * import { Billow } from \"@usebillow/sdk\";\n * import { createUsageMeter, meterOpenAI } from \"@usebillow/sdk/ingestion\";\n *\n * const billow = new Billow(process.env.BILLOW_SECRET_KEY!);\n * const meter = createUsageMeter(billow);\n * const openai = meterOpenAI(new OpenAI(), {\n * meter,\n * feature: \"tokens\",\n * customer: (params) => String(params.user), // your billow customer id\n * });\n * // use `openai` exactly as before — every completion auto-meters its tokens.\n */\n\nimport type { Billow } from \"./index\";\n\n/** One usage event handed to `track()`. Mirrors {@link Billow.track}'s input. */\nexport interface UsageRecord {\n customerId: string;\n featureId: string;\n /** Units to record (the engine defaults to 1). */\n value?: number;\n /** Event properties for meter filters / property-based aggregations. */\n properties?: Record<string, string | number>;\n /**\n * Dedup key. Auto-generated per record when omitted, so a retried dispatch is a\n * no-op — set it yourself to dedupe across process restarts.\n */\n idempotencyKey?: string;\n}\n\n/** The minimal client the meter needs — the real {@link Billow} satisfies it. */\nexport type TrackClient = Pick<Billow, \"track\">;\n\nexport interface MeterOptions {\n /** Max dispatch attempts for one record before it's dropped (default 5). */\n maxAttempts?: number;\n /** Base retry backoff in ms; doubles each attempt (default 250). */\n retryBaseMs?: number;\n /** Called once when a record is permanently dropped after exhausting retries. */\n onError?: (error: unknown, record: UsageRecord) => void;\n}\n\n/**\n * A buffered, non-blocking dispatcher to `track()`. `record()` returns immediately\n * and never throws; delivery (with retries under an idempotency key) happens in the\n * background. Call {@link UsageMeter.flush} before a serverless handler returns so\n * pending records aren't lost when the process freezes.\n */\nexport interface UsageMeter {\n /** Enqueue a usage event. Returns immediately, never throws. */\n record(record: UsageRecord): void;\n /**\n * Enqueue a usage event whose record resolves LATER (e.g. a streamed response\n * whose token totals arrive as a promise). Registers the pending work immediately\n * so {@link UsageMeter.flush} awaits it — a `null` resolution or a rejected source\n * is dropped. Returns immediately, never throws.\n */\n recordAsync(source: Promise<UsageRecord | null>): void;\n /** Resolve once every buffered dispatch has settled (delivered or dropped). */\n flush(): Promise<void>;\n /** Records still in flight (queued or retrying). */\n readonly pending: number;\n}\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\nconst DEFAULT_RETRY_BASE_MS = 250;\n\nfunction newIdempotencyKey(): string {\n return crypto.randomUUID();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Build a {@link UsageMeter} bound to a billow client (or any `{ track }`). */\nexport function createUsageMeter(client: TrackClient, options: MeterOptions = {}): UsageMeter {\n const maxAttempts = Math.max(1, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n const retryBaseMs = Math.max(0, options.retryBaseMs ?? DEFAULT_RETRY_BASE_MS);\n const inFlight = new Set<Promise<void>>();\n\n async function dispatch(record: UsageRecord): Promise<void> {\n // Freeze one idempotency key for the record so every retry is the SAME call.\n const input: UsageRecord = {\n ...record,\n idempotencyKey: record.idempotencyKey ?? newIdempotencyKey(),\n };\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n await client.track(input);\n return;\n } catch (error) {\n lastError = error;\n if (attempt < maxAttempts) await sleep(retryBaseMs * 2 ** (attempt - 1));\n }\n }\n try {\n options.onError?.(lastError, input);\n } catch {\n // A throwing onError must not reject the tracked dispatch (which would make\n // flush() reject) — the meter's contract is that it never throws.\n }\n }\n\n /** Register a unit of metering work so `flush()`/`pending` account for it. */\n function track(work: Promise<void>): void {\n const p = work.finally(() => {\n inFlight.delete(p);\n });\n inFlight.add(p);\n }\n\n return {\n record(record) {\n track(dispatch(record));\n },\n recordAsync(source) {\n // Chain resolve-then-dispatch into ONE tracked unit so flush() covers work\n // whose record isn't known yet. A null record or a rejected source is dropped.\n track(\n source.then(\n (record) => (record ? dispatch(record) : undefined),\n () => undefined,\n ),\n );\n },\n flush() {\n return Promise.all([...inFlight]).then(() => undefined);\n },\n get pending() {\n return inFlight.size;\n },\n };\n}\n\n/**\n * Derive a usage record from a completed call. Return `null` to skip metering it\n * (e.g. a cache hit with no billable usage). Receives the resolved result and the\n * original call arguments.\n */\nexport type UsageExtractor<A extends unknown[], R> = (result: R, args: A) => UsageRecord | null;\n\n/**\n * Wrap any async function so each successful call auto-records usage via `meter` —\n * the generic ingestion primitive. Point it at any source by supplying an `extract`.\n * Metering runs AFTER the call resolves and never blocks it; an extractor that\n * throws is swallowed. If the wrapped call itself rejects, nothing is recorded and\n * the error propagates unchanged.\n */\nexport function meterFunction<A extends unknown[], R>(\n fn: (...args: A) => Promise<R>,\n meter: UsageMeter,\n extract: UsageExtractor<A, R>,\n): (...args: A) => Promise<R> {\n return async (...args: A) => {\n const result = await fn(...args);\n try {\n const record = extract(result, args);\n if (record) meter.record(record);\n } catch {\n // Metering must never break the wrapped call — drop extractor errors.\n }\n return result;\n };\n}\n\n/**\n * Yield every value of `source` straight through to the consumer while calling\n * `onValue` for each and `onDone` when iteration finishes (including an early\n * `break`/`return` — it runs in a `finally`). Taps a stream WITHOUT consuming it:\n * the caller still receives every chunk. Tap callbacks that throw are swallowed so\n * they can't break the stream.\n */\nexport async function* tapAsyncIterable<T>(\n source: AsyncIterable<T>,\n taps: { onValue?: (value: T) => void; onDone?: () => void },\n): AsyncGenerator<T> {\n try {\n for await (const value of source) {\n try {\n taps.onValue?.(value);\n } catch {\n // never let a tap break the passthrough\n }\n yield value;\n }\n } finally {\n try {\n taps.onDone?.();\n } catch {\n // never let a tap break the passthrough\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// LLM token metering\n// ---------------------------------------------------------------------------\n\n/** Normalized token counts, whatever the provider's field naming. */\nexport interface TokenCounts {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\n/** Which token count a meter records as its `value` (default `\"total\"`). */\nexport type TokenCount = \"total\" | \"prompt\" | \"completion\";\n\nfunction firstNumber(...values: unknown[]): number | null {\n for (const v of values) if (typeof v === \"number\" && Number.isFinite(v)) return v;\n return null;\n}\n\n/**\n * Read token counts from a provider usage object, accepting OpenAI (`prompt_tokens`\n * / `completion_tokens` / `total_tokens`), Vercel AI SDK v4 (`promptTokens` / …) and\n * v5 (`inputTokens` / `outputTokens`) shapes. Returns `null` when no token fields\n * are present. `totalTokens` is derived from prompt+completion when not supplied.\n */\nexport function normalizeTokenUsage(usage: unknown): TokenCounts | null {\n if (typeof usage !== \"object\" || usage === null) return null;\n const u = usage as {\n prompt_tokens?: unknown;\n promptTokens?: unknown;\n inputTokens?: unknown;\n completion_tokens?: unknown;\n completionTokens?: unknown;\n outputTokens?: unknown;\n total_tokens?: unknown;\n totalTokens?: unknown;\n };\n const prompt = firstNumber(u.prompt_tokens, u.promptTokens, u.inputTokens);\n const completion = firstNumber(u.completion_tokens, u.completionTokens, u.outputTokens);\n const total = firstNumber(u.total_tokens, u.totalTokens);\n if (prompt === null && completion === null && total === null) return null;\n const promptTokens = prompt ?? 0;\n const completionTokens = completion ?? 0;\n return {\n promptTokens,\n completionTokens,\n totalTokens: total ?? promptTokens + completionTokens,\n };\n}\n\nfunction pickCount(counts: TokenCounts, which: TokenCount): number {\n if (which === \"prompt\") return counts.promptTokens;\n if (which === \"completion\") return counts.completionTokens;\n return counts.totalTokens;\n}\n\n/** A value supplied directly, or resolved from a call's params. */\ntype Resolvable<T, P> = T | ((params: P) => T);\n\nfunction resolveValue<T, P>(r: Resolvable<T, P>, params: P): T {\n return typeof r === \"function\" ? (r as (p: P) => T)(params) : r;\n}\n\nexport interface MeterLLMOptions<P = unknown> {\n /** The buffered meter that dispatches to `track()`. */\n meter: UsageMeter;\n /** The metered feature (token meter) id — static, or resolved per call. */\n feature: Resolvable<string, P>;\n /**\n * The billow customer to bill. Static for single-tenant, or resolved per call\n * (e.g. from the OpenAI `user` param) for multi-tenant. Returning `null`/`undefined`\n * skips metering that call — there's no customer to attribute it to.\n */\n customer: Resolvable<string | null | undefined, P>;\n /** Which token count to record as the meter value (default `\"total\"`). */\n count?: TokenCount;\n /** Extra event properties merged onto each record (`model` is added automatically). */\n properties?: (params: P, tokens: TokenCounts) => Record<string, string | number>;\n}\n\n/**\n * Build the usage record for one LLM call from its usage + model, or `null` to skip.\n * TOTAL by contract — a throwing `customer`/`feature`/`properties` resolver (e.g. an\n * unexpected params shape) drops the record rather than surfacing in the wrapped\n * call, so every caller (sync or async) inherits the non-blocking guarantee here.\n */\nfunction buildTokenRecord<P>(\n options: MeterLLMOptions<P>,\n params: P,\n usage: unknown,\n model: unknown,\n): UsageRecord | null {\n const counts = normalizeTokenUsage(usage);\n if (!counts) return null;\n try {\n const customerId = resolveValue(options.customer, params);\n if (!customerId) return null;\n const properties: Record<string, string | number> = {\n tokens_prompt: counts.promptTokens,\n tokens_completion: counts.completionTokens,\n tokens_total: counts.totalTokens,\n ...(typeof model === \"string\" ? { model } : {}),\n ...options.properties?.(params, counts),\n };\n return {\n customerId,\n featureId: resolveValue(options.feature, params),\n value: pickCount(counts, options.count ?? \"total\"),\n properties,\n };\n } catch {\n return null; // a resolver mistake must never break the wrapped call\n }\n}\n\nfunction isPromiseLike(v: unknown): v is Promise<unknown> {\n return (\n (typeof v === \"object\" || typeof v === \"function\") &&\n v !== null &&\n typeof (v as { then?: unknown }).then === \"function\"\n );\n}\n\n/** The two params slots an OpenAI-style `create(body, requestOptions?)` takes. */\ntype CreateArgs = [params: Record<string, unknown>, ...rest: unknown[]];\n\nfunction wrapOpenAICreate(\n create: (...args: unknown[]) => unknown,\n thisArg: unknown,\n options: MeterLLMOptions<Record<string, unknown>>,\n): (...args: CreateArgs) => unknown {\n return (params, ...rest) => {\n const returned = Reflect.apply(create, thisArg, [params, ...rest]);\n // openai-node returns a thenable (APIPromise) for BOTH streaming and not.\n if (!isPromiseLike(returned)) return returned;\n\n if ((params as { stream?: unknown }).stream === true) {\n // Streaming: TAP iteration to read the usage the final chunk carries (present\n // when the caller sets `stream_options.include_usage`) WITHOUT dropping the\n // OpenAI return contract — the APIPromise keeps its helpers and the resolved\n // Stream keeps its methods; we only override `Symbol.asyncIterator`.\n return proxyResolved(returned, (stream) =>\n typeof stream === \"object\" && stream !== null\n ? proxyAsyncIterable(stream, () =>\n tapOpenAIStream(stream as AsyncIterable<unknown>, params, options),\n )\n : stream,\n );\n }\n // Non-streaming: record from the resolved completion's `.usage`, tracked by the\n // meter so `flush()` awaits it. The caller receives the ORIGINAL promise\n // untouched (APIPromise helpers intact); a failed call resolves to no record.\n options.meter.recordAsync(returned.then((resp) => completionRecord(resp, params, options)));\n return returned;\n };\n}\n\nfunction completionRecord(\n resp: unknown,\n params: Record<string, unknown>,\n options: MeterLLMOptions<Record<string, unknown>>,\n): UsageRecord | null {\n if (typeof resp !== \"object\" || resp === null) return null;\n const r = resp as { usage?: unknown; model?: unknown };\n return buildTokenRecord(options, params, r.usage, r.model);\n}\n\n/**\n * Proxy a thenable so awaiting it yields `map(resolvedValue)`, while every other\n * property/method (an APIPromise's `.withResponse()`/`.asResponse()`, …) passes\n * straight through. Lets us tap the resolved value without dropping the return\n * contract.\n */\nfunction proxyResolved(\n source: Promise<unknown>,\n map: (value: unknown) => unknown,\n): Promise<unknown> {\n const mappedThen = (onF?: (v: unknown) => unknown, onR?: (e: unknown) => unknown) =>\n source.then((v) => (onF ? onF(map(v)) : map(v)), onR);\n return new Proxy(source, {\n get(target, prop) {\n // Route `then`/`catch`/`finally` through the mapping so awaiting via ANY of\n // them yields the tapped value — binding the native methods to `target` would\n // resolve the raw (un-tapped) stream and silently skip metering.\n if (prop === \"then\") return mappedThen;\n if (prop === \"catch\") return (onR: (e: unknown) => unknown) => mappedThen(undefined, onR);\n if (prop === \"finally\") {\n return (cb?: () => void) =>\n mappedThen(\n (v) => {\n cb?.();\n return v;\n },\n (e) => {\n cb?.();\n throw e;\n },\n );\n }\n const value = Reflect.get(target, prop);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n }) as Promise<unknown>;\n}\n\n/**\n * Proxy an async-iterable object so `for await` runs `makeIterator()` (our tap),\n * while every other property/method (a Stream's `.tee()`, `.toReadableStream()`, …)\n * passes straight through. Taps iteration WITHOUT replacing the object.\n */\nfunction proxyAsyncIterable(source: object, makeIterator: () => AsyncIterator<unknown>): object {\n return new Proxy(source, {\n get(target, prop) {\n if (prop === Symbol.asyncIterator) return makeIterator;\n const value = Reflect.get(target, prop);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n}\n\n/** Usage + model folded out of a streamed response, ready for {@link buildTokenRecord}. */\ninterface StreamUsage {\n usage?: unknown;\n model?: unknown;\n}\n\n/**\n * Meter a streamed response: tap the stream (yielding every chunk untouched), fold\n * each chunk into an accumulator via `reduce`, and record ONE usage event when\n * iteration finishes. This is the reusable middle between the generic\n * {@link tapAsyncIterable} and a specific provider's chunk shape — a new streaming\n * source (Anthropic SSE, etc.) plugs in by supplying only its `reduce`.\n */\nfunction meterStream<C, P>(\n stream: AsyncIterable<C>,\n params: P,\n options: MeterLLMOptions<P>,\n reduce: (chunk: C, acc: StreamUsage) => void,\n): AsyncGenerator<C> {\n const acc: StreamUsage = {};\n return tapAsyncIterable(stream, {\n onValue: (chunk) => reduce(chunk, acc),\n onDone: () => {\n const record = buildTokenRecord(options, params, acc.usage, acc.model);\n if (record) options.meter.record(record);\n },\n });\n}\n\nfunction tapOpenAIStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n options: MeterLLMOptions<Record<string, unknown>>,\n): AsyncGenerator<unknown> {\n return meterStream(stream, params, options, (chunk, acc) => {\n if (typeof chunk !== \"object\" || chunk === null) return;\n const c = chunk as { usage?: unknown; model?: unknown };\n if (c.usage) acc.usage = c.usage; // the final chunk carries usage (include_usage)\n if (c.model && acc.model === undefined) acc.model = c.model;\n });\n}\n\n/**\n * Wrap an OpenAI-compatible client so every `chat.completions.create` call\n * auto-meters its token usage. Returns a proxy of the SAME type — use it exactly as\n * before; every other property/method passes straight through untouched.\n *\n * Reads the token count from the provider's own response (no re-tokenizing), for\n * both blocking and streaming calls. For a STREAMED call, pass\n * `stream_options: { include_usage: true }` so the final chunk carries usage —\n * otherwise a streamed call can't be metered (billow never mutates your request).\n *\n * A streamed response is metered when consumed the standard way: `await` the call,\n * then `for await` the stream. The `Stream` helpers (`.tee()`, `.toReadableStream()`)\n * and the un-awaited `APIPromise` helpers (`.withResponse()`, `.asResponse()`) are\n * PRESERVED (they keep working), but consuming through them bypasses the iteration\n * tap, so those calls are not token-metered.\n *\n * Works with any client exposing `chat.completions.create` returning a `.usage`\n * shape: OpenAI, Azure OpenAI, Together, Groq, OpenRouter, and other compatibles.\n *\n * const openai = meterOpenAI(new OpenAI(), { meter, feature: \"tokens\", customer });\n * const res = await openai.chat.completions.create({ model, messages }); // metered\n */\nexport function meterOpenAI<T extends object>(\n client: T,\n options: MeterLLMOptions<Record<string, unknown>>,\n): T {\n const root = client as { chat?: { completions?: { create?: unknown } } };\n const completions = root.chat?.completions;\n const create = completions?.create;\n if (typeof create !== \"function\" || !completions) {\n throw new TypeError(\"meterOpenAI: expected client.chat.completions.create to be a function\");\n }\n const wrapped = wrapOpenAICreate(create as (...args: unknown[]) => unknown, completions, options);\n return replaceCreate(client, wrapped);\n}\n\n/**\n * Return a non-mutating proxy of `client` that swaps ONLY `chat.completions.create`\n * for `wrapped`, passing every other access straight through. Untouched methods keep\n * their real receiver, so `this` stays correct.\n */\nfunction replaceCreate<T extends object>(client: T, wrapped: (...args: CreateArgs) => unknown): T {\n const root = client as { chat: { completions: object } };\n const completionsProxy = new Proxy(root.chat.completions, {\n get: (t, p, r) => (p === \"create\" ? wrapped : Reflect.get(t, p, r)),\n });\n const chatProxy = new Proxy(root.chat, {\n get: (t, p, r) => (p === \"completions\" ? completionsProxy : Reflect.get(t, p, r)),\n });\n return new Proxy(client, {\n get: (t, p, r) => (p === \"chat\" ? chatProxy : Reflect.get(t, p, r)),\n });\n}\n\n/**\n * Meter a Vercel AI SDK result (the object `generateText`/`streamText` resolves to).\n * Reads `result.usage` — an object (`generateText`) or a Promise (`streamText`) — and\n * records the token count, non-blocking. Never touches `result.textStream`, so a\n * streamed response is delivered to your consumer untouched. Accepts AI SDK v4\n * (`promptTokens`/`completionTokens`) and v5 (`inputTokens`/`outputTokens`) shapes.\n *\n * const result = streamText({ model, prompt });\n * meterAIResult(result, { meter, feature: \"tokens\", customer: customerId });\n * return result.toDataStreamResponse();\n */\nexport function meterAIResult(\n result: { usage?: unknown; response?: unknown },\n options: MeterLLMOptions<void>,\n): void {\n const model = extractAIModel(result.response);\n const usage = result.usage;\n if (isPromiseLike(usage)) {\n // `streamText` resolves usage LATE — hand the meter the whole resolve→record\n // chain so `flush()` (the README's serverless guidance) awaits it instead of\n // snapshotting an empty in-flight set and dropping the usage.\n options.meter.recordAsync(usage.then((u) => buildTokenRecord(options, undefined, u, model)));\n return;\n }\n const record = buildTokenRecord(options, undefined, usage, model);\n if (record) options.meter.record(record);\n}\n\n/** Best-effort model id from an AI SDK result's `response` (skipped if it's a promise). */\nfunction extractAIModel(response: unknown): unknown {\n if (typeof response !== \"object\" || response === null) return undefined;\n const m = (response as { modelId?: unknown }).modelId;\n return typeof m === \"string\" ? m : undefined;\n}\n"]}
1
+ {"version":3,"sources":["../src/ingestion.ts"],"names":[],"mappings":"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","file":"ingestion.cjs","sourcesContent":["/**\n * Auto-metering (PRD-16): ingestion strategies that call billow's `track()` for you,\n * so you never hand-instrument usage.\n *\n * Two layers:\n * 1. A generic primitive - {@link createUsageMeter} + {@link meterFunction} - a\n * non-blocking, buffered, idempotent dispatcher you can point at ANY usage\n * source (an S3 upload, a job run, a DB write).\n * 2. LLM strategies built on it - {@link meterOpenAI} (OpenAI-compatible clients)\n * and {@link meterAIResult} (Vercel AI SDK) that auto-count prompt+completion\n * tokens from the provider's own response (never re-tokenizing).\n *\n * Posture (every strategy): SERVER-SIDE ONLY - a browser can't be trusted to\n * self-report usage - and NON-BLOCKING: metering is a side effect that can never\n * delay or break the wrapped call. A failed `track()` buffers and retries under an\n * idempotency key; if it ultimately fails it is dropped (via `onError`), never thrown.\n *\n * import { Billow } from \"@usebillow/sdk\";\n * import { createUsageMeter, meterOpenAI } from \"@usebillow/sdk/ingestion\";\n *\n * const billow = new Billow(process.env.BILLOW_SECRET_KEY!);\n * const meter = createUsageMeter(billow);\n * const openai = meterOpenAI(new OpenAI(), {\n * meter,\n * feature: \"tokens\",\n * customer: (params) => String(params.user), // your billow customer id\n * });\n * // use `openai` exactly as before - every completion auto-meters its tokens.\n */\n\nimport type { Billow } from \"./index\";\n\n/** One usage event handed to `track()`. Mirrors {@link Billow.track}'s input. */\nexport interface UsageRecord {\n customerId: string;\n featureId: string;\n /** Units to record (the engine defaults to 1). */\n value?: number;\n /** Event properties for meter filters / property-based aggregations. */\n properties?: Record<string, string | number>;\n /**\n * Dedup key. Auto-generated per record when omitted, so a retried dispatch is a\n * no-op - set it yourself to dedupe across process restarts.\n */\n idempotencyKey?: string;\n}\n\n/** The minimal client the meter needs - the real {@link Billow} satisfies it. */\nexport type TrackClient = Pick<Billow, \"track\">;\n\nexport interface MeterOptions {\n /** Max dispatch attempts for one record before it's dropped (default 5). */\n maxAttempts?: number;\n /** Base retry backoff in ms; doubles each attempt (default 250). */\n retryBaseMs?: number;\n /** Called once when a record is permanently dropped after exhausting retries. */\n onError?: (error: unknown, record: UsageRecord) => void;\n}\n\n/**\n * A buffered, non-blocking dispatcher to `track()`. `record()` returns immediately\n * and never throws; delivery (with retries under an idempotency key) happens in the\n * background. Call {@link UsageMeter.flush} before a serverless handler returns so\n * pending records aren't lost when the process freezes.\n */\nexport interface UsageMeter {\n /** Enqueue a usage event. Returns immediately, never throws. */\n record(record: UsageRecord): void;\n /**\n * Enqueue a usage event whose record resolves LATER (e.g. a streamed response\n * whose token totals arrive as a promise). Registers the pending work immediately\n * so {@link UsageMeter.flush} awaits it - a `null` resolution or a rejected source\n * is dropped. Returns immediately, never throws.\n */\n recordAsync(source: Promise<UsageRecord | null>): void;\n /** Resolve once every buffered dispatch has settled (delivered or dropped). */\n flush(): Promise<void>;\n /** Records still in flight (queued or retrying). */\n readonly pending: number;\n}\n\nconst DEFAULT_MAX_ATTEMPTS = 5;\nconst DEFAULT_RETRY_BASE_MS = 250;\n\nfunction newIdempotencyKey(): string {\n return crypto.randomUUID();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Build a {@link UsageMeter} bound to a billow client (or any `{ track }`). */\nexport function createUsageMeter(client: TrackClient, options: MeterOptions = {}): UsageMeter {\n const maxAttempts = Math.max(1, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n const retryBaseMs = Math.max(0, options.retryBaseMs ?? DEFAULT_RETRY_BASE_MS);\n const inFlight = new Set<Promise<void>>();\n\n async function dispatch(record: UsageRecord): Promise<void> {\n // Freeze one idempotency key for the record so every retry is the SAME call.\n const input: UsageRecord = {\n ...record,\n idempotencyKey: record.idempotencyKey ?? newIdempotencyKey(),\n };\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n await client.track(input);\n return;\n } catch (error) {\n lastError = error;\n if (attempt < maxAttempts) await sleep(retryBaseMs * 2 ** (attempt - 1));\n }\n }\n try {\n options.onError?.(lastError, input);\n } catch {\n // A throwing onError must not reject the tracked dispatch (which would make\n // flush() reject) - the meter's contract is that it never throws.\n }\n }\n\n /** Register a unit of metering work so `flush()`/`pending` account for it. */\n function track(work: Promise<void>): void {\n const p = work.finally(() => {\n inFlight.delete(p);\n });\n inFlight.add(p);\n }\n\n return {\n record(record) {\n track(dispatch(record));\n },\n recordAsync(source) {\n // Chain resolve-then-dispatch into ONE tracked unit so flush() covers work\n // whose record isn't known yet. A null record or a rejected source is dropped.\n track(\n source.then(\n (record) => (record ? dispatch(record) : undefined),\n () => undefined,\n ),\n );\n },\n flush() {\n return Promise.all([...inFlight]).then(() => undefined);\n },\n get pending() {\n return inFlight.size;\n },\n };\n}\n\n/**\n * Derive a usage record from a completed call. Return `null` to skip metering it\n * (e.g. a cache hit with no billable usage). Receives the resolved result and the\n * original call arguments.\n */\nexport type UsageExtractor<A extends unknown[], R> = (result: R, args: A) => UsageRecord | null;\n\n/**\n * Wrap any async function so each successful call auto-records usage via `meter` -\n * the generic ingestion primitive. Point it at any source by supplying an `extract`.\n * Metering runs AFTER the call resolves and never blocks it; an extractor that\n * throws is swallowed. If the wrapped call itself rejects, nothing is recorded and\n * the error propagates unchanged.\n */\nexport function meterFunction<A extends unknown[], R>(\n fn: (...args: A) => Promise<R>,\n meter: UsageMeter,\n extract: UsageExtractor<A, R>,\n): (...args: A) => Promise<R> {\n return async (...args: A) => {\n const result = await fn(...args);\n try {\n const record = extract(result, args);\n if (record) meter.record(record);\n } catch {\n // Metering must never break the wrapped call - drop extractor errors.\n }\n return result;\n };\n}\n\n/**\n * Yield every value of `source` straight through to the consumer while calling\n * `onValue` for each and `onDone` when iteration finishes (including an early\n * `break`/`return` - it runs in a `finally`). Taps a stream WITHOUT consuming it:\n * the caller still receives every chunk. Tap callbacks that throw are swallowed so\n * they can't break the stream.\n */\nexport async function* tapAsyncIterable<T>(\n source: AsyncIterable<T>,\n taps: { onValue?: (value: T) => void; onDone?: () => void },\n): AsyncGenerator<T> {\n try {\n for await (const value of source) {\n try {\n taps.onValue?.(value);\n } catch {\n // never let a tap break the passthrough\n }\n yield value;\n }\n } finally {\n try {\n taps.onDone?.();\n } catch {\n // never let a tap break the passthrough\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// LLM token metering\n// ---------------------------------------------------------------------------\n\n/** Normalized token counts, whatever the provider's field naming. */\nexport interface TokenCounts {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n}\n\n/** Which token count a meter records as its `value` (default `\"total\"`). */\nexport type TokenCount = \"total\" | \"prompt\" | \"completion\";\n\nfunction firstNumber(...values: unknown[]): number | null {\n for (const v of values) if (typeof v === \"number\" && Number.isFinite(v)) return v;\n return null;\n}\n\n/**\n * Read token counts from a provider usage object, accepting OpenAI (`prompt_tokens`\n * / `completion_tokens` / `total_tokens`), Vercel AI SDK v4 (`promptTokens` / …) and\n * v5 (`inputTokens` / `outputTokens`) shapes. Returns `null` when no token fields\n * are present. `totalTokens` is derived from prompt+completion when not supplied.\n */\nexport function normalizeTokenUsage(usage: unknown): TokenCounts | null {\n if (typeof usage !== \"object\" || usage === null) return null;\n const u = usage as {\n prompt_tokens?: unknown;\n promptTokens?: unknown;\n inputTokens?: unknown;\n completion_tokens?: unknown;\n completionTokens?: unknown;\n outputTokens?: unknown;\n total_tokens?: unknown;\n totalTokens?: unknown;\n };\n const prompt = firstNumber(u.prompt_tokens, u.promptTokens, u.inputTokens);\n const completion = firstNumber(u.completion_tokens, u.completionTokens, u.outputTokens);\n const total = firstNumber(u.total_tokens, u.totalTokens);\n if (prompt === null && completion === null && total === null) return null;\n const promptTokens = prompt ?? 0;\n const completionTokens = completion ?? 0;\n return {\n promptTokens,\n completionTokens,\n totalTokens: total ?? promptTokens + completionTokens,\n };\n}\n\nfunction pickCount(counts: TokenCounts, which: TokenCount): number {\n if (which === \"prompt\") return counts.promptTokens;\n if (which === \"completion\") return counts.completionTokens;\n return counts.totalTokens;\n}\n\n/** A value supplied directly, or resolved from a call's params. */\ntype Resolvable<T, P> = T | ((params: P) => T);\n\nfunction resolveValue<T, P>(r: Resolvable<T, P>, params: P): T {\n return typeof r === \"function\" ? (r as (p: P) => T)(params) : r;\n}\n\nexport interface MeterLLMOptions<P = unknown> {\n /** The buffered meter that dispatches to `track()`. */\n meter: UsageMeter;\n /** The metered feature (token meter) id - static, or resolved per call. */\n feature: Resolvable<string, P>;\n /**\n * The billow customer to bill. Static for single-tenant, or resolved per call\n * (e.g. from the OpenAI `user` param) for multi-tenant. Returning `null`/`undefined`\n * skips metering that call - there's no customer to attribute it to.\n */\n customer: Resolvable<string | null | undefined, P>;\n /** Which token count to record as the meter value (default `\"total\"`). */\n count?: TokenCount;\n /** Extra event properties merged onto each record (`model` is added automatically). */\n properties?: (params: P, tokens: TokenCounts) => Record<string, string | number>;\n}\n\n/**\n * Build the usage record for one LLM call from its usage + model, or `null` to skip.\n * TOTAL by contract - a throwing `customer`/`feature`/`properties` resolver (e.g. an\n * unexpected params shape) drops the record rather than surfacing in the wrapped\n * call, so every caller (sync or async) inherits the non-blocking guarantee here.\n */\nfunction buildTokenRecord<P>(\n options: MeterLLMOptions<P>,\n params: P,\n usage: unknown,\n model: unknown,\n): UsageRecord | null {\n const counts = normalizeTokenUsage(usage);\n if (!counts) return null;\n try {\n const customerId = resolveValue(options.customer, params);\n if (!customerId) return null;\n const properties: Record<string, string | number> = {\n tokens_prompt: counts.promptTokens,\n tokens_completion: counts.completionTokens,\n tokens_total: counts.totalTokens,\n ...(typeof model === \"string\" ? { model } : {}),\n ...options.properties?.(params, counts),\n };\n return {\n customerId,\n featureId: resolveValue(options.feature, params),\n value: pickCount(counts, options.count ?? \"total\"),\n properties,\n };\n } catch {\n return null; // a resolver mistake must never break the wrapped call\n }\n}\n\nfunction isPromiseLike(v: unknown): v is Promise<unknown> {\n return (\n (typeof v === \"object\" || typeof v === \"function\") &&\n v !== null &&\n typeof (v as { then?: unknown }).then === \"function\"\n );\n}\n\n/** The two params slots an OpenAI-style `create(body, requestOptions?)` takes. */\ntype CreateArgs = [params: Record<string, unknown>, ...rest: unknown[]];\n\nfunction wrapOpenAICreate(\n create: (...args: unknown[]) => unknown,\n thisArg: unknown,\n options: MeterLLMOptions<Record<string, unknown>>,\n): (...args: CreateArgs) => unknown {\n return (params, ...rest) => {\n const returned = Reflect.apply(create, thisArg, [params, ...rest]);\n // openai-node returns a thenable (APIPromise) for BOTH streaming and not.\n if (!isPromiseLike(returned)) return returned;\n\n if ((params as { stream?: unknown }).stream === true) {\n // Streaming: TAP iteration to read the usage the final chunk carries (present\n // when the caller sets `stream_options.include_usage`) WITHOUT dropping the\n // OpenAI return contract - the APIPromise keeps its helpers and the resolved\n // Stream keeps its methods; we only override `Symbol.asyncIterator`.\n return proxyResolved(returned, (stream) =>\n typeof stream === \"object\" && stream !== null\n ? proxyAsyncIterable(stream, () =>\n tapOpenAIStream(stream as AsyncIterable<unknown>, params, options),\n )\n : stream,\n );\n }\n // Non-streaming: record from the resolved completion's `.usage`, tracked by the\n // meter so `flush()` awaits it. The caller receives the ORIGINAL promise\n // untouched (APIPromise helpers intact); a failed call resolves to no record.\n options.meter.recordAsync(returned.then((resp) => completionRecord(resp, params, options)));\n return returned;\n };\n}\n\nfunction completionRecord(\n resp: unknown,\n params: Record<string, unknown>,\n options: MeterLLMOptions<Record<string, unknown>>,\n): UsageRecord | null {\n if (typeof resp !== \"object\" || resp === null) return null;\n const r = resp as { usage?: unknown; model?: unknown };\n return buildTokenRecord(options, params, r.usage, r.model);\n}\n\n/**\n * Proxy a thenable so awaiting it yields `map(resolvedValue)`, while every other\n * property/method (an APIPromise's `.withResponse()`/`.asResponse()`, …) passes\n * straight through. Lets us tap the resolved value without dropping the return\n * contract.\n */\nfunction proxyResolved(\n source: Promise<unknown>,\n map: (value: unknown) => unknown,\n): Promise<unknown> {\n const mappedThen = (onF?: (v: unknown) => unknown, onR?: (e: unknown) => unknown) =>\n source.then((v) => (onF ? onF(map(v)) : map(v)), onR);\n return new Proxy(source, {\n get(target, prop) {\n // Route `then`/`catch`/`finally` through the mapping so awaiting via ANY of\n // them yields the tapped value - binding the native methods to `target` would\n // resolve the raw (un-tapped) stream and silently skip metering.\n if (prop === \"then\") return mappedThen;\n if (prop === \"catch\") return (onR: (e: unknown) => unknown) => mappedThen(undefined, onR);\n if (prop === \"finally\") {\n return (cb?: () => void) =>\n mappedThen(\n (v) => {\n cb?.();\n return v;\n },\n (e) => {\n cb?.();\n throw e;\n },\n );\n }\n const value = Reflect.get(target, prop);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n }) as Promise<unknown>;\n}\n\n/**\n * Proxy an async-iterable object so `for await` runs `makeIterator()` (our tap),\n * while every other property/method (a Stream's `.tee()`, `.toReadableStream()`, …)\n * passes straight through. Taps iteration WITHOUT replacing the object.\n */\nfunction proxyAsyncIterable(source: object, makeIterator: () => AsyncIterator<unknown>): object {\n return new Proxy(source, {\n get(target, prop) {\n if (prop === Symbol.asyncIterator) return makeIterator;\n const value = Reflect.get(target, prop);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n}\n\n/** Usage + model folded out of a streamed response, ready for {@link buildTokenRecord}. */\ninterface StreamUsage {\n usage?: unknown;\n model?: unknown;\n}\n\n/**\n * Meter a streamed response: tap the stream (yielding every chunk untouched), fold\n * each chunk into an accumulator via `reduce`, and record ONE usage event when\n * iteration finishes. This is the reusable middle between the generic\n * {@link tapAsyncIterable} and a specific provider's chunk shape - a new streaming\n * source (Anthropic SSE, etc.) plugs in by supplying only its `reduce`.\n */\nfunction meterStream<C, P>(\n stream: AsyncIterable<C>,\n params: P,\n options: MeterLLMOptions<P>,\n reduce: (chunk: C, acc: StreamUsage) => void,\n): AsyncGenerator<C> {\n const acc: StreamUsage = {};\n return tapAsyncIterable(stream, {\n onValue: (chunk) => reduce(chunk, acc),\n onDone: () => {\n const record = buildTokenRecord(options, params, acc.usage, acc.model);\n if (record) options.meter.record(record);\n },\n });\n}\n\nfunction tapOpenAIStream(\n stream: AsyncIterable<unknown>,\n params: Record<string, unknown>,\n options: MeterLLMOptions<Record<string, unknown>>,\n): AsyncGenerator<unknown> {\n return meterStream(stream, params, options, (chunk, acc) => {\n if (typeof chunk !== \"object\" || chunk === null) return;\n const c = chunk as { usage?: unknown; model?: unknown };\n if (c.usage) acc.usage = c.usage; // the final chunk carries usage (include_usage)\n if (c.model && acc.model === undefined) acc.model = c.model;\n });\n}\n\n/**\n * Wrap an OpenAI-compatible client so every `chat.completions.create` call\n * auto-meters its token usage. Returns a proxy of the SAME type - use it exactly as\n * before; every other property/method passes straight through untouched.\n *\n * Reads the token count from the provider's own response (no re-tokenizing), for\n * both blocking and streaming calls. For a STREAMED call, pass\n * `stream_options: { include_usage: true }` so the final chunk carries usage -\n * otherwise a streamed call can't be metered (billow never mutates your request).\n *\n * A streamed response is metered when consumed the standard way: `await` the call,\n * then `for await` the stream. The `Stream` helpers (`.tee()`, `.toReadableStream()`)\n * and the un-awaited `APIPromise` helpers (`.withResponse()`, `.asResponse()`) are\n * PRESERVED (they keep working), but consuming through them bypasses the iteration\n * tap, so those calls are not token-metered.\n *\n * Works with any client exposing `chat.completions.create` returning a `.usage`\n * shape: OpenAI, Azure OpenAI, Together, Groq, OpenRouter, and other compatibles.\n *\n * const openai = meterOpenAI(new OpenAI(), { meter, feature: \"tokens\", customer });\n * const res = await openai.chat.completions.create({ model, messages }); // metered\n */\nexport function meterOpenAI<T extends object>(\n client: T,\n options: MeterLLMOptions<Record<string, unknown>>,\n): T {\n const root = client as { chat?: { completions?: { create?: unknown } } };\n const completions = root.chat?.completions;\n const create = completions?.create;\n if (typeof create !== \"function\" || !completions) {\n throw new TypeError(\"meterOpenAI: expected client.chat.completions.create to be a function\");\n }\n const wrapped = wrapOpenAICreate(create as (...args: unknown[]) => unknown, completions, options);\n return replaceCreate(client, wrapped);\n}\n\n/**\n * Return a non-mutating proxy of `client` that swaps ONLY `chat.completions.create`\n * for `wrapped`, passing every other access straight through. Untouched methods keep\n * their real receiver, so `this` stays correct.\n */\nfunction replaceCreate<T extends object>(client: T, wrapped: (...args: CreateArgs) => unknown): T {\n const root = client as { chat: { completions: object } };\n const completionsProxy = new Proxy(root.chat.completions, {\n get: (t, p, r) => (p === \"create\" ? wrapped : Reflect.get(t, p, r)),\n });\n const chatProxy = new Proxy(root.chat, {\n get: (t, p, r) => (p === \"completions\" ? completionsProxy : Reflect.get(t, p, r)),\n });\n return new Proxy(client, {\n get: (t, p, r) => (p === \"chat\" ? chatProxy : Reflect.get(t, p, r)),\n });\n}\n\n/**\n * Meter a Vercel AI SDK result (the object `generateText`/`streamText` resolves to).\n * Reads `result.usage` - an object (`generateText`) or a Promise (`streamText`) - and\n * records the token count, non-blocking. Never touches `result.textStream`, so a\n * streamed response is delivered to your consumer untouched. Accepts AI SDK v4\n * (`promptTokens`/`completionTokens`) and v5 (`inputTokens`/`outputTokens`) shapes.\n *\n * const result = streamText({ model, prompt });\n * meterAIResult(result, { meter, feature: \"tokens\", customer: customerId });\n * return result.toDataStreamResponse();\n */\nexport function meterAIResult(\n result: { usage?: unknown; response?: unknown },\n options: MeterLLMOptions<void>,\n): void {\n const model = extractAIModel(result.response);\n const usage = result.usage;\n if (isPromiseLike(usage)) {\n // `streamText` resolves usage LATE - hand the meter the whole resolve→record\n // chain so `flush()` (the README's serverless guidance) awaits it instead of\n // snapshotting an empty in-flight set and dropping the usage.\n options.meter.recordAsync(usage.then((u) => buildTokenRecord(options, undefined, u, model)));\n return;\n }\n const record = buildTokenRecord(options, undefined, usage, model);\n if (record) options.meter.record(record);\n}\n\n/** Best-effort model id from an AI SDK result's `response` (skipped if it's a promise). */\nfunction extractAIModel(response: unknown): unknown {\n if (typeof response !== \"object\" || response === null) return undefined;\n const m = (response as { modelId?: unknown }).modelId;\n return typeof m === \"string\" ? m : undefined;\n}\n"]}