@buildbase/sdk 0.0.54 → 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/AGENTS.md +8 -4
  2. package/CHANGELOG.md +53 -0
  3. package/LICENSE +21 -0
  4. package/README.md +203 -45
  5. package/dist/css/styles.css +1 -1
  6. package/dist/index.cjs +1 -1
  7. package/dist/index.d.ts +196 -88
  8. package/dist/index.mjs +1 -1
  9. package/dist/mcp/index.cjs +1 -1
  10. package/dist/mcp/index.d.ts +226 -16
  11. package/dist/mcp/index.mjs +1 -1
  12. package/dist/react/chunks/SettingsDialog-B6DhyNae.cjs +2 -0
  13. package/dist/react/chunks/SettingsDialog-K38BI74F.mjs +2 -0
  14. package/dist/react/chunks/SubscriptionDialog-BidcQ_vc.mjs +2 -0
  15. package/dist/react/chunks/SubscriptionDialog-CfDLoOzW.cjs +2 -0
  16. package/dist/react/chunks/ar-CCKONfUU.mjs +2 -0
  17. package/dist/react/chunks/ar-DrHMtT1E.cjs +2 -0
  18. package/dist/react/chunks/de-Dhtorn10.cjs +2 -0
  19. package/dist/react/chunks/de-X9mfnMFM.mjs +2 -0
  20. package/dist/react/chunks/es--8iZ7Trv.mjs +2 -0
  21. package/dist/react/chunks/es-CUR7LB6a.cjs +2 -0
  22. package/dist/react/chunks/fr-BqMs_F5g.cjs +2 -0
  23. package/dist/react/chunks/fr-rUp34NG7.mjs +2 -0
  24. package/dist/react/chunks/hi-B_IiucJZ.mjs +2 -0
  25. package/dist/react/chunks/hi-C2i1_hdv.cjs +2 -0
  26. package/dist/react/chunks/ja-4hLI6wMX.cjs +2 -0
  27. package/dist/react/chunks/ja-CIGOj3vV.mjs +2 -0
  28. package/dist/react/chunks/react-BXTDLnE8.cjs +2 -0
  29. package/dist/react/chunks/react-CXCk05WI.mjs +2 -0
  30. package/dist/react/chunks/zh-BSgd6ai5.cjs +2 -0
  31. package/dist/react/chunks/zh-DyVvcYFC.mjs +2 -0
  32. package/dist/react/index.cjs +1 -1
  33. package/dist/react/index.d.ts +460 -142
  34. package/dist/react/index.mjs +1 -1
  35. package/docs/ARCHITECTURE.md +419 -0
  36. package/docs/ERROR_CODES.md +96 -0
  37. package/docs/MCP-AND-AGENT-READINESS.md +893 -0
  38. package/docs/THEMING.md +67 -0
  39. package/docs/UI-CONFIG.md +207 -0
  40. package/package.json +14 -3
  41. package/dist/react/chunks/SettingsDialog-B28WJsAr.cjs +0 -2
  42. package/dist/react/chunks/SettingsDialog-blhppbNm.mjs +0 -2
  43. package/dist/react/chunks/SubscriptionDialog-BTWVX3cH.mjs +0 -2
  44. package/dist/react/chunks/SubscriptionDialog-QKmwvJU1.cjs +0 -2
  45. package/dist/react/chunks/ar-1Z1MOGAP.mjs +0 -2
  46. package/dist/react/chunks/ar-VGzBv3AZ.cjs +0 -2
  47. package/dist/react/chunks/de-BjdDg60Y.cjs +0 -2
  48. package/dist/react/chunks/de-CXUItplO.mjs +0 -2
  49. package/dist/react/chunks/es-BBPsSZUp.cjs +0 -2
  50. package/dist/react/chunks/es-BTbzVutz.mjs +0 -2
  51. package/dist/react/chunks/fr-Cax48X_S.cjs +0 -2
  52. package/dist/react/chunks/fr-DPMeOQu3.mjs +0 -2
  53. package/dist/react/chunks/hi-BJqvpG6d.cjs +0 -2
  54. package/dist/react/chunks/hi-JfJx-LV7.mjs +0 -2
  55. package/dist/react/chunks/ja-CDGtLzTk.mjs +0 -2
  56. package/dist/react/chunks/ja-DvVyj5xX.cjs +0 -2
  57. package/dist/react/chunks/react-6QJCOE-D.cjs +0 -2
  58. package/dist/react/chunks/react-CC6T7Zky.mjs +0 -2
  59. package/dist/react/chunks/zh-BAcqxkxk.cjs +0 -2
  60. package/dist/react/chunks/zh-BNZ2Ooe8.mjs +0 -2
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- export{az as ApiVersion,aA as AuthApi,aB as AuthStatus,m as BBAction,aC as BBScreen,n as BBStatus,aD as BB_PARAM,aE as BaseApi,aF as BetaForm,ab as BillingIntervals,aG as CURRENCY_DISPLAY,aH as CURRENCY_FLAG,C as ConnectedAgents,aI as ConnectedAgentsApi,aJ as CreditActionsProvider,aK as CreditBalance,aL as CreditBalanceContextProvider,aM as CreditBucketSource,aN as CreditBucketStatus,aO as CreditStorePage,t as CreditTransactionType,aP as DEFAULT_ROLE_PERMISSIONS,ac as DunningState,E as EmptyState,aQ as EventEmitter,aR as FullScreenLoader,$ as InvoiceStatuses,L as LoadingState,aS as PLAN_CURRENCY_CODES,aT as PLAN_CURRENCY_OPTIONS,aU as PUSH_SERVICE_WORKER_SCRIPT,P as Permission,aV as PricingPage,aW as PushApi,aX as PushNotificationProvider,aY as QuotaUsageContextProvider,aZ as SDKEvent,ax as SETTINGS_SCREENS,a_ as SUPPORTED_LOCALES,a$ as SaaSOSProvider,q as SectionHeader,b0 as SettingsApi,aq as SettingsScreen,as as SidebarNavItem,ar as SidebarNavSection,p as StatusBanner,b1 as SubscriptionContextProvider,ae as SubscriptionItemType,a7 as SubscriptionStatus,b2 as UserApi,b3 as WhenAuthenticated,b4 as WhenCreditsAvailable,b5 as WhenCreditsExhausted,b6 as WhenCreditsLow,b7 as WhenNoSubscription,b8 as WhenNotTrialing,b9 as WhenPermission,ba as WhenQuotaAvailable,bb as WhenQuotaExhausted,bc as WhenQuotaOverage,bd as WhenQuotaThreshold,be as WhenRoles,bf as WhenSubscription,bg as WhenSubscriptionToPlans,bh as WhenTrialEnding,bi as WhenTrialing,bj as WhenUnauthenticated,bk as WhenUserFeatureDisabled,bl as WhenUserFeatureEnabled,bm as WhenWorkspaceFeatureDisabled,bn as WhenWorkspaceFeatureEnabled,bo as WhenWorkspaceRoles,bp as WorkspaceApi,bq as WorkspaceSwitcher,br as calculateBillableSeats,bs as calculateSeatOverageCents,bt as calculateTotalSubscriptionCents,bu as cleanBBParams,bv as clearAuthIntent,bw as consumeAuthIntent,bx as createBBUrl,ai as createCheckoutRedirectUrls,r as createCreditPurchaseRedirectUrls,by as eventEmitter,bz as formatCents,bA as formatOverageRate,bB as formatOverageRateWithLabel,bC as formatQuotaIncludedOverage,bD as formatQuotaWithPrice,ay as getAvailableCurrenciesFromPlans,a8 as getBasePriceCents,a6 as getBillingIntervalAndCurrencyFromPriceId,O as getCurrencyFlag,g as getCurrencySymbol,bE as getDisplayCurrency,aa as getPerSeatPriceCents,bF as getPricingVariant,ag as getQuotaDisplayValue,af as getQuotaDisplayWithVariant,am as getQuotaOverageCents,bG as getQuotaUnitLabelFromName,a9 as getSeatPricing,ah as getStripePriceIdForInterval,bH as hasPermission,o as invalidateCreditBalance,bI as invalidateQuotaUsage,aj as invalidateSubscription,bJ as isZeroDecimalCurrency,au as mergeUIConfig,bK as minorAmountToDisplay,bL as readBBParams,bM as resolveMaxUsers,bN as resolvePermissions,s as safeRedirect,bO as saveAuthIntent,bP as useAllQuotaUsage,a4 as useBillingPortal,a2 as useCancelSubscription,bQ as useConnectedAgents,bR as useConnectedAgentsApi,bS as useConsumeCredits,a1 as useCreateCheckoutSession,bT as useCreditBalance,h as useCreditBalanceContext,i as useCreditPackages,k as useCreditTransactions,j as useExpiringCredits,bU as useFullScreenLoader,bV as useInvoice,_ as useInvoices,e as usePermissions,bW as usePlanGroup,a5 as usePlanGroupVersions,bX as usePublicCreditPackages,bY as usePublicPlanGroupVersion,bZ as usePublicPlans,l as usePurchaseCredits,X as usePushNotifications,ak as useQuotaUsageContext,b_ as useQuotaUsageStatus,b$ as useRecordUsage,a3 as useResumeSubscription,an as useSaaSAuth,c0 as useSaaSOs,z as useSaaSSettings,y as useSaaSWorkspaces,ao as useSeatStatus,c1 as useSubscription,al as useSubscriptionContext,a0 as useSubscriptionManagement,u as useTranslation,c2 as useTrialStatus,at as useUIConfig,f as useUIVisibility,c3 as useUpdateSubscription,c4 as useUsageLogs,c5 as useUserAttributes,c6 as useUserFeatures,c7 as validateInvite,c8 as validateRedirectUrl,w as workspaceSettingsManager}from"./chunks/react-CC6T7Zky.mjs";import"react/jsx-runtime";import"react";import"clsx";import"tailwind-merge";import"intl-messageformat";import"@hookform/resolvers/zod";import"react-hook-form";import"@radix-ui/react-slot";import"class-variance-authority";import"lucide-react";import"@radix-ui/react-label";import"zod";import"@radix-ui/react-avatar";import"@radix-ui/react-dialog";import"@radix-ui/react-icons";import"@radix-ui/react-radio-group";import"@radix-ui/react-scroll-area";import"@radix-ui/react-separator";
2
+ export{aF as ApiVersion,aG as AuthApi,aH as AuthStatus,o as BBAction,aI as BBScreen,p as BBStatus,aJ as BB_PARAM,aK as BaseApi,aL as BetaForm,a6 as BillingIntervals,aM as BuildBaseProvider,aN as CURRENCY_DISPLAY,aO as CURRENCY_FLAG,aP as ConnectMcpGuide,C as ConnectedAgents,aQ as ConnectedAgentsApi,aR as CreditActionsProvider,aS as CreditBalance,aT as CreditBalanceContextProvider,aU as CreditBucketSource,aV as CreditBucketStatus,aW as CreditStorePage,y as CreditTransactionType,aX as DEFAULT_ROLE_PERMISSIONS,al as DunningState,E as EmptyState,aY as EventEmitter,aZ as FullScreenLoader,a4 as InvoiceStatuses,L as LoadingState,a_ as PLAN_CURRENCY_CODES,a$ as PLAN_CURRENCY_OPTIONS,b0 as PUSH_SERVICE_WORKER_SCRIPT,P as Permission,b1 as PricingPage,b2 as PushApi,b3 as PushNotificationProvider,b4 as QuotaUsageContextProvider,b5 as SDKEvent,aC as SETTINGS_SCREENS,b6 as SUPPORTED_LOCALES,aM as SaaSOSProvider,s as SectionHeader,b7 as SettingsApi,av as SettingsScreen,ax as SidebarNavItem,aw as SidebarNavSection,r as StatusBanner,b8 as SubscriptionContextProvider,a7 as SubscriptionItemType,aa as SubscriptionStatus,b9 as UserApi,ba as WhenAuthenticated,bb as WhenCreditsAvailable,bc as WhenCreditsExhausted,bd as WhenCreditsLow,be as WhenNoSubscription,bf as WhenNotTrialing,bg as WhenPermission,bh as WhenQuotaAvailable,bi as WhenQuotaExhausted,bj as WhenQuotaOverage,bk as WhenQuotaThreshold,bl as WhenRoles,bm as WhenSubscription,bn as WhenSubscriptionToPlans,bo as WhenTrialEnding,bp as WhenTrialing,bq as WhenUnauthenticated,br as WhenUserFeatureDisabled,bs as WhenUserFeatureEnabled,bt as WhenWorkspaceFeatureDisabled,bu as WhenWorkspaceFeatureEnabled,bv as WhenWorkspaceRoles,bw as WorkspaceApi,bx as WorkspaceSwitcher,by as calculateBillableSeats,bz as calculateSeatOverageCents,bA as calculateTotalSubscriptionCents,bB as cleanBBParams,bC as clearAuthIntent,bD as consumeAuthIntent,bE as createBBUrl,an as createCheckoutRedirectUrls,v as createCreditPurchaseRedirectUrls,bF as eventEmitter,bG as fillMcpTemplate,bH as formatCents,f as formatMinorAmountIntl,bI as formatOverageRate,bJ as formatOverageRateWithLabel,bK as formatQuotaIncludedOverage,bL as formatQuotaWithPrice,aE as getAvailableCurrenciesFromPlans,ai as getBasePriceCents,ah as getBillingIntervalAndCurrencyFromPriceId,e as getCurrencyDecimals,T as getCurrencyFlag,g as getCurrencySymbol,bM as getDisplayCurrency,ak as getPerSeatPriceCents,aD as getPricingVariant,a9 as getQuotaDisplayValue,a8 as getQuotaDisplayWithVariant,ar as getQuotaOverageCents,bN as getQuotaUnitLabelFromName,aj as getSeatPricing,am as getStripePriceIdForInterval,bO as hasPermission,q as invalidateCreditBalance,bP as invalidateQuotaUsage,ao as invalidateSubscription,bQ as isZeroDecimalCurrency,bR as mcpServerKey,az as mergeUIConfig,bS as minorAmountToDisplay,bT as readBBParams,bU as resolveMaxUsers,bV as resolvePermissions,x as safeRedirect,bW as saveAuthIntent,bX as useAllQuotaUsage,af as useBillingPortal,ad as useCancelSubscription,bY as useConnectedAgents,bZ as useConnectedAgentsApi,b_ as useConsumeCredits,ac as useCreateCheckoutSession,b$ as useCreditBalance,j as useCreditBalanceContext,k as useCreditPackages,m as useCreditTransactions,l as useExpiringCredits,c0 as useFullScreenLoader,c1 as useInvoice,a2 as useInvoices,c2 as useMcpConnection,h as usePermissions,c3 as usePlanGroup,ag as usePlanGroupVersions,c4 as usePublicCreditPackages,c5 as usePublicPlanGroupVersion,c6 as usePublicPlans,n as usePurchaseCredits,_ as usePushNotifications,ap as useQuotaUsageContext,c7 as useQuotaUsageStatus,c8 as useRecordUsage,ae as useResumeSubscription,as as useSaaSAuth,c9 as useSaaSOs,G as useSaaSSettings,F as useSaaSWorkspaces,at as useSeatStatus,ca as useSubscription,aq as useSubscriptionContext,ab as useSubscriptionManagement,u as useTranslation,cb as useTrialStatus,ay as useUIConfig,i as useUIVisibility,cc as useUpdateSubscription,cd as useUsageLogs,ce as useUserAttributes,cf as useUserFeatures,cg as validateInvite,ch as validateRedirectUrl,w as workspaceSettingsManager}from"./chunks/react-CXCk05WI.mjs";import"react/jsx-runtime";import"react";import"clsx";import"tailwind-merge";import"intl-messageformat";import"@hookform/resolvers/zod";import"react-hook-form";import"@radix-ui/react-slot";import"class-variance-authority";import"lucide-react";import"@radix-ui/react-label";import"zod";import"@radix-ui/react-avatar";import"@radix-ui/react-dialog";import"@radix-ui/react-icons";import"@radix-ui/react-radio-group";import"@radix-ui/react-scroll-area";import"@radix-ui/react-separator";import"@radix-ui/react-accordion";
@@ -0,0 +1,419 @@
1
+ # SDK Architecture Documentation
2
+
3
+ This document describes the internal architecture and design decisions of the BuildBase SDK.
4
+
5
+ ## Overview
6
+
7
+ The BuildBase SDK is a React-based SDK that provides authentication, workspace management, user management, and subscription features. It uses React Context for state management and follows a provider-based architecture.
8
+
9
+ ## Architecture Layers
10
+
11
+ ### 1. Provider Layer
12
+
13
+ The SDK uses a nested provider structure:
14
+
15
+ ```
16
+ SaaSOSProvider (root)
17
+ ├── TranslationProvider (i18n)
18
+ ├── SDKContextProvider (context management)
19
+ ├── AuthProviderWrapper (authentication)
20
+ ├── PortalProvider (portal rendering)
21
+ ├── ContextConfigProvider (OS configuration)
22
+ ├── CheckoutConfigProvider (Stripe checkout params)
23
+ ├── PermissionConfigProvider (app permissions)
24
+ ├── UserProvider (user attributes/features)
25
+ ├── SubscriptionContextProvider (subscription for current workspace; powers subscription gates)
26
+ ├── QuotaUsageContextProvider (quota usage; powers quota gates)
27
+ ├── CreditBalanceContextProvider (credit balance; powers credit gates)
28
+ ├── PushNotificationProvider (browser push)
29
+ └── WorkspaceSettingsProvider (workspace settings UI)
30
+ ```
31
+
32
+ **Design Decision**: Nested providers allow for:
33
+
34
+ - Clear separation of concerns
35
+ - Independent feature enablement
36
+ - Proper dependency ordering (auth before workspace, etc.)
37
+
38
+ ### 2. Context Layer
39
+
40
+ The SDK uses multiple React contexts for state management:
41
+
42
+ #### AuthContext
43
+
44
+ - **Purpose**: Manages authentication state and session
45
+ - **State**: `{ session: AuthSession | null, status: AuthStatus }`
46
+ - **Design**: Single source of truth for auth state. Status enum drives all auth flags (derived, not stored).
47
+
48
+ #### OSContext
49
+
50
+ - **Purpose**: Manages SDK configuration (serverUrl, version, orgId, settings)
51
+ - **State**: `{ serverUrl, version, orgId, settings, auth }`
52
+ - **Design**: Immutable config that rarely changes after initialization.
53
+
54
+ #### WorkspaceContext
55
+
56
+ - **Purpose**: Manages workspace state and operations
57
+ - **State**: `{ workspaces[], currentWorkspace, loading, error, ... }`
58
+ - **Design**: Centralized workspace state with optimistic updates.
59
+
60
+ #### SDKContext
61
+
62
+ - **Purpose**: Combines all contexts into a single provider
63
+ - **Design**: Reduces provider nesting and provides unified state access.
64
+
65
+ #### SubscriptionContext
66
+
67
+ - **Purpose**: Provides subscription data for the current workspace to subscription gate components
68
+ - **State**: `{ response: ISubscriptionResponse | null, loading: boolean, refetch: () => Promise<void> }`
69
+ - **Design**: Read-only; data comes from `useSubscription(currentWorkspace?._id)`. Refetches when workspace changes or when subscription is invalidated (e.g. after plan update, cancel, resume). Internal invalidation notifier allows mutation hooks to trigger a refetch so gates stay in sync.
70
+
71
+ **Design Decision**: Multiple contexts instead of single context:
72
+
73
+ - Better performance (components only re-render when their context changes)
74
+ - Clearer separation of concerns
75
+ - Easier to test individual features
76
+
77
+ ### 3. API Layer
78
+
79
+ The SDK uses a **central base class + domain APIs** pattern. All domain API classes extend `BaseApi` for shared URL building, auth headers, and request/response handling.
80
+
81
+ #### BaseApi (`src/lib/api-base.ts`)
82
+
83
+ - **Purpose**: Abstract base for all SDK API clients
84
+ - **Provides**: `baseUrl`, `getAuthHeaders()`, `url(path)`, `fetchJson<T>()`, `fetchResponse()`, `throwResponseError()`, `unwrapResponse<T>()`
85
+ - **Config**: `IBaseApiConfig` (serverUrl, version, optional orgId, onUnauthorized, timeout, maxRetries, debug, onError)
86
+
87
+ #### Domain APIs (extend BaseApi)
88
+
89
+ | Class | Location | Purpose |
90
+ | ---------------- | -------------------------------- | ----------------------------------------- |
91
+ | **UserApi** | `src/providers/user/api.ts` | User attributes, user features |
92
+ | **WorkspaceApi** | `src/providers/workspace/api.ts` | Workspaces, subscription, invoices, users |
93
+ | **SettingsApi** | `src/providers/os/api.ts` | Organization settings |
94
+
95
+ All are exported from the package; consumers typically use the high-level hooks (e.g. `useSaaSWorkspaces`, `useUserAttributes`) or instantiate API classes with config from `useSaaSOs()`.
96
+
97
+ #### API utilities (shared helpers)
98
+
99
+ - **Location**: `src/lib/api-utils.ts`
100
+ - **Functions**: `safeFetch`, `handleApiResponse`, `getErrorMessage`, `isAbortError`, `fetchWithTimeout`
101
+ - **Error helpers** (`src/lib/error-handler.ts`): `handleError`, `getHookErrorMessage`, `createSDKError`
102
+
103
+ #### Currency, pricing variant & quota utilities
104
+
105
+ Multi-currency plans use **pricing variants** (`IPricingVariant`) and **per-interval quotas** (`IQuotaByInterval`). These modules are in `src/api/` and are exported from the package:
106
+
107
+ | Module | Purpose |
108
+ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
109
+ | **currency-utils** | `CURRENCY_DISPLAY`, `CURRENCY_FLAG`, `PLAN_CURRENCY_CODES`, `PLAN_CURRENCY_OPTIONS`, `getCurrencySymbol`, `getCurrencyFlag`, `formatCents`, `formatOverageRate`, `formatOverageRateWithLabel`, `formatQuotaIncludedOverage`, `getQuotaUnitLabelFromName` |
110
+ | **pricing-variant-utils** | `getPricingVariant`, `getBasePriceCents`, `getStripePriceIdForInterval`, `getQuotaOverageCents`, `getQuotaDisplayWithVariant`, `getAvailableCurrenciesFromPlans`, `getDisplayCurrency`, `getBillingIntervalAndCurrencyFromPriceId`; types: `IPricingVariant`, `PlanVersionWithPricingVariants`, `QuotaDisplayWithOverage` |
111
+ | **quota-utils** | `getQuotaDisplayValue`, `formatQuotaWithPrice`; types: `QuotaDisplayValue`, `FormatQuotaWithPriceOptions` |
112
+
113
+ Plan and subscription types use `IPlanVersion.pricingVariants` (instead of single `basePricing`/`stripePrices`) and `IQuotaByInterval` / `IQuotaIntervalValue` for quotas and overages per billing interval.
114
+
115
+ **Design Decision**: Central base class + domain APIs:
116
+
117
+ - Single place for URL building, auth, and fetch behavior
118
+ - Easy to add new domains (extend BaseApi)
119
+ - Consistent error handling and logging
120
+
121
+ ### 4. Hook Layer
122
+
123
+ The SDK exposes hooks for consuming context and performing operations. **Prefer these hooks over `useAppSelector`** for state access so the SDK can evolve internal state without breaking consumers.
124
+
125
+ #### Auth Hooks
126
+
127
+ - `useSaaSAuth()`: Main auth hook (user, session, status, signIn, signOut, openWorkspaceSettings)
128
+
129
+ #### OS Hooks
130
+
131
+ - `useSaaSOs()`: Full OS config (serverUrl, version, orgId, auth, settings). Use when you need the config object.
132
+ - `useSaaSSettings()`: Organization settings and getSettings. Prefer this when you only need settings.
133
+
134
+ #### Workspace Hooks
135
+
136
+ - `useSaaSWorkspaces()`: Main workspace management hook (workspaces, currentWorkspace, loading, switching, switchingToId, CRUD and switch actions)
137
+ - Subscription hooks: `useSubscription`, `usePlanGroup`, etc.
138
+
139
+ #### Subscription Context Hook
140
+
141
+ - `useSubscriptionContext()`: Returns subscription for current workspace (response, loading, refetch). Used by subscription gate components; available to app code when subscription data or manual refetch is needed. Must be used within SubscriptionContextProvider.
142
+
143
+ #### User Hooks
144
+
145
+ - `useUserAttributes()`: User attributes access
146
+ - `useUserFeatures()`: User feature flags
147
+
148
+ **Design Decision**: Hooks pattern:
149
+
150
+ - Familiar React API
151
+ - Automatic re-renders on state changes
152
+ - Easy to use in functional components
153
+ - Type-safe with TypeScript
154
+ - Single public API for state; internal use of `useAppSelector` is limited to hook/context implementation
155
+
156
+ ### 5. Component Layer
157
+
158
+ The SDK provides conditional rendering components:
159
+
160
+ #### Auth Components
161
+
162
+ - `WhenAuthenticated`: Renders when user is authenticated
163
+ - `WhenUnauthenticated`: Renders when user is not authenticated
164
+
165
+ #### Role Components
166
+
167
+ - `WhenRoles`: Renders based on user's global role
168
+ - `WhenWorkspaceRoles`: Renders based on user's workspace role
169
+
170
+ #### Feature Components
171
+
172
+ - `WhenUserFeatureEnabled/Disabled`: Renders based on user feature flags
173
+ - `WhenWorkspaceFeatureEnabled/Disabled`: Renders based on workspace feature flags
174
+
175
+ #### Subscription Gate Components
176
+
177
+ - `WhenSubscription`: Renders when current workspace has an active subscription (any plan)
178
+ - `WhenNoSubscription`: Renders when current workspace has no subscription
179
+ - `WhenSubscriptionToPlans`: Renders when current workspace is subscribed to one of the given plan slugs
180
+
181
+ All subscription gates consume `useSubscriptionContext()` and must be used within `SubscriptionContextProvider` (included in SaaSOSProvider by default).
182
+
183
+ **Design Decision**: Conditional components:
184
+
185
+ - Declarative API for feature gating
186
+ - Reduces boilerplate in consumer apps
187
+ - Type-safe with TypeScript
188
+
189
+ ## State Management
190
+
191
+ ### Context-Based State (No Redux)
192
+
193
+ **Decision**: Use React Context instead of Redux.
194
+
195
+ **Rationale**:
196
+
197
+ - Simpler for SDK consumers (no Redux setup required)
198
+ - Less bundle size
199
+ - Sufficient for SDK's state management needs
200
+ - Better integration with React 19
201
+
202
+ ### State Updates
203
+
204
+ State updates use reducer pattern:
205
+
206
+ ```typescript
207
+ // Example: AuthContext reducer
208
+ function authReducer(state: IAuthState, action: AuthAction): IAuthState {
209
+ switch (action.type) {
210
+ case 'AUTHENTICATION_STARTED':
211
+ return { ...state, status: AuthStatus.redirecting };
212
+ // ...
213
+ }
214
+ }
215
+ ```
216
+
217
+ **Design Decision**: Reducer pattern:
218
+
219
+ - Predictable state updates
220
+ - Easy to debug (action-based)
221
+ - Type-safe with TypeScript
222
+
223
+ ### Derived State
224
+
225
+ Some state is derived rather than stored:
226
+
227
+ ```typescript
228
+ // Auth flags are derived from status
229
+ const flags = getAuthFlags(auth.status);
230
+ // Returns: { isLoading, isAuthenticated, isRedirecting }
231
+ ```
232
+
233
+ **Design Decision**: Derived state:
234
+
235
+ - Single source of truth (status enum)
236
+ - Prevents state inconsistencies
237
+ - Reduces state size
238
+
239
+ ## Authentication Flow
240
+
241
+ ### OAuth Flow
242
+
243
+ 1. User calls `signIn()`
244
+ 2. SDK redirects to OAuth provider
245
+ 3. User authenticates with provider
246
+ 4. Provider redirects back with `?code=...`
247
+ 5. SDK exchanges code for session
248
+ 6. Session stored in localStorage and context
249
+
250
+ ### Session Management
251
+
252
+ - **Source of truth**: httpOnly cookie (set by your server, not readable by JS)
253
+ - **Hydration**: On mount, SDK calls `getSession()` callback to restore the session from your server endpoint
254
+ - **Validation**: Session validated by fetching user profile with the sessionId
255
+ - **Expiration**: 401 responses trigger `onSessionExpired` callback (during hydration and mid-session via `onUnauthorized` interceptor in BaseApi)
256
+ - **Guards**: Component-scoped refs prevent duplicate hydration across mount/remount cycles
257
+
258
+ **Design Decision**: httpOnly cookie + callback pattern (similar to next-auth):
259
+
260
+ - Secure: session token not accessible to JS (XSS-safe)
261
+ - Flexible: server controls cookie lifetime, httpOnly, secure flags
262
+ - Framework-agnostic: works with any server (Next.js, Express, Hono)
263
+
264
+ ### Workspace Switching
265
+
266
+ - **Entry point**: `switchToWorkspace(id)` calls auth callback `onWorkspaceChange({ workspace, user, role })`, then updates current workspace and storage.
267
+ - **State**: `switchingToId` (ID being switched to) and derived `switching`; used for loaders and to avoid overwriting with stale results.
268
+ - **Concurrency**: A version ref ensures only the latest switch completes; rejections from `onWorkspaceChange` are caught so they do not surface as unhandled.
269
+
270
+ ## Error Handling
271
+
272
+ ### Error Handler
273
+
274
+ Centralized error handler (`src/lib/error-handler.ts`):
275
+
276
+ - Logs errors in development
277
+ - Supports custom error callbacks
278
+ - Provides error context (component, action, metadata)
279
+ - Creates standardized SDKError instances
280
+
281
+ ### Error Boundaries
282
+
283
+ React Error Boundaries catch component errors:
284
+
285
+ - `SDKErrorBoundary`: Catches errors in SDK components
286
+ - Prevents app crashes
287
+ - Provides fallback UI
288
+ - Logs errors automatically
289
+
290
+ **Design Decision**: Multiple error handling layers:
291
+
292
+ - Network errors: Handled in API utilities
293
+ - Component errors: Handled by Error Boundaries
294
+ - Application errors: Handled by error handler
295
+ - User-facing errors: Can be customized via callbacks
296
+
297
+ ## Performance Optimizations
298
+
299
+ ### Memoization
300
+
301
+ - Context values memoized to prevent unnecessary re-renders
302
+ - Hook return values memoized
303
+ - API client instances memoized (recreated only when config changes)
304
+
305
+ ### Request Deduplication
306
+
307
+ - Refs used to prevent duplicate concurrent requests
308
+ - Example: `fetchingProfileRef` in auth provider
309
+
310
+ ### AbortController
311
+
312
+ - All API calls support AbortSignal
313
+ - Requests cancelled on unmount
314
+ - Prevents memory leaks and race conditions
315
+
316
+ **Design Decision**: AbortController pattern:
317
+
318
+ - Prevents race conditions
319
+ - Reduces unnecessary network traffic
320
+ - Better user experience (no stale data)
321
+
322
+ ## Type Safety
323
+
324
+ ### TypeScript Usage
325
+
326
+ - Full TypeScript coverage
327
+ - Strict type checking
328
+ - Exported types for all public APIs
329
+
330
+ ### Type Exports
331
+
332
+ All public types exported from `src/index.ts`:
333
+
334
+ - API types (subscriptions, invoices, plans, pricing variants, quotas, etc.)
335
+ - Plan/subscription: `IPlanVersion`, `IPricingVariant`, `IQuotaByInterval`, `IQuotaIntervalValue`, `IStripePricesByInterval`, `IQuotaOveragesByInterval`, `IPublicPlanVersion`, `IPublicPlansResponse`, and related
336
+ - Currency/quota helpers: `QuotaDisplayValue`, `FormatQuotaWithPriceOptions`, `PlanVersionWithPricingVariants`, `QuotaDisplayWithOverage`
337
+ - Context types
338
+ - Error types
339
+ - Component prop types
340
+
341
+ **Design Decision**: Comprehensive type exports:
342
+
343
+ - Better developer experience
344
+ - Type-safe SDK usage
345
+ - IDE autocomplete support
346
+
347
+ ## Event System
348
+
349
+ ### Event Emitter
350
+
351
+ The SDK includes an event emitter for workspace/user events:
352
+
353
+ - `workspace:created`
354
+ - `workspace:updated`
355
+ - `workspace:deleted`
356
+ - `workspace:changed`
357
+ - `user:created`
358
+ - `user:updated`
359
+ - etc.
360
+
361
+ **Design Decision**: Event system:
362
+
363
+ - Allows consumers to react to SDK events
364
+ - Decouples SDK from consumer app logic
365
+ - Supports custom event handlers via callbacks
366
+
367
+ ## Testing Considerations
368
+
369
+ ### Testability
370
+
371
+ - Hooks can be tested with `@testing-library/react-hooks`
372
+ - Contexts can be tested independently
373
+ - API clients can be mocked
374
+ - Components can be tested with React Testing Library
375
+
376
+ ### Mocking
377
+
378
+ - API calls can be mocked at the fetch level
379
+ - Contexts can be mocked with custom providers
380
+ - Event emitter can be mocked
381
+
382
+ ## Bundle Size
383
+
384
+ ### Tree Shaking
385
+
386
+ - Named exports for all public APIs
387
+ - No default exports (except ErrorBoundary)
388
+ - Side-effect-free modules where possible
389
+
390
+ ### Dependencies
391
+
392
+ - Minimal external dependencies
393
+ - Peer dependencies for React (not bundled)
394
+ - Radix UI components (tree-shakeable)
395
+
396
+ ## Future Considerations
397
+
398
+ - **Request Caching**: Optional cache for GET requests
399
+ - **Request Interceptors**: Optional request/response interceptors
400
+ - **Offline Support**: Optional response caching
401
+ - **Migration**: Backward compatible API; deprecation warnings before breaking changes; semantic versioning
402
+
403
+ ## Summary
404
+
405
+ The BuildBase SDK follows a layered architecture:
406
+
407
+ 1. **Providers**: Nested React providers for feature enablement
408
+ 2. **Contexts**: Multiple React contexts for state management
409
+ 3. **APIs**: Centralized API clients with shared utilities
410
+ 4. **Hooks**: React hooks for consuming SDK features
411
+ 5. **Components**: Conditional rendering components
412
+
413
+ Key design principles:
414
+
415
+ - **Simplicity**: Easy to use, minimal setup
416
+ - **Type Safety**: Full TypeScript coverage
417
+ - **Performance**: Memoization, request deduplication, AbortController
418
+ - **Error Handling**: Multiple layers of error handling
419
+ - **Developer Experience**: Comprehensive documentation, JSDoc comments, examples
@@ -0,0 +1,96 @@
1
+ # Error Codes Reference
2
+
3
+ This document lists error codes used in the BuildBase SDK and their meanings. These codes can be used with `createSDKError()` and may be set on `SDKError.code` when the SDK throws. Not every code is used in every release; this doc serves as the canonical reference.
4
+
5
+ ## SDK Error Codes
6
+
7
+ ### Authentication Errors
8
+
9
+ | Code | Description | When It Occurs |
10
+ | ----------------- | ----------------------- | ----------------------------------------------------------------------- |
11
+ | `AUTH_FAILED` | Authentication failed | When OAuth flow fails or user cannot be authenticated |
12
+ | `AUTH_REQUIRED` | Authentication required | When an operation requires authentication but user is not authenticated |
13
+ | `SESSION_EXPIRED` | Session expired | When user session has expired and needs to be refreshed |
14
+ | `INVALID_SESSION` | Invalid session | When session data is corrupted or invalid |
15
+
16
+ ### Network Errors
17
+
18
+ | Code | Description | When It Occurs |
19
+ | ----------------- | ------------------------- | ----------------------------------------------------------- |
20
+ | `NETWORK_ERROR` | Network connection failed | When fetch fails due to network issues (offline, DNS, CORS) |
21
+ | `REQUEST_TIMEOUT` | Request timeout | When request exceeds timeout duration |
22
+ | `ABORT_ERROR` | Request aborted | When request is cancelled via AbortController |
23
+
24
+ ### API Errors
25
+
26
+ | Code | Description | When It Occurs |
27
+ | -------------- | ------------------- | ------------------------------------------ |
28
+ | `API_ERROR` | Generic API error | When API returns an error response |
29
+ | `BAD_REQUEST` | Bad request (400) | When request is malformed or invalid |
30
+ | `UNAUTHORIZED` | Unauthorized (401) | When authentication is required or invalid |
31
+ | `FORBIDDEN` | Forbidden (403) | When user doesn't have permission |
32
+ | `NOT_FOUND` | Not found (404) | When resource doesn't exist |
33
+ | `SERVER_ERROR` | Server error (500+) | When server encounters an error |
34
+
35
+ ### Workspace Errors
36
+
37
+ | Code | Description | When It Occurs |
38
+ | -------------------------- | ------------------------ | -------------------------------------------------------- |
39
+ | `WORKSPACE_NOT_FOUND` | Workspace not found | When workspace doesn't exist or user doesn't have access |
40
+ | `WORKSPACE_ACCESS_DENIED` | Workspace access denied | When user doesn't have permission to access workspace |
41
+ | `WORKSPACE_OWNER_REQUIRED` | Workspace owner required | When operation requires workspace owner (e.g., delete) |
42
+ | `INVALID_WORKSPACE_ID` | Invalid workspace ID | When workspace ID format is invalid |
43
+
44
+ ### User Management Errors
45
+
46
+ | Code | Description | When It Occurs |
47
+ | -------------------------- | ------------------------ | -------------------------------------------- |
48
+ | `USER_NOT_FOUND` | User not found | When user doesn't exist |
49
+ | `USER_ALREADY_EXISTS` | User already exists | When trying to add user that already exists |
50
+ | `CANNOT_REMOVE_OWNER` | Cannot remove owner | When trying to remove workspace owner |
51
+ | `CANNOT_CHANGE_OWNER_ROLE` | Cannot change owner role | When trying to change workspace owner's role |
52
+
53
+ ### Subscription Errors
54
+
55
+ | Code | Description | When It Occurs |
56
+ | ------------------------ | ---------------------- | ------------------------------------ |
57
+ | `SUBSCRIPTION_NOT_FOUND` | Subscription not found | When workspace has no subscription |
58
+ | `SUBSCRIPTION_ERROR` | Subscription error | When subscription operation fails |
59
+ | `CHECKOUT_ERROR` | Checkout error | When checkout session creation fails |
60
+ | `PLAN_NOT_FOUND` | Plan not found | When plan doesn't exist |
61
+
62
+ ### Configuration Errors
63
+
64
+ | Code | Description | When It Occurs |
65
+ | -------------------- | ----------------------- | ------------------------------------------ |
66
+ | `INVALID_CONFIG` | Invalid configuration | When SDK configuration is invalid |
67
+ | `INVALID_SERVER_URL` | Invalid server URL | When serverUrl is not a valid URL |
68
+ | `INVALID_ORG_ID` | Invalid organization ID | When orgId is not a valid MongoDB ObjectId |
69
+ | `INVALID_VERSION` | Invalid API version | When API version is not supported |
70
+
71
+ ### Generic Errors
72
+
73
+ | Code | Description | When It Occurs |
74
+ | ------------------ | ---------------- | ------------------------------------ |
75
+ | `UNKNOWN_ERROR` | Unknown error | When error type cannot be determined |
76
+ | `VALIDATION_ERROR` | Validation error | When input validation fails |
77
+
78
+ ## HTTP Status Code Mappings
79
+
80
+ The SDK automatically maps HTTP status codes to error messages:
81
+
82
+ | Status Code | Error Message |
83
+ | ----------- | ---------------------------------------- |
84
+ | 400 | Bad Request |
85
+ | 401 | Unauthorized - Please check your session |
86
+ | 403 | Forbidden - You do not have permission |
87
+ | 404 | Resource not found |
88
+ | 500 | Internal server error |
89
+ | 502 | Bad Gateway |
90
+ | 503 | Service unavailable |
91
+
92
+ ## Error Handling
93
+
94
+ - **Hook errors**: Use the `error` property from hooks (e.g. `useSaaSWorkspaces()`, `useUserAttributes()`) and show user feedback (toast, inline message).
95
+ - **Async operations**: In `catch` blocks, check `error.message`; for aborted requests, ignore or treat as cancelled.
96
+ - **React errors**: Wrap your app with an error boundary to catch render-time errors.