Comments
import { Aside } from ‘@astrojs/starlight/components’;
Comentarios anidados en tiempo real, asociados a un artifact o a cualquier contexto
dentro de él. Accedé vía sdk.comments.
Métodos
Sección titulada «Métodos»// CRUDadd(options: { content: string; contextId?: string; parentId?: string; authorName?: string; position?: CommentPosition; state?: unknown; mentions?: string[];}): Promise<Comment>
reply(parentId: string, content: string, authorName?: string): Promise<Comment>edit(id: string, content: string): Promise<Comment>delete(id: string): Promise<boolean>findById(id: string): Promise<Comment | null>getReplies(parentId: string): Promise<Comment[]>getThread(rootId: string): Promise<CommentThread>
// Configuración (solo owner)getConfig(): Promise<CommentsConfig>setConfig(config: Partial<CommentsConfig>): Promise<CommentsConfig>
// Tiempo realsubscribe(handler: (event: CommentEvent) => void): () => voidsubscribeToContext(contextId: string, handler: (event: CommentEvent) => void): () => voiddisconnect(): void
// State bridge (comentarios anclados)onCaptureState(fn: () => unknown | Promise<unknown>): voidonRestoreState(fn: (state: unknown) => void | Promise<void>): voidQuery builder
Sección titulada «Query builder»find(filter?: { contextId?: string; parentId?: string | null }): CommentsQuery
query.context(contextId: string): CommentsQueryquery.topLevel(): CommentsQueryquery.sort(field: 'createdAt' | 'updatedAt', order: 'asc' | 'desc'): CommentsQueryquery.limit(n: number): CommentsQueryquery.skip(n: number): CommentsQueryquery.exec(): Promise<Comment[]>interface Comment { id: string; contextId: string | null; parentId: string | null; authorId: string | null; authorName: string; content: string; createdAt: string; updatedAt: string; resolved?: boolean; resolvedBy?: string | null; resolvedAt?: string | null; position?: CommentPosition | null; state?: unknown | null; mentions?: string[]; // Campos de action item (presentes si está asignado) assigneeUserId?: string | null; assigneeEmail?: string | null; dueAt?: string | null;}
interface CommentsConfig { enabled: boolean; identityMode: 'anonymous' | 'named' | 'authenticated'; allowReplies: boolean; maxDepth: number; overlayEnabled?: boolean;}
interface CommentEvent { type: 'comment:added' | 'comment:updated' | 'comment:deleted' | 'comment:resolved'; comment: Comment;}
interface CommentThread { comment: Comment; replies: CommentThread[];}
interface CommentPosition { selector?: string; relX?: number; relY?: number; pctX?: number; pctY?: number; scrollY?: number;}Ejemplos
Sección titulada «Ejemplos»// Configurar (solo owner)await sdk.comments.setConfig({ enabled: true, identityMode: 'named', allowReplies: true, maxDepth: 3,});
// Agregar un comentario anclado a un slideconst comment = await sdk.comments.add({ content: '¡Buen gráfico!', contextId: 'slide-5', authorName: 'Alice',});
// Responderawait sdk.comments.reply(comment.id, '¡Gracias!', 'Bob');
// Consultar comentarios de primer nivel para un contextoconst comments = await sdk.comments .find({ contextId: 'slide-5' }) .topLevel() .sort('createdAt', 'desc') .limit(50) .exec();
// Obtener el hilo completo anidadoconst thread = await sdk.comments.getThread(comment.id);
// Actualizaciones en tiempo realconst unsub = sdk.comments.subscribeToContext('slide-5', (event) => { if (event.type === 'comment:added') renderComment(event.comment);});// Más tarde:unsub();State bridge
Sección titulada «State bridge»Los comentarios anclados pueden capturar y restaurar el estado de la app (p. ej., filtros activos de un dashboard). Registrá los callbacks antes de agregar comentarios:
sdk.comments.onCaptureState(() => ({ filters: currentFilters, activeTab,}));
sdk.comments.onRestoreState((state) => { currentFilters = state.filters; activeTab = state.activeTab;});Al agregar un comentario se almacena el estado actual. Al abrir un comentario anclado se
reproduce el estado vía onRestoreState.
Action items
Sección titulada «Action items»Cualquier comentario puede convertirse en un action item asignándolo a un miembro o colaborador del workspace. El asignado recibe un email (y un mensaje de Telegram si tiene la cuenta vinculada). Al resolver el comentario, el solicitante recibe una notificación y puede reabrirlo con un clic.
En el viewer del artifact: abrí el panel de comentarios → botón Assign → elegí una persona y, opcionalmente, una fecha límite.
Vía API:
# Asignar al crearPOST /v1/data/{artifactId}/comments{ "content": "Corregir el eje Y", "assignee": "alice@example.com", "dueAt": "2025-08-01T00:00:00Z" }
# Asignar o desasignar un comentario existentePATCH /v1/data/{artifactId}/comments/{id}/assign{ "assignee": "alice@example.com", "dueAt": "2025-08-01T00:00:00Z" }
# DesasignarPATCH /v1/data/{artifactId}/comments/{id}/assign{ "assignee": null }El assignee debe estar en el conjunto de personas del artifact (miembros del workspace
- colaboradores); las direcciones desconocidas devuelven
400 ASSIGNEE_NOT_FOUND.
Seguimiento: todos ven sus action items abiertos en la campana de notificaciones del Home — ordenados por fecha límite, los vencidos resaltados, con botones Hecho y Reabrir inline.
Filtrar por asignado:
GET /v1/data/{artifactId}/comments?assignee=meGET /v1/data/{artifactId}/comments?assignee=alice@example.comHerramientas de crew IA: action_item_create, action_item_list.
Toolbar del viewer (UI integrada)
Sección titulada «Toolbar del viewer (UI integrada)»Con comentarios habilitados en una página, los viewers logueados ven una toolbar flotante:
| Función | Notas |
|---|---|
| Badge de no leídos | Se actualiza por WebSocket antes de abrir el panel |
| Filtros Abiertos / Resueltos | Cambiá la vista del hilo |
| Reacciones | 👍 ❤️ ✅ 🎉 👀 en cualquier comentario |
| Indicadores de escritura | Ves cuando alguien está escribiendo |
| Presencia | ”N otros acá” en el encabezado (canal de comments, no analytics de página) |
| Resolver / Reabrir | Marcá hilos como hechos sin borrarlos |
Owners y colaboradores también gestionan hilos desde la pestaña Comments del Inspector del workspace.