Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { users } from "./routes/users";
import { profile } from "./routes/profile";
import { rooms } from "./routes/rooms";
import { search } from "./routes/search";
import { cleanupOldData } from "./lib/cleanup";

// Durable Object — live per-room state (WebSocket + match broadcast).
export { Room } from "./durable-objects/room";

const app = new Hono<{ Bindings: Env }>();

app.get("/api/health", (c) => c.json({ ok: true, service: "cinemate", version: "v3.6" }));
app.get("/api/health", (c) => c.json({ ok: true, service: "cinemate", version: "v3.7" }));

app.route("/api/users", users);
app.route("/api/profile", profile);
Expand All @@ -24,4 +25,10 @@ app.get("/join", (c) => c.env.ASSETS.fetch(new Request(new URL("/index.html", c.

app.notFound((c) => c.json({ error: "not_found" }, 404));

export default app;
// fetch = the Hono app; scheduled = the daily D1 cleanup (Cron Trigger, see wrangler.toml).
export default {
fetch: (request: Request, env: Env, ctx: ExecutionContext) => app.fetch(request, env, ctx),
scheduled: (_event: ScheduledController, env: Env, ctx: ExecutionContext) => {
ctx.waitUntil(cleanupOldData(env));
},
} satisfies ExportedHandler<Env>;
24 changes: 24 additions & 0 deletions src/lib/cleanup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Scheduled cleanup: drop data older than the retention window so D1 stays tidy.
// Rooms are ephemeral ("what do we watch tonight"), so 30 days is plenty.
// Runs from the Cron Trigger (see wrangler.toml + the scheduled handler in index.ts).

import type { Env } from "../types";

const RETENTION = "-30 days";

export async function cleanupOldData(env: Env): Promise<void> {
const oldRooms = `SELECT id FROM rooms WHERE created_at < datetime('now', '${RETENTION}')`;
// Delete children first (not relying on FK cascade being enabled), then rooms,
// then orphaned users and their profiles.
await env.DB.batch([
env.DB.prepare(`DELETE FROM swipes WHERE room_id IN (${oldRooms})`),
env.DB.prepare(`DELETE FROM matches WHERE room_id IN (${oldRooms})`),
env.DB.prepare(`DELETE FROM rooms WHERE created_at < datetime('now', '${RETENTION}')`),
env.DB.prepare(
`DELETE FROM users WHERE created_at < datetime('now', '${RETENTION}')
AND id NOT IN (SELECT user_a_id FROM rooms)
AND id NOT IN (SELECT user_b_id FROM rooms WHERE user_b_id IS NOT NULL)`,
),
env.DB.prepare(`DELETE FROM profiles WHERE user_id NOT IN (SELECT id FROM users)`),
]);
}
4 changes: 4 additions & 0 deletions wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ workers_dev = false
# The Worker serves both the files in public/ and the /api routes on one origin.
# Assets take priority: GET / -> index.html, /app.js -> file; routes without a
# matching file (e.g. /api/*) reach the Worker. No CORS, a single deploy.
# Daily cleanup of old rooms/swipes/matches (see scheduled handler in src/index.ts).
[triggers]
crons = ["0 4 * * *"]

[assets]
directory = "./public"
# ASSETS binding: lets the Worker serve index.html for SPA paths like /join.
Expand Down
Loading