···11import { Hono } from "hono";
22import { cors } from "hono/cors";
33import type { Bindings } from "./types";
44-import { health, webhook, feed, stats, records, admin, rss } from "./routes";
44+import {
55+ health,
66+ webhook,
77+ feed,
88+ stats,
99+ records,
1010+ admin,
1111+ rss,
1212+ jetstream,
1313+} from "./routes";
514import { processDocument } from "./utils";
615716const app = new Hono<{ Bindings: Bindings }>();
···1726app.route("/records", records);
1827app.route("/admin", admin);
1928app.route("/rss.xml", rss);
2929+app.route("/jetstream", jetstream);
20302131// 404 handler
2232app.notFound((c) => {
2333 return c.json({ error: "Not found" }, 404);
2434});
3535+3636+// Export Durable Object class
3737+export { JetstreamConsumer } from "./durable-objects/jetstream-consumer";
25382639// Export for Cloudflare Workers
2740export default {
2841 fetch: app.fetch,
2929- async scheduled(event: ScheduledEvent, env: Bindings, ctx: ExecutionContext) {
4242+ async scheduled(_event: ScheduledEvent, env: Bindings, _ctx: ExecutionContext) {
3043 const batchSize = 50;
3144 // Select stale documents
3245 const { results } = await env.DB.prepare(
···4962 // Send to queue
5063 await env.RESOLUTION_QUEUE.sendBatch(messages);
5164 console.log(`Queued ${messages.length} documents for resolution`);
6565+ }
6666+6767+ // Cleanup: keep only the 300 most recent verified documents, delete everything else
6868+ const deletedVerified = await env.DB.prepare(
6969+ `DELETE FROM resolved_documents WHERE verified = 1 AND uri NOT IN (
7070+ SELECT uri FROM resolved_documents WHERE verified = 1
7171+ ORDER BY published_at DESC LIMIT 300
7272+ )`,
7373+ ).run();
7474+ if (deletedVerified.meta.changes > 0) {
7575+ console.log(`Cleaned up ${deletedVerified.meta.changes} old verified documents`);
7676+ }
7777+7878+ // Delete unverified/stale documents older than 24 hours
7979+ const deletedUnverified = await env.DB.prepare(
8080+ `DELETE FROM resolved_documents WHERE (verified IS NULL OR verified = 0)
8181+ AND resolved_at < datetime('now', '-24 hours')`,
8282+ ).run();
8383+ if (deletedUnverified.meta.changes > 0) {
8484+ console.log(`Cleaned up ${deletedUnverified.meta.changes} unverified documents`);
8585+ }
8686+8787+ // Clean up orphaned repo_records
8888+ if (deletedVerified.meta.changes > 0 || deletedUnverified.meta.changes > 0) {
8989+ const orphaned = await env.DB.prepare(
9090+ `DELETE FROM repo_records WHERE NOT EXISTS (
9191+ SELECT 1 FROM resolved_documents WHERE resolved_documents.did = repo_records.did
9292+ AND resolved_documents.rkey = repo_records.rkey
9393+ )`,
9494+ ).run();
9595+ if (orphaned.meta.changes > 0) {
9696+ console.log(`Cleaned up ${orphaned.meta.changes} orphaned repo_records`);
9797+ }
9898+ }
9999+100100+ // Ensure Jetstream consumer DO is alive
101101+ try {
102102+ const id = env.JETSTREAM_CONSUMER.idFromName("singleton");
103103+ const stub = env.JETSTREAM_CONSUMER.get(id);
104104+ await stub.fetch(new Request("http://do/start"));
105105+ } catch (error) {
106106+ console.error("Failed to ping Jetstream consumer:", error);
52107 }
53108 },
54109 async queue(batch: MessageBatch<any>, env: Bindings) {
+1
packages/server/src/routes/index.ts
···55export { default as records } from "./records";
66export { default as admin } from "./admin";
77export { default as rss } from "./rss";
88+export { default as jetstream } from "./jetstream";