@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
package/README.md CHANGED
@@ -7,6 +7,7 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
7
7
  ## ๐Ÿ“‘ Table of Contents
8
8
 
9
9
  - [Features](#-features)
10
+ - [Customization Map](#-customization-map)
10
11
  - [Installation](#installation)
11
12
  - [Quick Start](#quick-start)
12
13
  - [UI Configuration](#๏ธ-ui-configuration)
@@ -19,6 +20,7 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
19
20
  - [Trial Gates](#-trial-gates)
20
21
  - [Push Notifications](#-push-notifications)
21
22
  - [Notifications](#-notifications)
23
+ - [Connected Agents](#-connected-agents)
22
24
  - [User Management](#-user-management)
23
25
  - [Workspace Management](#-complete-workspace-management)
24
26
  - [Public Pricing (No Login)](#-public-pricing-no-login)
@@ -52,6 +54,7 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
52
54
  - **โณ Trial Gates** - `WhenTrialing`, `WhenNotTrialing`, `WhenTrialEnding` components + `useTrialStatus` hook
53
55
  - **๐Ÿ”” Push Notifications** - Browser push notifications with `usePushNotifications` hook, auto-triggers for billing events, and campaign management
54
56
  - **๐Ÿ“ฌ Notifications** - Email + push notification system with per-event channel control, workspace preferences, and server-side `notification.send()` API
57
+ - **๐Ÿ”Œ Connected Agents** - `<ConnectedAgents />` screen to list/revoke authorized AI agents, plus a built-in "Connect an agent" setup guide (ChatGPT, Claude, Cursor, VS Code, Windsurf, Cline) driven by an `mcp` provider prop
55
58
  - **๐Ÿ’บ Seat-Based Pricing** - Per-seat billing with included seats, billable seat tracking, and seat limit enforcement
56
59
  - **๐Ÿ’ฑ Multi-Currency** - Per-currency pricing variants with workspace billing currency lock
57
60
  - **๐Ÿค Affiliate Tracking** - Pass referral data to Stripe checkout via `getCheckoutStripeParams` prop (Rewardful, Endorsely, FirstPromoter, etc.)
@@ -66,6 +69,31 @@ Also works server-side (Next.js API routes, Express, Hono) โ€” see [Server-Side
66
69
  - **๐ŸŒ Internationalization (i18n)** - 8 locales (en, es, fr, de, ja, zh, hi, ar), ICU MessageFormat, RTL support, native numerals
67
70
  - **๐Ÿ  Workspace Modes** - Personal (solo B2C) or Platform (multi-user B2B), configured from admin dashboard
68
71
 
72
+ ## ๐ŸŽจ Customization Map
73
+
74
+ Everything the SDK lets you configure, override, or extend โ€” one row per knob, so you can see the whole surface before reading any deep-dive section. The philosophy throughout: **safe defaults, everything overridable, the SDK accelerates but never gates.**
75
+
76
+ | What you customize | How | Where to read more |
77
+ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
78
+ | Provider setup & workspace behavior | `<SaaSOSProvider>` / `<BuildBaseProvider>` props (`serverUrl`, `orgId`, `locale`, workspace auto-create, redirects) | [Configuration Reference](#๏ธ-configuration-reference) |
79
+ | Which SDK UI renders at all | `ui` prop: hide/show settings sections, workspace switcher, per-screen toggles | [UI Configuration](#๏ธ-ui-configuration) ยท `docs/UI-CONFIG.md` |
80
+ | Every user-facing string | `ui.messages` deep-override (e.g. rename "Subscription" โ†’ "Billing"), per-locale | [UI Configuration](#๏ธ-ui-configuration) |
81
+ | Language & number systems | `locale` prop โ€” 8 locales, ICU plurals, RTL (`ar`), native numerals | [Internationalization](#-internationalization-i18n) |
82
+ | Look & feel | CSS custom properties (`--primary`, `--destructive`, โ€ฆ) โ€” semantic tokens, light/dark, no palette lock-in | `docs/THEMING.md` |
83
+ | Date/number formats | `ui.formats` (`Intl` options passed through) | `docs/UI-CONFIG.md` |
84
+ | Conditional UI | Gate components: `WhenAuthenticated`, `WhenPermission`, `WhenWorkspaceFeatureEnabled`, `WhenSubscription`, `WhenTrialing`, `WhenQuotaAvailable`, `WhenCreditsAvailable`, โ€ฆ | [Subscription Gates](#-subscription-gates) & siblings |
85
+ | Checkout behavior | `getCheckoutStripeParams` (affiliate/referral params), plan-picker behavior config | [Affiliate Tracking](#affiliate--referral-tracking) |
86
+ | Connect-an-agent guide | `mcp` prop (`url`, `name`, `docsUrl`, `clients`, `prompt`) โ†’ in-app setup guide + `<ConnectedAgents />` screen | [Connected Agents](#-connected-agents) |
87
+ | Error presentation | `ui.errorBoundary`, centralized `handleError` reporting | [Error Handling](#๏ธ-error-handling) |
88
+ | React-free server access | `BuildBase()` factory โ€” workspaces, usage, credits, notifications from API routes/jobs | [Server-Side Usage](#server-side-usage) |
89
+ | Agent discovery surface | `createAgentStack` / `resolveAgentPath`: robots.txt, llms.txt, `.well-known/*`, all documents overridable (e.g. `config.llmsTxt`) | [Agent Readiness](#agent-readiness-discovery) ยท `docs/MCP-AND-AGENT-READINESS.md` |
90
+ | MCP tools | `builtinTools` (`'readonly'`/`'all'`/`false`/include/exclude) + your own via `defineMcpTool` (custom tools override built-ins) | [MCP Server](#mcp-server-buildbasesdkmcp) |
91
+ | MCP resources & prompts | Opt-in `builtinResources` catalog + `defineMcpResource`/`defineMcpResourceTemplate`/`defineMcpPrompt` | [MCP Server](#mcp-server-buildbasesdkmcp) |
92
+ | MCP auth & hardening | `auth.verify` (your token format) or `buildbaseAuth` preset; `rateLimit`, `cors`, `allowedOrigins`, `formatToolError` | `docs/MCP-AND-AGENT-READINESS.md` |
93
+ | Per-request context for your MCP tools | `context(auth, req)` factory โ†’ `ctx.custom` (your DB, services) | [MCP Server](#mcp-server-buildbasesdkmcp) |
94
+ | Money display | `formatMinorAmountIntl`/`formatCents`/`getCurrencyDecimals` โ€” full ISO 4217 (0/2/3-decimal currencies) | [Multi-Currency](#-multi-currency--pricing-utilities) |
95
+ | Webhooks from the platform | `verifyWebhookSignature` (HMAC, timing-safe) | [Webhook Verification](#webhook-verification) |
96
+
69
97
  ## Installation
70
98
 
71
99
  ```bash
@@ -87,6 +115,7 @@ import '@buildbase/sdk/css';
87
115
  // components/provider.tsx
88
116
  'use client';
89
117
 
118
+ // BuildBaseProvider is an identical brand-aligned alias โ€” prefer it in new code
90
119
  import { SaaSOSProvider } from '@buildbase/sdk/react';
91
120
  import { ApiVersion } from '@buildbase/sdk';
92
121
 
@@ -283,7 +312,7 @@ function MembersPanel() {
283
312
 
284
313
  `useUIConfig()` gives you the raw `ui` object if you only need the config values; `mergeUIConfig(base, override)` is the deep-merge used for per-dialog overrides.
285
314
 
286
- ๐Ÿ“– **Full guide with the complete toggle reference, precedence rules, and recipes (single-tenant, external billing, white-label, read-only): [docs/UI-CONFIG.md](./docs/UI-CONFIG.md)**
315
+ ๐Ÿ“– **Full guide with the complete toggle reference, precedence rules, and recipes (single-tenant, external billing, white-label, read-only): [docs/UI-CONFIG.md](https://unpkg.com/@buildbase/sdk/docs/UI-CONFIG.md)**
287
316
 
288
317
  ## ๐Ÿ” Authentication
289
318
 
@@ -346,9 +375,16 @@ openWorkspaceSettings('users'); // Workspace members
346
375
  openWorkspaceSettings('subscription'); // Plan & Billing
347
376
  openWorkspaceSettings('usage'); // Quota usage dashboard
348
377
  openWorkspaceSettings('features'); // Feature toggles
378
+ openWorkspaceSettings('connected-agents'); // Connected AI agents + connect guide
349
379
  openWorkspaceSettings('danger'); // Delete workspace (owner only)
350
380
  ```
351
381
 
382
+ Some sections accept an optional second `action` argument to deep-link past the screen. For connected agents, open the setup guide directly:
383
+
384
+ ```tsx
385
+ openWorkspaceSettings('connected-agents', { action: 'openConnectGuide' });
386
+ ```
387
+
352
388
  ### Authentication Components
353
389
 
354
390
  For declarative rendering, use the conditional components:
@@ -504,7 +540,9 @@ Use the `useUserFeatures` hook to check feature flags programmatically:
504
540
  import { useUserFeatures } from '@buildbase/sdk/react';
505
541
 
506
542
  function FeatureCheck() {
507
- const { features, isFeatureEnabled, refreshFeatures } = useUserFeatures();
543
+ // { features, isFeatureEnabled, loading, error, refetch }
544
+ // (the older `isLoading` / `refreshFeatures` names still work but are deprecated)
545
+ const { features, isFeatureEnabled, refetch } = useUserFeatures();
508
546
 
509
547
  return (
510
548
  <div>{isFeatureEnabled('premium-features') ? <PremiumContent /> : <StandardContent />}</div>
@@ -1074,6 +1112,57 @@ Platform mode supports granular overrides from the admin dashboard:
1074
1112
 
1075
1113
  These let you achieve team-like, managed, or enterprise-like behavior without a separate mode.
1076
1114
 
1115
+ ## ๐Ÿ”Œ Connected Agents
1116
+
1117
+ Let users connect AI agents to their account and manage them. `<ConnectedAgents />` is a ready-made screen (also a workspace settings section) that lists the agents a user has authorized โ€” each with a **Disconnect** action โ€” and, when you provide an MCP server address, shows a **Connect an agent** button that opens a plain-language setup guide.
1118
+
1119
+ ### Enable the connect guide
1120
+
1121
+ Pass an `mcp` config to the provider. Without it the screen still lists and revokes agents; with it, the "Connect an agent" button and setup dialog appear.
1122
+
1123
+ ```tsx
1124
+ <SaaSOSProvider
1125
+ // ...serverUrl, orgId, auth
1126
+ mcp={{
1127
+ url: 'https://app.example.com/api/mcp', // your MCP server endpoint (required to show the guide)
1128
+ name: 'Acme', // friendly name used in prose + config snippets
1129
+ docsUrl: 'https://docs.example.com/agents', // optional "Learn more" link
1130
+ }}
1131
+ >
1132
+ ```
1133
+
1134
+ The dialog walks users through the major AI apps โ€” **ChatGPT, Claude, Cursor, VS Code, Windsurf, Cline** โ€” each with the exact click-path or config-file snippet (your server URL is filled in for them), plus a copy-and-paste prompt for chat assistants. It's fully translated (all 8 locales), RTL-aware, and responsive (full-screen on mobile, centered card on desktop).
1135
+
1136
+ ### The screen
1137
+
1138
+ ```tsx
1139
+ import { ConnectedAgents } from '@buildbase/sdk/react';
1140
+
1141
+ function AgentsPage() {
1142
+ return <ConnectedAgents />;
1143
+ }
1144
+ ```
1145
+
1146
+ Props: `title`, `description`, `disconnectLabel`, `emptyLabel` (all default to translated strings; pass `null` to hide the heading) and `showConnectGuide` (default `true` โ€” set `false` to hide the connect button even when `mcp` is configured).
1147
+
1148
+ Because it's a settings section, you can also open it programmatically:
1149
+
1150
+ ```tsx
1151
+ const { openWorkspaceSettings } = useSaaSAuth();
1152
+
1153
+ openWorkspaceSettings('connected-agents'); // the screen (list + connect button)
1154
+ openWorkspaceSettings('connected-agents', { action: 'openConnectGuide' }); // straight to the setup dialog
1155
+ ```
1156
+
1157
+ The same deep link works via URL: `?bb=action:openConnectGuide`.
1158
+
1159
+ ### Custom UI
1160
+
1161
+ - **`useConnectedAgents()`** โ€” headless `{ agents, loading, error, revoking, refresh, revoke }` for a fully custom list.
1162
+ - **`useMcpConnection()`** โ€” the `mcp` config you passed (or `null`), for building your own guide.
1163
+ - **`<ConnectMcpGuide />`** โ€” the guide body on its own (copyable server URL + paste-in prompt + per-client accordion), embeddable anywhere. Override the app list via `mcp.clients` and the prompt via `mcp.prompt` (`false` hides it).
1164
+ - **`fillMcpTemplate` / `mcpServerKey`** โ€” the placeholder helpers (`{{url}}` / `{{name}}` / `{{key}}`) for building custom client snippets.
1165
+
1077
1166
  ## ๐Ÿ‘ค User Management
1078
1167
 
1079
1168
  ### User Attributes
@@ -1084,8 +1173,9 @@ Manage custom user attributes (key-value pairs):
1084
1173
  import { useUserAttributes } from '@buildbase/sdk/react';
1085
1174
 
1086
1175
  function UserProfile() {
1087
- const { attributes, isLoading, updateAttribute, updateAttributes, refreshAttributes } =
1088
- useUserAttributes();
1176
+ // { attributes, loading, error, refetch, updateAttribute, updateAttributes }
1177
+ // (the older `isLoading` / `refreshAttributes` names still work but are deprecated)
1178
+ const { attributes, loading, updateAttribute, updateAttributes, refetch } = useUserAttributes();
1089
1179
 
1090
1180
  const handleUpdate = async () => {
1091
1181
  // Update single attribute
@@ -1245,19 +1335,23 @@ Plans support **pricing variants** (multi-currency). Use these utilities for dis
1245
1335
 
1246
1336
  ### Currency utilities
1247
1337
 
1248
- | Export | Purpose |
1249
- | ------------------------------------ | --------------------------------------------------------- |
1250
- | `CURRENCY_DISPLAY` | Map of currency code โ†’ symbol (e.g. `usd` โ†’ `$`) |
1251
- | `CURRENCY_FLAG` | Map of currency code โ†’ flag emoji |
1252
- | `PLAN_CURRENCY_CODES` | Allowed billing currency codes (for dropdowns/validation) |
1253
- | `PLAN_CURRENCY_OPTIONS` | Options array for plan currency selects |
1254
- | `getCurrencySymbol(currency)` | Symbol for a Stripe currency code |
1255
- | `getCurrencyFlag(currency)` | Flag emoji for a currency code |
1256
- | `formatCents(cents, currency)` | Format cents as localized price string |
1257
- | `formatOverageRate(cents, currency)` | Format overage rate for display |
1258
- | `formatOverageRateWithLabel(...)` | Overage rate with optional unit label |
1259
- | `formatQuotaIncludedOverage(...)` | "X included, then $Y / unit" style text |
1260
- | `getQuotaUnitLabelFromName(name)` | Human-readable unit label from quota name |
1338
+ | Export | Purpose |
1339
+ | -------------------------------------------------- | --------------------------------------------------------------- |
1340
+ | `CURRENCY_DISPLAY` | Map of currency code โ†’ symbol (e.g. `usd` โ†’ `$`) |
1341
+ | `CURRENCY_FLAG` | Map of currency code โ†’ flag emoji |
1342
+ | `PLAN_CURRENCY_CODES` | Allowed billing currency codes (for dropdowns/validation) |
1343
+ | `PLAN_CURRENCY_OPTIONS` | Options array for plan currency selects |
1344
+ | `getCurrencySymbol(currency)` | Symbol for a Stripe currency code |
1345
+ | `getCurrencyFlag(currency)` | Flag emoji for a currency code |
1346
+ | `formatCents(cents, currency)` | Format a minor-unit amount with the symbol table |
1347
+ | `formatMinorAmountIntl(amount, currency, locale?)` | Locale-aware `Intl` money formatting of minor units |
1348
+ | `getCurrencyDecimals(currency)` | ISO 4217 minor-unit digits (0 JPY, 2 USD, 3 KWD; CLDR fallback) |
1349
+ | `isZeroDecimalCurrency(currency)` | True when the currency has no minor unit (JPY, KRW, โ€ฆ) |
1350
+ | `minorAmountToDisplay(amount, currency)` | Minor units โ†’ display number string (no symbol) |
1351
+ | `formatOverageRate(cents, currency)` | Format overage rate for display |
1352
+ | `formatOverageRateWithLabel(...)` | Overage rate with optional unit label |
1353
+ | `formatQuotaIncludedOverage(...)` | "X included, then $Y / unit" style text |
1354
+ | `getQuotaUnitLabelFromName(name)` | Human-readable unit label from quota name |
1261
1355
 
1262
1356
  ### Pricing variant utilities
1263
1357
 
@@ -1297,7 +1391,9 @@ import {
1297
1391
  const variant = getPricingVariant(planVersion, 'usd');
1298
1392
  const cents = getBasePriceCents(planVersion, 'usd', 'monthly');
1299
1393
  if (cents != null) {
1300
- console.log(getCurrencySymbol('usd') + (cents / 100).toFixed(2));
1394
+ // Never divide by 100 yourself โ€” formatCents applies the currency's ISO 4217
1395
+ // minor-unit factor (JPY ยฅ1,000 stays whole, KWD divides by 1000, USD by 100).
1396
+ console.log(formatCents(cents, 'usd')); // "$12.99"
1301
1397
  }
1302
1398
 
1303
1399
  // Quota display with overage
@@ -2067,7 +2163,7 @@ import { eventEmitter } from '@buildbase/sdk';
2067
2163
 
2068
2164
  ## ๐Ÿ›ก๏ธ Error Handling
2069
2165
 
2070
- The SDK handles errors internally: API failures, auth errors, and component errors are logged and surfaced through hook states (e.g. `error` from `useSaaSWorkspaces`) and callbacks. **SaaSOSProvider** wraps its children in an internal **SDKErrorBoundary** to catch React render errors inside the SDK tree. For app-level errors, wrap your app (or routes) in your own error boundary (e.g. Reactโ€™s `ErrorBoundary` or your frameworkโ€™s error UI). For failed async operations, check the `error` property on hooks and show user feedback (e.g. toast or inline message). See [Error codes](docs/ERROR_CODES.md) for SDK error codes and HTTP mappings.
2166
+ The SDK handles errors internally: API failures, auth errors, and component errors are logged and surfaced through hook states (e.g. `error` from `useSaaSWorkspaces`) and callbacks. **SaaSOSProvider** wraps its children in an internal **SDKErrorBoundary** to catch React render errors inside the SDK tree. For app-level errors, wrap your app (or routes) in your own error boundary (e.g. Reactโ€™s `ErrorBoundary` or your frameworkโ€™s error UI). For failed async operations, check the `error` property on hooks and show user feedback (e.g. toast or inline message). See [Error codes](https://unpkg.com/@buildbase/sdk/docs/ERROR_CODES.md) for SDK error codes and HTTP mappings.
2071
2167
 
2072
2168
  ## โš™๏ธ Settings
2073
2169
 
@@ -2077,7 +2173,11 @@ Access OS-level settings:
2077
2173
  import { useSaaSSettings } from '@buildbase/sdk/react';
2078
2174
 
2079
2175
  function SettingsExample() {
2080
- const { settings, getSettings } = useSaaSSettings();
2176
+ // { settings, loading, error, refetch } โ€” `loading` is true until the one-time
2177
+ // fetch settles, so you can wait instead of rendering with partial defaults.
2178
+ const { settings, loading, refetch } = useSaaSSettings();
2179
+
2180
+ if (loading) return <Spinner />;
2081
2181
 
2082
2182
  return (
2083
2183
  <div>
@@ -2155,9 +2255,11 @@ Prefer these SDK hooks for state and operations instead of `useAppSelector`:
2155
2255
  | `useSaaSAuth()` | Auth state (user, session, status), signIn(returnUrl?), signOut, openWorkspaceSettings |
2156
2256
  | `useSaaSWorkspaces()` | Workspaces, currentWorkspace, loading, switching/switchingToId, CRUD and switch actions |
2157
2257
  | `useSaaSOs()` | OS config (serverUrl, version, orgId, auth, settings) when you need the full config object |
2158
- | `useSaaSSettings()` | Organization settings and getSettings (prefer this when you only need settings) |
2159
- | `useUserAttributes()` | User attributes and update/refresh |
2160
- | `useUserFeatures()` | User feature flags |
2258
+ | `useSaaSSettings()` | Organization settings โ€” `{ settings, loading, error, refetch }` (prefer this when you only need settings) |
2259
+ | `useUserAttributes()` | User attributes โ€” `{ attributes, loading, error, refetch, updateAttribute, updateAttributes }` |
2260
+ | `useUserFeatures()` | User feature flags โ€” `{ features, isFeatureEnabled, loading, error, refetch }` |
2261
+ | `useConnectedAgents()` | Authorized AI agents โ€” `{ agents, loading, error, revoking, refresh, revoke }` |
2262
+ | `useMcpConnection()` | The `mcp` connection config passed to the provider (or `null`), for a custom connect guide |
2161
2263
  | `useSubscriptionContext()` | Subscription for current workspace (response, loading, refetch); use inside SubscriptionContextProvider |
2162
2264
  | `useTrialStatus()` | Trial state: `isTrialing`, `daysRemaining`, `trialEndsAt`, `isTrialEnding` |
2163
2265
  | `usePushNotifications()` | Push notification state and actions: `isSubscribed`, `subscribe()`, `unsubscribe()` |
@@ -2177,12 +2279,12 @@ Using hooks keeps your code stable if internal state shape changes and avoids di
2177
2279
 
2178
2280
  ### Types
2179
2281
 
2180
- All TypeScript types are exported for type safety. See the [TypeScript definitions](./dist/index.d.ts) for complete type information.
2282
+ All TypeScript types are exported for type safety. See the [TypeScript definitions](https://unpkg.com/@buildbase/sdk/dist/index.d.ts) for complete type information.
2181
2283
 
2182
2284
  ### Further documentation
2183
2285
 
2184
- - [Architecture](docs/ARCHITECTURE.md) โ€“ Layers, providers, APIs (BaseApi, UserApi, WorkspaceApi, SettingsApi), state, auth flow
2185
- - [Error codes](docs/ERROR_CODES.md) โ€“ SDK error codes and HTTP status mappings
2286
+ - [Architecture](https://unpkg.com/@buildbase/sdk/docs/ARCHITECTURE.md) โ€“ Layers, providers, APIs (BaseApi, UserApi, WorkspaceApi, SettingsApi), state, auth flow
2287
+ - [Error codes](https://unpkg.com/@buildbase/sdk/docs/ERROR_CODES.md) โ€“ SDK error codes and HTTP status mappings
2186
2288
 
2187
2289
  ## โš™๏ธ Configuration Reference
2188
2290
 
@@ -2935,11 +3037,11 @@ app.post('/webhooks/buildbase', (req, res) => {
2935
3037
 
2936
3038
  ## Agent Readiness (Discovery)
2937
3039
 
2938
- > **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](docs/MCP-AND-AGENT-READINESS.md) covers the whole surface โ€” the fast path, the auth model, and the scope/resource customization spectrum. This section is the overview.
3040
+ > **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md) covers the whole surface โ€” the fast path, the auth model, and the scope/resource customization spectrum. This section is the overview.
2939
3041
 
2940
3042
  Make a consuming app [agent ready](https://isitagentready.com) by serving the machine-readable discovery documents an AI client looks for โ€” Agent Card, A2A card, OAuth metadata (RFC 8414/9728), Agent Skills, API Catalog (RFC 9727), MCP Server Card (SEP-1649 v1.0) + discovery manifest (SEP-1960), `robots.txt` with AI-bot rules + Content Signals, `sitemap.xml`, `security.txt`, `llms.txt`/`llms-full.txt`, and `auth.md`. Framework-agnostic and zero React: every function returns a plain `DiscoveryDocument` (`{ status, contentType, body, cacheControl, vary? }`).
2941
3043
 
2942
- The fast path is [`createAgentStack`](docs/MCP-AND-AGENT-READINESS.md#fast-path--createagentstack) โ€” one config derives the MCP handler **and** the whole discovery surface. To wire the discovery layer on its own, use `resolveAgentPath`:
3044
+ The fast path is [`createAgentStack`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#fast-path--createagentstack) โ€” one config derives the MCP handler **and** the whole discovery surface. To wire the discovery layer on its own, use `resolveAgentPath`:
2943
3045
 
2944
3046
  ```ts
2945
3047
  // lib/agent-ready.ts
@@ -2948,17 +3050,17 @@ import { resolveAgentPath, type AgentReadyConfig } from '@buildbase/sdk';
2948
3050
  export const agentConfig: AgentReadyConfig = {
2949
3051
  serverUrl: process.env.BUILDBASE_URL!,
2950
3052
  orgId: process.env.BUILDBASE_ORG_ID!,
2951
- siteUrl: 'https://imejis.io',
2952
- site: { name: 'Imejis', description: 'Generate images from templates via API.' },
3053
+ siteUrl: 'https://example.com',
3054
+ site: { name: 'Acme', description: 'Generate images from templates via API.' },
2953
3055
  // Discovery content is YOURS โ€” defined here in code, not in the platform:
2954
3056
  scopes: [
2955
3057
  { name: 'designs:read', description: 'View designs' },
2956
3058
  { name: 'render:execute', description: 'Render images' },
2957
3059
  ],
2958
- llmsTxt: '# Imejis\n\n> Generate images from templates via API.',
3060
+ llmsTxt: '# Acme\n\n> Generate images from templates via API.',
2959
3061
  robots: { contentSignals: { search: true, aiInput: true, aiTrain: false } },
2960
3062
  sitemap: { urls: ['/', '/pricing'] }, // omit if you already generate sitemaps
2961
- protectedResources: [{ resource: 'https://imejis.io/mcp' }], // scopes inherited from catalog
3063
+ protectedResources: [{ resource: 'https://example.com/mcp' }], // scopes inherited from catalog
2962
3064
  // skills, security, apiCatalog, mcpServerCard, a2aCard, extraPaths โ€” all optional
2963
3065
  };
2964
3066
 
@@ -3049,9 +3151,9 @@ Clean split, no duplication: **your app owns discovery content, the platform own
3049
3151
 
3050
3152
  ## MCP Server (`@buildbase/sdk/mcp`)
3051
3153
 
3052
- > **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](docs/MCP-AND-AGENT-READINESS.md).
3154
+ > **Full guide:** [`docs/MCP-AND-AGENT-READINESS.md`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md).
3053
3155
 
3054
- Turn your app into a **live MCP server** so AI agents can operate it: the built-in tools expose your BuildBase state (workspaces, subscription, quotas, credits, feature flags, permissions) and you add your own product tools with zod schemas. Stateless Streamable HTTP (MCP 2025-06-18) โ€” pure functions plus a Web-standard `Request`/`Response` adapter, so it runs on Node 18+, edge, Deno, and Bun. Server-only, zero React; split from the core entry because it uses `zod` at runtime.
3156
+ Turn your app into a **live MCP server** so AI agents can operate it: the built-in tools expose your BuildBase state (workspaces, subscription, quotas, credits, feature flags, permissions) and you add your own product tools with zod schemas โ€” plus **resources** (context a host loads without tool calls) and **prompts** (user-facing workflow templates). Stateless Streamable HTTP (MCP 2025-11-25, negotiating down to 2024-11-05) โ€” pure functions plus a Web-standard `Request`/`Response` adapter, so it runs on Node 18+, edge, Deno, and Bun. Server-only, zero React; split from the core entry because it uses `zod` at runtime.
3055
3157
 
3056
3158
  The fast path bundles the server + the whole discovery surface from one config:
3057
3159
 
@@ -3063,8 +3165,8 @@ import { z } from 'zod';
3063
3165
  export const agent = createAgentStack({
3064
3166
  serverUrl: process.env.NEXT_PUBLIC_BUILDBASE_SERVER_URL!,
3065
3167
  orgId: process.env.NEXT_PUBLIC_BUILDBASE_ORG_ID!,
3066
- siteUrl: 'https://imejis.io',
3067
- site: { name: 'Imejis', description: 'Generate images from templates via API.' },
3168
+ siteUrl: 'https://example.com',
3169
+ site: { name: 'Acme', description: 'Generate images from templates via API.' },
3068
3170
  secret: process.env.SYSTEM_SECRET!, // derives buildbaseAuth (verify + aud + sid decrypt)
3069
3171
  scopes: [{ name: 'render:execute', description: 'Render images' }],
3070
3172
  mcp: {
@@ -3102,10 +3204,10 @@ const buildbase = BuildBase({
3102
3204
 
3103
3205
  export const mcp = createMcpHandler({
3104
3206
  buildbase,
3105
- serverInfo: { name: 'imejis', version: '1.0.0' },
3207
+ serverInfo: { name: 'acme', version: '1.0.0' },
3106
3208
  auth: buildbaseAuth({
3107
3209
  secret: process.env.SYSTEM_SECRET!,
3108
- resource: ['https://imejis.io/mcp', 'https://imejis.io/api/mcp'],
3210
+ resource: ['https://example.com/mcp', 'https://example.com/api/mcp'],
3109
3211
  requireAudience: true,
3110
3212
  }),
3111
3213
  builtinTools: 'readonly',
@@ -3123,14 +3225,14 @@ app.post('/mcp', async (req, res) => {
3123
3225
  });
3124
3226
  ```
3125
3227
 
3126
- > **Copy-paste recipes for every framework** โ€” Next.js (App + Pages Router), Express, Fastify, Hono, Bun, Deno, Cloudflare Workers, and React/SPA (WebMCP) โ€” plus the per-framework mint route and a production checklist: [`docs/MCP-AND-AGENT-READINESS.md`](docs/MCP-AND-AGENT-READINESS.md#framework-recipes). Two adapters cover them all: `mcp.fetch(Request)` (web standard โ€” App Router, Hono, Bun, Deno, edge) and `mcp.handle({method,headers,body})` (pure โ€” Express, Fastify, Pages Router).
3228
+ > **Copy-paste recipes for every framework** โ€” Next.js (App + Pages Router), Express, Fastify, Hono, Bun, Deno, Cloudflare Workers, and React/SPA (WebMCP) โ€” plus the per-framework mint route and a production checklist: [`docs/MCP-AND-AGENT-READINESS.md`](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#framework-recipes). Two adapters cover them all: `mcp.fetch(Request)` (web standard โ€” App Router, Hono, Bun, Deno, edge) and `mcp.handle({method,headers,body})` (pure โ€” Express, Fastify, Pages Router).
3127
3229
 
3128
3230
  Advertise it via the server card so agents find the endpoint (the stack sets this automatically):
3129
3231
 
3130
3232
  ```ts
3131
3233
  export const agentConfig: AgentReadyConfig = {
3132
3234
  // ...
3133
- mcpServerCard: mcp.serverCard({ endpoint: 'https://imejis.io/api/mcp' }),
3235
+ mcpServerCard: mcp.serverCard({ endpoint: 'https://example.com/api/mcp' }),
3134
3236
  };
3135
3237
  ```
3136
3238
 
@@ -3159,6 +3261,62 @@ The agent acts as an authenticated app user โ€” it knows your app, not BuildBase
3159
3261
 
3160
3262
  Want per-scope gating on top? Set `requiredScopes` on your own custom tools and return the granted `scopes` from `auth.verify` โ€” the handler hides a tool from `tools/list` (and refuses the call) when its `requiredScopes` aren't all granted. A token that carries **no** scopes sees only tools that require none (the built-ins), so a token minted without a `scope` claim can never unlock a scoped tool. Opt-in, using **your** scope names โ€” the SDK never imposes its own.
3161
3263
 
3264
+ ### Rich tool results (images, links, mixed content)
3265
+
3266
+ Return any JSON-serializable value and the handler wraps it (string โ†’ text block; object โ†’ JSON text + `structuredContent`). For full control โ€” images, audio, resource links, mixed blocks, or the `isError` flag โ€” return a wire-shaped `McpToolResult` built with the exported helpers:
3267
+
3268
+ ```ts
3269
+ import { mcpImage, mcpResourceLink, mcpText } from '@buildbase/sdk/mcp';
3270
+
3271
+ execute: async (input, ctx) => ({
3272
+ content: [
3273
+ mcpText('Revenue chart for Q2:'),
3274
+ mcpImage(chartPngBase64, 'image/png'),
3275
+ mcpResourceLink('https://app.example.com/reports/q2.pdf', 'q2-report'),
3276
+ ],
3277
+ structuredContent: { totalCents: 1_299_00, currency: 'usd' },
3278
+ });
3279
+ ```
3280
+
3281
+ ### Resources & prompts
3282
+
3283
+ Both are **opt-in**, and `initialize` capabilities only advertise what you actually configured โ€” existing servers are byte-identical until you opt in.
3284
+
3285
+ ```ts
3286
+ createMcpHandler({
3287
+ buildbase,
3288
+ // Lean built-in context catalog: buildbase://profile, buildbase://workspaces,
3289
+ // buildbase://workspace/{workspaceId}. Richer data stays tools-only.
3290
+ builtinResources: true,
3291
+ resources: [
3292
+ defineMcpResource({
3293
+ uri: 'app://docs/getting-started',
3294
+ name: 'getting-started',
3295
+ mimeType: 'text/markdown',
3296
+ read: () => gettingStartedMarkdown, // string | object (JSON) | { text } | { blob }
3297
+ }),
3298
+ ],
3299
+ resourceTemplates: [
3300
+ defineMcpResourceTemplate({
3301
+ uriTemplate: 'app://orders/{orderId}',
3302
+ name: 'order',
3303
+ read: (params, _uri, ctx) => ctx.custom.db.order.find(params.orderId),
3304
+ }),
3305
+ ],
3306
+ prompts: [
3307
+ defineMcpPrompt({
3308
+ name: 'analyze_usage',
3309
+ description: 'Review quota usage and suggest actions',
3310
+ arguments: [{ name: 'workspaceId', required: true }],
3311
+ get: async (args, ctx) =>
3312
+ `Review this workspace's quota usage:\n${JSON.stringify(await ctx.bb.usage.getAll(args.workspaceId))}`,
3313
+ }),
3314
+ ],
3315
+ });
3316
+ ```
3317
+
3318
+ `requiredScopes` gates resources and prompts exactly like tools. Deliberately out of scope (the stateless transport has no push channel): resource subscriptions, `listChanged`, sampling, elicitation.
3319
+
3162
3320
  ### Production hardening
3163
3321
 
3164
3322
  The handler ships with safe defaults; these are the knobs to review before going live:
@@ -3175,7 +3333,7 @@ export const mcp = createMcpHandler({
3175
3333
  buildbase,
3176
3334
  auth: { verify, resourceMetadataUrl },
3177
3335
  builtinTools: { include: ['get_quota_usage', 'record_usage'] },
3178
- allowedOrigins: ['https://app.imejis.io'],
3336
+ allowedOrigins: ['https://app.example.com'],
3179
3337
  maxRequestBytes: 512 * 1024,
3180
3338
  rateLimit: async auth => ({ ok: await limiter.allow(auth?.userId), retryAfter: 30 }),
3181
3339
  onError: (err, ctx) => logger.error({ err, ...ctx }, 'mcp error'),
@@ -3223,7 +3381,7 @@ mintToken: (claims) => mintAgentToken({ claims, secret: process.env.SYSTEM_SECRE
3223
3381
 
3224
3382
  // verify (MCP server) โ€” HS256 + RFC 8707 audience + sid decrypt โ†’ McpAuthInfo
3225
3383
  import { buildbaseAuth } from '@buildbase/sdk/mcp';
3226
- auth: buildbaseAuth({ secret: process.env.SYSTEM_SECRET!, resource: 'https://imejis.io/mcp' }),
3384
+ auth: buildbaseAuth({ secret: process.env.SYSTEM_SECRET!, resource: 'https://example.com/mcp' }),
3227
3385
  ```
3228
3386
 
3229
3387
  Bringing your own token format? `auth.verify(token, req) โ†’ McpAuthInfo` accepts any Bearer token; set `auth.resourceMetadataUrl` so 401s carry the RFC 9728 challenge. Set `auth: false` to disable auth (local dev only). Debug audience mismatches with `MCP_AUTH_DEBUG=1`. Test with the MCP Inspector: `npx @modelcontextprotocol/inspector --cli http://localhost:3000/api/mcp --transport http --header "Authorization: Bearer <token>" --method tools/list`.
@@ -3232,7 +3390,7 @@ Bringing your own token format? `auth.verify(token, req) โ†’ McpAuthInfo` accept
3232
3390
 
3233
3391
  ### Scopes & resources โ€” restrict or open up
3234
3392
 
3235
- Scopes and resources are **app-owned** โ€” the shared BuildBase authorization server stays scope/resource-agnostic. Scopes have three levers: **declare** a catalog (`scopes: [{ name, description }]` โ†’ `scopes_supported` in your own RFC 9728 protected-resource metadata), **gate per tool** (`requiredScopes` on a custom tool โ†’ hidden/refused unless the token carries them), and the **floor** (every tool runs under the user's BuildBase session, so the platform enforces the user's real permissions โ€” an agent never exceeds the user). Resources have two: **declare** `protectedResources` (RFC 9728) and **bind** the token audience via `buildbaseAuth({ resource, requireAudience })` (RFC 8707) โ€” the audience check at your resource is the whole gate. Built-ins are restricted with `builtinTools`, not scopes. Public clients (Claude Desktop, Cursor, Inspector) self-register with PKCE and no secret. Full model: [the guide](docs/MCP-AND-AGENT-READINESS.md#scopes--resources-restrict-or-open-up).
3393
+ Scopes and resources are **app-owned** โ€” the shared BuildBase authorization server stays scope/resource-agnostic. Scopes have three levers: **declare** a catalog (`scopes: [{ name, description }]` โ†’ `scopes_supported` in your own RFC 9728 protected-resource metadata), **gate per tool** (`requiredScopes` on a custom tool โ†’ hidden/refused unless the token carries them), and the **floor** (every tool runs under the user's BuildBase session, so the platform enforces the user's real permissions โ€” an agent never exceeds the user). Resources have two: **declare** `protectedResources` (RFC 9728) and **bind** the token audience via `buildbaseAuth({ resource, requireAudience })` (RFC 8707) โ€” the audience check at your resource is the whole gate. Built-ins are restricted with `builtinTools`, not scopes. Public clients (Claude Desktop, Cursor, Inspector) self-register with PKCE and no secret. Full model: [the guide](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#scopes--resources-restrict-or-open-up).
3236
3394
 
3237
3395
  ## OAuth2 App Bridge
3238
3396
 
@@ -3243,7 +3401,7 @@ BuildBase runs the full OAuth2 authorization flow (login, consent, code, PKCE, r
3243
3401
 
3244
3402
  Both requests carry `Authorization: Bearer <JWT>`, an HS256 JWT signed with your client secret. This toolkit verifies those requests (timing-safe, no `alg` confusion) and shapes the exact response body the platform expects, so you write only the part that's yours: minting/invalidating a token in your own format.
3245
3403
 
3246
- > For the common case, `mintToken: (claims) => mintAgentToken({ claims, secret })` is the preset โ€” it signs HS256 with your secret, binds `aud` to the granted RFC 8707 resource, and embeds the encrypted `sid`. The examples below show the hand-rolled equivalent, for apps that mint their own token format (e.g. one shared with their web sessions). See [the guide](docs/MCP-AND-AGENT-READINESS.md#auth-minting--verifying-the-token).
3404
+ > For the common case, `mintToken: (claims) => mintAgentToken({ claims, secret })` is the preset โ€” it signs HS256 with your secret, binds `aud` to the granted RFC 8707 resource, and embeds the encrypted `sid`. The examples below show the hand-rolled equivalent, for apps that mint their own token format (e.g. one shared with their web sessions). See [the guide](https://unpkg.com/@buildbase/sdk/docs/MCP-AND-AGENT-READINESS.md#auth-minting--verifying-the-token).
3247
3405
 
3248
3406
  ```ts
3249
3407
  // applicationTokenUrl handler (Next.js Pages Router)
@@ -3284,7 +3442,7 @@ When an agent calls your protected API without a valid token, reply with an RFC
3284
3442
  import { bearerChallenge } from '@buildbase/sdk';
3285
3443
 
3286
3444
  const c = bearerChallenge({
3287
- resourceMetadataUrl: 'https://imejis.io/.well-known/oauth-protected-resource',
3445
+ resourceMetadataUrl: 'https://example.com/.well-known/oauth-protected-resource',
3288
3446
  error: 'invalid_token',
3289
3447
  });
3290
3448
  res.writeHead(c.status, c.headers).end(c.body);