@bpinternal/billing-ui 0.0.1

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,892 @@
1
+ import { Appearance } from '@stripe/stripe-js';
2
+ import { billing } from '@botpress/client';
3
+ import { ButtonHTMLAttributes } from 'react';
4
+ import { ClassValue } from 'clsx';
5
+ import { Client } from '@botpress/client';
6
+ import { CSSProperties } from 'react';
7
+ import { InputHTMLAttributes } from 'react';
8
+ import { JSX } from 'react/jsx-runtime';
9
+ import { QueryClient } from '@tanstack/react-query';
10
+ import { ReactElement } from 'react';
11
+ import { ReactNode } from 'react';
12
+ import { ReactPortal } from 'react';
13
+ import { SelectHTMLAttributes } from 'react';
14
+ import { Stripe } from '@stripe/stripe-js';
15
+ import { StripeCardElementOptions } from '@stripe/stripe-js';
16
+ import { SVGProps } from 'react';
17
+ import { UseMutationResult } from '@tanstack/react-query';
18
+ import { UseQueryResult } from '@tanstack/react-query';
19
+
20
+ export declare function addDays(iso: string, days: number): string;
21
+
22
+ export declare type Addon = Awaited<ReturnType<BillingClient['listAddons']>>[number];
23
+
24
+ /** Strip Smaug's "Add-on - " name prefix. */
25
+ export declare function addonDisplayName(name: string): string;
26
+
27
+ /**
28
+ * "Now → New" resource totals once the selected add-on quantities are applied.
29
+ * new = plan base feature + Σ (quantity × add-on increment) across add-ons that grant it.
30
+ * Only returns rows that actually change, so the preview stays focused.
31
+ */
32
+ export declare function addonLimitsPreview(plan: Plan, addons: Addon[] | undefined, quantities: Record<string, number>): LimitPreviewRow[];
33
+
34
+ /**
35
+ * Add-on price for a given plan. Smaug keys add-on prices by plan id
36
+ * (e.g. { plus: { amount: 65 }, team: { amount: 50 } }); fall back to kind, then
37
+ * to an interval key for environments that price add-ons globally.
38
+ *
39
+ * Deliberately does NOT fall back to "any price with a matching interval" — that
40
+ * would borrow another plan's price for a plan that isn't sold add-ons at all
41
+ * (e.g. community), making them look purchasable when they aren't. A plan with no
42
+ * id/kind/interval-keyed price returns null → no add-ons offered.
43
+ */
44
+ export declare function addonPrice(addon: Addon, plan: Plan, interval: BillingInterval): {
45
+ amount: number;
46
+ currency: string;
47
+ } | null;
48
+
49
+ /**
50
+ * Clickable summary of active add-ons (current quantities from the live
51
+ * subscription). Acts as a preview button that opens add-on management.
52
+ */
53
+ export declare const AddonsSummaryCard: ({ onManage, className }: AddonsSummaryCardProps) => JSX.Element;
54
+
55
+ export declare type AddonsSummaryCardProps = {
56
+ /** Opens the manage-add-ons dialog. */
57
+ onManage: () => void;
58
+ className?: string;
59
+ };
60
+
61
+ export declare const Badge: ({ variant, children, className }: BadgeProps) => JSX.Element;
62
+
63
+ export declare type BadgeProps = {
64
+ variant?: 'accent' | 'neutral' | 'success';
65
+ children: ReactNode;
66
+ className?: string;
67
+ };
68
+
69
+ export declare const BankIcon: ({ size, ...props }: IconProps) => JSX.Element;
70
+
71
+ export declare type BillingAddress = {
72
+ lineOne: string;
73
+ lineTwo?: string;
74
+ city: string;
75
+ state?: string;
76
+ postalCode: string;
77
+ country: string;
78
+ };
79
+
80
+ export declare type BillingAnalytics = {
81
+ trackPaymentDetailsConfirmed?: (props: {
82
+ plan_name: string;
83
+ interval: BillingInterval;
84
+ }) => void;
85
+ trackPlanUpgradeInitiated?: (props: {
86
+ plan_name: string;
87
+ interval: BillingInterval;
88
+ current_plan_name?: string;
89
+ }) => void;
90
+ trackPlanUpgraded?: (props: {
91
+ plan_name: string;
92
+ interval: BillingInterval;
93
+ amount_paid: number;
94
+ next_cycle_amount: number;
95
+ previous_plan_name?: string;
96
+ previous_interval?: BillingInterval;
97
+ }) => void;
98
+ trackPlanDowngraded?: (props: {
99
+ plan_name: string;
100
+ interval: BillingInterval;
101
+ previous_plan_name?: string;
102
+ }) => void;
103
+ trackPlanDowngradeCancelled?: (props: {
104
+ plan_name: string;
105
+ }) => void;
106
+ };
107
+
108
+ export declare type BillingChangeEvent = {
109
+ type: 'subscription' | 'addons' | 'payment-method' | 'billing-address';
110
+ };
111
+
112
+ /**
113
+ * The billing engine surface this UI library talks to — literally the subset of
114
+ * `@botpress/client`'s `billing.Client` (Smaug v4) we call.
115
+ *
116
+ * `@botpress/client` is a type-only import (erased at runtime — no hard
117
+ * dependency): pass a real `billing.Client` instance straight in, or implement
118
+ * this interface over your own backend proxy (e.g. tRPC) — the shapes are the
119
+ * official wire shapes, the transport is yours.
120
+ */
121
+ export declare type BillingClient = Pick<billing.Client, 'listPlans' | 'listAddons' | 'getSubscription' | 'previewSubscriptionUpdate' | 'setPlan' | 'setAddons' | 'getPaymentMethod' | 'createPaymentMethodIntent' | 'setPaymentMethod' | 'getBillingAddress' | 'setBillingAddress' | 'getCustomer' | 'setCustomer' | 'listInvoices' | 'getBillingReadonly' | 'getWorkspaceUsages'> &
122
+ /**
123
+ * Per-bot usage breakdown is OPTIONAL: those methods live on the generic
124
+ * `@botpress/client` (not the billing client), so a host that wants the per-bot
125
+ * view passes a client object that also exposes them. Omit them and the
126
+ * UsageDashboard hides the per-bot section. Still type-only — no runtime dep.
127
+ */
128
+ Partial<Pick<Client, 'breakDownWorkspaceUsageByBot' | 'listBots'>>;
129
+
130
+ declare type BillingContextValue = {
131
+ client: BillingClient;
132
+ queryClient: QueryClient;
133
+ /** Workspace scope used to namespace query keys (workspaceId or 'default'). */
134
+ scope: string;
135
+ stripePromise: Promise<Stripe | null>;
136
+ email?: string;
137
+ locale: string;
138
+ isDark: boolean;
139
+ toast: (toast: BillingToast) => void;
140
+ analytics: BillingAnalytics;
141
+ featureLabels?: Record<string, (quantity: number) => string>;
142
+ isOutdatedBilling: boolean;
143
+ manageBillingUrl?: string;
144
+ /** Background poll interval (ms) for queries; `false` when disabled (≤ 0). */
145
+ refetchInterval: number | false;
146
+ /** Re-fetch all billing data (plans, subscription, add-ons, …). Awaitable. */
147
+ refresh: () => Promise<void>;
148
+ /** Internal: notify the host that billing changed. Called by the mutation hooks. */
149
+ notifyBillingChange: (event: BillingChangeEvent) => void;
150
+ };
151
+
152
+ export declare type BillingInterval = 'month' | 'year';
153
+
154
+ export declare const billingKeys: {
155
+ /** Everything for one workspace — use to invalidate/clear the whole scope. */
156
+ root: (scope: string) => readonly ["bpb", string];
157
+ plans: (scope: string) => readonly ["bpb", string, "plans"];
158
+ addons: (scope: string) => readonly ["bpb", string, "addons"];
159
+ subscription: (scope: string) => readonly ["bpb", string, "subscription"];
160
+ preview: (scope: string, update: SubscriptionUpdate) => readonly ["bpb", string, "preview", SubscriptionUpdate];
161
+ paymentMethod: (scope: string) => readonly ["bpb", string, "payment-method"];
162
+ billingAddress: (scope: string) => readonly ["bpb", string, "billing-address"];
163
+ customer: (scope: string) => readonly ["bpb", string, "customer"];
164
+ invoices: (scope: string) => readonly ["bpb", string, "invoices"];
165
+ readonly: (scope: string) => readonly ["bpb", string, "billing-readonly"];
166
+ usages: (scope: string, period: string) => readonly ["bpb", string, "usages", string];
167
+ bots: (scope: string) => readonly ["bpb", string, "bots"];
168
+ usageByBot: (scope: string, type: string, period: string) => readonly ["bpb", string, "usage-by-bot", string, string];
169
+ };
170
+
171
+ export declare const BillingProvider: ({ client, stripePublishableKey, email, locale, theme, onToast, analytics, featureLabels, billingVersion, workspaceId, persist, manageBillingUrl, onBillingChange, refreshInterval, children, }: BillingProviderProps) => JSX.Element;
172
+
173
+ export declare type BillingProviderProps = {
174
+ /** Billing engine client — `@botpress/client`'s `billing.Client` or any compatible adapter */
175
+ client: BillingClient;
176
+ /** Stripe publishable key (pk_…). The only Stripe key the frontend ever sees. */
177
+ stripePublishableKey: string;
178
+ /** Workspace owner email shown in the checkout contact section */
179
+ email?: string;
180
+ locale?: string;
181
+ theme?: BillingTheme;
182
+ onToast?: (toast: BillingToast) => void;
183
+ analytics?: BillingAnalytics;
184
+ /** Override the human label shown for a plan feature key (e.g. bot_count) */
185
+ featureLabels?: Record<string, (quantity: number) => string>;
186
+ /**
187
+ * Workspace billing version (from the generic client's `getWorkspace().billingVersion`).
188
+ * Smaug only serves v4 — any other value makes the dialogs render a
189
+ * "manage billing in Dashboard" gate instead of the self-serve flow.
190
+ * Omit if the host app gates on the version itself.
191
+ */
192
+ billingVersion?: string;
193
+ /**
194
+ * Workspace id. Used to namespace the query cache so one workspace's billing
195
+ * data never leaks into another's, and to scope persisted cache (see `persist`).
196
+ * Strongly recommended when a host can switch workspaces. Defaults to 'default'.
197
+ */
198
+ workspaceId?: string;
199
+ /**
200
+ * Persist the billing cache to localStorage so it survives reloads (instant
201
+ * render, then a background refresh). On by default. Only the current
202
+ * workspace's scope is stored, keyed by `workspaceId`. Set false to opt out.
203
+ */
204
+ persist?: boolean;
205
+ /** Where the gate sends the user, e.g. https://app.botpress.cloud/workspaces/{id}/billing */
206
+ manageBillingUrl?: string;
207
+ /**
208
+ * Fired after any billing change the library commits (subscribe, plan change,
209
+ * add-on update). The library already refreshes its own queries; use this to
210
+ * refresh billing UI the host renders OUTSIDE this provider (e.g. a plan badge
211
+ * elsewhere in the app). The argument names what changed.
212
+ */
213
+ onBillingChange?: (event: BillingChangeEvent) => void;
214
+ /**
215
+ * How often (ms) to poll billing data (subscription, usage, …) in the background.
216
+ * Defaults to 30_000. Set to 0 (or any value ≤ 0) to disable background refresh.
217
+ */
218
+ refreshInterval?: number;
219
+ children: ReactNode;
220
+ };
221
+
222
+ export declare type BillingTheme = 'light' | 'dark' | 'system';
223
+
224
+ export declare type BillingToast = {
225
+ type: 'success' | 'error';
226
+ message: string;
227
+ };
228
+
229
+ export declare const BoltIcon: ({ size, ...props }: IconProps) => JSX.Element;
230
+
231
+ /** A per-bot usage row enriched with the bot's display name. */
232
+ export declare type BotUsageRow = {
233
+ botId: string;
234
+ name: string;
235
+ value: number;
236
+ };
237
+
238
+ export declare const Button: ({ variant, size, block, loading, className, disabled, children, type, ...props }: ButtonProps) => JSX.Element;
239
+
240
+ export declare type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
241
+ variant?: 'primary' | 'accent' | 'outline' | 'ghost';
242
+ size?: 'sm' | 'md' | 'lg';
243
+ block?: boolean;
244
+ loading?: boolean;
245
+ children?: ReactNode;
246
+ };
247
+
248
+ export declare const CalendarIcon: ({ size, ...props }: IconProps) => JSX.Element;
249
+
250
+ /** Minimal card-brand badge (saved-card row). Stripe's own UI shows real brand art. */
251
+ export declare const CardBrandBadge: ({ brand }: {
252
+ brand: string;
253
+ }) => JSX.Element;
254
+
255
+ export declare const CardIcon: ({ size, ...props }: IconProps) => JSX.Element;
256
+
257
+ export declare const ChartIcon: ({ size, ...props }: IconProps) => JSX.Element;
258
+
259
+ export declare const CheckIcon: ({ size, ...props }: IconProps) => JSX.Element;
260
+
261
+ /**
262
+ * "Configure your plan" — checkout (plan interval, payment method via Stripe
263
+ * CardElement, billing address, business VAT, proration preview + subscribe).
264
+ *
265
+ * A Stripe SetupIntent is created every time the dialog opens and the whole
266
+ * body mounts inside one <Elements> tree so CardElement, AddressElement and
267
+ * the subscribe button share the same Stripe context.
268
+ */
269
+ export declare const CheckoutDialog: ({ open, onOpenChange, planId, interval, onBack, onSuccess }: CheckoutDialogProps) => JSX.Element;
270
+
271
+ export declare type CheckoutDialogProps = {
272
+ open: boolean;
273
+ onOpenChange: (open: boolean) => void;
274
+ planId: string;
275
+ /** Initial billing interval — the user can still switch inside the dialog */
276
+ interval: BillingInterval;
277
+ /** Back to the plan picker (renders the ‹ chevron when provided) */
278
+ onBack?: () => void;
279
+ onSuccess?: () => void;
280
+ };
281
+
282
+ export declare const ChevronDownIcon: ({ size, ...props }: IconProps) => JSX.Element;
283
+
284
+ export declare const ChevronLeftIcon: ({ size, ...props }: IconProps) => JSX.Element;
285
+
286
+ export declare const ChevronRightIcon: ({ size, ...props }: IconProps) => JSX.Element;
287
+
288
+ export declare const CloseIcon: ({ size, ...props }: IconProps) => JSX.Element;
289
+
290
+ export declare function cn(...inputs: ClassValue[]): string;
291
+
292
+ /**
293
+ * Per-pack conversations pricing for a plan, e.g. { packSize: 100, amount: 65 }
294
+ * → "+$65 per 100 conversations". Returns null when the plan has no overage add-on
295
+ * (e.g. Free) or the add-on isn't priced for it.
296
+ */
297
+ export declare function conversationPackPrice(addons: Addon[] | undefined, plan: Plan, interval: BillingInterval): {
298
+ packSize: number;
299
+ amount: number;
300
+ currency: string;
301
+ } | null;
302
+
303
+ /** The add-on that sells extra conversations (keyed by its conversation_sessions increment). */
304
+ export declare function conversationsAddon(addons: Addon[] | undefined): Addon | null;
305
+
306
+ /** Currency code → its symbol ("usd" → "$", "eur" → "€"); falls back to the uppercased code. */
307
+ export declare function currencySymbol(currency: string): string;
308
+
309
+ export declare type Customer = Awaited<ReturnType<BillingClient['getCustomer']>>;
310
+
311
+ /**
312
+ * Plain-language explanations of what each plan feature means, keyed by the exact
313
+ * marketing label above. Shown as a hover tooltip in the pricing table. Override
314
+ * per-app via UpgradePlanDialog's `featureDescriptions` prop.
315
+ */
316
+ export declare const DEFAULT_FEATURE_DESCRIPTIONS: Record<string, string>;
317
+
318
+ /**
319
+ * Human labels for Smaug plan feature keys. Overridable per-key via the
320
+ * BillingProvider `featureLabels` prop.
321
+ */
322
+ export declare const DEFAULT_FEATURE_LABELS: Record<string, (quantity: number) => string>;
323
+
324
+ /**
325
+ * Curated marketing feature lists per plan kind — what the pricing table says,
326
+ * mirroring Desk's billing-features. Quota numbers stay out of this list; the
327
+ * conversations volume is rendered as the card's headline metric instead.
328
+ * Override per-app via UpgradePlanDialog's `planFeatures` prop.
329
+ */
330
+ export declare const DEFAULT_PLAN_FEATURES: Record<PlanKind, string[]>;
331
+
332
+ export declare const Dialog: ({ open, onOpenChange, size, children, className, showClose, ...aria }: DialogProps) => ReactPortal | null;
333
+
334
+ export declare type DialogProps = {
335
+ open: boolean;
336
+ onOpenChange: (open: boolean) => void;
337
+ /** sm = confirm, md = form, xl = full checkout / plan picker */
338
+ size?: 'sm' | 'md' | 'xl';
339
+ 'aria-label': string;
340
+ children: ReactNode;
341
+ className?: string;
342
+ showClose?: boolean;
343
+ };
344
+
345
+ export declare const DownloadIcon: ({ size, ...props }: IconProps) => JSX.Element;
346
+
347
+ export declare const ENTERPRISE_CONTACT_URL = "https://botpress.com/contact-us/managed-plan";
348
+
349
+ export declare type Entitlement = {
350
+ key: string;
351
+ label: string;
352
+ unit: 'count' | 'bytes';
353
+ /** Plan base allowance. */
354
+ base: number;
355
+ /** Extra granted by active add-ons (Σ quantity × increment). */
356
+ added: number;
357
+ /** base + added. */
358
+ total: number;
359
+ };
360
+
361
+ export declare const ExternalLinkIcon: ({ size, ...props }: IconProps) => JSX.Element;
362
+
363
+ /** Description for a feature label — exact map first, then a keyword fallback for templated quota labels. */
364
+ export declare function featureDescription(label: string, overrides?: Record<string, string>): string | undefined;
365
+
366
+ export declare function featureLabel(key: string, quantity: number, overrides?: Record<string, (quantity: number) => string>): string;
367
+
368
+ /** Human-readable bytes — "10 GB", "1.5 GB", "500 MB". */
369
+ export declare function formatBytes(bytes: number): string;
370
+
371
+ export declare function formatCurrency(amount: number, currency?: string, decimal?: number): string;
372
+
373
+ export declare function formatDate(iso: string, locale?: string): string;
374
+
375
+ export declare function formatQuantity(n: number): string;
376
+
377
+ export declare function formatUsage(value: number, unit: UsageUnit): string;
378
+
379
+ export declare function getCardElementStyle(isDark: boolean): StripeCardElementOptions['style'];
380
+
381
+ export declare function getStripeAppearance(isDark: boolean): Appearance;
382
+
383
+ export declare function getStripePromise(publishableKey: string): Promise<Stripe | null>;
384
+
385
+ export declare const GlobeIcon: ({ size, ...props }: IconProps) => JSX.Element;
386
+
387
+ /**
388
+ * Pick a feature glyph from its marketing label (ChatGPT-style top-feature icons).
389
+ * Keyword-matched, with a generic sparkle fallback so every line still gets an icon.
390
+ */
391
+ export declare function iconForFeature(label: string): (props: IconProps) => ReactElement;
392
+
393
+ declare type IconProps = SVGProps<SVGSVGElement> & {
394
+ size?: number;
395
+ };
396
+
397
+ export declare const InfinityIcon: ({ size, ...props }: IconProps) => JSX.Element;
398
+
399
+ /**
400
+ * A dotted-underlined term that reveals an explanatory tooltip on hover or
401
+ * keyboard focus. CSS-only positioning (centered above the term), so it carries
402
+ * no JS/positioning dependency.
403
+ */
404
+ export declare const InfoTooltip: ({ label, children }: InfoTooltipProps) => JSX.Element;
405
+
406
+ export declare type InfoTooltipProps = {
407
+ /** The term to annotate — gets a dotted underline + help cursor. */
408
+ label: ReactNode;
409
+ /** Tooltip body shown on hover/focus. */
410
+ children: ReactNode;
411
+ };
412
+
413
+ /** Floating-label input matching Stripe Elements' field look (grey fill, label inside). */
414
+ export declare const Input: ({ label, className, id, ...props }: InputProps) => JSX.Element;
415
+
416
+ export declare type InputProps = InputHTMLAttributes<HTMLInputElement> & {
417
+ label?: string;
418
+ };
419
+
420
+ export declare type Invoice = Awaited<ReturnType<BillingClient['listInvoices']>>['invoices'][number];
421
+
422
+ /**
423
+ * Read-only billing history. Lists invoices newest-first with status, amount,
424
+ * period, and a PDF download when Stripe provides one.
425
+ */
426
+ export declare const InvoicesDialog: ({ open, onOpenChange }: InvoicesDialogProps) => JSX.Element;
427
+
428
+ export declare type InvoicesDialogProps = {
429
+ open: boolean;
430
+ onOpenChange: (open: boolean) => void;
431
+ };
432
+
433
+ export declare const LayersIcon: ({ size, ...props }: IconProps) => JSX.Element;
434
+
435
+ export declare type LimitPreviewRow = {
436
+ key: string;
437
+ label: string;
438
+ unit: 'count' | 'bytes';
439
+ now: number;
440
+ next: number;
441
+ };
442
+
443
+ export declare const LockIcon: ({ size, ...props }: IconProps) => JSX.Element;
444
+
445
+ /**
446
+ * Add-on management for the CURRENT subscription (Desk's manage-subscription
447
+ * parity): quantities seeded from the live subscription (scheduled `next`
448
+ * first), totals computed client-side, committed as absolute quantities via
449
+ * setAddons — 0 removes an add-on. No plan change involved.
450
+ */
451
+ export declare const ManageAddonsDialog: ({ open, onOpenChange, onSuccess }: ManageAddonsDialogProps) => JSX.Element;
452
+
453
+ export declare type ManageAddonsDialogProps = {
454
+ open: boolean;
455
+ onOpenChange: (open: boolean) => void;
456
+ onSuccess?: () => void;
457
+ };
458
+
459
+ export declare const MessageIcon: ({ size, ...props }: IconProps) => JSX.Element;
460
+
461
+ export declare const MinusIcon: ({ size, ...props }: IconProps) => JSX.Element;
462
+
463
+ /** Smaug reports ai_spend in nano-dollars (1e9 nano = $1) — same as the dashboard. */
464
+ export declare const NANO_DOLLARS_PER_DOLLAR = 1000000000;
465
+
466
+ /**
467
+ * Shown instead of the self-serve flow when the workspace isn't on billing v4
468
+ * (Smaug). Legacy versions (v1–v3) are managed in the Botpress Dashboard.
469
+ */
470
+ export declare const OutdatedBillingGate: () => JSX.Element;
471
+
472
+ export declare const PaintIcon: ({ size, ...props }: IconProps) => JSX.Element;
473
+
474
+ export declare type PaymentMethod = NonNullable<Awaited<ReturnType<BillingClient['getPaymentMethod']>>['paymentMethod']>;
475
+
476
+ export declare type PaymentMethodCard = NonNullable<PaymentMethod['card']>;
477
+
478
+ /**
479
+ * Update the saved card and/or billing address. A fresh SetupIntent is created
480
+ * on open and the whole body mounts inside one <Elements> tree so the
481
+ * CardElement and AddressElement share Stripe context. Card is confirmed via
482
+ * confirmCardSetup (no address required), then persisted; address is saved
483
+ * independently — matching Desk's separation.
484
+ */
485
+ export declare const PaymentMethodDialog: ({ open, onOpenChange, onSuccess }: PaymentMethodDialogProps) => JSX.Element;
486
+
487
+ export declare type PaymentMethodDialogProps = {
488
+ open: boolean;
489
+ onOpenChange: (open: boolean) => void;
490
+ onSuccess?: () => void;
491
+ };
492
+
493
+ export declare type Plan = Awaited<ReturnType<BillingClient['listPlans']>>[number];
494
+
495
+ export declare const PLAN_ORDER: PlanKind[];
496
+
497
+ /**
498
+ * Full-width current-plan hero with per-tier color identity (accent rail + name,
499
+ * soft tinted surface). Surfaces the plan name, total monthly/annual cost
500
+ * (plan + add-ons), conversation allowance, the billing period and when it
501
+ * renews, plus a manage CTA. On legacy billing it deep-links to the Dashboard.
502
+ */
503
+ export declare const PlanBanner: ({ onManage, className }: PlanBannerProps) => JSX.Element;
504
+
505
+ export declare type PlanBannerProps = {
506
+ /** Opens the plan picker / checkout. */
507
+ onManage: () => void;
508
+ className?: string;
509
+ };
510
+
511
+ /** "Plan - Plus" → "Plus" (Smaug prefixes plan names) */
512
+ export declare function planDisplayName(name: string): string;
513
+
514
+ /**
515
+ * Current total entitlements per resource = plan base + active add-on packs.
516
+ * `quantities` maps add-on id → owned quantity (from the live subscription).
517
+ * Returns one row per known resource the plan or its add-ons provide, so a
518
+ * caller can render e.g. "250 + 300 conversations" (base + added).
519
+ */
520
+ export declare function planEntitlements(plan: Plan | undefined, addons: Addon[] | undefined, quantities: Record<string, number>): Entitlement[];
521
+
522
+ /**
523
+ * Canonical plan kinds. Smaug plan ids/names vary by environment, so plans are
524
+ * classified by name — same heuristic as the dashboard's getPlanNameFromId.
525
+ */
526
+ export declare type PlanKind = 'community' | 'plus' | 'team' | 'enterprise' | 'managed';
527
+
528
+ export declare function planKind(plan: Pick<Plan, 'name' | 'metadata'>): PlanKind;
529
+
530
+ /**
531
+ * Clickable summary of the current plan — name, interval, price, conversation
532
+ * allowance. Acts as a preview button that opens the plan-management flow.
533
+ */
534
+ export declare const PlanSummaryCard: ({ onManage, className }: PlanSummaryCardProps) => JSX.Element;
535
+
536
+ export declare type PlanSummaryCardProps = {
537
+ /** Opens the plan picker / checkout. */
538
+ onManage: () => void;
539
+ className?: string;
540
+ };
541
+
542
+ /**
543
+ * Ultra-compact plan + conversations-usage summary for a dropdown/menu.
544
+ * Full-width (adapts to the menu), shows the plan name and a "N left"
545
+ * conversations bar with its reset date. Hidden on legacy billing.
546
+ */
547
+ export declare const PlanUsageWidget: ({ onManage, period, variant, className, style }: PlanUsageWidgetProps) => JSX.Element | null;
548
+
549
+ export declare type PlanUsageWidgetProps = {
550
+ /** Click handler — e.g. open the plan picker or navigate to billing. Renders a › affordance when set. */
551
+ onManage?: () => void;
552
+ /** Period (any datetime in the billing month); defaults to current month. */
553
+ period?: string;
554
+ /**
555
+ * Surface treatment:
556
+ * - 'card' (default) — its own filled, rounded surface.
557
+ * - 'plain' — transparent, no padding; inherits the host container's surface
558
+ * (e.g. to blend into a sidebar). The host owns the background.
559
+ */
560
+ variant?: 'card' | 'plain';
561
+ className?: string;
562
+ /**
563
+ * Inline styles on the root. Handy for overriding the surface via the library's
564
+ * CSS variables, e.g. `style={{ ['--bpb-bg-input']: 'transparent' }}`.
565
+ */
566
+ style?: CSSProperties;
567
+ };
568
+
569
+ export declare const PlusIcon: ({ size, ...props }: IconProps) => JSX.Element;
570
+
571
+ export declare type PreviewLineItem = SubscriptionPreview['costs']['immediate']['lineItems'][number];
572
+
573
+ export declare type Price = NonNullable<Plan['prices']['month']>;
574
+
575
+ export declare const PuzzleIcon: ({ size, ...props }: IconProps) => JSX.Element;
576
+
577
+ declare type QueryOptions = {
578
+ enabled?: boolean;
579
+ };
580
+
581
+ export declare const ReceiptIcon: ({ size, ...props }: IconProps) => JSX.Element;
582
+
583
+ export declare const SegmentedControl: <T extends string>({ options, value, onChange, className, ...aria }: SegmentedControlProps<T>) => JSX.Element;
584
+
585
+ export declare type SegmentedControlOption<T extends string> = {
586
+ value: T;
587
+ label: string;
588
+ badge?: string;
589
+ };
590
+
591
+ export declare type SegmentedControlProps<T extends string> = {
592
+ options: SegmentedControlOption<T>[];
593
+ value: T;
594
+ onChange: (value: T) => void;
595
+ 'aria-label': string;
596
+ className?: string;
597
+ };
598
+
599
+ export declare const Select: ({ label, className, children, ...props }: SelectProps) => JSX.Element;
600
+
601
+ export declare type SelectProps = SelectHTMLAttributes<HTMLSelectElement> & {
602
+ label?: string;
603
+ };
604
+
605
+ declare type SetCustomerInput = {
606
+ name?: string;
607
+ address?: BillingAddress;
608
+ taxIds?: TaxId[];
609
+ };
610
+
611
+ declare type SetSubscriptionInput = {
612
+ planId: string;
613
+ interval: BillingInterval;
614
+ addons?: Record<string, number>;
615
+ couponCode?: string;
616
+ };
617
+
618
+ export declare const ShieldIcon: ({ size, ...props }: IconProps) => JSX.Element;
619
+
620
+ export declare const Skeleton: ({ width, height, rounded, className }: SkeletonProps) => JSX.Element;
621
+
622
+ export declare type SkeletonProps = {
623
+ width?: number | string;
624
+ height?: number | string;
625
+ rounded?: boolean;
626
+ className?: string;
627
+ };
628
+
629
+ export declare const SparkleIcon: ({ size, ...props }: IconProps) => JSX.Element;
630
+
631
+ export declare const Stepper: ({ value, onChange, min, max, step, className, ...aria }: StepperProps) => JSX.Element;
632
+
633
+ export declare type StepperProps = {
634
+ value: number;
635
+ onChange: (value: number) => void;
636
+ min?: number;
637
+ max?: number;
638
+ step?: number;
639
+ 'aria-label': string;
640
+ className?: string;
641
+ };
642
+
643
+ export declare type Subscription = Awaited<ReturnType<BillingClient['getSubscription']>>;
644
+
645
+ export declare type SubscriptionPreview = Awaited<ReturnType<BillingClient['previewSubscriptionUpdate']>>;
646
+
647
+ export declare type SubscriptionStatus = Subscription['plan']['current']['status'];
648
+
649
+ export declare type SubscriptionUpdate = {
650
+ plan: {
651
+ planId: string;
652
+ interval: BillingInterval;
653
+ };
654
+ /** Addon id → desired quantity. 0 removes the addon. */
655
+ addons?: Record<string, number>;
656
+ couponCode?: string;
657
+ };
658
+
659
+ export declare type TaxId = Customer['taxIds'][number];
660
+
661
+ export declare function toStripeLocale(locale: string): string;
662
+
663
+ export declare const UpgradePlanDialog: ({ open, onOpenChange, onSelectPlan, recommendedPlanId, defaultInterval, excludePlanIds, planFeatures, featureDescriptions, }: UpgradePlanDialogProps) => JSX.Element;
664
+
665
+ export declare type UpgradePlanDialogProps = {
666
+ open: boolean;
667
+ onOpenChange: (open: boolean) => void;
668
+ /** Called when the user picks an upgrade — open the CheckoutDialog with these values. */
669
+ onSelectPlan: (planId: string, interval: BillingInterval) => void;
670
+ /** Plan kind (or exact id) to mark as Recommended. Desk recommends `team`. */
671
+ recommendedPlanId?: string;
672
+ defaultInterval?: BillingInterval;
673
+ /** Additional plan ids to hide. Enterprise + managed are always hidden. */
674
+ excludePlanIds?: string[];
675
+ /** Per-kind marketing feature strings; defaults to DEFAULT_PLAN_FEATURES (Desk copy). */
676
+ planFeatures?: Partial<Record<PlanKind, string[]>>;
677
+ /** Feature label → tooltip description; merged over DEFAULT_FEATURE_DESCRIPTIONS. */
678
+ featureDescriptions?: Record<string, string>;
679
+ };
680
+
681
+ /**
682
+ * The user-facing billing quotas surfaced in usage UI. getWorkspaceUsages also
683
+ * returns internal counters (bot count, incoming messages, collaborator count,
684
+ * saved/indexed file counts, …) that aren't billing concerns — keys not listed
685
+ * here are ignored. Order is the display priority.
686
+ */
687
+ export declare const USAGE_METRICS: {
688
+ key: string;
689
+ label: string;
690
+ unit: UsageUnit;
691
+ }[];
692
+
693
+ /**
694
+ * A usage warning banner — visible only when a quota is past `threshold` (90%
695
+ * by default), on billing v4. Renders nothing otherwise (and on legacy billing),
696
+ * so it's safe to mount unconditionally on any page.
697
+ */
698
+ export declare const UsageBanner: ({ position, threshold, onUpgrade, dismissible, ctaLabel, period, className, }: UsageBannerProps) => JSX.Element | null;
699
+
700
+ export declare type UsageBannerProps = {
701
+ /**
702
+ * Mount behavior:
703
+ * - 'inline' (default) — sits in normal flow and pushes the page content down.
704
+ * - 'sticky-top' — sticks to the top of the scroll container.
705
+ * - 'fixed-top' / 'fixed-bottom' — pinned to the viewport (overlays content).
706
+ */
707
+ position?: 'inline' | 'sticky-top' | 'fixed-top' | 'fixed-bottom';
708
+ /** Consumption fraction that triggers the banner (0–1). Default 0.9 (90%). */
709
+ threshold?: number;
710
+ /**
711
+ * Primary CTA handler. If omitted, the banner opens its own plan picker +
712
+ * checkout so it works with zero host wiring.
713
+ */
714
+ onUpgrade?: () => void;
715
+ /** Show a dismiss (×) button. The banner reappears on remount. Default true. */
716
+ dismissible?: boolean;
717
+ /** CTA label. Default "Upgrade plan". */
718
+ ctaLabel?: string;
719
+ /** Period (any datetime in the billing month) to evaluate; defaults to current month. */
720
+ period?: string;
721
+ className?: string;
722
+ };
723
+
724
+ /** A client that can serve per-bot usage (both optional methods present). */
725
+ export declare type UsageBreakdownClient = Required<Pick<Client, 'breakDownWorkspaceUsageByBot' | 'listBots'>>;
726
+
727
+ /** One { botId, value } row from a per-bot usage breakdown. */
728
+ export declare type UsageBreakdownEntry = Awaited<ReturnType<Client['breakDownWorkspaceUsageByBot']>>['data'][number];
729
+
730
+ /**
731
+ * Read-only usage overview for the current billing month, grouped into
732
+ * Conversations / Storage / AI usage. Data comes from getWorkspaceUsages — the
733
+ * UI invents no numbers. A bare-minimum dashboard, not a deep analytics view.
734
+ */
735
+ export declare const UsageDashboard: ({ period, showPeriodSelector, periodMonths, className, }: UsageDashboardProps) => JSX.Element;
736
+
737
+ export declare type UsageDashboardProps = {
738
+ /** Any datetime within the billing month to report; defaults to the current month. */
739
+ period?: string;
740
+ /** Show a month dropdown to browse past billing periods. Default true. */
741
+ showPeriodSelector?: boolean;
742
+ /** How many recent months the period selector offers (incl. current). Default 12. */
743
+ periodMonths?: number;
744
+ className?: string;
745
+ };
746
+
747
+ export declare type UsageEntry = WorkspaceUsages[string];
748
+
749
+ export declare type UsageItem = {
750
+ key: string;
751
+ label: string;
752
+ unit: UsageUnit;
753
+ used: number;
754
+ quota: number;
755
+ remaining: number;
756
+ /** Consumed percentage, 0–100. */
757
+ pct: number;
758
+ };
759
+
760
+ /** Resolve the user-facing usage metrics (with a real quota), highest-consumed first. */
761
+ export declare function usageItems(quotas: WorkspaceUsages | undefined): UsageItem[];
762
+
763
+ /**
764
+ * Wraps any element with a usage popover — a themed card showing the plan,
765
+ * reset date, and every user-facing quota with a mini bar. Reveals on
766
+ * hover/focus after `delay`. Renders the children plainly on legacy billing
767
+ * or when there's no usage to show (the popover just never opens).
768
+ */
769
+ export declare const UsagePopover: ({ children, delay, placement, period, className }: UsagePopoverProps) => JSX.Element;
770
+
771
+ export declare type UsagePopoverProps = {
772
+ /** The trigger — hovering/focusing it reveals the usage popover. */
773
+ children: ReactNode;
774
+ /** Delay in ms before the popover appears on hover/focus. Default 200. */
775
+ delay?: number;
776
+ /** Where the card opens relative to the trigger. Default 'top'. */
777
+ placement?: 'top' | 'bottom';
778
+ /** Period (any datetime in the billing month); defaults to current month. */
779
+ period?: string;
780
+ className?: string;
781
+ };
782
+
783
+ /**
784
+ * A compact circular usage indicator — the ring reflects the MOST-consumed
785
+ * metric across all quotas (conversations, AI spend, storage, …), colored by
786
+ * tier (blue ≤75%, amber 75–90%, red 90%+). Hovering reveals a UsagePopover
787
+ * listing every metric. Renders nothing on legacy billing / while loading.
788
+ */
789
+ export declare const UsageRing: ({ size, thickness, showLabel, onClick, popoverDelay, period, className, ...aria }: UsageRingProps) => JSX.Element | null;
790
+
791
+ export declare type UsageRingProps = {
792
+ /** Diameter in px. Default 20. */
793
+ size?: number;
794
+ /** Ring thickness in px. Default 3.5. */
795
+ thickness?: number;
796
+ /** Show the highest used % beside the ring. Default false. */
797
+ showLabel?: boolean;
798
+ /** Click handler (e.g. open usage / upgrade). */
799
+ onClick?: () => void;
800
+ /** Delay in ms before the usage popover appears on hover/focus. Default 200. */
801
+ popoverDelay?: number;
802
+ /** Period (any datetime in the billing month); defaults to current month. */
803
+ period?: string;
804
+ className?: string;
805
+ 'aria-label'?: string;
806
+ };
807
+
808
+ /** Consumption tier for a used % — drives the blue/amber/red coloring. */
809
+ export declare function usageTier(pct: number): 'normal' | 'warning' | 'critical';
810
+
811
+ export declare type UsageUnit = 'count' | 'bytes' | 'nano-usd';
812
+
813
+ export declare function useAddons(): UseQueryResult<Addon[], Error>;
814
+
815
+ export declare function useBilling(): BillingContextValue;
816
+
817
+ export declare function useBillingAddress(options?: QueryOptions): UseQueryResult<{
818
+ address: BillingAddress | null;
819
+ }, Error>;
820
+
821
+ /** Managed/enterprise locks — when planReadonly, plan changes go through sales. */
822
+ export declare function useBillingReadonly(options?: QueryOptions): UseQueryResult<{
823
+ planReadonly: boolean;
824
+ addonsReadonly: boolean;
825
+ }, Error>;
826
+
827
+ export declare function useCreatePaymentMethodIntent(): UseMutationResult<{
828
+ clientSecret: string;
829
+ }, Error, void>;
830
+
831
+ export declare function useCustomer(options?: QueryOptions): UseQueryResult<Customer, Error>;
832
+
833
+ export declare function useInvoices(options?: QueryOptions): UseQueryResult<{
834
+ invoices: Invoice[];
835
+ meta: {
836
+ nextToken?: string;
837
+ };
838
+ }, Error>;
839
+
840
+ export declare function usePaymentMethod(options?: QueryOptions): UseQueryResult<{
841
+ paymentMethod: PaymentMethod | null;
842
+ }, Error>;
843
+
844
+ export declare function usePlans(): UseQueryResult<Plan[], Error>;
845
+
846
+ export declare const UsersIcon: ({ size, ...props }: IconProps) => JSX.Element;
847
+
848
+ /** Absolute add-on quantities for the current subscription (0 removes an add-on). */
849
+ export declare function useSetAddons(): UseMutationResult<void, Error, {
850
+ addons: Record<string, number>;
851
+ couponCode?: string;
852
+ }>;
853
+
854
+ export declare function useSetBillingAddress(): UseMutationResult<void, Error, BillingAddress>;
855
+
856
+ export declare function useSetCustomer(): UseMutationResult<Customer, Error, SetCustomerInput>;
857
+
858
+ export declare function useSetPaymentMethod(): UseMutationResult<PaymentMethod, Error, {
859
+ paymentMethodId: string;
860
+ }>;
861
+
862
+ /** Commits the plan (and add-ons when provided), then invalidates everything cost-related. */
863
+ export declare function useSetSubscription(): UseMutationResult<void, Error, SetSubscriptionInput>;
864
+
865
+ export declare function useSubscription(options?: QueryOptions): UseQueryResult<Subscription, Error>;
866
+
867
+ /** Proration preview — gate with `enabled` so it only runs while checkout is open. */
868
+ export declare function useSubscriptionPreview(update: SubscriptionUpdate, options?: QueryOptions): UseQueryResult<SubscriptionPreview, Error>;
869
+
870
+ /** Whether the configured client can serve a per-bot usage breakdown. */
871
+ export declare function useSupportsUsageByBot(): boolean;
872
+
873
+ /**
874
+ * Per-feature usage vs. quota for a billing month (defaults to the current month).
875
+ * Returns the `quotas` map keyed by feature (conversation_sessions, table_rows, …).
876
+ */
877
+ export declare function useUsage(options?: QueryOptions & {
878
+ period?: string;
879
+ }): UseQueryResult<WorkspaceUsages, Error>;
880
+
881
+ /**
882
+ * Per-bot usage breakdown for a quota type (e.g. ai_spend), joined with bot names.
883
+ * Returns null when the client doesn't expose the generic per-bot methods (the
884
+ * billing client alone can't do this) — callers should hide the per-bot UI then.
885
+ */
886
+ export declare function useUsageByBot(type: string, options?: QueryOptions & {
887
+ period?: string;
888
+ }): UseQueryResult<BotUsageRow[], Error>;
889
+
890
+ export declare type WorkspaceUsages = Awaited<ReturnType<BillingClient['getWorkspaceUsages']>>['quotas'];
891
+
892
+ export { }