@base44/sdk 0.1.0 → 0.1.1

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