diff --git a/src/client.ts b/src/client.ts index 67d4dcf..8f7d675 100644 --- a/src/client.ts +++ b/src/client.ts @@ -18,6 +18,7 @@ export type Base44Client = ReturnType; * Create a Base44 client instance * @param {Object} config - Client configuration * @param {string} [config.serverUrl='https://base44.app'] - API server URL + * @param {string} [config.appBaseUrl] - Application base URL * @param {string|number} config.appId - Application ID * @param {string} [config.token] - Authentication token * @param {string} [config.serviceToken] - Service role authentication token @@ -26,6 +27,7 @@ export type Base44Client = ReturnType; */ export function createClient(config: { serverUrl?: string; + appBaseUrl?: string; appId: string; token?: string; serviceToken?: string; @@ -33,7 +35,6 @@ export function createClient(config: { functionsVersion?: string; headers?: Record; options?: CreateClientOptions; - onRedirectToLogin?: () => void; }) { const { serverUrl = "https://base44.app", @@ -41,9 +42,9 @@ export function createClient(config: { token, serviceToken, requiresAuth = false, + appBaseUrl, options, functionsVersion, - onRedirectToLogin, headers: optionalHeaders, } = config; @@ -75,50 +76,36 @@ export function createClient(config: { baseURL: `${serverUrl}/api`, headers, token, - requiresAuth, - appId, - serverUrl, onError: options?.onError, - onRedirectToLogin, }); const functionsAxiosClient = createAxiosClient({ baseURL: `${serverUrl}/api`, headers: functionHeaders, token, - requiresAuth, - appId, - serverUrl, interceptResponses: false, onError: options?.onError, - onRedirectToLogin, }); const serviceRoleAxiosClient = createAxiosClient({ baseURL: `${serverUrl}/api`, headers, token: serviceToken, - serverUrl, - appId, onError: options?.onError, - onRedirectToLogin, }); const serviceRoleFunctionsAxiosClient = createAxiosClient({ baseURL: `${serverUrl}/api`, headers: functionHeaders, token: serviceToken, - serverUrl, - appId, interceptResponses: false, - onRedirectToLogin, }); const userModules = { entities: createEntitiesModule(axiosClient, appId), integrations: createIntegrationsModule(axiosClient, appId), auth: createAuthModule(axiosClient, functionsAxiosClient, appId, { - onRedirectToLogin, + appBaseUrl, serverUrl, }), functions: createFunctionsModule(functionsAxiosClient, appId), @@ -144,7 +131,7 @@ export function createClient(config: { socket, appId, serverUrl, - token + token, }), cleanup: () => { socket.disconnect(); diff --git a/src/modules/auth.ts b/src/modules/auth.ts index 519ca62..412b65a 100644 --- a/src/modules/auth.ts +++ b/src/modules/auth.ts @@ -13,7 +13,7 @@ export function createAuthModule( appId: string, options: { serverUrl: string; - onRedirectToLogin?: () => void; + appBaseUrl?: string; } ) { return { @@ -46,10 +46,6 @@ export function createAuthModule( ); } - if (options.onRedirectToLogin) { - options.onRedirectToLogin(); - return; - } // If nextUrl is not provided, use the current URL const redirectUrl = nextUrl ? new URL(nextUrl, window.location.origin).toString() @@ -57,8 +53,8 @@ export function createAuthModule( // Build the login URL const loginUrl = `${ - options.serverUrl - }/login?from_url=${encodeURIComponent(redirectUrl)}&app_id=${appId}`; + options.appBaseUrl ?? "" + }/login?from_url=${encodeURIComponent(redirectUrl)}`; // Redirect to the login page window.location.href = loginUrl; diff --git a/src/utils/axios-client.ts b/src/utils/axios-client.ts index aaff872..ec4dc52 100644 --- a/src/utils/axios-client.ts +++ b/src/utils/axios-client.ts @@ -57,21 +57,6 @@ function safeErrorLog(prefix: string, error: unknown) { } } -/** - * Redirects to the login page with the current URL as return destination - * @param {string} serverUrl - Base server URL - * @param {string|number} appId - Application ID - */ -function redirectToLogin(serverUrl: string, appId: string) { - if (typeof window === "undefined") { - return; // Can't redirect in non-browser environment - } - - const currentUrl = encodeURIComponent(window.location.href); - const loginUrl = `${serverUrl}/login?from_url=${currentUrl}&app_id=${appId}`; - window.location.href = loginUrl; -} - /** * Creates an axios client with default configuration and interceptors * @param {Object} options - Client configuration options @@ -87,22 +72,14 @@ export function createAxiosClient({ baseURL, headers = {}, token, - requiresAuth = false, - appId, - serverUrl, interceptResponses = true, onError, - onRedirectToLogin, }: { baseURL: string; headers?: Record; token?: string; - requiresAuth?: boolean; - appId: string; - serverUrl: string; interceptResponses?: boolean; onError?: (error: Error) => void; - onRedirectToLogin?: () => void; }) { const client = axios.create({ baseURL, @@ -193,26 +170,6 @@ export function createAxiosClient({ safeErrorLog("[Base44 SDK Error]", base44Error); } - // Check for 403 Forbidden (authentication required) and redirect to login if requiresAuth is true - console.log( - requiresAuth, - error.response?.status, - typeof window !== "undefined" - ); - if ( - requiresAuth && - error.response?.status === 403 && - typeof window !== "undefined" - ) { - console.log("Authentication required. Redirecting to login..."); - // Use a slight delay to allow the error to propagate first - setTimeout(() => { - onRedirectToLogin - ? onRedirectToLogin() - : redirectToLogin(serverUrl, appId); - }, 100); - } - onError?.(base44Error); return Promise.reject(base44Error); diff --git a/tests/unit/auth.test.js b/tests/unit/auth.test.js index e871ceb..9ed354e 100644 --- a/tests/unit/auth.test.js +++ b/tests/unit/auth.test.js @@ -149,7 +149,7 @@ describe('Auth Module', () => { // Verify the redirect URL was set correctly expect(mockLocation.href).toBe( - `${serverUrl}/login?from_url=${encodeURIComponent(nextUrl)}&app_id=${appId}` + `/login?from_url=${encodeURIComponent(nextUrl)}` ); // Restore window @@ -164,14 +164,61 @@ describe('Auth Module', () => { global.window = { location: mockLocation }; - + base44.auth.redirectToLogin(); - + // Verify the redirect URL uses current URL expect(mockLocation.href).toBe( - `${serverUrl}/login?from_url=${encodeURIComponent(currentUrl)}&app_id=${appId}` + `/login?from_url=${encodeURIComponent(currentUrl)}` ); - + + // Restore window + global.window = originalWindow; + }); + + test('should use appBaseUrl for login redirect when provided', () => { + const customAppBaseUrl = 'https://custom-app.example.com'; + const clientWithCustomUrl = createClient({ + serverUrl, + appId, + appBaseUrl: customAppBaseUrl, + }); + + // Mock window.location + const originalWindow = global.window; + const mockLocation = { href: '' }; + global.window = { + location: mockLocation + }; + + const nextUrl = 'https://example.com/dashboard'; + clientWithCustomUrl.auth.redirectToLogin(nextUrl); + + // Verify the redirect URL uses the custom appBaseUrl + expect(mockLocation.href).toBe( + `${customAppBaseUrl}/login?from_url=${encodeURIComponent(nextUrl)}` + ); + + // Restore window + global.window = originalWindow; + }); + + test('should use relative URL for login redirect when appBaseUrl is not provided', () => { + // Mock window.location + const originalWindow = global.window; + const mockLocation = { href: '', origin: 'https://current-app.com' }; + global.window = { + location: mockLocation + }; + + const nextUrl = 'https://example.com/dashboard'; + base44.auth.redirectToLogin(nextUrl); + + // Verify the redirect URL uses a relative path (no appBaseUrl prefix) + expect(mockLocation.href).toBe( + `/login?from_url=${encodeURIComponent(nextUrl)}` + ); + // Restore window global.window = originalWindow; });