Add self-hosted kids calendar app
Express + SQLite (node:sqlite, no native build step) family calendar: parent accounts with household invites, per-child calendars with save/duplicate/print, a token-gated read-only kiosk view for tablets, and polling to keep parent and kiosk views in sync. Defaults to port 3007.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
const api = {
|
||||
async request(method, path, body) {
|
||||
const res = await fetch(path, {
|
||||
method,
|
||||
credentials: 'include',
|
||||
headers: body !== undefined ? { 'Content-Type': 'application/json' } : undefined,
|
||||
body: body !== undefined ? JSON.stringify(body) : undefined,
|
||||
});
|
||||
|
||||
if (res.status === 204) return null;
|
||||
|
||||
let data = null;
|
||||
const text = await res.text();
|
||||
if (text) {
|
||||
try { data = JSON.parse(text); } catch { data = null; }
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const err = new Error((data && data.error) || `Request failed (${res.status})`);
|
||||
err.status = res.status;
|
||||
throw err;
|
||||
}
|
||||
return data;
|
||||
},
|
||||
get(path) { return this.request('GET', path); },
|
||||
post(path, body) { return this.request('POST', path, body === undefined ? {} : body); },
|
||||
patch(path, body) { return this.request('PATCH', path, body === undefined ? {} : body); },
|
||||
del(path) { return this.request('DELETE', path); },
|
||||
};
|
||||
Reference in New Issue
Block a user