Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { getAccessToken } from "./utils/auth-utils.js";
import { createFunctionsModule } from "./modules/functions.js";
import { createAgentsModule } from "./modules/agents.js";
import { createAiGatewayModule } from "./modules/ai-gateway.js";
import { createAppLogsModule } from "./modules/app-logs.js";
import { createUsersModule } from "./modules/users.js";
import { RoomsSocket, RoomsSocketConfig } from "./utils/socket-utils.js";
Expand Down Expand Up @@ -190,6 +191,7 @@ export function createClient(config: CreateClientConfig): Base44Client {
serverUrl,
token,
}),
aiGateway: createAiGatewayModule({ serverUrl, token }),
appLogs: createAppLogsModule(axiosClient, appId),
users: createUsersModule(axiosClient, appId),
analytics: createAnalyticsModule({
Expand Down Expand Up @@ -233,6 +235,7 @@ export function createClient(config: CreateClientConfig): Base44Client {
serverUrl,
token,
}),
aiGateway: createAiGatewayModule({ serverUrl, token: serviceToken }),
appLogs: createAppLogsModule(serviceRoleAxiosClient, appId),
cleanup: () => {
if (socket) {
Expand Down
5 changes: 5 additions & 0 deletions src/client.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
} from "./modules/connectors.types.js";
import type { FunctionsModule } from "./modules/functions.types.js";
import type { AgentsModule } from "./modules/agents.types.js";
import type { AiGatewayModule } from "./modules/ai-gateway.types.js";
import type { AppLogsModule } from "./modules/app-logs.types.js";
import type { AnalyticsModule } from "./modules/analytics.types.js";

Expand Down Expand Up @@ -87,6 +88,8 @@ export interface CreateClientConfig {
export interface Base44Client {
/** {@link AgentsModule | Agents module} for managing AI agent conversations. */
agents: AgentsModule;
/** {@link AiGatewayModule | AI Gateway module} for connecting to the Base44 AI Gateway with your own SDK. */
aiGateway: AiGatewayModule;
/** {@link AnalyticsModule | Analytics module} for tracking custom events in your app. */
analytics: AnalyticsModule;
/** {@link AppLogsModule | App logs module} for tracking app usage. */
Expand Down Expand Up @@ -129,6 +132,8 @@ export interface Base44Client {
readonly asServiceRole: {
/** {@link AgentsModule | Agents module} with elevated permissions. */
agents: AgentsModule;
/** {@link AiGatewayModule | AI Gateway module} with the service-role token. */
aiGateway: AiGatewayModule;
/** {@link AppLogsModule | App logs module} with elevated permissions. */
appLogs: AppLogsModule;
/** {@link ConnectorsModule | Connectors module} for OAuth token retrieval. */
Expand Down
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ export type {
CreateConversationParams,
} from "./modules/agents.types.js";

export type {
AiGatewayModule,
AiGatewayConnection,
} from "./modules/ai-gateway.types.js";

export type { AppLogsModule } from "./modules/app-logs.types.js";

export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
Expand Down
20 changes: 20 additions & 0 deletions src/modules/ai-gateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { getAccessToken } from "../utils/auth-utils.js";
import {
AiGatewayModule,
AiGatewayModuleConfig,
AiGatewayConnection,
} from "./ai-gateway.types.js";

export function createAiGatewayModule({
serverUrl,
token,
}: AiGatewayModuleConfig): AiGatewayModule {
const connection = (): AiGatewayConnection => ({
baseURL: `${serverUrl}/api/ai/openai/v1`,
token: token ?? getAccessToken() ?? "",
});

return {
connection,
};
}
67 changes: 67 additions & 0 deletions src/modules/ai-gateway.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* A connection to the Base44 AI Gateway.
*
* Contains the base URL and bearer token to use with any OpenAI-compatible client
* (the OpenAI SDK, Mastra, and others) pointed at the Base44 AI Gateway.
*/
export interface AiGatewayConnection {
/** Base URL of the gateway's OpenAI-compatible endpoint. */
baseURL: string;
/** Bearer token used to authenticate requests to the gateway. */
token: string;
}

/**
* Configuration for the AI Gateway module.
* @internal
*/
export interface AiGatewayModuleConfig {
/** Server URL */
serverUrl?: string;
/** Authentication token */
token?: string;
}

/**
* The AI Gateway module.
*
* Exposes the connection details for the Base44 AI Gateway so you can call it from
* your own code using any OpenAI-compatible SDK — for example, to build a custom
* agent on top of the gateway.
*/
export interface AiGatewayModule {
/**
* Gets the connection details for the Base44 AI Gateway.
*
* Returns the `baseURL` and `token` to pass to any OpenAI-compatible client (the
* OpenAI SDK, Mastra, and others), so you can call the gateway from your own code
* without constructing the URL or handling the token yourself.
*
* The `token` is the current caller's bearer token: the app user's token for
* `base44.aiGateway`, or the service-role token for `base44.asServiceRole.aiGateway`.
* When the caller is unauthenticated, `token` is an empty string and gateway
* requests will be rejected.
*
* @returns The gateway {@linkcode AiGatewayConnection | connection} (`baseURL` and `token`).
*
* @example
* ```typescript
* // Inside a backend function, call the gateway with any OpenAI-compatible SDK
* import { createClientFromRequest } from 'npm:@base44/sdk';
* import OpenAI from 'npm:openai';
*
* Deno.serve(async (req) => {
* const base44 = createClientFromRequest(req);
* const { baseURL, token } = base44.aiGateway.connection();
*
* const openai = new OpenAI({ baseURL, apiKey: token });
* const res = await openai.chat.completions.create({
* model: 'claude_sonnet_4_6',
* messages: [{ role: 'user', content: 'Hello!' }],
* });
* return Response.json({ text: res.choices[0].message.content });
* });
* ```
*/
connection(): AiGatewayConnection;
}
1 change: 1 addition & 0 deletions src/modules/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./app.types.js";
export * from "./agents.types.js";
export * from "./ai-gateway.types.js";
export * from "./connectors.types.js";
export * from "./analytics.types.js";
41 changes: 41 additions & 0 deletions tests/unit/ai-gateway.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, test, expect } from "vitest";
import { createClient } from "../../src/index.ts";

describe("AI Gateway Module", () => {
const appId = "test-app-id";
const serverUrl = "https://api.base44.com";
const baseURL = `${serverUrl}/api/ai/openai/v1`;

describe("connection", () => {
test("should return the OpenAI-compatible gateway baseURL", () => {
const base44 = createClient({ serverUrl, appId });
expect(base44.aiGateway.connection().baseURL).toBe(baseURL);
});

test("should return an empty token when unauthenticated", () => {
const base44 = createClient({ serverUrl, appId });
expect(base44.aiGateway.connection().token).toBe("");
});

test("should use the user token when authenticated", () => {
const base44 = createClient({ serverUrl, appId, token: "user-token" });
expect(base44.aiGateway.connection()).toEqual({
baseURL,
token: "user-token",
});
});

test("should use the service-role token via asServiceRole", () => {
const base44 = createClient({
serverUrl,
appId,
token: "user-token",
serviceToken: "service-token",
});
expect(base44.asServiceRole.aiGateway.connection()).toEqual({
baseURL,
token: "service-token",
});
});
});
});
Loading