database-petani-mobile/node_modules/@base44/sdk/dist/client.js
2026-02-23 16:39:35 +07:00

353 lines
14 KiB
JavaScript

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 } 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) {
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 serviceRoleAxiosClient = createAxiosClient({
baseURL: `${serverUrl}/api`,
headers,
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,
});
const userModules = {
entities: createEntitiesModule({
axios: axiosClient,
appId,
getSocket,
}),
integrations: createIntegrationsModule(axiosClient, appId),
auth: userAuthModule,
functions: createFunctionsModule(functionsAxiosClient, appId),
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, token),
connectors: createConnectorsModule(serviceRoleAxiosClient, appId),
functions: createFunctionsModule(serviceRoleFunctionsAxiosClient, appId),
agents: createAgentsModule({
axios: serviceRoleAxiosClient,
getSocket,
appId,
serverUrl,
token,
}),
appLogs: createAppLogsModule(serviceRoleAxiosClient, appId),
cleanup: () => {
if (socket) {
socket.disconnect();
}
},
};
// Always try to get token from localStorage or URL parameters
if (typeof window !== "undefined") {
// Get token from URL or localStorage
const accessToken = token || getAccessToken();
if (accessToken) {
userModules.auth.setToken(accessToken);
}
}
// 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,
});
}