@base44/sdk 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,10 +20,10 @@ import { createClient } from '@base44/sdk';
20
20
  // Create a client instance
21
21
  const base44 = createClient({
22
22
  serverUrl: 'https://base44.app', // Optional, defaults to 'https://base44.app'
23
- appId: 'your-app-id', // Required
24
- env: 'prod', // Optional, defaults to 'prod'
25
- token: 'your-token', // Optional
26
- autoInitAuth: true, // Optional, defaults to true - auto-detects tokens from URL or localStorage
23
+ appId: 'your-app-id', // Required
24
+ token: 'your-user-token', // Optional, for user authentication
25
+ serviceToken: 'your-service-token', // Optional, for service role authentication
26
+ autoInitAuth: true, // Optional, defaults to true - auto-detects tokens from URL or localStorage
27
27
  });
28
28
  ```
29
29
 
@@ -63,6 +63,77 @@ const newProducts = await base44.entities.Product.bulkCreate([
63
63
  ]);
64
64
  ```
65
65
 
66
+ ### Service Role Authentication
67
+
68
+ Service role authentication allows server-side applications to perform operations with elevated privileges. This is useful for administrative tasks, background jobs, and server-to-server communication.
69
+
70
+ ```javascript
71
+ import { createClient } from '@base44/sdk';
72
+
73
+ // Create a client with service role token
74
+ const base44 = createClient({
75
+ appId: 'your-app-id',
76
+ token: 'user-token', // For user operations
77
+ serviceToken: 'service-token' // For service role operations
78
+ });
79
+
80
+ // User operations (uses user token)
81
+ const userEntities = await base44.entities.User.list();
82
+
83
+ // Service role operations (uses service token)
84
+ const allEntities = await base44.asServiceRole.entities.User.list();
85
+
86
+ // Service role has access to:
87
+ // - base44.asServiceRole.entities
88
+ // - base44.asServiceRole.integrations
89
+ // - base44.asServiceRole.functions
90
+ // Note: Service role does NOT have access to auth module for security
91
+
92
+ // If no service token is provided, accessing asServiceRole throws an error
93
+ const clientWithoutService = createClient({ appId: 'your-app-id' });
94
+ try {
95
+ await clientWithoutService.asServiceRole.entities.User.list();
96
+ } catch (error) {
97
+ // Error: Service token is required to use asServiceRole
98
+ }
99
+ ```
100
+
101
+ ### Server-Side Usage
102
+
103
+ For server-side applications, you can create a client from incoming HTTP requests:
104
+
105
+ ```javascript
106
+ import { createClientFromRequest } from '@base44/sdk';
107
+
108
+ // In your server handler (Express, Next.js, etc.)
109
+ app.get('/api/data', async (req, res) => {
110
+ try {
111
+ // Extract client configuration from request headers
112
+ const base44 = createClientFromRequest(req);
113
+
114
+ // Headers used:
115
+ // - Authorization: Bearer <user-token>
116
+ // - Base44-Service-Authorization: Bearer <service-token>
117
+ // - Base44-App-Id: <app-id>
118
+ // - Base44-Api-Url: <custom-api-url> (optional)
119
+
120
+ // Use appropriate authentication based on available tokens
121
+ let data;
122
+ if (base44.asServiceRole) {
123
+ // Service token available - use elevated privileges
124
+ data = await base44.asServiceRole.entities.SensitiveData.list();
125
+ } else {
126
+ // Only user token available - use user permissions
127
+ data = await base44.entities.PublicData.list();
128
+ }
129
+
130
+ res.json(data);
131
+ } catch (error) {
132
+ res.status(500).json({ error: error.message });
133
+ }
134
+ });
135
+ ```
136
+
66
137
  ### Working with Integrations
67
138
 
68
139
  ```javascript
@@ -103,7 +174,7 @@ import { getAccessToken } from '@base44/sdk/utils/auth-utils';
103
174
  // Create a client with authentication
104
175
  const base44 = createClient({
105
176
  appId: 'your-app-id',
106
- accessToken: getAccessToken() // Automatically retrieves token from localStorage or URL
177
+ token: getAccessToken() // Automatically retrieves token from localStorage or URL
107
178
  });
108
179
 
109
180
  // Check authentication status
@@ -167,7 +238,7 @@ function AuthProvider({ children }) {
167
238
  const [client] = useState(() =>
168
239
  createClient({
169
240
  appId: 'your-app-id',
170
- accessToken: getAccessToken()
241
+ token: getAccessToken()
171
242
  })
172
243
  );
173
244
 
@@ -347,6 +418,24 @@ async function fetchProducts() {
347
418
  }
348
419
  }
349
420
 
421
+ // Service role operations with TypeScript
422
+ async function adminOperations() {
423
+ const base44 = createClient({
424
+ appId: 'your-app-id',
425
+ serviceToken: 'service-token'
426
+ });
427
+
428
+ // TypeScript knows asServiceRole requires a service token
429
+ try {
430
+ const allUsers: Entity[] = await base44.asServiceRole.entities.User.list();
431
+ console.log(`Total users: ${allUsers.length}`);
432
+ } catch (error) {
433
+ if (error instanceof Error) {
434
+ console.error(error.message); // Service token is required to use asServiceRole
435
+ }
436
+ }
437
+ }
438
+
350
439
  // Authentication with TypeScript
351
440
  async function handleAuth(auth: AuthModule) {
352
441
  // Check authentication
@@ -456,6 +545,25 @@ try {
456
545
  }
457
546
  ```
458
547
 
548
+ ## Functions
549
+
550
+ The SDK supports invoking custom functions:
551
+
552
+ ```javascript
553
+ // Invoke a function without parameters
554
+ const result = await base44.functions.myFunction();
555
+
556
+ // Invoke a function with parameters
557
+ const result = await base44.functions.calculateTotal({
558
+ items: ['item1', 'item2'],
559
+ discount: 0.1
560
+ });
561
+
562
+ // Functions are automatically authenticated with the user token
563
+ // Service role can also invoke functions
564
+ const serviceResult = await base44.asServiceRole.functions.adminFunction();
565
+ ```
566
+
459
567
  ## Testing
460
568
 
461
569
  The SDK includes comprehensive tests to ensure reliability.
package/dist/client.d.ts CHANGED
@@ -3,18 +3,39 @@
3
3
  * @param {Object} config - Client configuration
4
4
  * @param {string} [config.serverUrl='https://base44.app'] - API server URL
5
5
  * @param {string|number} config.appId - Application ID
6
- * @param {string} [config.env='prod'] - Environment ('prod' or 'dev')
7
6
  * @param {string} [config.token] - Authentication token
7
+ * @param {string} [config.serviceToken] - Service role authentication token
8
8
  * @param {boolean} [config.requiresAuth=false] - Whether the app requires authentication
9
9
  * @returns {Object} Base44 client instance
10
10
  */
11
11
  export declare function createClient(config: {
12
12
  serverUrl?: string;
13
13
  appId: string;
14
- env?: string;
15
14
  token?: string;
15
+ serviceToken?: string;
16
16
  requiresAuth?: boolean;
17
17
  }): {
18
+ /**
19
+ * Set authentication token for all requests
20
+ * @param {string} newToken - New auth token
21
+ */
22
+ setToken(newToken: string): void;
23
+ /**
24
+ * Get current configuration
25
+ * @returns {Object} Current configuration
26
+ */
27
+ getConfig(): {
28
+ serverUrl: string;
29
+ appId: string;
30
+ requiresAuth: boolean;
31
+ };
32
+ asServiceRole: {
33
+ entities: {};
34
+ integrations: {};
35
+ functions: {
36
+ invoke(functionName: string, data: Record<string, any>): Promise<import("axios").AxiosResponse<any, any>>;
37
+ };
38
+ };
18
39
  entities: {};
19
40
  integrations: {};
20
41
  auth: {
@@ -24,7 +45,7 @@ export declare function createClient(config: {
24
45
  redirectToLogin(nextUrl: string): void;
25
46
  logout(redirectUrl?: string): void;
26
47
  setToken(token: string, saveToStorage?: boolean): void;
27
- loginViaUsernamePassword(email: string, password: string, turnstileToken?: string): Promise<{
48
+ loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<{
28
49
  access_token: string;
29
50
  user: any;
30
51
  }>;
@@ -33,6 +54,8 @@ export declare function createClient(config: {
33
54
  functions: {
34
55
  invoke(functionName: string, data: Record<string, any>): Promise<import("axios").AxiosResponse<any, any>>;
35
56
  };
57
+ };
58
+ export declare function createClientFromRequest(request: Request): {
36
59
  /**
37
60
  * Set authentication token for all requests
38
61
  * @param {string} newToken - New auth token
@@ -45,7 +68,31 @@ export declare function createClient(config: {
45
68
  getConfig(): {
46
69
  serverUrl: string;
47
70
  appId: string;
48
- env: string;
49
71
  requiresAuth: boolean;
50
72
  };
73
+ asServiceRole: {
74
+ entities: {};
75
+ integrations: {};
76
+ functions: {
77
+ invoke(functionName: string, data: Record<string, any>): Promise<import("axios").AxiosResponse<any, any>>;
78
+ };
79
+ };
80
+ entities: {};
81
+ integrations: {};
82
+ auth: {
83
+ me(): Promise<import("axios").AxiosResponse<any, any>>;
84
+ getSsoAccessToken(): Promise<import("axios").AxiosResponse<any, any>>;
85
+ updateMe(data: Record<string, any>): Promise<import("axios").AxiosResponse<any, any>>;
86
+ redirectToLogin(nextUrl: string): void;
87
+ logout(redirectUrl?: string): void;
88
+ setToken(token: string, saveToStorage?: boolean): void;
89
+ loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<{
90
+ access_token: string;
91
+ user: any;
92
+ }>;
93
+ isAuthenticated(): Promise<boolean>;
94
+ };
95
+ functions: {
96
+ invoke(functionName: string, data: Record<string, any>): Promise<import("axios").AxiosResponse<any, any>>;
97
+ };
51
98
  };
package/dist/client.js CHANGED
@@ -9,30 +9,27 @@ import { createFunctionsModule } from "./modules/functions.js";
9
9
  * @param {Object} config - Client configuration
10
10
  * @param {string} [config.serverUrl='https://base44.app'] - API server URL
11
11
  * @param {string|number} config.appId - Application ID
12
- * @param {string} [config.env='prod'] - Environment ('prod' or 'dev')
13
12
  * @param {string} [config.token] - Authentication token
13
+ * @param {string} [config.serviceToken] - Service role authentication token
14
14
  * @param {boolean} [config.requiresAuth=false] - Whether the app requires authentication
15
15
  * @returns {Object} Base44 client instance
16
16
  */
17
17
  export function createClient(config) {
18
- const { serverUrl = "https://base44.app", appId, env = "prod", token, requiresAuth = false, } = config;
19
- // Create the base axios client
18
+ const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, } = config;
20
19
  const axiosClient = createAxiosClient({
21
20
  baseURL: `${serverUrl}/api`,
22
21
  headers: {
23
22
  "X-App-Id": String(appId),
24
- "X-Environment": env,
25
23
  },
26
24
  token,
27
- requiresAuth, // Pass requiresAuth to axios client
28
- appId, // Pass appId for login redirect
29
- serverUrl, // Pass serverUrl for login redirect
25
+ requiresAuth,
26
+ appId,
27
+ serverUrl,
30
28
  });
31
29
  const functionsAxiosClient = createAxiosClient({
32
30
  baseURL: `${serverUrl}/api`,
33
31
  headers: {
34
32
  "X-App-Id": String(appId),
35
- "X-Environment": env,
36
33
  },
37
34
  token,
38
35
  requiresAuth,
@@ -40,17 +37,42 @@ export function createClient(config) {
40
37
  serverUrl,
41
38
  interceptResponses: false,
42
39
  });
43
- // Create modules
44
- const entities = createEntitiesModule(axiosClient, appId);
45
- const integrations = createIntegrationsModule(axiosClient, appId);
46
- const auth = createAuthModule(axiosClient, appId, serverUrl);
47
- const functions = createFunctionsModule(functionsAxiosClient, appId);
40
+ const serviceRoleAxiosClient = createAxiosClient({
41
+ baseURL: `${serverUrl}/api`,
42
+ headers: {
43
+ "X-App-Id": String(appId),
44
+ },
45
+ token: serviceToken,
46
+ serverUrl,
47
+ appId,
48
+ });
49
+ const serviceRoleFunctionsAxiosClient = createAxiosClient({
50
+ baseURL: `${serverUrl}/api`,
51
+ headers: {
52
+ "X-App-Id": String(appId),
53
+ },
54
+ token: serviceToken,
55
+ serverUrl,
56
+ appId,
57
+ interceptResponses: false,
58
+ });
59
+ const userModules = {
60
+ entities: createEntitiesModule(axiosClient, appId),
61
+ integrations: createIntegrationsModule(axiosClient, appId),
62
+ auth: createAuthModule(axiosClient, functionsAxiosClient, appId),
63
+ functions: createFunctionsModule(functionsAxiosClient, appId),
64
+ };
65
+ const serviceRoleModules = {
66
+ entities: createEntitiesModule(serviceRoleAxiosClient, appId),
67
+ integrations: createIntegrationsModule(serviceRoleAxiosClient, appId),
68
+ functions: createFunctionsModule(serviceRoleFunctionsAxiosClient, appId),
69
+ };
48
70
  // Always try to get token from localStorage or URL parameters
49
71
  if (typeof window !== "undefined") {
50
72
  // Get token from URL or localStorage
51
73
  const accessToken = token || getAccessToken();
52
74
  if (accessToken) {
53
- auth.setToken(accessToken);
75
+ userModules.auth.setToken(accessToken);
54
76
  }
55
77
  }
56
78
  // If authentication is required, verify token and redirect to login if needed
@@ -58,29 +80,26 @@ export function createClient(config) {
58
80
  // We perform this check asynchronously to not block client creation
59
81
  setTimeout(async () => {
60
82
  try {
61
- const isAuthenticated = await auth.isAuthenticated();
83
+ const isAuthenticated = await userModules.auth.isAuthenticated();
62
84
  if (!isAuthenticated) {
63
- auth.redirectToLogin(window.location.href);
85
+ userModules.auth.redirectToLogin(window.location.href);
64
86
  }
65
87
  }
66
88
  catch (error) {
67
89
  console.error("Authentication check failed:", error);
68
- auth.redirectToLogin(window.location.href);
90
+ userModules.auth.redirectToLogin(window.location.href);
69
91
  }
70
92
  }, 0);
71
93
  }
72
94
  // Assemble and return the client
73
- return {
74
- entities,
75
- integrations,
76
- auth,
77
- functions,
95
+ const client = {
96
+ ...userModules,
78
97
  /**
79
98
  * Set authentication token for all requests
80
99
  * @param {string} newToken - New auth token
81
100
  */
82
101
  setToken(newToken) {
83
- auth.setToken(newToken);
102
+ userModules.auth.setToken(newToken);
84
103
  },
85
104
  /**
86
105
  * Get current configuration
@@ -90,9 +109,49 @@ export function createClient(config) {
90
109
  return {
91
110
  serverUrl,
92
111
  appId,
93
- env,
94
112
  requiresAuth,
95
113
  };
96
114
  },
115
+ /**
116
+ * Access service role modules - throws error if no service token was provided
117
+ * @throws {Error} When accessed without a service token
118
+ */
119
+ get asServiceRole() {
120
+ if (!serviceToken) {
121
+ throw new Error('Service token is required to use asServiceRole. Please provide a serviceToken when creating the client.');
122
+ }
123
+ return serviceRoleModules;
124
+ }
97
125
  };
126
+ return client;
127
+ }
128
+ export function createClientFromRequest(request) {
129
+ const authHeader = request.headers.get("Authorization");
130
+ const serviceRoleAuthHeader = request.headers.get("Base44-Service-Authorization");
131
+ const appId = request.headers.get("Base44-App-Id");
132
+ const serverUrlHeader = request.headers.get("Base44-Api-Url");
133
+ if (!appId) {
134
+ throw new Error("Base44-App-Id header is required, but is was not found on the request");
135
+ }
136
+ // Validate authorization header formats
137
+ let serviceRoleToken;
138
+ let userToken;
139
+ if (serviceRoleAuthHeader !== null) {
140
+ if (serviceRoleAuthHeader === '' || !serviceRoleAuthHeader.startsWith('Bearer ') || serviceRoleAuthHeader.split(' ').length !== 2) {
141
+ throw new Error('Invalid authorization header format. Expected "Bearer <token>"');
142
+ }
143
+ serviceRoleToken = serviceRoleAuthHeader.split(' ')[1];
144
+ }
145
+ if (authHeader !== null) {
146
+ if (authHeader === '' || !authHeader.startsWith('Bearer ') || authHeader.split(' ').length !== 2) {
147
+ throw new Error('Invalid authorization header format. Expected "Bearer <token>"');
148
+ }
149
+ userToken = authHeader.split(' ')[1];
150
+ }
151
+ return createClient({
152
+ serverUrl: serverUrlHeader || "https://base44.app",
153
+ appId,
154
+ token: userToken,
155
+ serviceToken: serviceRoleToken,
156
+ });
98
157
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { createClient } from "./client.js";
1
+ import { createClient, createClientFromRequest } from "./client.js";
2
2
  import { Base44Error } from "./utils/axios-client.js";
3
3
  import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl } from "./utils/auth-utils.js";
4
- export { createClient, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
4
+ export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
package/dist/index.js CHANGED
@@ -1,6 +1,4 @@
1
- import { createClient } from "./client.js";
1
+ import { createClient, createClientFromRequest } from "./client.js";
2
2
  import { Base44Error } from "./utils/axios-client.js";
3
3
  import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, } from "./utils/auth-utils.js";
4
- export { createClient, Base44Error,
5
- // Export auth utilities for easier access
6
- getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
4
+ export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
@@ -6,7 +6,7 @@ import { AxiosInstance } from "axios";
6
6
  * @param {string} serverUrl - Server URL
7
7
  * @returns {Object} Auth module with authentication methods
8
8
  */
9
- export declare function createAuthModule(axios: AxiosInstance, appId: string, serverUrl: string): {
9
+ export declare function createAuthModule(axios: AxiosInstance, functionsAxiosClient: AxiosInstance, appId: string): {
10
10
  /**
11
11
  * Get current user information
12
12
  * @returns {Promise<Object>} Current user data
@@ -49,7 +49,7 @@ export declare function createAuthModule(axios: AxiosInstance, appId: string, se
49
49
  * @param turnstileToken - Optional Turnstile captcha token
50
50
  * @returns Login response with access_token and user
51
51
  */
52
- loginViaUsernamePassword(email: string, password: string, turnstileToken?: string): Promise<{
52
+ loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<{
53
53
  access_token: string;
54
54
  user: any;
55
55
  }>;
@@ -5,7 +5,7 @@
5
5
  * @param {string} serverUrl - Server URL
6
6
  * @returns {Object} Auth module with authentication methods
7
7
  */
8
- export function createAuthModule(axios, appId, serverUrl) {
8
+ export function createAuthModule(axios, functionsAxiosClient, appId) {
9
9
  return {
10
10
  /**
11
11
  * Get current user information
@@ -83,6 +83,7 @@ export function createAuthModule(axios, appId, serverUrl) {
83
83
  if (!token)
84
84
  return;
85
85
  axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
86
+ functionsAxiosClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
86
87
  // Save token to localStorage if requested
87
88
  if (saveToStorage &&
88
89
  typeof window !== "undefined" &&
@@ -102,7 +103,7 @@ export function createAuthModule(axios, appId, serverUrl) {
102
103
  * @param turnstileToken - Optional Turnstile captcha token
103
104
  * @returns Login response with access_token and user
104
105
  */
105
- async loginViaUsernamePassword(email, password, turnstileToken) {
106
+ async loginViaEmailPassword(email, password, turnstileToken) {
106
107
  var _a;
107
108
  try {
108
109
  const response = await axios.post(`/apps/${appId}/auth/login`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",