70 lines
1.6 KiB
JavaScript
70 lines
1.6 KiB
JavaScript
// Single source of truth for all backend communication.
|
|
|
|
async function http(path, { method = 'GET', body } = {}) {
|
|
const headers = { 'Content-Type': 'application/json' };
|
|
|
|
const res = await fetch(path, {
|
|
method,
|
|
headers,
|
|
credentials: 'include',
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
|
|
if (!res.ok) {
|
|
let message = res.statusText;
|
|
let data;
|
|
try {
|
|
data = await res.json();
|
|
message = data.error || data.message || message;
|
|
} catch {
|
|
message = (await res.text().catch(() => message)) || message;
|
|
}
|
|
const err = new Error(message || `Request failed (${res.status})`);
|
|
err.status = res.status;
|
|
err.data = data;
|
|
throw err;
|
|
}
|
|
if (res.status === 204) return null;
|
|
return res.json();
|
|
}
|
|
|
|
export const auth = {
|
|
async me() {
|
|
try {
|
|
const data = await http('/api/auth/me');
|
|
return {
|
|
user: data.user ?? null,
|
|
googleClientId: data.googleClientId ?? null,
|
|
};
|
|
} catch (err) {
|
|
if (err.status === 401 || err.status === 403) {
|
|
return {
|
|
user: null,
|
|
googleClientId: err.data?.googleClientId ?? null,
|
|
forbidden: err.status === 403,
|
|
message: err.message,
|
|
};
|
|
}
|
|
throw err;
|
|
}
|
|
},
|
|
|
|
async loginWithGoogle(idToken) {
|
|
const data = await http('/api/auth/login', {
|
|
method: 'POST',
|
|
body: { idToken },
|
|
});
|
|
return { user: data.user };
|
|
},
|
|
|
|
async logout() {
|
|
try {
|
|
await http('/api/auth/logout', { method: 'POST' });
|
|
} catch (err) {
|
|
if (err.status !== 401) throw err;
|
|
}
|
|
},
|
|
};
|
|
|
|
export default { auth };
|