84 lines
3.0 KiB
JavaScript
84 lines
3.0 KiB
JavaScript
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
// @ts-nocheck
|
|
import { getAppState } from './store';
|
|
|
|
const rawBackendUrl = import.meta.env.VITE_BACKEND_URL ?? 'http://localhost:3000';
|
|
const backendUrl = rawBackendUrl.replace(/\/+$/, '');
|
|
|
|
const toBackendUrl = (path) => {
|
|
if (/^https?:\/\//i.test(path)) {
|
|
return path;
|
|
}
|
|
|
|
return `${backendUrl}${path.startsWith('/') ? path : `/${path}`}`;
|
|
};
|
|
|
|
const request = async (path, options = {}) => {
|
|
const { deviceToken } = getAppState();
|
|
const headers = { 'Content-Type': 'application/json' };
|
|
|
|
if (deviceToken) {
|
|
headers.Authorization = `Bearer ${deviceToken}`;
|
|
}
|
|
|
|
const response = await fetch(toBackendUrl(path), {
|
|
...options,
|
|
credentials: 'include',
|
|
headers: {
|
|
...headers,
|
|
...(options.headers || {})
|
|
}
|
|
});
|
|
|
|
const data = await response.json().catch(() => ({}));
|
|
if (!response.ok) {
|
|
throw new Error(data.message || data.error || response.statusText || 'Request failed');
|
|
}
|
|
|
|
return data;
|
|
};
|
|
|
|
export const getBackendUrl = () => backendUrl;
|
|
|
|
export const api = {
|
|
request,
|
|
auth: {
|
|
signUp: (data) => request('/api/auth/sign-up/email', { method: 'POST', body: JSON.stringify(data) }),
|
|
signIn: (data) => request('/api/auth/sign-in/email', { method: 'POST', body: JSON.stringify(data) }),
|
|
getSession: () => request('/api/auth/get-session'),
|
|
signOut: () => request('/api/auth/sign-out', { method: 'POST', body: JSON.stringify({}) })
|
|
},
|
|
devices: {
|
|
register: (data) => request('/devices/register', { method: 'POST', body: JSON.stringify(data) }),
|
|
list: () => request('/devices'),
|
|
update: (deviceId, data) => request(`/devices/${deviceId}`, { method: 'PATCH', body: JSON.stringify(data) }),
|
|
listLinks: () => request('/device-links'),
|
|
link: (cameraDeviceId, clientDeviceId) =>
|
|
request('/device-links', { method: 'POST', body: JSON.stringify({ cameraDeviceId, clientDeviceId }) }),
|
|
unlink: (linkId) => request(`/device-links/${linkId}`, { method: 'DELETE' })
|
|
},
|
|
streams: {
|
|
request: (cameraDeviceId) =>
|
|
request('/streams/request', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ cameraDeviceId, reason: 'on_demand' })
|
|
}),
|
|
accept: (id) => request(`/streams/${id}/accept`, { method: 'POST', body: JSON.stringify({}) }),
|
|
end: (id) => request(`/streams/${id}/end`, { method: 'POST', body: JSON.stringify({ reason: 'completed' }) })
|
|
},
|
|
events: {
|
|
startMotion: (payload = {}) =>
|
|
request('/events/motion/start', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ title: 'Simulated Motion', triggeredBy: 'motion', ...payload })
|
|
}),
|
|
endMotion: (id) => request(`/events/${id}/motion/end`, { method: 'POST', body: JSON.stringify({ status: 'completed' }) }),
|
|
finalizeRecording: (id, payload) => request(`/recordings/${id}/finalize`, { method: 'POST', body: JSON.stringify(payload) })
|
|
},
|
|
ops: {
|
|
listRecordings: () => request('/recordings/me/list'),
|
|
getRecordingDownloadUrl: (recordingId) => request(`/recordings/${recordingId}/download-url`),
|
|
listNotifications: () => request('/push-notifications/me')
|
|
}
|
|
};
|