diff --git a/skills/base44-sdk/SKILL.md b/skills/base44-sdk/SKILL.md index a195f9f..27ac437 100644 --- a/skills/base44-sdk/SKILL.md +++ b/skills/base44-sdk/SKILL.md @@ -225,7 +225,8 @@ const base44 = createClient({ - Send emails → `integrations.Core.SendEmail()` - Upload files → `integrations.Core.UploadFile()` - Custom APIs → `integrations.custom.call()` -- App-scoped OAuth (app builder's account) → `asServiceRole.connectors.getConnection()` (backend only) +- App-scoped OAuth (app builder's account, shared by all users) → `asServiceRole.connectors.getConnection()` (backend only) +- Per-user OAuth (each app user connects their own account) → `connectors.connectAppUser()` (frontend) + `asServiceRole.connectors.getCurrentAppUserConnection()` (backend) **Tracking and analytics?** - Track custom events → `analytics.track()` diff --git a/skills/base44-sdk/references/QUICK_REFERENCE.md b/skills/base44-sdk/references/QUICK_REFERENCE.md index 33fd337..a430800 100644 --- a/skills/base44-sdk/references/QUICK_REFERENCE.md +++ b/skills/base44-sdk/references/QUICK_REFERENCE.md @@ -8,7 +8,7 @@ Compact method signatures for all SDK modules. **Verify against this before writ ``` loginViaEmailPassword(email, password, turnstileToken?) → Promise<{access_token, user}> -loginWithProvider('google' | 'microsoft' | 'facebook', fromUrl?) → void +loginWithProvider('google' | 'microsoft' | 'facebook' | 'apple' | 'sso', fromUrl?) → void me() → Promise updateMe(data) → Promise isAuthenticated() → Promise @@ -35,8 +35,8 @@ list(sort?, limit?, skip?, fields?) → Promise[]> filter(query, sort?, limit?, skip?, fields?) → Promise[]> get(id) → Promise update(id, data) → Promise -updateMany(query, mongoUpdateOp) → Promise // e.g. { $set: { field: val } } -bulkUpdate(dataArray) → Promise // each item must have id +updateMany(query, mongoUpdateOp) → Promise // e.g. { $set: { field: val } }; batched by 500, check result.has_more +bulkUpdate(dataArray) → Promise // each item must have id; max 500 per request delete(id) → Promise deleteMany(query) → Promise importEntities(file) → Promise> // frontend only @@ -45,6 +45,8 @@ subscribe(callback) → () => void // returns unsu **Sort:** Use `SortField`: `-fieldName` for descending (e.g., `-created_date`). Max 5,000 per request for list/filter. +**Query operators** (`filter`, `updateMany`, `deleteMany`): `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$exists`, `$regex` (string), `$all`/`$size` (array), `$not`; root-level `$and`/`$or`/`$nor`. + --- ## Functions (`base44.functions.*`) @@ -58,10 +60,27 @@ fetch(path, init?) → Promise // low-level, for streaming/custom me --- +## Agents (`base44.agents.*`) + +Requires a logged-in user. + +``` +createConversation({agent_name, metadata?}) → Promise +getConversations() → Promise +getConversation(id) → Promise // full data, incl. untruncated tool calls +listConversations({q?, sort?, limit?, skip?, fields?}) → Promise +subscribeToConversation(id, onUpdate?) → () => void // realtime; tool call data truncated +addMessage(conversation, message) → Promise +getWhatsAppConnectURL(agentName) → string +getTelegramConnectURL(agentName) → string +``` + +--- + ## Integrations (`base44.integrations.Core.*`) ``` -InvokeLLM({prompt, add_context_from_internet?, response_json_schema?, file_urls?}) → Promise +InvokeLLM({prompt, model?, add_context_from_internet?, response_json_schema?, file_urls?}) → Promise // file_urls and add_context_from_internet are mutually exclusive GenerateImage({prompt}) → Promise<{url}> SendEmail({to, subject, body, from_name?}) → Promise UploadFile({file}) → Promise<{file_url}> @@ -103,8 +122,6 @@ track({eventName, properties?}) → void ``` logUserInApp(pageName) → Promise -fetchLogs(params?) → Promise -getStats(params?) → Promise ``` --- @@ -119,15 +136,26 @@ inviteUser(userEmail, role) → Promise // role: 'user' | 'admin' ## Service Role Connectors (`base44.asServiceRole.connectors.*`) -**Backend only, service role required.** App-scoped (shared account). +**Backend only, service role required.** ``` -getConnection(integrationType) → Promise<{accessToken, connectionConfig}> // recommended -getAccessToken(integrationType) → Promise // deprecated +getConnection(integrationType) → Promise<{accessToken, connectionConfig}> // shared, by integration type (recommended) +getWorkspaceConnection(connectorId) → Promise<{accessToken, connectionConfig}> // shared, by workspace connector ID +getCurrentAppUserConnection(connectorId) → Promise<{accessToken, connectionConfig}> // per-user; needs createClientFromRequest(req) +getAccessToken(integrationType) → Promise // deprecated ``` **Types:** Run `npx base44 connectors list-available` to see all available integration types. +## App User Connectors (`base44.connectors.*`) + +**Frontend.** Per-user OAuth flow (each app user connects their own account). + +``` +connectAppUser(connectorId) → Promise // redirect URL; window.location.href = url +disconnectAppUser(connectorId) → Promise +``` + --- ## SSO (`base44.asServiceRole.sso.*`) @@ -136,6 +164,7 @@ getAccessToken(integrationType) → Promise // ``` getAccessToken(userId) → Promise<{access_token}> +getIdToken(userId) → Promise // stored ID token, not refreshed; needs on-behalf-of token for the same user ``` --- diff --git a/skills/base44-sdk/references/app-logs.md b/skills/base44-sdk/references/app-logs.md index 9865bb0..337d75f 100644 --- a/skills/base44-sdk/references/app-logs.md +++ b/skills/base44-sdk/references/app-logs.md @@ -12,8 +12,8 @@ Log user activity in your app via `base44.appLogs`. | Method | Signature | Description | |--------|-----------|-------------| | `logUserInApp(pageName)` | `Promise` | Log user activity on a page | -| `fetchLogs(params?)` | `Promise` | Fetch app logs with optional filter parameters | -| `getStats(params?)` | `Promise` | Get app usage statistics | + +**Note:** the SDK also implements `fetchLogs()` and `getStats()`, but both are marked `@internal` in source — not part of the supported public API, and may change or be removed without notice. View logged activity in the Analytics page of your app dashboard instead. ## Examples @@ -59,32 +59,6 @@ function handleSettingsChange() { } ``` -### Fetch Logs - -```javascript -// Fetch all logs -const logs = await base44.appLogs.fetchLogs(); - -// Fetch logs with filters -const recentLogs = await base44.appLogs.fetchLogs({ - limit: 50, - page: "/dashboard" -}); -``` - -### Get Stats - -```javascript -// Get usage statistics for the app -const stats = await base44.appLogs.getStats(); - -// Get stats with date range params -const weekStats = await base44.appLogs.getStats({ - from: "2024-01-01", - to: "2024-01-07" -}); -``` - ## Notes - Logs appear in the Analytics page of your app dashboard @@ -102,19 +76,5 @@ interface AppLogsModule { * @returns Promise that resolves when the log is recorded. */ logUserInApp(pageName: string): Promise; - - /** - * Fetch app logs with optional filter parameters. - * @param params - Optional filter parameters (e.g., limit, page name, date range). - * @returns Promise resolving to the logs data. - */ - fetchLogs(params?: Record): Promise; - - /** - * Get app usage statistics. - * @param params - Optional filter parameters (e.g., date range). - * @returns Promise resolving to the statistics data. - */ - getStats(params?: Record): Promise; } ``` diff --git a/skills/base44-sdk/references/auth.md b/skills/base44-sdk/references/auth.md index ad3c43d..0dbdd19 100644 --- a/skills/base44-sdk/references/auth.md +++ b/skills/base44-sdk/references/auth.md @@ -80,7 +80,7 @@ interface ChangePasswordParams { ### Provider Type ```typescript -type Provider = 'google' | 'microsoft' | 'facebook'; +type Provider = 'google' | 'microsoft' | 'facebook' | 'apple' | 'sso'; ``` --- @@ -92,7 +92,7 @@ type Provider = 'google' | 'microsoft' | 'facebook'; interface AuthModule { // User Info me(): Promise; - updateMe(data: Partial>): Promise; + updateMe(data: Record): Promise; isAuthenticated(): Promise; // Login/Logout @@ -125,9 +125,9 @@ interface AuthModule { |--------|-----------|-------------|-------------| | `register()` | `params: RegisterParams` | `Promise` | Create new user account | | `loginViaEmailPassword()` | `email: string, password: string, turnstileToken?: string` | `Promise` | Authenticate with email/password | -| `loginWithProvider()` | `provider: Provider, fromUrl?: string` | `void` | Initiate OAuth login flow. Providers: `'google'` (default), `'microsoft'`, `'facebook'` (enable in app settings) | +| `loginWithProvider()` | `provider: Provider, fromUrl?: string` | `void` | Initiate OAuth login flow. Providers: `'google'` (default), `'microsoft'`, `'facebook'`, `'apple'` (enable in app settings), `'sso'` (enterprise SSO, requires SSO setup) | | `me()` | None | `Promise` | Get current authenticated user | -| `updateMe()` | `data: Partial` | `Promise` | Update current user's profile | +| `updateMe()` | `data: Record` | `Promise` | Update current user's profile | | `logout()` | `redirectUrl?: string` | `void` | Redirect to server-side logout (clears HTTP-only cookies and session), then to redirectUrl or current URL | | `redirectToLogin()` | `nextUrl: string` | `void` | ⚠️ **Avoid** - Prefer custom login UI with `loginViaEmailPassword()` or `loginWithProvider()` | | `isAuthenticated()` | None | `Promise` | Check if user is logged in | @@ -215,7 +215,7 @@ try { ### Login with OAuth Provider -Supported providers: `'google'` (enabled by default), `'microsoft'`, and `'facebook'`. Enable Microsoft or Facebook in your app's authentication settings before using them. +Supported providers: `'google'` (enabled by default), `'microsoft'`, `'facebook'`, `'apple'`, and `'sso'` (enterprise SSO). Enable Microsoft, Facebook, Apple, or SSO in your app's authentication settings before using them. Requires a browser environment. ```javascript // Redirect to Google OAuth @@ -224,11 +224,17 @@ base44.auth.loginWithProvider('google'); // Redirect to Google OAuth and return to current page after base44.auth.loginWithProvider('google', window.location.href); -// Microsoft or Facebook (enable in app settings first) +// Microsoft, Facebook, or Apple (enable in app settings first) base44.auth.loginWithProvider('microsoft'); base44.auth.loginWithProvider('facebook', '/dashboard'); +base44.auth.loginWithProvider('apple', '/dashboard'); + +// Enterprise SSO (set up an SSO provider in app settings first) +base44.auth.loginWithProvider('sso', '/dashboard'); ``` +**Inside an iframe:** if the app is embedded in an iframe, `loginWithProvider()` doesn't do a full-page redirect. It opens a centered popup instead, waits for the popup to `postMessage` back an `access_token` (and optionally `is_new_user`), then navigates the top-level window to `fromUrl` with those values appended as query params. Outside an iframe, it's a plain `window.location.href` redirect. + ### Get Current User ```javascript @@ -589,17 +595,22 @@ Configure authentication providers in your app dashboard: - **Google** - OAuth authentication - **Microsoft** - OAuth authentication - **Facebook** - OAuth authentication +- **Apple** - Sign in with Apple **SSO Providers (Elite Plan):** - **Okta** - **Azure AD** - **GitHub** +Note: the SDK always passes the single provider value `'sso'` for `loginWithProvider()` regardless of which enterprise SSO provider is configured in your app's authentication settings — the specific provider (Okta, Azure AD, GitHub, etc.) is a dashboard configuration detail, not a separate SDK parameter. + ### Using OAuth Providers - **Google** – enabled by default. - **Microsoft** – enable in your app's authentication settings before use. - **Facebook** – enable in your app's authentication settings before use. +- **Apple** – enable in your app's authentication settings before use. +- **SSO** – set up an SSO provider in your app's authentication settings before use. ```javascript // Initiate OAuth login flow @@ -608,7 +619,7 @@ base44.auth.loginWithProvider('google'); // Return to specific page after authentication base44.auth.loginWithProvider('microsoft', '/dashboard'); -// Supported values: 'google', 'microsoft', 'facebook' +// Supported values: 'google', 'microsoft', 'facebook', 'apple', 'sso' ``` --- diff --git a/skills/base44-sdk/references/base44-agents.md b/skills/base44-sdk/references/base44-agents.md index 49b1cbd..32897f3 100644 --- a/skills/base44-sdk/references/base44-agents.md +++ b/skills/base44-sdk/references/base44-agents.md @@ -9,7 +9,7 @@ AI agent conversations and messages via `base44.agents`. ## Contents - [Concepts](#concepts) - [Methods](#methods) -- [Examples](#examples) (Create, Get Conversations, List, Subscribe, Send Message, WhatsApp) +- [Examples](#examples) (Create, Get Conversations, List, Subscribe, Send Message, WhatsApp, Telegram) - [Message Structure](#message-structure) - [Conversation Structure](#conversation-structure) - [Common Patterns](#common-patterns) @@ -30,6 +30,7 @@ AI agent conversations and messages via `base44.agents`. | `subscribeToConversation(id, onUpdate?)` | `() => void` | Realtime updates via WebSocket; tool call data truncated (returns unsubscribe function) | | `addMessage(conversation, message)` | `Promise` | Send a message | | `getWhatsAppConnectURL(agentName)` | `string` | Get WhatsApp connection URL for agent | +| `getTelegramConnectURL(agentName)` | `string` | Get Telegram connection URL for agent | ## Examples @@ -125,6 +126,14 @@ const whatsappUrl = base44.agents.getWhatsAppConnectURL("support-agent"); console.log(whatsappUrl); ``` +### Get Telegram Connection URL + +```javascript +const telegramUrl = base44.agents.getTelegramConnectURL("support-agent"); +// Returns URL for users to connect with agent via Telegram +console.log(telegramUrl); +``` + ## Message Structure ```javascript @@ -136,13 +145,14 @@ console.log(whatsappUrl); // Optional fields reasoning: { - content: "Agent's reasoning process", - timing: 1500 + start_date: "2024-01-15T10:29:58Z", + end_date: "2024-01-15T10:30:00Z", + content: "Agent's reasoning process" }, tool_calls: [{ name: "search", - arguments: { query: "weather" }, - result: { ... }, + arguments_string: '{"query":"weather"}', + results: "...", status: "success" }], file_urls: ["https://..."], @@ -295,7 +305,7 @@ interface AgentMessageToolCall { /** Arguments passed to the tool as JSON string. */ arguments_string: string; /** Status of the tool call. */ - status: "running" | "success" | "error" | "stopped"; + status: "running" | "success" | "error" | "stopped" | "waiting_for_user_input"; /** Results from the tool call. */ results?: string; } @@ -384,5 +394,8 @@ interface AgentsModule { /** Gets WhatsApp connection URL for an agent. */ getWhatsAppConnectURL(agentName: AgentName): string; + + /** Gets Telegram connection URL for an agent. */ + getTelegramConnectURL(agentName: AgentName): string; } ``` diff --git a/skills/base44-sdk/references/client.md b/skills/base44-sdk/references/client.md index 27cd623..297f4e7 100644 --- a/skills/base44-sdk/references/client.md +++ b/skills/base44-sdk/references/client.md @@ -137,8 +137,12 @@ base44.functions // Backend function invocation base44.integrations // Third-party services base44.users // User invitations +// Backend only +base44.aiGateway // Connect an OpenAI-compatible SDK to Base44's AI gateway (see ai-gateway.md) + // Service role only (backend) base44.asServiceRole.agents +base44.asServiceRole.aiGateway base44.asServiceRole.appLogs base44.asServiceRole.connectors // App-scoped OAuth tokens (ConnectorsModule) base44.asServiceRole.entities @@ -185,6 +189,7 @@ useEffect(() => { createClient({ appId: "your-app-id", // Required: MUST use 'appId' (not 'clientId' or 'id') token: "jwt-token", // Optional: pre-set auth token + serverUrl: "https://base44.app", // Optional: defaults to "https://base44.app"; point at a local dev server if needed options: { // Optional: configuration options onError: (error) => {} // Optional: global error handler (must be in options) } @@ -206,6 +211,8 @@ interface CreateClientConfig { appId: string; /** User authentication token. Used to authenticate as a specific user. */ token?: string; + /** Base URL of the Base44 server to point the SDK at (e.g. for local development). @defaultValue "https://base44.app" */ + serverUrl?: string; /** @internal Service role token; only set automatically in Base44-hosted backend functions. */ serviceToken?: string; /** Additional client options. */ @@ -238,6 +245,8 @@ interface Base44Client { functions: FunctionsModule; /** Integrations module for calling pre-built integration methods. */ integrations: IntegrationsModule; + /** Connect an OpenAI-compatible SDK to Base44's AI gateway (backend only). */ + aiGateway: AiGatewayModule; /** Cleanup function to disconnect WebSocket connections. */ cleanup(): void; @@ -257,6 +266,7 @@ interface Base44Client { entities: EntitiesModule; functions: FunctionsModule; integrations: IntegrationsModule; + aiGateway: AiGatewayModule; /** SSO token generation for users. */ sso: SsoModule; cleanup(): void; diff --git a/skills/base44-sdk/references/connectors.md b/skills/base44-sdk/references/connectors.md index ca90664..d95d420 100644 --- a/skills/base44-sdk/references/connectors.md +++ b/skills/base44-sdk/references/connectors.md @@ -1,11 +1,15 @@ # Connectors Module -OAuth token management for external services. +OAuth token management for external services. Unlike the `integrations` module (which provides pre-built functions), connectors give you raw OAuth tokens so you can call external service APIs directly. -- **`base44.asServiceRole.connectors`** — App-scoped OAuth tokens (backend/service role only). All users share the same connected account. +There are two connector types: + +- **Shared connectors** (`base44.asServiceRole.connectors`) — a single OAuth token shared by all app users. Best for shared service accounts (e.g. posting to a company Slack channel). **Backend/service role only.** +- **App user connectors** (`base44.connectors` for initiating the OAuth flow from the frontend; `base44.asServiceRole.connectors.getCurrentAppUserConnection()` on the backend) — each app user has their own OAuth token. Best for actions that need to happen as the individual user (e.g. sending from their own Gmail). ## Contents - [Service Role Connectors (`base44.asServiceRole.connectors`)](#service-role-connectors-base44asserviceroleconnectors) +- [App User Connectors (`base44.connectors`)](#app-user-connectors-base44connectors) - [Available Services](#available-services) - [Type Definitions](#type-definitions) @@ -13,13 +17,15 @@ OAuth token management for external services. ## Service Role Connectors (`base44.asServiceRole.connectors`) -App-scoped OAuth tokens. The app builder connects the account once; all users share it. **Backend/service role only.** +App-scoped OAuth tokens. **Backend/service role only.** ### Methods | Method | Signature | Description | |--------|-----------|-------------| -| `getConnection(integrationType)` | `Promise` | Get access token and optional connection config | +| `getConnection(integrationType)` | `Promise` | Get access token and optional connection config for a shared connector, by integration type | +| `getWorkspaceConnection(connectorId)` | `Promise` | Get access token and optional connection config for a workspace-registered connector, by connector ID | +| `getCurrentAppUserConnection(connectorId)` | `Promise` | Get the current app user's OAuth token for an app user connector | | `getAccessToken(integrationType)` | `Promise` | ⚠️ **Deprecated** — use `getConnection()` instead | ### Examples @@ -65,40 +71,104 @@ const events = await fetch( ).then(r => r.json()); ``` +```javascript +// Workspace-registered connector, by connector ID (not integration type) +const { accessToken, connectionConfig } = await base44.asServiceRole.connectors.getWorkspaceConnection("abc123def"); + +const response = await fetch(`https://${connectionConfig?.subdomain}.snowflakecomputing.com/api/v2/statements`, { + headers: { Authorization: `Bearer ${accessToken}` } +}); +``` + +```javascript +// App user connector: get the current app user's own token (backend only) +Deno.serve(async (req) => { + const base44 = createClientFromRequest(req); // resolves the requesting app user + + const { accessToken } = await base44.asServiceRole.connectors.getCurrentAppUserConnection("abc123def"); + + const events = await fetch("https://www.googleapis.com/calendar/v3/calendars/primary/events", { + headers: { Authorization: `Bearer ${accessToken}` } + }).then(r => r.json()); + + return Response.json(events); +}); +``` + +--- + +## App User Connectors (`base44.connectors`) + +Each signed-in app user has their own OAuth token. Register OAuth credentials for the service in Workspace Settings to get a **connector ID**, then use these frontend methods to let the user connect/disconnect their own account. On the backend, retrieve the current app user's token with `base44.asServiceRole.connectors.getCurrentAppUserConnection(connectorId)` (see above) — this requires `createClientFromRequest(req)` so the SDK knows which app user to act on behalf of. + +### Methods + +| Method | Signature | Description | +|--------|-----------|-------------| +| `connectAppUser(connectorId)` | `Promise` | Get the OAuth redirect URL to start the app user's connection flow | +| `disconnectAppUser(connectorId)` | `Promise` | Remove the current app user's stored connection | + +### Examples + +```javascript +// Frontend: start the OAuth flow for the current app user +const redirectUrl = await base44.connectors.connectAppUser("abc123def"); +window.location.href = redirectUrl; + +// Frontend: disconnect the current app user's connection +await base44.connectors.disconnectAppUser("abc123def"); +``` + --- ## Available Services +All services below support both shared connectors (`getConnection()`) and app user connectors (register in Workspace Settings, then `connectAppUser()` / `getCurrentAppUserConnection()`). + | Service | Type identifier | |---------|----------------| | Airtable | `airtable` | +| BambooHR | `bamboohr` | | Box | `box` | +| Calendly | `calendly` | | ClickUp | `clickup` | +| Contentful | `contentful` | +| Databricks | `databricks` | | Discord | `discord` | | Dropbox | `dropbox` | | GitHub | `github` | +| GitLab | `gitlab` | | Gmail | `gmail` | +| Google Ads | `googleads` | | Google Analytics | `google_analytics` | | Google BigQuery | `googlebigquery` | | Google Calendar | `googlecalendar` | | Google Classroom | `google_classroom` | | Google Docs | `googledocs` | | Google Drive | `googledrive` | +| Google Meet | `googlemeet` | | Google Search Console | `google_search_console` | | Google Sheets | `googlesheets` | | Google Slides | `googleslides` | +| Google Tasks | `googletasks` | | HubSpot | `hubspot` | +| Hugging Face | `hugging_face` | +| Instagram Business | `instagram` | | Linear | `linear` | | LinkedIn | `linkedin` | | Microsoft Teams | `microsoft_teams` | | Microsoft OneDrive | `one_drive` | | Notion | `notion` | | Outlook | `outlook` | +| QuickBooks | `quickbooks` | | Salesforce | `salesforce` | | SharePoint | `share_point` | | Slack User | `slack` | | Slack Bot | `slackbot` | +| Snowflake | `snowflake` | | Splitwise | `splitwise` | +| Square | `square` | +| Supabase | `supabase` | | TikTok | `tiktok` | | Typeform | `typeform` | | Wix | `wix` | @@ -131,7 +201,7 @@ Run `npx base44 connectors list-available` from the CLI to see all available typ */ type ConnectorIntegrationType = string; -/** Connection details returned by getConnection(). */ +/** Connection details returned by getConnection() and getWorkspaceConnection(). */ interface ConnectorConnectionResponse { /** The OAuth access token for the external service. */ accessToken: string; @@ -139,14 +209,35 @@ interface ConnectorConnectionResponse { connectionConfig: Record | null; } +/** Connection details returned by getCurrentAppUserConnection(). */ +interface AppUserConnectorConnectionResponse { + /** The OAuth access token for the app user's connection. */ + accessToken: string; + /** Key-value configuration for the connection, or null if not needed. */ + connectionConfig: Record | null; +} + /** Service role connectors module (app-scoped OAuth). Backend only. */ interface ConnectorsModule { /** - * Retrieves the OAuth access token and optional connection config. + * Retrieves the shared OAuth access token and optional connection config, by integration type. * @param integrationType - e.g., 'googlecalendar', 'slack', 'github'. */ getConnection(integrationType: ConnectorIntegrationType): Promise; + /** + * Retrieves the OAuth access token and optional connection config for a workspace-registered + * connector, by connector ID (the `OrganizationConnector` database ID). + */ + getWorkspaceConnection(connectorId: string): Promise; + + /** + * Retrieves the current app user's OAuth access token and optional connection config for an + * app user connector. Requires a client created with `createClientFromRequest(req)` so the SDK + * knows which app user to act on behalf of. + */ + getCurrentAppUserConnection(connectorId: string): Promise; + /** * @deprecated Use getConnection() instead. * Retrieves only the OAuth access token string. @@ -154,4 +245,13 @@ interface ConnectorsModule { getAccessToken(integrationType: ConnectorIntegrationType): Promise; } +/** User-scoped connectors module for app user OAuth flows. Available via `base44.connectors`. */ +interface UserConnectorsModule { + /** Gets the OAuth redirect URL to start the app user's connection flow for a connector. */ + connectAppUser(connectorId: string): Promise; + + /** Removes the current app user's stored connection for a connector. */ + disconnectAppUser(connectorId: string): Promise; +} + ``` diff --git a/skills/base44-sdk/references/entities.md b/skills/base44-sdk/references/entities.md index 8a2f51c..5d5efd4 100644 --- a/skills/base44-sdk/references/entities.md +++ b/skills/base44-sdk/references/entities.md @@ -91,8 +91,24 @@ const titles = await base44.entities.Task.filter( null, ["id", "title"] ); + +// Query operators (MongoDB-style) +const highValue = await base44.entities.Order.filter({ + amount: { $gte: 100 }, + status: { $in: ["pending", "processing"] } +}); + +// Combine with $and / $or / $nor at the root level +const flagged = await base44.entities.Task.filter({ + $or: [ + { priority: "high" }, + { count: { $gte: 100 } } + ] +}); ``` +**Supported query operators:** `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$exists` (all fields); `$regex` (string fields); `$all`, `$size` (array fields); `$not` (negates a field-level operator expression); `$and`, `$or`, `$nor` (root-level, combine nested filter queries). + ### Get by ID ```javascript @@ -138,6 +154,24 @@ await base44.entities.Task.updateMany( ); ``` +**Batching:** results are batched in groups of up to 500. When `result.has_more` is `true`, call `updateMany` again with the *same query* to process the next batch — make sure the query excludes already-updated records so you don't re-process the same entities: + +```javascript +// Process all pending items in batches of 500. +// The query filters by 'pending', so updated records (now 'processed') +// are automatically excluded from the next batch. +let hasMore = true; +let totalUpdated = 0; +while (hasMore) { + const result = await base44.entities.Job.updateMany( + { status: "pending" }, + { $set: { status: "processed" } } + ); + totalUpdated += result.updated; + hasMore = result.has_more; +} +``` + ### Bulk Update (by ID) ```javascript @@ -149,6 +183,16 @@ const updated = await base44.entities.Task.bulkUpdate([ ]); ``` +**Limit:** up to 500 records per request. For more, chunk the array yourself: + +```javascript +const allUpdates = reassignments.map(r => ({ id: r.taskId, owner: r.newOwner })); +for (let i = 0; i < allUpdates.length; i += 500) { + const batch = allUpdates.slice(i, i + 500); + await base44.entities.Task.bulkUpdate(batch); +} +``` + ### Import from File ```javascript @@ -184,6 +228,8 @@ unsubscribe(); } ``` +**Oversize payloads:** the realtime transport caps payload size. If a broadcast would exceed it, the server sets `data._oversize: true` and slims the payload (fields over 10 KB arrive as empty strings, or the whole record may collapse to a stub). The SDK logs a console warning when this happens. On `create`/`update` events, check for `data._oversize` and call `entities.EntityName.get(id)` to fetch the full record instead of rendering the slimmed payload. + ## User Entity Every app has a built-in `User` entity with special rules: @@ -222,7 +268,7 @@ Operations succeed or fail based on these rules - no partial results. RLS and FLS are configured in entity schema files (`base44/entities/*.jsonc`). See [entities-create.md](../../base44-cli/references/entities-create.md#row-level-security-rls) for configuration details. -**Note:** `asServiceRole` sets the user's role to `"admin"` but does NOT bypass RLS. Your RLS rules must include admin access (e.g., `{ "user_condition": { "role": "admin" } }`) for service role operations to succeed. +**Note:** `asServiceRole` operations bypass entity access rules and field-level security entirely — they can read and write any record in any entity, regardless of RLS/FLS rules. ## Type Definitions @@ -257,6 +303,8 @@ interface UpdateManyResult { success: boolean; /** Number of entities that were updated. */ updated: number; + /** Whether more records match the query and weren't updated in this batch. When `true`, call `updateMany` again with the same query to process the next batch. */ + has_more: boolean; } /** Result returned when deleting a single entity. */ @@ -325,6 +373,37 @@ type EntityRecord = { }; ``` +### EntityFilterQuery + +Query type accepted by `filter()`, `updateMany()`, and `deleteMany()`. Each field can use an exact value, `null`, an array shorthand (matches any listed value), or a field-level operator object. Root-level `$and`, `$or`, `$nor` combine nested filter queries. + +```typescript +/** Query object accepted by entity filtering methods. */ +type EntityFilterQuery = { + [K in keyof T]?: EntityFilterValue; +} & { + $and?: EntityFilterQuery[]; + $or?: EntityFilterQuery[]; + $nor?: EntityFilterQuery[]; +}; + +/** Value accepted when filtering an entity field: exact match, array shorthand, or operator object. */ +type EntityFilterValue = + | (Exclude | null) + | (Exclude | null)[] + | EntityFilterOperators; + +/** MongoDB-style query operators accepted for a single entity field. */ +type EntityFilterOperators = { + $eq?: T; $ne?: T; $gt?: T; $gte?: T; $lt?: T; $lte?: T; + $in?: T[]; $nin?: T[]; + $exists?: boolean; + $regex?: string; // string fields only + $all?: T; $size?: number; // array fields only + $not?: EntityFilterOperators; // negates a field-level filter expression +}; +``` + ### EntityHandler ```typescript @@ -340,7 +419,7 @@ interface EntityHandler { /** Filters records based on a query. Max 5,000 per request. */ filter( - query: Partial, + query: EntityFilterQuery, sort?: SortField, limit?: number, skip?: number, @@ -360,19 +439,20 @@ interface EntityHandler { delete(id: string): Promise; /** Deletes multiple records matching a query. */ - deleteMany(query: Partial): Promise; + deleteMany(query: EntityFilterQuery): Promise; /** Creates multiple records in a single request. */ bulkCreate(data: Partial[]): Promise; /** * Updates multiple records matching a query using MongoDB update operators. + * Results are batched in groups of up to 500 — see `has_more` on the result. * @param query - Filter to select which records to update. * @param data - MongoDB update operator object (e.g., `{ $set: { field: value } }`). */ - updateMany(query: Partial, data: Record>): Promise; + updateMany(query: EntityFilterQuery, data: Record>): Promise; - /** Updates multiple records by ID, each with its own update data. */ + /** Updates multiple records by ID, each with its own update data. Up to 500 records per request. */ bulkUpdate(data: (Partial & { id: string })[]): Promise; /** Imports records from a file (frontend only). */ diff --git a/skills/base44-sdk/references/integrations.md b/skills/base44-sdk/references/integrations.md index 178a546..84d0961 100644 --- a/skills/base44-sdk/references/integrations.md +++ b/skills/base44-sdk/references/integrations.md @@ -55,13 +55,20 @@ const response = await base44.integrations.Core.InvokeLLM({ prompt: "Describe what's in this image", file_urls: ["https://...uploaded_image.png"] }); + +// Override the app-level model for this call +const response = await base44.integrations.Core.InvokeLLM({ + prompt: "Explain quantum computing", + model: "gpt_5_5" +}); ``` **Parameters:** - `prompt` (string, required): The prompt text to send to the model -- `add_context_from_internet` (boolean, optional): If true, uses Google Search/Maps/News for real-time context +- `model` (string, optional): Overrides the app-level model setting for this call. One of `'gpt_5_mini'`, `'gemini_3_flash'`, `'gpt_5_4'`, `'gpt_5_5'`, `'gemini_3_1_pro'`, `'claude_sonnet_4_6'`, `'claude_opus_4_6'`, `'claude_opus_4_7'`, `'claude_opus_4_8'` +- `add_context_from_internet` (boolean, optional): If true, uses Google Search/Maps/News for real-time context. Don't combine with `file_urls` - `response_json_schema` (object, optional): JSON schema for structured output -- `file_urls` (string[], optional): URLs of uploaded files for context +- `file_urls` (string[], optional): URLs of uploaded files for context. Don't combine with `add_context_from_internet` > `InvokeLLM` is a **single call with no tools**. Don't chain it to simulate an agent loop — for a tool-using agent, build a **code agent** on the AI gateway. See [ai-gateway.md](ai-gateway.md). @@ -92,7 +99,7 @@ await base44.integrations.Core.SendEmail({ **Parameters:** - `to` (string, required): Recipient email address - `subject` (string, required): Email subject line -- `body` (string, required): Plain text or HTML email body +- `body` (string, required): Plain text email body content - `from_name` (string, optional): Sender name displayed to recipient **Limitations:** @@ -219,11 +226,24 @@ const response = await base44.integrations.custom.call( } ``` +### Errors + +`custom.call()` throws: +- `Error` if `slug` is not provided +- `Error` if `operationId` is not provided +- `Base44Error` if the integration or operation is not found (404) +- `Base44Error` if the external API call fails (502) +- `Base44Error` if the request times out (504) + ## Requirements - **Core integrations**: Available on all plans - **Catalog/Custom integrations**: Require Builder plan or higher +## Authentication Modes + +Available in all authentication modes. Use `base44.asServiceRole.integrations` for elevated/service-role calls (same `Core` and `custom` submodules). + ## Type Definitions ### Core Integration Parameters @@ -233,11 +253,13 @@ const response = await base44.integrations.custom.call( interface InvokeLLMParams { /** The prompt text to send to the model. */ prompt: string; - /** If true, uses Google Search/Maps/News for real-time context. */ + /** Overrides the app-level model setting for this call. */ + model?: 'gpt_5_mini' | 'gemini_3_flash' | 'gpt_5_4' | 'gpt_5_5' | 'gemini_3_1_pro' | 'claude_sonnet_4_6' | 'claude_opus_4_6' | 'claude_opus_4_7' | 'claude_opus_4_8'; + /** If true, uses Google Search/Maps/News for real-time context. Don't combine with `file_urls`. */ add_context_from_internet?: boolean; /** JSON schema for structured output. If provided, returns object instead of string. */ response_json_schema?: object; - /** File URLs (from UploadFile) to provide as context. */ + /** File URLs (from UploadFile) to provide as context. Don't combine with `add_context_from_internet`. */ file_urls?: string[]; } @@ -271,7 +293,7 @@ interface SendEmailParams { to: string; /** Email subject line. */ subject: string; - /** Plain text or HTML email body. */ + /** Plain text email body content. */ body: string; /** Sender name (defaults to app name). */ from_name?: string; @@ -372,6 +394,6 @@ type IntegrationsModule = { /** Custom integrations module. */ custom: CustomIntegrationsModule; /** Additional integration packages (dynamic). */ - [packageName: string]: any; + [packageName: string]: IntegrationPackage; }; ``` diff --git a/skills/base44-sdk/references/sso.md b/skills/base44-sdk/references/sso.md index c7a5d70..df9388e 100644 --- a/skills/base44-sdk/references/sso.md +++ b/skills/base44-sdk/references/sso.md @@ -9,6 +9,7 @@ Single Sign-On (SSO) support for authenticating Base44 users with external syste | Method | Signature | Description | |--------|-----------|-------------| | `getAccessToken(userId)` | `Promise` | Get an SSO access token for a specific user | +| `getIdToken(userId)` | `Promise` | Get the stored SSO OIDC ID token for the current app user | ## Examples @@ -48,6 +49,23 @@ Deno.serve(async (req) => { }); ``` +### Get the Stored SSO ID Token + +Returns the stored SSO OIDC ID token as-is (does not refresh it). The service-role client must include an on-behalf-of token for the same user passed as `userid` — use `createClientFromRequest(req)` with the current user's request. + +```javascript +import { createClientFromRequest } from "npm:@base44/sdk"; + +Deno.serve(async (req) => { + const base44 = createClientFromRequest(req); + const user = await base44.auth.me(); + + const idToken = await base44.asServiceRole.sso.getIdToken(user.id); + + return Response.json({ idToken }); +}); +``` + ## Use Cases - Authenticating Base44 users with external SaaS tools (e.g., Okta, Azure AD) @@ -71,5 +89,13 @@ interface SsoModule { * @returns Promise resolving to the SSO access token response. */ getAccessToken(userid: string): Promise; + + /** + * Gets the stored SSO OIDC ID token for the current app user. Does not refresh the token. + * The service-role client must include an on-behalf-of token for the same user. + * @param userid - The current app user's ID. + * @returns Promise resolving to the raw ID-token string. + */ + getIdToken(userid: string): Promise; } ```