@buildbase/sdk 0.0.28 → 0.0.30
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 +236 -90
- package/dist/index.d.ts +650 -1991
- package/dist/index.js +1 -29
- package/dist/index.mjs +1 -0
- package/dist/react/index.d.ts +3180 -0
- package/dist/react/index.js +36 -0
- package/dist/react/index.mjs +36 -0
- package/package.json +13 -8
- package/dist/index.esm.js +0 -29
- /package/dist/{saas-os.css → css/styles.css} +0 -0
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# @buildbase/sdk
|
|
2
2
|
|
|
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
|
|
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, billing, and more.
|
|
4
|
+
|
|
5
|
+
Also works server-side (Next.js API routes, Express, Hono) — see [Server-Side Usage](#server-side-usage) below.
|
|
4
6
|
|
|
5
7
|
## 📑 Table of Contents
|
|
6
8
|
|
|
7
9
|
- [Features](#-features)
|
|
8
|
-
- [Installation](
|
|
9
|
-
- [Quick Start](
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Quick Start](#quick-start)
|
|
10
12
|
- [Authentication](#-authentication)
|
|
11
13
|
- [Role-Based Access Control](#-role-based-access-control)
|
|
12
14
|
- [Feature Flags](#️-feature-flags)
|
|
@@ -28,7 +30,7 @@ A React SDK for [BuildBase](https://www.buildbase.app/) that provides essential
|
|
|
28
30
|
- [Troubleshooting](#-troubleshooting)
|
|
29
31
|
- [API Reference](#-api-reference)
|
|
30
32
|
- [Best Practices](#-best-practices)
|
|
31
|
-
- [
|
|
33
|
+
- [Server-Side Usage](#server-side-usage)
|
|
32
34
|
|
|
33
35
|
## 🚀 Features
|
|
34
36
|
|
|
@@ -47,99 +49,103 @@ A React SDK for [BuildBase](https://www.buildbase.app/) that provides essential
|
|
|
47
49
|
- **📝 Beta Form** - Pre-built signup/waitlist form component
|
|
48
50
|
- **📡 Event System** - Subscribe to user and workspace events
|
|
49
51
|
- **🛡️ Error Handling** - Centralized error handling with error boundaries
|
|
52
|
+
- **🖥️ Server-Side SDK** - `BuildBase()` factory for API routes, background jobs, Express, Hono — zero React dependency
|
|
50
53
|
|
|
51
|
-
##
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
npm install @buildbase/sdk
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Peer Dependencies
|
|
58
|
-
|
|
59
|
-
This package requires React 19 and React DOM 19:
|
|
54
|
+
## Installation
|
|
60
55
|
|
|
61
56
|
```bash
|
|
62
|
-
npm install react@^19.0.0 react-dom@^19.0.0
|
|
57
|
+
npm install @buildbase/sdk react@^19.0.0 react-dom@^19.0.0
|
|
63
58
|
```
|
|
64
59
|
|
|
65
|
-
##
|
|
60
|
+
## Quick Start
|
|
66
61
|
|
|
67
62
|
### 1. Import CSS
|
|
68
63
|
|
|
69
|
-
First, import the required CSS file in your app:
|
|
70
|
-
|
|
71
64
|
```tsx
|
|
72
|
-
|
|
65
|
+
// app/layout.tsx (or your root layout)
|
|
66
|
+
import '@buildbase/sdk/css'
|
|
73
67
|
```
|
|
74
68
|
|
|
75
|
-
### 2. Create
|
|
76
|
-
|
|
77
|
-
Create a client-side provider component:
|
|
69
|
+
### 2. Create Provider
|
|
78
70
|
|
|
79
71
|
```tsx
|
|
80
|
-
|
|
72
|
+
// components/provider.tsx
|
|
73
|
+
'use client'
|
|
81
74
|
|
|
82
|
-
import { SaaSOSProvider } from '@buildbase/sdk'
|
|
83
|
-
import
|
|
75
|
+
import { SaaSOSProvider } from '@buildbase/sdk/react'
|
|
76
|
+
import { ApiVersion } from '@buildbase/sdk'
|
|
84
77
|
|
|
85
|
-
export default function SaaSProvider(
|
|
78
|
+
export default function SaaSProvider({ children }: { children: React.ReactNode }) {
|
|
86
79
|
return (
|
|
87
80
|
<SaaSOSProvider
|
|
88
81
|
serverUrl="https://your-api-server.com"
|
|
89
|
-
version=
|
|
82
|
+
version={ApiVersion.V1}
|
|
90
83
|
orgId="your-org-id"
|
|
91
84
|
auth={{
|
|
92
85
|
clientId: 'your-client-id',
|
|
93
86
|
redirectUrl: 'http://localhost:3000',
|
|
94
87
|
callbacks: {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
88
|
+
// Called on page refresh to restore session from httpOnly cookie
|
|
89
|
+
getSession: async () => {
|
|
90
|
+
const res = await fetch('/api/auth/session')
|
|
91
|
+
const data = await res.json()
|
|
92
|
+
return data.sessionId ?? null
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// Called after OAuth redirect to exchange code for sessionId
|
|
96
|
+
handleAuthentication: async (code) => {
|
|
97
|
+
const res = await fetch('/api/auth/verify', {
|
|
98
98
|
method: 'POST',
|
|
99
|
+
headers: { 'Content-Type': 'application/json' },
|
|
99
100
|
body: JSON.stringify({ code }),
|
|
100
|
-
})
|
|
101
|
-
const data = await
|
|
102
|
-
|
|
103
|
-
return { sessionId: data.sessionId };
|
|
101
|
+
})
|
|
102
|
+
const data = await res.json()
|
|
103
|
+
return { sessionId: data.sessionId }
|
|
104
104
|
},
|
|
105
|
+
|
|
106
|
+
// Called on sign out to clear the httpOnly cookie
|
|
105
107
|
onSignOut: async () => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
await fetch('/api/auth/signout', { method: 'POST' })
|
|
109
|
+
window.location.reload()
|
|
108
110
|
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
console.log('SDK Event:', eventType, data)
|
|
111
|
+
|
|
112
|
+
handleEvent: (eventType, data) => {
|
|
113
|
+
console.log('SDK Event:', eventType, data)
|
|
112
114
|
},
|
|
113
115
|
onWorkspaceChange: async ({ workspace, user, role }) => {
|
|
114
|
-
|
|
115
|
-
// Switch proceeds only when this resolves; reject to abort.
|
|
116
|
-
console.log('Switching to workspace:', workspace.name, 'as', role);
|
|
116
|
+
console.log('Switching to:', workspace.name, 'as', role)
|
|
117
117
|
},
|
|
118
118
|
},
|
|
119
119
|
}}
|
|
120
120
|
>
|
|
121
|
-
{
|
|
121
|
+
{children}
|
|
122
122
|
</SaaSOSProvider>
|
|
123
|
-
)
|
|
123
|
+
)
|
|
124
124
|
}
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
The SDK uses the same session pattern as next-auth: the session token lives in an httpOnly cookie (set by your server), and the SDK calls `getSession()` on page refresh to restore it. You need three server endpoints:
|
|
128
|
+
|
|
129
|
+
- **`/api/auth/verify`** — exchanges OAuth code for sessionId, sets httpOnly cookie
|
|
130
|
+
- **`/api/auth/session`** — reads httpOnly cookie, returns `{ sessionId }` (called on page refresh)
|
|
131
|
+
- **`/api/auth/signout`** — clears the httpOnly cookie
|
|
128
132
|
|
|
129
|
-
|
|
133
|
+
### 3. Wrap Your App
|
|
130
134
|
|
|
131
135
|
```tsx
|
|
132
|
-
|
|
136
|
+
// app/layout.tsx
|
|
137
|
+
import SaaSProvider from '@/components/provider'
|
|
138
|
+
import '@buildbase/sdk/css'
|
|
133
139
|
|
|
134
|
-
function
|
|
140
|
+
export default function RootLayout({ children }) {
|
|
135
141
|
return (
|
|
136
|
-
<
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
<html>
|
|
143
|
+
<body>
|
|
144
|
+
<SaaSProvider>{children}</SaaSProvider>
|
|
145
|
+
</body>
|
|
146
|
+
</html>
|
|
147
|
+
)
|
|
140
148
|
}
|
|
141
|
-
|
|
142
|
-
export default App;
|
|
143
149
|
```
|
|
144
150
|
|
|
145
151
|
### 4. Workspace Management
|
|
@@ -148,7 +154,7 @@ The WorkspaceSwitcher component uses a render prop pattern, giving you full cont
|
|
|
148
154
|
|
|
149
155
|
```tsx
|
|
150
156
|
import React from 'react';
|
|
151
|
-
import { WorkspaceSwitcher } from '@buildbase/sdk';
|
|
157
|
+
import { WorkspaceSwitcher } from '@buildbase/sdk/react';
|
|
152
158
|
|
|
153
159
|
function WorkspaceExample() {
|
|
154
160
|
return (
|
|
@@ -192,7 +198,7 @@ function WorkspaceExample() {
|
|
|
192
198
|
Use the `useSaaSAuth` hook to manage authentication state and actions:
|
|
193
199
|
|
|
194
200
|
```tsx
|
|
195
|
-
import { useSaaSAuth } from '@buildbase/sdk';
|
|
201
|
+
import { useSaaSAuth } from '@buildbase/sdk/react';
|
|
196
202
|
|
|
197
203
|
function AuthExample() {
|
|
198
204
|
const { user, isAuthenticated, signIn, signOut, status } = useSaaSAuth();
|
|
@@ -254,7 +260,7 @@ openWorkspaceSettings('danger'); // Delete workspace (owner only)
|
|
|
254
260
|
For declarative rendering, use the conditional components:
|
|
255
261
|
|
|
256
262
|
```tsx
|
|
257
|
-
import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk';
|
|
263
|
+
import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk/react';
|
|
258
264
|
|
|
259
265
|
function App() {
|
|
260
266
|
return (
|
|
@@ -278,7 +284,7 @@ function App() {
|
|
|
278
284
|
Control access based on user roles:
|
|
279
285
|
|
|
280
286
|
```tsx
|
|
281
|
-
import { WhenRoles, WhenWorkspaceRoles } from '@buildbase/sdk';
|
|
287
|
+
import { WhenRoles, WhenWorkspaceRoles } from '@buildbase/sdk/react';
|
|
282
288
|
|
|
283
289
|
function AdminPanel() {
|
|
284
290
|
return (
|
|
@@ -312,7 +318,7 @@ import {
|
|
|
312
318
|
WhenWorkspaceFeatureDisabled,
|
|
313
319
|
WhenUserFeatureEnabled,
|
|
314
320
|
WhenUserFeatureDisabled,
|
|
315
|
-
} from '@buildbase/sdk';
|
|
321
|
+
} from '@buildbase/sdk/react';
|
|
316
322
|
|
|
317
323
|
function FeatureExample() {
|
|
318
324
|
return (
|
|
@@ -344,7 +350,7 @@ function FeatureExample() {
|
|
|
344
350
|
Use the `useUserFeatures` hook to check feature flags programmatically:
|
|
345
351
|
|
|
346
352
|
```tsx
|
|
347
|
-
import { useUserFeatures } from '@buildbase/sdk';
|
|
353
|
+
import { useUserFeatures } from '@buildbase/sdk/react';
|
|
348
354
|
|
|
349
355
|
function FeatureCheck() {
|
|
350
356
|
const { features, isFeatureEnabled, refreshFeatures } = useUserFeatures();
|
|
@@ -364,7 +370,7 @@ Control UI visibility based on the current workspace’s subscription. Subscript
|
|
|
364
370
|
### Subscription Gate Components
|
|
365
371
|
|
|
366
372
|
```tsx
|
|
367
|
-
import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk';
|
|
373
|
+
import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk/react';
|
|
368
374
|
|
|
369
375
|
function BillingExample() {
|
|
370
376
|
return (
|
|
@@ -418,7 +424,7 @@ All gates must be used inside **SubscriptionContextProvider** (included in SaaSO
|
|
|
418
424
|
Use the hook when you need subscription data or a manual refetch (e.g. after returning from Stripe checkout):
|
|
419
425
|
|
|
420
426
|
```tsx
|
|
421
|
-
import { useSubscriptionContext } from '@buildbase/sdk';
|
|
427
|
+
import { useSubscriptionContext } from '@buildbase/sdk/react';
|
|
422
428
|
|
|
423
429
|
function SubscriptionStatus() {
|
|
424
430
|
const { response, loading, refetch } = useSubscriptionContext();
|
|
@@ -455,7 +461,7 @@ Control UI based on trial state. Works with Stripe-native trials (both card-requ
|
|
|
455
461
|
### Trial Gate Components
|
|
456
462
|
|
|
457
463
|
```tsx
|
|
458
|
-
import { WhenTrialing, WhenNotTrialing, WhenTrialEnding } from '@buildbase/sdk';
|
|
464
|
+
import { WhenTrialing, WhenNotTrialing, WhenTrialEnding } from '@buildbase/sdk/react';
|
|
459
465
|
|
|
460
466
|
function TrialExample() {
|
|
461
467
|
return (
|
|
@@ -492,7 +498,7 @@ All trial gates support `loadingComponent` and `fallbackComponent` props.
|
|
|
492
498
|
Hook that computes trial information from the subscription context:
|
|
493
499
|
|
|
494
500
|
```tsx
|
|
495
|
-
import { useTrialStatus } from '@buildbase/sdk';
|
|
501
|
+
import { useTrialStatus } from '@buildbase/sdk/react';
|
|
496
502
|
|
|
497
503
|
function TrialInfo() {
|
|
498
504
|
const { isTrialing, daysRemaining, trialEndsAt, isTrialEnding } = useTrialStatus();
|
|
@@ -557,7 +563,7 @@ Everything else is built-in — permission handling, subscribe/unsubscribe, sett
|
|
|
557
563
|
Manage custom user attributes (key-value pairs):
|
|
558
564
|
|
|
559
565
|
```tsx
|
|
560
|
-
import { useUserAttributes } from '@buildbase/sdk';
|
|
566
|
+
import { useUserAttributes } from '@buildbase/sdk/react';
|
|
561
567
|
|
|
562
568
|
function UserProfile() {
|
|
563
569
|
const { attributes, isLoading, updateAttribute, updateAttributes, refreshAttributes } =
|
|
@@ -589,7 +595,7 @@ function UserProfile() {
|
|
|
589
595
|
The `useSaaSWorkspaces` hook provides comprehensive workspace management:
|
|
590
596
|
|
|
591
597
|
```tsx
|
|
592
|
-
import { useSaaSWorkspaces } from '@buildbase/sdk';
|
|
598
|
+
import { useSaaSWorkspaces } from '@buildbase/sdk/react';
|
|
593
599
|
|
|
594
600
|
function WorkspaceManager() {
|
|
595
601
|
const {
|
|
@@ -640,7 +646,7 @@ Display subscription plans and pricing on public pages (e.g. marketing site, pri
|
|
|
640
646
|
Fetches public plans by slug. Returns `items` (features, limits, quotas) and `plans` (with pricing). You construct the layout from this data:
|
|
641
647
|
|
|
642
648
|
```tsx
|
|
643
|
-
import { usePublicPlans } from '@buildbase/sdk';
|
|
649
|
+
import { usePublicPlans } from '@buildbase/sdk/react';
|
|
644
650
|
|
|
645
651
|
function PublicPricingPage() {
|
|
646
652
|
const { items, plans, loading, error } = usePublicPlans('main-pricing');
|
|
@@ -663,7 +669,7 @@ function PublicPricingPage() {
|
|
|
663
669
|
Use the `PricingPage` component with a render-prop pattern:
|
|
664
670
|
|
|
665
671
|
```tsx
|
|
666
|
-
import { PricingPage } from '@buildbase/sdk';
|
|
672
|
+
import { PricingPage } from '@buildbase/sdk/react';
|
|
667
673
|
|
|
668
674
|
function PublicPricingPage() {
|
|
669
675
|
return (
|
|
@@ -748,7 +754,7 @@ import {
|
|
|
748
754
|
getBasePriceCents,
|
|
749
755
|
getQuotaDisplayValue,
|
|
750
756
|
formatQuotaWithPrice,
|
|
751
|
-
} from '@buildbase/sdk';
|
|
757
|
+
} from '@buildbase/sdk/react';
|
|
752
758
|
|
|
753
759
|
// Display price for a plan version in a currency
|
|
754
760
|
const variant = getPricingVariant(planVersion, 'usd');
|
|
@@ -786,7 +792,7 @@ Use the SDK hooks inside your React app. Quota gate components (see [Quota Gates
|
|
|
786
792
|
#### Record Usage
|
|
787
793
|
|
|
788
794
|
```tsx
|
|
789
|
-
import { useRecordUsage, useSaaSWorkspaces } from '@buildbase/sdk';
|
|
795
|
+
import { useRecordUsage, useSaaSWorkspaces } from '@buildbase/sdk/react';
|
|
790
796
|
|
|
791
797
|
function SendEmailButton() {
|
|
792
798
|
const { currentWorkspace } = useSaaSWorkspaces();
|
|
@@ -816,7 +822,7 @@ function SendEmailButton() {
|
|
|
816
822
|
#### Check Single Quota Status
|
|
817
823
|
|
|
818
824
|
```tsx
|
|
819
|
-
import { useQuotaUsageStatus, useSaaSWorkspaces } from '@buildbase/sdk';
|
|
825
|
+
import { useQuotaUsageStatus, useSaaSWorkspaces } from '@buildbase/sdk/react';
|
|
820
826
|
|
|
821
827
|
function QuotaStatusBar({ quotaSlug }: { quotaSlug: string }) {
|
|
822
828
|
const { currentWorkspace } = useSaaSWorkspaces();
|
|
@@ -841,7 +847,7 @@ function QuotaStatusBar({ quotaSlug }: { quotaSlug: string }) {
|
|
|
841
847
|
#### Check All Quotas
|
|
842
848
|
|
|
843
849
|
```tsx
|
|
844
|
-
import { useAllQuotaUsage, useSaaSWorkspaces } from '@buildbase/sdk';
|
|
850
|
+
import { useAllQuotaUsage, useSaaSWorkspaces } from '@buildbase/sdk/react';
|
|
845
851
|
|
|
846
852
|
function QuotaDashboard() {
|
|
847
853
|
const { currentWorkspace } = useSaaSWorkspaces();
|
|
@@ -866,7 +872,7 @@ function QuotaDashboard() {
|
|
|
866
872
|
#### Usage Logs
|
|
867
873
|
|
|
868
874
|
```tsx
|
|
869
|
-
import { useUsageLogs, useSaaSWorkspaces } from '@buildbase/sdk';
|
|
875
|
+
import { useUsageLogs, useSaaSWorkspaces } from '@buildbase/sdk/react';
|
|
870
876
|
|
|
871
877
|
function UsageLogsTable() {
|
|
872
878
|
const { currentWorkspace } = useSaaSWorkspaces();
|
|
@@ -1077,7 +1083,7 @@ import {
|
|
|
1077
1083
|
WhenQuotaExhausted,
|
|
1078
1084
|
WhenQuotaOverage,
|
|
1079
1085
|
WhenQuotaThreshold,
|
|
1080
|
-
} from '@buildbase/sdk';
|
|
1086
|
+
} from '@buildbase/sdk/react';
|
|
1081
1087
|
|
|
1082
1088
|
function Dashboard() {
|
|
1083
1089
|
return (
|
|
@@ -1145,7 +1151,7 @@ All gates must be used inside `QuotaUsageContextProvider` (included in `SaaSOSPr
|
|
|
1145
1151
|
Use the hook when you need raw quota data or a manual refetch (e.g. after a bulk operation):
|
|
1146
1152
|
|
|
1147
1153
|
```tsx
|
|
1148
|
-
import { useQuotaUsageContext } from '@buildbase/sdk';
|
|
1154
|
+
import { useQuotaUsageContext } from '@buildbase/sdk/react';
|
|
1149
1155
|
|
|
1150
1156
|
function QuotaDebug() {
|
|
1151
1157
|
const { quotas, loading, refetch } = useQuotaUsageContext();
|
|
@@ -1180,7 +1186,7 @@ function QuotaDebug() {
|
|
|
1180
1186
|
Use the pre-built `BetaForm` component for signup/waitlist forms:
|
|
1181
1187
|
|
|
1182
1188
|
```tsx
|
|
1183
|
-
import { BetaForm } from '@buildbase/sdk';
|
|
1189
|
+
import { BetaForm } from '@buildbase/sdk/react';
|
|
1184
1190
|
|
|
1185
1191
|
function SignupPage() {
|
|
1186
1192
|
return (
|
|
@@ -1201,7 +1207,8 @@ function SignupPage() {
|
|
|
1201
1207
|
Subscribe to SDK events for user and workspace changes:
|
|
1202
1208
|
|
|
1203
1209
|
```tsx
|
|
1204
|
-
import { SaaSOSProvider
|
|
1210
|
+
import { SaaSOSProvider } from '@buildbase/sdk/react';
|
|
1211
|
+
import { eventEmitter } from '@buildbase/sdk';
|
|
1205
1212
|
|
|
1206
1213
|
// In your provider configuration
|
|
1207
1214
|
<SaaSOSProvider
|
|
@@ -1249,7 +1256,7 @@ The SDK handles errors internally: API failures, auth errors, and component erro
|
|
|
1249
1256
|
Access OS-level settings:
|
|
1250
1257
|
|
|
1251
1258
|
```tsx
|
|
1252
|
-
import { useSaaSSettings } from '@buildbase/sdk';
|
|
1259
|
+
import { useSaaSSettings } from '@buildbase/sdk/react';
|
|
1253
1260
|
|
|
1254
1261
|
function SettingsExample() {
|
|
1255
1262
|
const { settings, getSettings } = useSaaSSettings();
|
|
@@ -1296,7 +1303,8 @@ All SDK API clients extend a shared base class and are exported from the package
|
|
|
1296
1303
|
Get OS config from `useSaaSOs()` and instantiate API classes when you need low-level access; otherwise prefer the high-level hooks (`useSaaSWorkspaces`, `useUserAttributes`, `useSaaSSettings`, etc.):
|
|
1297
1304
|
|
|
1298
1305
|
```tsx
|
|
1299
|
-
import {
|
|
1306
|
+
import { useSaaSOs } from '@buildbase/sdk/react';
|
|
1307
|
+
import { UserApi, WorkspaceApi, SettingsApi } from '@buildbase/sdk';
|
|
1300
1308
|
|
|
1301
1309
|
const os = useSaaSOs();
|
|
1302
1310
|
const workspaceApi = new WorkspaceApi({
|
|
@@ -1361,10 +1369,16 @@ All TypeScript types are exported for type safety. See the [TypeScript definitio
|
|
|
1361
1369
|
interface IAuthConfig {
|
|
1362
1370
|
clientId: string; // OAuth client ID
|
|
1363
1371
|
redirectUrl: string; // OAuth redirect URL
|
|
1364
|
-
callbacks
|
|
1372
|
+
callbacks: {
|
|
1373
|
+
// Required: restore session on page refresh (reads httpOnly cookie via server endpoint)
|
|
1374
|
+
getSession: () => Promise<string | null>;
|
|
1375
|
+
// Required: exchange OAuth code for sessionId (sets httpOnly cookie on server)
|
|
1365
1376
|
handleAuthentication: (code: string) => Promise<{ sessionId: string }>;
|
|
1366
|
-
|
|
1377
|
+
// Required: clear session on sign out (clears httpOnly cookie on server)
|
|
1378
|
+
onSignOut: () => Promise<void>;
|
|
1379
|
+
// Optional: listen to SDK events
|
|
1367
1380
|
handleEvent?: (eventType: EventType, data: EventData) => void | Promise<void>;
|
|
1381
|
+
// Optional: called before workspace switch
|
|
1368
1382
|
onWorkspaceChange?: (params: OnWorkspaceChangeParams) => Promise<void>;
|
|
1369
1383
|
};
|
|
1370
1384
|
}
|
|
@@ -1372,10 +1386,15 @@ interface IAuthConfig {
|
|
|
1372
1386
|
interface OnWorkspaceChangeParams {
|
|
1373
1387
|
workspace: IWorkspace;
|
|
1374
1388
|
user: AuthUser | null;
|
|
1375
|
-
role: string | null;
|
|
1389
|
+
role: string | null;
|
|
1376
1390
|
}
|
|
1377
1391
|
```
|
|
1378
1392
|
|
|
1393
|
+
**Session flow** (same pattern as next-auth):
|
|
1394
|
+
- Session token is stored in an **httpOnly cookie** (set by your server, not readable by JS)
|
|
1395
|
+
- On page refresh, the SDK calls `getSession()` once to restore the session
|
|
1396
|
+
- Session data (user info) lives **in-memory only** (React context) — no localStorage
|
|
1397
|
+
|
|
1379
1398
|
### Validation Requirements
|
|
1380
1399
|
|
|
1381
1400
|
- **serverUrl**: Must be a valid URL (e.g., `https://api.example.com`)
|
|
@@ -1403,7 +1422,7 @@ interface OnWorkspaceChangeParams {
|
|
|
1403
1422
|
### Pattern 1: Protected Routes
|
|
1404
1423
|
|
|
1405
1424
|
```tsx
|
|
1406
|
-
import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk';
|
|
1425
|
+
import { WhenAuthenticated, WhenUnauthenticated } from '@buildbase/sdk/react';
|
|
1407
1426
|
|
|
1408
1427
|
function App() {
|
|
1409
1428
|
return (
|
|
@@ -1430,7 +1449,7 @@ function ProtectedRoutes() {
|
|
|
1430
1449
|
### Pattern 2: Role-Based Navigation
|
|
1431
1450
|
|
|
1432
1451
|
```tsx
|
|
1433
|
-
import { WhenRoles } from '@buildbase/sdk';
|
|
1452
|
+
import { WhenRoles } from '@buildbase/sdk/react';
|
|
1434
1453
|
|
|
1435
1454
|
function Navigation() {
|
|
1436
1455
|
return (
|
|
@@ -1453,7 +1472,7 @@ function Navigation() {
|
|
|
1453
1472
|
### Pattern 3: Workspace Context Provider
|
|
1454
1473
|
|
|
1455
1474
|
```tsx
|
|
1456
|
-
import { useSaaSWorkspaces } from '@buildbase/sdk';
|
|
1475
|
+
import { useSaaSWorkspaces } from '@buildbase/sdk/react';
|
|
1457
1476
|
import { createContext, useContext } from 'react';
|
|
1458
1477
|
|
|
1459
1478
|
const WorkspaceContext = createContext(null);
|
|
@@ -1472,7 +1491,7 @@ export function useWorkspace() {
|
|
|
1472
1491
|
### Pattern 4: Feature Gated Components
|
|
1473
1492
|
|
|
1474
1493
|
```tsx
|
|
1475
|
-
import { WhenWorkspaceFeatureEnabled } from '@buildbase/sdk';
|
|
1494
|
+
import { WhenWorkspaceFeatureEnabled } from '@buildbase/sdk/react';
|
|
1476
1495
|
|
|
1477
1496
|
function Dashboard() {
|
|
1478
1497
|
return (
|
|
@@ -1494,7 +1513,7 @@ function Dashboard() {
|
|
|
1494
1513
|
### Pattern 4b: Subscription-Gated UI
|
|
1495
1514
|
|
|
1496
1515
|
```tsx
|
|
1497
|
-
import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk';
|
|
1516
|
+
import { WhenSubscription, WhenNoSubscription, WhenSubscriptionToPlans } from '@buildbase/sdk/react';
|
|
1498
1517
|
|
|
1499
1518
|
function BillingPage() {
|
|
1500
1519
|
return (
|
|
@@ -1520,7 +1539,7 @@ SubscriptionContextProvider is included in SaaSOSProvider by default, so no extr
|
|
|
1520
1539
|
### Pattern 4c: Quota-Gated UI
|
|
1521
1540
|
|
|
1522
1541
|
```tsx
|
|
1523
|
-
import { WhenQuotaAvailable, WhenQuotaExhausted, WhenQuotaThreshold } from '@buildbase/sdk';
|
|
1542
|
+
import { WhenQuotaAvailable, WhenQuotaExhausted, WhenQuotaThreshold } from '@buildbase/sdk/react';
|
|
1524
1543
|
|
|
1525
1544
|
function FeatureWithQuota() {
|
|
1526
1545
|
return (
|
|
@@ -1546,7 +1565,7 @@ QuotaUsageContextProvider is included in SaaSOSProvider by default, so no extra
|
|
|
1546
1565
|
### Pattern 5: Handling Workspace Changes
|
|
1547
1566
|
|
|
1548
1567
|
```tsx
|
|
1549
|
-
import { useSaaSWorkspaces } from '@buildbase/sdk';
|
|
1568
|
+
import { useSaaSWorkspaces } from '@buildbase/sdk/react';
|
|
1550
1569
|
import { useEffect } from 'react';
|
|
1551
1570
|
|
|
1552
1571
|
function App() {
|
|
@@ -1692,7 +1711,7 @@ useEffect(() => {
|
|
|
1692
1711
|
**Solution**: Ensure CSS is imported:
|
|
1693
1712
|
|
|
1694
1713
|
```tsx
|
|
1695
|
-
import '@buildbase/sdk/
|
|
1714
|
+
import '@buildbase/sdk/css';
|
|
1696
1715
|
```
|
|
1697
1716
|
|
|
1698
1717
|
### FAQ
|
|
@@ -1710,7 +1729,7 @@ A: Use the `trigger` render prop to fully customize the UI.
|
|
|
1710
1729
|
A: No, the SDK manages one current workspace at a time. Use `switchToWorkspace()` (runs `onWorkspaceChange` first) or `setCurrentWorkspace()` (direct set, bypasses callback).
|
|
1711
1730
|
|
|
1712
1731
|
**Q: How do I handle offline scenarios?**
|
|
1713
|
-
A: The
|
|
1732
|
+
A: The session token is stored in an httpOnly cookie (set by your server). On page refresh, the SDK calls your `getSession` callback to restore it. Handle offline scenarios in your `handleAuthentication` and `getSession` callbacks.
|
|
1714
1733
|
|
|
1715
1734
|
**Q: Can I use this without TypeScript?**
|
|
1716
1735
|
A: Yes, but TypeScript is recommended for better developer experience.
|
|
@@ -1881,6 +1900,133 @@ refreshWorkspaces();
|
|
|
1881
1900
|
await fetchWorkspaces();
|
|
1882
1901
|
```
|
|
1883
1902
|
|
|
1903
|
+
## Server-Side Usage
|
|
1904
|
+
|
|
1905
|
+
The SDK also works on the server — API routes, background jobs, webhooks, cron tasks. Zero React dependency.
|
|
1906
|
+
|
|
1907
|
+
```
|
|
1908
|
+
@buildbase/sdk Server: BuildBase() factory, API classes, types, utilities
|
|
1909
|
+
@buildbase/sdk/react Client: React hooks, providers, gate components (documented above)
|
|
1910
|
+
```
|
|
1911
|
+
|
|
1912
|
+
### Setup (Next.js)
|
|
1913
|
+
|
|
1914
|
+
Configure once, use everywhere. Same pattern as Auth.js.
|
|
1915
|
+
|
|
1916
|
+
```ts
|
|
1917
|
+
// lib/buildbase.ts
|
|
1918
|
+
import BuildBase from '@buildbase/sdk'
|
|
1919
|
+
import { cookies } from 'next/headers'
|
|
1920
|
+
|
|
1921
|
+
export const { auth, workspace, subscription, usage, plans, invoices, users, features, settings, withSession, client } = BuildBase({
|
|
1922
|
+
serverUrl: process.env.BUILDBASE_URL!,
|
|
1923
|
+
orgId: process.env.BUILDBASE_ORG_ID!,
|
|
1924
|
+
getSessionId: async () => {
|
|
1925
|
+
const c = await cookies()
|
|
1926
|
+
return c.get('bb-session-id')?.value ?? null
|
|
1927
|
+
},
|
|
1928
|
+
})
|
|
1929
|
+
```
|
|
1930
|
+
|
|
1931
|
+
Use in API routes — session is resolved automatically:
|
|
1932
|
+
|
|
1933
|
+
```ts
|
|
1934
|
+
// app/api/workspace/route.ts
|
|
1935
|
+
import { auth, workspace, subscription } from '@/lib/buildbase'
|
|
1936
|
+
|
|
1937
|
+
export async function GET() {
|
|
1938
|
+
const session = await auth()
|
|
1939
|
+
if (!session) return Response.json({ error: 'Unauthorized' }, { status: 401 })
|
|
1940
|
+
|
|
1941
|
+
const workspaces = await workspace.list()
|
|
1942
|
+
return Response.json({ workspaces })
|
|
1943
|
+
}
|
|
1944
|
+
```
|
|
1945
|
+
|
|
1946
|
+
### Setup (Express)
|
|
1947
|
+
|
|
1948
|
+
No `getSessionId` callback — use `withSession()` per-request instead.
|
|
1949
|
+
|
|
1950
|
+
```ts
|
|
1951
|
+
// buildbase.ts
|
|
1952
|
+
import BuildBase from '@buildbase/sdk'
|
|
1953
|
+
|
|
1954
|
+
const bb = BuildBase({
|
|
1955
|
+
serverUrl: process.env.BUILDBASE_URL!,
|
|
1956
|
+
orgId: process.env.BUILDBASE_ORG_ID!,
|
|
1957
|
+
})
|
|
1958
|
+
|
|
1959
|
+
export const { withSession, plans } = bb
|
|
1960
|
+
```
|
|
1961
|
+
|
|
1962
|
+
```ts
|
|
1963
|
+
// routes
|
|
1964
|
+
app.get('/workspaces', async (req, res) => {
|
|
1965
|
+
const { workspace } = withSession(req.headers['x-session-id'])
|
|
1966
|
+
res.json(await workspace.list())
|
|
1967
|
+
})
|
|
1968
|
+
|
|
1969
|
+
app.post('/usage', async (req, res) => {
|
|
1970
|
+
const { usage } = withSession(req.headers['x-session-id'])
|
|
1971
|
+
const result = await usage.record(req.body.workspaceId, {
|
|
1972
|
+
quotaSlug: 'api-calls',
|
|
1973
|
+
quantity: 1,
|
|
1974
|
+
})
|
|
1975
|
+
res.json(result)
|
|
1976
|
+
})
|
|
1977
|
+
```
|
|
1978
|
+
|
|
1979
|
+
### Background Jobs / Webhooks
|
|
1980
|
+
|
|
1981
|
+
For service accounts (no user session), use `withSession()` with a service token:
|
|
1982
|
+
|
|
1983
|
+
```ts
|
|
1984
|
+
import { withSession } from '@/lib/buildbase'
|
|
1985
|
+
|
|
1986
|
+
const bb = withSession(process.env.SERVICE_SESSION_ID!)
|
|
1987
|
+
|
|
1988
|
+
// Record usage from a webhook
|
|
1989
|
+
await bb.usage.record(workspaceId, {
|
|
1990
|
+
quotaSlug: 'uploads',
|
|
1991
|
+
quantity: 1,
|
|
1992
|
+
source: 'webhook:file.processed',
|
|
1993
|
+
})
|
|
1994
|
+
|
|
1995
|
+
// Check subscription
|
|
1996
|
+
const sub = await bb.subscription.get(workspaceId)
|
|
1997
|
+
```
|
|
1998
|
+
|
|
1999
|
+
### Server-Side Actions Reference
|
|
2000
|
+
|
|
2001
|
+
| Module | Methods |
|
|
2002
|
+
|--------|---------|
|
|
2003
|
+
| `workspace` | `list`, `get`, `create`, `update`, `delete` |
|
|
2004
|
+
| `users` | `list`, `invite`, `remove`, `updateRole`, `getProfile`, `updateProfile` |
|
|
2005
|
+
| `subscription` | `get`, `checkout`, `update`, `cancel`, `resume`, `getBillingPortalUrl` |
|
|
2006
|
+
| `plans` | `getGroup`, `getVersions`, `getPublic`, `getVersion` |
|
|
2007
|
+
| `invoices` | `list`, `get` |
|
|
2008
|
+
| `usage` | `record`, `getQuota`, `getAll`, `getLogs` |
|
|
2009
|
+
| `settings` | `get` |
|
|
2010
|
+
| `features` | `list`, `update` |
|
|
2011
|
+
|
|
2012
|
+
### BuildBase Config Options
|
|
2013
|
+
|
|
2014
|
+
```ts
|
|
2015
|
+
BuildBase({
|
|
2016
|
+
serverUrl: '...', // Required
|
|
2017
|
+
orgId: '...', // Required
|
|
2018
|
+
getSessionId: async () => ..., // Session resolver (Next.js: read cookie)
|
|
2019
|
+
timeout: 30_000, // Request timeout in ms (default: 30s)
|
|
2020
|
+
maxRetries: 2, // Retry on network errors / 5xx
|
|
2021
|
+
debug: true, // Log all API calls to console
|
|
2022
|
+
headers: { 'X-Source': 'cron' }, // Custom headers on every request
|
|
2023
|
+
onError: (err, ctx) => { // Centralized error callback
|
|
2024
|
+
Sentry.captureException(err, { extra: ctx })
|
|
2025
|
+
},
|
|
2026
|
+
fetch: customFetch, // Replace global fetch (testing, proxying)
|
|
2027
|
+
})
|
|
2028
|
+
```
|
|
2029
|
+
|
|
1884
2030
|
## 🤝 Contributing
|
|
1885
2031
|
|
|
1886
2032
|
1. Fork the repository
|