@base44/sdk 0.1.0 → 0.1.2
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 +3 -3
- package/dist/index.esm.js +1 -672
- package/dist/index.js +1 -679
- package/dist/index.umd.js +1 -1
- package/package.json +3 -3
package/dist/index.esm.js
CHANGED
|
@@ -1,672 +1 @@
|
|
|
1
|
-
import axios from
|
|
2
|
-
|
|
3
|
-
class Base44Error extends Error {
|
|
4
|
-
constructor(message, status, code, data, originalError) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = 'Base44Error';
|
|
7
|
-
this.status = status;
|
|
8
|
-
this.code = code;
|
|
9
|
-
this.data = data;
|
|
10
|
-
this.originalError = originalError;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Add a method to safely serialize this error without circular references
|
|
14
|
-
toJSON() {
|
|
15
|
-
return {
|
|
16
|
-
name: this.name,
|
|
17
|
-
message: this.message,
|
|
18
|
-
status: this.status,
|
|
19
|
-
code: this.code,
|
|
20
|
-
data: this.data
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Safely logs error information without circular references
|
|
27
|
-
* @param {string} prefix - Prefix for the log message
|
|
28
|
-
* @param {Error} error - The error to log
|
|
29
|
-
*/
|
|
30
|
-
function safeErrorLog(prefix, error) {
|
|
31
|
-
if (error instanceof Base44Error) {
|
|
32
|
-
console.error(`${prefix} ${error.status}: ${error.message}`);
|
|
33
|
-
if (error.data) {
|
|
34
|
-
try {
|
|
35
|
-
console.error('Error data:', JSON.stringify(error.data, null, 2));
|
|
36
|
-
} catch (e) {
|
|
37
|
-
console.error('Error data: [Cannot stringify error data]');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
console.error(`${prefix} ${error.message}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Redirects to the login page with the current URL as return destination
|
|
47
|
-
* @param {string} serverUrl - Base server URL
|
|
48
|
-
* @param {string|number} appId - Application ID
|
|
49
|
-
*/
|
|
50
|
-
function redirectToLogin(serverUrl, appId) {
|
|
51
|
-
if (typeof window === 'undefined') {
|
|
52
|
-
return; // Can't redirect in non-browser environment
|
|
53
|
-
}
|
|
54
|
-
const currentUrl = encodeURIComponent(window.location.href);
|
|
55
|
-
const loginUrl = `${serverUrl}/login?from_url=${currentUrl}&app_id=${appId}`;
|
|
56
|
-
window.location.href = loginUrl;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Creates an axios client with default configuration and interceptors
|
|
61
|
-
* @param {Object} options - Client configuration options
|
|
62
|
-
* @param {string} options.baseURL - Base URL for all requests
|
|
63
|
-
* @param {Object} options.headers - Additional headers
|
|
64
|
-
* @param {string} options.token - Auth token
|
|
65
|
-
* @param {boolean} options.requiresAuth - Whether the application requires authentication
|
|
66
|
-
* @param {string|number} options.appId - Application ID (needed for login redirect)
|
|
67
|
-
* @param {string} options.serverUrl - Server URL (needed for login redirect)
|
|
68
|
-
* @returns {import('axios').AxiosInstance} Configured axios instance
|
|
69
|
-
*/
|
|
70
|
-
function createAxiosClient(_ref) {
|
|
71
|
-
let {
|
|
72
|
-
baseURL,
|
|
73
|
-
headers = {},
|
|
74
|
-
token,
|
|
75
|
-
requiresAuth = false,
|
|
76
|
-
appId,
|
|
77
|
-
serverUrl
|
|
78
|
-
} = _ref;
|
|
79
|
-
const client = axios.create({
|
|
80
|
-
baseURL,
|
|
81
|
-
headers: {
|
|
82
|
-
'Content-Type': 'application/json',
|
|
83
|
-
'Accept': 'application/json',
|
|
84
|
-
...headers
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Add token to requests if available
|
|
89
|
-
if (token) {
|
|
90
|
-
client.defaults.headers.common['Authorization'] = `Bearer ${token}`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Add origin URL in browser environment
|
|
94
|
-
client.interceptors.request.use(config => {
|
|
95
|
-
if (typeof window !== 'undefined') {
|
|
96
|
-
config.headers = {
|
|
97
|
-
...config.headers,
|
|
98
|
-
'X-Origin-URL': window.location.href
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
return config;
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// Handle responses
|
|
105
|
-
client.interceptors.response.use(response => response.data, error => {
|
|
106
|
-
const message = error.response?.data?.message || error.response?.data?.detail || error.message;
|
|
107
|
-
const base44Error = new Base44Error(message, error.response?.status, error.response?.data?.code, error.response?.data, error);
|
|
108
|
-
|
|
109
|
-
// Log errors in development
|
|
110
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
111
|
-
safeErrorLog('[Base44 SDK Error]', base44Error);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Check for 403 Forbidden (authentication required) and redirect to login if requiresAuth is true
|
|
115
|
-
console.log(requiresAuth, error.response?.status, typeof window !== 'undefined');
|
|
116
|
-
if (requiresAuth && error.response?.status === 403 && typeof window !== 'undefined') {
|
|
117
|
-
console.log('Authentication required. Redirecting to login...');
|
|
118
|
-
// Use a slight delay to allow the error to propagate first
|
|
119
|
-
setTimeout(() => {
|
|
120
|
-
redirectToLogin(serverUrl, appId);
|
|
121
|
-
}, 100);
|
|
122
|
-
}
|
|
123
|
-
return Promise.reject(base44Error);
|
|
124
|
-
});
|
|
125
|
-
return client;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Creates the entities module for the Base44 SDK
|
|
130
|
-
* @param {import('axios').AxiosInstance} axios - Axios instance
|
|
131
|
-
* @param {string|number} appId - Application ID
|
|
132
|
-
* @returns {Object} Entities module
|
|
133
|
-
*/
|
|
134
|
-
function createEntitiesModule(axios, appId) {
|
|
135
|
-
// Using Proxy to dynamically handle entity names
|
|
136
|
-
return new Proxy({}, {
|
|
137
|
-
get(target, entityName) {
|
|
138
|
-
// Don't create handlers for internal properties
|
|
139
|
-
if (typeof entityName !== 'string' || entityName === 'then' || entityName.startsWith('_')) {
|
|
140
|
-
return undefined;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Create entity handler
|
|
144
|
-
return createEntityHandler(axios, appId, entityName);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Creates a handler for a specific entity
|
|
151
|
-
* @param {import('axios').AxiosInstance} axios - Axios instance
|
|
152
|
-
* @param {string|number} appId - Application ID
|
|
153
|
-
* @param {string} entityName - Entity name
|
|
154
|
-
* @returns {Object} Entity handler with CRUD methods
|
|
155
|
-
*/
|
|
156
|
-
function createEntityHandler(axios, appId, entityName) {
|
|
157
|
-
const baseURL = `/apps/${appId}/entities/${entityName}`;
|
|
158
|
-
return {
|
|
159
|
-
/**
|
|
160
|
-
* List entities with optional pagination and sorting
|
|
161
|
-
* @param {string} [sort] - Sort parameter
|
|
162
|
-
* @param {number} [limit] - Limit results
|
|
163
|
-
* @param {number} [skip] - Skip results (pagination)
|
|
164
|
-
* @param {string[]} [fields] - Fields to include
|
|
165
|
-
* @returns {Promise<Array>} List of entities
|
|
166
|
-
*/
|
|
167
|
-
async list(sort, limit, skip, fields) {
|
|
168
|
-
const params = {};
|
|
169
|
-
if (sort) params.sort = sort;
|
|
170
|
-
if (limit) params.limit = limit;
|
|
171
|
-
if (skip) params.skip = skip;
|
|
172
|
-
if (fields) params.fields = Array.isArray(fields) ? fields.join(',') : fields;
|
|
173
|
-
return axios.get(baseURL, {
|
|
174
|
-
params
|
|
175
|
-
});
|
|
176
|
-
},
|
|
177
|
-
/**
|
|
178
|
-
* Filter entities based on query
|
|
179
|
-
* @param {Object} query - Filter query
|
|
180
|
-
* @param {string} [sort] - Sort parameter
|
|
181
|
-
* @param {number} [limit] - Limit results
|
|
182
|
-
* @param {number} [skip] - Skip results (pagination)
|
|
183
|
-
* @param {string[]} [fields] - Fields to include
|
|
184
|
-
* @returns {Promise<Array>} Filtered entities
|
|
185
|
-
*/
|
|
186
|
-
async filter(query, sort, limit, skip, fields) {
|
|
187
|
-
const params = {
|
|
188
|
-
q: JSON.stringify(query)
|
|
189
|
-
};
|
|
190
|
-
if (sort) params.sort = sort;
|
|
191
|
-
if (limit) params.limit = limit;
|
|
192
|
-
if (skip) params.skip = skip;
|
|
193
|
-
if (fields) params.fields = Array.isArray(fields) ? fields.join(',') : fields;
|
|
194
|
-
return axios.get(baseURL, {
|
|
195
|
-
params
|
|
196
|
-
});
|
|
197
|
-
},
|
|
198
|
-
/**
|
|
199
|
-
* Get entity by ID
|
|
200
|
-
* @param {string} id - Entity ID
|
|
201
|
-
* @returns {Promise<Object>} Entity
|
|
202
|
-
*/
|
|
203
|
-
async get(id) {
|
|
204
|
-
return axios.get(`${baseURL}/${id}`);
|
|
205
|
-
},
|
|
206
|
-
/**
|
|
207
|
-
* Create new entity
|
|
208
|
-
* @param {Object} data - Entity data
|
|
209
|
-
* @returns {Promise<Object>} Created entity
|
|
210
|
-
*/
|
|
211
|
-
async create(data) {
|
|
212
|
-
return axios.post(baseURL, data);
|
|
213
|
-
},
|
|
214
|
-
/**
|
|
215
|
-
* Update entity by ID
|
|
216
|
-
* @param {string} id - Entity ID
|
|
217
|
-
* @param {Object} data - Updated entity data
|
|
218
|
-
* @returns {Promise<Object>} Updated entity
|
|
219
|
-
*/
|
|
220
|
-
async update(id, data) {
|
|
221
|
-
return axios.put(`${baseURL}/${id}`, data);
|
|
222
|
-
},
|
|
223
|
-
/**
|
|
224
|
-
* Delete entity by ID
|
|
225
|
-
* @param {string} id - Entity ID
|
|
226
|
-
* @returns {Promise<void>}
|
|
227
|
-
*/
|
|
228
|
-
async delete(id) {
|
|
229
|
-
return axios.delete(`${baseURL}/${id}`);
|
|
230
|
-
},
|
|
231
|
-
/**
|
|
232
|
-
* Delete multiple entities based on query
|
|
233
|
-
* @param {Object} query - Delete query
|
|
234
|
-
* @returns {Promise<void>}
|
|
235
|
-
*/
|
|
236
|
-
async deleteMany(query) {
|
|
237
|
-
return axios.delete(baseURL, {
|
|
238
|
-
data: query
|
|
239
|
-
});
|
|
240
|
-
},
|
|
241
|
-
/**
|
|
242
|
-
* Create multiple entities in a single request
|
|
243
|
-
* @param {Array} data - Array of entity data
|
|
244
|
-
* @returns {Promise<Array>} Created entities
|
|
245
|
-
*/
|
|
246
|
-
async bulkCreate(data) {
|
|
247
|
-
return axios.post(`${baseURL}/bulk`, data);
|
|
248
|
-
},
|
|
249
|
-
/**
|
|
250
|
-
* Import entities from a file
|
|
251
|
-
* @param {File} file - File to import
|
|
252
|
-
* @returns {Promise<Object>} Import result
|
|
253
|
-
*/
|
|
254
|
-
async importEntities(file) {
|
|
255
|
-
const formData = new FormData();
|
|
256
|
-
formData.append('file', file, file.name);
|
|
257
|
-
return axios.post(`${baseURL}/import`, formData, {
|
|
258
|
-
headers: {
|
|
259
|
-
'Content-Type': 'multipart/form-data'
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Creates the integrations module for the Base44 SDK
|
|
268
|
-
* @param {import('axios').AxiosInstance} axios - Axios instance
|
|
269
|
-
* @param {string|number} appId - Application ID
|
|
270
|
-
* @returns {Object} Integrations module
|
|
271
|
-
*/
|
|
272
|
-
function createIntegrationsModule(axios, appId) {
|
|
273
|
-
// Using nested Proxy objects to handle dynamic package and endpoint names
|
|
274
|
-
return new Proxy({}, {
|
|
275
|
-
get(target, packageName) {
|
|
276
|
-
// Skip internal properties
|
|
277
|
-
if (typeof packageName !== 'string' || packageName === 'then' || packageName.startsWith('_')) {
|
|
278
|
-
return undefined;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Create a proxy for integration endpoints
|
|
282
|
-
return new Proxy({}, {
|
|
283
|
-
get(target, endpointName) {
|
|
284
|
-
// Skip internal properties
|
|
285
|
-
if (typeof endpointName !== 'string' || endpointName === 'then' || endpointName.startsWith('_')) {
|
|
286
|
-
return undefined;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Return a function that calls the integration endpoint
|
|
290
|
-
return async data => {
|
|
291
|
-
// Validate input
|
|
292
|
-
if (typeof data === 'string') {
|
|
293
|
-
throw new Error(`Integration ${endpointName} must receive an object with named parameters, received: ${data}`);
|
|
294
|
-
}
|
|
295
|
-
let formData;
|
|
296
|
-
let contentType;
|
|
297
|
-
|
|
298
|
-
// Handle file uploads with FormData
|
|
299
|
-
if (data instanceof FormData || data && Object.values(data).some(value => value instanceof File)) {
|
|
300
|
-
formData = new FormData();
|
|
301
|
-
Object.keys(data).forEach(key => {
|
|
302
|
-
if (data[key] instanceof File) {
|
|
303
|
-
formData.append(key, data[key], data[key].name);
|
|
304
|
-
} else if (typeof data[key] === 'object' && data[key] !== null) {
|
|
305
|
-
formData.append(key, JSON.stringify(data[key]));
|
|
306
|
-
} else {
|
|
307
|
-
formData.append(key, data[key]);
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
contentType = 'multipart/form-data';
|
|
311
|
-
} else {
|
|
312
|
-
formData = data;
|
|
313
|
-
contentType = 'application/json';
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// For Core package
|
|
317
|
-
if (packageName === 'Core') {
|
|
318
|
-
return axios.post(`/apps/${appId}/integrations/Core/${endpointName}`, formData || data, {
|
|
319
|
-
headers: {
|
|
320
|
-
'Content-Type': contentType
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// For other packages
|
|
326
|
-
return axios.post(`/apps/${appId}/integrations/installable/${packageName}/integration-endpoints/${endpointName}`, formData || data, {
|
|
327
|
-
headers: {
|
|
328
|
-
'Content-Type': contentType
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Creates the auth module for the Base44 SDK
|
|
340
|
-
* @param {import('axios').AxiosInstance} axios - Axios instance
|
|
341
|
-
* @param {string|number} appId - Application ID
|
|
342
|
-
* @param {string} serverUrl - Server URL
|
|
343
|
-
* @returns {Object} Auth module with authentication methods
|
|
344
|
-
*/
|
|
345
|
-
function createAuthModule(axios, appId, serverUrl) {
|
|
346
|
-
return {
|
|
347
|
-
/**
|
|
348
|
-
* Get current user information
|
|
349
|
-
* @returns {Promise<Object>} Current user data
|
|
350
|
-
*/
|
|
351
|
-
async me() {
|
|
352
|
-
return axios.get(`/apps/${appId}/entities/User/me`);
|
|
353
|
-
},
|
|
354
|
-
/**
|
|
355
|
-
* Update current user data
|
|
356
|
-
* @param {Object} data - Updated user data
|
|
357
|
-
* @returns {Promise<Object>} Updated user
|
|
358
|
-
*/
|
|
359
|
-
async updateMe(data) {
|
|
360
|
-
return axios.put(`/apps/${appId}/entities/User/me`, data);
|
|
361
|
-
},
|
|
362
|
-
/**
|
|
363
|
-
* Redirects the user to the Base44 login page
|
|
364
|
-
* @param {string} nextUrl - URL to redirect to after successful login
|
|
365
|
-
* @throws {Error} When not in a browser environment
|
|
366
|
-
*/
|
|
367
|
-
login(nextUrl) {
|
|
368
|
-
// This function only works in a browser environment
|
|
369
|
-
if (typeof window === 'undefined') {
|
|
370
|
-
throw new Error('Login method can only be used in a browser environment');
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// If nextUrl is not provided, use the current URL
|
|
374
|
-
const redirectUrl = nextUrl || window.location.href;
|
|
375
|
-
|
|
376
|
-
// Build the login URL
|
|
377
|
-
const loginUrl = `${serverUrl}/login?from_url=${encodeURIComponent(redirectUrl)}&app_id=${appId}`;
|
|
378
|
-
|
|
379
|
-
// Redirect to the login page
|
|
380
|
-
window.location.href = loginUrl;
|
|
381
|
-
},
|
|
382
|
-
/**
|
|
383
|
-
* Logout the current user
|
|
384
|
-
* Removes the token from localStorage and optionally redirects to a URL
|
|
385
|
-
* @param {string} [redirectUrl] - Optional URL to redirect to after logout
|
|
386
|
-
* @returns {Promise<void>}
|
|
387
|
-
*/
|
|
388
|
-
async logout(redirectUrl) {
|
|
389
|
-
// Remove token from axios headers
|
|
390
|
-
delete axios.defaults.headers.common['Authorization'];
|
|
391
|
-
|
|
392
|
-
// Remove token from localStorage
|
|
393
|
-
if (typeof window !== 'undefined' && window.localStorage) {
|
|
394
|
-
try {
|
|
395
|
-
window.localStorage.removeItem('base44_access_token');
|
|
396
|
-
} catch (e) {
|
|
397
|
-
console.error('Failed to remove token from localStorage:', e);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Redirect if a URL is provided
|
|
402
|
-
if (redirectUrl && typeof window !== 'undefined') {
|
|
403
|
-
window.location.href = redirectUrl;
|
|
404
|
-
}
|
|
405
|
-
return Promise.resolve();
|
|
406
|
-
},
|
|
407
|
-
/**
|
|
408
|
-
* Set authentication token
|
|
409
|
-
* @param {string} token - Auth token
|
|
410
|
-
* @param {boolean} [saveToStorage=true] - Whether to save the token to localStorage
|
|
411
|
-
*/
|
|
412
|
-
setToken(token) {
|
|
413
|
-
let saveToStorage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
414
|
-
if (!token) return;
|
|
415
|
-
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
|
|
416
|
-
|
|
417
|
-
// Save token to localStorage if requested
|
|
418
|
-
if (saveToStorage && typeof window !== 'undefined' && window.localStorage) {
|
|
419
|
-
try {
|
|
420
|
-
window.localStorage.setItem('base44_access_token', token);
|
|
421
|
-
} catch (e) {
|
|
422
|
-
console.error('Failed to save token to localStorage:', e);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
},
|
|
426
|
-
/**
|
|
427
|
-
* Verify if the current token is valid
|
|
428
|
-
* @returns {Promise<boolean>} True if token is valid
|
|
429
|
-
*/
|
|
430
|
-
async isAuthenticated() {
|
|
431
|
-
try {
|
|
432
|
-
await this.me();
|
|
433
|
-
return true;
|
|
434
|
-
} catch (error) {
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Utility functions for authentication and token handling
|
|
443
|
-
*/
|
|
444
|
-
|
|
445
|
-
/**
|
|
446
|
-
* Retrieves an access token from either localStorage or URL parameters
|
|
447
|
-
*
|
|
448
|
-
* @param {Object} options - Configuration options
|
|
449
|
-
* @param {string} [options.storageKey='base44_access_token'] - The key to use in localStorage
|
|
450
|
-
* @param {string} [options.paramName='access_token'] - The URL parameter name
|
|
451
|
-
* @param {boolean} [options.saveToStorage=true] - Whether to save the token to localStorage if found in URL
|
|
452
|
-
* @param {boolean} [options.removeFromUrl=true] - Whether to remove the token from URL after retrieval
|
|
453
|
-
* @returns {string|null} The access token or null if not found
|
|
454
|
-
*/
|
|
455
|
-
function getAccessToken() {
|
|
456
|
-
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
457
|
-
const {
|
|
458
|
-
storageKey = 'base44_access_token',
|
|
459
|
-
paramName = 'access_token',
|
|
460
|
-
saveToStorage = true,
|
|
461
|
-
removeFromUrl = true
|
|
462
|
-
} = options;
|
|
463
|
-
let token = null;
|
|
464
|
-
|
|
465
|
-
// Try to get token from URL parameters
|
|
466
|
-
if (typeof window !== 'undefined' && window.location) {
|
|
467
|
-
try {
|
|
468
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
469
|
-
token = urlParams.get(paramName);
|
|
470
|
-
|
|
471
|
-
// If token found in URL
|
|
472
|
-
if (token) {
|
|
473
|
-
// Save token to localStorage if requested
|
|
474
|
-
if (saveToStorage) {
|
|
475
|
-
saveAccessToken(token, {
|
|
476
|
-
storageKey
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// Remove token from URL for security if requested
|
|
481
|
-
if (removeFromUrl) {
|
|
482
|
-
urlParams.delete(paramName);
|
|
483
|
-
const newUrl = `${window.location.pathname}${urlParams.toString() ? `?${urlParams.toString()}` : ''}${window.location.hash}`;
|
|
484
|
-
window.history.replaceState({}, document.title, newUrl);
|
|
485
|
-
}
|
|
486
|
-
return token;
|
|
487
|
-
}
|
|
488
|
-
} catch (e) {
|
|
489
|
-
console.error('Error retrieving token from URL:', e);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// If no token in URL, try localStorage
|
|
494
|
-
if (typeof window !== 'undefined' && window.localStorage) {
|
|
495
|
-
try {
|
|
496
|
-
token = window.localStorage.getItem(storageKey);
|
|
497
|
-
return token;
|
|
498
|
-
} catch (e) {
|
|
499
|
-
console.error('Error retrieving token from localStorage:', e);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
return null;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* Saves an access token to localStorage
|
|
507
|
-
*
|
|
508
|
-
* @param {string} token - The access token to save
|
|
509
|
-
* @param {Object} options - Configuration options
|
|
510
|
-
* @param {string} [options.storageKey='base44_access_token'] - The key to use in localStorage
|
|
511
|
-
* @returns {boolean} Success status
|
|
512
|
-
*/
|
|
513
|
-
function saveAccessToken(token) {
|
|
514
|
-
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
515
|
-
const {
|
|
516
|
-
storageKey = 'base44_access_token'
|
|
517
|
-
} = options;
|
|
518
|
-
if (typeof window === 'undefined' || !window.localStorage || !token) {
|
|
519
|
-
return false;
|
|
520
|
-
}
|
|
521
|
-
try {
|
|
522
|
-
window.localStorage.setItem(storageKey, token);
|
|
523
|
-
return true;
|
|
524
|
-
} catch (e) {
|
|
525
|
-
console.error('Error saving token to localStorage:', e);
|
|
526
|
-
return false;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* Removes the access token from localStorage
|
|
532
|
-
*
|
|
533
|
-
* @param {Object} options - Configuration options
|
|
534
|
-
* @param {string} [options.storageKey='base44_access_token'] - The key to use in localStorage
|
|
535
|
-
* @returns {boolean} Success status
|
|
536
|
-
*/
|
|
537
|
-
function removeAccessToken() {
|
|
538
|
-
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
539
|
-
const {
|
|
540
|
-
storageKey = 'base44_access_token'
|
|
541
|
-
} = options;
|
|
542
|
-
if (typeof window === 'undefined' || !window.localStorage) {
|
|
543
|
-
return false;
|
|
544
|
-
}
|
|
545
|
-
try {
|
|
546
|
-
window.localStorage.removeItem(storageKey);
|
|
547
|
-
return true;
|
|
548
|
-
} catch (e) {
|
|
549
|
-
console.error('Error removing token from localStorage:', e);
|
|
550
|
-
return false;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
/**
|
|
555
|
-
* Constructs the absolute URL for the login page
|
|
556
|
-
*
|
|
557
|
-
* @param {string} nextUrl - URL to redirect back to after login
|
|
558
|
-
* @param {Object} options - Configuration options
|
|
559
|
-
* @param {string} options.serverUrl - Server URL (e.g., 'https://app.base44.com')
|
|
560
|
-
* @param {string|number} options.appId - Application ID
|
|
561
|
-
* @param {string} [options.loginPath='/login'] - Path to the login endpoint
|
|
562
|
-
* @returns {string} The complete login URL
|
|
563
|
-
*/
|
|
564
|
-
function getLoginUrl(nextUrl, options) {
|
|
565
|
-
const {
|
|
566
|
-
serverUrl,
|
|
567
|
-
appId,
|
|
568
|
-
loginPath = '/login'
|
|
569
|
-
} = options;
|
|
570
|
-
if (!serverUrl || !appId) {
|
|
571
|
-
throw new Error('serverUrl and appId are required to construct login URL');
|
|
572
|
-
}
|
|
573
|
-
const encodedRedirectUrl = encodeURIComponent(nextUrl || (typeof window !== 'undefined' ? window.location.href : ''));
|
|
574
|
-
return `${serverUrl}${loginPath}?from_url=${encodedRedirectUrl}&app_id=${appId}`;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
* Create a Base44 client instance
|
|
579
|
-
* @param {Object} config - Client configuration
|
|
580
|
-
* @param {string} [config.serverUrl='https://app.base44.com'] - API server URL
|
|
581
|
-
* @param {string|number} config.appId - Application ID
|
|
582
|
-
* @param {string} [config.env='prod'] - Environment ('prod' or 'dev')
|
|
583
|
-
* @param {string} [config.token] - Authentication token
|
|
584
|
-
* @param {boolean} [config.requiresAuth=false] - Whether the app requires authentication
|
|
585
|
-
* @returns {Object} Base44 client instance
|
|
586
|
-
*/
|
|
587
|
-
function createClient(config) {
|
|
588
|
-
if (!config || !config.appId) {
|
|
589
|
-
throw new Error('appId is required');
|
|
590
|
-
}
|
|
591
|
-
const {
|
|
592
|
-
serverUrl = 'https://app.base44.com',
|
|
593
|
-
appId,
|
|
594
|
-
env = 'prod',
|
|
595
|
-
token,
|
|
596
|
-
requiresAuth = false
|
|
597
|
-
} = config;
|
|
598
|
-
console.log("DOES IT?", requiresAuth, typeof window !== 'undefined');
|
|
599
|
-
|
|
600
|
-
// Create the base axios client
|
|
601
|
-
const axiosClient = createAxiosClient({
|
|
602
|
-
baseURL: `${serverUrl}/api`,
|
|
603
|
-
headers: {
|
|
604
|
-
'X-App-Id': String(appId),
|
|
605
|
-
'X-Environment': env
|
|
606
|
-
},
|
|
607
|
-
token,
|
|
608
|
-
requiresAuth,
|
|
609
|
-
// Pass requiresAuth to axios client
|
|
610
|
-
appId,
|
|
611
|
-
// Pass appId for login redirect
|
|
612
|
-
serverUrl // Pass serverUrl for login redirect
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
// Create modules
|
|
616
|
-
const entities = createEntitiesModule(axiosClient, appId);
|
|
617
|
-
const integrations = createIntegrationsModule(axiosClient, appId);
|
|
618
|
-
const auth = createAuthModule(axiosClient, appId, serverUrl);
|
|
619
|
-
|
|
620
|
-
// Always try to get token from localStorage or URL parameters
|
|
621
|
-
if (typeof window !== 'undefined') {
|
|
622
|
-
// Get token from URL or localStorage
|
|
623
|
-
const accessToken = token || getAccessToken();
|
|
624
|
-
if (accessToken) {
|
|
625
|
-
auth.setToken(accessToken);
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// If authentication is required, verify token and redirect to login if needed
|
|
630
|
-
if (requiresAuth && typeof window !== 'undefined') {
|
|
631
|
-
// We perform this check asynchronously to not block client creation
|
|
632
|
-
setTimeout(async () => {
|
|
633
|
-
try {
|
|
634
|
-
const isAuthenticated = await auth.isAuthenticated();
|
|
635
|
-
if (!isAuthenticated) {
|
|
636
|
-
auth.login(window.location.href);
|
|
637
|
-
}
|
|
638
|
-
} catch (error) {
|
|
639
|
-
console.error('Authentication check failed:', error);
|
|
640
|
-
auth.login(window.location.href);
|
|
641
|
-
}
|
|
642
|
-
}, 0);
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
// Assemble and return the client
|
|
646
|
-
return {
|
|
647
|
-
entities,
|
|
648
|
-
integrations,
|
|
649
|
-
auth,
|
|
650
|
-
/**
|
|
651
|
-
* Set authentication token for all requests
|
|
652
|
-
* @param {string} newToken - New auth token
|
|
653
|
-
*/
|
|
654
|
-
setToken(newToken) {
|
|
655
|
-
auth.setToken(newToken);
|
|
656
|
-
},
|
|
657
|
-
/**
|
|
658
|
-
* Get current configuration
|
|
659
|
-
* @returns {Object} Current configuration
|
|
660
|
-
*/
|
|
661
|
-
getConfig() {
|
|
662
|
-
return {
|
|
663
|
-
serverUrl,
|
|
664
|
-
appId,
|
|
665
|
-
env,
|
|
666
|
-
requiresAuth
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
};
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
export { Base44Error, createClient, getAccessToken, getLoginUrl, removeAccessToken, saveAccessToken };
|
|
1
|
+
import e from"axios";class t extends Error{constructor(e,t,o,n,r){super(e),this.name="Base44Error",this.status=t,this.code=o,this.data=n,this.originalError=r}toJSON(){return{name:this.name,message:this.message,status:this.status,code:this.code,data:this.data}}}function o(o){let{baseURL:n,headers:r={},token:a,requiresAuth:i=!1,appId:s,serverUrl:c}=o;const d=e.create({baseURL:n,headers:{"Content-Type":"application/json",Accept:"application/json",...r}});return a&&(d.defaults.headers.common.Authorization=`Bearer ${a}`),d.interceptors.request.use((e=>("undefined"!=typeof window&&(e.headers={...e.headers,"X-Origin-URL":window.location.href}),e))),d.interceptors.response.use((e=>e.data),(e=>{const o=e.response?.data?.message||e.response?.data?.detail||e.message,n=new t(o,e.response?.status,e.response?.data?.code,e.response?.data,e);return"production"!==process.env.NODE_ENV&&function(e,o){if(o instanceof t){if(console.error(`${e} ${o.status}: ${o.message}`),o.data)try{console.error("Error data:",JSON.stringify(o.data,null,2))}catch(e){console.error("Error data: [Cannot stringify error data]")}}else console.error(`${e} ${o.message}`)}("[Base44 SDK Error]",n),console.log(i,e.response?.status,"undefined"!=typeof window),i&&403===e.response?.status&&"undefined"!=typeof window&&(console.log("Authentication required. Redirecting to login..."),setTimeout((()=>{!function(e,t){if("undefined"==typeof window)return;const o=`${e}/login?from_url=${encodeURIComponent(window.location.href)}&app_id=${t}`;window.location.href=o}(c,s)}),100)),Promise.reject(n)})),d}function n(e,t){return new Proxy({},{get(o,n){if("string"==typeof n&&"then"!==n&&!n.startsWith("_"))return function(e,t,o){const n=`/apps/${t}/entities/${o}`;return{async list(t,o,r,a){const i={};return t&&(i.sort=t),o&&(i.limit=o),r&&(i.skip=r),a&&(i.fields=Array.isArray(a)?a.join(","):a),e.get(n,{params:i})},async filter(t,o,r,a,i){const s={q:JSON.stringify(t)};return o&&(s.sort=o),r&&(s.limit=r),a&&(s.skip=a),i&&(s.fields=Array.isArray(i)?i.join(","):i),e.get(n,{params:s})},get:async t=>e.get(`${n}/${t}`),create:async t=>e.post(n,t),update:async(t,o)=>e.put(`${n}/${t}`,o),delete:async t=>e.delete(`${n}/${t}`),deleteMany:async t=>e.delete(n,{data:t}),bulkCreate:async t=>e.post(`${n}/bulk`,t),async importEntities(t){const o=new FormData;return o.append("file",t,t.name),e.post(`${n}/import`,o,{headers:{"Content-Type":"multipart/form-data"}})}}}(e,t,n)}})}function r(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{storageKey:t="base44_access_token",paramName:o="access_token",saveToStorage:n=!0,removeFromUrl:r=!0}=e;let i=null;if("undefined"!=typeof window&&window.location)try{const e=new URLSearchParams(window.location.search);if(i=e.get(o),i){if(n&&a(i,{storageKey:t}),r){e.delete(o);const t=`${window.location.pathname}${e.toString()?`?${e.toString()}`:""}${window.location.hash}`;window.history.replaceState({},document.title,t)}return i}}catch(e){console.error("Error retrieving token from URL:",e)}if("undefined"!=typeof window&&window.localStorage)try{return i=window.localStorage.getItem(t),i}catch(e){console.error("Error retrieving token from localStorage:",e)}return null}function a(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{storageKey:o="base44_access_token"}=t;if("undefined"==typeof window||!window.localStorage||!e)return!1;try{return window.localStorage.setItem(o,e),!0}catch(e){return console.error("Error saving token to localStorage:",e),!1}}function i(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const{storageKey:t="base44_access_token"}=e;if("undefined"==typeof window||!window.localStorage)return!1;try{return window.localStorage.removeItem(t),!0}catch(e){return console.error("Error removing token from localStorage:",e),!1}}function s(e,t){const{serverUrl:o,appId:n,loginPath:r="/login"}=t;if(!o||!n)throw new Error("serverUrl and appId are required to construct login URL");return`${o}${r}?from_url=${encodeURIComponent(e||("undefined"!=typeof window?window.location.href:""))}&app_id=${n}`}function c(e){if(!e||!e.appId)throw new Error("appId is required");const{serverUrl:t="https://base44.app",appId:a,env:i="prod",token:s,requiresAuth:c=!1}=e,d=o({baseURL:`${t}/api`,headers:{"X-App-Id":String(a),"X-Environment":i},token:s,requiresAuth:c,appId:a,serverUrl:t}),l=n(d,a),p=function(e,t){return new Proxy({},{get(o,n){if("string"==typeof n&&"then"!==n&&!n.startsWith("_"))return new Proxy({},{get(o,r){if("string"==typeof r&&"then"!==r&&!r.startsWith("_"))return async o=>{if("string"==typeof o)throw new Error(`Integration ${r} must receive an object with named parameters, received: ${o}`);let a,i;return o instanceof FormData||o&&Object.values(o).some((e=>e instanceof File))?(a=new FormData,Object.keys(o).forEach((e=>{o[e]instanceof File?a.append(e,o[e],o[e].name):"object"==typeof o[e]&&null!==o[e]?a.append(e,JSON.stringify(o[e])):a.append(e,o[e])})),i="multipart/form-data"):(a=o,i="application/json"),"Core"===n?e.post(`/apps/${t}/integration-endpoints/Core/${r}`,a||o,{headers:{"Content-Type":i}}):e.post(`/apps/${t}/integration-endpoints/installable/${n}/integration-endpoints/${r}`,a||o,{headers:{"Content-Type":i}})}}})}})}(d,a),u=function(e,t,o){return{me:async()=>e.get(`/apps/${t}/entities/User/me`),updateMe:async o=>e.put(`/apps/${t}/entities/User/me`,o),login(e){if("undefined"==typeof window)throw new Error("Login method can only be used in a browser environment");const n=e||window.location.href,r=`${o}/login?from_url=${encodeURIComponent(n)}&app_id=${t}`;window.location.href=r},async logout(t){if(delete e.defaults.headers.common.Authorization,"undefined"!=typeof window&&window.localStorage)try{window.localStorage.removeItem("base44_access_token")}catch(e){console.error("Failed to remove token from localStorage:",e)}return t&&"undefined"!=typeof window&&(window.location.href=t),Promise.resolve()},setToken(t){let o=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(t&&(e.defaults.headers.common.Authorization=`Bearer ${t}`,o&&"undefined"!=typeof window&&window.localStorage))try{window.localStorage.setItem("base44_access_token",t)}catch(e){console.error("Failed to save token to localStorage:",e)}},async isAuthenticated(){try{return await this.me(),!0}catch(e){return!1}}}}(d,a,t);if("undefined"!=typeof window){const e=s||r();e&&u.setToken(e)}return c&&"undefined"!=typeof window&&setTimeout((async()=>{try{await u.isAuthenticated()||u.login(window.location.href)}catch(e){console.error("Authentication check failed:",e),u.login(window.location.href)}}),0),{entities:l,integrations:p,auth:u,setToken(e){u.setToken(e)},getConfig:()=>({serverUrl:t,appId:a,env:i,requiresAuth:c})}}export{t as Base44Error,c as createClient,r as getAccessToken,s as getLoginUrl,i as removeAccessToken,a as saveAccessToken};
|