Skip to content

Comments

Comments are an open contract. Templatical Cloud implements it, the same way your own backend would.

ts
const editor = await initCloud({ container: '#editor', auth: { url: '/api/token' } });

Nothing to configure. Cloud supplies the provider and the identity, and the header's Comments button appears as soon as a template is saved.

The adapter

MethodCloud
listEvery thread for the template, each with its replies
createStores a comment or a reply, signed with the token's user claim
updateEdits a comment's body
deleteRemoves a comment, and a root's replies with it
setResolvedMarks a thread resolved or reopened
subscribeBinds Cloud's realtime channel, so a colleague's comment appears as they write it

All four mutations are enabled: comment storage and its realtime fan-out are what the commenting plan feature pays for, so there is no Cloud tier that can read a thread but not reply to it.

Availability

Three conditions, and none implies another:

  • comments: false switches the feature off entirely.
  • The commenting plan feature must be granted.
  • The template must be saved. Cloud anchors a comment server-side, so there has to be a stored template to anchor it to — the Comments button does not render before the first save.
js
const editor = await initCloud({
  container: '#editor',
  auth: { url: '/api/templatical/token' },
  comments: false, // off, whatever the plan grants
});

Author identity

Cloud sends user_id / user_name / user_signature with every write, taken from the auth token's user claim and verified by its backend. So initCloud() accepts no user key: it fills init({ user }) from that same claim, and a browser-supplied identity could only disagree with the one the server trusts.

A project whose token endpoint omits the user claim gets no comments feature at all — unavailable, never anonymous.

Bringing your own

Configuration and events, inside initCloud() — never storage.

A comment is keyed to a template id Cloud issued, and its author is signed by Cloud's token, so initCloud()'s comments key takes CommentsOptionsonCreated, onUpdated, onDeleted, onResolved and onUnresolved — rather than a full provider:

ts
await initCloud({
  container: '#editor',
  auth: { url: '/api/token' },
  comments: {
    onCreated: (comment, { origin }) => {},
    onResolved: (comment) => {},
    onUnresolved: (comment) => {},
  },
});

Passing a full provider is fine: list, create, update, delete, setResolved and subscribe are ignored with a console warning naming them, while onCreated, onUpdated, onDeleted, onResolved and onUnresolved reach the editor regardless. An OSS comments provider moving to Cloud needs no change — leave the key exactly as it is.

Bring your own storage with init(), where the whole set — templates, version history, comments, rendering — is yours.

Headless use

useComments and useCommentListener live in @templatical/core and take a provider. Cloud's adapter is createCloudCommentsProvider from @templatical/core/cloud:

ts
import { useComments, useCommentListener } from '@templatical/core';
import { createCloudCommentsProvider } from '@templatical/core/cloud';

const provider = createCloudCommentsProvider({
  authManager,
  channel,                                 // Ref<PresenceChannel | null>
  getSocketId: () => websocket.getSocketId(),
});

const comments = useComments({
  provider,
  getTemplateId: () => templateId,
  getUser: () => ({ id: authManager.userConfig.id, name: authManager.userConfig.name }),
});

useCommentListener({ comments, provider, getTemplateId: () => templateId });

See the comments guide for the full reactive surface.