"use client" // The project's notes, live (umbrella TS6.4 and TS6.6): the page's view renders the first page and hands it // over as the seed, so the page arrives complete; this keeps it current through the organization's live stream // -- a note another member adds, renames or deletes appears without a reload. The rows come from // `notes.note.getMany`, under the same permission as the list, so the stream itself never carries a note's // contents. import type { ProjectSlugs } from "@conusai-kit/ui" import { liveCollection, useDataClient, useLive } from "@conusai-kit/ui/data" // Its live sync stops when no live query reads it any more (TanStack DB's collection GC). import { useState } from "react" import { NOTE_COLLECTION, type NoteView } from "../contract/index.js" export function useLiveNotes(slugs: ProjectSlugs, seed: readonly NoteView[]): readonly NoteView[] { const client = useDataClient() // One collection for the life of the page: a page of another project mounts its own, and the seed is the // first render's. const [notes] = useState(() => liveCollection({ client, org: slugs.org, topic: { ws: slugs.workspace, project: slugs.project }, entity: NOTE_COLLECTION.entity, key: NOTE_COLLECTION.key, version: "version", seed, list: { procedure: NOTE_COLLECTION.list, input: { ...slugs }, rows: (out) => (out as { notes: NoteView[] }).notes, }, getMany: { procedure: NOTE_COLLECTION.getMany, input: { ...slugs }, rows: (out) => (out as { items: NoteView[] }).items, }, }), ) // Newest first, as the list procedure orders them, through the query operators (umbrella ยง7.2). const { data, isReady } = useLive(notes, (q, rows) => q.from({ note: rows }).orderBy(({ note }: { note: NoteView }) => note.createdAt, "desc"), ) // Until the collection is ready the server's rows are the answer, so the first paint matches it. return isReady ? data : seed }