@meetreeve/billing-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,434 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * Catalog types mirroring reeve-services `packages/commerce/types.py` →
6
+ * `Catalog.to_public_dict()`, served by `GET /api/v2/commerce/catalog/{host_app}`.
7
+ * Structurally identical to reeve-frontend's app-local mirror
8
+ * (`src/lib/api/commerce.ts`) — duplicated here rather than imported so this
9
+ * package has zero dependency on reeve-frontend's `src/` tree and can be
10
+ * dropped into any consumer app (e.g. AgentPik) unchanged.
11
+ *
12
+ * DEV-1786: the wire payload doesn't carry `currency` / `popular` /
13
+ * `purchasable` yet — that's a reeve-services gap (`packages/commerce/types.py`)
14
+ * out of scope for this FE-only ticket (rs `packages/commerce/types.py` is
15
+ * collision-fenced this batch to DEV-5037). All three are OPTIONAL here so:
16
+ * - a catalog that already has them (once the BE ships it) needs no type
17
+ * change to start using them, and
18
+ * - callers can inject the same effect today via `PricingTable`'s
19
+ * `presentation` prop (badge/highlighted) without waiting on the BE.
20
+ * See the PR body for the concrete BE follow-up.
21
+ */
22
+ interface CatalogPlan {
23
+ id: string;
24
+ name: string;
25
+ price_cents: number;
26
+ /** "month" | "year" | ... — whatever the catalog emits. */
27
+ interval: string;
28
+ credits_grant_monthly: number | null;
29
+ credits_grant_lifetime: number | null;
30
+ features: string[];
31
+ /**
32
+ * key → -1 unlimited | 0 blocked | N capped. e.g. `{ seats, brands_max, voice }`.
33
+ * Same -1/0/N convention as reeve-services' `Entitlements` (packages/commerce/entitlements.py).
34
+ */
35
+ feature_limits: Record<string, number>;
36
+ support_tier: string | null;
37
+ /** Gap field (not yet on the wire) — ISO 4217 currency code, e.g. "usd". */
38
+ currency?: string;
39
+ /** Gap field (not yet on the wire) — highlight this as the recommended tier. */
40
+ popular?: boolean;
41
+ /** Gap field (not yet on the wire) — false disables the CTA (e.g. a retired tier still returned for existing subscribers). Defaults to true. */
42
+ purchasable?: boolean;
43
+ }
44
+ interface CatalogPack {
45
+ id: string;
46
+ name: string;
47
+ credits: number;
48
+ price_cents: number;
49
+ /** Gap field (not yet on the wire) — ISO 4217 currency code, e.g. "usd". */
50
+ currency?: string;
51
+ }
52
+ interface Catalog {
53
+ host_app: string;
54
+ plans: CatalogPlan[];
55
+ packs: CatalogPack[];
56
+ }
57
+ /**
58
+ * Normalized credit balance (DEV-1787). The two source payloads diverge —
59
+ * Studio's legacy `{total, base_credits, top_up_credits, byok_available,
60
+ * base_credits_expire_at}` (reeve-frontend `src/lib/api/credits.ts`) vs
61
+ * AgentPik's `{balance, base, top_up, expiring_soon}` — and AgentPik's own
62
+ * `normalizeCreditBalance` (`lib/api/studio.ts`) already emits this exact
63
+ * shape, so it's adopted as the package's contract. Every app maps its own
64
+ * wire shape onto this with a small app-side adapter (never in the
65
+ * package) before it reaches `CreditsMeter` / `LowBalanceBanner`.
66
+ */
67
+ interface CreditBalance {
68
+ /** Whole running balance — base + top-up (+ any carryover). */
69
+ total: number;
70
+ /** Remaining plan-grant credits for the current period (or lifetime grant). */
71
+ base_credits: number;
72
+ /** Purchased top-up credits (roll over, don't reset with the billing period). */
73
+ top_up_credits: number;
74
+ /** Credits due to expire soon — units match `total` (credits, not a date). Optional: not every app tracks this. */
75
+ expiring_soon?: number;
76
+ /** ISO date the base-credit grant expires, if the app tracks per-grant expiry. */
77
+ base_credits_expire_at?: string | null;
78
+ /** True when the account has "bring your own key" — usage isn't metered against the balance. */
79
+ byok_available?: boolean;
80
+ }
81
+ /**
82
+ * The credits `view` payload — mirrors reeve-services'
83
+ * `GET /api/v1/credits/view/{owner_id}` (`packages/credits/service.py`,
84
+ * `api/routers/credits_host_app.py`). The BE already branches per host_app
85
+ * via the Credits registry's `display_mode` (`packages/credits/registry.py`:
86
+ * "balance" | "percentage"), so `CreditsMeter` renders whichever `mode` it's
87
+ * handed rather than re-deriving it from a bare registry flag.
88
+ */
89
+ interface CreditsView {
90
+ mode: "balance" | "percentage" | "unavailable";
91
+ /** percentage mode only — 0-100. */
92
+ percentage_used?: number;
93
+ /** percentage mode only — ISO date the usage window resets. */
94
+ reset_at?: string | null;
95
+ /** balance mode only — the running total (a bare number; pass the full normalized `CreditBalance` as `CreditsMeter`'s `balance` prop for the base/top-up detail rows). */
96
+ balance?: number;
97
+ /** balance mode only. */
98
+ expiring_soon?: number;
99
+ owner_type?: string;
100
+ /** unavailable mode only — why (e.g. no ledger exists yet for this owner). */
101
+ reason?: string;
102
+ }
103
+
104
+ /** Whole-dollar amount from integer cents ($20 from 2000). */
105
+ declare function dollarsFromCents(cents: number): number;
106
+ /**
107
+ * Minimal, dependency-free price formatter. Good enough for the catalog's
108
+ * only currently-live currency (USD, `currency` is a DEV-1786 gap field —
109
+ * see types.ts). Swap for `Intl.NumberFormat` per-currency once the catalog
110
+ * actually carries non-USD plans.
111
+ */
112
+ declare function formatPrice(cents: number, currency?: string): string;
113
+ /** Thousands-separated credit count, e.g. 100000 -> "100,000". */
114
+ declare function formatCredits(n: number): string;
115
+
116
+ /**
117
+ * Client-side mirror of reeve-services' `Entitlements.min_tier_for`
118
+ * (`packages/commerce/entitlements.py`) — the lowest catalog-order plan
119
+ * whose `feature_limits[featureKey]` is present and non-zero. Same
120
+ * -1 (unlimited) / 0 (blocked) / N (capped) convention as the BE.
121
+ *
122
+ * "Catalog order IS tier order" — `commerce_bootstrap.py` registers plans
123
+ * low-to-high, and `to_public_dict()` preserves that order on the wire, so
124
+ * this does not re-sort by price. A featureKey absent from a plan's
125
+ * `feature_limits` entirely is treated as blocked (0), not unlocked — a
126
+ * catalog that hasn't been told about a feature must never produce a false
127
+ * unlock.
128
+ *
129
+ * Returns `null` when no plan in the catalog unlocks the feature at all
130
+ * (e.g. a misconfigured catalog, or a feature nothing has been wired to
131
+ * yet) — callers (see `UpgradePaywall`) must handle this without dead-ending
132
+ * the CTA.
133
+ */
134
+ declare function resolveUnlockingPlan(plans: CatalogPlan[], featureKey: string): CatalogPlan | null;
135
+ /** Whether `plan` already unlocks `featureKey` (non-zero limit, incl. -1 unlimited). */
136
+ declare function isFeatureUnlocked(plan: CatalogPlan | null | undefined, featureKey: string): boolean;
137
+ /** True when `limit` means "no cap" in the BE's -1/0/N convention. */
138
+ declare function isUnlimited(limit: number | undefined): boolean;
139
+
140
+ /**
141
+ * Per-plan-id presentation overlay. Marketing copy stays app-side — the
142
+ * catalog stays the source of truth for price, credits, and feature
143
+ * bullets. Mirrors AgentPik's `PLAN_STYLE` pattern (#204).
144
+ */
145
+ interface PlanPresentation {
146
+ /** Small pill/badge label, e.g. "Most popular". Overrides `plan.popular`. */
147
+ badge?: string;
148
+ /** One-line marketing hook rendered under the price. */
149
+ tagline?: string;
150
+ /** Extra className merged onto the card — app-level accent/highlight styling. */
151
+ className?: string;
152
+ /** Force the highlighted treatment regardless of `plan.popular`. */
153
+ highlighted?: boolean;
154
+ /** CTA label override. Defaults to "Current plan" / "Get {name}". */
155
+ cta?: string;
156
+ }
157
+ interface PricingTableProps {
158
+ /** Injected, not fetched — the caller owns the `getCatalog()` call (RSC or client). */
159
+ catalog: Catalog;
160
+ /** "grid" = full tier comparison (Studio/reeve shape). "band" = single highlighted plan (AgentPik shape). Default "grid". */
161
+ variant?: "grid" | "band";
162
+ /** Which plan to feature in "band" mode. Falls back to `currentPlanId`, then the `popular` plan, then the first plan. */
163
+ bandPlanId?: string;
164
+ /** Render the credit-pack grid below the plans. Default: true iff `catalog.packs.length`. */
165
+ showPacks?: boolean;
166
+ /** Signed-in user's current plan id — drives the "Your plan" badge + CTA state. */
167
+ currentPlanId?: string | null;
168
+ /** Per-plan-id presentation overlay (badge/tagline/style). Marketing copy stays app-side. */
169
+ presentation?: Record<string, PlanPresentation>;
170
+ /** Checkout wiring stays app-local/injected — called when a plan's CTA is clicked. */
171
+ onSelectPlan?: (plan: CatalogPlan) => void | Promise<void>;
172
+ /** Called when a pack's Buy CTA is clicked. */
173
+ onBuyPack?: (pack: CatalogPack) => void | Promise<void>;
174
+ className?: string;
175
+ }
176
+ /**
177
+ * Catalog-driven pricing surface — tier grid, single-plan band, and/or
178
+ * credit-pack cards. Renders from an INJECTED `catalog` (never fetches — the
179
+ * caller owns `getCatalog()` / RSC data flow), so a price/bullet edit in the
180
+ * reeve-services catalog SSOT changes the rendered page with zero FE deploy.
181
+ */
182
+ declare function PricingTable({ catalog, variant, bandPlanId, showPacks, currentPlanId, presentation, onSelectPlan, onBuyPack, className, }: PricingTableProps): react_jsx_runtime.JSX.Element;
183
+
184
+ /**
185
+ * DEV-2917's 402 `upgrade_options` payload shape (`["plan", "addon"]`) —
186
+ * pass it straight through when the caller already has it from a 402
187
+ * response, to control which CTA(s) render. Defaults to `["plan"]`.
188
+ */
189
+ type UpgradeOption = "plan" | "addon";
190
+ interface UpgradePaywallProps {
191
+ /** The gated capability — keyed the same as the catalog's `feature_limits` (e.g. "brands_max"). */
192
+ featureKey: string;
193
+ catalog: Catalog;
194
+ currentPlanId?: string | null;
195
+ /** "modal" (default) renders in a Radix Dialog; "inline" renders as a plain card. */
196
+ variant?: "modal" | "inline";
197
+ /** Modal-only. Ignored for `variant="inline"`. Defaults to `true` (always visible) so an inline embed and a controlled modal share the same component without extra plumbing. */
198
+ open?: boolean;
199
+ onClose?: () => void;
200
+ /**
201
+ * Fires with the resolved unlocking plan when the primary CTA is clicked.
202
+ * Checkout wiring (Stripe, etc.) stays app-local/injected. The CTA is
203
+ * never a dead end: if no tier unlocks the feature, this still fires with
204
+ * the catalog's top-tier plan so the caller has something concrete to act
205
+ * on (e.g. route to a general pricing/contact page).
206
+ */
207
+ onUpgrade?: (plan: CatalogPlan) => void | Promise<void>;
208
+ /** Which CTA(s) to render — DEV-2917's 402 `upgrade_options` shape. Defaults to `["plan"]`. */
209
+ upgradeOptions?: UpgradeOption[];
210
+ /** Required when `upgradeOptions` includes "addon". */
211
+ onAddon?: () => void | Promise<void>;
212
+ addonLabel?: string;
213
+ /** App-local escape hatch (e.g. Studio's "Delete an existing brand instead") — kept generic so copy/behavior stays app-side. */
214
+ secondaryAction?: {
215
+ label: string;
216
+ onClick: () => void;
217
+ disabled?: boolean;
218
+ };
219
+ title?: string;
220
+ description?: string;
221
+ className?: string;
222
+ }
223
+ /**
224
+ * Feature-gated upgrade paywall. Resolves the lowest-tier plan that unlocks
225
+ * `featureKey` from the injected `catalog` (client-side mirror of
226
+ * reeve-services' `Entitlements.min_tier_for`) and always renders a working
227
+ * upgrade CTA — no dead-end paywalls (cf. the `BrandQuotaPaywall` "Delete an
228
+ * existing brand" pattern this replaces, DEV-823).
229
+ */
230
+ declare function UpgradePaywall(props: UpgradePaywallProps): react_jsx_runtime.JSX.Element;
231
+
232
+ interface AutoCheckoutProps {
233
+ /** Validated against these before firing — never trusts a bare URL id. */
234
+ packs?: CatalogPack[];
235
+ plans?: CatalogPlan[];
236
+ onBuyPack?: (pack: CatalogPack) => void | Promise<void>;
237
+ onSelectPlan?: (plan: CatalogPlan) => void | Promise<void>;
238
+ /** Query param read for a pending pack purchase. Default "credits". */
239
+ packParam?: string;
240
+ /** Query param read for a pending plan subscription. Default "plan". */
241
+ planParam?: string;
242
+ }
243
+ /**
244
+ * Post-login/return auto-checkout resume. Drop anywhere on a pricing
245
+ * surface: reads `?<packParam>=<id>` / `?<planParam>=<id>` from the URL
246
+ * (validated against the injected catalog data, never a bare id) and fires
247
+ * the matching handler once, then strips the param so a refresh can't
248
+ * re-fire it. Seeded from AgentPik's `AutoCheckout` (#204) — ref-guarded so
249
+ * StrictMode's double-effect can't double-fire.
250
+ *
251
+ * Deliberately framework-agnostic: uses `window.history.replaceState`
252
+ * instead of `next/navigation`'s `useRouter()` for the param-strip. Two
253
+ * reasons, not just one:
254
+ * 1. Portability — this package has no other Next.js-only dependency, and
255
+ * a raw History API call works identically in a Vite SPA consumer
256
+ * (e.g. a future non-Next host) with zero extra plumbing.
257
+ * 2. A real bundling hazard: `next` is a peer dependency here, but
258
+ * `next/navigation`'s router context is a *runtime singleton* keyed to
259
+ * the exact `next` module instance the host app's tree was rendered
260
+ * with. Pulling `useRouter` in from this package's own bundle risked
261
+ * resolving a second `next` instance (pnpm content-addresses `next` by
262
+ * its full peer-resolution hash, so "same semver range" doesn't
263
+ * guarantee "same physical module" the way it does for `react`) —
264
+ * observed concretely as `next`'s real router throwing "invariant
265
+ * expected app router to be mounted" instead of the host app's test
266
+ * mock intercepting it. `window.history` has no such identity concern.
267
+ * Reading via `window.location` (not `useSearchParams()`) is the same
268
+ * choice reeve-frontend's own newer `pricing-full.tsx` (DEV-2443) already
269
+ * made for this exact resume pattern, and sidesteps needing a Suspense
270
+ * boundary here at all.
271
+ */
272
+ declare function AutoCheckout({ packs, plans, onBuyPack, onSelectPlan, packParam, planParam, }: AutoCheckoutProps): null;
273
+
274
+ interface PlanCardProps {
275
+ /** The account's current plan, looked up from the catalog by id (app-side). Null renders a "no plan on file" empty state — never a blank card. */
276
+ plan: CatalogPlan | null;
277
+ /** ISO date string — rendered as "Renews {date}" when present. */
278
+ renewalDate?: string | null;
279
+ /** Subscription status (e.g. "active" | "trialing" | "past_due" | "canceled"). Omit or "free" hides the status pill. */
280
+ status?: string | null;
281
+ /** True for the free tier — swaps the CTA row to a single primary "Upgrade" action instead of manage/change. */
282
+ isFreePlan?: boolean;
283
+ /** Opens the Stripe customer portal / app-local subscription management. Omit to hide the "Manage billing" CTA. */
284
+ onManage?: () => void | Promise<void>;
285
+ manageLabel?: string;
286
+ /** Fires for the free-plan CTA ("Upgrade") or the paid-plan "Change plan" CTA. Omit to hide. */
287
+ onChangePlan?: () => void | Promise<void>;
288
+ changePlanLabel?: string;
289
+ className?: string;
290
+ }
291
+ /**
292
+ * Current-plan summary card — tier, price, renewal date, and the
293
+ * manage/change-plan CTAs. Distinct from `PricingTable`'s internal
294
+ * (unexported) plan card: that one is a selectable tier in a comparison
295
+ * grid; this one is a single-plan status summary for the account settings
296
+ * surface. Renders from an INJECTED `plan` (the caller resolves it from the
297
+ * catalog by id) — this component never fetches.
298
+ */
299
+ declare function PlanCard({ plan, renewalDate, status, isFreePlan, onManage, manageLabel, onChangePlan, changePlanLabel, className, }: PlanCardProps): react_jsx_runtime.JSX.Element;
300
+
301
+ interface CreditsMeterProps {
302
+ /**
303
+ * The credits `view` payload (`GET /api/v1/credits/view/{owner_id}`) —
304
+ * this component renders `view.mode` directly rather than re-deriving a
305
+ * display mode from a bare registry flag. Freya is registered
306
+ * "percentage"; Studio/AgentPik/reeve are registered "balance".
307
+ */
308
+ view: CreditsView;
309
+ /**
310
+ * Optional normalized balance for the balance-mode detail rows
311
+ * (base/top-up split, expiry, BYOK badge). `view.balance` alone only
312
+ * carries the running total — pass this when the caller already has the
313
+ * fuller balance object (e.g. from its own credits fetch).
314
+ */
315
+ balance?: CreditBalance;
316
+ className?: string;
317
+ }
318
+ /**
319
+ * Usage/credits meter — same component for both Credits registry display
320
+ * modes (DEV-1787): Freya-style "% of allowance used" and Studio/AgentPik-
321
+ * style "credits remaining". Renders from an INJECTED `view` payload; never
322
+ * fetches.
323
+ */
324
+ declare function CreditsMeter({ view, balance, className }: CreditsMeterProps): react_jsx_runtime.JSX.Element;
325
+
326
+ interface BuyMorePacksProps {
327
+ packs: CatalogPack[];
328
+ /**
329
+ * "fixed-pack" (AgentPik shape) renders a card grid, one CTA per pack.
330
+ * "presets" (Studio shape) renders a compact row of quick-buy chips.
331
+ * Both purchase the same catalog-driven `CatalogPack` — the config only
332
+ * changes the layout, so a consumer picks whichever matches its existing
333
+ * buy-flow density without the package needing two data shapes.
334
+ */
335
+ purchaseModel?: "fixed-pack" | "presets";
336
+ /** Checkout wiring stays app-local/injected — called when a pack's CTA is clicked. */
337
+ onPurchase: (pack: CatalogPack) => void | Promise<void>;
338
+ /**
339
+ * Query param read for a just-completed top-up checkout return, e.g.
340
+ * `?topup=success`. Default "topup". The param is always stripped from
341
+ * the URL on mount if present, whether or not `onTopupSuccess` is given.
342
+ */
343
+ successParam?: string;
344
+ /**
345
+ * Fires when `?<successParam>=success` is present on mount — seeded from
346
+ * AgentPik's post-checkout re-poll (#205): fires at 0s/2s/5s since the
347
+ * ledger webhook can lag the checkout redirect by a couple seconds.
348
+ */
349
+ onTopupSuccess?: () => void | Promise<void>;
350
+ className?: string;
351
+ }
352
+ /**
353
+ * Catalog-driven credit-pack purchase flow, plus the post-checkout
354
+ * `?topup=success` resume. Renders from an INJECTED `packs` list (never
355
+ * fetches — the caller owns `getCatalog()`).
356
+ */
357
+ declare function BuyMorePacks({ packs, purchaseModel, onPurchase, successParam, onTopupSuccess, className, }: BuyMorePacksProps): react_jsx_runtime.JSX.Element | null;
358
+
359
+ interface LowBalanceBannerProps {
360
+ /** Normalized balance — always injected. Unlike the reeve-frontend original this ported from, this component never fetches. */
361
+ balance: CreditBalance;
362
+ /** Daily burn rate (credits/day) for a "running out soon" warning alongside the fixed low-balance threshold. */
363
+ burnRate?: number;
364
+ /** Balance below which "low" fires. Default 5 — mirrors the legacy `LOW_BALANCE_THRESHOLD`. */
365
+ threshold?: number;
366
+ variant?: "default" | "compact";
367
+ /** Buy-credits CTA — app-local routing/checkout stays injected. Omit to hide the CTA. */
368
+ onAddCredits?: () => void;
369
+ addCreditsLabel?: string;
370
+ /** BYOK CTA, shown alongside the empty-balance state. Omit to hide it. */
371
+ onAddByok?: () => void;
372
+ addByokLabel?: string;
373
+ className?: string;
374
+ }
375
+ /**
376
+ * Low/zero-balance warning banner (DEV-1787, ported from reeve-frontend's
377
+ * `src/components/credits/low-balance-banner.tsx`). Props-only — the
378
+ * original self-fetched via `getBalance()`; here `balance` is always
379
+ * injected so the package never makes an HTTP call. BYOK accounts (usage
380
+ * isn't metered against the balance) never see the warning.
381
+ */
382
+ declare function LowBalanceBanner({ balance, burnRate, threshold, variant, onAddCredits, addCreditsLabel, onAddByok, addByokLabel, className, }: LowBalanceBannerProps): react_jsx_runtime.JSX.Element | null;
383
+
384
+ interface BillingSettingsPanelProps {
385
+ /** Current plan, looked up from the catalog by id (app-side). Null renders PlanCard's empty state. */
386
+ plan: CatalogPlan | null;
387
+ renewalDate?: string | null;
388
+ planStatus?: string | null;
389
+ isFreePlan?: boolean;
390
+ onManagePlan?: () => void | Promise<void>;
391
+ manageLabel?: string;
392
+ onChangePlan?: () => void | Promise<void>;
393
+ changePlanLabel?: string;
394
+ creditsView: CreditsView;
395
+ creditsBalance?: CreditBalance;
396
+ /** Default true — hidden entirely when `creditsBalance` is omitted (nothing to evaluate the threshold against). */
397
+ showLowBalanceBanner?: boolean;
398
+ lowBalanceThreshold?: number;
399
+ burnRate?: number;
400
+ onAddCredits?: () => void;
401
+ addCreditsLabel?: string;
402
+ onAddByok?: () => void;
403
+ packs?: CatalogPack[];
404
+ purchaseModel?: "fixed-pack" | "presets";
405
+ onBuyPack?: (pack: CatalogPack) => void | Promise<void>;
406
+ topupSuccessParam?: string;
407
+ onTopupSuccess?: () => void | Promise<void>;
408
+ /** When provided (and `showUpgradeSection` isn't false), renders the catalog-driven upgrade section below Buy more. */
409
+ catalog?: Catalog;
410
+ /** Default: renders whenever `catalog` is provided. Set false to suppress even with a catalog (e.g. a paid plan that only wants the PlanCard's own "Change plan" CTA). */
411
+ showUpgradeSection?: boolean;
412
+ upgradeVariant?: "grid" | "band";
413
+ upgradePresentation?: Record<string, PlanPresentation>;
414
+ onSelectPlan?: (plan: CatalogPlan) => void | Promise<void>;
415
+ /**
416
+ * Owner-scoped ledger/history UI is out of scope pending DEV-1188 — the
417
+ * package ships no built-in history list. Pass a caller-owned node (e.g.
418
+ * an app's existing ledger table) to render it here; omit to keep the
419
+ * slot fully inert (renders nothing, not an empty placeholder).
420
+ */
421
+ historySlot?: ReactNode;
422
+ className?: string;
423
+ }
424
+ /**
425
+ * Thin composition of the DEV-1787 billing primitives (`PlanCard` /
426
+ * `CreditsMeter` / `BuyMorePacks` / `LowBalanceBanner`) plus DEV-1786's
427
+ * `PricingTable` as the embedded upgrade slot. All data + handlers are
428
+ * injected — this component never fetches. Sections that have nothing to
429
+ * render (no packs, no catalog, no history node) render nothing rather
430
+ * than an empty shell.
431
+ */
432
+ declare function BillingSettingsPanel({ plan, renewalDate, planStatus, isFreePlan, onManagePlan, manageLabel, onChangePlan, changePlanLabel, creditsView, creditsBalance, showLowBalanceBanner, lowBalanceThreshold, burnRate, onAddCredits, addCreditsLabel, onAddByok, packs, purchaseModel, onBuyPack, topupSuccessParam, onTopupSuccess, catalog, showUpgradeSection, upgradeVariant, upgradePresentation, onSelectPlan, historySlot, className, }: BillingSettingsPanelProps): react_jsx_runtime.JSX.Element;
433
+
434
+ export { AutoCheckout, type AutoCheckoutProps, BillingSettingsPanel, type BillingSettingsPanelProps, BuyMorePacks, type BuyMorePacksProps, type Catalog, type CatalogPack, type CatalogPlan, type CreditBalance, CreditsMeter, type CreditsMeterProps, type CreditsView, LowBalanceBanner, type LowBalanceBannerProps, PlanCard, type PlanCardProps, type PlanPresentation, PricingTable, type PricingTableProps, type UpgradeOption, UpgradePaywall, type UpgradePaywallProps, dollarsFromCents, formatCredits, formatPrice, isFeatureUnlocked, isUnlimited, resolveUnlockingPlan };