@buildbase/sdk 0.0.7 → 0.0.9

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