buhapp-telegram/public/js/api.js
root 058649013d Fix login: same-origin proxy + minimal api.js + без retry/timeout
- api.js полностью переписан: simple fetch с credentials:'include', без mode:cors
- emailLogin: без 150мс паузы, без retry — same-origin не висит
- nginx: /api/* → backend через тот же домен (убирает cross-subdomain)
- backend cookie: SameSite=Lax, host-only
2026-08-21 11:04:11 +00:00

100 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Same-origin API wrapper (api проксируется через nginx на тот же домен)
// Никаких retry/timeout на login — только UI feedback
const DEFAULT_INIT = {
credentials: 'include',
cache: 'no-store',
redirect: 'follow',
};
export async function api(path, options = {}) {
const { json, headers: extraHeaders, ...rest } = options;
const headers = new Headers(extraHeaders || {});
let body = rest.body;
if (json !== undefined) {
headers.set('Content-Type', 'application/json');
body = JSON.stringify(json);
}
if (!headers.has('Accept')) {
headers.set('Accept', 'application/json');
}
const res = await fetch(path, {
...DEFAULT_INIT,
...rest,
headers,
body,
});
const ct = res.headers.get('content-type') || '';
const isJson = ct.includes('application/json');
const data = isJson ? await res.json().catch(() => null) : await res.text();
if (!res.ok) {
const err = new Error((data && (data.message || data.error)) || `HTTP ${res.status}`);
err.status = res.status;
err.data = data;
throw err;
}
return data;
}
export const apiGet = (path, opts) => api(path, { ...opts, method: 'GET' });
export const apiPost = (path, json, opts) => api(path, { ...opts, method: 'POST', json });
export const apiPut = (path, json, opts) => api(path, { ...opts, method: 'PUT', json });
export const apiDelete = (path, opts) => api(path, { ...opts, method: 'DELETE' });
// Совместимость со старым window.API.Auth
window.API = {
api, apiGet, apiPost, apiPut, apiDelete,
// обёртки для совместимости со старыми view
Auth: {
loginEmail: (email, password) => apiPost('/api/v1/auth/login', { email, password }),
registerEmail: (data) => apiPost('/api/v1/auth/register', data),
me: () => apiGet('/api/v1/me'),
updateMe: (p) => apiPut('/api/v1/me', p),
getPrefs: () => apiGet('/api/v1/me/prefs'),
updatePrefs: (p) => apiPut('/api/v1/me/prefs', p),
updateLocation: (lat, lng, visible) => apiPut('/api/v1/me/location', { lat, lng, visible }),
setVisibility: (v) => apiPut('/api/v1/me/visibility', { visible: v }),
searchNearby: (lat, lng, radius) => apiGet(`/api/v1/search/nearby?lat=${lat}&lng=${lng}&radius=${radius}`),
getUser: (id) => apiGet('/api/v1/users/' + id),
},
ChatApi: {
ensureChat: (otherId) => apiPost('/api/v1/chats', { other_id: otherId }),
listChats: () => apiGet('/api/v1/chats'),
listMessages: (chatId) => apiGet('/api/v1/chats/' + chatId + '/messages'),
sendMessage: (chatId, body, photoUrl) => apiPost('/api/v1/chats/' + chatId + '/messages', { body, photo_url: photoUrl }),
editMessage: (msgId, body) => apiPut('/api/v1/messages/' + msgId, { body }),
deleteMessage: (msgId) => apiDelete('/api/v1/messages/' + msgId),
markRead: (chatId) => apiPut('/api/v1/chats/' + chatId + '/read', {}),
block: (userId) => apiPost('/api/v1/blocks', { user_id: userId }),
report: (type, id, reason) => apiPost('/api/v1/reports', { target_type: type, target_id: id, reason }),
},
ReviewApi: {
create: (chatId, rating, body, anonymous) => apiPost('/api/v1/reviews', { chat_id: chatId, rating, body, anonymous }),
listForUser: (userId) => apiGet('/api/v1/users/' + userId + '/reviews'),
stats: (userId) => apiGet('/api/v1/users/' + userId + '/stats'),
},
ConsentApi: {
status: () => apiGet('/api/v1/auth/consents').catch(() => ({ all_accepted: false, accepted: {} })),
accept: (payload) => apiPost('/api/v1/auth/consents', payload),
},
PlacesApi: {
nearby: (lat, lng, radius, limit = 30) => apiGet(`/api/v1/places/nearby?lat=${lat}&lng=${lng}&radius=${radius || 5}&limit=${limit}`).catch((e) => ({ places: [], count: 0, error: e.message })),
},
Store: {
access: null,
refresh: null,
user: null,
save(tokens) {
if (!tokens) return;
this.access = tokens.Access || tokens.access;
this.refresh = tokens.Refresh || tokens.refresh;
},
load() { return this.access; },
clear() { this.access = null; this.refresh = null; this.user = null; },
},
};