← Files WixARCHIVED FILE

skills/wix-headless-templates/blog/rest/comments.ts

3.64 KB · Oct 8, 2026 · 12:02 UTC

↓ Download file

See the change to this file →

// Post comments over REST — the twin of app/wix/blog/comments.ts. Same exports, same DTOs; the
// rules and mappers come from comments-core (the SAME file the SDK transport uses, deployed flat
// next to this one). Every call runs as the calling identity — in a port, the viewer's session
// token, never a process-wide one (a create would be attributed to whoever that token is).
// docs: https://dev.wix.com/docs/api-reference/crm/community/comments/comments/list-comments-by-resource.md
// docs: https://dev.wix.com/docs/api-reference/crm/community/comments/comments/create-comment.md
// docs: https://dev.wix.com/docs/api-reference/crm/community/comments/comments/delete-comment.md
import { wixRequest } from "./client.js";
import { fetchAuthorsByIds } from "./authors.js";
import {
  commentAuthorIds,
  createCommentBody,
  listCommentsParams,
  listRepliesParams,
  rawCommentsOf,
  toComment,
  toCommentPage,
  toCommentThread,
  type CreateCommentOptions,
  type ListCommentsOptions,
} from "./comments-core.js";
import type { Raw } from "./posts-core.js";
import type { BlogComment, CommentPage, CommentThread } from "./types.js";

export { type CreateCommentOptions, type ListCommentsOptions };

const COMMENTS = "/comments/v1/comments";

/**
 * One page of top-level comments plus each one's reply seam (cursor, no replies yet).
 * GET /comments/v1/comments/list-by-resource?appId=&contextId=&resourceId=&commentSort.order=&replySort.order=OLDEST_FIRST&cursorPaging.limit=10&cursorPaging.repliesLimit=0[&cursorPaging.cursor=]
 */
export async function fetchComments(o: ListCommentsOptions & { currentMemberId?: string | null }): Promise<CommentPage> {
  const res = await wixRequest<Raw>(`${COMMENTS}/list-by-resource`, { method: "GET", query: listCommentsParams(o) });
  const authors = await fetchAuthorsByIds(commentAuthorIds(rawCommentsOf(res)));
  return toCommentPage(res, { authors, currentMemberId: o.currentMemberId ?? null });
}

/**
 * One page of a top-level comment's replies, from the cursor its seam (or a previous page) handed back.
 * GET /comments/v1/comments/list-by-resource?appId=&contextId=&resourceId=&replySort.order=OLDEST_FIRST&cursorPaging.limit=10&cursorPaging.cursor=
 */
export async function fetchReplies(o: { referenceId: string; topLevelId: string; cursor: string; currentMemberId?: string | null }): Promise<CommentThread> {
  const res = await wixRequest<Raw>(`${COMMENTS}/list-by-resource`, { method: "GET", query: listRepliesParams(o) });
  const authors = await fetchAuthorsByIds(commentAuthorIds(rawCommentsOf(res)));
  return toCommentThread(res, { authors, currentMemberId: o.currentMemberId ?? null, topLevelId: o.topLevelId });
}

/**
 * Post a comment (or a reply, with `parentId`) as the current identity. Throws a WixApiError —
 * isPermissionDenied(e) means this viewer may not comment here (sign in).
 * POST /comments/v1/comments  { comment: { appId, contextId, resourceId, content: { richContent }, parentComment?: { id } } }
 */
export async function createComment(o: CreateCommentOptions & { topLevelId?: string | null; currentMemberId?: string | null }): Promise<BlogComment> {
  const res = await wixRequest<Raw>(COMMENTS, { body: createCommentBody(o) });
  const raw: Raw = res?.comment ?? {};
  const authors = await fetchAuthorsByIds(commentAuthorIds([raw]));
  return toComment(raw, { authors, currentMemberId: o.currentMemberId ?? null, topLevelId: o.topLevelId ?? o.parentId ?? null });
}

/** Delete the current member's own comment.  DELETE /comments/v1/comments/{commentId} */
export async function deleteComment(commentId: string): Promise<void> {
  await wixRequest(`${COMMENTS}/${encodeURIComponent(commentId)}`, { method: "DELETE" });
}

SHA-256: e661255614d2f6df9433d4e143ef2d7bb5b55889237bb1ec7415c03df5371f45