feat: PWA update strategy with hashed assets and cache control
Move frontend sources to frontend/, build content-hashed assets at deploy, network-first SW for shell/JS, immutable cache for /assets/, version.json update banner, and Cache-Control middleware. Docs in docs/PWA-STRATEGY.md. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { getToken, clearToken } from "./auth.js";
|
||||
|
||||
async function request(path, options = {}) {
|
||||
const headers = { "Content-Type": "application/json", ...(options.headers || {}) };
|
||||
const token = getToken();
|
||||
if (token) headers.Authorization = `Bearer ${token}`;
|
||||
|
||||
const resp = await fetch(path, { ...options, headers });
|
||||
if (resp.status === 401) {
|
||||
clearToken();
|
||||
window.location.reload();
|
||||
throw new Error("Unauthorized");
|
||||
}
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json().catch(() => ({}));
|
||||
throw new Error(err.detail || resp.statusText);
|
||||
}
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
export const api = {
|
||||
login: (pin) => request("/api/auth/pin", { method: "POST", body: JSON.stringify({ pin }) }),
|
||||
config: () => request("/api/config"),
|
||||
today: () => request("/api/today"),
|
||||
log: (data) => request("/api/log", { method: "POST", body: JSON.stringify(data) }),
|
||||
history: (days = 90) => request(`/api/history?days=${days}`),
|
||||
stats: () => request("/api/stats"),
|
||||
roast: () => request("/api/roast"),
|
||||
snooze: (slot_id, minutes) => request("/api/snooze", { method: "POST", body: JSON.stringify({ slot_id, minutes }) }),
|
||||
vapidKey: () => request("/api/vapid-public-key"),
|
||||
pushSubscribe: (subscription) =>
|
||||
request("/api/push/subscribe", { method: "POST", body: JSON.stringify({ subscription }) }),
|
||||
};
|
||||
Reference in New Issue
Block a user