UNPKG

@replyke/core

Version:

Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.

291 lines 13.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initializeAuthThunk = exports.signOutAllThunk = exports.changePasswordThunk = exports.verifyExternalUserThunk = exports.requestNewAccessTokenThunk = exports.signOutThunk = exports.signInWithEmailAndPasswordThunk = exports.signUpWithEmailAndPasswordThunk = void 0; const toolkit_1 = require("@reduxjs/toolkit"); const axios_1 = __importDefault(require("../../config/axios")); const handleError_1 = require("../../utils/handleError"); const authSlice_1 = require("./authSlice"); const userSlice_1 = require("./userSlice"); const accountsSlice_1 = require("./accountsSlice"); const baseApi_1 = require("../api/baseApi"); // Auth service functions - calling existing API patterns directly const authService = { async signUpWithEmailAndPassword(projectId, data) { // Check if we need to use FormData (when files are present) if (data.avatarFile || data.bannerFile) { const formData = new FormData(); // Append regular fields formData.append("email", data.email); formData.append("password", data.password); if (data.name?.trim()) formData.append("name", data.name.trim()); if (data.username?.trim()) formData.append("username", data.username.trim()); if (data.bio?.trim()) formData.append("bio", data.bio.trim()); if (data.location) formData.append("location", JSON.stringify(data.location)); if (data.birthdate) formData.append("birthdate", data.birthdate.toISOString()); if (data.metadata) formData.append("metadata", JSON.stringify(data.metadata)); if (data.secureMetadata) formData.append("secureMetadata", JSON.stringify(data.secureMetadata)); // Append avatar file and options if (data.avatarFile) { formData.append("avatarFile", data.avatarFile); if (data.avatarOptions) { formData.append("avatarFile.options", JSON.stringify(data.avatarOptions)); } } // Append banner file and options if (data.bannerFile) { formData.append("bannerFile", data.bannerFile); if (data.bannerOptions) { formData.append("bannerFile.options", JSON.stringify(data.bannerOptions)); } } const response = await axios_1.default.post(`/${projectId}/auth/sign-up`, formData, { headers: { "Content-Type": "multipart/form-data" }, }); return response.data; } // Fallback to regular JSON request (backward compatibility) const response = await axios_1.default.post(`/${projectId}/auth/sign-up`, { email: data.email, password: data.password, name: data.name?.trim(), username: data.username?.trim(), avatar: data.avatar, bio: data.bio?.trim(), location: data.location, birthdate: data.birthdate, metadata: data.metadata, secureMetadata: data.secureMetadata, }); return response.data; }, async signInWithEmailAndPassword(projectId, data) { const response = await axios_1.default.post(`/${projectId}/auth/sign-in`, data); return response.data; }, async signOut(projectId, refreshToken) { const payload = refreshToken ? { refreshToken } : {}; await axios_1.default.post(`/${projectId}/auth/sign-out`, payload); }, async requestNewAccessToken(projectId, refreshToken) { const payload = refreshToken ? { refreshToken } : {}; const response = await axios_1.default.post(`/${projectId}/auth/request-new-access-token`, payload); return response.data; }, async verifyExternalUser(projectId, userJwt) { const response = await axios_1.default.post(`/${projectId}/auth/verify-external-user`, { userJwt }); return response.data; }, async changePassword(projectId, data) { await axios_1.default.post(`/${projectId}/auth/change-password`, data); }, }; // Async Thunks exports.signUpWithEmailAndPasswordThunk = (0, toolkit_1.createAsyncThunk)("auth/signUpWithEmailAndPassword", async (data, { dispatch, rejectWithValue }) => { try { dispatch((0, authSlice_1.setAuthenticating)(true)); const result = await authService.signUpWithEmailAndPassword(data.projectId, data); // Update auth state dispatch((0, authSlice_1.setTokens)({ accessToken: result.accessToken, refreshToken: result.refreshToken, })); dispatch((0, authSlice_1.setUser)(result.user)); dispatch((0, userSlice_1.setUser)(result.user)); // Sync user to user slice return result; } catch (error) { (0, handleError_1.handleError)(error, "Failed to register user with email and password:"); return rejectWithValue(error instanceof Error ? error.message : "Unknown error"); } finally { dispatch((0, authSlice_1.setAuthenticating)(false)); } }); exports.signInWithEmailAndPasswordThunk = (0, toolkit_1.createAsyncThunk)("auth/signInWithEmailAndPassword", async (data, { dispatch, rejectWithValue }) => { try { dispatch((0, authSlice_1.setAuthenticating)(true)); const result = await authService.signInWithEmailAndPassword(data.projectId, data); // Update auth state dispatch((0, authSlice_1.setTokens)({ accessToken: result.accessToken, refreshToken: result.refreshToken, })); dispatch((0, authSlice_1.setUser)(result.user)); dispatch((0, userSlice_1.setUser)(result.user)); // Sync user to user slice return result; } catch (error) { (0, handleError_1.handleError)(error, "Failed to log user in:"); return rejectWithValue(error instanceof Error ? error.message : "Unknown error"); } finally { dispatch((0, authSlice_1.setAuthenticating)(false)); } }); exports.signOutThunk = (0, toolkit_1.createAsyncThunk)("auth/signOut", async (data, { dispatch, getState, rejectWithValue }) => { const state = getState(); const refreshToken = state.replyke.auth.refreshToken; const activeAccountId = state.replyke.accounts.activeAccountId; const accounts = state.replyke.accounts.accounts; if (!refreshToken) { throw new Error("No refresh token"); } try { dispatch((0, authSlice_1.setAuthenticating)(true)); await authService.signOut(data.projectId, refreshToken); // Remove current account from the multi-account map if (activeAccountId) { dispatch((0, accountsSlice_1.removeAccount)(activeAccountId)); } // Check for remaining accounts const remainingIds = Object.keys(accounts).filter((id) => id !== activeAccountId); if (remainingIds.length > 0) { // Switch to the first remaining account const nextId = remainingIds[0]; const nextAccount = accounts[nextId]; dispatch((0, authSlice_1.resetAuth)()); dispatch((0, userSlice_1.clearUser)()); dispatch(baseApi_1.baseApi.util.resetApiState()); dispatch((0, authSlice_1.setTokens)({ accessToken: null, refreshToken: nextAccount.refreshToken, })); dispatch((0, authSlice_1.setInitialized)(false)); await dispatch((0, exports.requestNewAccessTokenThunk)({ projectId: data.projectId })); dispatch((0, authSlice_1.setInitialized)(true)); } else { // No remaining accounts — standard sign-out dispatch((0, authSlice_1.resetAuth)()); dispatch((0, userSlice_1.clearUser)()); dispatch(baseApi_1.baseApi.util.resetApiState()); } return; } catch (error) { (0, handleError_1.handleError)(error, "Failed to log user out:"); return rejectWithValue(error instanceof Error ? error.message : "Unknown error"); } finally { dispatch((0, authSlice_1.setAuthenticating)(false)); } }); exports.requestNewAccessTokenThunk = (0, toolkit_1.createAsyncThunk)("auth/requestNewAccessToken", async (data, { dispatch, getState, rejectWithValue }) => { const state = getState(); const refreshToken = state.replyke.auth.refreshToken; if (!refreshToken) { return; } try { const result = await authService.requestNewAccessToken(data.projectId, refreshToken); // Update auth state (store rotated refresh token from server) dispatch((0, authSlice_1.setTokens)({ accessToken: result.accessToken, refreshToken: result.refreshToken, })); dispatch((0, authSlice_1.setUser)(result.user)); dispatch((0, userSlice_1.setUser)(result.user)); // Sync user to user slice return result.accessToken; } catch (error) { (0, handleError_1.handleError)(error, "Request new access token error:"); return rejectWithValue(error instanceof Error ? error.message : "Unknown error"); } }); exports.verifyExternalUserThunk = (0, toolkit_1.createAsyncThunk)("auth/verifyExternalUser", async (data, { dispatch, rejectWithValue }) => { try { const result = await authService.verifyExternalUser(data.projectId, data.userJwt); // Update auth state dispatch((0, authSlice_1.setTokens)({ accessToken: result.accessToken, refreshToken: result.refreshToken, })); dispatch((0, authSlice_1.setUser)(result.user)); dispatch((0, userSlice_1.setUser)(result.user)); // Sync user to user slice return result; } catch (error) { (0, handleError_1.handleError)(error, "Verify external user error:"); return rejectWithValue(error instanceof Error ? error.message : "Unknown error"); } }); exports.changePasswordThunk = (0, toolkit_1.createAsyncThunk)("auth/changePassword", async (data, { dispatch, getState, rejectWithValue }) => { const state = getState(); if (!state.replyke.auth.user) { throw new Error("No user is authenticated"); } try { dispatch((0, authSlice_1.setAuthenticating)(true)); await authService.changePassword(data.projectId, data); return; } catch (error) { (0, handleError_1.handleError)(error, "Failed to change password:"); return rejectWithValue(error instanceof Error ? error.message : "Unknown error"); } finally { dispatch((0, authSlice_1.setAuthenticating)(false)); } }); exports.signOutAllThunk = (0, toolkit_1.createAsyncThunk)("auth/signOutAll", async (data, { dispatch, getState, rejectWithValue }) => { const state = getState(); const accounts = state.replyke.accounts.accounts; try { dispatch((0, authSlice_1.setAuthenticating)(true)); // Sign out from each account on the server (best-effort) const signOutPromises = Object.values(accounts).map(async (account) => { try { await authService.signOut(data.projectId, account.refreshToken); } catch (err) { // Best-effort: log but don't fail the entire operation (0, handleError_1.handleError)(err, `Failed to sign out account on server:`); } }); await Promise.all(signOutPromises); // Clear all local state dispatch((0, accountsSlice_1.clearAllAccounts)()); dispatch((0, authSlice_1.resetAuth)()); dispatch((0, userSlice_1.clearUser)()); dispatch(baseApi_1.baseApi.util.resetApiState()); return; } catch (error) { (0, handleError_1.handleError)(error, "Failed to sign out all accounts:"); return rejectWithValue(error instanceof Error ? error.message : "Unknown error"); } finally { dispatch((0, authSlice_1.setAuthenticating)(false)); } }); // Initialize auth - handles the startup flow exports.initializeAuthThunk = (0, toolkit_1.createAsyncThunk)("auth/initialize", async (data, { dispatch }) => { try { // Step 1: If we have a signed token, verify external user if (data.signedToken) { await dispatch((0, exports.verifyExternalUserThunk)({ projectId: data.projectId, userJwt: data.signedToken, })); } // Step 2: Try to refresh access token await dispatch((0, exports.requestNewAccessTokenThunk)({ projectId: data.projectId })); } catch (error) { (0, handleError_1.handleError)(error, "Auth initialization failed:"); } finally { dispatch((0, authSlice_1.setInitialized)(true)); } }); //# sourceMappingURL=authThunks.js.map