first commit

This commit is contained in:
2026-06-24 09:48:54 +02:00
commit 41e62ddcad
33739 changed files with 4266226 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 base44
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+153
View File
@@ -0,0 +1,153 @@
# Base44 JavaScript SDK
The Base44 SDK provides a JavaScript interface for building apps on the Base44 platform.
You can use it in two ways:
- **Inside Base44 apps**: When Base44 generates your app, the SDK is already set up and ready to use.
- **External apps**: Use the SDK to build your own frontend or backend that uses Base44 as a backend service.
## Installation
**Inside Base44 apps**: The SDK is already available. No installation needed.
**External apps**: Install the SDK via npm:
```bash
npm install @base44/sdk
```
## Modules
The SDK provides access to Base44's functionality through the following modules:
- **[`agents`](https://docs.base44.com/developers/references/sdk/docs/interfaces/agents)**: Interact with AI agents and manage conversations.
- **[`analytics`](https://docs.base44.com/developers/references/sdk/docs/interfaces/analytics)**: Track custom events in your app.
- **[`app-logs`](https://docs.base44.com/developers/references/sdk/docs/interfaces/app-logs)**: Access and query app logs.
- **[`auth`](https://docs.base44.com/developers/references/sdk/docs/interfaces/auth)**: Manage user authentication, registration, and session handling.
- **[`connectors`](https://docs.base44.com/developers/references/sdk/docs/interfaces/connectors)**: Manage OAuth connections and access tokens for third-party services.
- **[`entities`](https://docs.base44.com/developers/references/sdk/docs/interfaces/entities)**: Work with your app's data entities using CRUD operations.
- **[`functions`](https://docs.base44.com/developers/references/sdk/docs/interfaces/functions)**: Execute backend functions.
- **[`integrations`](https://docs.base44.com/developers/references/sdk/docs/type-aliases/integrations)**: Access pre-built and third-party integrations.
## Quickstarts
How you get started depends on whether you're working inside a Base44-generated app or building your own.
### Inside Base44 apps
In Base44-generated apps, the client is pre-configured. Just import and use it:
```typescript
import { base44 } from "@/api/base44Client";
// Create a new task
const newTask = await base44.entities.Task.create({
title: "Complete project documentation",
status: "pending",
dueDate: "2024-12-31",
});
// Update the task
await base44.entities.Task.update(newTask.id, {
status: "in-progress",
});
// List all tasks
const tasks = await base44.entities.Task.list();
```
### External apps
When using Base44 as a backend for your own app, install the SDK and create the client yourself:
```typescript
import { createClient } from "@base44/sdk";
// Create a client for your Base44 app
const base44 = createClient({
appId: "your-app-id", // Find this in the Base44 editor URL
});
// Read public data
const products = await base44.entities.Products.list();
// Authenticate a user (token is automatically set)
await base44.auth.loginViaEmailPassword("user@example.com", "password");
// Access user's data
const userOrders = await base44.entities.Orders.list();
```
### Service role
By default, the client operates with user-level permissions, limiting access to what the current user can see and do. The service role provides elevated permissions for backend operations and is only available in Base44-hosted backend functions. External backends can't use service role permissions.
```typescript
import { createClientFromRequest } from "npm:@base44/sdk";
Deno.serve(async (req) => {
const base44 = createClientFromRequest(req);
// Access all data with admin-level permissions
const allOrders = await base44.asServiceRole.entities.Orders.list();
return Response.json({ orders: allOrders });
});
```
## Learn more
The best way to get started with the JavaScript SDK is to have Base44 build an app for you. Once you have an app, you can explore the generated code and experiment with the SDK to see how it works in practice. You can also ask Base44 to demonstrate specific features of the SDK.
For a deeper understanding, check out these guides:
1. [Base44 client](https://docs.base44.com/developers/references/sdk/getting-started/client) - Work with the client in frontend, backend, and external app contexts.
2. [Work with data](https://docs.base44.com/developers/references/sdk/getting-started/work-with-data) - Create, read, update, and delete data.
3. [Common SDK patterns](https://docs.base44.com/developers/references/sdk/getting-started/work-with-sdk) - Authentication, integrations, functions, and error handling.
For the complete documentation and API reference, visit the **[Base44 Developer Docs](https://docs.base44.com/developers/home)**.
## Development
### Build the SDK
Build the SDK from source:
```bash
npm install
npm run build
```
### Run tests
Run the test suite:
```bash
# Run all tests
npm test
# Run unit tests only
npm run test:unit
# Run with coverage
npm run test:coverage
```
For E2E tests, create a `tests/.env` file with:
```
BASE44_APP_ID=your_app_id
BASE44_AUTH_TOKEN=your_auth_token
```
### Generate documentation
Generate API documentation locally:
```bash
# Process and preview locally
npm run create-docs
cd docs
mintlify dev
```
+96
View File
@@ -0,0 +1,96 @@
import type { Base44Client, CreateClientConfig, CreateClientOptions } from "./client.types.js";
export type { Base44Client, CreateClientConfig, CreateClientOptions };
/**
* Creates a Base44 client.
*
* This is the main entry point for the Base44 SDK. It creates a client that provides access to the SDK's modules, such as {@linkcode EntitiesModule | entities}, {@linkcode AuthModule | auth}, and {@linkcode FunctionsModule | functions}.
*
* How you get a client depends on your context:
* - **Inside a Base44 app:** The client is automatically created and configured for you. Import it from `@/api/base44Client`.
* - **External app using Base44 as a backend:** Call `createClient()` directly in your code to create and configure the client.
*
* The client supports three authentication modes:
* - **Anonymous**: Access modules without authentication using `base44.moduleName`. Operations are scoped to public data and permissions.
* - **User authentication**: Access modules with user-level permissions using `base44.moduleName`. Operations are scoped to the authenticated user's data and permissions. Use `base44.auth.loginViaEmailPassword()` or other auth methods to get a token.
* - **Service role authentication**: Access modules with elevated permissions using `base44.asServiceRole.moduleName`. Operations can access any data available to the app's admin. Only available in Base44-hosted backend functions. Create a client with service role authentication using {@linkcode createClientFromRequest | createClientFromRequest()}.
*
* For example, when using the {@linkcode EntitiesModule | entities} module:
* - **Anonymous**: Can only read public data.
* - **User authentication**: Can access the current user's data.
* - **Service role authentication**: Can access all data that admins can access.
*
* Most modules are available in all three modes, but with different permission levels. However, some modules are only available in specific authentication modes.
*
* @param config - Configuration object for the client.
* @returns A configured Base44 client instance with access to all SDK modules.
*
* @example
* ```typescript
* // Create a client for your app
* import { createClient } from '@base44/sdk';
*
* const base44 = createClient({
* appId: 'my-app-id'
* });
*
* // Use the client to access your data
* const products = await base44.entities.Products.list();
* ```
*/
export declare function createClient(config: CreateClientConfig): Base44Client;
/**
* Creates a Base44 client from an HTTP request.
*
* This function is designed for use in Base44-hosted backend functions. For frontends and external backends, use {@linkcode createClient | createClient()} instead.
*
* When used in a Base44-hosted backend function, `createClientFromRequest()` automatically extracts authentication tokens from the request headers that Base44 injects when forwarding requests. The returned client includes service role access using `base44.asServiceRole`, which provides admin-level permissions.
*
* To learn more about the Base44 client, see {@linkcode createClient | createClient()}.
*
* @param request - The incoming HTTP request object containing Base44 authentication headers.
* @returns A configured Base44 client instance with authentication from the incoming request.
*
* @example
* ```typescript
* // User authentication in backend function
* import { createClientFromRequest } from 'npm:@base44/sdk';
*
* Deno.serve(async (req) => {
* try {
* const base44 = createClientFromRequest(req);
* const user = await base44.auth.me();
*
* if (!user) {
* return Response.json({ error: 'Unauthorized' }, { status: 401 });
* }
*
* // Access user's data
* const userOrders = await base44.entities.Orders.filter({ userId: user.id });
* return Response.json({ orders: userOrders });
* } catch (error) {
* return Response.json({ error: error.message }, { status: 500 });
* }
* });
* ```
*
* @example
* ```typescript
* // Service role authentication in backend function
* import { createClientFromRequest } from 'npm:@base44/sdk';
*
* Deno.serve(async (req) => {
* try {
* const base44 = createClientFromRequest(req);
*
* // Access admin data with service role permissions
* const recentOrders = await base44.asServiceRole.entities.Orders.list('-created_at', 50);
*
* return Response.json({ orders: recentOrders });
* } catch (error) {
* return Response.json({ error: error.message }, { status: 500 });
* }
* });
* ```
*
*/
export declare function createClientFromRequest(request: Request): Base44Client;
+381
View File
@@ -0,0 +1,381 @@
import { createAxiosClient } from "./utils/axios-client.js";
import { createEntitiesModule } from "./modules/entities.js";
import { createIntegrationsModule } from "./modules/integrations.js";
import { createAuthModule } from "./modules/auth.js";
import { createSsoModule } from "./modules/sso.js";
import { createConnectorsModule, createUserConnectorsModule, } from "./modules/connectors.js";
import { getAccessToken } from "./utils/auth-utils.js";
import { createFunctionsModule } from "./modules/functions.js";
import { createAgentsModule } from "./modules/agents.js";
import { createAppLogsModule } from "./modules/app-logs.js";
import { createUsersModule } from "./modules/users.js";
import { RoomsSocket } from "./utils/socket-utils.js";
import { createAnalyticsModule } from "./modules/analytics.js";
/**
* Creates a Base44 client.
*
* This is the main entry point for the Base44 SDK. It creates a client that provides access to the SDK's modules, such as {@linkcode EntitiesModule | entities}, {@linkcode AuthModule | auth}, and {@linkcode FunctionsModule | functions}.
*
* How you get a client depends on your context:
* - **Inside a Base44 app:** The client is automatically created and configured for you. Import it from `@/api/base44Client`.
* - **External app using Base44 as a backend:** Call `createClient()` directly in your code to create and configure the client.
*
* The client supports three authentication modes:
* - **Anonymous**: Access modules without authentication using `base44.moduleName`. Operations are scoped to public data and permissions.
* - **User authentication**: Access modules with user-level permissions using `base44.moduleName`. Operations are scoped to the authenticated user's data and permissions. Use `base44.auth.loginViaEmailPassword()` or other auth methods to get a token.
* - **Service role authentication**: Access modules with elevated permissions using `base44.asServiceRole.moduleName`. Operations can access any data available to the app's admin. Only available in Base44-hosted backend functions. Create a client with service role authentication using {@linkcode createClientFromRequest | createClientFromRequest()}.
*
* For example, when using the {@linkcode EntitiesModule | entities} module:
* - **Anonymous**: Can only read public data.
* - **User authentication**: Can access the current user's data.
* - **Service role authentication**: Can access all data that admins can access.
*
* Most modules are available in all three modes, but with different permission levels. However, some modules are only available in specific authentication modes.
*
* @param config - Configuration object for the client.
* @returns A configured Base44 client instance with access to all SDK modules.
*
* @example
* ```typescript
* // Create a client for your app
* import { createClient } from '@base44/sdk';
*
* const base44 = createClient({
* appId: 'my-app-id'
* });
*
* // Use the client to access your data
* const products = await base44.entities.Products.list();
* ```
*/
export function createClient(config) {
var _a, _b;
const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
// Normalize appBaseUrl to always be a string (empty if not provided or invalid)
const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
const socketConfig = {
serverUrl,
mountPath: "/ws-user-apps/socket.io/",
transports: ["websocket"],
appId,
token,
};
let socket = null;
const getSocket = () => {
if (!socket) {
socket = RoomsSocket({
config: socketConfig,
});
}
return socket;
};
const headers = {
...optionalHeaders,
"X-App-Id": String(appId),
};
const functionHeaders = functionsVersion
? {
...headers,
"Base44-Functions-Version": functionsVersion,
}
: headers;
const axiosClient = createAxiosClient({
baseURL: `${serverUrl}/api`,
headers,
token,
onError: options === null || options === void 0 ? void 0 : options.onError,
});
const functionsAxiosClient = createAxiosClient({
baseURL: `${serverUrl}/api`,
headers: functionHeaders,
token,
interceptResponses: false,
onError: options === null || options === void 0 ? void 0 : options.onError,
});
const serviceRoleHeaders = {
...headers,
...(token ? { "on-behalf-of": `Bearer ${token}` } : {}),
};
const serviceRoleAxiosClient = createAxiosClient({
baseURL: `${serverUrl}/api`,
headers: serviceRoleHeaders,
token: serviceToken,
onError: options === null || options === void 0 ? void 0 : options.onError,
});
const serviceRoleFunctionsAxiosClient = createAxiosClient({
baseURL: `${serverUrl}/api`,
headers: functionHeaders,
token: serviceToken,
interceptResponses: false,
});
const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
appBaseUrl: normalizedAppBaseUrl,
serverUrl,
});
// Apply the access token before any module that may issue authenticated
// requests during construction (notably analytics, which fires an init
// event whose flush calls auth.me()). Without this, the first User/me
// request is built before setToken runs and goes out unauthenticated.
if (typeof window !== "undefined") {
const accessToken = token || getAccessToken();
if (accessToken) {
userAuthModule.setToken(accessToken);
}
}
const userModules = {
entities: createEntitiesModule({
axios: axiosClient,
appId,
getSocket,
}),
integrations: createIntegrationsModule(axiosClient, appId),
connectors: createUserConnectorsModule(axiosClient, appId),
auth: userAuthModule,
functions: createFunctionsModule(functionsAxiosClient, appId, {
getAuthHeaders: () => {
const headers = {};
// Get current token from storage or initial config
const currentToken = token || getAccessToken();
if (currentToken) {
headers["Authorization"] = `Bearer ${currentToken}`;
}
return headers;
},
baseURL: (_a = functionsAxiosClient.defaults) === null || _a === void 0 ? void 0 : _a.baseURL,
}),
agents: createAgentsModule({
axios: axiosClient,
getSocket,
appId,
serverUrl,
token,
}),
appLogs: createAppLogsModule(axiosClient, appId),
users: createUsersModule(axiosClient, appId),
analytics: createAnalyticsModule({
axiosClient,
serverUrl,
appId,
userAuthModule,
}),
cleanup: () => {
userModules.analytics.cleanup();
if (socket) {
socket.disconnect();
}
},
};
const serviceRoleModules = {
entities: createEntitiesModule({
axios: serviceRoleAxiosClient,
appId,
getSocket,
}),
integrations: createIntegrationsModule(serviceRoleAxiosClient, appId),
sso: createSsoModule(serviceRoleAxiosClient, appId),
connectors: createConnectorsModule(serviceRoleAxiosClient, appId),
functions: createFunctionsModule(serviceRoleFunctionsAxiosClient, appId, {
getAuthHeaders: () => {
const headers = {};
// Use service token for authorization
if (serviceToken) {
headers["Authorization"] = `Bearer ${serviceToken}`;
}
return headers;
},
baseURL: (_b = serviceRoleFunctionsAxiosClient.defaults) === null || _b === void 0 ? void 0 : _b.baseURL,
}),
agents: createAgentsModule({
axios: serviceRoleAxiosClient,
getSocket,
appId,
serverUrl,
token,
}),
appLogs: createAppLogsModule(serviceRoleAxiosClient, appId),
cleanup: () => {
if (socket) {
socket.disconnect();
}
},
};
// If authentication is required, verify token and redirect to login if needed
if (requiresAuth && typeof window !== "undefined") {
// We perform this check asynchronously to not block client creation
setTimeout(async () => {
try {
const isAuthenticated = await userModules.auth.isAuthenticated();
if (!isAuthenticated) {
userModules.auth.redirectToLogin(window.location.href);
}
}
catch (error) {
console.error("Authentication check failed:", error);
userModules.auth.redirectToLogin(window.location.href);
}
}, 0);
}
// Assemble and return the client
const client = {
...userModules,
/**
* Sets a new authentication token for all subsequent requests.
*
* @param newToken - The new authentication token
*
* @example
* ```typescript
* // Update token after login
* const { access_token } = await base44.auth.loginViaEmailPassword(
* 'user@example.com',
* 'password'
* );
* base44.setToken(access_token);
* ```
*/
setToken(newToken) {
userModules.auth.setToken(newToken);
if (socket) {
socket.updateConfig({
token: newToken,
});
}
socketConfig.token = newToken;
},
/**
* Gets the current client configuration.
*
* @internal
*/
getConfig() {
return {
serverUrl,
appId,
requiresAuth,
};
},
/**
* Provides access to service role modules.
*
* Service role authentication provides elevated permissions for backend operations. Unlike user authentication, which is scoped to a specific user's permissions, service role authentication has access to the data and operations available to the app's admin.
*
* @throws {Error} When accessed without providing a serviceToken during client creation.
*
* @example
* ```typescript
* const base44 = createClient({
* appId: 'my-app-id',
* serviceToken: 'service-role-token'
* });
*
* // Also access a module with elevated permissions
* const allUsers = await base44.asServiceRole.entities.User.list();
* ```
*/
get asServiceRole() {
if (!serviceToken) {
throw new Error("Service token is required to use asServiceRole. Please provide a serviceToken when creating the client.");
}
return serviceRoleModules;
},
};
return client;
}
/**
* Creates a Base44 client from an HTTP request.
*
* This function is designed for use in Base44-hosted backend functions. For frontends and external backends, use {@linkcode createClient | createClient()} instead.
*
* When used in a Base44-hosted backend function, `createClientFromRequest()` automatically extracts authentication tokens from the request headers that Base44 injects when forwarding requests. The returned client includes service role access using `base44.asServiceRole`, which provides admin-level permissions.
*
* To learn more about the Base44 client, see {@linkcode createClient | createClient()}.
*
* @param request - The incoming HTTP request object containing Base44 authentication headers.
* @returns A configured Base44 client instance with authentication from the incoming request.
*
* @example
* ```typescript
* // User authentication in backend function
* import { createClientFromRequest } from 'npm:@base44/sdk';
*
* Deno.serve(async (req) => {
* try {
* const base44 = createClientFromRequest(req);
* const user = await base44.auth.me();
*
* if (!user) {
* return Response.json({ error: 'Unauthorized' }, { status: 401 });
* }
*
* // Access user's data
* const userOrders = await base44.entities.Orders.filter({ userId: user.id });
* return Response.json({ orders: userOrders });
* } catch (error) {
* return Response.json({ error: error.message }, { status: 500 });
* }
* });
* ```
*
* @example
* ```typescript
* // Service role authentication in backend function
* import { createClientFromRequest } from 'npm:@base44/sdk';
*
* Deno.serve(async (req) => {
* try {
* const base44 = createClientFromRequest(req);
*
* // Access admin data with service role permissions
* const recentOrders = await base44.asServiceRole.entities.Orders.list('-created_at', 50);
*
* return Response.json({ orders: recentOrders });
* } catch (error) {
* return Response.json({ error: error.message }, { status: 500 });
* }
* });
* ```
*
*/
export function createClientFromRequest(request) {
const authHeader = request.headers.get("Authorization");
const serviceRoleAuthHeader = request.headers.get("Base44-Service-Authorization");
const appId = request.headers.get("Base44-App-Id");
const serverUrlHeader = request.headers.get("Base44-Api-Url");
const functionsVersion = request.headers.get("Base44-Functions-Version");
const stateHeader = request.headers.get("Base44-State");
if (!appId) {
throw new Error("Base44-App-Id header is required, but is was not found on the request");
}
// Validate authorization header formats
let serviceRoleToken;
let userToken;
if (serviceRoleAuthHeader !== null) {
if (serviceRoleAuthHeader === "" ||
!serviceRoleAuthHeader.startsWith("Bearer ") ||
serviceRoleAuthHeader.split(" ").length !== 2) {
throw new Error('Invalid authorization header format. Expected "Bearer <token>"');
}
serviceRoleToken = serviceRoleAuthHeader.split(" ")[1];
}
if (authHeader !== null) {
if (authHeader === "" ||
!authHeader.startsWith("Bearer ") ||
authHeader.split(" ").length !== 2) {
throw new Error('Invalid authorization header format. Expected "Bearer <token>"');
}
userToken = authHeader.split(" ")[1];
}
// Prepare additional headers to propagate
const additionalHeaders = {};
if (stateHeader) {
additionalHeaders["Base44-State"] = stateHeader;
}
return createClient({
serverUrl: serverUrlHeader || "https://base44.app",
appId,
token: userToken,
serviceToken: serviceRoleToken,
functionsVersion: functionsVersion !== null && functionsVersion !== void 0 ? functionsVersion : undefined,
headers: additionalHeaders,
});
}
+144
View File
@@ -0,0 +1,144 @@
import type { EntitiesModule } from "./modules/entities.types.js";
import type { IntegrationsModule } from "./modules/integrations.types.js";
import type { AuthModule } from "./modules/auth.types.js";
import type { SsoModule } from "./modules/sso.types.js";
import type { ConnectorsModule, UserConnectorsModule } from "./modules/connectors.types.js";
import type { FunctionsModule } from "./modules/functions.types.js";
import type { AgentsModule } from "./modules/agents.types.js";
import type { AppLogsModule } from "./modules/app-logs.types.js";
import type { AnalyticsModule } from "./modules/analytics.types.js";
/**
* Options for creating a Base44 client.
*/
export interface CreateClientOptions {
/**
* Optional error handler that will be called whenever an API error occurs.
*/
onError?: (error: Error) => void;
}
/**
* Configuration for creating a Base44 client.
*/
export interface CreateClientConfig {
/**
* The Base44 server URL.
*
* You don't need to set this for production use. The SDK defaults to `https://base44.app`.
*
* Set this when using a local development server to point SDK requests at your local machine instead of the hosted backend.
*
* @defaultValue `"https://base44.app"`
*/
serverUrl?: string;
/**
* The base URL of the app, which is used for login redirects.
* @internal
*/
appBaseUrl?: string;
/**
* The Base44 app ID.
*
* You can find the `appId` in the browser URL when you're in the app editor.
* It's the string between `/apps/` and `/editor/`.
*/
appId: string;
/**
* User authentication token. Used to authenticate as a specific user.
*
* Inside Base44 apps, the token is managed automatically. For external apps, use auth methods like {@linkcode AuthModule.loginViaEmailPassword | loginViaEmailPassword()} which set the token automatically.
*/
token?: string;
/**
* Service role authentication token. Provides elevated permissions to access data available to the app's admin. Only available in Base44-hosted backend functions. Automatically added to client's created using {@linkcode createClientFromRequest | createClientFromRequest()}.
* @internal
*/
serviceToken?: string;
/**
* Whether authentication is required. If true, redirects to login if not authenticated.
* @internal
*/
requiresAuth?: boolean;
/**
* Version string for functions API.
* @internal
*/
functionsVersion?: string;
/**
* Additional headers to include in API requests.
* @internal
*/
headers?: Record<string, string>;
/**
* Additional client options.
*/
options?: CreateClientOptions;
}
/**
* The Base44 client instance.
*
* Provides access to all SDK modules for interacting with the app.
*/
export interface Base44Client {
/** {@link AgentsModule | Agents module} for managing AI agent conversations. */
agents: AgentsModule;
/** {@link AnalyticsModule | Analytics module} for tracking custom events in your app. */
analytics: AnalyticsModule;
/** {@link AppLogsModule | App logs module} for tracking app usage. */
appLogs: AppLogsModule;
/** {@link AuthModule | Auth module} for user authentication and management. */
auth: AuthModule;
/** {@link UserConnectorsModule | Connectors module} for app-user OAuth flows. */
connectors: UserConnectorsModule;
/** {@link EntitiesModule | Entities module} for CRUD operations on your data models. */
entities: EntitiesModule;
/** {@link FunctionsModule | Functions module} for invoking custom backend functions. */
functions: FunctionsModule;
/** {@link IntegrationsModule | Integrations module} for calling pre-built integration endpoints. */
integrations: IntegrationsModule;
/** Cleanup function to disconnect WebSocket connections. Call when you're done with the client. */
cleanup: () => void;
/**
* Sets a new authentication token for all subsequent requests.
*
* Updates the token for both HTTP requests and WebSocket connections.
*
* @param newToken - The new authentication token.
*/
setToken(newToken: string): void;
/**
* Gets the current client configuration.
* @internal
*/
getConfig(): {
serverUrl: string;
appId: string;
requiresAuth: boolean;
};
/**
* Provides access to supported modules with elevated permissions.
*
* Service role authentication provides elevated permissions for backend operations. Unlike user authentication, which is scoped to a specific user's permissions, service role authentication has access to the data and operations available to the app's admin.
*
* @throws {Error} When accessed without providing a serviceToken during client creation
*/
readonly asServiceRole: {
/** {@link AgentsModule | Agents module} with elevated permissions. */
agents: AgentsModule;
/** {@link AppLogsModule | App logs module} with elevated permissions. */
appLogs: AppLogsModule;
/** {@link ConnectorsModule | Connectors module} for OAuth token retrieval. */
connectors: ConnectorsModule;
/** {@link EntitiesModule | Entities module} with elevated permissions. */
entities: EntitiesModule;
/** {@link FunctionsModule | Functions module} with elevated permissions. */
functions: FunctionsModule;
/** {@link IntegrationsModule | Integrations module} with elevated permissions. */
integrations: IntegrationsModule;
/** {@link SsoModule | SSO module} for generating SSO tokens.
* @internal
*/
sso: SsoModule;
/** Cleanup function to disconnect WebSocket connections. */
cleanup: () => void;
};
}
+1
View File
@@ -0,0 +1 @@
export {};
+16
View File
@@ -0,0 +1,16 @@
import { createClient, createClientFromRequest, type Base44Client, type CreateClientConfig, type CreateClientOptions } from "./client.js";
import { Base44Error, type Base44ErrorJSON } from "./utils/axios-client.js";
import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl } from "./utils/auth-utils.js";
export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
export type { Base44Client, CreateClientConfig, CreateClientOptions, Base44ErrorJSON, };
export * from "./types.js";
export type { DeleteManyResult, DeleteResult, EntitiesModule, EntityFilterOperators, EntityFilterQuery, EntityFilterValue, EntityHandler, EntityRecord, EntityTypeRegistry, ImportResult, RealtimeEventType, RealtimeEvent, RealtimeCallback, SortField, UpdateManyResult, } from "./modules/entities.types.js";
export type { AuthModule, LoginResponse, RegisterParams, VerifyOtpParams, ChangePasswordParams, ResetPasswordParams, User, } from "./modules/auth.types.js";
export type { IntegrationsModule, IntegrationEndpointFunction, CoreIntegrations, InvokeLLMParams, GenerateImageParams, GenerateImageResult, UploadFileParams, UploadFileResult, SendEmailParams, SendEmailResult, ExtractDataFromUploadedFileParams, ExtractDataFromUploadedFileResult, UploadPrivateFileParams, UploadPrivateFileResult, CreateFileSignedUrlParams, CreateFileSignedUrlResult, } from "./modules/integrations.types.js";
export type { FunctionsModule, FunctionName, FunctionNameRegistry, } from "./modules/functions.types.js";
export type { AgentsModule, AgentName, AgentNameRegistry, AgentConversation, AgentMessage, AgentMessageReasoning, AgentMessageToolCall, AgentMessageUsage, AgentMessageCustomContext, AgentMessageMetadata, CreateConversationParams, } from "./modules/agents.types.js";
export type { AppLogsModule } from "./modules/app-logs.types.js";
export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
export type { ConnectorsModule, UserConnectorsModule, } from "./modules/connectors.types.js";
export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
export type { GetAccessTokenOptions, SaveAccessTokenOptions, RemoveAccessTokenOptions, GetLoginUrlOptions, } from "./utils/auth-utils.types.js";
+5
View File
@@ -0,0 +1,5 @@
import { createClient, createClientFromRequest, } from "./client.js";
import { Base44Error } from "./utils/axios-client.js";
import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, } from "./utils/auth-utils.js";
export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
export * from "./types.js";
+2
View File
@@ -0,0 +1,2 @@
import { AgentsModule, AgentsModuleConfig } from "./agents.types.js";
export declare function createAgentsModule({ axios, getSocket, appId, serverUrl, token, }: AgentsModuleConfig): AgentsModule;
+89
View File
@@ -0,0 +1,89 @@
import { getAccessToken } from "../utils/auth-utils.js";
export function createAgentsModule({ axios, getSocket, appId, serverUrl, token, }) {
const baseURL = `/apps/${appId}/agents`;
// Track active conversations
const currentConversations = {};
const getConversations = () => {
return axios.get(`${baseURL}/conversations`);
};
const getConversation = (conversationId) => {
return axios.get(`${baseURL}/conversations/${conversationId}`);
};
const listConversations = (filterParams) => {
return axios.get(`${baseURL}/conversations`, {
params: filterParams,
});
};
const createConversation = (conversation) => {
return axios.post(`${baseURL}/conversations`, conversation);
};
const addMessage = async (conversation, message) => {
return axios.post(`${baseURL}/conversations/v2/${conversation.id}/messages`, message);
};
const subscribeToConversation = (conversationId, onUpdate) => {
const room = `/agent-conversations/${conversationId}`;
const socket = getSocket();
// Store the promise for initial conversation state
const conversationPromise = getConversation(conversationId).then((conv) => {
currentConversations[conversationId] = conv;
return conv;
});
return socket.subscribeToRoom(room, {
connect: () => { },
update_model: async ({ data: jsonStr }) => {
const data = JSON.parse(jsonStr);
if (data._message) {
// Wait for initial conversation to be loaded
await conversationPromise;
const message = data._message;
// Update shared conversation state
const currentConversation = currentConversations[conversationId];
if (currentConversation) {
const messages = currentConversation.messages || [];
const existingIndex = messages.findIndex((m) => m.id === message.id);
const updatedMessages = existingIndex !== -1
? messages.map((m, i) => (i === existingIndex ? message : m))
: [...messages, message];
currentConversations[conversationId] = {
...currentConversation,
messages: updatedMessages,
};
onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(currentConversations[conversationId]);
}
}
},
});
};
const getWhatsAppConnectURL = (agentName) => {
const baseUrl = `${serverUrl}/api/apps/${appId}/agents/${encodeURIComponent(agentName)}/whatsapp`;
const accessToken = token !== null && token !== void 0 ? token : getAccessToken();
if (accessToken) {
return `${baseUrl}?token=${accessToken}`;
}
else {
// No token - URL will redirect to login automatically
return baseUrl;
}
};
const getTelegramConnectURL = (agentName) => {
const baseUrl = `${serverUrl}/api/apps/${appId}/agents/${encodeURIComponent(agentName)}/telegram`;
const accessToken = token !== null && token !== void 0 ? token : getAccessToken();
if (accessToken) {
return `${baseUrl}?token=${accessToken}`;
}
else {
// No token - URL will redirect to login automatically
return baseUrl;
}
};
return {
getConversations,
getConversation,
listConversations,
createConversation,
addMessage,
subscribeToConversation,
getWhatsAppConnectURL,
getTelegramConnectURL,
};
}
+397
View File
@@ -0,0 +1,397 @@
import { AxiosInstance } from "axios";
import { RoomsSocket } from "../utils/socket-utils.js";
import { ModelFilterParams } from "../types.js";
/**
* Registry of agent names. The [`types generate`](/developers/references/cli/commands/types-generate) command fills this registry, then [`AgentName`](#agentname) resolves to a union of the keys.
*/
export interface AgentNameRegistry {
}
/**
* Union of all agent names from the [`AgentNameRegistry`](#agentnameregistry). Defaults to `string` when no types have been generated.
*
* @example
* ```typescript
* // Using generated agent name types
* // With generated types, you get autocomplete on agent names
* const conversation = await base44.agents.createConversation({ agent_name: 'SupportBot' });
* ```
*/
export type AgentName = keyof AgentNameRegistry extends never ? string : keyof AgentNameRegistry;
/**
* Reasoning information for an agent message.
*
* Contains details about the agent's reasoning process when generating a response.
*/
export interface AgentMessageReasoning {
/** When reasoning started. */
start_date: string;
/** When reasoning ended. */
end_date?: string;
/** Reasoning content. */
content: string;
}
/**
* A tool call made by the agent.
*
* Represents a function or tool that the agent invoked during message generation.
*/
export interface AgentMessageToolCall {
/** Tool call ID. */
id: string;
/** Name of the tool called. */
name: string;
/** Arguments passed to the tool as JSON string. */
arguments_string: string;
/** Status of the tool call. */
status: "running" | "success" | "error" | "stopped" | "waiting_for_user_input";
/** Results from the tool call. */
results?: string;
}
/**
* Token usage statistics for an agent message.
*
* Tracks the number of tokens consumed when generating the message.
*/
export interface AgentMessageUsage {
/** Number of tokens in the prompt. */
prompt_tokens?: number;
/** Number of tokens in the completion. */
completion_tokens?: number;
}
/**
* Custom context provided with an agent message.
*
* Additional contextual information that can be passed to the agent.
*/
export interface AgentMessageCustomContext {
/** Context message. */
message: string;
/** Associated data for the context. */
data: Record<string, any>;
/** Type of context. */
type: string;
}
/**
* Metadata about when and by whom a message was created.
*/
export interface AgentMessageMetadata {
/** When the message was created. */
created_date: string;
/** Email of the user who created the message. */
created_by_email: string;
/** Full name of the user who created the message. */
created_by_full_name: string;
}
/**
* An agent conversation containing messages exchanged with an AI agent.
*/
export interface AgentConversation {
/** Unique identifier for the conversation. */
id: string;
/** App ID. */
app_id: string;
/** Name of the agent in this conversation. */
agent_name: string;
/** ID of the user who created the conversation. */
created_by_id: string;
/** When the conversation was created. */
created_date: string;
/** When the conversation was last updated. */
updated_date: string;
/** Array of messages in the conversation. */
messages: AgentMessage[];
/** Optional metadata associated with the conversation. */
metadata?: Record<string, any>;
}
/**
* A message in an agent conversation.
*/
export interface AgentMessage {
/** Unique identifier for the message. */
id: string;
/** Role of the message sender. */
role: "user" | "assistant" | "system";
/** When the message was created. */
created_date: string;
/** When the message was last updated. */
updated_date: string;
/** Optional reasoning information for the message. */
reasoning?: AgentMessageReasoning | null;
/** Message content. */
content?: string | Record<string, any>;
/** URLs to files attached to the message. */
file_urls?: string[];
/** Tool calls made by the agent. */
tool_calls?: AgentMessageToolCall[];
/** Token usage statistics. */
usage?: AgentMessageUsage;
/** Whether the message is hidden from the user. */
hidden?: boolean;
/** Custom context provided with the message. */
custom_context?: AgentMessageCustomContext[];
/** Model used to generate the message. */
model?: string;
/** Checkpoint ID for the message. */
checkpoint_id?: string;
/** Metadata about when and by whom the message was created. */
metadata?: AgentMessageMetadata;
/** Additional custom parameters for the message. */
additional_message_params?: Record<string, any>;
}
/**
* Parameters for creating a new conversation.
*/
export interface CreateConversationParams {
/** The name of the agent to create a conversation with. */
agent_name: AgentName;
/** Optional metadata to attach to the conversation. */
metadata?: Record<string, any>;
}
/**
* Configuration for creating the agents module.
* @internal
*/
export interface AgentsModuleConfig {
/** Axios instance for HTTP requests */
axios: AxiosInstance;
/** Function to get WebSocket instance for realtime updates (lazy initialization) */
getSocket: () => ReturnType<typeof RoomsSocket>;
/** App ID */
appId: string;
/** Server URL */
serverUrl?: string;
/** Authentication token */
token?: string;
}
/**
* Agents module for managing AI agent conversations.
*
* This module provides methods to create and manage conversations with AI agents,
* send messages, and subscribe to realtime updates. Conversations can be used
* for chat interfaces, support systems, or any interactive AI app.
*
* ## Key Features
*
* The agents module enables you to:
*
* - **Create conversations** with agents defined in the app.
* - **Send messages** from users to agents and receive AI-generated responses.
* - **Retrieve conversations** individually or as filtered lists with sorting and pagination.
* - **Subscribe to realtime updates** using WebSocket connections to receive instant notifications when new messages arrive.
* - **Attach metadata** to conversations for tracking context, categories, priorities, or linking to external systems.
* - **Generate WhatsApp connection URLs** for users to interact with agents through WhatsApp.
*
* ## Conversation Structure
*
* The agents module operates with a two-level hierarchy:
*
* 1. **Conversations**: Top-level containers that represent a dialogue with a specific agent. Each conversation has a unique ID, is associated with an agent by name, and belongs to the user who created it. Conversations can include optional metadata for tracking app-specific context like ticket IDs, categories, or custom fields.
*
* 2. **Messages**: Individual exchanges within a conversation. Each message has a role, content, and optional metadata like token usage, tool calls, file attachments, and reasoning information. Messages are stored as an array within their parent conversation.
*
* ## Authentication Modes
*
* This module is available to use with a client in all authentication modes:
*
* - **Anonymous or User authentication** (`base44.agents`): Access is scoped to the current user's permissions. Users must be authenticated to create and access conversations.
* - **Service role authentication** (`base44.asServiceRole.agents`): Operations have elevated admin-level permissions. Can access all conversations that the app's admin role has access to.
*
* ## Generated Types
*
* If you're working in a TypeScript project, you can generate types from your agents to get autocomplete on agent names when creating conversations or subscribing to updates. See the [Dynamic Types](/developers/references/sdk/getting-started/dynamic-types) guide to get started.
*/
export interface AgentsModule {
/**
* Gets all conversations from all agents in the app.
*
* Retrieves all conversations. Use {@linkcode listConversations | listConversations()} to filter which conversations are returned, apply sorting, or paginate results. Use {@linkcode getConversation | getConversation()} to retrieve a specific conversation by ID.
*
* @returns Promise resolving to an array of conversations.
*
* @example
* ```typescript
* // Get all conversations
* const conversations = await base44.agents.getConversations();
* console.log(`Total conversations: ${conversations.length}`);
* ```
*
* @see {@linkcode listConversations | listConversations()} for filtering, sorting, and pagination
* @see {@linkcode getConversation | getConversation()} for retrieving a specific conversation by ID
*/
getConversations(): Promise<AgentConversation[]>;
/**
* Gets a specific conversation by ID.
*
* Retrieves a single conversation using its unique identifier. To retrieve
* all conversations, use {@linkcode getConversations | getConversations()}. To filter, sort, or paginate conversations, use {@linkcode listConversations | listConversations()}.
*
* This function returns the complete stored conversation including full tool call results, even for large responses.
*
* @param conversationId - The unique identifier of the conversation.
* @returns Promise resolving to the conversation, or undefined if not found.
*
* @example
* ```typescript
* // Get a specific conversation by ID
* const conversation = await base44.agents.getConversation('conv-123');
* if (conversation) {
* console.log(`Conversation has ${conversation.messages.length} messages`);
* }
* ```
*
* @see {@linkcode getConversations | getConversations()} for retrieving all conversations
* @see {@linkcode listConversations | listConversations()} for filtering and sorting conversations
*/
getConversation(conversationId: string): Promise<AgentConversation | undefined>;
/**
* Lists conversations with filtering, sorting, and pagination.
*
* Provides querying capabilities including filtering by fields, sorting, pagination, and field selection. For cases where you need all conversations without filtering, use {@linkcode getConversations | getConversations()}. To retrieve a specific conversation by ID, use {@linkcode getConversation | getConversation()}.
*
* @param filterParams - Filter parameters for querying conversations.
* @returns Promise resolving to an array of filtered conversations.
*
* @example
* ```typescript
* // List recent conversations with pagination
* const recentConversations = await base44.agents.listConversations({
* limit: 10,
* sort: '-created_date'
* });
* ```
*
* @example
* ```typescript
* // Filter by agent and metadata
* const supportConversations = await base44.agents.listConversations({
* q: {
* agent_name: 'support-agent',
* 'metadata.priority': 'high'
* },
* sort: '-created_date',
* limit: 20
* });
* ```
*
* @see {@linkcode getConversations | getConversations()} for retrieving all conversations without filtering
* @see {@linkcode getConversation | getConversation()} for retrieving a specific conversation by ID
*/
listConversations(filterParams: ModelFilterParams): Promise<AgentConversation[]>;
/**
* Creates a new conversation with an agent.
*
* @param conversation - Conversation details including agent name and optional metadata.
* @returns Promise resolving to the created conversation.
*
* @example
* ```typescript
* // Create a new conversation with metadata
* const conversation = await base44.agents.createConversation({
* agent_name: 'support-agent',
* metadata: {
* order_id: 'ORD-789',
* product_id: 'PROD-456',
* category: 'technical-support'
* }
* });
* console.log(`Created conversation: ${conversation.id}`);
* ```
*/
createConversation(conversation: CreateConversationParams): Promise<AgentConversation>;
/**
* Adds a message to a conversation.
*
* Sends a message to the agent and updates the conversation. This method
* also updates the realtime socket to notify any subscribers.
*
* @param conversation - The conversation to add the message to.
* @param message - The message to add.
* @returns Promise resolving to the created message.
*
* @example
* ```typescript
* // Send a message to the agent
* const message = await base44.agents.addMessage(conversation, {
* role: 'user',
* content: 'Hello, I need help with my order #12345'
* });
* console.log(`Message sent with ID: ${message.id}`);
* ```
*/
addMessage(conversation: AgentConversation, message: Partial<AgentMessage>): Promise<AgentMessage>;
/**
* Subscribes to realtime updates for a conversation.
*
* Establishes a WebSocket connection to receive instant updates when new
* messages are added to the conversation. Returns an unsubscribe function
* to clean up the connection.
*
* <Note>
* When receiving messages through this function, tool call data is truncated for efficiency. The `arguments_string` is limited to 500 characters and `results` to 50 characters. The complete tool call data is always saved in storage and can be retrieved by calling {@linkcode getConversation | getConversation()} after the message completes.
* </Note>
*
* @param conversationId - The conversation ID to subscribe to.
* @param onUpdate - Callback function called when the conversation is updated. The callback receives a conversation object with the following properties:
* - `id`: Unique identifier for the conversation.
* - `agent_name`: Name of the agent in this conversation.
* - `created_date`: ISO 8601 timestamp of when the conversation was created.
* - `updated_date`: ISO 8601 timestamp of when the conversation was last updated.
* - `messages`: Array of messages in the conversation. Each message includes `id`, `role` (`'user'`, `'assistant'`, or `'system'`), `content`, `created_date`, and optionally `tool_calls`, `reasoning`, `file_urls`, and `usage`.
* - `metadata`: Optional metadata associated with the conversation.
* @returns Unsubscribe function to stop receiving updates.
*
* @example
* ```typescript
* // Subscribe to realtime updates
* const unsubscribe = base44.agents.subscribeToConversation(
* 'conv-123',
* (updatedConversation) => {
* const latestMessage = updatedConversation.messages[updatedConversation.messages.length - 1];
* console.log('New message:', latestMessage.content);
* }
* );
*
* // Later, clean up the subscription
* unsubscribe();
* ```
*/
subscribeToConversation(conversationId: string, onUpdate?: (conversation: AgentConversation) => void): () => void;
/**
* Gets WhatsApp connection URL for an agent.
*
* Generates a URL that users can use to connect with the agent through WhatsApp.
* The URL includes authentication if a token is available.
*
* @param agentName - The name of the agent.
* @returns WhatsApp connection URL.
*
* @example
* ```typescript
* // Get WhatsApp connection URL
* const whatsappUrl = base44.agents.getWhatsAppConnectURL('support-agent');
* console.log(`Connect through WhatsApp: ${whatsappUrl}`);
* // User can open this URL to start a WhatsApp conversation
* ```
*/
getWhatsAppConnectURL(agentName: AgentName): string;
/**
* Gets Telegram connection URL for an agent.
*
* Generates a URL that users can use to connect with the agent through Telegram.
* The URL includes authentication if a token is available. When the user opens
* this URL, they are redirected to the agent's Telegram bot with an activation
* code that securely links their account.
*
* @param agentName - The name of the agent.
* @returns Telegram connection URL.
*
* @example
* ```typescript
* // Get Telegram connection URL
* const telegramUrl = base44.agents.getTelegramConnectURL('support-agent');
* console.log(`Connect through Telegram: ${telegramUrl}`);
* // User can open this URL to start a Telegram conversation
* ```
*/
getTelegramConnectURL(agentName: AgentName): string;
}
+1
View File
@@ -0,0 +1 @@
export {};
+20
View File
@@ -0,0 +1,20 @@
import { AxiosInstance } from "axios";
import { TrackEventParams, AnalyticsModuleOptions } from "./analytics.types";
import type { AuthModule } from "./auth.types";
export declare const USER_HEARTBEAT_EVENT_NAME = "__user_heartbeat_event__";
export declare const ANALYTICS_INITIALIZATION_EVENT_NAME = "__initialization_event__";
export declare const ANALYTICS_SESSION_DURATION_EVENT_NAME = "__session_duration_event__";
export declare const ANALYTICS_CONFIG_ENABLE_URL_PARAM_KEY = "analytics-enable";
export declare const ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY = "base44_analytics_session_id";
export interface AnalyticsModuleArgs {
axiosClient: AxiosInstance;
serverUrl: string;
appId: string;
userAuthModule: AuthModule;
}
export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, userAuthModule, }: AnalyticsModuleArgs) => {
track: (params: TrackEventParams) => void;
cleanup: () => void;
};
export declare function getAnalyticsConfigFromUrlParams(): AnalyticsModuleOptions | undefined;
export declare function getAnalyticsSessionId(): string;
+277
View File
@@ -0,0 +1,277 @@
import { getSharedInstance } from "../utils/sharedInstance.js";
import { generateUuid } from "../utils/common.js";
export const USER_HEARTBEAT_EVENT_NAME = "__user_heartbeat_event__";
export const ANALYTICS_INITIALIZATION_EVENT_NAME = "__initialization_event__";
export const ANALYTICS_SESSION_DURATION_EVENT_NAME = "__session_duration_event__";
export const ANALYTICS_CONFIG_ENABLE_URL_PARAM_KEY = "analytics-enable";
export const ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY = "base44_analytics_session_id";
const defaultConfiguration = {
// default to enabled //
enabled: true,
maxQueueSize: 1000,
throttleTime: 1000,
batchSize: 30,
heartBeatInterval: 60 * 1000,
};
///////////////////////////////////////////////
//// shared queue for analytics events ////
///////////////////////////////////////////////
const ANALYTICS_SHARED_STATE_NAME = "analytics";
// shared state//
const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, () => ({
requestsQueue: [],
isProcessing: false,
isHeartBeatProcessing: false,
wasInitializationTracked: false,
sessionContext: null,
sessionStartTime: null,
config: {
...defaultConfiguration,
...getAnalyticsConfigFromUrlParams(),
},
}));
export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthModule, }) => {
var _a;
// prevent overflow of events //
const { maxQueueSize, throttleTime, batchSize } = analyticsSharedState.config;
if (!((_a = analyticsSharedState.config) === null || _a === void 0 ? void 0 : _a.enabled)) {
return {
track: () => { },
cleanup: () => { },
};
}
let clearHeartBeatProcessor = undefined;
const trackBatchUrl = `${serverUrl}/api/apps/${appId}/analytics/track/batch`;
const batchRequestFallback = async (events) => {
await axiosClient.request({
method: "POST",
url: `/apps/${appId}/analytics/track/batch`,
data: { events },
});
};
// currently disabled, until fully tested //
const beaconRequest = (events) => {
try {
const beaconPayload = JSON.stringify({ events });
const blob = new Blob([beaconPayload], { type: "application/json" });
return (typeof navigator === "undefined" ||
beaconPayload.length > 60000 ||
!navigator.sendBeacon(trackBatchUrl, blob));
}
catch (_a) {
return false;
}
};
const flush = async (eventsData, options = {}) => {
if (eventsData.length === 0)
return;
const sessionContext_ = await getSessionContext(userAuthModule);
const events = eventsData.map(transformEventDataToApiRequestData(sessionContext_));
try {
if (!options.isBeacon || !beaconRequest(events)) {
await batchRequestFallback(events);
}
}
catch (_a) {
// do nothing
}
};
const startProcessing = () => {
startAnalyticsProcessor(flush, {
throttleTime,
batchSize,
});
};
const track = (params) => {
if (analyticsSharedState.requestsQueue.length >= maxQueueSize) {
return;
}
const intrinsicData = getEventIntrinsicData();
analyticsSharedState.requestsQueue.push({
...params,
...intrinsicData,
});
startProcessing();
};
const onDocVisible = () => {
startAnalyticsProcessor(flush, {
throttleTime,
batchSize,
});
clearHeartBeatProcessor = startHeartBeatProcessor(track);
setSessionDurationTimerStart();
};
const onDocHidden = () => {
stopAnalyticsProcessor();
clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
trackSessionDurationEvent(track);
// flush entire queue on visibility change and hope for the best //
const eventsData = analyticsSharedState.requestsQueue.splice(0);
flush(eventsData, { isBeacon: true });
};
const onVisibilityChange = () => {
if (typeof window === "undefined")
return;
if (document.visibilityState === "hidden") {
onDocHidden();
}
else if (document.visibilityState === "visible") {
onDocVisible();
}
};
const cleanup = () => {
stopAnalyticsProcessor();
clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
if (typeof window !== "undefined") {
window.removeEventListener("visibilitychange", onVisibilityChange);
}
};
// start the flusing process ///
startProcessing();
// start the heart beat processor //
clearHeartBeatProcessor = startHeartBeatProcessor(track);
// track the referrer event //
trackInitializationEvent(track);
// start the visibility change listener //
if (typeof window !== "undefined") {
window.addEventListener("visibilitychange", onVisibilityChange);
}
return {
track,
cleanup,
};
};
function stopAnalyticsProcessor() {
analyticsSharedState.isProcessing = false;
}
async function startAnalyticsProcessor(handleTrack, options) {
if (analyticsSharedState.isProcessing) {
// only one instance of the analytics processor can be running at a time //
return;
}
analyticsSharedState.isProcessing = true;
const { throttleTime = 1000, batchSize = 30 } = options !== null && options !== void 0 ? options : {};
while (analyticsSharedState.isProcessing &&
analyticsSharedState.requestsQueue.length > 0) {
const requests = analyticsSharedState.requestsQueue.splice(0, batchSize);
requests.length && (await handleTrack(requests));
await new Promise((resolve) => setTimeout(resolve, throttleTime));
}
analyticsSharedState.isProcessing = false;
}
function startHeartBeatProcessor(track) {
var _a;
if (analyticsSharedState.isHeartBeatProcessing ||
((_a = analyticsSharedState.config.heartBeatInterval) !== null && _a !== void 0 ? _a : 0) < 10) {
return () => { };
}
analyticsSharedState.isHeartBeatProcessing = true;
const interval = setInterval(() => {
track({ eventName: USER_HEARTBEAT_EVENT_NAME });
}, analyticsSharedState.config.heartBeatInterval);
return () => {
clearInterval(interval);
analyticsSharedState.isHeartBeatProcessing = false;
};
}
function trackInitializationEvent(track) {
if (typeof window === "undefined" ||
analyticsSharedState.wasInitializationTracked) {
return;
}
analyticsSharedState.wasInitializationTracked = true;
track({
eventName: ANALYTICS_INITIALIZATION_EVENT_NAME,
properties: {
referrer: document === null || document === void 0 ? void 0 : document.referrer,
},
});
}
function setSessionDurationTimerStart() {
if (typeof window === "undefined" ||
analyticsSharedState.sessionStartTime !== null) {
return;
}
analyticsSharedState.sessionStartTime = new Date().toISOString();
}
function trackSessionDurationEvent(track) {
if (typeof window === "undefined" ||
analyticsSharedState.sessionStartTime === null)
return;
const sessionDuration = new Date().getTime() -
new Date(analyticsSharedState.sessionStartTime).getTime();
analyticsSharedState.sessionStartTime = null;
track({
eventName: ANALYTICS_SESSION_DURATION_EVENT_NAME,
properties: { sessionDuration },
});
}
function getEventIntrinsicData() {
return {
timestamp: new Date().toISOString(),
pageUrl: typeof window !== "undefined" ? window.location.pathname : null,
};
}
function transformEventDataToApiRequestData(sessionContext) {
return (eventData) => ({
event_name: eventData.eventName,
properties: eventData.properties,
timestamp: eventData.timestamp,
page_url: eventData.pageUrl,
...sessionContext,
});
}
let sessionContextPromise = null;
async function getSessionContext(userAuthModule) {
if (!analyticsSharedState.sessionContext) {
if (!sessionContextPromise) {
const sessionId = getAnalyticsSessionId();
sessionContextPromise = userAuthModule
.me()
.then((user) => ({
user_id: user.id,
session_id: sessionId,
}))
.catch(() => ({
user_id: null,
session_id: sessionId,
}));
}
analyticsSharedState.sessionContext = await sessionContextPromise;
}
return analyticsSharedState.sessionContext;
}
export function getAnalyticsConfigFromUrlParams() {
if (typeof window === "undefined")
return undefined;
const urlParams = new URLSearchParams(window.location.search);
const analyticsEnable = urlParams.get(ANALYTICS_CONFIG_ENABLE_URL_PARAM_KEY);
// if the url param is not set, return undefined //
if (analyticsEnable == null || !analyticsEnable.length)
return undefined;
// remove the url param from the url //
const newUrlParams = new URLSearchParams(window.location.search);
newUrlParams.delete(ANALYTICS_CONFIG_ENABLE_URL_PARAM_KEY);
const newUrl = window.location.pathname +
(newUrlParams.toString() ? "?" + newUrlParams.toString() : "");
window.history.replaceState({}, "", newUrl);
// return the config object //
return { enabled: analyticsEnable === "true" };
}
export function getAnalyticsSessionId() {
if (typeof window === "undefined") {
return generateUuid();
}
try {
const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
if (!sessionId) {
const newSessionId = generateUuid();
localStorage.setItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY, newSessionId);
return newSessionId;
}
return sessionId;
}
catch (_a) {
return generateUuid();
}
}
+122
View File
@@ -0,0 +1,122 @@
/**
* Properties for analytics events.
*
* Key-value pairs with additional event data. Values can be strings, numbers, booleans, or null.
*/
export type TrackEventProperties = {
[key: string]: string | number | boolean | null | undefined;
};
/**
* Parameters for tracking an analytics event.
*/
export type TrackEventParams = {
/**
* Name of the event to track.
*
* Use descriptive names like `button_click`, `form_submit`, or `purchase_completed`.
*/
eventName: string;
/**
* Optional key-value pairs with additional event data.
*
* Values can be strings, numbers, booleans, or null.
*
* @example
* ```typescript
* base44.analytics.track({
* eventName: 'add_to_cart',
* properties: {
* product_id: 'prod_123',
* price: 29.99,
* quantity: 2
* }
* });
* ```
*/
properties?: TrackEventProperties;
};
export type TrackEventIntrinsicData = {
timestamp: string;
pageUrl?: string | null;
};
export type TrackEventData = {
properties?: TrackEventProperties;
eventName: string;
} & TrackEventIntrinsicData;
export type SessionContext = {
user_id?: string | null;
session_id?: string | null;
};
export type AnalyticsApiRequestData = {
event_name: string;
properties?: TrackEventProperties;
timestamp?: string;
page_url?: string | null;
} & SessionContext;
export type AnalyticsApiBatchRequest = {
method: "POST";
url: `/apps/${string}/analytics/track/batch`;
data: {
events: AnalyticsApiRequestData[];
};
};
export type AnalyticsModuleOptions = {
enabled?: boolean;
maxQueueSize?: number;
throttleTime?: number;
batchSize?: number;
heartBeatInterval?: number;
};
/**
* Analytics module for tracking custom events in your app.
*
* Use this module to track specific user actions. Track things like button clicks, form submissions, purchases, and feature usage.
*
* <Note> Analytics events tracked with this module appear as custom event cards in the [Analytics dashboard](/documentation/performance-and-seo/app-analytics).</Note>
*
* ## Best Practices
*
* When tracking events:
*
* - Choose clear, descriptive event names in snake_case like `signup_button_click` or `purchase_completed` rather than generic names like `click`.
* - Include relevant context in your properties such as identifiers like `product_id`, measurements like `price`, and flags like `is_first_purchase`.
*
* ## Authentication Modes
*
* This module is only available in user authentication mode (`base44.analytics`).
*/
export interface AnalyticsModule {
/**
* Tracks a custom event that appears as a card in your Analytics dashboard.
*
* Each unique event name becomes its own card showing total count and trends over time. This method returns immediately and events are sent in batches in the background.
*
* @param params - Event parameters.
* @param params.eventName - Name of the event. This becomes the card title in your dashboard. Use descriptive names like `'signup_button_click'` or `'purchase_completed'`.
* @param params.properties - Optional data to attach to the event. You can filter and analyze events by these properties in the dashboard.
*
* @example Track a button click
* ```typescript
* // Track a button click
* base44.analytics.track({
* eventName: 'signup_button_click'
* });
* ```
*
* @example Track with properties
* ```typescript
* // Track with properties
* base44.analytics.track({
* eventName: 'add_to_cart',
* properties: {
* product_id: 'prod_123',
* product_name: 'Premium Widget',
* price: 29.99,
* quantity: 2,
* is_first_purchase: true
* }
* });
* ```
*/
track(params: TrackEventParams): void;
}
+1
View File
@@ -0,0 +1 @@
export {};
+11
View File
@@ -0,0 +1,11 @@
import { AxiosInstance } from "axios";
import { AppLogsModule } from "./app-logs.types";
/**
* Creates the app logs module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @returns App logs module with methods for tracking and analyzing app usage
* @internal
*/
export declare function createAppLogsModule(axios: AxiosInstance, appId: string): AppLogsModule;
+27
View File
@@ -0,0 +1,27 @@
/**
* Creates the app logs module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @returns App logs module with methods for tracking and analyzing app usage
* @internal
*/
export function createAppLogsModule(axios, appId) {
const baseURL = `/app-logs/${appId}`;
return {
// Log user activity in the app
async logUserInApp(pageName) {
await axios.post(`${baseURL}/log-user-in-app/${pageName}`);
},
// Fetch app logs with optional parameters
async fetchLogs(params = {}) {
const response = await axios.get(baseURL, { params });
return response;
},
// Get app statistics
async getStats(params = {}) {
const response = await axios.get(`${baseURL}/stats`, { params });
return response;
},
};
}
+46
View File
@@ -0,0 +1,46 @@
/**
* App Logs module for tracking and analyzing app usage.
*
* This module provides a method to log user activity. The logs are reflected in the Analytics page in the app dashboard.
*
* ## Authentication Modes
*
* This module is available to use with a client in all authentication modes.
*/
export interface AppLogsModule {
/**
* Log user activity in the app.
*
* Records when a user visits a specific page or section of the app. Useful for tracking user navigation patterns and popular features. The logs are reflected in the Analytics page in the app dashboard.
*
* The specified page name doesn't have to be the name of an actual page in the app, it can be any string you want to use to track the activity.
*
* @param pageName - Name of the page or section being visited.
* @returns Promise that resolves when the log is recorded.
*
* @example
* ```typescript
* // Log page visit or feature usage
* await base44.appLogs.logUserInApp('home');
* await base44.appLogs.logUserInApp('features-section');
* await base44.appLogs.logUserInApp('button-click');
* ```
*/
logUserInApp(pageName: string): Promise<void>;
/**
* Fetch app logs with optional parameters.
*
* @param params - Optional query parameters for filtering logs.
* @returns Promise resolving to the logs data.
* @internal
*/
fetchLogs(params?: Record<string, any>): Promise<any>;
/**
* Get app statistics.
*
* @param params - Optional query parameters for filtering stats.
* @returns Promise resolving to the stats data.
* @internal
*/
getStats(params?: Record<string, any>): Promise<any>;
}
+1
View File
@@ -0,0 +1 @@
export {};
+142
View File
@@ -0,0 +1,142 @@
/**
* @internal
*/
export interface AppMessageContent {
content?: string;
file_urls?: string[];
custom_context?: unknown;
additional_message_params?: Record<string, unknown>;
[key: string]: unknown;
}
/**
* @internal
*/
export interface AppConversationMessage extends AppMessageContent {
id?: string | null;
role?: "user" | "assistant" | string;
}
/**
* @internal
*/
export interface AppConversationLike {
id?: string | null;
messages?: AppMessageContent[] | null;
model?: string;
functions_fail_silently?: boolean;
}
/**
* @internal
*/
export interface DenoProjectLike {
project_id: string;
project_name: string;
app_id: string;
deployment_name_to_info: Record<string, {
id: string;
code: string;
}>;
}
/**
* @internal
*/
export interface AppLike {
id?: string;
conversation?: AppConversationLike | null;
app_stage?: "pending" | "product_flows" | "ready" | string;
created_date?: string;
updated_date?: string;
created_by?: string;
organization_id?: string;
name?: string;
user_description?: string;
entities?: Record<string, any>;
additional_user_data_schema?: any;
pages?: {
[key: string]: string;
};
components: {
[key: string]: any;
};
layout?: string;
globals_css?: string;
agents?: Record<string, any>;
logo_url?: string;
slug?: string;
public_settings?: "private_with_login" | "public_with_login" | "public_without_login" | "workspace_with_login" | string;
is_blocked?: boolean;
github_repo_url?: string;
main_page?: string;
installable_integrations?: any;
backend_project?: DenoProjectLike;
last_deployed_at?: string;
is_remixable?: boolean;
remixed_from_app_id?: string;
hide_entity_created_by?: boolean;
platform_version?: number;
enable_username_password?: boolean;
auth_config?: AuthConfigLike;
status?: {
state?: string;
details?: any;
last_updated_date?: string;
};
custom_instructions?: any;
frozen_files?: string[];
deep_coding_mode?: boolean;
needs_to_add_diff?: boolean;
installed_integration_context_items?: any[];
model?: string;
is_starred?: boolean;
agents_enabled?: boolean;
categories?: string[];
functions?: any;
function_names?: string[];
user_entity?: UserEntityLike;
app_code_hash?: string;
has_backend_functions_enabled?: boolean;
}
/**
* @internal
*/
export interface UserLike {
id?: string | null;
}
/**
* @internal
*/
export interface UserEntityLike {
type: string;
name: string;
title?: string;
properties?: {
role?: {
type?: string;
description?: string;
enum?: ("admin" | "user" | string)[];
};
email?: {
type?: string;
description?: string;
};
full_name?: {
type?: string;
description?: string;
};
};
required: string[];
}
/**
* @internal
*/
export interface AuthConfigLike {
enable_username_password?: boolean;
enable_google_login?: boolean;
enable_microsoft_login?: boolean;
enable_facebook_login?: boolean;
sso_provider_name?: string;
enable_sso_login?: boolean;
}
/**
* @internal
*/
export type LoginInfoResponse = Pick<AppLike, "id" | "name" | "slug" | "logo_url" | "user_description" | "updated_date" | "created_date" | "auth_config" | "platform_version">;
+1
View File
@@ -0,0 +1 @@
export {};
+13
View File
@@ -0,0 +1,13 @@
import { AxiosInstance } from "axios";
import { AuthModule, AuthModuleOptions } from "./auth.types";
/**
* Creates the auth module for the Base44 SDK.
*
* @param axios - Axios instance for API requests
* @param functionsAxiosClient - Axios instance for functions API requests
* @param appId - Application ID
* @param options - Configuration options including server URLs
* @returns Auth module with authentication and user management methods
* @internal
*/
export declare function createAuthModule(axios: AxiosInstance, functionsAxiosClient: AxiosInstance, appId: string, options: AuthModuleOptions): AuthModule;
+240
View File
@@ -0,0 +1,240 @@
function isInsideIframe() {
if (typeof window === "undefined")
return false;
return window !== window.parent;
}
/**
* Opens a URL in a centered popup and waits for the backend to postMessage
* the auth result back. On success, redirects the current window to
* redirectUrl with the token params appended, preserving the same behaviour
* as a normal full-page redirect flow.
*
* @param url - The login URL to open in the popup (should include popup_origin).
* @param redirectUrl - Where to redirect after auth (the original fromUrl).
* @param expectedOrigin - The origin we expect the postMessage to come from.
*/
function loginViaPopup(url, redirectUrl, expectedOrigin) {
const width = 500;
const height = 600;
const left = Math.round(window.screenX + (window.outerWidth - width) / 2);
const top = Math.round(window.screenY + (window.outerHeight - height) / 2);
const popup = window.open(url, "base44_auth", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`);
if (!popup) {
return;
}
const cleanup = () => {
window.removeEventListener("message", onMessage);
clearInterval(pollTimer);
if (!popup.closed)
popup.close();
};
const onMessage = (event) => {
var _a;
if (event.origin !== expectedOrigin)
return;
if (event.source !== popup)
return;
if (!((_a = event.data) === null || _a === void 0 ? void 0 : _a.access_token))
return;
cleanup();
const callbackUrl = new URL(redirectUrl);
const { access_token, is_new_user } = event.data;
callbackUrl.searchParams.set("access_token", access_token);
if (is_new_user != null) {
callbackUrl.searchParams.set("is_new_user", String(is_new_user));
}
window.location.href = callbackUrl.toString();
};
// Only used to detect the user closing the popup before auth completes
const pollTimer = setInterval(() => {
if (popup.closed)
cleanup();
}, 500);
window.addEventListener("message", onMessage);
}
/**
* Creates the auth module for the Base44 SDK.
*
* @param axios - Axios instance for API requests
* @param functionsAxiosClient - Axios instance for functions API requests
* @param appId - Application ID
* @param options - Configuration options including server URLs
* @returns Auth module with authentication and user management methods
* @internal
*/
export function createAuthModule(axios, functionsAxiosClient, appId, options) {
return {
// Get current user information
async me() {
return axios.get(`/apps/${appId}/entities/User/me`);
},
// Update current user data
async updateMe(data) {
return axios.put(`/apps/${appId}/entities/User/me`, data);
},
// Redirects the user to the app's login page
redirectToLogin(nextUrl) {
// This function only works in a browser environment
if (typeof window === "undefined") {
throw new Error("Login method can only be used in a browser environment");
}
// If nextUrl is not provided, use the current URL
const redirectUrl = nextUrl
? new URL(nextUrl, window.location.origin).toString()
: window.location.href;
// Build the login URL
const loginUrl = `${options.appBaseUrl}/login?from_url=${encodeURIComponent(redirectUrl)}`;
// Redirect to the login page
window.location.href = loginUrl;
},
// Redirects the user to a provider's login page
loginWithProvider(provider, fromUrl = "/") {
// Build the full redirect URL
const redirectUrl = new URL(fromUrl, window.location.origin).toString();
const queryParams = `app_id=${appId}&from_url=${encodeURIComponent(redirectUrl)}`;
// SSO uses a different URL structure with appId in the path
let authPath;
if (provider === "sso") {
authPath = `/apps/${appId}/auth/sso/login`;
}
else {
// Google is the default provider, so no provider path segment needed
const providerPath = provider === "google" ? "" : `/${provider}`;
authPath = `/apps/auth${providerPath}/login`;
}
const loginUrl = `${options.appBaseUrl}/api${authPath}?${queryParams}`;
// When running inside an iframe, use a popup to avoid OAuth providers
// blocking iframe navigation.
if (isInsideIframe()) {
const popupLoginUrl = `${loginUrl}&popup_origin=${encodeURIComponent(window.location.origin)}`;
return loginViaPopup(popupLoginUrl, redirectUrl, window.location.origin);
}
// Default: full-page redirect
window.location.href = loginUrl;
},
// Logout the current user
logout(redirectUrl) {
// Remove token from axios headers (always do this)
delete axios.defaults.headers.common["Authorization"];
// Only do the rest if in a browser environment
if (typeof window !== "undefined") {
// Remove token from localStorage
if (window.localStorage) {
try {
window.localStorage.removeItem("base44_access_token");
// Remove "token" that is set by the built-in SDK of platform version 2
window.localStorage.removeItem("token");
}
catch (e) {
console.error("Failed to remove token from localStorage:", e);
}
}
// Determine the from_url parameter
const fromUrl = redirectUrl || window.location.href;
// Redirect to server-side logout endpoint to clear HTTP-only cookies
const logoutUrl = `${options.appBaseUrl}/api/apps/auth/logout?from_url=${encodeURIComponent(fromUrl)}`;
window.location.href = logoutUrl;
}
},
// Set authentication token
setToken(token, saveToStorage = true) {
if (!token)
return;
// handle token change for axios clients
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
functionsAxiosClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
// Save token to localStorage if requested
if (saveToStorage &&
typeof window !== "undefined" &&
window.localStorage) {
try {
window.localStorage.setItem("base44_access_token", token);
// Set "token" that is set by the built-in SDK of platform version 2
window.localStorage.setItem("token", token);
}
catch (e) {
console.error("Failed to save token to localStorage:", e);
}
}
},
// Login using username and password
async loginViaEmailPassword(email, password, turnstileToken) {
var _a;
try {
const response = await axios.post(`/apps/${appId}/auth/login`, {
email,
password,
...(turnstileToken && { turnstile_token: turnstileToken }),
});
const { access_token, user } = response;
if (access_token) {
this.setToken(access_token);
}
return {
access_token,
user,
};
}
catch (error) {
// Handle authentication errors and cleanup
if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401) {
await this.logout();
}
throw error;
}
},
// Verify if the current token is valid
async isAuthenticated() {
try {
await this.me();
return true;
}
catch (error) {
return false;
}
},
// Invite a user to the app
inviteUser(userEmail, role) {
return axios.post(`/apps/${appId}/users/invite-user`, {
user_email: userEmail,
role,
});
},
// Register a new user account
register(payload) {
return axios.post(`/apps/${appId}/auth/register`, payload);
},
// Verify an OTP (One-time password) code
verifyOtp({ email, otpCode }) {
return axios.post(`/apps/${appId}/auth/verify-otp`, {
email,
otp_code: otpCode,
});
},
// Resend an OTP code to the user's email
resendOtp(email) {
return axios.post(`/apps/${appId}/auth/resend-otp`, { email });
},
// Request a password reset
resetPasswordRequest(email) {
return axios.post(`/apps/${appId}/auth/reset-password-request`, {
email,
});
},
// Reset password using a reset token
resetPassword({ resetToken, newPassword }) {
return axios.post(`/apps/${appId}/auth/reset-password`, {
reset_token: resetToken,
new_password: newPassword,
});
},
// Change the user's password
changePassword({ userId, currentPassword, newPassword, }) {
return axios.post(`/apps/${appId}/auth/change-password`, {
user_id: userId,
current_password: currentPassword,
new_password: newPassword,
});
},
};
}
+477
View File
@@ -0,0 +1,477 @@
/**
* An authenticated user.
*/
export interface User {
/** Unique user identifier. */
id: string;
/** When the user was created. */
created_date: string;
/** When the user was last updated. */
updated_date: string;
/** User's email address. */
email: string;
/** User's full name. */
full_name: string | null;
/** Whether the user is disabled. */
disabled: boolean | null;
/** Whether the user's email has been verified. */
is_verified: boolean;
/** The app ID this user belongs to. */
app_id: string;
/** Whether this is a service account. */
is_service: boolean;
/** Internal app role.
* @internal
*/
_app_role: string;
/**
* User's role in the app. Roles are configured in the app settings and determine the user's permissions and access levels.
*/
role: string;
/**
* Additional custom fields defined in the user schema. Any custom properties added to the user schema in the app will be available here with their configured types and values.
*/
[key: string]: any;
}
/**
* Response from login endpoints containing user information and access token.
*/
export interface LoginResponse {
/** JWT access token for authentication. */
access_token: string;
/** User information. */
user: User;
}
/**
* Payload for user registration.
*/
export interface RegisterParams {
/** User's email address. */
email: string;
/** User's password. */
password: string;
/** Optional {@link https://developers.cloudflare.com/turnstile/ | Cloudflare Turnstile CAPTCHA token} for bot protection. */
turnstile_token?: string | null;
/** Optional {@link https://docs.base44.com/Getting-Started/Referral-program | referral code} from an existing user. */
referral_code?: string | null;
}
/**
* Parameters for OTP verification.
*/
export interface VerifyOtpParams {
/** User's email address. */
email: string;
/** One-time password code received by email. */
otpCode: string;
}
/**
* Parameters for changing a user's password.
*/
export interface ChangePasswordParams {
/** User ID. */
userId: string;
/** Current password for verification. */
currentPassword: string;
/** New password to set. */
newPassword: string;
}
/**
* Parameters for resetting a password with a token.
*/
export interface ResetPasswordParams {
/** Reset token received by email. */
resetToken: string;
/** New password to set. */
newPassword: string;
}
/**
* Configuration options for the auth module.
*/
export interface AuthModuleOptions {
/** Server URL for API requests. */
serverUrl: string;
/** Base URL for the app (used for login redirects). */
appBaseUrl: string;
}
/**
* Authentication module for managing user authentication and authorization. The module automatically stores tokens in local storage when available and manages authorization headers for API requests.
*
* ## Features
*
* This module provides comprehensive authentication functionality including:
* - Email/password login and registration
* - Token management
* - User profile access and updates
* - Password reset flows
* - OTP verification
* - User invitations
*
* ## Authentication Modes
*
* The auth module is only available in user authentication mode (`base44.auth`).
*/
export interface AuthModule {
/**
* Gets the current authenticated user's information.
*
* @returns Promise resolving to the user's profile data.
*
* @example
* ```typescript
* // Get current user information
* const user = await base44.auth.me();
* console.log(`Logged in as: ${user.email}`);
* console.log(`User ID: ${user.id}`);
* ```
*/
me(): Promise<User>;
/**
* Updates the current authenticated user's information.
*
* You can update `role` and any [custom fields](/developers/backend/resources/entities/user-schema#custom-fields) defined in your
* User entity schema.
* The `role` value must be either `'user'` or `'admin'`.
* <Note>
* The following fields are read-only and can't be changed with this method:
* `id`, `email`, `full_name`, `created_date`, `updated_date`, and `created_by`.
* </Note>
*
* @param data - Object containing the fields to update.
* @returns Promise resolving to the updated user data.
*
* @example
* ```typescript
* // Update role and custom fields defined in your User entity
* await base44.auth.updateMe({
* role: 'admin',
* bio: 'Software developer',
* preferences: { theme: 'dark' }
* });
* ```
*/
updateMe(data: Record<string, any>): Promise<User>;
/**
* Redirects the user to the app's login page.
*
* Redirects with a callback URL to return to after successful authentication. Requires a browser environment and can't be used in the backend.
*
* @param nextUrl - URL to redirect to after successful login.
* @throws {Error} When not in a browser environment.
*
* @example
* ```typescript
* // Redirect to login and come back to current page
* base44.auth.redirectToLogin(window.location.href);
* ```
*
* @example
* ```typescript
* // Redirect to login and then go to the dashboard page
* base44.auth.redirectToLogin('/dashboard');
* ```
*/
redirectToLogin(nextUrl: string): void;
/**
* Redirects the user to a third-party authentication provider's login page.
*
* Initiates an OAuth login flow with one of the built-in providers. Requires a browser environment and can't be used in the backend.
*
* Supported providers:
* - `'google'`: {@link https://developers.google.com/identity/protocols/oauth2 | Google OAuth}. Enabled by default.
* - `'microsoft'`: {@link https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow | Microsoft OAuth}. Enable Microsoft in your app's authentication settings before specifying this provider.
* - `'facebook'`: {@link https://developers.facebook.com/docs/facebook-login | Facebook Login}. Enable Facebook in your app's authentication settings before using.
* - `'apple'`: {@link https://developer.apple.com/sign-in-with-apple/ | Sign in with Apple}. Enable Apple in your app's authentication settings before using this provider.
* - `'sso'`: Enterprise SSO. {@link https://docs.base44.com/Setting-up-your-app/Setting-up-SSO | Set up an SSO provider} in your app's authentication settings before using this provider.
*
* @param provider - The authentication provider to use: `'google'`, `'microsoft'`, `'facebook'`, `'apple'`, or `'sso'`.
* @param fromUrl - URL to redirect to after successful authentication. Defaults to `'/'`.
*
* @example
* ```typescript
* // Google
* base44.auth.loginWithProvider('google', window.location.pathname);
* ```
*
* @example
* ```typescript
* // Microsoft
* base44.auth.loginWithProvider('microsoft', '/dashboard');
* ```
*
* @example
* ```typescript
* // Apple
* base44.auth.loginWithProvider('apple', '/dashboard');
* ```
*
* @example
* ```typescript
* // SSO
* base44.auth.loginWithProvider('sso', '/dashboard');
* ```
*
*/
loginWithProvider(provider: string, fromUrl?: string): void;
/**
* Logs out the current user.
*
* Removes the authentication token from local storage and Axios headers, then optionally redirects to a URL or reloads the page. Requires a browser environment and can't be used in the backend.
*
* @param redirectUrl - Optional URL to redirect to after logout. Reloads the page if not provided.
*
* @example
* ```typescript
* // Logout and reload page
* base44.auth.logout();
* ```
*
* @example
* ```typescript
* // Logout and redirect to login page
* base44.auth.logout('/login');
* ```
*
* @example
* ```typescript
* // Logout and redirect to home
* base44.auth.logout('/');
* ```
*/
logout(redirectUrl?: string): void;
/**
* Sets the authentication token.
*
* Updates the authorization header for API requests and optionally saves the token to local storage for persistence. Saving to local storage requires a browser environment and is automatically skipped in backend environments.
*
* @param token - JWT authentication token.
* @param saveToStorage - Whether to save the token to local storage. Defaults to true.
*
* @example
* ```typescript
* // Set token and save to local storage
* base44.auth.setToken('eyJhbGciOiJIUzI1NiIs...');
* ```
*
* @example
* ```typescript
* // Set token without saving to local storage
* base44.auth.setToken('eyJhbGciOiJIUzI1NiIs...', false);
* ```
*/
setToken(token: string, saveToStorage?: boolean): void;
/**
* Logs in a registered user using email and password.
*
* Authenticates a user with email and password credentials. The user must already have a registered account. For new users, use {@linkcode register | register()} first to create an account. On successful login, automatically sets the token for subsequent requests.
*
* @param email - User's email address.
* @param password - User's password.
* @param turnstileToken - Optional {@link https://developers.cloudflare.com/turnstile/ | Cloudflare Turnstile CAPTCHA token} for bot protection.
* @returns Promise resolving to login response with access token and user data.
* @throws Error if the email and password combination is invalid or the user is not registered.
*
* @example
* ```typescript
* // Login with email and password
* try {
* const { access_token, user } = await base44.auth.loginViaEmailPassword(
* 'user@example.com',
* 'securePassword123'
* );
* console.log('Login successful!', user);
* } catch (error) {
* console.error('Login failed:', error);
* }
* ```
*
* @example
* ```typescript
* // With captcha token
* const response = await base44.auth.loginViaEmailPassword(
* 'user@example.com',
* 'securePassword123',
* 'captcha-token-here'
* );
* ```
*/
loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<LoginResponse>;
/**
* Checks if the current user is authenticated.
*
* @returns Promise resolving to true if authenticated, false otherwise.
*
* @example
* ```typescript
* // Check authentication status
* const isAuthenticated = await base44.auth.isAuthenticated();
* if (isAuthenticated) {
* console.log('User is logged in');
* } else {
* // Redirect to login page
* base44.auth.redirectToLogin(window.location.href);
* }
* ```
*/
isAuthenticated(): Promise<boolean>;
/**
* Invites a user to the app.
*
* Sends an invitation email to a potential user with a specific role.
* Roles are configured in the app settings and determine
* the user's permissions and access levels.
*
* @param userEmail - Email address of the user to invite.
* @param role - Role to assign to the invited user. Must match a role defined in the app. For example, `'admin'` or `'user'`.
* @returns Promise that resolves when the invitation is sent successfully. Throws an error if the invitation fails.
*
* @example
* ```typescript
* try {
* await base44.auth.inviteUser('newuser@example.com', 'user');
* console.log('Invitation sent successfully!');
* } catch (error) {
* console.error('Failed to send invitation:', error);
* }
* ```
*/
inviteUser(userEmail: string, role: string): Promise<any>;
/**
* Registers a new user account.
*
* Creates a new user account with email and password. After successful registration,
* use {@linkcode loginViaEmailPassword | loginViaEmailPassword()} to log in the user.
*
* @param params - Registration details including email, password, and optional fields.
* @returns Promise resolving to the registration response.
*
* @example
* ```typescript
* // Register a new user
* await base44.auth.register({
* email: 'newuser@example.com',
* password: 'securePassword123',
* referral_code: 'FRIEND2024'
* });
*
* // Login after registration
* const { access_token, user } = await base44.auth.loginViaEmailPassword(
* 'newuser@example.com',
* 'securePassword123'
* );
* ```
*/
register(params: RegisterParams): Promise<any>;
/**
* Verifies an OTP (One-time password) code.
*
* Validates an OTP code sent to the user's email during registration
* or authentication.
*
* @param params - Object containing email and OTP code.
* @returns Promise resolving to the verification response if valid.
* @throws Error if the OTP code is invalid, expired, or verification fails.
*
* @example
* ```typescript
* try {
* await base44.auth.verifyOtp({
* email: 'user@example.com',
* otpCode: '123456'
* });
* console.log('Email verified successfully!');
* } catch (error) {
* console.error('Invalid or expired OTP code');
* }
* ```
*/
verifyOtp(params: VerifyOtpParams): Promise<any>;
/**
* Resends an OTP code to the user's email address.
*
* Requests a new OTP code to be sent to the specified email address.
*
* @param email - Email address to send the OTP to.
* @returns Promise resolving when the OTP is sent successfully.
* @throws Error if the email is invalid or the request fails.
*
* @example
* ```typescript
* try {
* await base44.auth.resendOtp('user@example.com');
* console.log('OTP resent! Please check your email.');
* } catch (error) {
* console.error('Failed to resend OTP:', error);
* }
* ```
*/
resendOtp(email: string): Promise<any>;
/**
* Requests a password reset.
*
* Sends a password reset email to the specified email address.
*
* @param email - Email address for the account to reset.
* @returns Promise resolving when the password reset email is sent successfully.
* @throws Error if the email is invalid or the request fails.
*
* @example
* ```typescript
* try {
* await base44.auth.resetPasswordRequest('user@example.com');
* console.log('Password reset email sent!');
* } catch (error) {
* console.error('Failed to send password reset email:', error);
* }
* ```
*/
resetPasswordRequest(email: string): Promise<any>;
/**
* Resets password using a reset token.
*
* Completes the password reset flow by setting a new password
* using the token received by email.
*
* @param params - Object containing the reset token and new password.
* @returns Promise resolving when the password is reset successfully.
* @throws Error if the reset token is invalid, expired, or the request fails.
*
* @example
* ```typescript
* try {
* await base44.auth.resetPassword({
* resetToken: 'token-from-email',
* newPassword: 'newSecurePassword456'
* });
* console.log('Password reset successful!');
* } catch (error) {
* console.error('Failed to reset password:', error);
* }
* ```
*/
resetPassword(params: ResetPasswordParams): Promise<any>;
/**
* Changes the user's password.
*
* Updates the password for an authenticated user by verifying
* the current password and setting a new one.
*
* @param params - Object containing user ID, current password, and new password.
* @returns Promise resolving when the password is changed successfully.
* @throws Error if the current password is incorrect or the request fails.
*
* @example
* ```typescript
* try {
* await base44.auth.changePassword({
* userId: 'user-123',
* currentPassword: 'oldPassword123',
* newPassword: 'newSecurePassword456'
* });
* console.log('Password changed successfully!');
* } catch (error) {
* console.error('Failed to change password:', error);
* }
* ```
*/
changePassword(params: ChangePasswordParams): Promise<any>;
}
+1
View File
@@ -0,0 +1 @@
export {};
+20
View File
@@ -0,0 +1,20 @@
import { AxiosInstance } from "axios";
import { ConnectorsModule, UserConnectorsModule } from "./connectors.types.js";
/**
* Creates the Connectors module for the Base44 SDK.
*
* @param axios - Axios instance (should be service role client)
* @param appId - Application ID
* @returns Connectors module with methods to retrieve OAuth tokens
* @internal
*/
export declare function createConnectorsModule(axios: AxiosInstance, appId: string): ConnectorsModule;
/**
* Creates the user-scoped Connectors module (app-user OAuth flows).
*
* @param axios - Axios instance (user-scoped client)
* @param appId - Application ID
* @returns User connectors module with app-user OAuth methods
* @internal
*/
export declare function createUserConnectorsModule(axios: AxiosInstance, appId: string): UserConnectorsModule;
+98
View File
@@ -0,0 +1,98 @@
/**
* Creates the Connectors module for the Base44 SDK.
*
* @param axios - Axios instance (should be service role client)
* @param appId - Application ID
* @returns Connectors module with methods to retrieve OAuth tokens
* @internal
*/
export function createConnectorsModule(axios, appId) {
return {
/**
* Retrieve an OAuth access token for a specific external integration type.
* @deprecated Use getConnection(integrationType) and use the returned accessToken (and connectionConfig when needed) instead.
*/
// @ts-expect-error Return type mismatch with interface - implementation returns string, interface expects string but implementation is typed as ConnectorAccessTokenResponse
async getAccessToken(integrationType) {
if (!integrationType || typeof integrationType !== "string") {
throw new Error("Integration type is required and must be a string");
}
const response = await axios.get(`/apps/${appId}/external-auth/tokens/${integrationType}`);
// @ts-expect-error
return response.access_token;
},
async getConnection(integrationType) {
var _a;
if (!integrationType || typeof integrationType !== "string") {
throw new Error("Integration type is required and must be a string");
}
const response = await axios.get(`/apps/${appId}/external-auth/tokens/${integrationType}`);
const data = response;
return {
accessToken: data.access_token,
connectionConfig: (_a = data.connection_config) !== null && _a !== void 0 ? _a : null,
};
},
async getWorkspaceConnection(connectorId) {
var _a;
if (!connectorId || typeof connectorId !== "string") {
throw new Error("Connector ID is required and must be a string");
}
const response = await axios.get(`/apps/${appId}/external-auth/tokens/connectors/${connectorId}`);
const data = response;
return {
accessToken: data.access_token,
connectionConfig: (_a = data.connection_config) !== null && _a !== void 0 ? _a : null,
};
},
/**
* @deprecated Use getCurrentAppUserConnection(connectorId) and use the returned accessToken (and connectionConfig when needed) instead.
*/
async getCurrentAppUserAccessToken(connectorId) {
if (!connectorId || typeof connectorId !== "string") {
throw new Error("Connector ID is required and must be a string");
}
const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${connectorId}/token`);
const data = response;
return data.access_token;
},
async getCurrentAppUserConnection(connectorId) {
var _a;
if (!connectorId || typeof connectorId !== "string") {
throw new Error("Connector ID is required and must be a string");
}
const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${connectorId}/token`);
const data = response;
return {
accessToken: data.access_token,
connectionConfig: (_a = data.connection_config) !== null && _a !== void 0 ? _a : null,
};
},
};
}
/**
* Creates the user-scoped Connectors module (app-user OAuth flows).
*
* @param axios - Axios instance (user-scoped client)
* @param appId - Application ID
* @returns User connectors module with app-user OAuth methods
* @internal
*/
export function createUserConnectorsModule(axios, appId) {
return {
async connectAppUser(connectorId) {
if (!connectorId || typeof connectorId !== "string") {
throw new Error("Connector ID is required and must be a string");
}
const response = await axios.post(`/apps/${appId}/app-user-auth/connectors/${connectorId}/initiate`);
const data = response;
return data.redirect_url;
},
async disconnectAppUser(connectorId) {
if (!connectorId || typeof connectorId !== "string") {
throw new Error("Connector ID is required and must be a string");
}
await axios.delete(`/apps/${appId}/app-user-auth/connectors/${connectorId}`);
},
};
}
+371
View File
@@ -0,0 +1,371 @@
/**
* Registry of connector integration type names. The [`types generate`](/developers/references/cli/commands/types-generate) command fills this registry, then [`ConnectorIntegrationType`](#connectorintegrationtype) resolves to a union of the keys.
*/
export interface ConnectorIntegrationTypeRegistry {
}
/**
* Union of all connector integration type names from the [`ConnectorIntegrationTypeRegistry`](#connectorintegrationtyperegistry). Defaults to `string` when no types have been generated.
*
* @example
* ```typescript
* // Using generated connector type names
* // With generated types, you get autocomplete on integration types
* const connection = await base44.asServiceRole.connectors.getConnection('googlecalendar');
* const token = connection.accessToken;
* ```
*/
export type ConnectorIntegrationType = keyof ConnectorIntegrationTypeRegistry extends never ? string : keyof ConnectorIntegrationTypeRegistry;
/**
* Response from the connectors access token endpoint.
*/
export interface ConnectorAccessTokenResponse {
access_token: string;
integration_type: string;
connection_config: Record<string, string> | null;
}
/**
* Connection details.
*/
export interface ConnectorConnectionResponse {
/** The OAuth access token for the external service. */
accessToken: string;
/** Key-value configuration for the connection, or `null` if the connector does not provide one. */
connectionConfig: Record<string, string> | null;
}
/**
* Connection details for an app user connector.
*/
export interface AppUserConnectorConnectionResponse {
/** The OAuth access token for the app user's connection. */
accessToken: string;
/** Key-value configuration for the connection, or `null` if the connector does not provide one. */
connectionConfig: Record<string, string> | null;
}
/**
* Connectors module for managing OAuth tokens for external services.
*
* Unlike the {@link IntegrationsModule | integrations} module that provides pre-built functions, connectors give you raw OAuth tokens so you can call external service APIs directly. Use this when you need custom API interactions that the pre-built integrations do not cover.
*
* There are two connector types, depending on whether the token is shared across the app or specific to each user:
*
* - **[Shared connectors](#shared-connectors):** A single OAuth token shared by all app users. Best for shared service accounts.
* - **[App user connectors](#app-user-connectors):** Each app user has their own OAuth token. Best for actions that need to happen as the individual user.
*
* ## Shared connectors
*
* All app users share a single OAuth token. Use this for shared accounts. For example, posting to a company Slack channel or reading from a shared Google Calendar. To use a shared connector:
*
* 1. Connect the external service account in the app's Integration settings or using the [`connectors push`](/developers/references/cli/commands/connectors-push) CLI command.
* 2. In a backend function, call {@linkcode getConnection | getConnection()} using the service role client (`base44.asServiceRole.connectors`) with an [integration type](#available-connectors) string to retrieve the shared OAuth token.
* 3. Use the returned `accessToken` to call the external service's API directly. Some connectors also return a `connectionConfig` with additional values such as a subdomain for building the API URL.
*
* ## App user connectors
*
* Each signed-in app user has their own OAuth token. Use this when each user needs to act as themselves. For example, sending emails from their Gmail account or posting to their personal LinkedIn. To use an app user connector:
*
* 1. Register OAuth credentials for the service in Workspace Settings to get a **connector ID**. This requires workspace admin access.
* 2. From the frontend, call [connectAppUser()](#connectappuser) with the connector ID to get an authorization URL, then redirect the app user to that URL to complete the OAuth flow.
* 3. In a backend function, call {@linkcode getCurrentAppUserConnection | getCurrentAppUserConnection()} using the service role client (`base44.asServiceRole.connectors`) with the connector ID to retrieve the app user's token.
* 4. Use the returned `accessToken` to call the external service's API directly. Some connectors also return a `connectionConfig` with additional values such as a subdomain for building the API URL.
*
* ## Available connectors
*
* All connectors listed below support both shared and app user connections. For shared connectors, pass the integration type string to {@linkcode getConnection | getConnection()}. For app user connectors, register the connector in Workspace Settings and use the connector ID with {@linkcode getCurrentAppUserConnection | getCurrentAppUserConnection()}.
*
* | Service | Type identifier |
* |---|---|
* | Airtable | `airtable` |
* | BambooHR | `bamboohr` |
* | Box | `box` |
* | Calendly | `calendly` |
* | ClickUp | `clickup` |
* | Contentful | `contentful` |
* | Discord | `discord` |
* | Dropbox | `dropbox` |
* | GitHub | `github` |
* | GitLab | `gitlab` |
* | Gmail | `gmail` |
* | 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` |
* | Salesforce | `salesforce` |
* | SharePoint | `share_point` |
* | Slack User | `slack` |
* | Slack Bot | `slackbot` |
* | Splitwise | `splitwise` |
* | Supabase | `supabase` |
* | TikTok | `tiktok` |
* | Typeform | `typeform` |
* | Wix | `wix` |
* | Wrike | `wrike` |
*
* See the integration guides for more details:
*
* - **Scopes and permissions**: {@link https://docs.base44.com/Integrations/gmail-connector#gmail-scopes-and-permissions | Gmail}, {@link https://docs.base44.com/Integrations/linkedin-connector#linkedin-scopes-and-permissions | LinkedIn}, {@link https://docs.base44.com/Integrations/slack-connector#slack-scopes-and-permissions | Slack}, {@link https://docs.base44.com/Integrations/github-connector#github-scopes-and-permissions | GitHub}
* - **Slack connector types**: {@link https://docs.base44.com/Integrations/slack-connector#about-the-slack-connectors | About the Slack connectors} explains the difference between `slack` and `slackbot`
*
* ## Dynamic Types
*
* If you're working in a TypeScript project, you can generate types from your app's connector configurations to get autocomplete on integration type names when calling {@link getConnection}. See the [Dynamic Types](/developers/references/sdk/getting-started/dynamic-types) guide to get started.
*/
export interface ConnectorsModule {
/**
* Retrieves an OAuth access token for a specific [external integration type](#available-connectors).
*
* @deprecated Use {@link getConnection} instead.
*
* Returns the OAuth token string for an external service connected to the app.
* This token represents the connected account and can be used to make authenticated API calls to that external service on behalf of the app.
*
* @param integrationType - The type of integration, such as `'googlecalendar'`, `'slack'`, `'slackbot'`, `'github'`, or `'discord'`. See [Available connectors](#available-connectors) for the full list.
* @returns Promise resolving to the access token string.
*
* @example
* ```typescript
* // Google Calendar connection
* // Get Google Calendar OAuth token and fetch upcoming events
* const googleToken = await base44.asServiceRole.connectors.getAccessToken('googlecalendar');
*
* // Fetch upcoming 10 events
* const timeMin = new Date().toISOString();
* const url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?maxResults=10&orderBy=startTime&singleEvents=true&timeMin=${timeMin}`;
*
* const response = await fetch(url, {
* headers: { 'Authorization': `Bearer ${googleToken}` }
* });
*
* const events = await response.json();
* ```
*
* @example
* ```typescript
* // Slack User connection
* // Get Slack user token and list channels
* const slackToken = await base44.asServiceRole.connectors.getAccessToken('slack');
*
* // List all public and private channels
* const url = 'https://slack.com/api/conversations.list?types=public_channel,private_channel&limit=100';
*
* const response = await fetch(url, {
* headers: { 'Authorization': `Bearer ${slackToken}` }
* });
*
* const data = await response.json();
* ```
*
* @example
* ```typescript
* // Slack Bot connection
* // Get Slack bot token and post a message with a custom bot identity
* const botToken = await base44.asServiceRole.connectors.getAccessToken('slackbot');
*
* const response = await fetch('https://slack.com/api/chat.postMessage', {
* method: 'POST',
* headers: {
* 'Authorization': `Bearer ${botToken}`,
* 'Content-Type': 'application/json'
* },
* body: JSON.stringify({
* channel: '#alerts',
* text: 'Deployment to production completed successfully.',
* username: 'Deploy Bot',
* icon_emoji: ':rocket:'
* })
* });
*
* const result = await response.json();
* ```
*/
getAccessToken(integrationType: ConnectorIntegrationType): Promise<string>;
/**
* Retrieves the shared OAuth access token and connection configuration for a [shared connector](#shared-connectors) to a specific [external integration type](#available-connectors).
*
* Use this when a single shared account is connected and all app users access the same token. For per-user tokens, use [`getCurrentAppUserConnection()`](#getcurrentappuserconnection) instead.
*
* Some connectors require connection-specific parameters to build API calls.
* In such cases, the returned `connectionConfig` is an object with the additional parameters. If there are no extra parameters needed for the connection, the `connectionConfig` is `null`.
*
* For example, a service might need a subdomain to construct the API URL in
* the form of `{subdomain}.example.com`. In such a case the subdomain will be available as a property of the `connectionConfig` object.
*
* @param integrationType - The type of integration, such as `'googlecalendar'`, `'slack'`, `'slackbot'`, `'github'`, or `'discord'`. See [Available connectors](#available-connectors) for the full list.
* @returns Promise resolving to a {@link ConnectorConnectionResponse} with `accessToken` and `connectionConfig`.
*
* @example
* ```typescript
* // Google Calendar connection
* const { accessToken } = await base44.asServiceRole.connectors.getConnection('googlecalendar');
*
* const response = await fetch('https://www.googleapis.com/calendar/v3/users/me/calendarList', {
* headers: { Authorization: `Bearer ${accessToken}` }
* });
*
* const { items } = await response.json();
* ```
*
* @example
* ```typescript
* // Slack connection
* // Get Slack OAuth token and list channels
* const { accessToken } = await base44.asServiceRole.connectors.getConnection('slack');
*
* const url = 'https://slack.com/api/conversations.list?types=public_channel,private_channel&limit=100';
*
* const response = await fetch(url, {
* headers: { Authorization: `Bearer ${accessToken}` }
* });
*
* const data = await response.json();
* ```
*
* @example
* ```typescript
* // Using connectionConfig
* // Some connectors return a subdomain or other params needed to build the API URL
* const { accessToken, connectionConfig } = await base44.asServiceRole.connectors.getConnection('myservice');
*
* const subdomain = connectionConfig?.subdomain;
* const response = await fetch(
* `https://${subdomain}.example.com/api/v1/resources`,
* { headers: { Authorization: `Bearer ${accessToken}` } }
* );
*
* const data = await response.json();
* ```
*/
getConnection(integrationType: ConnectorIntegrationType): Promise<ConnectorConnectionResponse>;
/**
* Retrieves the OAuth access token and connection configuration for a **workspace-registered** connector
* (a connector backed by an OAuth app registered in the workspace, consented to once by the app builder).
*
* Use this method when the app's backend function needs to use a connector identified by its
* workspace-connector ID rather than a platform integration type. The token returned represents
* the app builder's consent against the workspace's OAuth app and is shared across all app users
* of the app — identical semantics to the platform-shared {@link getConnection} form,
* differing only in which OAuth app was used to produce the token.
*
* @param connectorId - The ID of the workspace connector (the `OrganizationConnector` database ID) as surfaced in the builder chat context.
* @returns Promise resolving to a {@link ConnectorConnectionResponse} with `accessToken` and `connectionConfig`.
*
* @example
* ```typescript
* // Get the connection for a workspace-registered connector
* 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}` },
* });
* ```
*/
getWorkspaceConnection(connectorId: string): Promise<ConnectorConnectionResponse>;
/**
* @internal
* @deprecated Use {@link getCurrentAppUserConnection} instead.
*/
getCurrentAppUserAccessToken(connectorId: string): Promise<string>;
/**
* Retrieves the OAuth access token and connection configuration for an [app user connector](#app-user-connectors).
*
* The token returned is specific to the app user making the current request. For this to work, the SDK client must know which app user to act on behalf of. Use {@linkcode createClientFromRequest | createClientFromRequest()} in a Base44 backend function to create such a client. It reads the app user's JWT from the incoming request and attaches it automatically so the runtime can resolve the correct user's connection.
*
* The connector must be registered in Workspace Settings with OAuth credentials before this method can return a connection. The app user must also have completed the OAuth flow using [connectAppUser()](#connectappuser).
*
* @param connectorId - The ID of the app user connector configured in your workspace. This is not the integration type string. You can find it on the connector's settings page in Workspace Settings.
* @returns Promise resolving to an {@link AppUserConnectorConnectionResponse} with `accessToken` and `connectionConfig`.
*
* @example
* ```typescript
* // Basic usage
* const { accessToken } = await base44.asServiceRole.connectors.getCurrentAppUserConnection('abc123def');
*
* const response = await fetch('https://www.googleapis.com/calendar/v3/calendars/primary/events', {
* headers: { Authorization: `Bearer ${accessToken}` }
* });
*
* const data = await response.json();
* ```
*
* @example
* ```typescript
* // Using connectionConfig
* const { accessToken, connectionConfig } = await base44.asServiceRole.connectors.getCurrentAppUserConnection('abc123def');
*
* const subdomain = connectionConfig?.subdomain;
* const response = await fetch(
* `https://${subdomain}.example.com/api/v1/resources`,
* { headers: { Authorization: `Bearer ${accessToken}` } }
* );
*
* const data = await response.json();
* ```
*/
getCurrentAppUserConnection(connectorId: string): Promise<AppUserConnectorConnectionResponse>;
}
/**
* User-scoped connectors module for managing app user OAuth connections.
*
* This module provides methods for app user OAuth flows: initiating an OAuth connection and disconnecting an app user's connection.
*
* Unlike {@link ConnectorsModule | ConnectorsModule} which manages app-scoped tokens,
* this module manages tokens scoped to individual app users. Methods are keyed on
* the connector ID, not the integration type.
*
* Available via `base44.connectors`.
*/
export interface UserConnectorsModule {
/**
* Initiates the OAuth flow for an [app user connector](#app-user-connectors).
*
* Returns a redirect URL that the app user should be navigated to in order to
* authenticate with the external service. The scopes and integration type are
* derived from the connector configuration in the backend.
*
* @param connectorId - The ID of the app user connector configured in your workspace. The AI builder inserts this ID into generated code when it sets up the connector flow. You can also retrieve it from the workspace connectors API.
* @returns Promise resolving to the redirect URL string.
*
* @example
* ```typescript
* // Start OAuth for the app user
* const redirectUrl = await base44.connectors.connectAppUser('abc123def');
*
* // Redirect the user to the OAuth provider
* window.location.href = redirectUrl;
* ```
*/
connectAppUser(connectorId: string): Promise<string>;
/**
* Disconnects an app user's OAuth connection for an [app user connector](#app-user-connectors).
*
* Removes the stored OAuth credentials for the currently authenticated app user's
* connection to the specified connector.
*
* @param connectorId - The ID of the app user connector configured in your workspace. The AI builder inserts this ID into generated code when it sets up the connector flow. You can also retrieve it from the workspace connectors API.
* @returns Promise resolving when the connection has been removed.
*
* @example
* ```typescript
* // Disconnect the app user's connection
* await base44.connectors.disconnectAppUser('abc123def');
* ```
*/
disconnectAppUser(connectorId: string): Promise<void>;
}
+1
View File
@@ -0,0 +1 @@
export {};
+11
View File
@@ -0,0 +1,11 @@
import { AxiosInstance } from "axios";
import { CustomIntegrationsModule } from "./custom-integrations.types.js";
/**
* Creates the custom integrations module for the Base44 SDK.
*
* @param axios - Axios instance for making HTTP requests
* @param appId - Application ID
* @returns Custom integrations module with `call()` method
* @internal
*/
export declare function createCustomIntegrationsModule(axios: AxiosInstance, appId: string): CustomIntegrationsModule;
+32
View File
@@ -0,0 +1,32 @@
/**
* Creates the custom integrations module for the Base44 SDK.
*
* @param axios - Axios instance for making HTTP requests
* @param appId - Application ID
* @returns Custom integrations module with `call()` method
* @internal
*/
export function createCustomIntegrationsModule(axios, appId) {
return {
async call(slug, operationId, params) {
// Validate required parameters
if (!(slug === null || slug === void 0 ? void 0 : slug.trim())) {
throw new Error("Integration slug is required and cannot be empty");
}
if (!(operationId === null || operationId === void 0 ? void 0 : operationId.trim())) {
throw new Error("Operation ID is required and cannot be empty");
}
// Convert camelCase to snake_case for Python backend
const { pathParams, queryParams, ...rest } = params !== null && params !== void 0 ? params : {};
const body = {
...rest,
...(pathParams && { path_params: pathParams }),
...(queryParams && { query_params: queryParams }),
};
// Make the API call
const response = await axios.post(`/apps/${appId}/integrations/custom/${slug}/${operationId}`, body);
// The axios interceptor extracts response.data, so we get the payload directly
return response;
},
};
}
+89
View File
@@ -0,0 +1,89 @@
/**
* Parameters for calling a custom integration endpoint.
* @internal
*/
export interface CustomIntegrationCallParams {
/**
* Request body payload to send to the external API.
*/
payload?: Record<string, any>;
/**
* Path parameters to substitute in the URL. For example, `{ owner: "user", repo: "repo" }`.
*/
pathParams?: Record<string, string>;
/**
* Query string parameters to append to the URL.
*/
queryParams?: Record<string, any>;
}
/**
* Response from a custom integration call.
* @internal
*/
export interface CustomIntegrationCallResponse {
/**
* Whether the external API returned a 2xx status code.
*/
success: boolean;
/**
* The HTTP status code returned by the external API.
*/
status_code: number;
/**
* The response data from the external API.
* Can be any JSON-serializable value depending on the external API's response.
*/
data: any;
}
/**
* Module for calling custom pre-configured API integrations.
*
* Custom integrations allow workspace administrators to connect any external API by importing an OpenAPI specification. Apps in the workspace can then call these integrations using this module.
*/
export interface CustomIntegrationsModule {
/**
* Call a custom integration endpoint.
*
* @param slug - The integration's unique identifier, as defined by the workspace admin.
* @param operationId - The endpoint in `method:path` format. For example, `"get:/contacts"`, or `"post:/users/{id}"`. The method is the HTTP verb in lowercase and the path matches the OpenAPI specification.
* @param params - Optional parameters including payload, pathParams, and queryParams.
* @returns Promise resolving to the integration call response.
*
* @throws {Error} If slug is not provided.
* @throws {Error} If operationId is not provided.
* @throws {Base44Error} If the integration or operation is not found (404).
* @throws {Base44Error} If the external API call fails (502).
* @throws {Base44Error} If the request times out (504).
*
* @example
* ```typescript
* // Call a custom CRM integration
* const response = await base44.integrations.custom.call(
* "my-crm",
* "get:/contacts",
* { queryParams: { limit: 10 } }
* );
*
* if (response.success) {
* console.log("Contacts:", response.data);
* }
* ```
*
* @example
* ```typescript
* // Call with path params and request body
* const response = await base44.integrations.custom.call(
* "github",
* "post:/repos/{owner}/{repo}/issues",
* {
* pathParams: { owner: "myorg", repo: "myrepo" },
* payload: {
* title: "Bug report",
* body: "Something is broken"
* }
* }
* );
* ```
*/
call(slug: string, operationId: string, params?: CustomIntegrationCallParams): Promise<CustomIntegrationCallResponse>;
}
+1
View File
@@ -0,0 +1 @@
export {};
+20
View File
@@ -0,0 +1,20 @@
import { AxiosInstance } from "axios";
import { EntitiesModule } from "./entities.types";
import { RoomsSocket } from "../utils/socket-utils.js";
/**
* Configuration for the entities module.
* @internal
*/
export interface EntitiesModuleConfig {
axios: AxiosInstance;
appId: string;
getSocket: () => ReturnType<typeof RoomsSocket>;
}
/**
* Creates the entities module for the Base44 SDK.
*
* @param config - Configuration object containing axios, appId, and getSocket
* @returns Entities module with dynamic entity access
* @internal
*/
export declare function createEntitiesModule(config: EntitiesModuleConfig): EntitiesModule;
+163
View File
@@ -0,0 +1,163 @@
/**
* Creates the entities module for the Base44 SDK.
*
* @param config - Configuration object containing axios, appId, and getSocket
* @returns Entities module with dynamic entity access
* @internal
*/
export function createEntitiesModule(config) {
const { axios, appId, getSocket } = config;
// Using Proxy to dynamically handle entity names
return new Proxy({}, {
get(target, entityName) {
// Don't create handlers for internal properties
if (typeof entityName !== "string" ||
entityName === "then" ||
entityName.startsWith("_")) {
return undefined;
}
// Create entity handler
return createEntityHandler(axios, appId, entityName, getSocket);
},
});
}
/**
* Parses the realtime message data and extracts event information.
* @internal
*/
function parseRealtimeMessage(dataStr) {
var _a;
try {
const parsed = JSON.parse(dataStr);
return {
type: parsed.type,
data: parsed.data,
id: parsed.id || ((_a = parsed.data) === null || _a === void 0 ? void 0 : _a.id),
timestamp: parsed.timestamp || new Date().toISOString(),
};
}
catch (error) {
console.warn("[Base44 SDK] Failed to parse realtime message:", error);
return null;
}
}
/**
* Creates a handler for a specific entity.
*
* @param axios - Axios instance
* @param appId - Application ID
* @param entityName - Entity name
* @param getSocket - Function to get the socket instance
* @returns Entity handler with CRUD methods
* @internal
*/
function createEntityHandler(axios, appId, entityName, getSocket) {
const baseURL = `/apps/${appId}/entities/${entityName}`;
return {
// List entities with optional pagination and sorting
async list(sort, limit, skip, fields) {
const params = {};
if (sort)
params.sort = sort;
if (limit)
params.limit = limit;
if (skip)
params.skip = skip;
if (fields)
params.fields = Array.isArray(fields) ? fields.join(",") : fields;
return axios.get(baseURL, { params });
},
// Filter entities based on query
async filter(query, sort, limit, skip, fields) {
const params = {
q: JSON.stringify(query),
};
if (sort)
params.sort = sort;
if (limit)
params.limit = limit;
if (skip)
params.skip = skip;
if (fields)
params.fields = Array.isArray(fields) ? fields.join(",") : fields;
return axios.get(baseURL, { params });
},
// Get entity by ID
async get(id) {
return axios.get(`${baseURL}/${id}`);
},
// Create new entity
async create(data) {
return axios.post(baseURL, data);
},
// Update entity by ID
async update(id, data) {
return axios.put(`${baseURL}/${id}`, data);
},
// Delete entity by ID
async delete(id) {
return axios.delete(`${baseURL}/${id}`);
},
// Delete multiple entities based on query
async deleteMany(query) {
return axios.delete(baseURL, { data: query });
},
// Create multiple entities in a single request
async bulkCreate(data) {
return axios.post(`${baseURL}/bulk`, data);
},
// Update multiple entities matching a query using a MongoDB update operator
async updateMany(query, data) {
return axios.patch(`${baseURL}/update-many`, { query, data });
},
// Update multiple entities by ID, each with its own update data
async bulkUpdate(data) {
return axios.put(`${baseURL}/bulk`, data);
},
// Import entities from a file
async importEntities(file) {
const formData = new FormData();
formData.append("file", file, file.name);
return axios.post(`${baseURL}/import`, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
},
// Subscribe to realtime updates
subscribe(callback) {
const room = `entities:${appId}:${entityName}`;
// Get the socket and subscribe to the room
const socket = getSocket();
const unsubscribe = socket.subscribeToRoom(room, {
update_model: (msg) => {
var _a;
const event = parseRealtimeMessage(msg.data);
if (!event) {
return;
}
// Server signals oversize broadcasts with `_oversize: true` on
// `data`. The wire payload was slimmed to fit under the realtime
// transport cap, so big string fields arrive as empty strings (or
// the whole record collapses to a stub). Surface this to the
// developer console so they know to fetch the full record on
// demand (e.g. a follow-up entities.X.get(id) call) instead of
// rendering the slimmed payload directly. Skip on delete events
// — the record no longer exists.
if (event.type !== "delete" && ((_a = event.data) === null || _a === void 0 ? void 0 : _a._oversize)) {
console.error(`[Base44 SDK] Realtime broadcast for ${entityName}#${event.id} was oversize and got slimmed for transport. ` +
`Fields >10 KB are empty and the rest of the record may be a stub. ` +
`Call \`entities.${entityName}.get("${event.id}")\` to fetch the full record.`);
}
try {
callback(event);
}
catch (error) {
console.error("[Base44 SDK] Subscription callback error:", error);
}
},
});
return unsubscribe;
},
};
}
+702
View File
@@ -0,0 +1,702 @@
/**
* Event types for realtime entity updates.
*/
export type RealtimeEventType = "create" | "update" | "delete";
/**
* Payload received when a realtime event occurs.
*
* @typeParam T - The entity type for the data field. Defaults to `any`.
*/
export interface RealtimeEvent<T = any> {
/** The type of change that occurred */
type: RealtimeEventType;
/** The entity data */
data: T;
/** The unique identifier of the affected entity */
id: string;
/** ISO 8601 timestamp of when the event occurred */
timestamp: string;
}
/**
* Callback function invoked when a realtime event occurs.
*
* @typeParam T - The entity type for the event data. Defaults to `any`.
*/
export type RealtimeCallback<T = any> = (event: RealtimeEvent<T>) => void;
/**
* Result returned when deleting a single entity.
*/
export interface DeleteResult {
/** Whether the deletion was successful. */
success: boolean;
}
/**
* Result returned when deleting multiple entities.
*/
export interface DeleteManyResult {
/** Whether the deletion was successful. */
success: boolean;
/** Number of entities that were deleted. */
deleted: number;
}
/**
* Result returned when updating multiple entities using a query.
*/
export interface UpdateManyResult {
/** Whether the operation was successful. */
success: boolean;
/** Number of entities that were updated. */
updated: number;
/** Whether there are more entities matching the query that were not updated in this batch. When `true`, call `updateMany` again with the same query to update the next batch. */
has_more: boolean;
}
/**
* Result returned when importing entities from a file.
*
* @typeParam T - The entity type for imported records. Defaults to `any`.
*/
export interface ImportResult<T = any> {
/** Status of the import operation. */
status: "success" | "error";
/** Details message, e.g., "Successfully imported 3 entities with RLS enforcement". */
details: string | null;
/** Array of created entity objects when successful, or null on error. */
output: T[] | null;
}
/**
* Sort field type for entity queries.
*
* Accepts any field name from the entity type with an optional prefix:
* - `'+'` prefix or no prefix: ascending sort
* - `'-'` prefix: descending sort
*
* @typeParam T - The entity type to derive sortable fields from.
*
* @example
* ```typescript
* // Specify sort direction by prefixing field names with + or -
* // Ascending sort
* 'created_date'
* '+created_date'
*
* // Descending sort
* '-created_date'
* ```
*/
export type SortField<T> = (keyof T & string) | `+${keyof T & string}` | `-${keyof T & string}`;
/**
* Entity filter query type system.
*
* `EntityFilterQuery<T>` keeps field names tied to the entity schema while
* allowing Base44's documented filtering syntax. Each field can use an exact
* value, `null`, an array shorthand for matching any listed value, or a
* field-level operator object. Root-level `$and`, `$or`, and `$nor` combine
* nested filter queries.
*
* Operator values are typed from the field they filter where possible. For
* example, numeric fields accept numeric comparison values, string fields
* accept `$regex`, and array fields accept `$all` and `$size`.
*/
/**
* Value accepted when filtering an entity field.
*
* Supports exact matches, `null`, array shorthand for matching any of the
* provided values, and documented MongoDB-style query operators.
*
* @typeParam T - Field value type.
*/
export type EntityFilterValue<T> = EntityFilterComparable<T> | EntityFilterComparable<T>[] | EntityFilterOperators<T>;
/**
* MongoDB-style query operators accepted for a single entity field.
*
* @typeParam T - Field value type.
*/
export type EntityFilterOperators<T> = EntityFilterCommonOperators<T> & {
/** Negates another field-level filter expression. */
$not?: EntityFilterCommonOperators<T>;
};
type EntityFilterComparable<T> = Exclude<T, undefined> | null;
type EntityFilterCommonOperators<T> = {
$eq?: EntityFilterComparable<T>;
$ne?: EntityFilterComparable<T>;
$gt?: EntityFilterComparable<T>;
$gte?: EntityFilterComparable<T>;
$lt?: EntityFilterComparable<T>;
$lte?: EntityFilterComparable<T>;
$in?: EntityFilterComparable<T>[];
$nin?: EntityFilterComparable<T>[];
$exists?: boolean;
} & EntityFilterStringOperators<T> & EntityFilterArrayOperators<T>;
type EntityFilterStringOperators<T> = Extract<Exclude<T, undefined | null>, string> extends never ? {} : {
$regex?: string;
};
type EntityFilterArrayElement<T> = T extends readonly (infer U)[] ? U : never;
type EntityFilterArrayOperators<T> = [
EntityFilterArrayElement<Exclude<T, undefined | null>>
] extends [never] ? {} : {
$all?: EntityFilterArrayElement<Exclude<T, undefined | null>>[];
$size?: number;
};
/**
* Query object accepted by entity filtering methods.
*
* Field keys are typed from the entity schema. `$and`, `$or`, and `$nor`
* combine nested filter queries at the root level.
*
* @typeParam T - Entity record type.
*/
export type EntityFilterQuery<T> = {
[K in keyof T]?: EntityFilterValue<T[K]>;
} & {
$and?: EntityFilterQuery<T>[];
$or?: EntityFilterQuery<T>[];
$nor?: EntityFilterQuery<T>[];
};
/**
* Fields added by the server to every entity record, such as `id`, `created_date`, `updated_date`, and `created_by`.
*/
interface ServerEntityFields {
/** Unique identifier of the record */
id: string;
/** ISO 8601 timestamp when the record was created */
created_date: string;
/** ISO 8601 timestamp when the record was last updated */
updated_date: string;
/** Email of the user who created the record (may be hidden in some responses) */
created_by?: string | null;
/** ID of the user who created the record */
created_by_id?: string | null;
/** Whether the record is sample/seed data */
is_sample?: boolean;
}
/**
* Registry mapping entity names to their TypeScript types. The [`types generate`](/developers/references/cli/commands/types-generate) command fills this registry, then [`EntityRecord`](#entityrecord) adds server fields.
*/
export interface EntityTypeRegistry {
}
/**
* Combines the [`EntityTypeRegistry`](#entitytyperegistry) schemas with server fields like `id`, `created_date`, and `updated_date` to give the complete record type for each entity. Use this when you need to type variables holding entity data.
*
* @example
* ```typescript
* // Using EntityRecord to get the complete type for an entity
* // Combine your schema with server fields (id, created_date, etc.)
* type TaskRecord = EntityRecord['Task'];
*
* const task: TaskRecord = await base44.entities.Task.create({
* title: 'My task',
* status: 'pending'
* });
*
* // Task now includes both your fields and server fields:
* console.log(task.id); // Server field
* console.log(task.created_date); // Server field
* console.log(task.title); // Your field
* ```
*/
export type EntityRecord = {
[K in keyof EntityTypeRegistry]: EntityTypeRegistry[K] & ServerEntityFields;
};
/**
* Entity handler providing CRUD operations for a specific entity type.
*
* Each entity in the app gets a handler with these methods for managing data.
*
* @typeParam T - The entity type. Defaults to `any` for backward compatibility.
*/
export interface EntityHandler<T = any> {
/**
* Lists records with optional pagination and sorting.
*
* Retrieves all records of this type with support for sorting,
* pagination, and field selection.
*
* **Note:** The maximum limit is 5,000 items per request.
*
* @typeParam K - The fields to include in the response. Defaults to all fields.
* @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
* @param limit - Maximum number of results to return. Defaults to `50`.
* @param skip - Number of results to skip for pagination. Defaults to `0`.
* @param fields - Array of field names to include in the response. Defaults to all fields.
* @returns Promise resolving to an array of records with selected fields.
*
* @example
* ```typescript
* // Get all records
* const records = await base44.entities.MyEntity.list();
* ```
*
* @example
* ```typescript
* // Get first 10 records sorted by date
* const recentRecords = await base44.entities.MyEntity.list('-created_date', 10);
* ```
*
* @example
* ```typescript
* // Get paginated results
* // Skip first 20, get next 10
* const page3 = await base44.entities.MyEntity.list('-created_date', 10, 20);
* ```
*
* @example
* ```typescript
* // Get only specific fields
* const fields = await base44.entities.MyEntity.list('-created_date', 10, 0, ['name', 'status']);
* ```
*/
list<K extends keyof T = keyof T>(sort?: SortField<T>, limit?: number, skip?: number, fields?: K[]): Promise<Pick<T, K>[]>;
/**
* Filters records based on a query.
*
* Retrieves records that match specific criteria with support for
* sorting, pagination, and field selection.
*
* **Note:** The maximum limit is 5,000 items per request.
*
* @typeParam K - The fields to include in the response. Defaults to all fields.
* @param query - Query object with field-value pairs. Each key should be a field name
* from your entity schema, and each value is the criteria to match. Records matching all
* specified criteria are returned. Field names are case-sensitive. Use field-value pairs
* for exact matches, `null` for null values, arrays as shorthand for matching any of the
* provided values, or documented MongoDB query operators for advanced filtering.
* @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
* @param limit - Maximum number of results to return. Defaults to `50`.
* @param skip - Number of results to skip for pagination. Defaults to `0`.
* @param fields - Array of field names to include in the response. Defaults to all fields.
* @returns Promise resolving to an array of filtered records with selected fields.
*
* @example
* ```typescript
* // Filter by single field
* const activeRecords = await base44.entities.MyEntity.filter({
* status: 'active'
* });
* ```
*
* @example
* ```typescript
* // Filter by multiple fields
* const filteredRecords = await base44.entities.MyEntity.filter({
* priority: 'high',
* status: 'active'
* });
* ```
*
* @example
* ```typescript
* // Filter by any matching value
* const records = await base44.entities.MyEntity.filter({
* external_id: ['item-1', 'item-2']
* });
* ```
*
* @example
* ```typescript
* // Filter with query operators
* const popularRecords = await base44.entities.MyEntity.filter({
* count: { $gte: 100 },
* external_id: { $in: ['item-1', 'item-2'] }
* });
* ```
*
* @example
* ```typescript
* // Filter with logical operators
* const records = await base44.entities.MyEntity.filter({
* $or: [
* { name: 'Example item' },
* { slug: 'example-item' }
* ]
* });
* ```
*
* @example
* ```typescript
* // Filter null values
* const recordsWithoutDescription = await base44.entities.MyEntity.filter({
* description: null
* });
* ```
*
* @example
* ```typescript
* // Filter with sorting and pagination
* const results = await base44.entities.MyEntity.filter(
* { status: 'active' },
* '-created_date',
* 20,
* 0
* );
* ```
*
* @example
* ```typescript
* // Filter with specific fields
* const fields = await base44.entities.MyEntity.filter(
* { priority: 'high' },
* '-created_date',
* 10,
* 0,
* ['name', 'priority']
* );
* ```
*/
filter<K extends keyof T = keyof T>(query: EntityFilterQuery<T>, sort?: SortField<T>, limit?: number, skip?: number, fields?: K[]): Promise<Pick<T, K>[]>;
/**
* Gets a single record by ID.
*
* Retrieves a specific record using its unique identifier.
*
* @param id - The unique identifier of the record.
* @returns Promise resolving to the record.
*
* @example
* ```typescript
* // Get record by ID
* const record = await base44.entities.MyEntity.get('entity-123');
* console.log(record.name);
* ```
*/
get(id: string): Promise<T>;
/**
* Creates a new record.
*
* Creates a new record with the provided data.
*
* @param data - Object containing the record data.
* @returns Promise resolving to the created record.
*
* @example
* ```typescript
* // Create a new record
* const newRecord = await base44.entities.MyEntity.create({
* name: 'My Item',
* status: 'active',
* priority: 'high'
* });
* console.log('Created record with ID:', newRecord.id);
* ```
*/
create(data: Partial<T>): Promise<T>;
/**
* Updates an existing record.
*
* Updates a record by ID with the provided data. Only the fields
* included in the data object will be updated.
*
* To update a single record by ID, use this method. To apply the same
* update to many records matching a query, use {@linkcode updateMany | updateMany()}.
* To update multiple specific records with different data each, use
* {@linkcode bulkUpdate | bulkUpdate()}.
*
* @param id - The unique identifier of the record to update.
* @param data - Object containing the fields to update.
* @returns Promise resolving to the updated record.
*
* @example
* ```typescript
* // Update single field
* const updated = await base44.entities.MyEntity.update('entity-123', {
* status: 'completed'
* });
* ```
*
* @example
* ```typescript
* // Update multiple fields
* const updated = await base44.entities.MyEntity.update('entity-123', {
* name: 'Updated name',
* priority: 'low',
* status: 'active'
* });
* ```
*/
update(id: string, data: Partial<T>): Promise<T>;
/**
* Deletes a single record by ID.
*
* Permanently removes a record from the database.
*
* @param id - The unique identifier of the record to delete.
* @returns Promise resolving to the deletion result.
*
* @example
* ```typescript
* // Delete a record
* const result = await base44.entities.MyEntity.delete('entity-123');
* console.log('Deleted:', result.success);
* ```
*/
delete(id: string): Promise<DeleteResult>;
/**
* Deletes multiple records matching a query.
*
* Permanently removes all records that match the provided query.
*
* @param query - Query object with field-value pairs. Each key should be a field name
* from your entity schema, and each value is the criteria to match. Records matching all
* specified criteria will be deleted. Field names are case-sensitive.
* @returns Promise resolving to the deletion result.
*
* @example
* ```typescript
* // Delete by multiple criteria
* const result = await base44.entities.MyEntity.deleteMany({
* status: 'completed',
* priority: 'low'
* });
* console.log('Deleted:', result.deleted);
* ```
*/
deleteMany(query: Partial<T>): Promise<DeleteManyResult>;
/**
* Creates multiple records in a single request.
*
* Efficiently creates multiple records at once. This is faster
* than creating them individually.
*
* @param data - Array of record data objects.
* @returns Promise resolving to an array of created records.
*
* @example
* ```typescript
* // Create multiple records at once
* const result = await base44.entities.MyEntity.bulkCreate([
* { name: 'Item 1', status: 'active' },
* { name: 'Item 2', status: 'active' },
* { name: 'Item 3', status: 'completed' }
* ]);
* ```
*/
bulkCreate(data: Partial<T>[]): Promise<T[]>;
/**
* Applies the same update to all records that match a query.
*
* Use this when you need to make the same change across all records that
* match specific criteria. For example, you could set every completed order
* to "archived", or increment a counter on all active users.
*
* Results are batched in groups of up to 500. When `has_more` is `true`
* in the response, call `updateMany` again with the same query to update
* the next batch. Make sure the query excludes already-updated records
* so you don't re-process the same entities on each iteration. For
* example, filter by `status: 'pending'` when setting status to `'processed'`.
*
* To update a single record by ID, use {@linkcode update | update()} instead. To update
* multiple specific records with different data each, use {@linkcode bulkUpdate | bulkUpdate()}.
*
* @param query - Query object to filter which records to update. Use field-value
* pairs for exact matches, or
* [MongoDB query operators](https://www.mongodb.com/docs/manual/reference/operator/query/)
* for advanced filtering. Supported query operators include `$eq`, `$ne`, `$gt`,
* `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$and`, `$or`, `$not`, `$nor`,
* `$exists`, `$regex`, `$all`, `$elemMatch`, and `$size`.
* @param data - Update operation object containing one or more
* [MongoDB update operators](https://www.mongodb.com/docs/manual/reference/operator/update/).
* Each field may only appear in one operator per call.
* Supported update operators include `$set`, `$rename`, `$unset`, `$inc`, `$mul`, `$min`, `$max`,
* `$currentDate`, `$addToSet`, `$push`, and `$pull`.
* @returns Promise resolving to the update result.
*
* @example
* ```typescript
* // Basic usage
* // Archive all completed orders
* const result = await base44.entities.Order.updateMany(
* { status: 'completed' },
* { $set: { status: 'archived' } }
* );
* console.log(`Updated ${result.updated} records`);
* ```
*
* @example
* ```typescript
* // Multiple query operators
* // Flag urgent items that haven't been handled yet
* const result = await base44.entities.Task.updateMany(
* { priority: { $in: ['high', 'critical'] }, status: { $ne: 'done' } },
* { $set: { flagged: true } }
* );
* ```
*
* @example
* ```typescript
* // Multiple update operators
* // Close out sales records and bump the view count
* const result = await base44.entities.Deal.updateMany(
* { category: 'sales' },
* { $set: { status: 'done' }, $inc: { view_count: 1 } }
* );
* ```
*
* @example
* ```typescript
* // Batched updates
* // 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;
* }
* ```
*/
updateMany(query: Partial<T>, data: Record<string, Record<string, any>>): Promise<UpdateManyResult>;
/**
* Updates the specified records in a single request, each with its own data.
*
* Use this when you already know which records to update and each one needs
* different field values. For example, you could update the status and amount
* on three separate invoices in one call.
*
* You can update up to 500 records per request.
*
* To apply the same update to all records matching a query, use
* {@linkcode updateMany | updateMany()}. To update a single record by ID, use
* {@linkcode update | update()}.
*
* @param data - Array of objects to update. Each object must contain an `id` field identifying which record to update and any fields to change.
* @returns Promise resolving to an array of the updated records.
*
* @example
* ```typescript
* // Basic usage
* // Update three invoices with different statuses and amounts
* const updated = await base44.entities.Invoice.bulkUpdate([
* { id: 'inv-1', status: 'paid', amount: 999 },
* { id: 'inv-2', status: 'cancelled' },
* { id: 'inv-3', amount: 450 }
* ]);
* ```
*
* @example
* ```typescript
* // More than 500 items
* // Reassign each task to a different owner in batches
* 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);
* }
* ```
*/
bulkUpdate(data: (Partial<T> & {
id: string;
})[]): Promise<T[]>;
/**
* Imports records from a file.
*
* Imports records from a file, typically CSV or similar format.
* The file format should match your entity structure. Requires a browser environment and can't be used in the backend.
*
* @param file - File object to import.
* @returns Promise resolving to the import result containing status, details, and created records.
*
* @example
* ```typescript
* // Import records from file in React
* const handleFileImport = async (event: React.ChangeEvent<HTMLInputElement>) => {
* const file = event.target.files?.[0];
* if (file) {
* const result = await base44.entities.MyEntity.importEntities(file);
* if (result.status === 'success' && result.output) {
* console.log(`Imported ${result.output.length} records`);
* }
* }
* };
* ```
*/
importEntities(file: File): Promise<ImportResult<T>>;
/**
* Subscribes to realtime updates for all records of this entity type.
*
* Establishes a WebSocket connection to receive instant updates when any
* record is created, updated, or deleted. Returns an unsubscribe function
* to clean up the connection.
*
* @param callback - Callback function called when an entity changes. The callback receives an event object with the following properties:
* - `type`: The type of change that occurred - `'create'`, `'update'`, or `'delete'`.
* - `data`: The entity data after the change.
* - `id`: The unique identifier of the affected entity.
* - `timestamp`: ISO 8601 timestamp of when the event occurred.
* @returns Unsubscribe function to stop receiving updates.
*
* @example
* ```typescript
* // Subscribe to all Task changes
* const unsubscribe = base44.entities.Task.subscribe((event) => {
* console.log(`Task ${event.id} was ${event.type}d:`, event.data);
* });
*
* // Later, clean up the subscription
* unsubscribe();
* ```
*/
subscribe(callback: RealtimeCallback<T>): () => void;
}
/**
* Typed entities module - maps registry keys to typed handlers (full record type).
*/
type TypedEntitiesModule = {
[K in keyof EntityTypeRegistry]: EntityHandler<EntityRecord[K]>;
};
/**
* Dynamic entities module - allows any entity name with untyped handler.
*/
type DynamicEntitiesModule = {
[entityName: string]: EntityHandler<any>;
};
/**
* Entities module for managing app data.
*
* This module provides dynamic access to all entities in the app.
* Each entity gets a handler with full CRUD operations and additional utility methods.
*
* Entities are accessed dynamically using the pattern:
* `base44.entities.EntityName.method()`
*
* This module is available to use with a client in all authentication modes:
*
* - **Anonymous or User authentication** (`base44.entities`): Access is scoped to the current user's permissions. Anonymous users can only access public entities, while authenticated users can access entities they have permission to view or modify.
* - **Service role authentication** (`base44.asServiceRole.entities`): Operations have elevated admin-level permissions. Can access all entities that the app's admin role has access to.
*
* ## Entity Handlers
*
* An entity handler is the object you get when you access an entity through `base44.entities.EntityName`. Every entity in your app automatically gets a handler with CRUD methods for managing records.
*
* For example, `base44.entities.Task` is an entity handler for Task records, and `base44.entities.User` is an entity handler for User records. Each handler provides methods like `list()`, `create()`, `update()`, and `delete()`.
*
* You don't need to instantiate or import entity handlers. They're automatically available for every entity you create in your app.
*
* ## Built-in User Entity
*
* Every app includes a built-in `User` entity that stores user account information. This entity has special security rules that can't be changed.
*
* Regular users can only read and update their own user record. With service role authentication, you can read, update, and delete any user. You can't create users using the entities module. Instead, use the functions of the {@link AuthModule | auth module} to invite or register new users.
*
* ## Generated Types
*
* If you're working in a TypeScript project, you can generate types from your entity schemas to get autocomplete and type checking on all entity methods. See the [Dynamic Types](/developers/references/sdk/getting-started/dynamic-types) guide to get started.
*
* @example
* ```typescript
* // Get all records from the MyEntity entity
* // Get all records the current user has permissions to view
* const myRecords = await base44.entities.MyEntity.list();
* ```
*
* @example
* ```typescript
* // List all users (admin only)
* const allUsers = await base44.asServiceRole.entities.User.list();
* ```
*/
export type EntitiesModule = TypedEntitiesModule & DynamicEntitiesModule;
export {};
+1
View File
@@ -0,0 +1 @@
export {};
+12
View File
@@ -0,0 +1,12 @@
import { AxiosInstance } from "axios";
import { FunctionsModule, FunctionsModuleConfig } from "./functions.types";
/**
* Creates the functions module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @param config - Optional configuration for fetch functionality
* @returns Functions module with methods to invoke custom backend functions
* @internal
*/
export declare function createFunctionsModule(axios: AxiosInstance, appId: string, config?: FunctionsModuleConfig): FunctionsModule;
+79
View File
@@ -0,0 +1,79 @@
/**
* Creates the functions module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @param config - Optional configuration for fetch functionality
* @returns Functions module with methods to invoke custom backend functions
* @internal
*/
export function createFunctionsModule(axios, appId, config) {
const joinBaseUrl = (base, path) => {
if (!base)
return path;
return `${String(base).replace(/\/$/, "")}${path}`;
};
const toHeaders = (inputHeaders) => {
const headers = new Headers();
// Get auth headers from the getter function if provided
if (config === null || config === void 0 ? void 0 : config.getAuthHeaders) {
const authHeaders = config.getAuthHeaders();
Object.entries(authHeaders).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
headers.set(key, String(value));
}
});
}
if (inputHeaders) {
new Headers(inputHeaders).forEach((value, key) => {
headers.set(key, value);
});
}
return headers;
};
return {
// Invoke a custom backend function by name
async invoke(functionName, data) {
// Validate input
if (typeof data === "string") {
throw new Error(`Function ${functionName} must receive an object with named parameters, received: ${data}`);
}
let formData;
let contentType;
// Handle file uploads with FormData
if (data instanceof FormData ||
(data && Object.values(data).some((value) => value instanceof File))) {
formData = new FormData();
Object.keys(data).forEach((key) => {
if (data[key] instanceof File) {
formData.append(key, data[key], data[key].name);
}
else if (typeof data[key] === "object" && data[key] !== null) {
formData.append(key, JSON.stringify(data[key]));
}
else {
formData.append(key, data[key]);
}
});
contentType = "multipart/form-data";
}
else {
formData = data;
contentType = "application/json";
}
return axios.post(`/apps/${appId}/functions/${functionName}`, formData || data, { headers: { "Content-Type": contentType } });
},
// Fetch a backend function endpoint directly.
async fetch(path, init = {}) {
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
const primaryPath = `/functions${normalizedPath}`;
const headers = toHeaders(init.headers);
const requestInit = {
...init,
headers,
};
const response = await fetch(joinBaseUrl(config === null || config === void 0 ? void 0 : config.baseURL, primaryPath), requestInit);
return response;
},
};
}
+150
View File
@@ -0,0 +1,150 @@
/**
* Registry of function names. The [`types generate`](/developers/references/cli/commands/types-generate) command fills this registry, then [`FunctionName`](#functionname) resolves to a union of the keys.
*/
export interface FunctionNameRegistry {
}
/**
* Union of all function names from the [`FunctionNameRegistry`](#functionnameregistry). Defaults to `string` when no types have been generated.
*
* @example
* ```typescript
* // Using generated function name types
* // With generated types, you get autocomplete on function names
* await base44.functions.invoke('calculateTotal', { items: ['item1', 'item2'] });
* ```
*/
export type FunctionName = keyof FunctionNameRegistry extends never ? string : keyof FunctionNameRegistry;
/**
* Options for {@linkcode FunctionsModule.fetch}.
*
* Alias of the native [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) type.
* Any option accepted by the browser `fetch` API is valid (`method`, `headers`, `body`, `signal`, etc.).
* Auth headers are merged in automatically; you do not need to set them.
*/
export type FunctionsFetchInit = RequestInit;
/**
* Configuration for the functions module.
* @internal
*/
export interface FunctionsModuleConfig {
getAuthHeaders?: () => Record<string, string>;
baseURL?: string;
}
/**
* Functions module for invoking custom backend functions.
*
* This module allows you to invoke the custom backend functions defined in the app.
*
* ## Authentication Modes
*
* This module is available to use with a client in all authentication modes:
*
* - **Anonymous or User authentication** (`base44.functions`): Functions are invoked with the current user's permissions. Anonymous users invoke functions without authentication, while authenticated users invoke functions with their authentication context.
* - **Service role authentication** (`base44.asServiceRole.functions`): Functions are invoked with elevated admin-level permissions. The function code receives a request with admin authentication context.
*
* ## Generated Types
*
* If you're working in a TypeScript project, you can generate types from your backend functions to get autocomplete on function names when calling `invoke()`. See the [Dynamic Types](/developers/references/sdk/getting-started/dynamic-types) guide to get started.
*/
export interface FunctionsModule {
/**
* Invokes a custom backend function by name.
*
* Sends a POST request to a custom backend function deployed to the app.
* The function receives the provided data as named parameters and returns
* the result. If any parameter is a `File` object, the request will automatically be
* sent as `multipart/form-data`. Otherwise, it will be sent as JSON.
*
* For streaming responses, non-POST methods, or raw response access, use {@linkcode fetch | fetch()} instead.
*
* @param functionName - The name of the function to invoke.
* @param data - An object containing named parameters for the function.
* @returns Promise resolving to the function's response. The `data` property contains the data returned by the function, if there is any.
*
* @example
* ```typescript
* // Basic function call
* const result = await base44.functions.invoke('calculateTotal', {
* items: ['item1', 'item2'],
* });
* console.log(result.data.total);
* ```
*
* @example
* ```typescript
* // Function with file upload in React
* const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
* const file = event.target.files?.[0];
* if (file) {
* const processedImage = await base44.functions.invoke('processImage', {
* image: file,
* filter: 'grayscale',
* quality: 80
* });
* }
* };
* ```
*/
invoke(functionName: FunctionName, data?: Record<string, any>): Promise<any>;
/**
* Performs a direct HTTP request to a backend function path and returns the native `Response`.
*
* Use `fetch()` when you need low-level control that {@linkcode invoke | invoke()} doesn't provide, such as:
* - Streaming responses, like SSE, chunked text, or NDJSON
* - Custom HTTP methods, like PUT, PATCH, or DELETE
* - Raw response access, including status codes, headers, and binary bodies
*
* @param path - Function path. Leading slash is optional, so `/chat` and `chat` are equivalent. For example, `'/streaming_demo'` or `'reports/export'`.
* @param init - Optional [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) options such as `method`, `headers`, `body`, and `signal`. Auth headers are added automatically.
* @returns Promise resolving to a native [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response).
*
* @example
* ```typescript
* // Stream an SSE response
* const response = await base44.functions.fetch('/chat', {
* method: 'POST',
* headers: { 'Content-Type': 'application/json' },
* body: JSON.stringify({ prompt: 'Hello!' }),
* });
*
* const reader = response.body!.getReader();
* const decoder = new TextDecoder();
*
* while (true) {
* const { done, value } = await reader.read();
* if (done) break;
* console.log(decoder.decode(value, { stream: true }));
* }
* ```
*
* @example
* ```typescript
* // PUT request
* const response = await base44.functions.fetch('/users/profile', {
* method: 'PUT',
* headers: { 'Content-Type': 'application/json' },
* body: JSON.stringify({ name: 'Jane', role: 'admin' }),
* });
*
* if (!response.ok) {
* throw new Error(`Request failed: ${response.status}`);
* }
*
* const updated = await response.json();
* ```
*
* @example
* ```typescript
* // Download a binary file
* const response = await base44.functions.fetch('/export/report');
* const blob = await response.blob();
*
* const url = URL.createObjectURL(blob);
* const a = document.createElement('a');
* a.href = url;
* a.download = 'report.pdf';
* a.click();
* ```
*/
fetch(path: string, init?: FunctionsFetchInit): Promise<Response>;
}
+1
View File
@@ -0,0 +1 @@
export {};
+11
View File
@@ -0,0 +1,11 @@
import { AxiosInstance } from "axios";
import { IntegrationsModule } from "./integrations.types.js";
/**
* Creates the integrations module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @returns Integrations module with dynamic access to integration endpoints
* @internal
*/
export declare function createIntegrationsModule(axios: AxiosInstance, appId: string): IntegrationsModule;
+77
View File
@@ -0,0 +1,77 @@
import { createCustomIntegrationsModule } from "./custom-integrations.js";
/**
* Creates the integrations module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @returns Integrations module with dynamic access to integration endpoints
* @internal
*/
export function createIntegrationsModule(axios, appId) {
// Create the custom integrations module once
const customModule = createCustomIntegrationsModule(axios, appId);
return new Proxy({}, {
get(target, packageName) {
// Skip internal properties
if (typeof packageName !== "string" ||
packageName === "then" ||
packageName.startsWith("_")) {
return undefined;
}
// Handle 'custom' specially - return the custom integrations module
if (packageName === "custom") {
return customModule;
}
// Create a proxy for integration endpoints
return new Proxy({}, {
get(target, endpointName) {
// Skip internal properties
if (typeof endpointName !== "string" ||
endpointName === "then" ||
endpointName.startsWith("_")) {
return undefined;
}
// Return a function that calls the integration endpoint
// This allows: client.integrations.PackageName.EndpointName(data)
return async (data) => {
// Validate input
if (typeof data === "string") {
throw new Error(`Integration ${endpointName} must receive an object with named parameters, received: ${data}`);
}
let formData;
let contentType;
// Handle file uploads with FormData
if (data instanceof FormData ||
(data &&
Object.values(data).some((value) => value instanceof File))) {
formData = new FormData();
Object.keys(data).forEach((key) => {
if (data[key] instanceof File) {
formData.append(key, data[key], data[key].name);
}
else if (typeof data[key] === "object" &&
data[key] !== null) {
formData.append(key, JSON.stringify(data[key]));
}
else {
formData.append(key, data[key]);
}
});
contentType = "multipart/form-data";
}
else {
formData = data;
contentType = "application/json";
}
// For Core package
if (packageName === "Core") {
return axios.post(`/apps/${appId}/integration-endpoints/Core/${endpointName}`, formData || data, { headers: { "Content-Type": contentType } });
}
// For other packages
return axios.post(`/apps/${appId}/integration-endpoints/installable/${packageName}/integration-endpoints/${endpointName}`, formData || data, { headers: { "Content-Type": contentType } });
};
},
});
},
});
}
+418
View File
@@ -0,0 +1,418 @@
import { CustomIntegrationsModule } from "./custom-integrations.types.js";
/**
* Function signature for calling an integration endpoint.
*
* If any parameter is a `File` object, the request will automatically be
* sent as `multipart/form-data`. Otherwise, it will be sent as JSON.
*
* @param data - An object containing named parameters for the integration endpoint.
* @returns Promise resolving to the integration endpoint's response.
*/
export type IntegrationEndpointFunction = (data: Record<string, any>) => Promise<any>;
/**
* A package containing integration endpoints.
*
* An integration package is a collection of endpoint functions indexed by endpoint name.
* Both `Core` and `custom` are integration packages that implement this structure.
*
* @example **Core package**
* ```typescript
* await base44.integrations.Core.InvokeLLM({
* prompt: 'Explain quantum computing',
* model: 'gpt_5'
* });
* ```
*
* @example **custom package**
* ```typescript
* await base44.integrations.custom.call(
* 'github',
* 'get:/repos/{owner}/{repo}',
* { pathParams: { owner: 'myorg', repo: 'myrepo' } }
* );
* ```
*/
export type IntegrationPackage = {
[endpointName: string]: IntegrationEndpointFunction;
};
/**
* Parameters for the InvokeLLM function.
*/
export interface InvokeLLMParams {
/** The prompt text to send to the model */
prompt: string;
/** Optionally specify a model to override the app-level model setting for this specific call.
*
* Options: `"gpt_5_mini"`, `"gemini_3_flash"`, `"gpt_5"`, `"gpt_5_4"`, `"gpt_5_5"`, `"gemini_3_1_pro"`, `"claude_sonnet_4_6"`, `"claude_opus_4_6"`, `"claude_opus_4_7"`
*/
model?: 'gpt_5_mini' | 'gemini_3_flash' | 'gpt_5' | 'gpt_5_4' | 'gpt_5_5' | 'gemini_3_1_pro' | 'claude_sonnet_4_6' | 'claude_opus_4_6' | 'claude_opus_4_7';
/** If set to `true`, the LLM will use Google Search, Maps, and News to gather real-time context before answering.
* @default false
*/
add_context_from_internet?: boolean;
/** If you want structured data back, provide a [JSON schema object](https://json-schema.org/understanding-json-schema/reference/object) here. If provided, the function returns a JSON object; otherwise, it returns a string. */
response_json_schema?: object;
/** A list of file URLs (uploaded via UploadFile) to provide as context/attachments to the LLM. Do not use this together with `add_context_from_internet`. */
file_urls?: string[];
}
/**
* Parameters for the GenerateImage function.
*/
export interface GenerateImageParams {
/** Description of the image to generate. */
prompt: string;
}
export interface GenerateImageResult {
/** URL of the generated image. */
url: string;
}
/**
* Parameters for the UploadFile function.
*/
export interface UploadFileParams {
/** The file object to upload. */
file: File;
}
export interface UploadFileResult {
/** URL of the uploaded file. */
file_url: string;
}
/**
* Parameters for the SendEmail function.
*/
export interface SendEmailParams {
/** Recipient email address. */
to: string;
/** Email subject line. */
subject: string;
/** Plain text email body content. */
body: string;
/** The name of the sender. If omitted, the app's name will be used. */
from_name?: string;
}
export type SendEmailResult = any;
/**
* Parameters for the ExtractDataFromUploadedFile function.
*/
export interface ExtractDataFromUploadedFileParams {
/** The URL of the uploaded file to extract data from. */
file_url: string;
/** A [JSON schema object](https://json-schema.org/understanding-json-schema/reference/object) defining what data fields you want to extract. */
json_schema: object;
}
export type ExtractDataFromUploadedFileResult = object;
/**
* Parameters for the UploadPrivateFile function.
*/
export interface UploadPrivateFileParams {
/** The file object to upload. */
file: File;
}
export interface UploadPrivateFileResult {
/** URI of the uploaded private file, used to create a signed URL. */
file_uri: string;
}
/**
* Parameters for the CreateFileSignedUrl function.
*/
export interface CreateFileSignedUrlParams {
/** URI of the uploaded private file. */
file_uri: string;
/** How long the signed URL should be valid for, in seconds.
* @default 300 (5 minutes)
*/
expires_in?: number;
}
export interface CreateFileSignedUrlResult {
/** Temporary signed URL to access the private file. */
signed_url: string;
}
/**
* Core package containing built-in Base44 integration functions.
*/
export interface CoreIntegrations {
/**
* Generate text or structured JSON data using AI models.
*
* @param params - Parameters for the LLM invocation
* @returns Promise resolving to a string (when no schema provided) or an object (when schema provided).
*
* @example
* ```typescript
* // Basic prompt
* const response = await base44.integrations.Core.InvokeLLM({
* prompt: "Write a haiku about coding."
* });
* ```
*
* @example
* ```typescript
* // Prompt with internet context
* const response = await base44.integrations.Core.InvokeLLM({
* prompt: "What is the current stock price of Wix and what was the latest major news about it?",
* add_context_from_internet: true
* });
* ```
*
* @example
* ```typescript
* // Structured JSON response
* const response = await base44.integrations.Core.InvokeLLM({
* prompt: "Analyze the sentiment of this review: 'The service was slow but the food was amazing.'",
* response_json_schema: {
* type: "object",
* properties: {
* sentiment: { type: "string", enum: ["positive", "negative", "mixed"] },
* score: { type: "number", description: "Score from 1-10" },
* key_points: { type: "array", items: { type: "string" } }
* }
* }
* });
* // Returns object: { sentiment: "mixed", score: 7, key_points: ["slow service", "amazing food"] }
* ```
*/
InvokeLLM(params: InvokeLLMParams): Promise<string | object>;
/**
* Create AI-generated images from text prompts.
*
* Images are generated as PNG files at approximately 1024px on the shorter side. The
* exact dimensions vary by aspect ratio.
*
* Prompts that violate the AI provider's content policy will be refused.
*
* @param params - Parameters for image generation
* @returns Promise resolving to an object containing the URL of the generated PNG image.
*
* @example
* ```typescript
* // Generate an image from a text prompt
* const {url} = await base44.integrations.Core.GenerateImage({
* prompt: "A serene mountain landscape with a lake in the foreground"
* });
* console.log(url); // https://...generated_image.png
* ```
*/
GenerateImage(params: GenerateImageParams): Promise<GenerateImageResult>;
/**
* Upload files to public storage and get a URL.
*
* @param params - Parameters for file upload
* @returns Promise resolving to an object containing the uploaded file URL.
*
* @example
* ```typescript
* // Upload a file in React
* const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
* const file = event.target.files?.[0];
* if (!file) return;
*
* const { file_url } = await base44.integrations.Core.UploadFile({ file });
* console.log(file_url); // https://...uploaded_file.pdf
* };
* ```
*/
UploadFile(params: UploadFileParams): Promise<UploadFileResult>;
/**
* Send emails to registered users of your app.
*
* @param params - Parameters for sending email
* @returns Promise resolving when the email is sent.
*/
SendEmail(params: SendEmailParams): Promise<SendEmailResult>;
/**
* Extract structured data from uploaded files based on the specified schema.
*
* Start by uploading the file to public storage using the {@linkcode UploadFile | UploadFile()} function. Then, use the `file_url` parameter to extract structured data from the uploaded file.
*
* @param params - Parameters for data extraction
* @returns Promise resolving to the extracted data.
*
* @example
* ```typescript
* // Extract data from an already uploaded file
* const result = await base44.integrations.Core.ExtractDataFromUploadedFile({
* file_url: "https://example.com/files/invoice.pdf",
* json_schema: {
* type: "object",
* properties: {
* invoice_number: { type: "string" },
* total_amount: { type: "number" },
* date: { type: "string" },
* vendor_name: { type: "string" }
* }
* }
* });
* console.log(result); // { invoice_number: "INV-12345", total_amount: 1250.00, ... }
* ```
*
* @example
* ```typescript
* // Upload a file and extract data in React
* const handleFileExtraction = async (event: React.ChangeEvent<HTMLInputElement>) => {
* const file = event.target.files?.[0];
* if (!file) return;
*
* // First, upload the file
* const { file_url } = await base44.integrations.Core.UploadFile({ file });
*
* // Then extract structured data from it
* const result = await base44.integrations.Core.ExtractDataFromUploadedFile({
* file_url,
* json_schema: {
* type: "object",
* properties: {
* summary: {
* type: "string",
* description: "A brief summary of the file content"
* },
* keywords: {
* type: "array",
* items: { type: "string" }
* },
* document_type: {
* type: "string"
* }
* }
* }
* });
* console.log(result); // { summary: "...", keywords: [...], document_type: "..." }
* };
* ```
*/
ExtractDataFromUploadedFile(params: ExtractDataFromUploadedFileParams): Promise<ExtractDataFromUploadedFileResult>;
/**
* Upload files to private storage that requires a signed URL to access.
*
* Create a signed URL to access uploaded files using the {@linkcode CreateFileSignedUrl | CreateFileSignedUrl()} function.
*
* @param params - Parameters for private file upload
* @returns Promise resolving to an object with a `file_uri` used to create a signed URL to access the uploaded file.
*
* @example
* ```typescript
* // Upload a private file
* const { file_uri } = await base44.integrations.Core.UploadPrivateFile({ file });
* console.log(file_uri); // "private/user123/document.pdf"
* ```
*
* @example
* ```typescript
* // Upload a private file and create a signed URL
* const handlePrivateUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
* const file = event.target.files?.[0];
* if (!file) return;
*
* // Upload to private storage
* const { file_uri } = await base44.integrations.Core.UploadPrivateFile({ file });
*
* // Create a signed URL that expires in 1 hour (3600 seconds)
* const { signed_url } = await base44.integrations.Core.CreateFileSignedUrl({
* file_uri,
* expires_in: 3600
* });
*
* console.log(signed_url); // Temporary URL to access the private file
* };
* ```
*/
UploadPrivateFile(params: UploadPrivateFileParams): Promise<UploadPrivateFileResult>;
/**
* Generate temporary access links for private files.
*
* Start by uploading the file to private storage using the {@linkcode UploadPrivateFile | UploadPrivateFile()} function. Then, use the `file_uri` parameter to create a signed URL to access the uploaded file.
*
* @param params - Parameters for creating signed URL
* @returns Promise resolving to an object with a temporary `signed_url`.
*
* @example
* ```typescript
* // Create a signed URL for a private file
* const { signed_url } = await base44.integrations.Core.CreateFileSignedUrl({
* file_uri: "private/user123/document.pdf",
* expires_in: 7200 // URL expires in 2 hours
* });
* console.log(signed_url); // https://...?signature=...
* ```
*/
CreateFileSignedUrl(params: CreateFileSignedUrlParams): Promise<CreateFileSignedUrlResult>;
}
/**
* Integrations module for calling integration methods.
*
* This module provides access to integration methods for interacting with external services. Unlike the connectors module that gives you raw OAuth tokens, integrations provide pre-built functions that Base44 executes on your behalf.
*
* ## Integration Types
*
* There are two types of integrations:
*
* - **Built-in integrations** (`Core`): Pre-built functions provided by Base44 for common tasks such as AI-powered text generation, image creation, file uploads, and email. Access core integration methods using:
* ```
* base44.integrations.Core.FunctionName(params)
* ```
*
* - **Custom workspace integrations** (`custom`): Pre-configured external APIs set up by workspace administrators. Workspace integration calls are proxied through Base44's backend, so credentials are never exposed to the frontend. Access custom workspace integration methods using:
* ```
* base44.integrations.custom.call(slug, operationId, params)
* ```
*
* <Info>To call a custom workspace integration, it must be pre-configured by a workspace administrator who imports an OpenAPI specification. Learn more about [custom workspace integrations](/documentation/integrations/managing-workspace-integrations).</Info>
*
* ## Authentication Modes
*
* This module is available to use with a client in all authentication modes:
*
* - **Anonymous or User authentication** (`base44.integrations`): Integration methods are invoked with the current user's permissions. Anonymous users invoke methods without authentication, while authenticated users invoke methods with their authentication context.
* - **Service role authentication** (`base44.asServiceRole.integrations`): Integration methods are invoked with elevated admin-level permissions. The methods execute with admin authentication context.
*/
export type IntegrationsModule = {
/**
* Core package containing built-in Base44 integration functions.
*
* @example
* ```typescript
* const response = await base44.integrations.Core.InvokeLLM({
* prompt: 'Explain quantum computing',
* model: 'gpt_5'
* });
* ```
*/
Core: CoreIntegrations;
/**
* Workspace integrations module for calling pre-configured external APIs.
*
* @example
* ```typescript
* const result = await base44.integrations.custom.call(
* 'github',
* 'get:/repos/{owner}/{repo}',
* { pathParams: { owner: 'myorg', repo: 'myrepo' } }
* );
* ```
*/
custom: CustomIntegrationsModule;
} & {
/**
* Access to additional integration packages.
*
* Allows accessing integration packages as properties. This enables both `Core` and `custom` packages,
* as well as any future integration packages that may be added.
*
* @example **Use Core integrations**
* ```typescript
* const response = await base44.integrations.Core.InvokeLLM({
* prompt: 'Explain quantum computing',
* model: 'gpt_5'
* });
* ```
*
* @example **Use custom integrations**
* ```typescript
* const result = await base44.integrations.custom.call(
* 'github',
* 'get:/repos/{owner}/{repo}',
* { pathParams: { owner: 'myorg', repo: 'myrepo' } }
* );
* ```
*/
[packageName: string]: IntegrationPackage;
};
+1
View File
@@ -0,0 +1 @@
export {};
+12
View File
@@ -0,0 +1,12 @@
import { AxiosInstance } from "axios";
import { SsoModule } from "./sso.types";
/**
* Creates the SSO module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @param userToken - User authentication token
* @returns SSO module with authentication methods
* @internal
*/
export declare function createSsoModule(axios: AxiosInstance, appId: string): SsoModule;
+18
View File
@@ -0,0 +1,18 @@
/**
* Creates the SSO module for the Base44 SDK.
*
* @param axios - Axios instance
* @param appId - Application ID
* @param userToken - User authentication token
* @returns SSO module with authentication methods
* @internal
*/
export function createSsoModule(axios, appId) {
return {
// Get SSO access token for a specific user
async getAccessToken(userid) {
const url = `/apps/${appId}/auth/sso/accesstoken/${userid}`;
return axios.get(url);
},
};
}
+44
View File
@@ -0,0 +1,44 @@
/**
* Response from SSO access token endpoint.
* @internal
*/
export interface SsoAccessTokenResponse {
access_token: string;
}
/**
* SSO (Single Sign-On) module for managing SSO authentication.
*
* This module provides methods for retrieving SSO access tokens for users.
* These tokens allow you to authenticate Base44 users with external
* systems or services.
*
* This module is only available to use with a client in service role authentication mode, which means it can only be used in backend environments.
*
* @internal
*
* @example
* ```typescript
* // Access SSO module with service role
* const response = await base44.asServiceRole.sso.getAccessToken('user_123');
* console.log(response.data.access_token);
* ```
*/
export interface SsoModule {
/**
* Gets SSO access token for a specific user.
*
* Retrieves a Single Sign-On access token that can be used to authenticate
* a user with external services or systems.
*
* @param userid - The user ID to get the access token for.
* @returns Promise resolving to the SSO access token response.
*
* @example
* ```typescript
* // Get SSO access token for a user
* const response = await base44.asServiceRole.sso.getAccessToken('user_123');
* console.log(response.access_token);
* ```
*/
getAccessToken(userid: string): Promise<SsoAccessTokenResponse>;
}
+1
View File
@@ -0,0 +1 @@
export {};
+4
View File
@@ -0,0 +1,4 @@
export * from "./app.types.js";
export * from "./agents.types.js";
export * from "./connectors.types.js";
export * from "./analytics.types.js";
+4
View File
@@ -0,0 +1,4 @@
export * from "./app.types.js";
export * from "./agents.types.js";
export * from "./connectors.types.js";
export * from "./analytics.types.js";
+16
View File
@@ -0,0 +1,16 @@
import { AxiosInstance } from "axios";
/**
* Creates the users module for the Base44 SDK
* @param {AxiosInstance} axios - Axios instance
* @param {string} appId - Application ID
* @returns {Object} Users module
*/
export declare function createUsersModule(axios: AxiosInstance, appId: string): {
/**
* Invite a user to the application
* @param {string} user_email - User's email address
* @param {'user'|'admin'} role - User's role (user or admin)
* @returns {Promise<any>}
*/
inviteUser(user_email: string, role: "user" | "admin"): Promise<any>;
};
+23
View File
@@ -0,0 +1,23 @@
/**
* Creates the users module for the Base44 SDK
* @param {AxiosInstance} axios - Axios instance
* @param {string} appId - Application ID
* @returns {Object} Users module
*/
export function createUsersModule(axios, appId) {
return {
/**
* Invite a user to the application
* @param {string} user_email - User's email address
* @param {'user'|'admin'} role - User's role (user or admin)
* @returns {Promise<any>}
*/
async inviteUser(user_email, role) {
if (role !== "user" && role !== "admin") {
throw new Error(`Invalid role: "${role}". Role must be either "user" or "admin".`);
}
const response = await axios.post(`/apps/${appId}/runtime/users/invite-user`, { user_email, role });
return response;
},
};
}
+72
View File
@@ -0,0 +1,72 @@
export * from "./modules/types.js";
/**
* Parameters for filtering, sorting, and paginating agent model data.
*
* Used in the agents module for querying agent conversations. Provides a structured way to specify query criteria, sorting, pagination, and field selection.
*
* @property q - Query object with field-value pairs for filtering.
* @property sort - Sort parameter. For example, "-created_date" for descending order.
* @property sort_by - Alternative sort parameter. Use either `sort` or `sort_by`.
* @property limit - Maximum number of results to return.
* @property skip - Number of results to skip. Used for pagination.
* @property fields - Array of field names to include in the response.
*
* @example
* ```typescript
* // Filter conversations by agent name
* const conversations = await base44.agents.listConversations({
* q: { agent_name: 'support-bot' }
* });
* ```
*
* @example
* ```typescript
* // Filter conversations with sorting
* const conversations = await base44.agents.listConversations({
* q: { status: 'active' },
* sort: '-created_at' // Sort by created_at descending
* });
* ```
*
* @example
* ```typescript
* // Filter conversations with pagination
* const conversations = await base44.agents.listConversations({
* q: { agent_name: 'support-bot' },
* limit: 20, // Get 20 results
* skip: 40 // Skip first 40 (page 3)
* });
* ```
*
* @example
* ```typescript
* // Filter conversations with field selection
* const conversations = await base44.agents.listConversations({
* q: { status: 'active' },
* fields: ['id', 'agent_name', 'created_at']
* });
* ```
*
* @example
* ```typescript
* // Filter conversations with multiple filters
* const conversations = await base44.agents.listConversations({
* q: {
* agent_name: 'support-bot',
* 'metadata.priority': 'high',
* status: 'active'
* },
* sort: '-updated_at',
* limit: 50,
* skip: 0
* });
* ```
*/
export interface ModelFilterParams {
q?: Record<string, any>;
sort?: string | null;
sort_by?: string | null;
limit?: number | null;
skip?: number | null;
fields?: string[] | null;
}
+1
View File
@@ -0,0 +1 @@
export * from "./modules/types.js";
+117
View File
@@ -0,0 +1,117 @@
import { GetAccessTokenOptions, SaveAccessTokenOptions, RemoveAccessTokenOptions, GetLoginUrlOptions } from "./auth-utils.types.js";
/**
* Retrieves an access token from URL parameters or local storage.
*
* Low-level utility for manually retrieving tokens. In most cases, the Base44 client handles
* token management automatically. This function is useful for custom authentication flows or when you need direct access to stored tokens. Requires a browser environment and can't be used in the backend.
*
* @internal
*
* @param options - Configuration options for token retrieval.
* @returns The access token string if found, null otherwise.
*
* @example
* ```typescript
* // Get access token from URL or local storage
* const token = getAccessToken();
*
* if (token) {
* console.log('User is authenticated');
* } else {
* console.log('No token found, redirect to login');
* }
* ```
* @example
* ```typescript
* // Get access token from custom local storage key
* const token = getAccessToken({ storageKey: 'my_app_token' });
* ```
* @example
* ```typescript
* // Get access token from URL but don't save or remove it
* const token = getAccessToken({
* saveToStorage: false,
* removeFromUrl: false
* });
* ```
*/
export declare function getAccessToken(options?: GetAccessTokenOptions): string | null;
/**
* Saves an access token to local storage.
*
* Low-level utility for manually saving tokens. In most cases, the Base44 client handles token management automatically. This function is useful for custom authentication flows or managing custom tokens. Requires a browser environment and can't be used in the backend.
*
* @internal
*
* @param token - The access token string to save.
* @param options - Configuration options for saving the token.
* @returns Returns`true` if the token was saved successfully, `false` otherwise.
*
* @example
* ```typescript
* // Save access token after login
* const response = await base44.auth.loginViaEmailPassword(email, password);
* const success = saveAccessToken(response.access_token, {});
*
* if (success) {
* console.log('User is now authenticated');
* // Token is now available for future page loads
* }
* ```
* @example
* ```typescript
* // Save access token to local storage using custom key
* const success = saveAccessToken(token, {
* storageKey: `my_custom_token_key`
* });
* ```
*/
export declare function saveAccessToken(token: string, options: SaveAccessTokenOptions): boolean;
/**
* Removes the access token from local storage.
*
* Low-level utility for manually removing tokens from the browser's local storage. In most cases, the Base44 client handles token management automatically. For standard logout flows, use {@linkcode AuthModule.logout | base44.auth.logout()} instead, which handles token removal and redirects automatically. This function is useful for custom authentication flows or when you need to manually remove tokens. Requires a browser environment and can't be used in the backend.
*
* @internal
*
* @param options - Configuration options for token removal.
* @returns Returns `true` if the token was removed successfully, `false` otherwise.
*
* @example
* ```typescript
* // Remove custom token key
* const success = removeAccessToken({
* storageKey: 'my_custom_token_key'
* });
* ```
*
* @example
* ```typescript
* // Standard logout flow with token removal and redirect
* base44.auth.logout('/login');
* ```
*/
export declare function removeAccessToken(options: RemoveAccessTokenOptions): boolean;
/**
* Constructs the absolute URL for the login page with a redirect parameter.
*
* Low-level utility for building login URLs. For standard login redirects, use {@linkcode AuthModule.redirectToLogin | base44.auth.redirectToLogin()} instead, which handles this automatically. This function is useful when you need to construct login URLs without a client instance or for custom authentication flows.
*
* @internal
*
* @param nextUrl - The URL to redirect to after successful login.
* @param options - Configuration options.
* @returns The complete login URL with encoded redirect parameters.
*
* @example
* ```typescript
* // Redirect to login page
* const loginUrl = getLoginUrl('/dashboard', {
* serverUrl: 'https://base44.app',
* appId: 'my-app-123'
* });
* window.location.href = loginUrl;
* // User will be redirected back to /dashboard after login
* ```
*/
export declare function getLoginUrl(nextUrl: string, options: GetLoginUrlOptions): string;
+189
View File
@@ -0,0 +1,189 @@
/**
* Retrieves an access token from URL parameters or local storage.
*
* Low-level utility for manually retrieving tokens. In most cases, the Base44 client handles
* token management automatically. This function is useful for custom authentication flows or when you need direct access to stored tokens. Requires a browser environment and can't be used in the backend.
*
* @internal
*
* @param options - Configuration options for token retrieval.
* @returns The access token string if found, null otherwise.
*
* @example
* ```typescript
* // Get access token from URL or local storage
* const token = getAccessToken();
*
* if (token) {
* console.log('User is authenticated');
* } else {
* console.log('No token found, redirect to login');
* }
* ```
* @example
* ```typescript
* // Get access token from custom local storage key
* const token = getAccessToken({ storageKey: 'my_app_token' });
* ```
* @example
* ```typescript
* // Get access token from URL but don't save or remove it
* const token = getAccessToken({
* saveToStorage: false,
* removeFromUrl: false
* });
* ```
*/
export function getAccessToken(options = {}) {
const { storageKey = "base44_access_token", paramName = "access_token", saveToStorage = true, removeFromUrl = true, } = options;
let token = null;
// Try to get token from URL parameters
if (typeof window !== "undefined" && window.location) {
try {
const urlParams = new URLSearchParams(window.location.search);
token = urlParams.get(paramName);
// If token found in URL
if (token) {
// Save token to local storage if requested
if (saveToStorage) {
saveAccessToken(token, { storageKey });
}
// Remove token from URL for security if requested
if (removeFromUrl) {
urlParams.delete(paramName);
const newUrl = `${window.location.pathname}${urlParams.toString() ? `?${urlParams.toString()}` : ""}${window.location.hash}`;
window.history.replaceState({}, document.title, newUrl);
}
return token;
}
}
catch (e) {
console.error("Error retrieving token from URL:", e);
}
}
// If no token in URL, try local storage
if (typeof window !== "undefined" && window.localStorage) {
try {
token = window.localStorage.getItem(storageKey);
return token;
}
catch (e) {
console.error("Error retrieving token from local storage:", e);
}
}
return null;
}
/**
* Saves an access token to local storage.
*
* Low-level utility for manually saving tokens. In most cases, the Base44 client handles token management automatically. This function is useful for custom authentication flows or managing custom tokens. Requires a browser environment and can't be used in the backend.
*
* @internal
*
* @param token - The access token string to save.
* @param options - Configuration options for saving the token.
* @returns Returns`true` if the token was saved successfully, `false` otherwise.
*
* @example
* ```typescript
* // Save access token after login
* const response = await base44.auth.loginViaEmailPassword(email, password);
* const success = saveAccessToken(response.access_token, {});
*
* if (success) {
* console.log('User is now authenticated');
* // Token is now available for future page loads
* }
* ```
* @example
* ```typescript
* // Save access token to local storage using custom key
* const success = saveAccessToken(token, {
* storageKey: `my_custom_token_key`
* });
* ```
*/
export function saveAccessToken(token, options) {
const { storageKey = "base44_access_token" } = options;
if (typeof window === "undefined" || !window.localStorage || !token) {
return false;
}
try {
window.localStorage.setItem(storageKey, token);
// Set "token" that is set by the built-in SDK of platform version 2
window.localStorage.setItem("token", token);
return true;
}
catch (e) {
console.error("Error saving token to local storage:", e);
return false;
}
}
/**
* Removes the access token from local storage.
*
* Low-level utility for manually removing tokens from the browser's local storage. In most cases, the Base44 client handles token management automatically. For standard logout flows, use {@linkcode AuthModule.logout | base44.auth.logout()} instead, which handles token removal and redirects automatically. This function is useful for custom authentication flows or when you need to manually remove tokens. Requires a browser environment and can't be used in the backend.
*
* @internal
*
* @param options - Configuration options for token removal.
* @returns Returns `true` if the token was removed successfully, `false` otherwise.
*
* @example
* ```typescript
* // Remove custom token key
* const success = removeAccessToken({
* storageKey: 'my_custom_token_key'
* });
* ```
*
* @example
* ```typescript
* // Standard logout flow with token removal and redirect
* base44.auth.logout('/login');
* ```
*/
export function removeAccessToken(options) {
const { storageKey = "base44_access_token" } = options;
if (typeof window === "undefined" || !window.localStorage) {
return false;
}
try {
window.localStorage.removeItem(storageKey);
return true;
}
catch (e) {
console.error("Error removing token from local storage:", e);
return false;
}
}
/**
* Constructs the absolute URL for the login page with a redirect parameter.
*
* Low-level utility for building login URLs. For standard login redirects, use {@linkcode AuthModule.redirectToLogin | base44.auth.redirectToLogin()} instead, which handles this automatically. This function is useful when you need to construct login URLs without a client instance or for custom authentication flows.
*
* @internal
*
* @param nextUrl - The URL to redirect to after successful login.
* @param options - Configuration options.
* @returns The complete login URL with encoded redirect parameters.
*
* @example
* ```typescript
* // Redirect to login page
* const loginUrl = getLoginUrl('/dashboard', {
* serverUrl: 'https://base44.app',
* appId: 'my-app-123'
* });
* window.location.href = loginUrl;
* // User will be redirected back to /dashboard after login
* ```
*/
export function getLoginUrl(nextUrl, options) {
const { serverUrl, appId, loginPath = "/login" } = options;
if (!serverUrl || !appId) {
throw new Error("serverUrl and appId are required to construct login URL");
}
const encodedRedirectUrl = encodeURIComponent(nextUrl || (typeof window !== "undefined" ? window.location.href : ""));
return `${serverUrl}${loginPath}?from_url=${encodedRedirectUrl}&app_id=${appId}`;
}
+146
View File
@@ -0,0 +1,146 @@
/**
* Configuration options for retrieving an access token.
*
* @internal
*
* @example
* ```typescript
* // Get access token from URL or local storage using default options
* const token = getAccessToken();
* ```
*
* @example
* ```typescript
* // Get access token from custom local storage key
* const token = getAccessToken({ storageKey: 'my_app_token' });
* ```
*
* @example
* ```typescript
* // Get token from URL but don't save or remove from URL
* const token = getAccessToken({
* saveToStorage: false,
* removeFromUrl: false
* });
* ```
*/
export interface GetAccessTokenOptions {
/**
* The key to use when storing or retrieving the token in local storage.
* @default 'base44_access_token'
*/
storageKey?: string;
/**
* The URL parameter name to check for the access token.
* @default 'access_token'
*/
paramName?: string;
/**
* Whether to save the token to local storage if found in the URL.
* @default true
*/
saveToStorage?: boolean;
/**
* Whether to remove the token from the URL after retrieval for security.
* @default true
*/
removeFromUrl?: boolean;
}
/**
* Configuration options for saving an access token.
*
* @internal
*
* @example
* ```typescript
* // Use default storage key
* saveAccessToken('my-token-123', {});
*
* // Use custom storage key
* saveAccessToken('my-token-123', { storageKey: 'my_app_token' });
* ```
*/
export interface SaveAccessTokenOptions {
/**
* The key to use when storing the token in local storage.
* @default 'base44_access_token'
*/
storageKey?: string;
}
/**
* Configuration options for removing an access token.
*
* @internal
*
* @example
* ```typescript
* // Remove token from default storage key
* removeAccessToken({});
*
* // Remove token from custom storage key
* removeAccessToken({ storageKey: 'my_app_token' });
* ```
*/
export interface RemoveAccessTokenOptions {
/**
* The key to use when removing the token from local storage.
* @default 'base44_access_token'
*/
storageKey?: string;
}
/**
* Configuration options for constructing a login URL.
*
* @internal
*
* @example
* ```typescript
* const loginUrl = getLoginUrl('/dashboard', {
* serverUrl: 'https://base44.app',
* appId: 'my-app-123'
* });
* // Returns: 'https://base44.app/login?from_url=%2Fdashboard&app_id=my-app-123'
*
* // Custom login path
* const loginUrl = getLoginUrl('/dashboard', {
* serverUrl: 'https://base44.app',
* appId: 'my-app-123',
* loginPath: '/auth/login'
* });
* ```
*/
export interface GetLoginUrlOptions {
/**
* The base server URL (e.g., 'https://base44.app').
*/
serverUrl: string;
/**
* The app ID.
*/
appId: string;
/**
* The path to the login endpoint.
* @default '/login'
*/
loginPath?: string;
}
/**
* Type definition for getAccessToken function.
* @internal
*/
export type GetAccessTokenFunction = (options?: GetAccessTokenOptions) => string | null;
/**
* Type definition for saveAccessToken function.
* @internal
*/
export type SaveAccessTokenFunction = (token: string, options: SaveAccessTokenOptions) => boolean;
/**
* Type definition for removeAccessToken function.
* @internal
*/
export type RemoveAccessTokenFunction = (options: RemoveAccessTokenOptions) => boolean;
/**
* Type definition for getLoginUrl function.
* @internal
*/
export type GetLoginUrlFunction = (nextUrl: string, options: GetLoginUrlOptions) => string;
+1
View File
@@ -0,0 +1 @@
export {};
+100
View File
@@ -0,0 +1,100 @@
import type { Base44ErrorJSON } from "./axios-client.types.js";
/**
* Custom error class for Base44 SDK errors.
*
* This error is thrown when API requests fail. It extends the standard `Error` class and includes additional information about the HTTP status, error code, and response data from the server.
*
* @example
* ```typescript
* try {
* await client.entities.Todo.get('invalid-id');
* } catch (error) {
* if (error instanceof Base44Error) {
* console.error('Status:', error.status); // 404
* console.error('Message:', error.message); // "Not found"
* console.error('Code:', error.code); // "NOT_FOUND"
* console.error('Data:', error.data); // Full response data
* }
* }
* ```
*
*/
export declare class Base44Error extends Error {
/**
* HTTP status code of the error.
*/
status: number;
/**
* Error code from the API.
*/
code: string;
/**
* Full response data from the server containing error details.
*/
data: any;
/**
* The original error object from Axios.
*/
originalError: unknown;
/**
* Creates a new Base44Error instance.
*
* @param message - Human-readable error message
* @param status - HTTP status code
* @param code - Error code from the API
* @param data - Full response data from the server
* @param originalError - Original axios error object
* @internal
*/
constructor(message: string, status: number, code: string, data: any, originalError: unknown);
/**
* Serializes the error to a JSON-safe object.
*
* Useful for logging or sending error information to external services
* without circular reference issues.
*
* @returns JSON-safe representation of the error.
*
* @example
* ```typescript
* try {
* await client.entities.Todo.get('invalid-id');
* } catch (error) {
* if (error instanceof Base44Error) {
* const json = error.toJSON();
* console.log(json);
* // {
* // name: "Base44Error",
* // message: "Not found",
* // status: 404,
* // code: "NOT_FOUND",
* // data: { ... }
* // }
* }
* }
* ```
*/
toJSON(): Base44ErrorJSON;
}
/**
* Creates an axios client with default configuration and interceptors.
*
* Sets up an axios instance with:
* - Default headers
* - Authentication token injection
* - Response data unwrapping
* - Error transformation to Base44Error
* - iframe messaging support
*
* @param options - Client configuration options
* @returns Configured axios instance
* @internal
*/
export declare function createAxiosClient({ baseURL, headers, token, interceptResponses, onError, }: {
baseURL: string;
headers?: Record<string, string>;
token?: string;
interceptResponses?: boolean;
onError?: (error: Error) => void;
}): import("axios").AxiosInstance;
export type { Base44ErrorJSON } from "./axios-client.types.js";
+193
View File
@@ -0,0 +1,193 @@
import axios from "axios";
import { isInIFrame } from "./common.js";
import { v4 as uuidv4 } from "uuid";
/**
* Custom error class for Base44 SDK errors.
*
* This error is thrown when API requests fail. It extends the standard `Error` class and includes additional information about the HTTP status, error code, and response data from the server.
*
* @example
* ```typescript
* try {
* await client.entities.Todo.get('invalid-id');
* } catch (error) {
* if (error instanceof Base44Error) {
* console.error('Status:', error.status); // 404
* console.error('Message:', error.message); // "Not found"
* console.error('Code:', error.code); // "NOT_FOUND"
* console.error('Data:', error.data); // Full response data
* }
* }
* ```
*
*/
export class Base44Error extends Error {
/**
* Creates a new Base44Error instance.
*
* @param message - Human-readable error message
* @param status - HTTP status code
* @param code - Error code from the API
* @param data - Full response data from the server
* @param originalError - Original axios error object
* @internal
*/
constructor(message, status, code, data, originalError) {
super(message);
this.name = "Base44Error";
this.status = status;
this.code = code;
this.data = data;
this.originalError = originalError;
}
/**
* Serializes the error to a JSON-safe object.
*
* Useful for logging or sending error information to external services
* without circular reference issues.
*
* @returns JSON-safe representation of the error.
*
* @example
* ```typescript
* try {
* await client.entities.Todo.get('invalid-id');
* } catch (error) {
* if (error instanceof Base44Error) {
* const json = error.toJSON();
* console.log(json);
* // {
* // name: "Base44Error",
* // message: "Not found",
* // status: 404,
* // code: "NOT_FOUND",
* // data: { ... }
* // }
* }
* }
* ```
*/
toJSON() {
return {
name: this.name,
message: this.message,
status: this.status,
code: this.code,
data: this.data,
};
}
}
/**
* Safely logs error information without circular references.
*
* @param prefix - Prefix for the log message
* @param error - The error to log
* @internal
*/
function safeErrorLog(prefix, error) {
if (error instanceof Base44Error) {
console.error(`${prefix} ${error.status}: ${error.message}`);
if (error.data) {
try {
console.error("Error data:", JSON.stringify(error.data, null, 2));
}
catch (e) {
console.error("Error data: [Cannot stringify error data]");
}
}
}
else {
console.error(`${prefix} ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Creates an axios client with default configuration and interceptors.
*
* Sets up an axios instance with:
* - Default headers
* - Authentication token injection
* - Response data unwrapping
* - Error transformation to Base44Error
* - iframe messaging support
*
* @param options - Client configuration options
* @returns Configured axios instance
* @internal
*/
export function createAxiosClient({ baseURL, headers = {}, token, interceptResponses = true, onError, }) {
const client = axios.create({
baseURL,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
...headers,
},
});
// Add token to requests if available
if (token) {
client.defaults.headers.common["Authorization"] = `Bearer ${token}`;
}
// Add origin URL in browser environment
client.interceptors.request.use((config) => {
if (typeof window !== "undefined") {
config.headers.set("X-Origin-URL", window.location.href);
}
const requestId = uuidv4();
config.requestId = requestId;
if (isInIFrame) {
try {
window.parent.postMessage({
type: "api-request-start",
requestId,
data: {
url: baseURL + config.url,
method: config.method,
body: config.data instanceof FormData
? "[FormData object]"
: config.data,
},
}, "*");
}
catch (_a) {
/* skip the logging */
}
}
return config;
});
// Handle responses
if (interceptResponses) {
client.interceptors.response.use((response) => {
var _a;
const requestId = (_a = response.config) === null || _a === void 0 ? void 0 : _a.requestId;
try {
if (isInIFrame && requestId) {
window.parent.postMessage({
type: "api-request-end",
requestId,
data: {
statusCode: response.status,
response: response.data,
},
}, "*");
}
}
catch (_b) {
/* do nothing */
}
return response.data;
}, (error) => {
var _a, _b, _c, _d, _e, _f, _g, _h;
const message = ((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) ||
((_d = (_c = error.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.detail) ||
error.message;
const base44Error = new Base44Error(message, (_e = error.response) === null || _e === void 0 ? void 0 : _e.status, (_g = (_f = error.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.code, (_h = error.response) === null || _h === void 0 ? void 0 : _h.data, error);
// Log errors in development
if (process.env.NODE_ENV !== "production") {
safeErrorLog("[Base44 SDK Error]", base44Error);
}
onError === null || onError === void 0 ? void 0 : onError(base44Error);
return Promise.reject(base44Error);
});
}
return client;
}
+28
View File
@@ -0,0 +1,28 @@
/**
* JSON representation of a Base44Error.
*
* This is the structure returned by {@linkcode Base44Error.toJSON | Base44Error.toJSON()}.
* Useful for logging or sending error information to external services.
*/
export interface Base44ErrorJSON {
/**
* The error name, always "Base44Error".
*/
name: string;
/**
* Human-readable error message.
*/
message: string;
/**
* HTTP status code of the error.
*/
status: number;
/**
* Error code from the API.
*/
code: string;
/**
* Full response data from the server containing error details.
*/
data: any;
}
+1
View File
@@ -0,0 +1 @@
export {};
+3
View File
@@ -0,0 +1,3 @@
export declare const isNode: boolean;
export declare const isInIFrame: boolean;
export declare const generateUuid: () => string;
+6
View File
@@ -0,0 +1,6 @@
export const isNode = typeof window === "undefined";
export const isInIFrame = !isNode && window.self !== window.top;
export const generateUuid = () => {
return (Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15));
};
+1
View File
@@ -0,0 +1 @@
export declare function getSharedInstance<T>(name: string, factory: () => T): T;
+15
View File
@@ -0,0 +1,15 @@
const windowObj = typeof window !== "undefined"
? window
: { base44SharedInstances: {} };
// Singleton (shared between sdk instances)//
export function getSharedInstance(name, factory) {
if (!windowObj.base44SharedInstances) {
windowObj.base44SharedInstances = {};
}
if (!windowObj.base44SharedInstances[name]) {
windowObj.base44SharedInstances[name] = {
instance: factory(),
};
}
return windowObj.base44SharedInstances[name].instance;
}
+47
View File
@@ -0,0 +1,47 @@
import { Socket } from "socket.io-client";
export interface RoomsSocketConfig {
serverUrl: string;
mountPath: string;
transports: string[];
appId: string;
token?: string;
}
export type TSocketRoom = string;
export type TJsonStr = string;
type RoomsSocketEventsMap = {
listen: {
connect: () => Promise<void> | void;
update_model: (msg: {
room: string;
data: TJsonStr;
}) => Promise<void> | void;
error: (error: Error) => Promise<void> | void;
};
emit: {
join: (room: string) => void;
leave: (room: string) => void;
};
};
type TEvent = keyof RoomsSocketEventsMap["listen"];
type THandler<E extends TEvent> = RoomsSocketEventsMap["listen"][E];
export type RoomsSocket = ReturnType<typeof RoomsSocket>;
export declare function RoomsSocket({ config }: {
config: RoomsSocketConfig;
}): {
socket: Socket<{
connect: () => Promise<void> | void;
update_model: (msg: {
room: string;
data: TJsonStr;
}) => Promise<void> | void;
error: (error: Error) => Promise<void> | void;
}, {
join: (room: string) => void;
leave: (room: string) => void;
}>;
subscribeToRoom: (room: TSocketRoom, handlers: Partial<{ [k in TEvent]: THandler<k>; }>) => () => void;
updateConfig: (config: Partial<RoomsSocketConfig>) => void;
updateModel: (room: string, data: any) => Promise<void>;
disconnect: () => void;
};
export {};
+160
View File
@@ -0,0 +1,160 @@
import { io } from "socket.io-client";
import { getAccessToken } from "./auth-utils.js";
const ROOM_LEAVE_GRACE_MS = 250;
function initializeSocket(config, handlers) {
var _a;
const socket = io(config.serverUrl, {
path: config.mountPath,
transports: config.transports,
query: {
app_id: config.appId,
token: (_a = config.token) !== null && _a !== void 0 ? _a : getAccessToken(),
},
});
socket.on("connect", async () => {
var _a;
console.log("connect", socket.id);
return (_a = handlers.connect) === null || _a === void 0 ? void 0 : _a.call(handlers);
});
socket.on("update_model", async (msg) => {
var _a;
return (_a = handlers.update_model) === null || _a === void 0 ? void 0 : _a.call(handlers, msg);
});
socket.on("error", async (error) => {
var _a;
return (_a = handlers.error) === null || _a === void 0 ? void 0 : _a.call(handlers, error);
});
socket.on("connect_error", async (error) => {
var _a;
console.error("connect_error", error);
return (_a = handlers.error) === null || _a === void 0 ? void 0 : _a.call(handlers, error);
});
return socket;
}
export function RoomsSocket({ config }) {
let currentConfig = { ...config };
const roomsToListeners = {};
const pendingRoomLeaves = {};
const handlers = {
connect: async () => {
const promises = [];
Object.keys(roomsToListeners).forEach((room) => {
const listeners = getListeners(room);
if (listeners.length === 0) {
return;
}
joinRoom(room);
listeners.forEach(({ connect }) => {
const promise = async () => connect === null || connect === void 0 ? void 0 : connect();
promises.push(promise());
});
});
await Promise.all(promises);
},
update_model: async (msg) => {
const listeners = getListeners(msg.room);
const promises = listeners.map((listener) => { var _a; return (_a = listener.update_model) === null || _a === void 0 ? void 0 : _a.call(listener, msg); });
await Promise.all(promises);
},
error: async (error) => {
console.error("error", error);
const promises = Object.values(roomsToListeners)
.flat()
.map((listener) => { var _a; return (_a = listener.error) === null || _a === void 0 ? void 0 : _a.call(listener, error); });
await Promise.all(promises);
},
};
let socket = initializeSocket(config, handlers);
function cleanup() {
disconnect();
}
function disconnect() {
clearPendingRoomLeaves();
if (socket) {
socket.disconnect();
}
}
function updateConfig(config) {
cleanup();
currentConfig = {
...currentConfig,
...config,
};
socket = initializeSocket(currentConfig, handlers);
}
function joinRoom(room) {
socket.emit("join", room);
}
function leaveRoom(room) {
socket.emit("leave", room);
}
async function updateModel(room, data) {
var _a;
const dataStr = JSON.stringify(data);
return (_a = handlers.update_model) === null || _a === void 0 ? void 0 : _a.call(handlers, { room, data: dataStr });
}
function getListeners(room) {
var _a;
return (_a = roomsToListeners[room]) !== null && _a !== void 0 ? _a : [];
}
function cancelPendingRoomLeave(room) {
const pendingLeave = pendingRoomLeaves[room];
if (!pendingLeave) {
return;
}
clearTimeout(pendingLeave);
delete pendingRoomLeaves[room];
}
function clearPendingRoomLeaves() {
Object.keys(pendingRoomLeaves).forEach((room) => {
var _a, _b;
clearTimeout(pendingRoomLeaves[room]);
delete pendingRoomLeaves[room];
if (((_b = (_a = roomsToListeners[room]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) === 0) {
delete roomsToListeners[room];
}
});
}
function scheduleRoomLeave(room) {
cancelPendingRoomLeave(room);
pendingRoomLeaves[room] = setTimeout(() => {
var _a, _b;
delete pendingRoomLeaves[room];
if (((_b = (_a = roomsToListeners[room]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0) {
return;
}
leaveRoom(room);
delete roomsToListeners[room];
}, ROOM_LEAVE_GRACE_MS);
}
const subscribeToRoom = (room, handlers) => {
if (roomsToListeners[room]) {
cancelPendingRoomLeave(room);
}
else {
joinRoom(room);
roomsToListeners[room] = [];
}
roomsToListeners[room].push(handlers);
let unsubscribed = false;
return () => {
var _a, _b;
if (unsubscribed) {
return;
}
unsubscribed = true;
roomsToListeners[room] =
(_b = (_a = roomsToListeners[room]) === null || _a === void 0 ? void 0 : _a.filter((listener) => listener !== handlers)) !== null && _b !== void 0 ? _b : [];
if (roomsToListeners[room].length === 0) {
scheduleRoomLeave(room);
}
};
};
return {
socket,
subscribeToRoom,
updateConfig,
updateModel,
disconnect,
};
}
+66
View File
@@ -0,0 +1,66 @@
{
"name": "@base44/sdk",
"version": "0.8.32",
"description": "JavaScript SDK for Base44 API",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"files": [
"dist"
],
"scripts": {
"build": "tsc",
"lint": "eslint src",
"test": "npm run test:types && vitest run",
"test:types": "tsc --noEmit -p tsconfig.type-tests.json",
"test:unit": "vitest run tests/unit",
"test:e2e": "vitest run tests/e2e",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"docs": "typedoc",
"prepublishOnly": "npm run build",
"create-docs": "npm run create-docs:generate && npm run create-docs:process",
"create-docs-local": "npm run create-docs && npm run copy-docs-local",
"copy-docs-local": "node scripts/mintlify-post-processing/copy-to-local-docs.js",
"create-docs:generate": "typedoc",
"create-docs:process": "node scripts/mintlify-post-processing/file-processing/file-processing.js"
},
"dependencies": {
"axios": "^1.17.0",
"socket.io-client": "^4.8.3",
"uuid": "^13.0.2"
},
"devDependencies": {
"@types/hast": "^3.0.4",
"@types/node": "^25.0.1",
"@types/unist": "^3.0.3",
"@typescript-eslint/parser": "^8.51.0",
"@vitest/coverage-istanbul": "^1.0.0",
"@vitest/coverage-v8": "^1.0.0",
"@vitest/ui": "^1.0.0",
"dotenv": "^16.3.1",
"eslint": "^9.39.2",
"eslint-plugin-import": "^2.32.0",
"nock": "^13.4.0",
"typedoc": "^0.28.14",
"typedoc-plugin-markdown": "^4.9.0",
"typescript": "^5.3.2",
"typescript-eslint": "^8.51.0",
"vitest": "^1.6.1"
},
"keywords": [
"base44",
"api",
"sdk"
],
"author": "Base44",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/base44/javascript-sdk.git"
},
"bugs": {
"url": "https://github.com/base44/javascript-sdk/issues"
},
"homepage": "https://github.com/base44/javascript-sdk#readme"
}