@buildbase/sdk 0.0.15 → 0.0.18

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 (37) hide show
  1. package/README.md +208 -98
  2. package/dist/index.d.ts +395 -168
  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/index.d.ts +6 -0
  9. package/dist/types/api/quota-utils.d.ts +24 -0
  10. package/dist/types/api/types.d.ts +40 -15
  11. package/dist/types/components/beta/api.d.ts +1 -2
  12. package/dist/types/components/pricing/PricingPage.d.ts +1 -1
  13. package/dist/types/components/subscription/index.d.ts +108 -0
  14. package/dist/types/contexts/SubscriptionContext/SubscriptionContext.d.ts +22 -0
  15. package/dist/types/contexts/SubscriptionContext/index.d.ts +2 -0
  16. package/dist/types/contexts/SubscriptionContext/subscriptionInvalidation.d.ts +19 -0
  17. package/dist/types/contexts/SubscriptionContext/types.d.ts +12 -0
  18. package/dist/types/contexts/index.d.ts +2 -0
  19. package/dist/types/contexts/shared/types.d.ts +21 -0
  20. package/dist/types/contexts/shared/useAppDispatch.d.ts +2 -12
  21. package/dist/types/contexts/shared/useAppSelector.d.ts +2 -12
  22. package/dist/types/contexts/shared/utils/reducerHelpers.d.ts +2 -2
  23. package/dist/types/index.d.ts +9 -2
  24. package/dist/types/lib/api-base.d.ts +49 -0
  25. package/dist/types/providers/ContextConfigProvider.d.ts +1 -1
  26. package/dist/types/providers/auth/api.d.ts +12 -0
  27. package/dist/types/providers/auth/hooks.d.ts +2 -0
  28. package/dist/types/providers/os/api.d.ts +11 -0
  29. package/dist/types/providers/os/hooks.d.ts +6 -0
  30. package/dist/types/providers/os/types.d.ts +2 -0
  31. package/dist/types/providers/user/api.d.ts +16 -0
  32. package/dist/types/providers/user/hooks.d.ts +1 -0
  33. package/dist/types/providers/workspace/api.d.ts +16 -5
  34. package/dist/types/providers/workspace/hooks.d.ts +10 -0
  35. package/dist/types/providers/workspace/subscription-hooks.d.ts +81 -1
  36. package/dist/types/providers/workspace/ui/SubscriptionDialog.d.ts +3 -2
  37. 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
@@ -315,6 +318,103 @@ function FeatureExample() {
315
318
 
316
319
  Use the `useUserFeatures` hook to check feature flags programmatically:
317
320
 
321
+ ## 📋 Subscription Gates
322
+
323
+ 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).
324
+
325
+ **SubscriptionContextProvider** is included in **SaaSOSProvider** by default, so subscription gates work without extra setup.
326
+
327
+ ### Subscription Gate Components
328
+
329
+ ```tsx
330
+ import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk';
331
+
332
+ function BillingExample() {
333
+ return (
334
+ <div>
335
+ {/* Show when workspace has any active subscription */}
336
+ <WhenSubscription>
337
+ <BillingSettings />
338
+ </WhenSubscription>
339
+
340
+ {/* Show when workspace has no subscription */}
341
+ <WhenNoSubscription>
342
+ <UpgradePrompt />
343
+ </WhenNoSubscription>
344
+
345
+ {/* Show only when subscribed to specific plans (by slug, case-insensitive) */}
346
+ <WhenSubscriptionToPlans plans={['pro', 'enterprise']}>
347
+ <AdvancedAnalytics />
348
+ </WhenSubscriptionToPlans>
349
+ </div>
350
+ );
351
+ }
352
+ ```
353
+
354
+ | Component | Renders when |
355
+ | ------------------------- | -------------------------------------------------------------------- |
356
+ | `WhenSubscription` | Current workspace has an active subscription (any plan); not loading |
357
+ | `WhenNoSubscription` | Current workspace has no subscription (or no workspace); not loading |
358
+ | `WhenSubscriptionToPlans` | Current workspace is subscribed to one of the given plan slugs |
359
+
360
+ 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):
361
+
362
+ ```tsx
363
+ <WhenSubscription
364
+ loadingComponent={<Skeleton className="h-20" />}
365
+ fallbackComponent={<UpgradePrompt />}
366
+ >
367
+ <BillingSettings />
368
+ </WhenSubscription>
369
+
370
+ <WhenSubscriptionToPlans
371
+ plans={['pro', 'enterprise']}
372
+ loadingComponent={<Spinner />}
373
+ fallbackComponent={<p>Upgrade to Pro or Enterprise to access this feature.</p>}
374
+ >
375
+ <AdvancedAnalytics />
376
+ </WhenSubscriptionToPlans>
377
+ ```
378
+
379
+ ### useSubscriptionContext
380
+
381
+ Use the hook when you need subscription data or a manual refetch (e.g. after returning from Stripe checkout):
382
+
383
+ ```tsx
384
+ import { useSubscriptionContext } from '@buildbase/sdk';
385
+
386
+ function SubscriptionStatus() {
387
+ const { response, loading, refetch } = useSubscriptionContext();
388
+
389
+ if (loading) return <Spinner />;
390
+ if (!response?.subscription) return <p>No active subscription</p>;
391
+
392
+ const plan = response.plan ?? response.subscription?.plan;
393
+ return (
394
+ <div>
395
+ <p>Plan: {plan?.name ?? plan?.slug}</p>
396
+ <button onClick={() => refetch()}>Refresh</button>
397
+ </div>
398
+ );
399
+ }
400
+ ```
401
+
402
+ | Property | Type | Description |
403
+ | ---------- | ------------------------------- | ------------------------------------------------------ |
404
+ | `response` | `ISubscriptionResponse \| null` | Current subscription data for the current workspace |
405
+ | `loading` | `boolean` | True while subscription is being fetched |
406
+ | `refetch` | `() => Promise<void>` | Manually refetch subscription (e.g. after plan change) |
407
+
408
+ **When subscription refetches**
409
+
410
+ - When the current workspace changes (automatic).
411
+ - When subscription is updated via SDK (e.g. `useUpdateSubscription`, cancel, resume) — refetch is triggered automatically.
412
+ - When you call `refetch()` (e.g. after redirect from checkout).
413
+
414
+ ### Feature Flags Hook
415
+
416
+ Use the `useUserFeatures` hook to check feature flags programmatically:
417
+
318
418
  ```tsx
319
419
  import { useUserFeatures } from '@buildbase/sdk';
320
420
 
@@ -375,6 +475,7 @@ function WorkspaceManager() {
375
475
  loading, // Loading state
376
476
  refreshing, // Refreshing state
377
477
  switching, // True when a workspace switch is in progress
478
+ switchingToId, // Workspace ID currently being switched to (null when not switching)
378
479
  error, // Error message
379
480
  fetchWorkspaces, // Fetch all workspaces
380
481
  refreshWorkspaces, // Background refresh
@@ -461,12 +562,12 @@ function PublicPricingPage() {
461
562
  }
462
563
  ```
463
564
 
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 |
565
+ | Prop | Type | Description |
566
+ | ----------------- | ------------------------------ | ----------------------------------------------------------------- |
567
+ | `slug` | `string` | Plan group slug (e.g. 'main-pricing', 'enterprise') |
568
+ | `children` | `(details) => ReactNode` | Render prop receiving `{ loading, error, items, plans, refetch }` |
569
+ | `loadingFallback` | `ReactNode` | Custom loading UI (defaults to skeleton) |
570
+ | `errorFallback` | `(error: string) => ReactNode` | Custom error UI |
470
571
 
471
572
  **Response shape**: `items` = subscription item definitions (features, limits, quotas with category); `plans` = plan versions with `pricing`, `quotas`, `features`, `limits`.
472
573
 
@@ -539,41 +640,7 @@ import { SaaSOSProvider, eventEmitter } from '@buildbase/sdk';
539
640
 
540
641
  ## 🛡️ Error Handling
541
642
 
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
- ```
643
+ 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. Wrap your app in an error boundary of your choice to catch React errors. For failed operations, check the `error` property on hooks and handle it in your UI (e.g. toast or inline message).
577
644
 
578
645
  ## ⚙️ Settings
579
646
 
@@ -595,6 +662,52 @@ function SettingsExample() {
595
662
 
596
663
  ## 📚 API Reference
597
664
 
665
+ ### Central APIs
666
+
667
+ All SDK API clients extend a shared base class and are exported from the package:
668
+
669
+ | Export | Purpose |
670
+ | ---------------- | ------------------------------------------------------------------------------- |
671
+ | `BaseApi` | Abstract base (URL, auth, `fetchJson`/`fetchResponse`) – extend for custom APIs |
672
+ | `IBaseApiConfig` | Config type: `serverUrl`, `version`, optional `orgId` |
673
+ | `UserApi` | User attributes and features |
674
+ | `WorkspaceApi` | Workspaces, subscription, invoices, users |
675
+ | `SettingsApi` | Organization settings |
676
+
677
+ Use the hooks (`useUserApi`, `useWorkspaceApi`, etc.) for a ready-made instance with OS config, or instantiate with your own config:
678
+
679
+ ```tsx
680
+ import { UserApi, WorkspaceApi, SettingsApi, useSaaSOs } from '@buildbase/sdk';
681
+
682
+ // Via hook (uses OS config from context)
683
+ const api = useWorkspaceApi(); // or useUserApi(), etc.
684
+
685
+ // Or instantiate with config
686
+ const os = useSaaSOs();
687
+ const workspaceApi = new WorkspaceApi({
688
+ serverUrl: os.serverUrl,
689
+ version: os.version,
690
+ orgId: os.orgId,
691
+ });
692
+ ```
693
+
694
+ ### Hooks
695
+
696
+ Prefer these SDK hooks for state and operations instead of `useAppSelector`:
697
+
698
+ | Hook | Purpose |
699
+ | -------------------------- | ------------------------------------------------------------------------------------------------------- |
700
+ | `useSaaSAuth()` | Auth state (user, session, status), signIn, signOut, openWorkspaceSettings |
701
+ | `useSaaSWorkspaces()` | Workspaces, currentWorkspace, loading, switching/switchingToId, CRUD and switch actions |
702
+ | `useSaaSOs()` | OS config (serverUrl, version, orgId, auth, settings) when you need the full config object |
703
+ | `useSaaSSettings()` | Organization settings and getSettings (prefer this when you only need settings) |
704
+ | `useUserAttributes()` | User attributes and update/refresh |
705
+ | `useUserFeatures()` | User feature flags |
706
+ | `useSubscriptionContext()` | Subscription for current workspace (response, loading, refetch); use inside SubscriptionContextProvider |
707
+ | Subscription hooks | `usePublicPlans`, `useSubscription`, `usePlanGroup`, etc. |
708
+
709
+ Using hooks keeps your code stable if internal state shape changes and avoids direct Redux/context coupling.
710
+
598
711
  ### Enums
599
712
 
600
713
  - `ApiVersion` - API version enum (currently only `V1`)
@@ -604,6 +717,11 @@ function SettingsExample() {
604
717
 
605
718
  All TypeScript types are exported for type safety. See the [TypeScript definitions](./dist/index.d.ts) for complete type information.
606
719
 
720
+ ### Further documentation
721
+
722
+ - [Architecture](docs/ARCHITECTURE.md) – Layers, APIs (BaseApi, UserApi, WorkspaceApi, SettingsApi), state, auth flow
723
+ - [Error codes](docs/ERROR_CODES.md) – SDK error codes and HTTP status mappings
724
+
607
725
  ## ⚙️ Configuration Reference
608
726
 
609
727
  ### SaaSOSProvider Props
@@ -752,6 +870,32 @@ function Dashboard() {
752
870
  }
753
871
  ```
754
872
 
873
+ ### Pattern 4b: Subscription-Gated UI
874
+
875
+ ```tsx
876
+ import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk';
877
+
878
+ function BillingPage() {
879
+ return (
880
+ <div>
881
+ <WhenNoSubscription>
882
+ <UpgradePrompt />
883
+ </WhenNoSubscription>
884
+
885
+ <WhenSubscription>
886
+ <BillingSettings />
887
+ </WhenSubscription>
888
+
889
+ <WhenSubscriptionToPlans plans={['pro', 'enterprise']}>
890
+ <AdvancedBillingFeatures />
891
+ </WhenSubscriptionToPlans>
892
+ </div>
893
+ );
894
+ }
895
+ ```
896
+
897
+ SubscriptionContextProvider is included in SaaSOSProvider by default, so no extra wrapper is needed.
898
+
755
899
  ### Pattern 5: Handling Workspace Changes
756
900
 
757
901
  ```tsx
@@ -769,7 +913,7 @@ function App() {
769
913
  }
770
914
  }, [currentWorkspace]);
771
915
 
772
- // Show loading during switch (switchingToId !== null)
916
+ // Show loading during switch; use switchingToId for the workspace ID being switched to
773
917
  if (switching) return <LoadingOverlay />;
774
918
 
775
919
  return <YourApp />;
@@ -778,37 +922,9 @@ function App() {
778
922
 
779
923
  For token generation or prep before switching, configure `onWorkspaceChange` in auth callbacks (see Quick Start)—it receives `{ workspace, user, role }`.
780
924
 
781
- ### Pattern 6: Error Boundary with Custom Fallback
782
-
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
- }
925
+ ### Pattern 6: Error Boundary
803
926
 
804
- function App() {
805
- return (
806
- <ErrorBoundary fallback={CustomErrorFallback}>
807
- <YourApp />
808
- </ErrorBoundary>
809
- );
810
- }
811
- ```
927
+ 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
928
 
813
929
  ## 🔧 Troubleshooting
814
930
 
@@ -984,39 +1100,33 @@ function App() {
984
1100
 
985
1101
  ### 2. Error Handling
986
1102
 
987
- ✅ **Do**: Wrap your app with `ErrorBoundary` and configure error handler.
1103
+ ✅ **Do**: Wrap your app with an error boundary (your framework’s or React’s) to catch render errors.
988
1104
 
989
- ```tsx
990
- // ✅ Good
991
- <ErrorBoundary>
992
- <SaaSOSProvider {...config}>
993
- <App />
994
- </SaaSOSProvider>
995
- </ErrorBoundary>
996
- ```
1105
+ ✅ **Do**: Handle async failures using the `error` from hooks and show user feedback (e.g. toast or inline message).
997
1106
 
998
- **Do**: Use `handleError` for custom error handling.
1107
+ ### 3. State Access: Prefer SDK Hooks Over useAppSelector
1108
+
1109
+ ✅ **Do**: Use SDK hooks for auth, workspace, and OS state.
999
1110
 
1000
1111
  ```tsx
1001
- try {
1002
- await someOperation();
1003
- } catch (error) {
1004
- handleError(error, {
1005
- component: 'MyComponent',
1006
- action: 'operation',
1007
- });
1008
- }
1112
+ // ✅ Good – use hooks
1113
+ const { user, isAuthenticated } = useSaaSAuth();
1114
+ const { workspaces, currentWorkspace, switchingToId } = useSaaSWorkspaces();
1115
+ const { settings } = useSaaSSettings();
1116
+ const os = useSaaSOs(); // when you need full OS config (serverUrl, version, orgId, etc.)
1009
1117
  ```
1010
1118
 
1011
- ### 3. Workspace Management
1119
+ **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.
1120
+
1121
+ ### 4. Workspace Management
1012
1122
 
1013
1123
  ✅ **Do**: Use `useSaaSWorkspaces` hook for workspace operations.
1014
1124
 
1015
1125
  ```tsx
1016
1126
  // ✅ Good
1017
- const { currentWorkspace, switchToWorkspace, switching } = useSaaSWorkspaces();
1127
+ const { currentWorkspace, switchToWorkspace, switching, switchingToId } = useSaaSWorkspaces();
1018
1128
  // switchToWorkspace: runs onWorkspaceChange first (token gen, etc.)
1019
- // switching: true when switch is in progress
1129
+ // switching: true when switch is in progress; switchingToId: workspace ID being switched to
1020
1130
  ```
1021
1131
 
1022
1132
  ✅ **Do**: Configure `onWorkspaceChange` in auth callbacks for token generation—receives `{ workspace, user, role }`.
@@ -1028,7 +1138,7 @@ const { currentWorkspace, switchToWorkspace, switching } = useSaaSWorkspaces();
1028
1138
  const [workspace, setWorkspace] = useState(null); // Don't do this
1029
1139
  ```
1030
1140
 
1031
- ### 4. Feature Flags
1141
+ ### 5. Feature Flags
1032
1142
 
1033
1143
  ✅ **Do**: Use feature flag components for conditional rendering.
1034
1144
 
@@ -1049,7 +1159,7 @@ if (isFeatureEnabled('premium')) {
1049
1159
  }
1050
1160
  ```
1051
1161
 
1052
- ### 5. Authentication
1162
+ ### 6. Authentication
1053
1163
 
1054
1164
  ✅ **Do**: Use `WhenAuthenticated`/`WhenUnauthenticated` for route protection.
1055
1165
 
@@ -1070,7 +1180,7 @@ const { signIn, status } = useSaaSAuth();
1070
1180
  </button>;
1071
1181
  ```
1072
1182
 
1073
- ### 6. Event Handling
1183
+ ### 7. Event Handling
1074
1184
 
1075
1185
  ✅ **Do**: Handle events in your provider configuration. Use `onWorkspaceChange` for prep before switch (e.g. generate token), and `handleEvent` for post-switch notifications.
1076
1186
 
@@ -1092,7 +1202,7 @@ const { signIn, status } = useSaaSAuth();
1092
1202
  >
1093
1203
  ```
1094
1204
 
1095
- ### 7. TypeScript
1205
+ ### 8. TypeScript
1096
1206
 
1097
1207
  ✅ **Do**: Use TypeScript for better type safety.
1098
1208
 
@@ -1105,7 +1215,7 @@ function MyComponent({ workspace }: { workspace: IWorkspace }) {
1105
1215
  }
1106
1216
  ```
1107
1217
 
1108
- ### 8. Performance
1218
+ ### 9. Performance
1109
1219
 
1110
1220
  ✅ **Do**: Memoize expensive computations.
1111
1221