@buildbase/sdk 0.0.6 → 0.0.8

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.
package/README.md CHANGED
@@ -2,12 +2,36 @@
2
2
 
3
3
  A React SDK for [BuildBase](https://www.buildbase.app/) that provides essential components to build SaaS applications faster. Skip the plumbing and focus on your core product with built-in authentication, workspace management, and user management.
4
4
 
5
+ ## 📑 Table of Contents
6
+
7
+ - [Features](#-features)
8
+ - [Installation](#-installation)
9
+ - [Quick Start](#-quick-start)
10
+ - [Authentication](#-authentication)
11
+ - [Role-Based Access Control](#-role-based-access-control)
12
+ - [Feature Flags](#️-feature-flags)
13
+ - [User Management](#-user-management)
14
+ - [Workspace Management](#-complete-workspace-management)
15
+ - [Beta Form Component](#-beta-form-component)
16
+ - [Event System](#-event-system)
17
+ - [Error Handling](#️-error-handling)
18
+ - [Settings](#️-settings)
19
+ - [Configuration Reference](#️-configuration-reference)
20
+ - [Common Patterns](#-common-patterns)
21
+ - [Troubleshooting](#-troubleshooting)
22
+ - [API Reference](#-api-reference)
23
+ - [Best Practices](#-best-practices)
24
+
5
25
  ## 🚀 Features
6
26
 
7
27
  - **🔐 Authentication System** - Complete auth flow with sign-in/sign-out
8
28
  - **🏢 Workspace Management** - Multi-workspace support with switching capabilities
9
29
  - **👥 Role-Based Access Control** - User roles and workspace-specific permissions
10
- - **🎯 Feature Flags** - Workspace-level feature toggles
30
+ - **🎯 Feature Flags** - Workspace-level and user-level feature toggles
31
+ - **👤 User Management** - User attributes and feature flags management
32
+ - **📝 Beta Form** - Pre-built signup/waitlist form component
33
+ - **📡 Event System** - Subscribe to user and workspace events
34
+ - **🛡️ Error Handling** - Centralized error handling with error boundaries
11
35
 
12
36
  ## 📦 Installation
13
37
 
@@ -53,38 +77,23 @@ export default function SaaSProvider(props: { children: React.ReactNode }) {
53
77
  clientId: 'your-client-id',
54
78
  redirectUrl: 'http://localhost:3000',
55
79
  callbacks: {
56
- verifyToken: async token => {
57
- return new Promise(resolve => {
58
- fetch('/api/auth/verify', {
59
- method: 'POST',
60
- body: JSON.stringify({ token }),
61
- })
62
- .then(response => response.json())
63
- .then((data: { valid: boolean }) => {
64
- resolve(data?.valid ?? false);
65
- })
66
- .catch(error => {
67
- console.error(error);
68
- resolve(false);
69
- });
80
+ handleAuthentication: async (code: string) => {
81
+ // Exchange OAuth code for session ID
82
+ const response = await fetch('/api/auth/token', {
83
+ method: 'POST',
84
+ body: JSON.stringify({ code }),
70
85
  });
86
+ const data = await response.json();
87
+ // Return sessionId - SDK will use this for authenticated requests
88
+ return { sessionId: data.sessionId };
71
89
  },
72
- handleAuthentication: async token => {
73
- return new Promise(resolve => {
74
- fetch('/api/auth/token', {
75
- method: 'POST',
76
- body: JSON.stringify({ token }),
77
- })
78
- .then(response => response.json())
79
- .then((data: { token: string; decoded: { id: string } }) => {
80
- localStorage.setItem('auth_token', data?.token ?? '');
81
- resolve();
82
- })
83
- .catch(error => {
84
- console.error(error);
85
- resolve();
86
- });
87
- });
90
+ onSignOut: async () => {
91
+ // Clean up any custom tokens/storage on sign out
92
+ localStorage.removeItem('custom_token');
93
+ },
94
+ handleEvent: async (eventType, data) => {
95
+ // Handle SDK events (user created, workspace changed, etc.)
96
+ console.log('SDK Event:', eventType, data);
88
97
  },
89
98
  },
90
99
  }}
@@ -124,7 +133,11 @@ import { WorkspaceSwitcher } from '@buildbase/sdk';
124
133
  function WorkspaceExample() {
125
134
  return (
126
135
  <WorkspaceSwitcher
127
- trigger={currentWorkspace => {
136
+ trigger={(isLoading, currentWorkspace) => {
137
+ if (isLoading) {
138
+ return <div>Loading...</div>;
139
+ }
140
+
128
141
  if (!currentWorkspace) {
129
142
  return (
130
143
  <div className="flex items-center gap-2 min-w-40 border rounded-md p-2 hover:bg-muted cursor-pointer">
@@ -195,10 +208,14 @@ function AuthExample() {
195
208
  ```tsx
196
209
  const {
197
210
  user, // Current user object (null if not authenticated)
211
+ session, // Full session object with user and sessionId
198
212
  isAuthenticated, // Boolean: true if user is authenticated
213
+ isLoading, // Boolean: true when checking authentication status
214
+ isRedirecting, // Boolean: true when redirecting for OAuth
215
+ status, // String: 'idle' | 'loading' | 'authenticated' | 'error'
199
216
  signIn, // Function: initiates sign-in flow
200
217
  signOut, // Function: signs out the user
201
- status, // String: 'idle' | 'loading' | 'authenticated' | 'error'
218
+ openWorkspaceSettings, // Function: opens workspace settings dialog
202
219
  } = useSaaSAuth();
203
220
  ```
204
221
 
@@ -257,14 +274,20 @@ function AdminPanel() {
257
274
 
258
275
  ## 🎛️ Feature Flags
259
276
 
260
- Control feature visibility based on workspace settings:
277
+ Control feature visibility based on workspace and user settings:
261
278
 
262
279
  ```tsx
263
- import { WhenWorkspaceFeatureEnabled, WhenWorkspaceFeatureDisabled } from '@buildbase/sdk';
280
+ import {
281
+ WhenWorkspaceFeatureEnabled,
282
+ WhenWorkspaceFeatureDisabled,
283
+ WhenUserFeatureEnabled,
284
+ WhenUserFeatureDisabled
285
+ } from '@buildbase/sdk';
264
286
 
265
287
  function FeatureExample() {
266
288
  return (
267
289
  <div>
290
+ {/* Workspace-level features */}
268
291
  <WhenWorkspaceFeatureEnabled slug="advanced-analytics">
269
292
  <AdvancedAnalytics />
270
293
  </WhenWorkspaceFeatureEnabled>
@@ -272,11 +295,772 @@ function FeatureExample() {
272
295
  <WhenWorkspaceFeatureDisabled slug="beta-features">
273
296
  <p>Beta features are not enabled for this workspace</p>
274
297
  </WhenWorkspaceFeatureDisabled>
298
+
299
+ {/* User-level features */}
300
+ <WhenUserFeatureEnabled slug="premium-features">
301
+ <PremiumDashboard />
302
+ </WhenUserFeatureEnabled>
303
+
304
+ <WhenUserFeatureDisabled slug="trial-mode">
305
+ <UpgradePrompt />
306
+ </WhenUserFeatureDisabled>
275
307
  </div>
276
308
  );
277
309
  }
278
310
  ```
279
311
 
312
+ ### Feature Flags Hook
313
+
314
+ Use the `useUserFeatures` hook to check feature flags programmatically:
315
+
316
+ ```tsx
317
+ import { useUserFeatures } from '@buildbase/sdk';
318
+
319
+ function FeatureCheck() {
320
+ const { features, isFeatureEnabled, refreshFeatures } = useUserFeatures();
321
+
322
+ return (
323
+ <div>
324
+ {isFeatureEnabled('premium-features') ? (
325
+ <PremiumContent />
326
+ ) : (
327
+ <StandardContent />
328
+ )}
329
+ </div>
330
+ );
331
+ }
332
+ ```
333
+
334
+ ## 👤 User Management
335
+
336
+ ### User Attributes
337
+
338
+ Manage custom user attributes (key-value pairs):
339
+
340
+ ```tsx
341
+ import { useUserAttributes } from '@buildbase/sdk';
342
+
343
+ function UserProfile() {
344
+ const {
345
+ attributes,
346
+ isLoading,
347
+ updateAttribute,
348
+ updateAttributes,
349
+ refreshAttributes
350
+ } = useUserAttributes();
351
+
352
+ const handleUpdate = async () => {
353
+ // Update single attribute
354
+ await updateAttribute('theme', 'dark');
355
+
356
+ // Or update multiple attributes
357
+ await updateAttributes({
358
+ theme: 'dark',
359
+ notifications: true,
360
+ language: 'en'
361
+ });
362
+ };
363
+
364
+ return (
365
+ <div>
366
+ <p>Theme: {attributes.theme}</p>
367
+ <button onClick={handleUpdate}>Update Preferences</button>
368
+ </div>
369
+ );
370
+ }
371
+ ```
372
+
373
+ ## 🏢 Complete Workspace Management
374
+
375
+ The `useSaaSWorkspaces` hook provides comprehensive workspace management:
376
+
377
+ ```tsx
378
+ import { useSaaSWorkspaces } from '@buildbase/sdk';
379
+
380
+ function WorkspaceManager() {
381
+ const {
382
+ workspaces, // Array of all workspaces
383
+ currentWorkspace, // Currently selected workspace
384
+ loading, // Loading state
385
+ refreshing, // Refreshing state
386
+ error, // Error message
387
+ fetchWorkspaces, // Fetch all workspaces
388
+ refreshWorkspaces, // Background refresh
389
+ setCurrentWorkspace, // Switch workspace
390
+ createWorkspace, // Create new workspace
391
+ updateWorkspace, // Update workspace
392
+ deleteWorkspace, // Delete workspace
393
+ getUsers, // Get workspace users
394
+ addUser, // Add user to workspace
395
+ removeUser, // Remove user from workspace
396
+ updateUser, // Update user role/permissions
397
+ getFeatures, // Get all available features
398
+ updateFeature, // Toggle workspace feature
399
+ getProfile, // Get current user profile
400
+ updateUserProfile, // Update user profile
401
+ } = useSaaSWorkspaces();
402
+
403
+ // Example: Create a workspace
404
+ const handleCreate = async () => {
405
+ await createWorkspace('My Workspace', 'https://example.com/logo.png');
406
+ };
407
+
408
+ // Example: Add user to workspace
409
+ const handleAddUser = async () => {
410
+ await addUser(currentWorkspace._id, 'user@example.com', 'member');
411
+ };
412
+
413
+ return (
414
+ <div>
415
+ {/* Your workspace UI */}
416
+ </div>
417
+ );
418
+ }
419
+ ```
420
+
421
+ ## 📝 Beta Form Component
422
+
423
+ Use the pre-built `BetaForm` component for signup/waitlist forms:
424
+
425
+ ```tsx
426
+ import { BetaForm } from '@buildbase/sdk';
427
+
428
+ function SignupPage() {
429
+ return (
430
+ <BetaForm
431
+ onSuccess={() => console.log('Form submitted!')}
432
+ onError={(error) => console.error(error)}
433
+ language="en" // Optional: 'en' | 'es' | 'fr' | 'de' | 'zh' | 'ja' | 'ko'
434
+ showSuccessMessage={true}
435
+ hideLogo={false}
436
+ hideTitles={false}
437
+ />
438
+ );
439
+ }
440
+ ```
441
+
442
+ ## 📡 Event System
443
+
444
+ Subscribe to SDK events for user and workspace changes:
445
+
446
+ ```tsx
447
+ import { SaaSOSProvider, eventEmitter } from '@buildbase/sdk';
448
+
449
+ // In your provider configuration
450
+ <SaaSOSProvider
451
+ auth={{
452
+ callbacks: {
453
+ handleEvent: async (eventType, data) => {
454
+ switch (eventType) {
455
+ case 'user:created':
456
+ console.log('User created:', data.user);
457
+ break;
458
+ case 'workspace:changed':
459
+ console.log('Workspace changed:', data.workspace);
460
+ break;
461
+ case 'workspace:user-added':
462
+ console.log('User added to workspace:', data.userId);
463
+ break;
464
+ // ... handle other events
465
+ }
466
+ },
467
+ },
468
+ }}
469
+ >
470
+ {children}
471
+ </SaaSOSProvider>
472
+ ```
473
+
474
+ ### Available Events
475
+
476
+ - `user:created` - User account created
477
+ - `user:updated` - User profile updated
478
+ - `workspace:changed` - Workspace switched
479
+ - `workspace:created` - New workspace created
480
+ - `workspace:updated` - Workspace updated
481
+ - `workspace:deleted` - Workspace deleted
482
+ - `workspace:user-added` - User added to workspace
483
+ - `workspace:user-removed` - User removed from workspace
484
+ - `workspace:user-role-changed` - User role changed
485
+
486
+ ## 🛡️ Error Handling
487
+
488
+ The SDK provides comprehensive error handling:
489
+
490
+ ```tsx
491
+ import {
492
+ ErrorBoundary,
493
+ SDKError,
494
+ handleError,
495
+ errorHandler
496
+ } from '@buildbase/sdk';
497
+
498
+ // Wrap your app with ErrorBoundary
499
+ function App() {
500
+ return (
501
+ <ErrorBoundary>
502
+ <YourApp />
503
+ </ErrorBoundary>
504
+ );
505
+ }
506
+
507
+ // Configure error handler
508
+ errorHandler.configure({
509
+ enableConsoleLogging: true,
510
+ showUserNotifications: false,
511
+ onError: (error, context) => {
512
+ // Custom error handling
513
+ console.error('SDK Error:', error, context);
514
+ },
515
+ });
516
+
517
+ // Use handleError in your code
518
+ try {
519
+ // Some operation
520
+ } catch (error) {
521
+ handleError(error, {
522
+ component: 'MyComponent',
523
+ action: 'handleSubmit',
524
+ metadata: { userId: '123' },
525
+ });
526
+ }
527
+ ```
528
+
529
+ ## ⚙️ Settings
530
+
531
+ Access OS-level settings:
532
+
533
+ ```tsx
534
+ import { useSaaSSettings } from '@buildbase/sdk';
535
+
536
+ function SettingsExample() {
537
+ const { settings, getSettings } = useSaaSSettings();
538
+
539
+ return (
540
+ <div>
541
+ <p>Max Workspaces: {settings?.workspace.maxWorkspaces}</p>
542
+ </div>
543
+ );
544
+ }
545
+ ```
546
+
547
+ ## 📚 API Reference
548
+
549
+ ### Enums
550
+
551
+ - `ApiVersion` - API version enum (currently only `V1`)
552
+
553
+ ### Types
554
+
555
+ All TypeScript types are exported for type safety. See the [TypeScript definitions](./dist/index.d.ts) for complete type information.
556
+
557
+ ## ⚙️ Configuration Reference
558
+
559
+ ### SaaSOSProvider Props
560
+
561
+ | Prop | Type | Required | Description |
562
+ | ---------- | ------------- | -------- | --------------------------------------------------------------------------- |
563
+ | `serverUrl` | `string` | ✅ | API server URL (must be valid URL) |
564
+ | `version` | `ApiVersion` | ✅ | API version (currently only `'v1'`) |
565
+ | `orgId` | `string` | ✅ | Organization ID (must be valid MongoDB ObjectId - 24 hex characters) |
566
+ | `auth` | `IAuthConfig` | ❌ | Authentication configuration |
567
+ | `children` | `ReactNode` | ✅ | React children |
568
+
569
+ ### Auth Configuration
570
+
571
+ ```tsx
572
+ interface IAuthConfig {
573
+ clientId: string; // OAuth client ID
574
+ redirectUrl: string; // OAuth redirect URL
575
+ callbacks?: {
576
+ handleAuthentication: (code: string) => Promise<{ sessionId: string }>;
577
+ onSignOut?: () => Promise<void>;
578
+ handleEvent?: (eventType: EventType, data: EventData) => void | Promise<void>;
579
+ };
580
+ }
581
+ ```
582
+
583
+ ### Validation Requirements
584
+
585
+ - **serverUrl**: Must be a valid URL (e.g., `https://api.example.com`)
586
+ - **version**: Must be exactly `'v1'` (only supported version)
587
+ - **orgId**: Must be a valid MongoDB ObjectId (24 hexadecimal characters, e.g., `507f1f77bcf86cd799439011`)
588
+
589
+ ### BetaForm Props
590
+
591
+ | Prop | Type | Default | Description |
592
+ | --------------------- | ------------------------------------------------------------- | -------------------- | ---------------------------------------- |
593
+ | `onSuccess` | `() => void` | - | Callback when form submits successfully |
594
+ | `onError` | `(error: string) => void` | - | Callback when form submission fails |
595
+ | `className` | `string` | `'w-full'` | CSS class for form container |
596
+ | `fieldClassName` | `string` | `'flex flex-col gap-1.5 w-full'` | CSS class for form fields |
597
+ | `language` | `'en' \| 'es' \| 'fr' \| 'de' \| 'zh' \| 'ja' \| 'ko'` | Auto-detect | Form language |
598
+ | `customTexts` | `Partial<FormText>` | `{}` | Custom text overrides |
599
+ | `autoFocus` | `boolean` | `true` | Auto-focus name field |
600
+ | `showSuccessMessage` | `boolean` | `true` | Show success message after submit |
601
+ | `successMessageDuration` | `number` | - | Duration to show success message (ms) |
602
+ | `hideLogo` | `boolean` | `false` | Hide logo |
603
+ | `hideTitles` | `boolean` | `false` | Hide titles |
604
+
605
+ ## 🎯 Common Patterns
606
+
607
+ ### Pattern 1: Protected Routes
608
+
609
+ ```tsx
610
+ import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk';
611
+
612
+ function App() {
613
+ return (
614
+ <WhenUnauthenticated>
615
+ <LoginPage />
616
+ </WhenUnauthenticated>
617
+
618
+ <WhenAuthenticated>
619
+ <ProtectedRoutes />
620
+ </WhenAuthenticated>
621
+ );
622
+ }
623
+
624
+ function ProtectedRoutes() {
625
+ return (
626
+ <Routes>
627
+ <Route path="/dashboard" element={<Dashboard />} />
628
+ <Route path="/settings" element={<Settings />} />
629
+ </Routes>
630
+ );
631
+ }
632
+ ```
633
+
634
+ ### Pattern 2: Role-Based Navigation
635
+
636
+ ```tsx
637
+ import { WhenRoles } from '@buildbase/sdk';
638
+
639
+ function Navigation() {
640
+ return (
641
+ <nav>
642
+ <Link to="/dashboard">Dashboard</Link>
643
+ <Link to="/projects">Projects</Link>
644
+
645
+ <WhenRoles roles={['admin', 'owner']}>
646
+ <Link to="/admin">Admin Panel</Link>
647
+ </WhenRoles>
648
+
649
+ <WhenRoles roles={['admin']}>
650
+ <Link to="/settings">Settings</Link>
651
+ </WhenRoles>
652
+ </nav>
653
+ );
654
+ }
655
+ ```
656
+
657
+ ### Pattern 3: Workspace Context Provider
658
+
659
+ ```tsx
660
+ import { useSaaSWorkspaces } from '@buildbase/sdk';
661
+ import { createContext, useContext } from 'react';
662
+
663
+ const WorkspaceContext = createContext(null);
664
+
665
+ export function WorkspaceProvider({ children }) {
666
+ const workspaceData = useSaaSWorkspaces();
667
+
668
+ return (
669
+ <WorkspaceContext.Provider value={workspaceData}>
670
+ {children}
671
+ </WorkspaceContext.Provider>
672
+ );
673
+ }
674
+
675
+ export function useWorkspace() {
676
+ return useContext(WorkspaceContext);
677
+ }
678
+ ```
679
+
680
+ ### Pattern 4: Feature Gated Components
681
+
682
+ ```tsx
683
+ import { WhenWorkspaceFeatureEnabled } from '@buildbase/sdk';
684
+
685
+ function Dashboard() {
686
+ return (
687
+ <div>
688
+ <StandardFeatures />
689
+
690
+ <WhenWorkspaceFeatureEnabled slug="advanced-analytics">
691
+ <AdvancedAnalytics />
692
+ </WhenWorkspaceFeatureEnabled>
693
+
694
+ <WhenWorkspaceFeatureEnabled slug="ai-assistant">
695
+ <AIAssistant />
696
+ </WhenWorkspaceFeatureEnabled>
697
+ </div>
698
+ );
699
+ }
700
+ ```
701
+
702
+ ### Pattern 5: Handling Workspace Changes
703
+
704
+ ```tsx
705
+ import { useSaaSWorkspaces } from '@buildbase/sdk';
706
+ import { useEffect } from 'react';
707
+
708
+ function App() {
709
+ const { currentWorkspace, setCurrentWorkspace } = useSaaSWorkspaces();
710
+
711
+ useEffect(() => {
712
+ if (currentWorkspace) {
713
+ // Update your app state when workspace changes
714
+ console.log('Workspace changed:', currentWorkspace);
715
+ // Reload data, update context, etc.
716
+ }
717
+ }, [currentWorkspace]);
718
+
719
+ return <YourApp />;
720
+ }
721
+ ```
722
+
723
+ ### Pattern 6: Error Boundary with Custom Fallback
724
+
725
+ ```tsx
726
+ import { ErrorBoundary, SDKError } from '@buildbase/sdk';
727
+
728
+ function CustomErrorFallback({ error, resetError }) {
729
+ if (error instanceof SDKError) {
730
+ return (
731
+ <div>
732
+ <h2>SDK Error: {error.message}</h2>
733
+ <button onClick={resetError}>Try Again</button>
734
+ </div>
735
+ );
736
+ }
737
+
738
+ return (
739
+ <div>
740
+ <h2>Something went wrong</h2>
741
+ <button onClick={resetError}>Reload</button>
742
+ </div>
743
+ );
744
+ }
745
+
746
+ function App() {
747
+ return (
748
+ <ErrorBoundary fallback={CustomErrorFallback}>
749
+ <YourApp />
750
+ </ErrorBoundary>
751
+ );
752
+ }
753
+ ```
754
+
755
+ ## 🔧 Troubleshooting
756
+
757
+ ### Common Issues
758
+
759
+ #### 1. "Invalid orgId" Error
760
+
761
+ **Problem**: `orgId` must be a valid MongoDB ObjectId (24 hexadecimal characters).
762
+
763
+ **Solution**:
764
+
765
+ ```tsx
766
+ // ❌ Wrong
767
+ orgId="123"
768
+
769
+ // ✅ Correct
770
+ orgId="507f1f77bcf86cd799439011" // 24 hex characters
771
+ ```
772
+
773
+ #### 2. "Invalid serverUrl" Error
774
+
775
+ **Problem**: `serverUrl` must be a valid URL.
776
+
777
+ **Solution**:
778
+
779
+ ```tsx
780
+ // ❌ Wrong
781
+ serverUrl="api.example.com"
782
+ serverUrl="not-a-url"
783
+
784
+ // ✅ Correct
785
+ serverUrl="https://api.example.com"
786
+ serverUrl="http://localhost:3000"
787
+ ```
788
+
789
+ #### 3. Authentication Not Working
790
+
791
+ **Problem**: User can't sign in or session not persisting.
792
+
793
+ **Solutions**:
794
+
795
+ - Ensure `handleAuthentication` callback returns `{ sessionId: string }`
796
+ - Check that your backend API is correctly exchanging the OAuth code
797
+ - Verify `redirectUrl` matches your OAuth app configuration
798
+ - Check browser console for error messages
799
+
800
+ ```tsx
801
+ // ✅ Correct callback
802
+ handleAuthentication: async (code: string) => {
803
+ const response = await fetch('/api/auth/token', {
804
+ method: 'POST',
805
+ body: JSON.stringify({ code }),
806
+ });
807
+ const data = await response.json();
808
+ return { sessionId: data.sessionId }; // Must return sessionId
809
+ }
810
+ ```
811
+
812
+ #### 4. Workspace Not Loading
813
+
814
+ **Problem**: Workspaces array is empty or not updating.
815
+
816
+ **Solutions**:
817
+
818
+ - Ensure user is authenticated before fetching workspaces
819
+ - Call `fetchWorkspaces()` explicitly if needed
820
+ - Check network tab for API errors
821
+ - Verify user has access to workspaces
822
+
823
+ ```tsx
824
+ const { fetchWorkspaces, workspaces } = useSaaSWorkspaces();
825
+
826
+ useEffect(() => {
827
+ if (isAuthenticated) {
828
+ fetchWorkspaces(); // Explicitly fetch if needed
829
+ }
830
+ }, [isAuthenticated]);
831
+ ```
832
+
833
+ #### 5. Feature Flags Not Working
834
+
835
+ **Problem**: Feature flags always return false or undefined.
836
+
837
+ **Solutions**:
838
+
839
+ - Ensure `getFeatures()` is called (usually automatic)
840
+ - Check that feature slugs match your backend configuration
841
+ - Verify workspace has the feature enabled
842
+ - Check user has the feature enabled (for user-level features)
843
+
844
+ ```tsx
845
+ const { getFeatures, currentWorkspace } = useSaaSWorkspaces();
846
+
847
+ useEffect(() => {
848
+ getFeatures(); // Ensure features are loaded
849
+ }, []);
850
+ ```
851
+
852
+ #### 6. TypeScript Errors
853
+
854
+ **Problem**: Type errors when using the SDK.
855
+
856
+ **Solutions**:
857
+
858
+ - Ensure you're using React 19+ (check peer dependencies)
859
+ - Import types explicitly if needed:
860
+
861
+ ```tsx
862
+ import type { IWorkspace, IUser } from '@buildbase/sdk';
863
+ ```
864
+
865
+ - Check that all required props are provided
866
+
867
+ #### 7. CSS Not Loading
868
+
869
+ **Problem**: Components look unstyled.
870
+
871
+ **Solution**: Ensure CSS is imported:
872
+
873
+ ```tsx
874
+ import '@buildbase/sdk/dist/saas-os.css';
875
+ ```
876
+
877
+ ### FAQ
878
+
879
+ **Q: Can I use this with Next.js?**
880
+ A: Yes! Just ensure you use `'use client'` directive in components using SDK hooks.
881
+
882
+ **Q: Can I use this with other React frameworks?**
883
+ A: Yes, as long as you're using React 19+.
884
+
885
+ **Q: How do I customize the workspace switcher UI?**
886
+ A: Use the `trigger` render prop to fully customize the UI.
887
+
888
+ **Q: Can I use multiple workspaces simultaneously?**
889
+ A: No, the SDK manages one current workspace at a time. Switch between workspaces using `setCurrentWorkspace()`.
890
+
891
+ **Q: How do I handle offline scenarios?**
892
+ A: The SDK stores session data in localStorage. Handle offline scenarios in your `handleAuthentication` callback.
893
+
894
+ **Q: Can I use this without TypeScript?**
895
+ A: Yes, but TypeScript is recommended for better developer experience.
896
+
897
+ ## 💡 Best Practices
898
+
899
+ ### 1. Provider Setup
900
+
901
+ ✅ **Do**: Wrap your entire app with `SaaSOSProvider` at the root level.
902
+
903
+ ```tsx
904
+ // ✅ Good
905
+ function App() {
906
+ return (
907
+ <SaaSOSProvider {...config}>
908
+ <YourApp />
909
+ </SaaSOSProvider>
910
+ );
911
+ }
912
+ ```
913
+
914
+ ❌ **Don't**: Nest providers or use multiple instances.
915
+
916
+ ```tsx
917
+ // ❌ Bad
918
+ <SaaSOSProvider>
919
+ <SaaSOSProvider> {/* Don't nest */}
920
+ <App />
921
+ </SaaSOSProvider>
922
+ </SaaSOSProvider>
923
+ ```
924
+
925
+ ### 2. Error Handling
926
+
927
+ ✅ **Do**: Wrap your app with `ErrorBoundary` and configure error handler.
928
+
929
+ ```tsx
930
+ // ✅ Good
931
+ <ErrorBoundary>
932
+ <SaaSOSProvider {...config}>
933
+ <App />
934
+ </SaaSOSProvider>
935
+ </ErrorBoundary>
936
+ ```
937
+
938
+ ✅ **Do**: Use `handleError` for custom error handling.
939
+
940
+ ```tsx
941
+ try {
942
+ await someOperation();
943
+ } catch (error) {
944
+ handleError(error, {
945
+ component: 'MyComponent',
946
+ action: 'operation',
947
+ });
948
+ }
949
+ ```
950
+
951
+ ### 3. Workspace Management
952
+
953
+ ✅ **Do**: Use `useSaaSWorkspaces` hook for workspace operations.
954
+
955
+ ```tsx
956
+ // ✅ Good
957
+ const { currentWorkspace, setCurrentWorkspace } = useSaaSWorkspaces();
958
+ ```
959
+
960
+ ❌ **Don't**: Manually manage workspace state.
961
+
962
+ ```tsx
963
+ // ❌ Bad
964
+ const [workspace, setWorkspace] = useState(null); // Don't do this
965
+ ```
966
+
967
+ ### 4. Feature Flags
968
+
969
+ ✅ **Do**: Use feature flag components for conditional rendering.
970
+
971
+ ```tsx
972
+ // ✅ Good
973
+ <WhenWorkspaceFeatureEnabled slug="feature">
974
+ <FeatureComponent />
975
+ </WhenWorkspaceFeatureEnabled>
976
+ ```
977
+
978
+ ✅ **Do**: Check features programmatically when needed.
979
+
980
+ ```tsx
981
+ // ✅ Good
982
+ const { isFeatureEnabled } = useUserFeatures();
983
+ if (isFeatureEnabled('premium')) {
984
+ // Do something
985
+ }
986
+ ```
987
+
988
+ ### 5. Authentication
989
+
990
+ ✅ **Do**: Use `WhenAuthenticated`/`WhenUnauthenticated` for route protection.
991
+
992
+ ```tsx
993
+ // ✅ Good
994
+ <WhenAuthenticated>
995
+ <ProtectedRoute />
996
+ </WhenAuthenticated>
997
+ ```
998
+
999
+ ✅ **Do**: Handle authentication errors gracefully.
1000
+
1001
+ ```tsx
1002
+ // ✅ Good
1003
+ const { signIn, status } = useSaaSAuth();
1004
+ <button onClick={signIn} disabled={status === 'loading'}>
1005
+ {status === 'loading' ? 'Signing in...' : 'Sign In'}
1006
+ </button>
1007
+ ```
1008
+
1009
+ ### 6. Event Handling
1010
+
1011
+ ✅ **Do**: Handle events in your provider configuration.
1012
+
1013
+ ```tsx
1014
+ // ✅ Good
1015
+ <SaaSOSProvider
1016
+ auth={{
1017
+ callbacks: {
1018
+ handleEvent: async (eventType, data) => {
1019
+ // Handle events
1020
+ if (eventType === 'workspace:changed') {
1021
+ // Update your app state
1022
+ }
1023
+ },
1024
+ },
1025
+ }}
1026
+ >
1027
+ ```
1028
+
1029
+ ### 7. TypeScript
1030
+
1031
+ ✅ **Do**: Use TypeScript for better type safety.
1032
+
1033
+ ```tsx
1034
+ // ✅ Good
1035
+ import type { IWorkspace, IUser } from '@buildbase/sdk';
1036
+
1037
+ function MyComponent({ workspace }: { workspace: IWorkspace }) {
1038
+ // Type-safe code
1039
+ }
1040
+ ```
1041
+
1042
+ ### 8. Performance
1043
+
1044
+ ✅ **Do**: Memoize expensive computations.
1045
+
1046
+ ```tsx
1047
+ // ✅ Good
1048
+ const filteredWorkspaces = useMemo(
1049
+ () => workspaces.filter(w => w.active),
1050
+ [workspaces]
1051
+ );
1052
+ ```
1053
+
1054
+ ✅ **Do**: Use `refreshWorkspaces()` for background updates instead of `fetchWorkspaces()`.
1055
+
1056
+ ```tsx
1057
+ // ✅ Good - doesn't block UI
1058
+ refreshWorkspaces();
1059
+
1060
+ // Use fetchWorkspaces() only when you need to wait for the result
1061
+ await fetchWorkspaces();
1062
+ ```
1063
+
280
1064
  ## 🤝 Contributing
281
1065
 
282
1066
  1. Fork the repository
@@ -291,7 +1075,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
291
1075
 
292
1076
  ## 🆘 Support
293
1077
 
294
- - 📧 Email: support@buildbase.app
1078
+ - 📧 Email: [support@buildbase.app](mailto:support@buildbase.app)
295
1079
  - 📖 Documentation: [BuildBase Docs](https://docs.buildbase.app/)
296
1080
 
297
1081
  ## 🔗 Links