From 5d8d185e5761248390a60c9f3a31683ab1e39aa1 Mon Sep 17 00:00:00 2001 From: yash-pouranik Date: Sat, 11 Apr 2026 15:40:11 +0530 Subject: [PATCH 1/7] sdk docs live --- mintlify/docs/docs.json | 4 +- mintlify/docs/sdk/auth.mdx | 167 ++++++++++++++++++--------------- mintlify/docs/sdk/database.mdx | 136 +++++++++------------------ mintlify/docs/sdk/mail.mdx | 49 ++++++++++ mintlify/docs/sdk/overview.mdx | 45 +++++---- mintlify/docs/sdk/schema.mdx | 42 +++++++++ mintlify/docs/sdk/storage.mdx | 64 ++----------- 7 files changed, 267 insertions(+), 240 deletions(-) create mode 100644 mintlify/docs/sdk/mail.mdx create mode 100644 mintlify/docs/sdk/schema.mdx diff --git a/mintlify/docs/docs.json b/mintlify/docs/docs.json index e4b85211..624bdc2f 100644 --- a/mintlify/docs/docs.json +++ b/mintlify/docs/docs.json @@ -54,7 +54,9 @@ "sdk/overview", "sdk/auth", "sdk/database", - "sdk/storage" + "sdk/storage", + "sdk/schema", + "sdk/mail" ] }, { diff --git a/mintlify/docs/sdk/auth.mdx b/mintlify/docs/sdk/auth.mdx index 67ccad5f..ae11f139 100644 --- a/mintlify/docs/sdk/auth.mdx +++ b/mintlify/docs/sdk/auth.mdx @@ -1,10 +1,10 @@ --- title: "Auth" -description: "Create accounts, log in users, and retrieve the current session with the SDK auth module." -keywords: ["auth", "authentication", "login", "signup", "sdk"] +description: "Manage user accounts, sessions, and social authentication with the SDK auth module." +keywords: ["auth", "authentication", "login", "signup", "sdk", "social auth", "oauth"] --- -Access auth methods via `client.auth`. The module stores the session token from `login()` automatically, so you do not need to thread it through subsequent calls manually. +Access auth methods via `client.auth`. The module automatically stores the `accessToken` from `login()` or `refreshToken()` and uses it for subsequent authenticated requests like `me()` or `updateProfile()`. ## signUp @@ -14,150 +14,167 @@ Create a new user account. signUp(payload: SignUpPayload): Promise ``` -**Parameters** - -| Name | Type | Required | Description | -|---|---|---|---| -| `email` | `string` | Yes | User's email address. | -| `password` | `string` | Yes | User's password. | -| `name` | `string` | No | Display name. | - -**Returns** `AuthUser` - -```typescript -interface AuthUser { - _id: string; - email: string; - name?: string; - [key: string]: unknown; -} -``` - **Example** ```typescript const user = await client.auth.signUp({ email: 'alice@example.com', password: 'secret123', + username: 'alice_dev', name: 'Alice', }); - -console.log(user._id); // '507f1f77bcf86cd799439011' ``` --- ## login -Authenticate an existing user. The returned token is stored internally in the auth module and used automatically by `me()`. +Authenticate an existing user. The returned `accessToken` is stored internally. ```typescript login(payload: LoginPayload): Promise ``` -**Parameters** - -| Name | Type | Required | Description | -|---|---|---|---| -| `email` | `string` | Yes | User's email address. | -| `password` | `string` | Yes | User's password. | - **Returns** `AuthResponse` ```typescript interface AuthResponse { - token: string; // accessToken — store this securely + accessToken: string; + token: string; // Alias for accessToken (deprecated) user: AuthUser; + expiresIn: string; } ``` **Example** ```typescript -const { token, user } = await client.auth.login({ +const { accessToken, user } = await client.auth.login({ email: 'alice@example.com', password: 'secret123', }); - -console.log(token); // 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' -console.log(user.name); // 'Alice' ``` - -Store `token` securely — for example in `localStorage` or an HTTP-only cookie — and pass it to authenticated API calls. Never expose it in URLs or logs. - +--- + +## refreshToken + +Rotate the current access token. + +- **Browser**: Call without arguments. It will automatically use the `refreshToken` stored in your HTTP-only cookies. +- **Mobile/Node**: Pass the `refreshToken` string manually. + +```typescript +refreshToken(refreshToken?: string): Promise +``` --- ## me -Fetch the profile of the currently authenticated user. If you call `login()` first, you do not need to pass a token explicitly — the module uses the stored session token automatically. +Fetch the profile of the currently authenticated user. ```typescript me(token?: string): Promise ``` -**Parameters** - -| Name | Type | Required | Description | -|---|---|---|---| -| `token` | `string` | No | Override the stored session token. | +--- -**Returns** `AuthUser` +## updateProfile -**Example — using the stored token after login()** +Update the authenticated user's profile fields. ```typescript -await client.auth.login({ email: 'alice@example.com', password: 'secret123' }); - -const user = await client.auth.me(); -console.log(user.email); // 'alice@example.com' +updateProfile(payload: UpdateProfilePayload, token?: string): Promise<{ message: string }> ``` -**Example — passing a token directly** +**Example** ```typescript -const token = localStorage.getItem('urbackend_token'); -const user = await client.auth.me(token); +await client.auth.updateProfile({ name: 'Alice Smith' }); ``` - -Calling `me()` without a token and without a prior `login()` in the same client instance throws an `AuthError`. Always pass the token explicitly if the client is newly initialized (for example, on page reload). - +--- + +## changePassword + +Change the authenticated user's password. + +```typescript +changePassword(payload: ChangePasswordPayload, token?: string): Promise<{ message: string }> +``` --- -## logout +## Social Auth + +urBackend supports OAuth via GitHub and Google. + +### socialStart + +Returns the URL to initiate the OAuth flow. Redirect your user's browser to this URL. + +```typescript +socialStart(provider: 'github' | 'google'): string +``` -Clear the locally stored session token. This does not invalidate the token on the server. +### socialExchange + +Exchange the `rtCode` received at your callback URL for a session. ```typescript -logout(): void +socialExchange(payload: SocialExchangePayload): Promise ``` **Example** ```typescript -client.auth.logout(); -// The stored session token is cleared. -// Subsequent calls to me() will require a token to be passed explicitly. +// At your /auth/callback page +const urlParams = new URLSearchParams(window.location.search); +const rtCode = urlParams.get('rtCode'); +const token = new URLSearchParams(window.location.hash.slice(1)).get('token'); + +const { refreshToken } = await client.auth.socialExchange({ token, rtCode }); ``` --- -## Error handling +## Account Verification + +Methods for handling email OTP flows. + +| Method | Description | +|---|---| +| `verifyEmail(payload)` | Verify an account using the OTP sent to email. | +| `resendVerificationOtp(payload)` | Request a new verification OTP. | +| `requestPasswordReset(payload)` | Start the "forgot password" flow. | +| `resetPassword(payload)` | Complete password reset using an OTP. | + +--- + +## publicProfile + +Fetch a public-safe profile for any user by their username. This does not return sensitive fields like email or provider IDs. ```typescript -import urBackend, { AuthError } from '@urbackend/sdk'; +publicProfile(username: string): Promise +``` -const client = urBackend({ apiKey: process.env.URBACKEND_API_KEY }); +--- -try { - await client.auth.login({ email: 'alice@example.com', password: 'wrong' }); -} catch (e) { - if (e instanceof AuthError) { - console.error('Login failed:', e.message); - // e.statusCode is 401 or 403 - } -} +## logout + +Revokes the current session on the server and clears the local token. + +```typescript +logout(token?: string): Promise<{ success: boolean; message: string }> ``` + +--- + +## Manual Token Management + +If you need to manage tokens manually (e.g., after social auth), use these helper methods: + +- `getToken()`: Returns the current in-memory access token. +- `setToken(token)`: Manually set the access token for the client. diff --git a/mintlify/docs/sdk/database.mdx b/mintlify/docs/sdk/database.mdx index 75a09d78..e9774b7b 100644 --- a/mintlify/docs/sdk/database.mdx +++ b/mintlify/docs/sdk/database.mdx @@ -1,47 +1,51 @@ --- title: "Database" description: "Read, insert, update, and delete documents in any collection using the SDK database module." -keywords: ["database", "collections", "crud", "sdk", "typescript"] +keywords: ["database", "collections", "crud", "sdk", "typescript", "rls", "query builder"] --- -Access database methods via `client.db`. Collections must be created in the [urBackend Dashboard](https://urbackend.bitbros.in) before you can write to them. Once registered, you can optionally define a schema or write arbitrary JSON documents. +Access database methods via `client.db`. Collections must be created in the [urBackend Dashboard](https://urbackend.bitbros.in) before you can interact with them. -All methods accept a generic type parameter `T` (extending `DocumentData`) so the returned documents are typed: +All methods accept a generic type parameter `T` (extending `DocumentData`) so the returned documents are fully typed. +## Row-Level Security (RLS) + +If a collection has RLS enabled, you must provide the user's `accessToken` to perform write operations (`insert`, `update`, `patch`, `delete`). + +Example pattern: ```typescript -interface DocumentData { - _id: string; - [key: string]: unknown; -} +const { accessToken } = await client.auth.login({ ... }); +await client.db.insert('posts', { content: 'Hello' }, accessToken); ``` - -Use a `pk_live_...` (publishable) key for read operations in frontend code. Use a `sk_live_...` (secret) key for writes in server-side code only. - - --- ## getAll -Fetch all documents from a collection. +Fetch documents from a collection with optional filtering, sorting, and pagination. ```typescript -getAll(collection: string): Promise +getAll(collection: string, params?: QueryParams): Promise ``` -Returns an empty array if the collection does not exist yet. +**Query Parameters (`params`)** + +| Parameter | Type | Description | +|---|---|---| +| `filter` | `object` | Filter by field suffixes (e.g. `{ age_gt: 18 }`). | +| `sort` | `string` | Sort order (e.g. `"createdAt:desc"`). | +| `limit` | `number` | Max documents to return (max 100). | +| `page` | `number` | Page number for pagination. | +| `populate` | `string \| string[]` | Expand Reference fields into full objects. | **Example** ```typescript -interface Product { - _id: string; - name: string; - price: number; -} - -const products = await client.db.getAll('products'); -// products is Product[] +const products = await client.db.getAll('products', { + filter: { category: 'electronics', price_lt: 500 }, + sort: 'price:asc', + limit: 20 +}); ``` --- @@ -51,61 +55,50 @@ const products = await client.db.getAll('products'); Fetch a single document by its ID. ```typescript -getOne(collection: string, id: string): Promise +getOne(collection: string, id: string, options?: { populate?: string | string[] }): Promise ``` -Throws `NotFoundError` if no document with that ID exists. - **Example** ```typescript -const product = await client.db.getOne('products', '507f1f77bcf86cd799439011'); -console.log(product.name); // 'Chair' +const product = await client.db.getOne('products', 'id_123', { populate: 'vendor' }); ``` --- ## insert -Insert a new document into a collection. The collection must already exist in the dashboard. +Insert a new document. If RLS is enabled, the `token` parameter is required. ```typescript -insert(collection: string, data: Record): Promise +insert(collection: string, data: Record, token?: string): Promise ``` -Returns the inserted document, including its server-assigned `_id`. +--- -**Example** +## update -```typescript -const product = await client.db.insert('products', { - name: 'Chair', - price: 99, -}); +Update an existing document by its ID. This performs a **full replacement** of the document fields. -console.log(product._id); // '507f1f77bcf86cd799439011' +```typescript +update(collection: string, id: string, data: Record, token?: string): Promise ``` --- -## update +## patch -Update an existing document by its ID. The `data` object is merged into the existing document. +Partially update a document. Only the fields provided in `data` will be modified. ```typescript -update(collection: string, id: string, data: Record): Promise +patch(collection: string, id: string, data: Record, token?: string): Promise ``` -Returns the updated document. - **Example** ```typescript -const updated = await client.db.update('products', '507f1f77bcf86cd799439011', { - price: 79, -}); - -console.log(updated.price); // 79 +// Only updates the price, leaves other fields unchanged +await client.db.patch('products', 'id_123', { price: 45 }); ``` --- @@ -115,61 +108,22 @@ console.log(updated.price); // 79 Delete a document by its ID. ```typescript -delete(collection: string, id: string): Promise<{ deleted: boolean }> -``` - -**Example** - -```typescript -const result = await client.db.delete('products', '507f1f77bcf86cd799439011'); -console.log(result.deleted); // true +delete(collection: string, id: string, token?: string): Promise<{ deleted: boolean }> ``` --- -## TypeScript generics +## TypeScript Support -Passing a generic type to database methods gives you full type inference on the returned document. Define an interface that extends the `_id: string` field: +Define your interfaces to get full IDE autocomplete: ```typescript interface BlogPost { _id: string; title: string; - body: string; - publishedAt: string; + author: string; } -// Typed array const posts = await client.db.getAll('posts'); - -// Typed document -const post = await client.db.getOne('posts', id); -post.title; // string — no type assertion needed -``` - ---- - -## Error handling - -```typescript -import urBackend, { NotFoundError, AuthError, RateLimitError } from '@urbackend/sdk'; - -const client = urBackend({ apiKey: process.env.URBACKEND_API_KEY }); - -try { - const product = await client.db.getOne('products', id); -} catch (e) { - if (e instanceof NotFoundError) { - // Document does not exist - console.error('Product not found'); - } else if (e instanceof AuthError) { - // Invalid or missing API key - console.error('Unauthorized'); - } else if (e instanceof RateLimitError) { - // Exceeded 100 requests per 15 minutes per IP - console.error(`Rate limited. Retry after ${e.retryAfter}s`); - } else { - throw e; - } -} +posts[0].title; // typed as string ``` diff --git a/mintlify/docs/sdk/mail.mdx b/mintlify/docs/sdk/mail.mdx new file mode 100644 index 00000000..5baa155a --- /dev/null +++ b/mintlify/docs/sdk/mail.mdx @@ -0,0 +1,49 @@ +--- +title: "Mail" +description: "Send transactional emails from your server using the SDK mail module." +keywords: ["mail", "email", "resend", "transactional email", "sdk"] +--- + +Access mail methods via `client.mail`. This module allows you to send emails using your project's configured mail provider (e.g. Resend). + + +Mail operations require a **Secret Key** (`sk_live_...`). This module should only be used in server-side environments (Node.js, Edge Functions, etc.). Never call these methods from a browser. + + +## send + +Send an email. + +```typescript +send(payload: SendMailPayload): Promise +``` + +**Parameters (`SendMailPayload`)** + +| Field | Type | Required | Description | +|---|---|---|---| +| `to` | `string \| string[]` | Yes | Recipient email address(es). | +| `subject` | `string` | Yes | Email subject line. | +| `text` | `string` | No | Plain text body. | +| `html` | `string` | No | HTML body. | + +**Returns (`SendMailResponse`)** + +| Field | Type | Description | +|---|---|---| +| `id` | `string` | The message ID from the provider. | +| `provider` | `string` | The provider used (`"byok"` or `"default"`). | +| `monthlyUsage` | `number` | Total emails sent this month. | +| `monthlyLimit` | `number` | Your project's monthly quota. | + +**Example** + +```typescript +const response = await client.mail.send({ + to: 'customer@example.com', + subject: 'Welcome to urBackend', + html: '

Hi there!

Thanks for joining.

' +}); + +console.log(response.id); +``` diff --git a/mintlify/docs/sdk/overview.mdx b/mintlify/docs/sdk/overview.mdx index 21734ccc..4bbfad12 100644 --- a/mintlify/docs/sdk/overview.mdx +++ b/mintlify/docs/sdk/overview.mdx @@ -37,22 +37,27 @@ import urBackend from '@urbackend/sdk'; const client = urBackend({ apiKey: process.env.URBACKEND_API_KEY }); -// Sign up a new user -const user = await client.auth.signUp({ +// Log in an existing user +const { accessToken } = await client.auth.login({ email: 'alice@example.com', - password: 'secret123', - name: 'Alice', + password: 'secret123' }); -// Insert a document (collection must be created in the dashboard first) -const product = await client.db.insert('products', { name: 'Chair', price: 99 }); +// Insert a document with RLS support (passing the user token) +const product = await client.db.insert('products', { name: 'Chair', price: 99 }, accessToken); -// Fetch all documents -const products = await client.db.getAll('products'); +// Fetch documents with filtering and sorting +const products = await client.db.getAll('products', { + filter: { price_gt: 50 }, + sort: 'price:asc' +}); -// Upload a file (browser) -const input = document.querySelector('input[type="file"]'); -const { url, path } = await client.storage.upload(input.files[0]); +// Send an email (server-side only, requires secret key) +await client.mail.send({ + to: 'user@example.com', + subject: 'Order Confirmed', + text: 'Your chair is on the way!' +}); ``` ## TypeScript generics @@ -109,23 +114,29 @@ try { ## API key security -Use `pk_live_...` (publishable key) in frontend/browser code. It allows read operations only. +Use `pk_live_...` (publishable key) in frontend/browser code. It allows read operations by default, and write operations only if RLS is enabled. -Use `sk_live_...` (secret key) in server-side code only. It allows reads and writes. Never expose it in client-side bundles or public repositories. +Use `sk_live_...` (secret key) in server-side code only. It allows full CRUD access. Never expose it in client-side bundles or public repositories. -The SDK logs a console warning if it detects you are using it in a browser context, as a reminder to check which key you are passing. +The SDK logs a console warning if it detects you are using a **Secret Key** (`sk_live_...`) in a browser context. ## Explore the SDK - + - Sign up, log in, and fetch the current user. + Login, logout, profile updates, and social auth. - Read and write documents in any collection. + CRUD operations, query building, and RLS support. Upload files and get back a public CDN URL. + + Inspect collection definitions and field types. + + + Send transactional emails from your server. + diff --git a/mintlify/docs/sdk/schema.mdx b/mintlify/docs/sdk/schema.mdx new file mode 100644 index 00000000..69f23a41 --- /dev/null +++ b/mintlify/docs/sdk/schema.mdx @@ -0,0 +1,42 @@ +--- +title: "Schema" +description: "Inspect collection definitions and field types using the SDK schema module." +keywords: ["schema", "introspection", "metadata", "sdk"] +--- + +Access schema methods via `client.schema`. This module allows you to programmatically retrieve the definitions of your collections, which is useful for building dynamic forms or data table components. + +## getSchema + +Fetch the schema definition for a specific collection. + +```typescript +getSchema(collection: string): Promise +``` + +**Returns (`CollectionSchema`)** + +| Field | Type | Description | +|---|---|---| +| `name` | `string` | The name of the collection. | +| `model` | `SchemaField[]` | Array of field definitions. | + +**`SchemaField` Object** + +| Field | Type | Description | +|---|---|---| +| `key` | `string` | The field name. | +| `type` | `string` | The Mongoose type (e.g. `"String"`, `"Number"`, `"Ref"`). | +| `required` | `boolean` | Whether the field is mandatory. | +| `unique` | `boolean` | Whether the field has a uniqueness constraint. | +| `ref` | `string` | If type is `"Ref"`, the target collection name. | + +**Example** + +```typescript +const schema = await client.schema.getSchema('products'); + +console.log(schema.name); // 'products' +console.log(schema.model[0].key); // 'name' +console.log(schema.model[0].type); // 'String' +``` diff --git a/mintlify/docs/sdk/storage.mdx b/mintlify/docs/sdk/storage.mdx index d6e5cf91..6d4214c6 100644 --- a/mintlify/docs/sdk/storage.mdx +++ b/mintlify/docs/sdk/storage.mdx @@ -17,7 +17,7 @@ Storage operations accept both `pk_live_...` and `sk_live_...` keys. Use `pk_liv Upload a file to storage. ```typescript -upload(file: File | Blob | Buffer, filename?: string): Promise<{ url: string; path: string }> +upload(file: File | Blob | Buffer, filename?: string): Promise ``` **Parameters** @@ -27,12 +27,13 @@ upload(file: File | Blob | Buffer, filename?: string): Promise<{ url: string; pa | `file` | `File \| Blob \| Buffer` | Yes | The file to upload. | | `filename` | `string` | No | Override the stored filename. | -**Returns** +**Returns (`UploadResponse`)** | Field | Type | Description | |---|---|---| | `url` | `string` | Public CDN URL for the uploaded file. | | `path` | `string` | Storage path — required to delete the file later. | +| `provider` | `'internal' \| 'external'` | Whether the file is stored on urBackend or your own Supabase. | Store the `path` alongside the `url` in your database. You need it to delete the file. @@ -44,27 +45,9 @@ Store the `path` alongside the `url` in your database. You need it to delete the const input = document.querySelector('input[type="file"]'); const file = input.files[0]; -const { url, path } = await client.storage.upload(file); +const { url, path, provider } = await client.storage.upload(file); console.log(url); // 'https://cdn.example.com/uploads/abc123.jpg' -console.log(path); // 'uploads/abc123.jpg' - -// Store both so you can delete the file later -await client.db.insert('product_images', { url, path }); -``` - -**Example — custom filename** - -```typescript -const { url, path } = await client.storage.upload(file, 'profile-photo.jpg'); -``` - -**Example — Node.js Buffer** - -```typescript -import { readFileSync } from 'fs'; - -const buffer = readFileSync('./report.pdf'); -const { url, path } = await client.storage.upload(buffer, 'report.pdf'); +console.log(provider); // 'internal' ``` --- @@ -83,46 +66,15 @@ deleteFile(path: string): Promise<{ deleted: boolean }> |---|---|---|---| | `path` | `string` | Yes | The `path` returned by `upload()`. | -**Example** - -```typescript -// Retrieve the stored path -const image = await client.db.getOne('product_images', id); - -const result = await client.storage.deleteFile(image.path); -console.log(result.deleted); // true -``` - --- ## Limits | Limit | Value | |---|---| -| Max file size | 5 MB per file | -| Total storage per project | 100 MB | +| Max file size | 10 MB per file | +| Total storage per project | 100 MB (Free Tier) | -Uploads that exceed 5 MB are rejected with a `StorageError`. Check `file.size` before calling `upload()` if you need to show a friendly error to your users. +Uploads that exceed 10 MB are rejected with a `StorageError`. - -**Example — checking file size before upload** - -```typescript -import { StorageError } from '@urbackend/sdk'; - -const MAX_BYTES = 5 * 1024 * 1024; // 5 MB - -if (file.size > MAX_BYTES) { - console.error('File must be 5 MB or smaller'); - return; -} - -try { - const { url, path } = await client.storage.upload(file); -} catch (e) { - if (e instanceof StorageError) { - console.error('Upload failed:', e.message); - } -} -``` From bcfa27cee00153fcc329e809bf2466b5415d29c4 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:22:10 +0000 Subject: [PATCH 2/7] fix: update SendMailResponse field types to match SDK contract Generated-By: mintlify-agent --- mintlify/docs/sdk/mail.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mintlify/docs/sdk/mail.mdx b/mintlify/docs/sdk/mail.mdx index 5baa155a..6b8c0e2d 100644 --- a/mintlify/docs/sdk/mail.mdx +++ b/mintlify/docs/sdk/mail.mdx @@ -31,8 +31,8 @@ send(payload: SendMailPayload): Promise | Field | Type | Description | |---|---|---| -| `id` | `string` | The message ID from the provider. | -| `provider` | `string` | The provider used (`"byok"` or `"default"`). | +| `id` | `string \| null` | The message ID from the provider (`null` if unavailable). | +| `provider` | `'byok' \| 'default'` | The provider used. | | `monthlyUsage` | `number` | Total emails sent this month. | | `monthlyLimit` | `number` | Your project's monthly quota. | From 92c0a705f82a5eb5291671d8a952a3fd3a156630 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:22:27 +0000 Subject: [PATCH 3/7] fix: correct socialExchange description and add null guards to example Generated-By: mintlify-agent --- mintlify/docs/sdk/auth.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mintlify/docs/sdk/auth.mdx b/mintlify/docs/sdk/auth.mdx index ae11f139..bb343f4f 100644 --- a/mintlify/docs/sdk/auth.mdx +++ b/mintlify/docs/sdk/auth.mdx @@ -120,7 +120,7 @@ socialStart(provider: 'github' | 'google'): string ### socialExchange -Exchange the `rtCode` received at your callback URL for a session. +Exchange the `rtCode` received at your callback URL for a refresh token. ```typescript socialExchange(payload: SocialExchangePayload): Promise @@ -134,6 +134,10 @@ const urlParams = new URLSearchParams(window.location.search); const rtCode = urlParams.get('rtCode'); const token = new URLSearchParams(window.location.hash.slice(1)).get('token'); +if (!rtCode || !token) { + throw new Error('Missing OAuth callback parameters'); +} + const { refreshToken } = await client.auth.socialExchange({ token, rtCode }); ``` From f93802f06b25518811f229ea384e0f1ca6e2bf40 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:22:41 +0000 Subject: [PATCH 4/7] Fix AuthResponse interface to match SDK type contract Generated-By: mintlify-agent --- mintlify/docs/sdk/auth.mdx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mintlify/docs/sdk/auth.mdx b/mintlify/docs/sdk/auth.mdx index bb343f4f..05cc8ec9 100644 --- a/mintlify/docs/sdk/auth.mdx +++ b/mintlify/docs/sdk/auth.mdx @@ -39,10 +39,11 @@ login(payload: LoginPayload): Promise ```typescript interface AuthResponse { - accessToken: string; - token: string; // Alias for accessToken (deprecated) - user: AuthUser; - expiresIn: string; + accessToken?: string; + token?: string; // Alias for accessToken (deprecated) + user?: AuthUser; + expiresIn?: string; + userId?: string; } ``` From 51ecc4de84cd3bbe966baf2aab13cc081c5ae8e7 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:24:11 +0000 Subject: [PATCH 5/7] Address CodeRabbit review feedback across SDK docs - auth.mdx: Make AuthResponse fields optional, add userId, use sentence-case headings, code-format method names, validate OAuth params before use - database.mdx: Clarify generic type T only applies to data-returning methods - mail.mdx: Fix id to string|null, provider to literal union type - overview.mdx: Use separate server client with secret key for mail example - schema.mdx: Add missing items and fields properties to SchemaField table - storage.mdx: Add null-safety guard for file input element Generated-By: mintlify-agent --- mintlify/docs/sdk/auth.mdx | 20 ++++++++++---------- mintlify/docs/sdk/database.mdx | 2 +- mintlify/docs/sdk/mail.mdx | 2 +- mintlify/docs/sdk/overview.mdx | 7 +++++-- mintlify/docs/sdk/schema.mdx | 4 +++- mintlify/docs/sdk/storage.mdx | 5 +++++ 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/mintlify/docs/sdk/auth.mdx b/mintlify/docs/sdk/auth.mdx index 05cc8ec9..5b6d1f2c 100644 --- a/mintlify/docs/sdk/auth.mdx +++ b/mintlify/docs/sdk/auth.mdx @@ -41,9 +41,9 @@ login(payload: LoginPayload): Promise interface AuthResponse { accessToken?: string; token?: string; // Alias for accessToken (deprecated) - user?: AuthUser; expiresIn?: string; userId?: string; + user?: AuthUser; } ``` @@ -107,11 +107,11 @@ changePassword(payload: ChangePasswordPayload, token?: string): Promise<{ messag --- -## Social Auth +## Social auth urBackend supports OAuth via GitHub and Google. -### socialStart +### `socialStart` Returns the URL to initiate the OAuth flow. Redirect your user's browser to this URL. @@ -119,7 +119,7 @@ Returns the URL to initiate the OAuth flow. Redirect your user's browser to this socialStart(provider: 'github' | 'google'): string ``` -### socialExchange +### `socialExchange` Exchange the `rtCode` received at your callback URL for a refresh token. @@ -135,8 +135,8 @@ const urlParams = new URLSearchParams(window.location.search); const rtCode = urlParams.get('rtCode'); const token = new URLSearchParams(window.location.hash.slice(1)).get('token'); -if (!rtCode || !token) { - throw new Error('Missing OAuth callback parameters'); +if (!token || !rtCode) { + throw new Error('Missing required OAuth callback parameters'); } const { refreshToken } = await client.auth.socialExchange({ token, rtCode }); @@ -144,7 +144,7 @@ const { refreshToken } = await client.auth.socialExchange({ token, rtCode }); --- -## Account Verification +## Account verification Methods for handling email OTP flows. @@ -157,7 +157,7 @@ Methods for handling email OTP flows. --- -## publicProfile +## `publicProfile` Fetch a public-safe profile for any user by their username. This does not return sensitive fields like email or provider IDs. @@ -167,7 +167,7 @@ publicProfile(username: string): Promise --- -## logout +## `logout` Revokes the current session on the server and clears the local token. @@ -177,7 +177,7 @@ logout(token?: string): Promise<{ success: boolean; message: string }> --- -## Manual Token Management +## Manual token management If you need to manage tokens manually (e.g., after social auth), use these helper methods: diff --git a/mintlify/docs/sdk/database.mdx b/mintlify/docs/sdk/database.mdx index e9774b7b..5762b70a 100644 --- a/mintlify/docs/sdk/database.mdx +++ b/mintlify/docs/sdk/database.mdx @@ -6,7 +6,7 @@ keywords: ["database", "collections", "crud", "sdk", "typescript", "rls", "query Access database methods via `client.db`. Collections must be created in the [urBackend Dashboard](https://urbackend.bitbros.in) before you can interact with them. -All methods accept a generic type parameter `T` (extending `DocumentData`) so the returned documents are fully typed. +Methods that return documents accept a generic type parameter `T` (extending `DocumentData`) so returned documents are fully typed. Methods like `delete()` return status objects and do not accept `T`. ## Row-Level Security (RLS) diff --git a/mintlify/docs/sdk/mail.mdx b/mintlify/docs/sdk/mail.mdx index 6b8c0e2d..ac3aeb35 100644 --- a/mintlify/docs/sdk/mail.mdx +++ b/mintlify/docs/sdk/mail.mdx @@ -32,7 +32,7 @@ send(payload: SendMailPayload): Promise | Field | Type | Description | |---|---|---| | `id` | `string \| null` | The message ID from the provider (`null` if unavailable). | -| `provider` | `'byok' \| 'default'` | The provider used. | +| `provider` | `"byok" \| "default"` | The provider used for sending. | | `monthlyUsage` | `number` | Total emails sent this month. | | `monthlyLimit` | `number` | Your project's monthly quota. | diff --git a/mintlify/docs/sdk/overview.mdx b/mintlify/docs/sdk/overview.mdx index 4bbfad12..77246379 100644 --- a/mintlify/docs/sdk/overview.mdx +++ b/mintlify/docs/sdk/overview.mdx @@ -52,8 +52,11 @@ const products = await client.db.getAll('products', { sort: 'price:asc' }); -// Send an email (server-side only, requires secret key) -await client.mail.send({ +// ⚠️ Server-side only — requires a secret key (sk_live_...). +// Do not use this initialization in browser/client code. +const serverClient = urBackend({ apiKey: process.env.URBACKEND_SECRET_KEY }); + +await serverClient.mail.send({ to: 'user@example.com', subject: 'Order Confirmed', text: 'Your chair is on the way!' diff --git a/mintlify/docs/sdk/schema.mdx b/mintlify/docs/sdk/schema.mdx index 69f23a41..d0824f4f 100644 --- a/mintlify/docs/sdk/schema.mdx +++ b/mintlify/docs/sdk/schema.mdx @@ -26,10 +26,12 @@ getSchema(collection: string): Promise | Field | Type | Description | |---|---|---| | `key` | `string` | The field name. | -| `type` | `string` | The Mongoose type (e.g. `"String"`, `"Number"`, `"Ref"`). | +| `type` | `string` | The Mongoose type (e.g. `"String"`, `"Number"`, `"Ref"`, `"Array"`). | | `required` | `boolean` | Whether the field is mandatory. | | `unique` | `boolean` | Whether the field has a uniqueness constraint. | | `ref` | `string` | If type is `"Ref"`, the target collection name. | +| `items` | `object` | Element type definition when type is `"Array"`. Contains `type` and optional nested `fields`. | +| `fields` | `SchemaField[]` | Nested field definitions for embedded objects or sub-documents. | **Example** diff --git a/mintlify/docs/sdk/storage.mdx b/mintlify/docs/sdk/storage.mdx index 6d4214c6..f8132221 100644 --- a/mintlify/docs/sdk/storage.mdx +++ b/mintlify/docs/sdk/storage.mdx @@ -43,6 +43,11 @@ Store the `path` alongside the `url` in your database. You need it to delete the ```typescript const input = document.querySelector('input[type="file"]'); + +if (!input?.files?.length) { + throw new Error('No file selected'); +} + const file = input.files[0]; const { url, path, provider } = await client.storage.upload(file); From 8d87b83b31e49566878b5de4f4c48adb474bdf09 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:26:43 +0000 Subject: [PATCH 6/7] Format API method names as code in auth.mdx headings Generated-By: mintlify-agent --- mintlify/docs/sdk/auth.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mintlify/docs/sdk/auth.mdx b/mintlify/docs/sdk/auth.mdx index 5b6d1f2c..1bb9c285 100644 --- a/mintlify/docs/sdk/auth.mdx +++ b/mintlify/docs/sdk/auth.mdx @@ -6,7 +6,7 @@ keywords: ["auth", "authentication", "login", "signup", "sdk", "social auth", "o Access auth methods via `client.auth`. The module automatically stores the `accessToken` from `login()` or `refreshToken()` and uses it for subsequent authenticated requests like `me()` or `updateProfile()`. -## signUp +## `signUp` Create a new user account. @@ -27,7 +27,7 @@ const user = await client.auth.signUp({ --- -## login +## `login` Authenticate an existing user. The returned `accessToken` is stored internally. @@ -58,7 +58,7 @@ const { accessToken, user } = await client.auth.login({ --- -## refreshToken +## `refreshToken` Rotate the current access token. @@ -71,7 +71,7 @@ refreshToken(refreshToken?: string): Promise --- -## me +## `me` Fetch the profile of the currently authenticated user. @@ -81,7 +81,7 @@ me(token?: string): Promise --- -## updateProfile +## `updateProfile` Update the authenticated user's profile fields. @@ -97,7 +97,7 @@ await client.auth.updateProfile({ name: 'Alice Smith' }); --- -## changePassword +## `changePassword` Change the authenticated user's password. From 625a2c427812576db3512d81d3977a81d7ae4c01 Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:27:22 +0000 Subject: [PATCH 7/7] Fix auth.mdx: use second-person voice and improve phrasing Generated-By: mintlify-agent --- mintlify/docs/sdk/auth.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mintlify/docs/sdk/auth.mdx b/mintlify/docs/sdk/auth.mdx index 1bb9c285..e23f8a02 100644 --- a/mintlify/docs/sdk/auth.mdx +++ b/mintlify/docs/sdk/auth.mdx @@ -4,7 +4,7 @@ description: "Manage user accounts, sessions, and social authentication with the keywords: ["auth", "authentication", "login", "signup", "sdk", "social auth", "oauth"] --- -Access auth methods via `client.auth`. The module automatically stores the `accessToken` from `login()` or `refreshToken()` and uses it for subsequent authenticated requests like `me()` or `updateProfile()`. +You can access auth methods via `client.auth`. When you call `login()` or `refreshToken()`, the module stores the `accessToken` and uses it for subsequent authenticated requests such as `me()` or `updateProfile()`. ## `signUp` @@ -113,7 +113,7 @@ urBackend supports OAuth via GitHub and Google. ### `socialStart` -Returns the URL to initiate the OAuth flow. Redirect your user's browser to this URL. +You receive a URL to initiate the OAuth flow. Redirect your user's browser to this URL. ```typescript socialStart(provider: 'github' | 'google'): string @@ -146,7 +146,7 @@ const { refreshToken } = await client.auth.socialExchange({ token, rtCode }); ## Account verification -Methods for handling email OTP flows. +Use these methods to handle email OTP flows. | Method | Description | |---|---| @@ -169,7 +169,7 @@ publicProfile(username: string): Promise ## `logout` -Revokes the current session on the server and clears the local token. +Call this to revoke your current session on the server and clear the local token. ```typescript logout(token?: string): Promise<{ success: boolean; message: string }> @@ -179,7 +179,7 @@ logout(token?: string): Promise<{ success: boolean; message: string }> ## Manual token management -If you need to manage tokens manually (e.g., after social auth), use these helper methods: +If you need to manage tokens manually (for example, after social auth), you can use these helper methods: - `getToken()`: Returns the current in-memory access token. - `setToken(token)`: Manually set the access token for the client.