mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 11:08:12 +00:00
187 lines
5.4 KiB
TypeScript
187 lines
5.4 KiB
TypeScript
import { URL_CONSTANTS } from "@/constants/URLS";
|
|
import type {
|
|
AuthUser,
|
|
ChangePasswordPayload,
|
|
CheckAvailabilityPayload,
|
|
CheckAvailabilityResponse,
|
|
ForgotPasswordRequestPayload,
|
|
ForgotPasswordVerifyPayload,
|
|
GenerateVerificationCodePayload,
|
|
LoginPayload,
|
|
LoginResponse,
|
|
OtpPayload,
|
|
OtpResponse,
|
|
ResetLinkAccount,
|
|
ResetTicket,
|
|
ResolveResetLinkPayload,
|
|
SendContactOtpPayload,
|
|
SendContactOtpResponse,
|
|
SetPasswordPayload,
|
|
SignupPayload,
|
|
SignupResponse,
|
|
UpdateAccountNamePayload,
|
|
UpdateContactPayload,
|
|
UpdateContactResponse,
|
|
} from "@/types/auth";
|
|
import { client } from "@/utils/api";
|
|
import { unwrap } from "@/utils/endpoint";
|
|
import { ApiResponse } from "@edr/types";
|
|
|
|
export const authService = {
|
|
login: async (body: LoginPayload) => {
|
|
const res = await client.post<LoginResponse>(
|
|
URL_CONSTANTS.AUTH.LOGIN,
|
|
body,
|
|
);
|
|
return res.data;
|
|
},
|
|
|
|
createUser: async (body: SignupPayload) => {
|
|
const res = await client.post<SignupResponse & ApiResponse<void>>(
|
|
URL_CONSTANTS.USERS.SIGN_UP,
|
|
body,
|
|
);
|
|
return res.data;
|
|
},
|
|
|
|
getMyInfo: async () => {
|
|
const res = await client.get<AuthUser>(URL_CONSTANTS.USERS.ME);
|
|
return res.data;
|
|
},
|
|
|
|
generateVerificationCode: async (body: GenerateVerificationCodePayload) => {
|
|
const res = await client.patch<ApiResponse<string>>(
|
|
URL_CONSTANTS.USERS.GENERATE_VERIFICATION_CODE,
|
|
body,
|
|
);
|
|
return res.data.data;
|
|
},
|
|
|
|
setPassword: async (body: SetPasswordPayload) => {
|
|
const res = await client.patch<ApiResponse<void>>(
|
|
URL_CONSTANTS.USERS.SET_PASSWORD,
|
|
body,
|
|
);
|
|
return res.data.data;
|
|
},
|
|
|
|
// The three calls below drive the unauthenticated forgot-password flow.
|
|
// Responses under /api/auth are *flattened* by the API's response
|
|
// interceptor ({ success, ...payload }), so there is no `.data.data` here.
|
|
|
|
requestPasswordReset: async (body: ForgotPasswordRequestPayload) => {
|
|
await client.post(URL_CONSTANTS.AUTH.FORGOT_PASSWORD_REQUEST, body);
|
|
},
|
|
|
|
verifyPasswordResetOtp: async (body: ForgotPasswordVerifyPayload) => {
|
|
const res = await client.post<ResetTicket>(
|
|
URL_CONSTANTS.AUTH.FORGOT_PASSWORD_VERIFY,
|
|
body,
|
|
);
|
|
return { userId: res.data.userId, verificationCode: res.data.verificationCode };
|
|
},
|
|
|
|
/**
|
|
* Validate a staff-issued reset link before showing the password form, and
|
|
* pick up the ticket it carries. Rejected links (expired, already spent) fail
|
|
* here rather than after the customer has typed a new password.
|
|
*/
|
|
resolveResetLink: async (body: ResolveResetLinkPayload) => {
|
|
const res = await client.post<ResetLinkAccount>(
|
|
URL_CONSTANTS.AUTH.FORGOT_PASSWORD_RESOLVE_LINK,
|
|
body,
|
|
);
|
|
return res.data;
|
|
},
|
|
|
|
/**
|
|
* Spend the reset ticket. Distinct from `setPassword` above, which the
|
|
* authenticated post-signup flow drives through `useAuth` — this one carries
|
|
* its own userId/verificationCode and never touches the session.
|
|
*/
|
|
resetPassword: async (body: SetPasswordPayload) => {
|
|
await client.patch(URL_CONSTANTS.USERS.SET_PASSWORD, body);
|
|
},
|
|
|
|
checkAvailability: async (params: CheckAvailabilityPayload) => {
|
|
const res = await client.get<CheckAvailabilityResponse>(
|
|
URL_CONSTANTS.USERS.CHECK_AVAILABILITY,
|
|
{ params },
|
|
);
|
|
return res.data;
|
|
},
|
|
|
|
sendOTP: async (body: OtpPayload) => {
|
|
const res = await client.post<ApiResponse<OtpResponse>>(
|
|
URL_CONSTANTS.OTP.SEND,
|
|
body,
|
|
);
|
|
return res.data.data;
|
|
},
|
|
|
|
verifyOTP: async (body: OtpPayload) => {
|
|
const res = await client.post<ApiResponse<OtpResponse>>(
|
|
URL_CONSTANTS.OTP.VERIFY,
|
|
body,
|
|
);
|
|
return res.data.data;
|
|
},
|
|
|
|
/**
|
|
* Change the signed-in user's password via IAM's own route: it verifies the
|
|
* old password with argon and owns the credential write (deactivating the
|
|
* previous one), so this app never touches password material.
|
|
*/
|
|
changePassword: async (body: ChangePasswordPayload) => {
|
|
await client.patch(URL_CONSTANTS.AUTH.CHANGE_PASSWORD, body);
|
|
},
|
|
|
|
// The three calls below manage the signed-in user's own account record
|
|
// (`/api/me`), which is what OTPs and SMS notifications are delivered to.
|
|
// Changing phone/email is OTP-gated server-side: the code goes to the NEW
|
|
// value, and the write only lands once it is verified.
|
|
|
|
sendContactOtp: async (body: SendContactOtpPayload) => {
|
|
const res = await client.post<ApiResponse<SendContactOtpResponse>>(
|
|
URL_CONSTANTS.ACCOUNT.CONTACT_OTP,
|
|
body,
|
|
);
|
|
return unwrap(res.data);
|
|
},
|
|
|
|
updateContact: async (body: UpdateContactPayload) => {
|
|
const res = await client.patch<ApiResponse<UpdateContactResponse>>(
|
|
URL_CONSTANTS.ACCOUNT.CONTACT,
|
|
body,
|
|
);
|
|
return unwrap(res.data);
|
|
},
|
|
|
|
updateAccountName: async (body: UpdateAccountNamePayload) => {
|
|
const res = await client.patch<ApiResponse<{ success: true }>>(
|
|
URL_CONSTANTS.ACCOUNT.NAME,
|
|
body,
|
|
);
|
|
return unwrap(res.data);
|
|
},
|
|
|
|
refreshToken: async () => {
|
|
const refreshTokenCookie = document.cookie
|
|
.split("; ")
|
|
.find((row) => row.startsWith("refresh-token="))
|
|
?.split("=")[1];
|
|
const res = await client.post<ApiResponse<LoginResponse>>(
|
|
URL_CONSTANTS.AUTH.REFRESH_TOKEN,
|
|
{ refreshToken: refreshTokenCookie },
|
|
);
|
|
return res.data.data;
|
|
},
|
|
|
|
logout: async () => {
|
|
const res = await client.patch<ApiResponse<void>>(
|
|
URL_CONSTANTS.AUTH.LOGOUT,
|
|
);
|
|
return res.data.data;
|
|
},
|
|
};
|