more fix and update

This commit is contained in:
lendry
2026-06-24 20:15:19 +03:00
parent dcab6557d3
commit 9727cf3f35
53 changed files with 3479 additions and 494 deletions

View File

@@ -129,14 +129,120 @@ export interface AuthTokens {
pinVerified: boolean;
user: PublicUser;
sessionId: string;
requiresTotp?: boolean;
totpChallengeToken?: string;
}
export interface UserProfileResponse {
birthDate?: string | null;
email?: string | null;
phone?: string | null;
backupEmail?: string | null;
backupPhone?: string | null;
displayName?: string;
firstName?: string | null;
lastName?: string | null;
}
export interface QrLoginSession {
sessionId: string;
status: 'PENDING' | 'APPROVED' | 'EXPIRED';
expiresAt: string;
qrPayload?: string;
auth?: AuthTokens & { user?: PublicUser };
}
export async function createQrLoginSession(deviceName: string) {
return apiFetch<QrLoginSession>('/auth/advanced/qr/session', {
method: 'POST',
body: JSON.stringify({
deviceName,
fingerprint: getDeviceFingerprint(),
deviceType: 'WEB'
})
});
}
export async function pollQrLoginSession(sessionId: string) {
return apiFetch<QrLoginSession>(`/auth/advanced/qr/session/${sessionId}`);
}
export interface TotpSetupResponse {
secret: string;
otpauthUrl: string;
}
export interface TotpStatusResponse {
isEnabled: boolean;
}
export interface PresignedUploadResponse {
uploadUrl: string;
storageKey: string;
expiresAt?: string;
uploadToken?: string;
}
export async function uploadMediaObject(
presigned: PresignedUploadResponse,
file: Blob,
contentType: string
) {
if (presigned.uploadToken) {
const apiBase = getApiUrl().replace(/\/$/, '');
const formData = new FormData();
formData.append('file', file, file instanceof File ? file.name : 'upload.bin');
const response = await fetch(`${apiBase}/media/upload`, {
method: 'POST',
headers: { 'X-Upload-Token': presigned.uploadToken },
body: formData
});
if (!response.ok) {
throw new Error('Не удалось загрузить файл');
}
return;
}
const response = await fetch(presigned.uploadUrl, {
method: 'PUT',
headers: { 'Content-Type': contentType },
body: file
});
if (!response.ok) {
throw new Error('Не удалось загрузить файл');
}
}
export interface FamilyInviteCandidate {
id: string;
displayName: string;
email?: string | null;
phone?: string | null;
username?: string | null;
hasAvatar?: boolean;
}
export async function searchFamilyInviteUsers(groupId: string, query: string, token?: string | null) {
return apiFetch<{ users?: FamilyInviteCandidate[] }>(
`/family/groups/${groupId}/invite-search?q=${encodeURIComponent(query)}`,
{},
token
);
}
export interface PasswordlessAuthResponse {
requiresPassword: boolean;
requiresTotp?: boolean;
totpChallengeToken?: string;
tempAuthToken?: string;
auth?: AuthTokens;
}
export interface OtpChannel {
channel: 'email' | 'phone' | 'backupEmail' | 'backupPhone' | string;
masked: string;
}
export interface LoginMethod {
kind: 'password' | 'otp';
channel: string;
@@ -147,9 +253,15 @@ export interface IdentifyResponse {
exists: boolean;
hasPassword: boolean;
isPinEnabled: boolean;
isTotpEnabled?: boolean;
otpChannels?: OtpChannel[];
methods?: LoginMethod[];
}
export interface BeginTotpLoginResponse {
totpChallengeToken: string;
}
export interface OtpSendResponse {
sent: boolean;
expiresAt: string;
@@ -587,8 +699,8 @@ export async function updateFamilyGroup(groupId: string, name: string, token?: s
return apiFetch<FamilyGroup>(`/family/groups/${groupId}`, { method: 'PATCH', body: JSON.stringify({ name }) }, token);
}
export async function sendFamilyInvite(groupId: string, target: string, token?: string | null) {
return apiFetch<FamilyInvite>(`/family/groups/${groupId}/invites`, { method: 'POST', body: JSON.stringify({ target }) }, token);
export async function sendFamilyInvite(groupId: string, payload: { inviteeUserId: string; target?: string }, token?: string | null) {
return apiFetch<FamilyInvite>(`/family/groups/${groupId}/invites`, { method: 'POST', body: JSON.stringify(payload) }, token);
}
export async function fetchFamilyInvites(token?: string | null) {