@replyke/core
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
291 lines • 13.2 kB
JavaScript
;
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