Provide a basic account system with login and server side session store identified by a cookie. Upon successful login a signed session cookie is set by the server with the session stored on the server identifying which account it is logged in as. The client uses a shared useFetch on the session endpoint to identify if it's logged in and which account it is logged in as, and refreshes this when loggin in or out.
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import { readFile, writeFile } from "node:fs/promises";
|
|
import { Schedule } from "~/shared/types/schedule";
|
|
import { Account, Subscription, Session } from "~/shared/types/account";
|
|
import { generateDemoSchedule, generateDemoAccounts } from "./generate-demo-schedule";
|
|
|
|
// For this demo I'm just storing the runtime data in JSON files. When making
|
|
// this into proper application this should be replaced with an actual database.
|
|
|
|
const schedulePath = "data/schedule.json";
|
|
const subscriptionsPath = "data/subscriptions.json";
|
|
const accountsPath = "data/accounts.json";
|
|
const sessionsPath = "data/sessions.json";
|
|
const nextSessionIdPath = "data/next-session-id.json";
|
|
|
|
async function readJson<T>(filePath: string, fallback: T) {
|
|
let data: T extends () => infer R ? R : T;
|
|
try {
|
|
data = JSON.parse(await readFile(filePath, "utf-8"));
|
|
} catch (err: any) {
|
|
if (err.code !== "ENOENT")
|
|
throw err;
|
|
data = typeof fallback === "function" ? fallback() : fallback;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
export async function readSchedule() {
|
|
return readJson(schedulePath, generateDemoSchedule);
|
|
}
|
|
|
|
export async function writeSchedule(schedule: Schedule) {
|
|
await writeFile(schedulePath, JSON.stringify(schedule, undefined, "\t") + "\n", "utf-8");
|
|
}
|
|
|
|
export async function readSubscriptions() {
|
|
let subscriptions = await readJson<Subscription[]>(subscriptionsPath, []);
|
|
if (subscriptions.length && "keys" in subscriptions[0]) {
|
|
// Discard old format
|
|
subscriptions = [];
|
|
}
|
|
return subscriptions;
|
|
}
|
|
|
|
export async function writeSubscriptions(subscriptions: Subscription[]) {
|
|
await writeFile(subscriptionsPath, JSON.stringify(subscriptions, undefined, "\t") + "\n", "utf-8");
|
|
}
|
|
|
|
export async function readAccounts() {
|
|
return await readJson(accountsPath, generateDemoAccounts);
|
|
}
|
|
|
|
export async function writeAccounts(accounts: Account[]) {
|
|
await writeFile(accountsPath, JSON.stringify(accounts, undefined, "\t") + "\n", "utf-8");
|
|
}
|
|
|
|
export async function nextSessionId() {
|
|
const nextId = await readJson(nextSessionIdPath, 0);
|
|
await writeFile(nextSessionIdPath, String(nextId + 1), "utf-8");
|
|
return nextId;
|
|
}
|
|
|
|
export async function readSessions() {
|
|
return await readJson<Session[]>(sessionsPath, []);
|
|
}
|
|
|
|
export async function writeSessions(sessions: Session[]) {
|
|
await writeFile(sessionsPath, JSON.stringify(sessions, undefined, "\t") + "\n", "utf-8");
|
|
}
|