@buildbase/sdk 0.0.18 → 0.0.20

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 (30) hide show
  1. package/README.md +537 -25
  2. package/dist/index.d.ts +784 -62
  3. package/dist/index.esm.js +5 -5
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +5 -5
  6. package/dist/index.js.map +1 -1
  7. package/dist/saas-os.css +1 -1
  8. package/dist/types/api/currency-utils.d.ts +44 -0
  9. package/dist/types/api/index.d.ts +5 -0
  10. package/dist/types/api/pricing-variant-utils.d.ts +53 -0
  11. package/dist/types/api/quota-utils.d.ts +7 -7
  12. package/dist/types/api/types.d.ts +156 -41
  13. package/dist/types/components/features/index.d.ts +16 -4
  14. package/dist/types/components/pricing/PricingPage.d.ts +2 -0
  15. package/dist/types/components/quota/index.d.ts +121 -0
  16. package/dist/types/components/subscription/index.d.ts +12 -3
  17. package/dist/types/components/user/auth.d.ts +8 -2
  18. package/dist/types/components/user/role.d.ts +8 -2
  19. package/dist/types/contexts/QuotaUsageContext/QuotaUsageContext.d.ts +22 -0
  20. package/dist/types/contexts/QuotaUsageContext/index.d.ts +2 -0
  21. package/dist/types/contexts/QuotaUsageContext/quotaUsageInvalidation.d.ts +19 -0
  22. package/dist/types/contexts/QuotaUsageContext/types.d.ts +14 -0
  23. package/dist/types/contexts/SubscriptionContext/types.d.ts +2 -0
  24. package/dist/types/index.d.ts +11 -3
  25. package/dist/types/providers/workspace/api.d.ts +28 -1
  26. package/dist/types/providers/workspace/hooks.d.ts +1 -1
  27. package/dist/types/providers/workspace/subscription-hooks.d.ts +180 -1
  28. package/dist/types/providers/workspace/types.d.ts +18 -1
  29. package/dist/types/providers/workspace/ui/SubscriptionDialog.d.ts +7 -1
  30. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -4,7 +4,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
 
5
5
  interface IDocument {
6
6
  _id: string;
7
- id: string;
7
+ /** Optional; some APIs only return _id. Prefer _id for identity. */
8
+ id?: string;
8
9
  createdAt: string;
9
10
  updatedAt: string;
10
11
  deleted: boolean;
@@ -13,12 +14,17 @@ interface IUser extends IDocument {
13
14
  _id: string;
14
15
  name: string;
15
16
  email: string;
16
- image: string;
17
+ /** Profile image URL. Often omitted or empty from API. */
18
+ image?: string;
17
19
  role: string;
18
- country: string;
19
- timezone: string;
20
- language: string;
21
- currency: string;
20
+ /** ISO country code. May be omitted. */
21
+ country?: string;
22
+ /** IANA timezone. May be omitted. */
23
+ timezone?: string;
24
+ /** Language code. May be omitted. */
25
+ language?: string;
26
+ /** Currency code. May be omitted. */
27
+ currency?: string;
22
28
  attributes?: Record<string, string | number | boolean>;
23
29
  }
24
30
  type BillingInterval = 'monthly' | 'yearly' | 'quarterly';
@@ -36,6 +42,8 @@ interface ISubscription {
36
42
  name: string;
37
43
  slug: string;
38
44
  description?: string;
45
+ /** Stripe currency code (e.g. 'usd', 'inr', 'eur'). */
46
+ currency?: string;
39
47
  };
40
48
  }
41
49
  interface ISubscriptionItem {
@@ -46,17 +54,14 @@ interface ISubscriptionItem {
46
54
  description?: string;
47
55
  category: string;
48
56
  }
49
- interface IQuotaValue {
50
- included: number;
51
- overage?: number;
52
- stripePriceId?: string;
53
- }
54
- /** Per-interval quota value (new plan-group/versions schema) */
57
+ /** Per-interval quota value (plan-group/versions and public plans schema). */
55
58
  interface IQuotaIntervalValue {
56
59
  included: number;
57
- overage: number;
58
- priceId: string;
59
- /** Optional unit size for overage pricing (e.g. 1000 = price per 1000 units). */
60
+ /** Overage price in cents. Omitted in public plans; use pricingVariant.quotaOverages for display. */
61
+ overage?: number;
62
+ /** Stripe price ID for overage. Omitted in public plans; use pricingVariant.quotaOveragePriceIds. */
63
+ priceId?: string;
64
+ /** Unit size for overage pricing (e.g. 1000 = price per 1000 units). */
60
65
  unitSize?: number;
61
66
  }
62
67
  /** Quota defined per billing interval (new plan-group/versions schema) */
@@ -65,11 +70,46 @@ interface IQuotaByInterval {
65
70
  yearly?: IQuotaIntervalValue;
66
71
  quarterly?: IQuotaIntervalValue;
67
72
  }
73
+ /** Base pricing per interval. Values are often in cents (Stripe); convert for display. */
68
74
  interface IBasePricing {
69
75
  monthly: number;
70
76
  yearly: number;
71
77
  quarterly: number;
72
78
  }
79
+ /** Stripe price IDs per billing interval (for a single currency variant). */
80
+ interface IStripePricesByInterval {
81
+ monthlyPriceId?: string;
82
+ yearlyPriceId?: string;
83
+ quarterlyPriceId?: string;
84
+ monthly?: string;
85
+ yearly?: string;
86
+ }
87
+ /** Overage amounts in cents per interval, keyed by quota slug. Used in pricing variants. */
88
+ type IQuotaOveragesByInterval = Record<string, {
89
+ monthly?: number;
90
+ yearly?: number;
91
+ quarterly?: number;
92
+ }>;
93
+ /** Overage Stripe price IDs per interval, keyed by quota slug. Used in pricing variants. */
94
+ type IQuotaOveragePriceIdsByInterval = Record<string, {
95
+ monthly?: string;
96
+ yearly?: string;
97
+ quarterly?: string;
98
+ }>;
99
+ /**
100
+ * Multi-currency pricing variant at plan version level.
101
+ * Each plan version can have multiple variants (e.g. usd, eur, inr, sgd).
102
+ */
103
+ interface IPricingVariant {
104
+ _id: string;
105
+ currency: string;
106
+ basePricing: IBasePricing;
107
+ stripePrices: IStripePricesByInterval;
108
+ /** Overage cents per quota slug per interval. */
109
+ quotaOverages?: IQuotaOveragesByInterval;
110
+ /** Stripe price IDs for overage per quota slug per interval. */
111
+ quotaOveragePriceIds?: IQuotaOveragePriceIdsByInterval;
112
+ }
73
113
  interface IPlanVersion {
74
114
  _id: string;
75
115
  version: number;
@@ -77,16 +117,10 @@ interface IPlanVersion {
77
117
  status: 'draft' | 'published';
78
118
  features?: Record<string, boolean>;
79
119
  limits?: Record<string, number>;
80
- /** Legacy: number | IQuotaValue. New schema: IQuotaByInterval (per-interval included/overage/priceId) */
81
- quotas?: Record<string, number | IQuotaValue | IQuotaByInterval>;
82
- basePricing?: IBasePricing;
83
- stripePrices?: {
84
- monthlyPriceId?: string;
85
- yearlyPriceId?: string;
86
- quarterlyPriceId?: string;
87
- monthly?: string;
88
- yearly?: string;
89
- };
120
+ /** Per-interval quotas (included, unitSize; overage from pricingVariant.quotaOverages). */
121
+ quotas?: Record<string, IQuotaByInterval>;
122
+ /** Multi-currency pricing. Each variant has currency, basePricing, stripePrices, quotaOverages. */
123
+ pricingVariants?: IPricingVariant[];
90
124
  subscriptionItems?: ISubscriptionItem[];
91
125
  isCurrent?: boolean;
92
126
  isLegacy?: boolean;
@@ -106,6 +140,8 @@ interface IPlan {
106
140
  name: string;
107
141
  slug: string;
108
142
  description?: string;
143
+ /** Stripe currency code (e.g. 'usd', 'inr', 'eur'). Used for pricing display. */
144
+ currency?: string;
109
145
  latestVersion?: IPlanVersionSummary;
110
146
  archived?: boolean;
111
147
  deleted?: boolean;
@@ -166,13 +202,19 @@ interface ISubscriptionResponse {
166
202
  group: IPlanGroup | null;
167
203
  groupVersion: IPlanGroupVersion | null;
168
204
  }
205
+ /** Plan version with nested plan info (name, slug, currency for display). */
169
206
  interface IPlanVersionWithPlan extends IPlanVersion {
170
207
  plan: IPlan;
171
208
  }
209
+ /**
210
+ * Plan group version with full plan versions (for GET .../plan-group/versions).
211
+ * Each plan has plan, subscriptionItems, quotas (per-interval), pricingVariants.
212
+ */
172
213
  interface IPlanGroupVersionWithPlans {
173
214
  _id: string;
174
215
  version: number;
175
216
  description?: string;
217
+ /** Full plan versions with nested plan (name, slug, currency). */
176
218
  plans: IPlanVersionWithPlan[];
177
219
  isCurrent?: boolean;
178
220
  whatsNew?: {
@@ -189,21 +231,31 @@ interface IPlanGroupInfo {
189
231
  }
190
232
  /** Response from GET workspaces/:id/subscription/plan-group (and by version). */
191
233
  interface IPlanGroupResponse {
192
- /** Plan group with latestVersion, archived, deleted, timestamps. */
193
- group: IPlanGroup;
234
+ /** Plan group with latestVersion, archived, deleted, timestamps. May be null in some API responses. */
235
+ group: IPlanGroup | null;
194
236
  /** Current group version with populated planVersionIds (or IDs). */
195
237
  groupVersion: IPlanGroupVersion;
196
- /** Full plan versions for display (subscriptionItems, basePricing, quotas, etc.). */
238
+ /** Full plan versions for display (subscriptionItems, pricingVariants, quotas). */
197
239
  plans: IPlanVersionWithPlan[];
198
240
  }
241
+ /**
242
+ * Response from GET workspaces/:workspaceId/subscription/plan-group/versions.
243
+ * Group summary plus current and available group versions; each version has plans with
244
+ * per-interval quotas and pricingVariants.
245
+ */
199
246
  interface IPlanGroupVersionsResponse {
247
+ /** Plan group summary (_id, name, slug). */
200
248
  group: IPlanGroupInfo;
249
+ /** Current group version (user's version when subscribed, or latest published when not). */
201
250
  currentVersion: IPlanGroupVersionWithPlans;
251
+ /** Newer versions when user has subscription; empty when no subscription. */
202
252
  availableVersions: IPlanGroupVersionWithPlans[];
203
253
  }
254
+ /** Request body for POST .../workspaces/:id/subscription/checkout. Only these fields are allowed. */
204
255
  interface ICheckoutSessionRequest {
205
256
  planVersionId: string;
206
257
  billingInterval?: BillingInterval;
258
+ currency?: string;
207
259
  successUrl?: string;
208
260
  cancelUrl?: string;
209
261
  }
@@ -218,6 +270,7 @@ interface ICheckoutSessionResponse {
218
270
  name: string;
219
271
  };
220
272
  }
273
+ /** Request body for PATCH .../workspaces/:id/subscription. Only these fields are allowed. */
221
274
  interface ISubscriptionUpdateRequest {
222
275
  planVersionId: string;
223
276
  billingInterval?: BillingInterval;
@@ -244,33 +297,33 @@ interface IPublicPlanItem {
244
297
  _id: string;
245
298
  name: string;
246
299
  slug: string;
247
- description: string;
300
+ description?: string;
248
301
  type: 'feature' | 'limit' | 'quota';
249
302
  category: IPublicPlanItemCategory;
250
303
  }
251
- interface IPublicPlanPricing {
252
- monthly: number;
253
- yearly: number;
254
- quarterly: number;
255
- }
256
- interface IPublicPlanQuotaValue {
257
- included: number;
258
- overage: number;
259
- stripePriceId?: string;
260
- }
304
+ /**
305
+ * Public plan version (e.g. from GET /api/v1/public/:orgId/plans/:slug).
306
+ * Each plan has _id, name (plan display name), version, status, pricingVariants, quotas, features, limits.
307
+ * Pricing is in cents (see response.notes).
308
+ */
261
309
  interface IPublicPlanVersion {
262
310
  _id: string;
311
+ /** Plan display name (e.g. "Pro", "Base Plan"). */
263
312
  name: string;
264
313
  version: number;
265
314
  status: 'draft' | 'published';
266
- pricing: IPublicPlanPricing;
267
- quotas: Record<string, IPublicPlanQuotaValue>;
315
+ /** Multi-currency pricing. Use getBasePriceCents(plan, currency, interval) and getQuotaDisplayWithVariant for display. */
316
+ pricingVariants?: IPricingVariant[];
317
+ /** Keyed by item slug. Per-interval: included, unitSize; overage from pricingVariant.quotaOverages. */
318
+ quotas: Record<string, IQuotaByInterval>;
268
319
  features: Record<string, boolean>;
269
320
  limits: Record<string, number>;
270
321
  }
271
322
  interface IPublicPlansResponse {
272
323
  items: IPublicPlanItem[];
273
324
  plans: IPublicPlanVersion[];
325
+ /** Optional note from API (e.g. "Pricing is in cents. Please convert to dollars for display."). */
326
+ notes?: string;
274
327
  }
275
328
  type InvoiceStatus = 'draft' | 'open' | 'paid' | 'uncollectible' | 'void';
276
329
  interface IInvoice {
@@ -296,6 +349,68 @@ interface IInvoiceResponse {
296
349
  success: boolean;
297
350
  invoice: IInvoice;
298
351
  }
352
+ /** Request body for POST .../workspaces/:id/subscription/usage */
353
+ interface IRecordUsageRequest {
354
+ quotaSlug: string;
355
+ quantity: number;
356
+ metadata?: Record<string, unknown>;
357
+ source?: string;
358
+ idempotencyKey?: string;
359
+ }
360
+ /** Response from POST .../workspaces/:id/subscription/usage */
361
+ interface IRecordUsageResponse {
362
+ used: number;
363
+ consumed: number;
364
+ included: number;
365
+ available: number;
366
+ overage: number;
367
+ billedAsync: boolean;
368
+ }
369
+ /** Single quota usage status (shared between status and all endpoints). */
370
+ interface IQuotaUsageStatus {
371
+ consumed: number;
372
+ included: number;
373
+ available: number;
374
+ overage: number;
375
+ hasOverage: boolean;
376
+ }
377
+ /** Response from GET .../workspaces/:id/subscription/usage/status?quotaSlug=X */
378
+ interface IQuotaUsageStatusResponse extends IQuotaUsageStatus {
379
+ quotaSlug: string;
380
+ }
381
+ /** Response from GET .../workspaces/:id/subscription/usage/all */
382
+ interface IAllQuotaUsageResponse {
383
+ quotas: Record<string, IQuotaUsageStatus>;
384
+ }
385
+ /** Single usage log entry from GET .../usage/logs */
386
+ interface IUsageLogEntry {
387
+ _id: string;
388
+ quotaSlug: string;
389
+ quantity: number;
390
+ source?: string;
391
+ workspace: string;
392
+ createdAt: string;
393
+ updatedAt: string;
394
+ }
395
+ /** Query parameters for GET .../workspaces/:id/subscription/usage/logs */
396
+ interface IUsageLogsQuery {
397
+ quotaSlug?: string;
398
+ from?: string;
399
+ to?: string;
400
+ source?: string;
401
+ page?: number;
402
+ limit?: number;
403
+ }
404
+ /** Paginated response from GET .../workspaces/:id/subscription/usage/logs */
405
+ interface IUsageLogsResponse {
406
+ docs: IUsageLogEntry[];
407
+ totalDocs: number;
408
+ limit: number;
409
+ page: number;
410
+ totalPages: number;
411
+ hasNextPage: boolean;
412
+ hasPrevPage: boolean;
413
+ }
299
414
 
300
415
  interface IWorkspace {
301
416
  _id: string;
@@ -306,7 +421,24 @@ interface IWorkspace {
306
421
  roles: string[];
307
422
  createdBy: string | IUser;
308
423
  features: Record<string, boolean>;
309
- subscription?: ISubscription | null;
424
+ /**
425
+ * Quota usage tracking: { [quotaSlug]: number } – how much of each quota has been used.
426
+ */
427
+ quotas?: Record<string, number>;
428
+ /**
429
+ * Subscription limits snapshot: { [limitSlug]: number | null } – synced from subscription plan.
430
+ * Limits are maximum values (e.g. max-users, max-workspaces). Updated when subscription is assigned/updated.
431
+ */
432
+ limits?: Record<string, number | null>;
433
+ subscription?: ISubscription | string | null;
434
+ /** Stripe Customer ID for this workspace. */
435
+ stripeCustomerId?: string;
436
+ /**
437
+ * Billing currency locked for this workspace (set on first subscription).
438
+ * Stripe allows one currency per customer; all future subscriptions must use this currency.
439
+ * When set, subscription UI only shows/uses this currency.
440
+ */
441
+ billingCurrency?: string | null;
310
442
  }
311
443
  interface IWorkspaceFeature {
312
444
  _id: string;
@@ -500,6 +632,8 @@ interface PricingPageDetails {
500
632
  items: IPublicPlanItem[];
501
633
  /** Plan versions with pricing, features, limits, quotas */
502
634
  plans: IPublicPlanVersion[];
635
+ /** Optional note from API (e.g. "Pricing is in cents. Please convert to dollars for display.") */
636
+ notes?: string;
503
637
  /** Refetch plan data */
504
638
  refetch: () => Promise<void>;
505
639
  }
@@ -563,7 +697,10 @@ interface IProps$2 {
563
697
  * }
564
698
  * ```
565
699
  */
566
- declare const WhenAuthenticated: (props: IProps$2) => react.ReactNode;
700
+ declare const WhenAuthenticated: {
701
+ (props: IProps$2): react.ReactNode;
702
+ displayName: string;
703
+ };
567
704
  /**
568
705
  * Conditional component that renders children only when user is NOT authenticated.
569
706
  * Returns null if user is authenticated.
@@ -605,7 +742,10 @@ declare const WhenAuthenticated: (props: IProps$2) => react.ReactNode;
605
742
  * }
606
743
  * ```
607
744
  */
608
- declare const WhenUnauthenticated: (props: IProps$2) => react.ReactNode;
745
+ declare const WhenUnauthenticated: {
746
+ (props: IProps$2): react.ReactNode;
747
+ displayName: string;
748
+ };
609
749
 
610
750
  interface IProps$1 {
611
751
  roles: string[];
@@ -647,7 +787,10 @@ interface IProps$1 {
647
787
  * }
648
788
  * ```
649
789
  */
650
- declare const WhenRoles: (props: IProps$1) => react.ReactNode;
790
+ declare const WhenRoles: {
791
+ (props: IProps$1): react.ReactNode;
792
+ displayName: string;
793
+ };
651
794
  /**
652
795
  * Conditional component that renders children only when user has one of the specified roles
653
796
  * in the current workspace. Checks workspace-specific role, not global role.
@@ -683,7 +826,10 @@ declare const WhenRoles: (props: IProps$1) => react.ReactNode;
683
826
  * }
684
827
  * ```
685
828
  */
686
- declare const WhenWorkspaceRoles: (props: IProps$1) => react.ReactNode;
829
+ declare const WhenWorkspaceRoles: {
830
+ (props: IProps$1): react.ReactNode;
831
+ displayName: string;
832
+ };
687
833
 
688
834
  interface IProps {
689
835
  slug: string;
@@ -725,7 +871,10 @@ interface IProps {
725
871
  * }
726
872
  * ```
727
873
  */
728
- declare const WhenWorkspaceFeatureEnabled: (props: IProps) => react.ReactNode;
874
+ declare const WhenWorkspaceFeatureEnabled: {
875
+ (props: IProps): react.ReactNode;
876
+ displayName: string;
877
+ };
729
878
  /**
730
879
  * Conditional component that renders children only when the specified workspace feature is disabled.
731
880
  * Checks feature flags at the workspace level.
@@ -745,7 +894,10 @@ declare const WhenWorkspaceFeatureEnabled: (props: IProps) => react.ReactNode;
745
894
  * }
746
895
  * ```
747
896
  */
748
- declare const WhenWorkspaceFeatureDisabled: (props: IProps) => react.ReactNode;
897
+ declare const WhenWorkspaceFeatureDisabled: {
898
+ (props: IProps): react.ReactNode;
899
+ displayName: string;
900
+ };
749
901
  /**
750
902
  * Conditional component that renders children only when the specified user feature is enabled.
751
903
  * Checks feature flags at the user level (from UserProvider).
@@ -781,7 +933,10 @@ declare const WhenWorkspaceFeatureDisabled: (props: IProps) => react.ReactNode;
781
933
  * }
782
934
  * ```
783
935
  */
784
- declare const WhenUserFeatureEnabled: (props: IProps) => react.ReactNode;
936
+ declare const WhenUserFeatureEnabled: {
937
+ (props: IProps): react.ReactNode;
938
+ displayName: string;
939
+ };
785
940
  /**
786
941
  * Conditional component that renders children only when the specified user feature is disabled.
787
942
  * Checks feature flags at the user level (from UserProvider).
@@ -801,7 +956,10 @@ declare const WhenUserFeatureEnabled: (props: IProps) => react.ReactNode;
801
956
  * }
802
957
  * ```
803
958
  */
804
- declare const WhenUserFeatureDisabled: (props: IProps) => react.ReactNode;
959
+ declare const WhenUserFeatureDisabled: {
960
+ (props: IProps): react.ReactNode;
961
+ displayName: string;
962
+ };
805
963
 
806
964
  interface IWhenSubscriptionProps {
807
965
  /** Content to render when the condition is met (workspace has an active subscription). */
@@ -839,7 +997,10 @@ interface IWhenSubscriptionProps {
839
997
  * </WhenSubscription>
840
998
  * ```
841
999
  */
842
- declare const WhenSubscription: (props: IWhenSubscriptionProps) => react.ReactNode;
1000
+ declare const WhenSubscription: {
1001
+ (props: IWhenSubscriptionProps): react.ReactNode;
1002
+ displayName: string;
1003
+ };
843
1004
  /**
844
1005
  * Renders children only when the current workspace has no subscription (or no current workspace).
845
1006
  * Optionally pass loadingComponent (while loading) or fallbackComponent (when already subscribed).
@@ -868,7 +1029,10 @@ declare const WhenSubscription: (props: IWhenSubscriptionProps) => react.ReactNo
868
1029
  * </WhenNoSubscription>
869
1030
  * ```
870
1031
  */
871
- declare const WhenNoSubscription: (props: IWhenSubscriptionProps) => react.ReactNode;
1032
+ declare const WhenNoSubscription: {
1033
+ (props: IWhenSubscriptionProps): react.ReactNode;
1034
+ displayName: string;
1035
+ };
872
1036
  interface IWhenSubscriptionToPlansProps {
873
1037
  /** Plan slugs to match (e.g. ['pro', 'enterprise']). Matching is case-insensitive. */
874
1038
  plans: string[];
@@ -909,7 +1073,131 @@ interface IWhenSubscriptionToPlansProps {
909
1073
  * </WhenSubscriptionToPlans>
910
1074
  * ```
911
1075
  */
912
- declare const WhenSubscriptionToPlans: (props: IWhenSubscriptionToPlansProps) => react.ReactNode;
1076
+ declare const WhenSubscriptionToPlans: {
1077
+ (props: IWhenSubscriptionToPlansProps): react.ReactNode;
1078
+ displayName: string;
1079
+ };
1080
+
1081
+ interface IWhenQuotaProps {
1082
+ /** Quota slug to check (e.g. 'api_calls', 'emails', 'storage'). */
1083
+ slug: string;
1084
+ /** Content to render when the condition is met. */
1085
+ children: React.ReactNode;
1086
+ /** Optional component/element to show while quota usage is loading (e.g. <Skeleton />). */
1087
+ loadingComponent?: React.ReactNode;
1088
+ /** Optional component/element to show when condition is not met (e.g. <UpgradePrompt />). */
1089
+ fallbackComponent?: React.ReactNode;
1090
+ }
1091
+ interface IWhenQuotaThresholdProps extends IWhenQuotaProps {
1092
+ /** Usage percentage threshold (0-100). Children render when usage >= this percentage. */
1093
+ threshold: number;
1094
+ }
1095
+ /**
1096
+ * Renders children only when the specified quota has remaining units (available > 0).
1097
+ * Must be used within QuotaUsageContextProvider (included in SaaSOSProvider by default).
1098
+ *
1099
+ * @example
1100
+ * ```tsx
1101
+ * <WhenQuotaAvailable slug="api_calls">
1102
+ * <MakeApiCallButton />
1103
+ * </WhenQuotaAvailable>
1104
+ * ```
1105
+ *
1106
+ * @example
1107
+ * ```tsx
1108
+ * <WhenQuotaAvailable
1109
+ * slug="emails"
1110
+ * loadingComponent={<Skeleton />}
1111
+ * fallbackComponent={<p>Email quota exhausted. <UpgradeLink /></p>}
1112
+ * >
1113
+ * <SendEmailButton />
1114
+ * </WhenQuotaAvailable>
1115
+ * ```
1116
+ */
1117
+ declare const WhenQuotaAvailable: {
1118
+ (props: IWhenQuotaProps): react.ReactNode;
1119
+ displayName: string;
1120
+ };
1121
+ /**
1122
+ * Renders children only when the specified quota is fully consumed (available <= 0).
1123
+ * Must be used within QuotaUsageContextProvider (included in SaaSOSProvider by default).
1124
+ *
1125
+ * @example
1126
+ * ```tsx
1127
+ * <WhenQuotaExhausted slug="api_calls">
1128
+ * <UpgradePrompt message="You've used all your API calls this month." />
1129
+ * </WhenQuotaExhausted>
1130
+ * ```
1131
+ *
1132
+ * @example
1133
+ * ```tsx
1134
+ * <WhenQuotaExhausted
1135
+ * slug="storage"
1136
+ * loadingComponent={<Spinner />}
1137
+ * fallbackComponent={null}
1138
+ * >
1139
+ * <StorageFullBanner />
1140
+ * </WhenQuotaExhausted>
1141
+ * ```
1142
+ */
1143
+ declare const WhenQuotaExhausted: {
1144
+ (props: IWhenQuotaProps): react.ReactNode;
1145
+ displayName: string;
1146
+ };
1147
+ /**
1148
+ * Renders children only when the specified quota is in overage (consumed > included).
1149
+ * Must be used within QuotaUsageContextProvider (included in SaaSOSProvider by default).
1150
+ *
1151
+ * @example
1152
+ * ```tsx
1153
+ * <WhenQuotaOverage slug="api_calls">
1154
+ * <OverageBillingWarning />
1155
+ * </WhenQuotaOverage>
1156
+ * ```
1157
+ *
1158
+ * @example
1159
+ * ```tsx
1160
+ * <WhenQuotaOverage
1161
+ * slug="emails"
1162
+ * loadingComponent={<Skeleton />}
1163
+ * fallbackComponent={null}
1164
+ * >
1165
+ * <p>You are being billed for overage usage.</p>
1166
+ * </WhenQuotaOverage>
1167
+ * ```
1168
+ */
1169
+ declare const WhenQuotaOverage: {
1170
+ (props: IWhenQuotaProps): react.ReactNode;
1171
+ displayName: string;
1172
+ };
1173
+ /**
1174
+ * Renders children when the specified quota's usage percentage reaches or exceeds the threshold.
1175
+ * Usage percentage = (consumed / included) * 100. If included is 0 and consumed > 0, treats as 100%.
1176
+ * Must be used within QuotaUsageContextProvider (included in SaaSOSProvider by default).
1177
+ *
1178
+ * @example
1179
+ * ```tsx
1180
+ * <WhenQuotaThreshold slug="api_calls" threshold={80}>
1181
+ * <p>Warning: You've used over 80% of your API calls.</p>
1182
+ * </WhenQuotaThreshold>
1183
+ * ```
1184
+ *
1185
+ * @example
1186
+ * ```tsx
1187
+ * <WhenQuotaThreshold
1188
+ * slug="storage"
1189
+ * threshold={90}
1190
+ * loadingComponent={<Spinner />}
1191
+ * fallbackComponent={null}
1192
+ * >
1193
+ * <StorageWarningBanner />
1194
+ * </WhenQuotaThreshold>
1195
+ * ```
1196
+ */
1197
+ declare const WhenQuotaThreshold: {
1198
+ (props: IWhenQuotaThresholdProps): react.ReactNode;
1199
+ displayName: string;
1200
+ };
913
1201
 
914
1202
  /**
915
1203
  * Value provided by SubscriptionContext and returned by useSubscriptionContext.
@@ -919,6 +1207,8 @@ interface SubscriptionContextValue {
919
1207
  response: ISubscriptionResponse | null;
920
1208
  /** True while subscription is being fetched. */
921
1209
  loading: boolean;
1210
+ /** Error message if the last fetch failed, or null. */
1211
+ error: string | null;
922
1212
  /** Refetch subscription for the current workspace. Call after plan change (e.g. upgrade) or when subscription was updated elsewhere. */
923
1213
  refetch: () => Promise<void>;
924
1214
  }
@@ -944,6 +1234,53 @@ declare const SubscriptionContextProvider: react__default.FC<{
944
1234
  */
945
1235
  declare function useSubscriptionContext(): SubscriptionContextValue;
946
1236
 
1237
+ /**
1238
+ * Notify all subscribers to refetch subscription (e.g. after update/cancel/resume).
1239
+ * Called internally by useUpdateSubscription, useCancelSubscription, useResumeSubscription on success.
1240
+ */
1241
+ declare function invalidateSubscription(): void;
1242
+
1243
+ /**
1244
+ * Value provided by QuotaUsageContext and returned by useQuotaUsageContext.
1245
+ */
1246
+ interface QuotaUsageContextValue {
1247
+ /** Current quota usage statuses keyed by slug, or null if not loaded. */
1248
+ quotas: Record<string, IQuotaUsageStatus> | null;
1249
+ /** True while quota usage is being fetched. */
1250
+ loading: boolean;
1251
+ /** Error message if the last fetch failed, or null. */
1252
+ error: string | null;
1253
+ /** Refetch all quota usage for the current workspace. Call after recording usage or when usage was updated elsewhere. */
1254
+ refetch: () => Promise<void>;
1255
+ }
1256
+
1257
+ /**
1258
+ * Provides quota usage data for the current workspace to quota gate components.
1259
+ * Fetches when workspace changes; refetches when quota usage is invalidated (e.g. after recording usage).
1260
+ * Must wrap (or be ancestor of) any component that uses WhenQuotaAvailable, WhenQuotaExhausted,
1261
+ * WhenQuotaOverage, WhenQuotaThreshold, or useQuotaUsageContext. Included in SaaSOSProvider by default.
1262
+ *
1263
+ * @param props - Component props
1264
+ * @param props.children - React tree that may use quota gates or useQuotaUsageContext
1265
+ * @returns Provider element that supplies quota usage context to descendants
1266
+ */
1267
+ declare const QuotaUsageContextProvider: react__default.FC<{
1268
+ children: ReactNode;
1269
+ }>;
1270
+ /**
1271
+ * Returns quota usage data for the current workspace. Must be used within QuotaUsageContextProvider.
1272
+ *
1273
+ * @returns QuotaUsageContextValue - { quotas, loading, refetch }
1274
+ * @throws Error if used outside QuotaUsageContextProvider
1275
+ */
1276
+ declare function useQuotaUsageContext(): QuotaUsageContextValue;
1277
+
1278
+ /**
1279
+ * Notify all subscribers to refetch quota usage (e.g. after recording usage).
1280
+ * Called internally by useRecordUsage on success.
1281
+ */
1282
+ declare function invalidateQuotaUsage(): void;
1283
+
947
1284
  type WorkspaceSettingsSection = 'profile' | 'general' | 'users' | 'subscription' | 'features' | 'danger';
948
1285
 
949
1286
  declare function useSaaSAuth(): {
@@ -1283,6 +1620,33 @@ declare class WorkspaceApi extends BaseApi {
1283
1620
  * @returns Updated subscription with cancelAtPeriodEnd set to false
1284
1621
  */
1285
1622
  resumeSubscription(workspaceId: string): Promise<ISubscriptionResponse>;
1623
+ /**
1624
+ * Record quota usage for a workspace
1625
+ * @param workspaceId - The workspace ID
1626
+ * @param request - Usage request with quotaSlug, quantity, and optional metadata/source
1627
+ * @returns Usage result with consumed/included/available/overage
1628
+ */
1629
+ recordUsage(workspaceId: string, request: IRecordUsageRequest): Promise<IRecordUsageResponse>;
1630
+ /**
1631
+ * Get usage status for a single quota
1632
+ * @param workspaceId - The workspace ID
1633
+ * @param quotaSlug - The quota slug to check
1634
+ * @returns Quota usage status with consumed/included/available/overage/hasOverage
1635
+ */
1636
+ getQuotaUsageStatus(workspaceId: string, quotaSlug: string): Promise<IQuotaUsageStatusResponse>;
1637
+ /**
1638
+ * Get usage status for all quotas in the workspace's current plan
1639
+ * @param workspaceId - The workspace ID
1640
+ * @returns All quota usage statuses keyed by quota slug
1641
+ */
1642
+ getAllQuotaUsage(workspaceId: string): Promise<IAllQuotaUsageResponse>;
1643
+ /**
1644
+ * Get paginated usage logs for a workspace
1645
+ * @param workspaceId - The workspace ID
1646
+ * @param query - Optional filters: quotaSlug, from, to, source, page, limit
1647
+ * @returns Paginated usage log entries
1648
+ */
1649
+ getUsageLogs(workspaceId: string, query?: IUsageLogsQuery): Promise<IUsageLogsResponse>;
1286
1650
  }
1287
1651
 
1288
1652
  declare const useSaaSWorkspaces: () => {
@@ -1300,7 +1664,7 @@ declare const useSaaSWorkspaces: () => {
1300
1664
  forceEmit?: boolean;
1301
1665
  }) => Promise<void>;
1302
1666
  resetCurrentWorkspace: () => void;
1303
- createWorkspace: (name: string, image: string) => Promise<void>;
1667
+ createWorkspace: (name: string, image?: string) => Promise<void>;
1304
1668
  allFeatures: IWorkspaceFeature[];
1305
1669
  getFeatures: () => Promise<IWorkspaceFeature[] | null>;
1306
1670
  updateFeature: (workspaceId: string, key: string, value: boolean) => Promise<IWorkspace>;
@@ -1346,6 +1710,7 @@ declare function WorkspaceSwitcher(props: {
1346
1710
  declare const usePublicPlans: (slug: string) => {
1347
1711
  items: IPublicPlanItem[];
1348
1712
  plans: IPublicPlanVersion[];
1713
+ notes: string | undefined;
1349
1714
  loading: boolean;
1350
1715
  error: string | null;
1351
1716
  refetch: () => Promise<void>;
@@ -1816,6 +2181,264 @@ declare const useInvoice: (workspaceId: string | null | undefined, invoiceId: st
1816
2181
  error: string | null;
1817
2182
  refetch: () => Promise<void>;
1818
2183
  };
2184
+ /**
2185
+ * Hook to cancel a subscription at the end of the current billing period.
2186
+ * Sets cancelAtPeriodEnd: true - subscription remains active until period ends.
2187
+ *
2188
+ * @param workspaceId - The workspace ID. Can be null/undefined.
2189
+ * @returns An object containing:
2190
+ * - `cancelSubscription()`: Function to cancel subscription at period end
2191
+ * - `loading`: Boolean indicating if cancellation is in progress
2192
+ * - `error`: Error message string (null if no error)
2193
+ *
2194
+ * @example
2195
+ * ```tsx
2196
+ * function CancelSubscriptionButton() {
2197
+ * const { currentWorkspace } = useSaaSWorkspaces();
2198
+ * const { cancelSubscription, loading } = useCancelSubscription(currentWorkspace?._id);
2199
+ * const { refetch } = useSubscription(currentWorkspace?._id);
2200
+ *
2201
+ * const handleCancel = async () => {
2202
+ * try {
2203
+ * await cancelSubscription();
2204
+ * await refetch(); // Refresh subscription data
2205
+ * alert('Subscription will be canceled at the end of the billing period');
2206
+ * } catch (error) {
2207
+ * console.error('Failed to cancel:', error);
2208
+ * }
2209
+ * };
2210
+ *
2211
+ * return (
2212
+ * <button onClick={handleCancel} disabled={loading}>
2213
+ * {loading ? 'Canceling...' : 'Cancel Subscription'}
2214
+ * </button>
2215
+ * );
2216
+ * }
2217
+ * ```
2218
+ */
2219
+ declare const useCancelSubscription: (workspaceId: string | null | undefined) => {
2220
+ cancelSubscription: () => Promise<ISubscriptionResponse>;
2221
+ loading: boolean;
2222
+ error: string | null;
2223
+ };
2224
+ /**
2225
+ * Hook to resume a subscription that was scheduled for cancellation.
2226
+ * Sets cancelAtPeriodEnd: false - subscription will continue after period ends.
2227
+ *
2228
+ * @param workspaceId - The workspace ID. Can be null/undefined.
2229
+ * @returns An object containing:
2230
+ * - `resumeSubscription()`: Function to resume subscription
2231
+ * - `loading`: Boolean indicating if resume is in progress
2232
+ * - `error`: Error message string (null if no error)
2233
+ *
2234
+ * @example
2235
+ * ```tsx
2236
+ * function ResumeSubscriptionButton() {
2237
+ * const { currentWorkspace } = useSaaSWorkspaces();
2238
+ * const { resumeSubscription, loading } = useResumeSubscription(currentWorkspace?._id);
2239
+ * const { refetch } = useSubscription(currentWorkspace?._id);
2240
+ *
2241
+ * const handleResume = async () => {
2242
+ * try {
2243
+ * await resumeSubscription();
2244
+ * await refetch(); // Refresh subscription data
2245
+ * alert('Subscription has been resumed');
2246
+ * } catch (error) {
2247
+ * console.error('Failed to resume:', error);
2248
+ * }
2249
+ * };
2250
+ *
2251
+ * return (
2252
+ * <button onClick={handleResume} disabled={loading}>
2253
+ * {loading ? 'Resuming...' : 'Resume Subscription'}
2254
+ * </button>
2255
+ * );
2256
+ * }
2257
+ * ```
2258
+ */
2259
+ declare const useResumeSubscription: (workspaceId: string | null | undefined) => {
2260
+ resumeSubscription: () => Promise<ISubscriptionResponse>;
2261
+ loading: boolean;
2262
+ error: string | null;
2263
+ };
2264
+ /**
2265
+ * Hook to record quota usage for a workspace.
2266
+ * Returns a function to record usage (mutation pattern).
2267
+ *
2268
+ * @param workspaceId - The workspace ID. Can be null/undefined.
2269
+ * @returns An object containing:
2270
+ * - `recordUsage(request)`: Function to record usage (throws if workspaceId is null)
2271
+ * - `loading`: Boolean indicating if recording is in progress
2272
+ * - `error`: Error message string (null if no error)
2273
+ *
2274
+ * @example
2275
+ * ```tsx
2276
+ * function RecordUsageButton() {
2277
+ * const { currentWorkspace } = useSaaSWorkspaces();
2278
+ * const { recordUsage, loading } = useRecordUsage(currentWorkspace?._id);
2279
+ *
2280
+ * const handleRecord = async () => {
2281
+ * try {
2282
+ * const result = await recordUsage({
2283
+ * quotaSlug: 'api_calls',
2284
+ * quantity: 1,
2285
+ * source: 'web-app',
2286
+ * });
2287
+ * console.log(`Used: ${result.consumed}/${result.included}`);
2288
+ * } catch (error) {
2289
+ * console.error('Failed to record usage:', error);
2290
+ * }
2291
+ * };
2292
+ *
2293
+ * return (
2294
+ * <button onClick={handleRecord} disabled={loading}>
2295
+ * {loading ? 'Recording...' : 'Record Usage'}
2296
+ * </button>
2297
+ * );
2298
+ * }
2299
+ * ```
2300
+ */
2301
+ declare const useRecordUsage: (workspaceId: string | null | undefined) => {
2302
+ recordUsage: (request: IRecordUsageRequest) => Promise<IRecordUsageResponse>;
2303
+ loading: boolean;
2304
+ error: string | null;
2305
+ };
2306
+ /**
2307
+ * Hook to get usage status for a single quota.
2308
+ * Automatically fetches when workspaceId or quotaSlug changes.
2309
+ *
2310
+ * @param workspaceId - The workspace ID. Can be null/undefined to disable fetching.
2311
+ * @param quotaSlug - The quota slug to check. Can be null/undefined to disable fetching.
2312
+ * @returns An object containing:
2313
+ * - `status`: Quota usage status (null if not loaded)
2314
+ * - `loading`: Boolean indicating if status is being fetched
2315
+ * - `error`: Error message string (null if no error)
2316
+ * - `refetch()`: Function to manually refetch the status
2317
+ *
2318
+ * @example
2319
+ * ```tsx
2320
+ * function QuotaStatusDisplay() {
2321
+ * const { currentWorkspace } = useSaaSWorkspaces();
2322
+ * const { status, loading } = useQuotaUsageStatus(currentWorkspace?._id, 'api_calls');
2323
+ *
2324
+ * if (loading) return <Loading />;
2325
+ * if (!status) return null;
2326
+ *
2327
+ * return (
2328
+ * <div>
2329
+ * <p>Used: {status.consumed} / {status.included}</p>
2330
+ * <p>Available: {status.available}</p>
2331
+ * {status.hasOverage && <p>Overage: {status.overage}</p>}
2332
+ * </div>
2333
+ * );
2334
+ * }
2335
+ * ```
2336
+ */
2337
+ declare const useQuotaUsageStatus: (workspaceId: string | null | undefined, quotaSlug: string | null | undefined) => {
2338
+ status: IQuotaUsageStatusResponse | null;
2339
+ loading: boolean;
2340
+ error: string | null;
2341
+ refetch: () => Promise<void>;
2342
+ };
2343
+ /**
2344
+ * Hook to get usage status for all quotas in the workspace's current plan.
2345
+ * Automatically fetches when workspaceId changes.
2346
+ *
2347
+ * @param workspaceId - The workspace ID. Can be null/undefined to disable fetching.
2348
+ * @returns An object containing:
2349
+ * - `quotas`: Record of quota usage statuses keyed by slug (null if not loaded)
2350
+ * - `loading`: Boolean indicating if statuses are being fetched
2351
+ * - `error`: Error message string (null if no error)
2352
+ * - `refetch()`: Function to manually refetch all statuses
2353
+ *
2354
+ * @example
2355
+ * ```tsx
2356
+ * function AllQuotasDisplay() {
2357
+ * const { currentWorkspace } = useSaaSWorkspaces();
2358
+ * const { quotas, loading } = useAllQuotaUsage(currentWorkspace?._id);
2359
+ *
2360
+ * if (loading) return <Loading />;
2361
+ * if (!quotas) return null;
2362
+ *
2363
+ * return (
2364
+ * <div>
2365
+ * {Object.entries(quotas).map(([slug, usage]) => (
2366
+ * <div key={slug}>
2367
+ * <p>{slug}: {usage.consumed}/{usage.included}</p>
2368
+ * {usage.hasOverage && <p>Overage: {usage.overage}</p>}
2369
+ * </div>
2370
+ * ))}
2371
+ * </div>
2372
+ * );
2373
+ * }
2374
+ * ```
2375
+ */
2376
+ declare const useAllQuotaUsage: (workspaceId: string | null | undefined) => {
2377
+ quotas: Record<string, IQuotaUsageStatus> | null;
2378
+ loading: boolean;
2379
+ error: string | null;
2380
+ refetch: () => Promise<void>;
2381
+ };
2382
+ /**
2383
+ * Hook to get paginated usage logs for a workspace.
2384
+ * Automatically fetches when workspaceId or filter params change.
2385
+ *
2386
+ * @param workspaceId - The workspace ID. Can be null/undefined to disable fetching.
2387
+ * @param quotaSlug - Optional quota slug to filter logs by.
2388
+ * @param options - Optional filters: from, to, source, page, limit
2389
+ * @returns An object containing:
2390
+ * - `logs`: Array of usage log entries
2391
+ * - `totalDocs`: Total number of log entries matching the query
2392
+ * - `totalPages`: Total number of pages
2393
+ * - `page`: Current page number
2394
+ * - `hasNextPage`: Whether there are more pages after the current one
2395
+ * - `hasPrevPage`: Whether there are pages before the current one
2396
+ * - `loading`: Boolean indicating if logs are being fetched
2397
+ * - `error`: Error message string (null if no error)
2398
+ * - `refetch()`: Function to manually refetch logs
2399
+ *
2400
+ * @example
2401
+ * ```tsx
2402
+ * function UsageLogsTable() {
2403
+ * const { currentWorkspace } = useSaaSWorkspaces();
2404
+ * const { logs, totalPages, page, hasNextPage, loading } = useUsageLogs(
2405
+ * currentWorkspace?._id,
2406
+ * 'api_calls',
2407
+ * { limit: 20 }
2408
+ * );
2409
+ *
2410
+ * if (loading) return <Loading />;
2411
+ *
2412
+ * return (
2413
+ * <div>
2414
+ * {logs.map(log => (
2415
+ * <div key={log._id}>
2416
+ * {log.quotaSlug}: {log.quantity} ({log.createdAt})
2417
+ * </div>
2418
+ * ))}
2419
+ * <p>Page {page} of {totalPages}</p>
2420
+ * </div>
2421
+ * );
2422
+ * }
2423
+ * ```
2424
+ */
2425
+ declare const useUsageLogs: (workspaceId: string | null | undefined, quotaSlug?: string, options?: {
2426
+ from?: string;
2427
+ to?: string;
2428
+ source?: string;
2429
+ page?: number;
2430
+ limit?: number;
2431
+ }) => {
2432
+ logs: IUsageLogEntry[];
2433
+ totalDocs: number;
2434
+ totalPages: number;
2435
+ page: number;
2436
+ hasNextPage: boolean;
2437
+ hasPrevPage: boolean;
2438
+ loading: boolean;
2439
+ error: string | null;
2440
+ refetch: () => Promise<void>;
2441
+ };
1819
2442
 
1820
2443
  /**
1821
2444
  * EventEmitter class to handle and trigger event callbacks
@@ -1906,23 +2529,122 @@ declare class SettingsApi extends BaseApi {
1906
2529
  getSettings(signal?: AbortSignal): Promise<ISettings>;
1907
2530
  }
1908
2531
 
2532
+ /**
2533
+ * Centralized formatting for subscription/quota display: cents, overage rates, included + overage text.
2534
+ * Currency must be provided by the caller (e.g. workspace.billingCurrency, plan.currency, or selected currency).
2535
+ */
2536
+ /** Common currency display (code or symbol). Use lowercase Stripe codes (usd, eur, etc.). */
2537
+ declare const CURRENCY_DISPLAY: Record<string, string>;
2538
+ /** Currency code to flag emoji (country/region associated with the currency). Use for dropdowns. */
2539
+ declare const CURRENCY_FLAG: Record<string, string>;
2540
+ /** Get flag emoji for a currency code. Returns empty string when unknown or empty. */
2541
+ declare function getCurrencyFlag(currency: string): string;
2542
+ /** Get currency symbol for display. Use lowercase Stripe codes (usd, eur). Returns code when unknown; empty string when currency is empty. */
2543
+ declare function getCurrencySymbol(currency: string): string;
2544
+ /** Allowed plan/pricing currency codes (must match server ALLOWED_BILLING_CURRENCIES). Use for dropdowns and validation. */
2545
+ declare const PLAN_CURRENCY_CODES: readonly ["usd", "eur", "gbp", "jpy", "cad", "aud", "chf", "cny", "hkd", "sgd", "inr", "mxn", "brl", "nzd", "sek", "nok", "dkk", "pln", "thb"];
2546
+ /** Options for plan currency select: { value, label } with symbol. Use in CreateOrEditPlan and anywhere a currency dropdown is needed. */
2547
+ declare const PLAN_CURRENCY_OPTIONS: {
2548
+ value: "usd" | "eur" | "gbp" | "jpy" | "cad" | "aud" | "chf" | "cny" | "hkd" | "sgd" | "inr" | "mxn" | "brl" | "nzd" | "sek" | "nok" | "dkk" | "pln" | "thb";
2549
+ label: string;
2550
+ }[];
2551
+ /** Format cents as money string (e.g. 1999, "usd" -> "$19.99"). Caller must pass currency (e.g. from plan or workspace). */
2552
+ declare function formatCents(cents: number, currency: string): string;
2553
+ /**
2554
+ * Format overage rate for display. When unitSize > 1: "$1.00/1,000 units"; else "$1.00/unit".
2555
+ * Returns null if overageCents is missing or negative.
2556
+ */
2557
+ declare function formatOverageRate(overageCents: number | undefined, unitSize: number | undefined, currency: string): string | null;
2558
+ /**
2559
+ * Format overage rate with optional unit label for comparison/preview UIs.
2560
+ * e.g. formatOverageRateWithLabel(50, 1000, "video") -> "$0.50/1,000 videos"
2561
+ * formatOverageRateWithLabel(46, 1, "video") -> "$0.46/video"
2562
+ * When unitLabel is omitted, falls back to formatOverageRate behavior.
2563
+ */
2564
+ declare function formatOverageRateWithLabel(overageCents: number | undefined, unitSize: number | undefined, unitLabel: string | undefined, currency: string): string | null;
2565
+ /**
2566
+ * Get singular unit label from item name or slug (e.g. "Videos" -> "video", "reels" -> "reel").
2567
+ * Used for quota display in comparison and preview.
2568
+ */
2569
+ declare function getQuotaUnitLabelFromName(nameOrSlug: string): string;
2570
+ /**
2571
+ * Format quota "included + overage" for display.
2572
+ * When unitSize >= 2: "Included: 1,000, after that $1.00/1,000 emails".
2573
+ * Otherwise: "Included: 5, after that $0.30/image".
2574
+ */
2575
+ declare function formatQuotaIncludedOverage(included: number | undefined, overageCents: number | undefined, unitLabel: string, currency: string, unitSize?: number): string;
2576
+
2577
+ /**
2578
+ * Helpers for multi-currency plan version pricing (pricingVariants).
2579
+ */
2580
+
2581
+ /** Get the pricing variant for a currency, or null if not available. */
2582
+ declare function getPricingVariant(planVersion: IPlanVersion, currency: string): IPricingVariant | null;
2583
+ /**
2584
+ * Get base price in cents for a plan version and currency/interval.
2585
+ */
2586
+ declare function getBasePriceCents(planVersion: IPlanVersion, currency: string, interval: BillingInterval): number | null;
2587
+ /**
2588
+ * Get Stripe price ID for the given plan version, currency, and interval.
2589
+ */
2590
+ declare function getStripePriceIdForInterval(planVersion: IPlanVersion, currency: string, interval: BillingInterval): string | null;
2591
+ /**
2592
+ * Get overage amount in cents for a quota in a given currency and interval.
2593
+ * Returns undefined if not defined in the pricing variant.
2594
+ */
2595
+ declare function getQuotaOverageCents(planVersion: IPlanVersion, currency: string, quotaSlug: string, interval: BillingInterval): number | undefined;
2596
+ /**
2597
+ * Get display currency for a plan version when using a given currency.
2598
+ * Returns the requested currency if the variant exists; otherwise plan.currency or null.
2599
+ */
2600
+ declare function getDisplayCurrency(planVersion: IPlanVersionWithPlan, currency: string): string;
2601
+ /** Minimal shape for extracting currencies (IPlanVersionWithPlan or IPublicPlanVersion). */
2602
+ type PlanVersionWithPricingVariants = {
2603
+ pricingVariants?: IPricingVariant[];
2604
+ };
2605
+ /**
2606
+ * Collect all unique currency codes from plan versions (from their pricingVariants).
2607
+ * Use for currency selector. Accepts IPlanVersionWithPlan[] or IPublicPlanVersion[].
2608
+ */
2609
+ declare function getAvailableCurrenciesFromPlans(planVersions: PlanVersionWithPricingVariants[]): string[];
2610
+ /**
2611
+ * Quota display shape: included count and optional overage (cents) and unitSize from plan + variant.
2612
+ */
2613
+ type QuotaDisplayWithOverage = {
2614
+ included: number;
2615
+ overage?: number;
2616
+ unitSize?: number;
2617
+ } | null;
2618
+ /**
2619
+ * Get quota display value for a slug/interval, merging plan version quotas (included, unitSize)
2620
+ * with pricing variant overage (cents) when available.
2621
+ */
2622
+ declare function getQuotaDisplayWithVariant(planVersion: IPlanVersion, currency: string, quotaSlug: string, interval: BillingInterval): QuotaDisplayWithOverage;
2623
+ /**
2624
+ * Resolve billing interval and currency from a Stripe price ID by checking all plan versions' pricingVariants.
2625
+ */
2626
+ declare function getBillingIntervalAndCurrencyFromPriceId(priceId: string | null | undefined, planVersions: IPlanVersionWithPlan[]): {
2627
+ interval: BillingInterval;
2628
+ currency: string;
2629
+ } | null;
2630
+
1909
2631
  type QuotaDisplayValue = {
1910
2632
  included: number;
1911
2633
  overage?: number;
1912
2634
  unitSize?: number;
1913
- } | number | null;
2635
+ } | null;
1914
2636
  /**
1915
- * Normalize a quota value (legacy or per-interval) to a display shape for a given billing interval.
1916
- * - Legacy: number or IQuotaValue → use as-is (interval ignored).
1917
- * - New schema: IQuotaByInterval → pick the interval slice (e.g. monthly, yearly, quarterly).
2637
+ * Normalize a per-interval quota value to a display shape for the given billing interval.
1918
2638
  */
1919
- declare function getQuotaDisplayValue(value: number | IQuotaValue | IQuotaByInterval | null | undefined, interval?: BillingInterval): QuotaDisplayValue;
2639
+ declare function getQuotaDisplayValue(value: IQuotaByInterval | null | undefined, interval?: BillingInterval): QuotaDisplayValue;
1920
2640
  /** Options for formatting quota with price. */
1921
2641
  interface FormatQuotaWithPriceOptions {
1922
2642
  /** If true, overage is in cents (Stripe); format as dollars. Default true. */
1923
2643
  overageInCents?: boolean;
1924
- /** Currency symbol. Default '$'. */
2644
+ /** Currency symbol override. When omitted, derived from `currency` (empty if no currency). */
1925
2645
  currencySymbol?: string;
2646
+ /** Stripe currency code (e.g. 'usd', 'inr'). Used to resolve symbol when currencySymbol is not set. */
2647
+ currency?: string;
1926
2648
  }
1927
2649
  /**
1928
2650
  * Format a quota display value as "X included, then $Y.YY / unit" (e.g. "10 included, then $10.00 / video").
@@ -1930,5 +2652,5 @@ interface FormatQuotaWithPriceOptions {
1930
2652
  */
1931
2653
  declare function formatQuotaWithPrice(value: QuotaDisplayValue, unitName: string, options?: FormatQuotaWithPriceOptions): string;
1932
2654
 
1933
- export { ApiVersion, AuthStatus, BaseApi, BetaForm, PricingPage, SaaSOSProvider, SettingsApi, SubscriptionContextProvider, UserApi, WhenAuthenticated, WhenNoSubscription, WhenRoles, WhenSubscription, WhenSubscriptionToPlans, WhenUnauthenticated, WhenUserFeatureDisabled, WhenUserFeatureEnabled, WhenWorkspaceFeatureDisabled, WhenWorkspaceFeatureEnabled, WhenWorkspaceRoles, WorkspaceApi, WorkspaceSwitcher, eventEmitter, formatQuotaWithPrice, getQuotaDisplayValue, useCreateCheckoutSession, useInvoice, useInvoices, usePlanGroup, usePlanGroupVersions, usePublicPlanGroupVersion, usePublicPlans, useSaaSAuth, useSaaSOs, useSaaSSettings, useSaaSWorkspaces, useSubscription, useSubscriptionContext, useSubscriptionManagement, useUpdateSubscription, useUserAttributes, useUserFeatures };
1934
- export type { BillingInterval, EventData, EventType, FormatQuotaWithPriceOptions, IBaseApiConfig, IBasePricing, ICheckoutSessionRequest, ICheckoutSessionResponse, IEventCallbacks, IInvoice, IInvoiceListResponse, IInvoiceResponse, IPlan, IPlanGroup, IPlanGroupInfo, IPlanGroupLatestVersion, IPlanGroupResponse, IPlanGroupVersion, IPlanGroupVersionWithPlans, IPlanGroupVersionsResponse, IPlanVersion, IPlanVersionSummary, IPlanVersionWithPlan, IPublicPlanItem, IPublicPlanItemCategory, IPublicPlanPricing, IPublicPlanQuotaValue, IPublicPlanVersion, IPublicPlansResponse, IQuotaByInterval, IQuotaIntervalValue, IQuotaValue, ISubscription, ISubscriptionItem, ISubscriptionResponse, ISubscriptionUpdateRequest, ISubscriptionUpdateResponse, InvoiceStatus, OnWorkspaceChangeParams, PricingPageDetails, PricingPageProps, QuotaDisplayValue, SubscriptionContextValue, UserCreatedEventData, UserUpdatedEventData, WorkspaceChangedEventData, WorkspaceCreatedEventData, WorkspaceDeletedEventData, WorkspaceUpdatedEventData, WorkspaceUserAddedEventData, WorkspaceUserRemovedEventData, WorkspaceUserRoleChangedEventData };
2655
+ export { ApiVersion, AuthStatus, BaseApi, BetaForm, CURRENCY_DISPLAY, CURRENCY_FLAG, PLAN_CURRENCY_CODES, PLAN_CURRENCY_OPTIONS, PricingPage, QuotaUsageContextProvider, SaaSOSProvider, SettingsApi, SubscriptionContextProvider, UserApi, WhenAuthenticated, WhenNoSubscription, WhenQuotaAvailable, WhenQuotaExhausted, WhenQuotaOverage, WhenQuotaThreshold, WhenRoles, WhenSubscription, WhenSubscriptionToPlans, WhenUnauthenticated, WhenUserFeatureDisabled, WhenUserFeatureEnabled, WhenWorkspaceFeatureDisabled, WhenWorkspaceFeatureEnabled, WhenWorkspaceRoles, WorkspaceApi, WorkspaceSwitcher, eventEmitter, formatCents, formatOverageRate, formatOverageRateWithLabel, formatQuotaIncludedOverage, formatQuotaWithPrice, getAvailableCurrenciesFromPlans, getBasePriceCents, getBillingIntervalAndCurrencyFromPriceId, getCurrencyFlag, getCurrencySymbol, getDisplayCurrency, getPricingVariant, getQuotaDisplayValue, getQuotaDisplayWithVariant, getQuotaOverageCents, getQuotaUnitLabelFromName, getStripePriceIdForInterval, invalidateQuotaUsage, invalidateSubscription, useAllQuotaUsage, useCancelSubscription, useCreateCheckoutSession, useInvoice, useInvoices, usePlanGroup, usePlanGroupVersions, usePublicPlanGroupVersion, usePublicPlans, useQuotaUsageContext, useQuotaUsageStatus, useRecordUsage, useResumeSubscription, useSaaSAuth, useSaaSOs, useSaaSSettings, useSaaSWorkspaces, useSubscription, useSubscriptionContext, useSubscriptionManagement, useUpdateSubscription, useUsageLogs, useUserAttributes, useUserFeatures };
2656
+ export type { BillingInterval, EventData, EventType, FormatQuotaWithPriceOptions, IAllQuotaUsageResponse, IBaseApiConfig, IBasePricing, ICheckoutSessionRequest, ICheckoutSessionResponse, IEventCallbacks, IInvoice, IInvoiceListResponse, IInvoiceResponse, IPlan, IPlanGroup, IPlanGroupInfo, IPlanGroupLatestVersion, IPlanGroupResponse, IPlanGroupVersion, IPlanGroupVersionWithPlans, IPlanGroupVersionsResponse, IPlanVersion, IPlanVersionSummary, IPlanVersionWithPlan, IPricingVariant, IPublicPlanItem, IPublicPlanItemCategory, IPublicPlanVersion, IPublicPlansResponse, IQuotaByInterval, IQuotaIntervalValue, IQuotaOveragePriceIdsByInterval, IQuotaOveragesByInterval, IQuotaUsageStatus, IQuotaUsageStatusResponse, IRecordUsageRequest, IRecordUsageResponse, IStripePricesByInterval, ISubscription, ISubscriptionItem, ISubscriptionResponse, ISubscriptionUpdateRequest, ISubscriptionUpdateResponse, IUsageLogEntry, IUsageLogsQuery, IUsageLogsResponse, InvoiceStatus, OnWorkspaceChangeParams, PlanVersionWithPricingVariants, PricingPageDetails, PricingPageProps, QuotaDisplayValue, QuotaDisplayWithOverage, QuotaUsageContextValue, SubscriptionContextValue, UserCreatedEventData, UserUpdatedEventData, WorkspaceChangedEventData, WorkspaceCreatedEventData, WorkspaceDeletedEventData, WorkspaceUpdatedEventData, WorkspaceUserAddedEventData, WorkspaceUserRemovedEventData, WorkspaceUserRoleChangedEventData };