Browse the docs

Examples

Guestbook example

An intentionally shared feed where authorship comes from ctx.auth and author names are stored as snapshots.

bunx @revnu/fuast new my-guestbook --template guestbook

A shared feed. Everyone who can open the app reads the same entries, and guests and accounts can both post.

What it shows

  • An entries table with body, authorId: userId(), and authorName and authorPicture snapshots.
  • A shared entries query: the newest 50 by by_creation, with no owner filter on purpose.
  • A sign mutation that cleans and bounds input and takes authorship from ctx.auth, never from the client.
  • A removeEntry mutation that lets authors delete only their own entries.
  • Live updates: a post in one tab appears in every other tab.

Server pattern

Shared reads are a query without an owner filter:

entries: query(async (ctx) => ctx.db.entries.withIndex("by_creation").order("desc").take(50))

Writes stay server-authoritative:

const author = ctx.auth.requireIdentity();
await ctx.db.entries.insert({
  body,
  authorId: author.userId,
  authorName: author.displayName,
  ...(author.picture ? { authorPicture: author.picture } : {})
});

Never accept authorId, authorName, or authorPicture as arguments.

Sharing comes from the query, not from a fake shared user. When a guest signs in, authorId moves to their account, so they can still remove their entries. authorName and authorPicture are snapshots from the moment of posting and do not change.

The entries tool description warns agents that entries were written by other people. Text in a shared feed can try to steer an agent that reads it.

Variations

  • Accounts only: call ctx.auth.requireSignedIn() in sign.
  • No guests anywhere: set auth: { requireSignIn: true }.
  • Longer history: switch entries to paginate() and the client to client.usePaginatedQuery("entries", {}, { initialNumItems: 20 }). See pagination.

Try it

bunx @revnu/fuast dev

Post from ?fuast_user=alice and ?fuast_user=bob in two tabs, and from ?fuast_guest=1. Deploy and share publicly with bunx @revnu/fuast share --visibility public.