@buildbase/sdk 0.0.7 → 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 +820 -36
- package/dist/index.d.ts +120 -3
- package/dist/index.esm.js +11 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/saas-os.css +1 -1
- package/dist/types/api/types.d.ts +1 -0
- package/dist/types/components/ErrorBoundary.d.ts +34 -0
- package/dist/types/components/features/index.d.ts +2 -0
- package/dist/types/components/ui/command.d.ts +7 -7
- package/dist/types/index.d.ts +5 -1
- package/dist/types/lib/error-handler.d.ts +60 -0
- package/dist/types/providers/auth/hooks.d.ts +1 -0
- package/dist/types/providers/user/hooks.d.ts +8 -0
- package/dist/types/providers/user/provider.d.ts +17 -0
- package/dist/types/providers/workspace/WorkspaceSettingsProvider.d.ts +9 -0
- package/dist/types/providers/workspace/settings-manager.d.ts +36 -0
- package/dist/types/providers/workspace/ui/SettingsDialog.d.ts +12 -3
- package/dist/types/providers/workspace/utils.d.ts +20 -0
- package/package.json +2 -1
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|