@buildbase/sdk 0.0.16 → 0.0.19

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 (40) hide show
  1. package/README.md +201 -98
  2. package/dist/index.d.ts +594 -198
  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 +11 -0
  10. package/dist/types/api/pricing-variant-utils.d.ts +53 -0
  11. package/dist/types/api/quota-utils.d.ts +24 -0
  12. package/dist/types/api/types.d.ts +118 -43
  13. package/dist/types/components/beta/api.d.ts +1 -2
  14. package/dist/types/components/pricing/PricingPage.d.ts +3 -1
  15. package/dist/types/components/subscription/index.d.ts +108 -0
  16. package/dist/types/contexts/SubscriptionContext/SubscriptionContext.d.ts +22 -0
  17. package/dist/types/contexts/SubscriptionContext/index.d.ts +2 -0
  18. package/dist/types/contexts/SubscriptionContext/subscriptionInvalidation.d.ts +19 -0
  19. package/dist/types/contexts/SubscriptionContext/types.d.ts +12 -0
  20. package/dist/types/contexts/index.d.ts +2 -0
  21. package/dist/types/contexts/shared/types.d.ts +21 -0
  22. package/dist/types/contexts/shared/useAppDispatch.d.ts +2 -12
  23. package/dist/types/contexts/shared/useAppSelector.d.ts +2 -12
  24. package/dist/types/contexts/shared/utils/reducerHelpers.d.ts +2 -2
  25. package/dist/types/index.d.ts +12 -2
  26. package/dist/types/lib/api-base.d.ts +49 -0
  27. package/dist/types/providers/ContextConfigProvider.d.ts +1 -1
  28. package/dist/types/providers/auth/api.d.ts +12 -0
  29. package/dist/types/providers/auth/hooks.d.ts +2 -0
  30. package/dist/types/providers/os/api.d.ts +11 -0
  31. package/dist/types/providers/os/hooks.d.ts +6 -0
  32. package/dist/types/providers/os/types.d.ts +2 -0
  33. package/dist/types/providers/user/api.d.ts +16 -0
  34. package/dist/types/providers/user/hooks.d.ts +1 -0
  35. package/dist/types/providers/workspace/api.d.ts +2 -5
  36. package/dist/types/providers/workspace/hooks.d.ts +11 -1
  37. package/dist/types/providers/workspace/subscription-hooks.d.ts +2 -1
  38. package/dist/types/providers/workspace/types.d.ts +18 -1
  39. package/dist/types/providers/workspace/ui/SubscriptionDialog.d.ts +7 -1
  40. package/package.json +1 -1
package/README.md CHANGED
@@ -10,6 +10,7 @@ A React SDK for [BuildBase](https://www.buildbase.app/) that provides essential
10
10
  - [Authentication](#-authentication)
11
11
  - [Role-Based Access Control](#-role-based-access-control)
12
12
  - [Feature Flags](#️-feature-flags)
13
+ - [Subscription Gates](#-subscription-gates)
13
14
  - [User Management](#-user-management)
14
15
  - [Workspace Management](#-complete-workspace-management)
15
16
  - [Public Pricing (No Login)](#-public-pricing-no-login)
@@ -22,6 +23,7 @@ A React SDK for [BuildBase](https://www.buildbase.app/) that provides essential
22
23
  - [Troubleshooting](#-troubleshooting)
23
24
  - [API Reference](#-api-reference)
24
25
  - [Best Practices](#-best-practices)
26
+ - [Documentation](#further-documentation)
25
27
 
26
28
  ## 🚀 Features
27
29
 
@@ -29,6 +31,7 @@ A React SDK for [BuildBase](https://www.buildbase.app/) that provides essential
29
31
  - **🏢 Workspace Management** - Multi-workspace support with switching capabilities
30
32
  - **👥 Role-Based Access Control** - User roles and workspace-specific permissions
31
33
  - **🎯 Feature Flags** - Workspace-level and user-level feature toggles
34
+ - **📋 Subscription Gates** - Show or hide UI based on current workspace subscription (plan)
32
35
  - **👤 User Management** - User attributes and feature flags management
33
36
  - **📝 Beta Form** - Pre-built signup/waitlist form component
34
37
  - **📡 Event System** - Subscribe to user and workspace events
@@ -327,6 +330,99 @@ function FeatureCheck() {
327
330
  }
328
331
  ```
329
332
 
333
+ ## 📋 Subscription Gates
334
+
335
+ Control UI visibility based on the current workspace’s subscription. Subscription data is loaded once per workspace and refetched when the workspace changes or when the subscription is updated (e.g. upgrade, cancel, resume).
336
+
337
+ **SubscriptionContextProvider** is included in **SaaSOSProvider** by default, so subscription gates work without extra setup.
338
+
339
+ ### Subscription Gate Components
340
+
341
+ ```tsx
342
+ import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk';
343
+
344
+ function BillingExample() {
345
+ return (
346
+ <div>
347
+ {/* Show when workspace has any active subscription */}
348
+ <WhenSubscription>
349
+ <BillingSettings />
350
+ </WhenSubscription>
351
+
352
+ {/* Show when workspace has no subscription */}
353
+ <WhenNoSubscription>
354
+ <UpgradePrompt />
355
+ </WhenNoSubscription>
356
+
357
+ {/* Show only when subscribed to specific plans (by slug, case-insensitive) */}
358
+ <WhenSubscriptionToPlans plans={['pro', 'enterprise']}>
359
+ <AdvancedAnalytics />
360
+ </WhenSubscriptionToPlans>
361
+ </div>
362
+ );
363
+ }
364
+ ```
365
+
366
+ | Component | Renders when |
367
+ | ------------------------- | -------------------------------------------------------------------- |
368
+ | `WhenSubscription` | Current workspace has an active subscription (any plan); not loading |
369
+ | `WhenNoSubscription` | Current workspace has no subscription (or no workspace); not loading |
370
+ | `WhenSubscriptionToPlans` | Current workspace is subscribed to one of the given plan slugs |
371
+
372
+ All gates must be used inside **SubscriptionContextProvider** (included in SaaSOSProvider). By default they return `null` while loading or when the condition is not met. You can pass optional **loadingComponent** (component/element to show while loading) and **fallbackComponent** (component/element to show when condition is not met):
373
+
374
+ ```tsx
375
+ <WhenSubscription
376
+ loadingComponent={<Skeleton className="h-20" />}
377
+ fallbackComponent={<UpgradePrompt />}
378
+ >
379
+ <BillingSettings />
380
+ </WhenSubscription>
381
+
382
+ <WhenSubscriptionToPlans
383
+ plans={['pro', 'enterprise']}
384
+ loadingComponent={<Spinner />}
385
+ fallbackComponent={<p>Upgrade to Pro or Enterprise to access this feature.</p>}
386
+ >
387
+ <AdvancedAnalytics />
388
+ </WhenSubscriptionToPlans>
389
+ ```
390
+
391
+ ### useSubscriptionContext
392
+
393
+ Use the hook when you need subscription data or a manual refetch (e.g. after returning from Stripe checkout):
394
+
395
+ ```tsx
396
+ import { useSubscriptionContext } from '@buildbase/sdk';
397
+
398
+ function SubscriptionStatus() {
399
+ const { response, loading, refetch } = useSubscriptionContext();
400
+
401
+ if (loading) return <Spinner />;
402
+ if (!response?.subscription) return <p>No active subscription</p>;
403
+
404
+ const plan = response.plan ?? response.subscription?.plan;
405
+ return (
406
+ <div>
407
+ <p>Plan: {plan?.name ?? plan?.slug}</p>
408
+ <button onClick={() => refetch()}>Refresh</button>
409
+ </div>
410
+ );
411
+ }
412
+ ```
413
+
414
+ | Property | Type | Description |
415
+ | ---------- | ------------------------------- | ------------------------------------------------------ |
416
+ | `response` | `ISubscriptionResponse \| null` | Current subscription data for the current workspace |
417
+ | `loading` | `boolean` | True while subscription is being fetched |
418
+ | `refetch` | `() => Promise<void>` | Manually refetch subscription (e.g. after plan change) |
419
+
420
+ **When subscription refetches**
421
+
422
+ - When the current workspace changes (automatic).
423
+ - When subscription is updated via SDK (e.g. `useUpdateSubscription`, cancel, resume) — refetch is triggered automatically.
424
+ - When you call `refetch()` (e.g. after redirect from checkout).
425
+
330
426
  ## 👤 User Management
331
427
 
332
428
  ### User Attributes
@@ -375,6 +471,7 @@ function WorkspaceManager() {
375
471
  loading, // Loading state
376
472
  refreshing, // Refreshing state
377
473
  switching, // True when a workspace switch is in progress
474
+ switchingToId, // Workspace ID currently being switched to (null when not switching)
378
475
  error, // Error message
379
476
  fetchWorkspaces, // Fetch all workspaces
380
477
  refreshWorkspaces, // Background refresh
@@ -461,12 +558,12 @@ function PublicPricingPage() {
461
558
  }
462
559
  ```
463
560
 
464
- | Prop | Type | Description |
465
- |------|------|-------------|
466
- | `slug` | `string` | Plan group slug (e.g. 'main-pricing', 'enterprise') |
467
- | `children` | `(details) => ReactNode` | Render prop receiving `{ loading, error, items, plans, refetch }` |
468
- | `loadingFallback` | `ReactNode` | Custom loading UI (defaults to skeleton) |
469
- | `errorFallback` | `(error: string) => ReactNode` | Custom error UI |
561
+ | Prop | Type | Description |
562
+ | ----------------- | ------------------------------ | ----------------------------------------------------------------- |
563
+ | `slug` | `string` | Plan group slug (e.g. 'main-pricing', 'enterprise') |
564
+ | `children` | `(details) => ReactNode` | Render prop receiving `{ loading, error, items, plans, refetch }` |
565
+ | `loadingFallback` | `ReactNode` | Custom loading UI (defaults to skeleton) |
566
+ | `errorFallback` | `(error: string) => ReactNode` | Custom error UI |
470
567
 
471
568
  **Response shape**: `items` = subscription item definitions (features, limits, quotas with category); `plans` = plan versions with `pricing`, `quotas`, `features`, `limits`.
472
569
 
@@ -539,41 +636,7 @@ import { SaaSOSProvider, eventEmitter } from '@buildbase/sdk';
539
636
 
540
637
  ## 🛡️ Error Handling
541
638
 
542
- The SDK provides comprehensive error handling:
543
-
544
- ```tsx
545
- import { ErrorBoundary, SDKError, handleError, errorHandler } from '@buildbase/sdk';
546
-
547
- // Wrap your app with ErrorBoundary
548
- function App() {
549
- return (
550
- <ErrorBoundary>
551
- <YourApp />
552
- </ErrorBoundary>
553
- );
554
- }
555
-
556
- // Configure error handler
557
- errorHandler.configure({
558
- enableConsoleLogging: true,
559
- showUserNotifications: false,
560
- onError: (error, context) => {
561
- // Custom error handling
562
- console.error('SDK Error:', error, context);
563
- },
564
- });
565
-
566
- // Use handleError in your code
567
- try {
568
- // Some operation
569
- } catch (error) {
570
- handleError(error, {
571
- component: 'MyComponent',
572
- action: 'handleSubmit',
573
- metadata: { userId: '123' },
574
- });
575
- }
576
- ```
639
+ The SDK handles errors internally: API failures, auth errors, and component errors are logged and surfaced through hook states (e.g. `error` from `useSaaSWorkspaces`) and callbacks. **SaaSOSProvider** wraps its children in an internal **SDKErrorBoundary** to catch React render errors inside the SDK tree. For app-level errors, wrap your app (or routes) in your own error boundary (e.g. React’s `ErrorBoundary` or your framework’s error UI). For failed async operations, check the `error` property on hooks and show user feedback (e.g. toast or inline message). See [Error codes](docs/ERROR_CODES.md) for SDK error codes and HTTP mappings.
577
640
 
578
641
  ## ⚙️ Settings
579
642
 
@@ -595,6 +658,49 @@ function SettingsExample() {
595
658
 
596
659
  ## 📚 API Reference
597
660
 
661
+ ### Central APIs
662
+
663
+ All SDK API clients extend a shared base class and are exported from the package:
664
+
665
+ | Export | Purpose |
666
+ | ---------------- | ------------------------------------------------------------------------------- |
667
+ | `BaseApi` | Abstract base (URL, auth, `fetchJson`/`fetchResponse`) – extend for custom APIs |
668
+ | `IBaseApiConfig` | Config type: `serverUrl`, `version`, optional `orgId` |
669
+ | `UserApi` | User attributes and features |
670
+ | `WorkspaceApi` | Workspaces, subscription, invoices, users |
671
+ | `SettingsApi` | Organization settings |
672
+
673
+ Get OS config from `useSaaSOs()` and instantiate API classes when you need low-level access; otherwise prefer the high-level hooks (`useSaaSWorkspaces`, `useUserAttributes`, `useSaaSSettings`, etc.):
674
+
675
+ ```tsx
676
+ import { UserApi, WorkspaceApi, SettingsApi, useSaaSOs } from '@buildbase/sdk';
677
+
678
+ const os = useSaaSOs();
679
+ const workspaceApi = new WorkspaceApi({
680
+ serverUrl: os.serverUrl,
681
+ version: os.version,
682
+ orgId: os.orgId,
683
+ });
684
+ // Similarly: new UserApi({ ... }), new SettingsApi({ ... })
685
+ ```
686
+
687
+ ### Hooks
688
+
689
+ Prefer these SDK hooks for state and operations instead of `useAppSelector`:
690
+
691
+ | Hook | Purpose |
692
+ | -------------------------- | ------------------------------------------------------------------------------------------------------- |
693
+ | `useSaaSAuth()` | Auth state (user, session, status), signIn, signOut, openWorkspaceSettings |
694
+ | `useSaaSWorkspaces()` | Workspaces, currentWorkspace, loading, switching/switchingToId, CRUD and switch actions |
695
+ | `useSaaSOs()` | OS config (serverUrl, version, orgId, auth, settings) when you need the full config object |
696
+ | `useSaaSSettings()` | Organization settings and getSettings (prefer this when you only need settings) |
697
+ | `useUserAttributes()` | User attributes and update/refresh |
698
+ | `useUserFeatures()` | User feature flags |
699
+ | `useSubscriptionContext()` | Subscription for current workspace (response, loading, refetch); use inside SubscriptionContextProvider |
700
+ | Subscription hooks | `usePublicPlans`, `useSubscription`, `usePlanGroup`, etc. |
701
+
702
+ Using hooks keeps your code stable if internal state shape changes and avoids direct Redux/context coupling.
703
+
598
704
  ### Enums
599
705
 
600
706
  - `ApiVersion` - API version enum (currently only `V1`)
@@ -604,6 +710,11 @@ function SettingsExample() {
604
710
 
605
711
  All TypeScript types are exported for type safety. See the [TypeScript definitions](./dist/index.d.ts) for complete type information.
606
712
 
713
+ ### Further documentation
714
+
715
+ - [Architecture](docs/ARCHITECTURE.md) – Layers, providers, APIs (BaseApi, UserApi, WorkspaceApi, SettingsApi), state, auth flow
716
+ - [Error codes](docs/ERROR_CODES.md) – SDK error codes and HTTP status mappings
717
+
607
718
  ## ⚙️ Configuration Reference
608
719
 
609
720
  ### SaaSOSProvider Props
@@ -752,6 +863,32 @@ function Dashboard() {
752
863
  }
753
864
  ```
754
865
 
866
+ ### Pattern 4b: Subscription-Gated UI
867
+
868
+ ```tsx
869
+ import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk';
870
+
871
+ function BillingPage() {
872
+ return (
873
+ <div>
874
+ <WhenNoSubscription>
875
+ <UpgradePrompt />
876
+ </WhenNoSubscription>
877
+
878
+ <WhenSubscription>
879
+ <BillingSettings />
880
+ </WhenSubscription>
881
+
882
+ <WhenSubscriptionToPlans plans={['pro', 'enterprise']}>
883
+ <AdvancedBillingFeatures />
884
+ </WhenSubscriptionToPlans>
885
+ </div>
886
+ );
887
+ }
888
+ ```
889
+
890
+ SubscriptionContextProvider is included in SaaSOSProvider by default, so no extra wrapper is needed.
891
+
755
892
  ### Pattern 5: Handling Workspace Changes
756
893
 
757
894
  ```tsx
@@ -769,7 +906,7 @@ function App() {
769
906
  }
770
907
  }, [currentWorkspace]);
771
908
 
772
- // Show loading during switch (switchingToId !== null)
909
+ // Show loading during switch; use switchingToId for the workspace ID being switched to
773
910
  if (switching) return <LoadingOverlay />;
774
911
 
775
912
  return <YourApp />;
@@ -778,37 +915,9 @@ function App() {
778
915
 
779
916
  For token generation or prep before switching, configure `onWorkspaceChange` in auth callbacks (see Quick Start)—it receives `{ workspace, user, role }`.
780
917
 
781
- ### Pattern 6: Error Boundary with Custom Fallback
918
+ ### Pattern 6: Error Boundary
782
919
 
783
- ```tsx
784
- import { ErrorBoundary, SDKError } from '@buildbase/sdk';
785
-
786
- function CustomErrorFallback({ error, resetError }) {
787
- if (error instanceof SDKError) {
788
- return (
789
- <div>
790
- <h2>SDK Error: {error.message}</h2>
791
- <button onClick={resetError}>Try Again</button>
792
- </div>
793
- );
794
- }
795
-
796
- return (
797
- <div>
798
- <h2>Something went wrong</h2>
799
- <button onClick={resetError}>Reload</button>
800
- </div>
801
- );
802
- }
803
-
804
- function App() {
805
- return (
806
- <ErrorBoundary fallback={CustomErrorFallback}>
807
- <YourApp />
808
- </ErrorBoundary>
809
- );
810
- }
811
- ```
920
+ Wrap your app (or a subtree) with an error boundary to catch React errors and show a fallback. Use your framework’s boundary (e.g. React’s `ErrorBoundary` or Next.js error UI). In catch blocks for async operations, show user feedback (e.g. toast or inline message) using the `error` state from hooks.
812
921
 
813
922
  ## 🔧 Troubleshooting
814
923
 
@@ -984,39 +1093,33 @@ function App() {
984
1093
 
985
1094
  ### 2. Error Handling
986
1095
 
987
- ✅ **Do**: Wrap your app with `ErrorBoundary` and configure error handler.
1096
+ ✅ **Do**: Wrap your app with an error boundary (your framework’s or React’s) to catch render errors.
988
1097
 
989
- ```tsx
990
- // ✅ Good
991
- <ErrorBoundary>
992
- <SaaSOSProvider {...config}>
993
- <App />
994
- </SaaSOSProvider>
995
- </ErrorBoundary>
996
- ```
1098
+ ✅ **Do**: Handle async failures using the `error` from hooks and show user feedback (e.g. toast or inline message).
1099
+
1100
+ ### 3. State Access: Prefer SDK Hooks Over useAppSelector
997
1101
 
998
- ✅ **Do**: Use `handleError` for custom error handling.
1102
+ ✅ **Do**: Use SDK hooks for auth, workspace, and OS state.
999
1103
 
1000
1104
  ```tsx
1001
- try {
1002
- await someOperation();
1003
- } catch (error) {
1004
- handleError(error, {
1005
- component: 'MyComponent',
1006
- action: 'operation',
1007
- });
1008
- }
1105
+ // ✅ Good – use hooks
1106
+ const { user, isAuthenticated } = useSaaSAuth();
1107
+ const { workspaces, currentWorkspace, switchingToId } = useSaaSWorkspaces();
1108
+ const { settings } = useSaaSSettings();
1109
+ const os = useSaaSOs(); // when you need full OS config (serverUrl, version, orgId, etc.)
1009
1110
  ```
1010
1111
 
1011
- ### 3. Workspace Management
1112
+ **Don't**: Use `useAppSelector(state => state.auth)` or similar in app code—prefer the hooks above so the SDK can evolve internal state without breaking you.
1113
+
1114
+ ### 4. Workspace Management
1012
1115
 
1013
1116
  ✅ **Do**: Use `useSaaSWorkspaces` hook for workspace operations.
1014
1117
 
1015
1118
  ```tsx
1016
1119
  // ✅ Good
1017
- const { currentWorkspace, switchToWorkspace, switching } = useSaaSWorkspaces();
1120
+ const { currentWorkspace, switchToWorkspace, switching, switchingToId } = useSaaSWorkspaces();
1018
1121
  // switchToWorkspace: runs onWorkspaceChange first (token gen, etc.)
1019
- // switching: true when switch is in progress
1122
+ // switching: true when switch is in progress; switchingToId: workspace ID being switched to
1020
1123
  ```
1021
1124
 
1022
1125
  ✅ **Do**: Configure `onWorkspaceChange` in auth callbacks for token generation—receives `{ workspace, user, role }`.
@@ -1028,7 +1131,7 @@ const { currentWorkspace, switchToWorkspace, switching } = useSaaSWorkspaces();
1028
1131
  const [workspace, setWorkspace] = useState(null); // Don't do this
1029
1132
  ```
1030
1133
 
1031
- ### 4. Feature Flags
1134
+ ### 5. Feature Flags
1032
1135
 
1033
1136
  ✅ **Do**: Use feature flag components for conditional rendering.
1034
1137
 
@@ -1049,7 +1152,7 @@ if (isFeatureEnabled('premium')) {
1049
1152
  }
1050
1153
  ```
1051
1154
 
1052
- ### 5. Authentication
1155
+ ### 6. Authentication
1053
1156
 
1054
1157
  ✅ **Do**: Use `WhenAuthenticated`/`WhenUnauthenticated` for route protection.
1055
1158
 
@@ -1070,7 +1173,7 @@ const { signIn, status } = useSaaSAuth();
1070
1173
  </button>;
1071
1174
  ```
1072
1175
 
1073
- ### 6. Event Handling
1176
+ ### 7. Event Handling
1074
1177
 
1075
1178
  ✅ **Do**: Handle events in your provider configuration. Use `onWorkspaceChange` for prep before switch (e.g. generate token), and `handleEvent` for post-switch notifications.
1076
1179
 
@@ -1092,7 +1195,7 @@ const { signIn, status } = useSaaSAuth();
1092
1195
  >
1093
1196
  ```
1094
1197
 
1095
- ### 7. TypeScript
1198
+ ### 8. TypeScript
1096
1199
 
1097
1200
  ✅ **Do**: Use TypeScript for better type safety.
1098
1201
 
@@ -1105,7 +1208,7 @@ function MyComponent({ workspace }: { workspace: IWorkspace }) {
1105
1208
  }
1106
1209
  ```
1107
1210
 
1108
- ### 8. Performance
1211
+ ### 9. Performance
1109
1212
 
1110
1213
  ✅ **Do**: Memoize expensive computations.
1111
1214