Cursor pagination for the activity feed

Node · Node · advanced · greenfield

Adds cursor-based pagination to the activity feed: fetches limit+1 rows to detect a next page without a count query, returns the page and the next cursor. Typed against the row shape.

Feed is ordered by a monotonic id descending; the client passes back the nextCursor verbatim.

Requirements

Files touched

--- src/feed/paginate.ts
+import { db } from '../lib/db';
+
+interface ActivityRow {
+  id: string;
+  actorId: string;
+  verb: string;
+}
+
+interface Page {
+  items: ActivityRow[];
+  nextCursor: string | null;
+}
+
+export async function activityPage(cursor: string | null, limit: number): Promise<Page> {
+  if (!Number.isInteger(limit) || limit < 1) {
+    throw new RangeError('limit must be a positive integer');
+  }
+  const rows: ActivityRow[] = await db.activity.findAfter(cursor, limit + 1);
+  const hasMore = rows.length > limit;
+  const items = hasMore ? rows.slice(0, limit) : rows;
+  const nextCursor = hasMore ? items[items.length - 1].id : null;
+  return { items, nextCursor };
+}

Review this PR

Node practice