SeuraaEdge
Docs/Use Cases
Use Cases

Add rooms, messages, and typing events to your product.

Build Chat

Use chat to combine channel subscription with narrowly scoped browser publishing.

Model The Channel

Use one private or presence channel per conversation:

ts
const channelName = `presence:conversation:${conversation.id}`;

Use a presence:* channel when the UI needs membership updates. Use a private:* channel when it only needs messages.

Authorize The User

Grant subscribe plus the browser publish permissions used by the UI:

ts
export async function POST(request: Request) {
  const user = await requireUser(request);
  const { channel } = await request.json();
  const conversationId = channel.replace("presence:conversation:", "");

  if (!(await canAccessConversation(user.id, conversationId))) {
    return Response.json({ error: "Forbidden" }, { status: 403 });
  }

  const session = edge.auth.signIn({
    channel,
    expiresInSeconds: 60,
    permissions: [
      "subscribe",
      "publish:message.created",
      "publish:typing.started",
      "publish:typing.stopped",
    ],
    userId: user.id,
  });

  return Response.json({ token: session.token });
}

The token above allows the browser to publish only message.created, typing.started, and typing.stopped.

Subscribe To Messages

ts
const channel = edge.channel(`presence:conversation:${conversationId}`);

channel.subscribe<{
  id: string;
  authorId: string;
  body: string;
  createdAt: string;
}>("message.created", (event) => {
  appendMessage(event.data);
});

If messages are persisted by your backend first, publish message.created from the backend after the write succeeds.

Publish User Input

The browser can publish directly when the token grants the event name:

ts
await channel.publish("message.created", {
  id: crypto.randomUUID(),
  authorId: currentUser.id,
  body: draft,
  createdAt: new Date().toISOString(),
});

To validate and persist messages before delivery, send the message to your backend first:

ts
await fetch(`/api/conversations/${conversationId}/messages`, {
  method: "POST",
  body: JSON.stringify({ body: draft }),
});

Then publish from trusted backend code:

ts
await edge.channels.publish(
  `presence:conversation:${conversation.id}`,
  "message.created",
  {
    id: message.id,
    authorId: message.authorId,
    body: message.body,
    createdAt: message.createdAt,
  },
  { clientEventId: message.id },
);

Add Typing Indicators

ts
await channel.publish("typing.started", {
  conversationId,
});

await channel.publish("typing.stopped", {
  conversationId,
});

Generate This With AI

Use this prompt to generate a complete TanStack Start app that demonstrates the flow end to end.

text
Build a complete TanStack Start app that demonstrates realtime chat with Seuraa Edge.

Use @seuraa/edge in the browser and @seuraa/edge-node only in trusted backend code.

Implement:
- A minimal chat UI with a signed-in demo user, a conversation view, a message list, a composer, and typing indicators.
- A conversation channel named `presence:conversation:${conversationId}`.
- A TanStack Start API route at /api/edge/token.
- The endpoint must use a small mock requireUser() helper, accept { channel }, extract conversationId from `presence:conversation:${conversationId}`, and check that the user can access that conversation.
- The endpoint must sign a short-lived channel token locally with permissions ["subscribe", "publish:message.created", "publish:typing.started", "publish:typing.stopped"].
- Do not call Edge to mint channel tokens. The backend SDK signs locally with SEURAA_APP_SECRET.
- A browser chat component that subscribes to "message.created" and appends messages.
- A send-message action that publishes "message.created" from the browser.
- A second backend route that demonstrates the persisted-message pattern: POST the draft to the backend, create a message object, then publish "message.created" from trusted backend code.
- Typing indicators that publish "typing.started" and "typing.stopped" from the browser.
- Call channel.unsubscribe() when the conversation view unmounts.
- Loading, connected, and error states in the UI.
- A .env.example file and short README instructions for running the app.

Use these environment variables:
- SEURAA_APP_KEY
- SEURAA_APP_SECRET

Do not expose SEURAA_APP_SECRET to browser code.