{"version":3,"file":"comments.cjs","sources":["../src/comments/threadstore/ThreadStoreAuth.ts","../src/comments/threadstore/DefaultThreadStoreAuth.ts","../src/comments/threadstore/ThreadStore.ts","../src/comments/threadstore/TipTapThreadStore.ts","../src/comments/threadstore/yjs/yjsHelpers.ts","../src/comments/threadstore/yjs/YjsThreadStoreBase.ts","../src/comments/threadstore/yjs/RESTYjsThreadStore.ts","../src/comments/threadstore/yjs/YjsThreadStore.ts"],"sourcesContent":["import { CommentData, ThreadData } from \"../types.js\";\n\nexport abstract class ThreadStoreAuth {\n  abstract canCreateThread(): boolean;\n  abstract canAddComment(thread: ThreadData): boolean;\n  abstract canUpdateComment(comment: CommentData): boolean;\n  abstract canDeleteComment(comment: CommentData): boolean;\n  abstract canDeleteThread(thread: ThreadData): boolean;\n  abstract canResolveThread(thread: ThreadData): boolean;\n  abstract canUnresolveThread(thread: ThreadData): boolean;\n  abstract canAddReaction(comment: CommentData, emoji?: string): boolean;\n  abstract canDeleteReaction(comment: CommentData, emoji?: string): boolean;\n}\n","import { CommentData, ThreadData } from \"../types.js\";\nimport { ThreadStoreAuth } from \"./ThreadStoreAuth.js\";\n\n/*\n * The DefaultThreadStoreAuth class defines the authorization rules for interacting with comments.\n * We take a role (\"comment\" or \"editor\") and implement the rules.\n *\n * This class is then used in the UI to show / hide specific interactions.\n *\n * Rules:\n * - View-only users should not be able to see any comments\n * - Comment-only users and editors can:\n * - - create new comments / replies / reactions\n * - - edit / delete their own comments / reactions\n * - - resolve / unresolve threads\n * - Editors can also delete any comment or thread\n */\nexport class DefaultThreadStoreAuth extends ThreadStoreAuth {\n  constructor(\n    private readonly userId: string,\n    private readonly role: \"comment\" | \"editor\",\n  ) {\n    super();\n  }\n\n  /**\n   * Auth: should be possible by anyone with comment access\n   */\n  canCreateThread(): boolean {\n    return true;\n  }\n\n  /**\n   * Auth: should be possible by anyone with comment access\n   */\n  canAddComment(_thread: ThreadData): boolean {\n    return true;\n  }\n\n  /**\n   * Auth: should only be possible by the comment author\n   */\n  canUpdateComment(comment: CommentData): boolean {\n    return comment.userId === this.userId;\n  }\n\n  /**\n   * Auth: should be possible by the comment author OR an editor of the document\n   */\n  canDeleteComment(comment: CommentData): boolean {\n    return comment.userId === this.userId || this.role === \"editor\";\n  }\n\n  /**\n   * Auth: should only be possible by an editor of the document\n   */\n  canDeleteThread(_thread: ThreadData): boolean {\n    return this.role === \"editor\";\n  }\n\n  /**\n   * Auth: should be possible by anyone with comment access\n   */\n  canResolveThread(_thread: ThreadData): boolean {\n    return true;\n  }\n\n  /**\n   * Auth: should be possible by anyone with comment access\n   */\n  canUnresolveThread(_thread: ThreadData): boolean {\n    return true;\n  }\n\n  /**\n   * Auth: should be possible by anyone with comment access\n   *\n   * Note: will also check if the user has already reacted with the same emoji. TBD: is that a nice design or should this responsibility be outside of auth?\n   */\n  canAddReaction(comment: CommentData, emoji?: string): boolean {\n    if (!emoji) {\n      return true;\n    }\n\n    return !comment.reactions.some(\n      (reaction) =>\n        reaction.emoji === emoji && reaction.userIds.includes(this.userId),\n    );\n  }\n\n  /**\n   * Auth: should be possible by anyone with comment access\n   *\n   * Note: will also check if the user has already reacted with the same emoji. TBD: is that a nice design or should this responsibility be outside of auth?\n   */\n  canDeleteReaction(comment: CommentData, emoji?: string): boolean {\n    if (!emoji) {\n      return true;\n    }\n\n    return comment.reactions.some(\n      (reaction) =>\n        reaction.emoji === emoji && reaction.userIds.includes(this.userId),\n    );\n  }\n}\n","import { CommentBody, CommentData, ThreadData } from \"../types.js\";\nimport { ThreadStoreAuth } from \"./ThreadStoreAuth.js\";\n\n/**\n * ThreadStore is an abstract class that defines the interface\n * to read / add / update / delete threads and comments.\n */\nexport abstract class ThreadStore {\n  public readonly auth: ThreadStoreAuth;\n\n  constructor(auth: ThreadStoreAuth) {\n    this.auth = auth;\n  }\n\n  /**\n   * A \"thread\" in the ThreadStore only contains information about the content\n   * of the thread / comments. It does not contain information about the position.\n   *\n   * This function can be implemented to store the thread in the document (by creating a mark)\n   * If not implemented, default behavior will apply (creating the mark via TipTap)\n   * See CommentsPlugin.ts for more details.\n   */\n  abstract addThreadToDocument?(options: {\n    threadId: string;\n    selection: {\n      prosemirror: {\n        head: number;\n        anchor: number;\n      };\n      yjs?: {\n        head: any;\n        anchor: any;\n      };\n    };\n  }): Promise<void>;\n\n  /**\n   * Creates a new thread with an initial comment.\n   */\n  abstract createThread(options: {\n    initialComment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    metadata?: any;\n  }): Promise<ThreadData>;\n\n  /**\n   * Adds a comment to a thread.\n   */\n  abstract addComment(options: {\n    comment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    threadId: string;\n  }): Promise<CommentData>;\n\n  /**\n   * Updates a comment in a thread.\n   */\n  abstract updateComment(options: {\n    comment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    threadId: string;\n    commentId: string;\n  }): Promise<void>;\n\n  /**\n   * Deletes a comment from a thread.\n   */\n  abstract deleteComment(options: {\n    threadId: string;\n    commentId: string;\n  }): Promise<void>;\n\n  /**\n   * Deletes a thread.\n   */\n  abstract deleteThread(options: { threadId: string }): Promise<void>;\n\n  /**\n   * Marks a thread as resolved.\n   */\n  abstract resolveThread(options: { threadId: string }): Promise<void>;\n\n  /**\n   * Marks a thread as unresolved.\n   */\n  abstract unresolveThread(options: { threadId: string }): Promise<void>;\n\n  /**\n   * Adds a reaction to a comment.\n   *\n   * Auth: should be possible by anyone with comment access\n   */\n  abstract addReaction(options: {\n    threadId: string;\n    commentId: string;\n    emoji: string;\n  }): Promise<void>;\n\n  /**\n   * Deletes a reaction from a comment.\n   *\n   * Auth: should be possible by the reaction author\n   */\n  abstract deleteReaction(options: {\n    threadId: string;\n    commentId: string;\n    emoji: string;\n  }): Promise<void>;\n\n  /**\n   * Retrieve data for a specific thread.\n   */\n  abstract getThread(threadId: string): ThreadData;\n\n  /**\n   * Retrieve all threads.\n   */\n  abstract getThreads(): Map<string, ThreadData>;\n\n  /**\n   * Subscribe to changes in the thread store.\n   *\n   * @returns a function to unsubscribe from the thread store\n   */\n  abstract subscribe(\n    cb: (threads: Map<string, ThreadData>) => void,\n  ): () => void;\n}\n","import type {\n  TCollabComment,\n  TCollabThread,\n  TiptapCollabProvider,\n} from \"@hocuspocus/provider\";\nimport {\n  CommentBody,\n  CommentData,\n  CommentReactionData,\n  ThreadData,\n} from \"../types.js\";\nimport { ThreadStore } from \"./ThreadStore.js\";\nimport { ThreadStoreAuth } from \"./ThreadStoreAuth.js\";\n\ntype ReactionAsTiptapData = {\n  emoji: string;\n  createdAt: number;\n  userId: string;\n};\n\n/**\n * The `TiptapThreadStore` integrates with Tiptap's collaboration provider for comment management.\n * You can pass a `TiptapCollabProvider` to the constructor which takes care of storing the comments.\n *\n * Under the hood, this actually works similarly to the `YjsThreadStore` implementation. (comments are stored in the Yjs document)\n */\nexport class TiptapThreadStore extends ThreadStore {\n  constructor(\n    private readonly userId: string,\n    private readonly provider: TiptapCollabProvider,\n    auth: ThreadStoreAuth, // TODO: use?\n  ) {\n    super(auth);\n  }\n\n  /**\n   * Creates a new thread with an initial comment.\n   */\n  public async createThread(options: {\n    initialComment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    metadata?: any;\n  }): Promise<ThreadData> {\n    let thread = this.provider.createThread({\n      data: options.metadata,\n    });\n\n    thread = this.provider.addComment(thread.id, {\n      content: options.initialComment.body,\n      data: {\n        metadata: options.initialComment.metadata,\n        userId: this.userId,\n      },\n    });\n\n    return this.tiptapThreadToThreadData(thread);\n  }\n\n  // TipTapThreadStore does not support addThreadToDocument\n  public addThreadToDocument = undefined;\n\n  /**\n   * Adds a comment to a thread.\n   */\n  public async addComment(options: {\n    comment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    threadId: string;\n  }): Promise<CommentBody> {\n    const thread = this.provider.addComment(options.threadId, {\n      content: options.comment.body,\n      data: {\n        metadata: options.comment.metadata,\n        userId: this.userId,\n      },\n    });\n\n    return this.tiptapCommentToCommentData(\n      thread.comments[thread.comments.length - 1],\n    );\n  }\n\n  /**\n   * Updates a comment in a thread.\n   */\n  public async updateComment(options: {\n    comment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    threadId: string;\n    commentId: string;\n  }) {\n    const comment = this.provider.getThreadComment(\n      options.threadId,\n      options.commentId,\n      true,\n    );\n\n    if (!comment) {\n      throw new Error(\"Comment not found\");\n    }\n\n    this.provider.updateComment(options.threadId, options.commentId, {\n      content: options.comment.body,\n      data: {\n        ...comment.data,\n        metadata: options.comment.metadata,\n      },\n    });\n  }\n\n  private tiptapCommentToCommentData(comment: TCollabComment): CommentData {\n    const reactions: CommentReactionData[] = [];\n\n    for (const reaction of (comment.data?.reactions ||\n      []) as ReactionAsTiptapData[]) {\n      const existingReaction = reactions.find(\n        (r) => r.emoji === reaction.emoji,\n      );\n      if (existingReaction) {\n        existingReaction.userIds.push(reaction.userId);\n        existingReaction.createdAt = new Date(\n          Math.min(existingReaction.createdAt.getTime(), reaction.createdAt),\n        );\n      } else {\n        reactions.push({\n          emoji: reaction.emoji,\n          createdAt: new Date(reaction.createdAt),\n          userIds: [reaction.userId],\n        });\n      }\n    }\n\n    return {\n      type: \"comment\",\n      id: comment.id,\n      body: comment.content,\n      metadata: comment.data?.metadata,\n      userId: comment.data?.userId,\n      createdAt: new Date(comment.createdAt),\n      updatedAt: new Date(comment.updatedAt),\n      reactions,\n    };\n  }\n\n  private tiptapThreadToThreadData(thread: TCollabThread): ThreadData {\n    return {\n      type: \"thread\",\n      id: thread.id,\n      comments: thread.comments.map((comment) =>\n        this.tiptapCommentToCommentData(comment),\n      ),\n      resolved: !!thread.resolvedAt,\n      metadata: thread.data?.metadata,\n      createdAt: new Date(thread.createdAt),\n      updatedAt: new Date(thread.updatedAt),\n    };\n  }\n\n  /**\n   * Deletes a comment from a thread.\n   */\n  public async deleteComment(options: { threadId: string; commentId: string }) {\n    this.provider.deleteComment(options.threadId, options.commentId);\n  }\n\n  /**\n   * Deletes a thread.\n   */\n  public async deleteThread(options: { threadId: string }) {\n    this.provider.deleteThread(options.threadId);\n  }\n\n  /**\n   * Marks a thread as resolved.\n   */\n  public async resolveThread(options: { threadId: string }) {\n    this.provider.updateThread(options.threadId, {\n      resolvedAt: new Date().toISOString(),\n    });\n  }\n\n  /**\n   * Marks a thread as unresolved.\n   */\n  public async unresolveThread(options: { threadId: string }) {\n    this.provider.updateThread(options.threadId, {\n      resolvedAt: null,\n    });\n  }\n\n  /**\n   * Adds a reaction to a comment.\n   *\n   * Auth: should be possible by anyone with comment access\n   */\n  public async addReaction(options: {\n    threadId: string;\n    commentId: string;\n    emoji: string;\n  }) {\n    const comment = this.provider.getThreadComment(\n      options.threadId,\n      options.commentId,\n      true,\n    );\n\n    if (!comment) {\n      throw new Error(\"Comment not found\");\n    }\n\n    this.provider.updateComment(options.threadId, options.commentId, {\n      data: {\n        ...comment.data,\n        reactions: [\n          ...((comment.data?.reactions || []) as ReactionAsTiptapData[]),\n          {\n            emoji: options.emoji,\n            createdAt: Date.now(),\n            userId: this.userId,\n          },\n        ],\n      },\n    });\n  }\n\n  /**\n   * Deletes a reaction from a comment.\n   *\n   * Auth: should be possible by the reaction author\n   */\n  public async deleteReaction(options: {\n    threadId: string;\n    commentId: string;\n    emoji: string;\n  }) {\n    const comment = this.provider.getThreadComment(\n      options.threadId,\n      options.commentId,\n      true,\n    );\n\n    if (!comment) {\n      throw new Error(\"Comment not found\");\n    }\n\n    this.provider.updateComment(options.threadId, options.commentId, {\n      data: {\n        ...comment.data,\n        reactions: (\n          (comment.data?.reactions || []) as ReactionAsTiptapData[]\n        ).filter(\n          (reaction) =>\n            reaction.emoji !== options.emoji && reaction.userId !== this.userId,\n        ),\n      },\n    });\n  }\n\n  public getThread(threadId: string): ThreadData {\n    const thread = this.provider.getThread(threadId);\n\n    if (!thread) {\n      throw new Error(\"Thread not found\");\n    }\n\n    return this.tiptapThreadToThreadData(thread);\n  }\n\n  public getThreads(): Map<string, ThreadData> {\n    return new Map(\n      this.provider\n        .getThreads()\n        .map((thread) => [thread.id, this.tiptapThreadToThreadData(thread)]),\n    );\n  }\n\n  public subscribe(cb: (threads: Map<string, ThreadData>) => void): () => void {\n    const newCb = () => {\n      cb(this.getThreads());\n    };\n    this.provider.watchThreads(newCb);\n    return () => {\n      this.provider.unwatchThreads(newCb);\n    };\n  }\n}\n","import * as Y from \"yjs\";\nimport { CommentData, CommentReactionData, ThreadData } from \"../../types.js\";\n\nexport function commentToYMap(comment: CommentData) {\n  const yMap = new Y.Map<any>();\n  yMap.set(\"id\", comment.id);\n  yMap.set(\"userId\", comment.userId);\n  yMap.set(\"createdAt\", comment.createdAt.getTime());\n  yMap.set(\"updatedAt\", comment.updatedAt.getTime());\n  if (comment.deletedAt) {\n    yMap.set(\"deletedAt\", comment.deletedAt.getTime());\n    yMap.set(\"body\", undefined);\n  } else {\n    yMap.set(\"body\", comment.body);\n  }\n  if (comment.reactions.length > 0) {\n    throw new Error(\"Reactions should be empty in commentToYMap\");\n  }\n\n  /**\n   * Reactions are stored in a map keyed by {userId-emoji},\n   * this makes it easy to add / remove reactions and in a way that works local-first.\n   * The cost is that \"reading\" the reactions is a bit more complex (see yMapToReactions).\n   */\n  yMap.set(\"reactionsByUser\", new Y.Map());\n  yMap.set(\"metadata\", comment.metadata);\n\n  return yMap;\n}\n\nexport function threadToYMap(thread: ThreadData) {\n  const yMap = new Y.Map();\n  yMap.set(\"id\", thread.id);\n  yMap.set(\"createdAt\", thread.createdAt.getTime());\n  yMap.set(\"updatedAt\", thread.updatedAt.getTime());\n  const commentsArray = new Y.Array<Y.Map<any>>();\n\n  commentsArray.push(thread.comments.map((comment) => commentToYMap(comment)));\n\n  yMap.set(\"comments\", commentsArray);\n  yMap.set(\"resolved\", thread.resolved);\n  yMap.set(\"resolvedUpdatedAt\", thread.resolvedUpdatedAt?.getTime());\n  yMap.set(\"resolvedBy\", thread.resolvedBy);\n  yMap.set(\"metadata\", thread.metadata);\n  return yMap;\n}\n\ntype SingleUserCommentReactionData = {\n  emoji: string;\n  createdAt: Date;\n  userId: string;\n};\n\nexport function yMapToReaction(\n  yMap: Y.Map<any>,\n): SingleUserCommentReactionData {\n  return {\n    emoji: yMap.get(\"emoji\"),\n    createdAt: new Date(yMap.get(\"createdAt\")),\n    userId: yMap.get(\"userId\"),\n  };\n}\n\nfunction yMapToReactions(yMap: Y.Map<any>): CommentReactionData[] {\n  const flatReactions = [...yMap.values()].map((reaction: Y.Map<any>) =>\n    yMapToReaction(reaction),\n  );\n  // combine reactions by the same emoji\n  return flatReactions.reduce(\n    (acc: CommentReactionData[], reaction: SingleUserCommentReactionData) => {\n      const existingReaction = acc.find((r) => r.emoji === reaction.emoji);\n      if (existingReaction) {\n        existingReaction.userIds.push(reaction.userId);\n        existingReaction.createdAt = new Date(\n          Math.min(\n            existingReaction.createdAt.getTime(),\n            reaction.createdAt.getTime(),\n          ),\n        );\n      } else {\n        acc.push({\n          emoji: reaction.emoji,\n          createdAt: reaction.createdAt,\n          userIds: [reaction.userId],\n        });\n      }\n      return acc;\n    },\n    [] as CommentReactionData[],\n  );\n}\n\nexport function yMapToComment(yMap: Y.Map<any>): CommentData {\n  return {\n    type: \"comment\",\n    id: yMap.get(\"id\"),\n    userId: yMap.get(\"userId\"),\n    createdAt: new Date(yMap.get(\"createdAt\")),\n    updatedAt: new Date(yMap.get(\"updatedAt\")),\n    deletedAt: yMap.get(\"deletedAt\")\n      ? new Date(yMap.get(\"deletedAt\"))\n      : undefined,\n    reactions: yMapToReactions(yMap.get(\"reactionsByUser\")),\n    metadata: yMap.get(\"metadata\"),\n    body: yMap.get(\"body\"),\n  };\n}\n\nexport function yMapToThread(yMap: Y.Map<any>): ThreadData {\n  return {\n    type: \"thread\",\n    id: yMap.get(\"id\"),\n    createdAt: new Date(yMap.get(\"createdAt\")),\n    updatedAt: new Date(yMap.get(\"updatedAt\")),\n    comments: ((yMap.get(\"comments\") as Y.Array<Y.Map<any>>) || []).map(\n      (comment) => yMapToComment(comment),\n    ),\n    resolved: yMap.get(\"resolved\"),\n    resolvedUpdatedAt: new Date(yMap.get(\"resolvedUpdatedAt\")),\n    resolvedBy: yMap.get(\"resolvedBy\"),\n    metadata: yMap.get(\"metadata\"),\n  };\n}\n","import * as Y from \"yjs\";\nimport { ThreadData } from \"../../types.js\";\nimport { ThreadStore } from \"../ThreadStore.js\";\nimport { ThreadStoreAuth } from \"../ThreadStoreAuth.js\";\nimport { yMapToThread } from \"./yjsHelpers.js\";\n\n/**\n * This is an abstract class that only implements the READ methods required by the ThreadStore interface.\n * The data is read from a Yjs Map.\n */\nexport abstract class YjsThreadStoreBase extends ThreadStore {\n  constructor(\n    protected readonly threadsYMap: Y.Map<any>,\n    auth: ThreadStoreAuth,\n  ) {\n    super(auth);\n  }\n\n  // TODO: async / reactive interface?\n  public getThread(threadId: string) {\n    const yThread = this.threadsYMap.get(threadId);\n    if (!yThread) {\n      throw new Error(\"Thread not found\");\n    }\n    const thread = yMapToThread(yThread);\n    return thread;\n  }\n\n  public getThreads(): Map<string, ThreadData> {\n    const threadMap = new Map<string, ThreadData>();\n    this.threadsYMap.forEach((yThread, id) => {\n      threadMap.set(id, yMapToThread(yThread));\n    });\n    return threadMap;\n  }\n\n  public subscribe(cb: (threads: Map<string, ThreadData>) => void) {\n    const observer = () => {\n      cb(this.getThreads());\n    };\n\n    this.threadsYMap.observeDeep(observer);\n\n    return () => {\n      this.threadsYMap.unobserveDeep(observer);\n    };\n  }\n}\n","import * as Y from \"yjs\";\nimport { CommentBody } from \"../../types.js\";\nimport { ThreadStoreAuth } from \"../ThreadStoreAuth.js\";\nimport { YjsThreadStoreBase } from \"./YjsThreadStoreBase.js\";\n\n/**\n * This is a REST-based implementation of the YjsThreadStoreBase.\n * It Reads data directly from the underlying document (same as YjsThreadStore),\n * but for Writes, it sends data to a REST API that should:\n * - check the user has the correct permissions to make the desired changes\n * - apply the updates to the underlying Yjs document\n *\n * (see https://github.com/TypeCellOS/BlockNote-demo-nextjs-hocuspocus)\n *\n * The reason we still use the Yjs document as underlying storage is that it makes it easy to\n * sync updates in real-time to other collaborators.\n * (but technically, you could also implement a different storage altogether\n * and not store the thread related data in the Yjs document)\n */\nexport class RESTYjsThreadStore extends YjsThreadStoreBase {\n  constructor(\n    private readonly BASE_URL: string,\n    private readonly headers: Record<string, string>,\n    threadsYMap: Y.Map<any>,\n    auth: ThreadStoreAuth,\n  ) {\n    super(threadsYMap, auth);\n  }\n\n  private doRequest = async (path: string, method: string, body?: any) => {\n    const response = await fetch(`${this.BASE_URL}${path}`, {\n      method,\n      body: JSON.stringify(body),\n      headers: {\n        \"Content-Type\": \"application/json\",\n        ...this.headers,\n      },\n    });\n\n    if (!response.ok) {\n      throw new Error(`Failed to ${method} ${path}: ${response.statusText}`);\n    }\n\n    return response.json();\n  };\n\n  public addThreadToDocument = async (options: {\n    threadId: string;\n    selection: {\n      prosemirror: {\n        head: number;\n        anchor: number;\n      };\n      yjs: {\n        head: any;\n        anchor: any;\n      };\n    };\n  }) => {\n    const { threadId, ...rest } = options;\n    return this.doRequest(`/${threadId}/addToDocument`, \"POST\", rest);\n  };\n\n  public createThread = async (options: {\n    initialComment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    metadata?: any;\n  }) => {\n    return this.doRequest(\"\", \"POST\", options);\n  };\n\n  public addComment = (options: {\n    comment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    threadId: string;\n  }) => {\n    const { threadId, ...rest } = options;\n    return this.doRequest(`/${threadId}/comments`, \"POST\", rest);\n  };\n\n  public updateComment = (options: {\n    comment: {\n      body: CommentBody;\n      metadata?: any;\n    };\n    threadId: string;\n    commentId: string;\n  }) => {\n    const { threadId, commentId, ...rest } = options;\n    return this.doRequest(`/${threadId}/comments/${commentId}`, \"PUT\", rest);\n  };\n\n  public deleteComment = (options: {\n    threadId: string;\n    commentId: string;\n    softDelete?: boolean;\n  }) => {\n    const { threadId, commentId, ...rest } = options;\n    return this.doRequest(\n      `/${threadId}/comments/${commentId}?soft=${!!rest.softDelete}`,\n      \"DELETE\",\n    );\n  };\n\n  public deleteThread = (options: { threadId: string }) => {\n    return this.doRequest(`/${options.threadId}`, \"DELETE\");\n  };\n\n  public resolveThread = (options: { threadId: string }) => {\n    return this.doRequest(`/${options.threadId}/resolve`, \"POST\");\n  };\n\n  public unresolveThread = (options: { threadId: string }) => {\n    return this.doRequest(`/${options.threadId}/unresolve`, \"POST\");\n  };\n\n  public addReaction = (options: {\n    threadId: string;\n    commentId: string;\n    emoji: string;\n  }) => {\n    const { threadId, commentId, ...rest } = options;\n    return this.doRequest(\n      `/${threadId}/comments/${commentId}/reactions`,\n      \"POST\",\n      rest,\n    );\n  };\n\n  public deleteReaction = (options: {\n    threadId: string;\n    commentId: string;\n    emoji: string;\n  }) => {\n    return this.doRequest(\n      `/${options.threadId}/comments/${options.commentId}/reactions/${options.emoji}`,\n      \"DELETE\",\n    );\n  };\n}\n","import { v4 } from \"uuid\";\nimport * as Y from \"yjs\";\nimport { CommentBody, CommentData, ThreadData } from \"../../types.js\";\nimport { ThreadStoreAuth } from \"../ThreadStoreAuth.js\";\nimport { YjsThreadStoreBase } from \"./YjsThreadStoreBase.js\";\nimport {\n  commentToYMap,\n  threadToYMap,\n  yMapToComment,\n  yMapToThread,\n} from \"./yjsHelpers.js\";\n\n/**\n * This is a Yjs-based implementation of the ThreadStore interface.\n *\n * It reads and writes thread / comments information directly to the underlying Yjs Document.\n *\n * @important While this is the easiest to add to your app, there are two challenges:\n * - The user needs to be able to write to the Yjs document to store the information.\n *   So a user without write access to the Yjs document cannot leave any comments.\n * - Even with write access, the operations are not secure. Unless your Yjs server\n *   guards against malicious operations, it's technically possible for one user to make changes to another user's comments, etc.\n *   (even though these options are not visible in the UI, a malicious user can make unauthorized changes to the underlying Yjs document)\n */\nexport class YjsThreadStore extends YjsThreadStoreBase {\n  constructor(\n    private readonly userId: string,\n    threadsYMap: Y.Map<any>,\n    auth: ThreadStoreAuth,\n  ) {\n    super(threadsYMap, auth);\n  }\n\n  private transact = <T, R>(\n    fn: (options: T) => R,\n  ): ((options: T) => Promise<R>) => {\n    return async (options: T) => {\n      return this.threadsYMap.doc!.transact(() => {\n        return fn(options);\n      });\n    };\n  };\n\n  public createThread = this.transact(\n    (options: {\n      initialComment: {\n        body: CommentBody;\n        metadata?: any;\n      };\n      metadata?: any;\n    }) => {\n      if (!this.auth.canCreateThread()) {\n        throw new Error(\"Not authorized\");\n      }\n\n      const date = new Date();\n\n      const comment: CommentData = {\n        type: \"comment\",\n        id: v4(),\n        userId: this.userId,\n        createdAt: date,\n        updatedAt: date,\n        reactions: [],\n        metadata: options.initialComment.metadata,\n        body: options.initialComment.body,\n      };\n\n      const thread: ThreadData = {\n        type: \"thread\",\n        id: v4(),\n        createdAt: date,\n        updatedAt: date,\n        comments: [comment],\n        resolved: false,\n        metadata: options.metadata,\n      };\n\n      this.threadsYMap.set(thread.id, threadToYMap(thread));\n\n      return thread;\n    },\n  );\n\n  // YjsThreadStore does not support addThreadToDocument\n  public addThreadToDocument = undefined;\n\n  public addComment = this.transact(\n    (options: {\n      comment: {\n        body: CommentBody;\n        metadata?: any;\n      };\n      threadId: string;\n    }) => {\n      const yThread = this.threadsYMap.get(options.threadId);\n      if (!yThread) {\n        throw new Error(\"Thread not found\");\n      }\n\n      if (!this.auth.canAddComment(yMapToThread(yThread))) {\n        throw new Error(\"Not authorized\");\n      }\n\n      const date = new Date();\n      const comment: CommentData = {\n        type: \"comment\",\n        id: v4(),\n        userId: this.userId,\n        createdAt: date,\n        updatedAt: date,\n        deletedAt: undefined,\n        reactions: [],\n        metadata: options.comment.metadata,\n        body: options.comment.body,\n      };\n\n      (yThread.get(\"comments\") as Y.Array<Y.Map<any>>).push([\n        commentToYMap(comment),\n      ]);\n\n      yThread.set(\"updatedAt\", new Date().getTime());\n      return comment;\n    },\n  );\n\n  public updateComment = this.transact(\n    (options: {\n      comment: {\n        body: CommentBody;\n        metadata?: any;\n      };\n      threadId: string;\n      commentId: string;\n    }) => {\n      const yThread = this.threadsYMap.get(options.threadId);\n      if (!yThread) {\n        throw new Error(\"Thread not found\");\n      }\n\n      const yCommentIndex = yArrayFindIndex(\n        yThread.get(\"comments\"),\n        (comment) => comment.get(\"id\") === options.commentId,\n      );\n\n      if (yCommentIndex === -1) {\n        throw new Error(\"Comment not found\");\n      }\n\n      const yComment = yThread.get(\"comments\").get(yCommentIndex);\n\n      if (!this.auth.canUpdateComment(yMapToComment(yComment))) {\n        throw new Error(\"Not authorized\");\n      }\n\n      yComment.set(\"body\", options.comment.body);\n      yComment.set(\"updatedAt\", new Date().getTime());\n      yComment.set(\"metadata\", options.comment.metadata);\n    },\n  );\n\n  public deleteComment = this.transact(\n    (options: {\n      threadId: string;\n      commentId: string;\n      softDelete?: boolean;\n    }) => {\n      const yThread = this.threadsYMap.get(options.threadId);\n      if (!yThread) {\n        throw new Error(\"Thread not found\");\n      }\n\n      const yCommentIndex = yArrayFindIndex(\n        yThread.get(\"comments\"),\n        (comment) => comment.get(\"id\") === options.commentId,\n      );\n\n      if (yCommentIndex === -1) {\n        throw new Error(\"Comment not found\");\n      }\n\n      const yComment = yThread.get(\"comments\").get(yCommentIndex);\n\n      if (!this.auth.canDeleteComment(yMapToComment(yComment))) {\n        throw new Error(\"Not authorized\");\n      }\n\n      if (yComment.get(\"deletedAt\")) {\n        throw new Error(\"Comment already deleted\");\n      }\n\n      if (options.softDelete) {\n        yComment.set(\"deletedAt\", new Date().getTime());\n        yComment.set(\"body\", undefined);\n      } else {\n        yThread.get(\"comments\").delete(yCommentIndex);\n      }\n\n      if (\n        (yThread.get(\"comments\") as Y.Array<any>)\n          .toArray()\n          .every((comment) => comment.get(\"deletedAt\"))\n      ) {\n        // all comments deleted\n        if (options.softDelete) {\n          yThread.set(\"deletedAt\", new Date().getTime());\n        } else {\n          this.threadsYMap.delete(options.threadId);\n        }\n      }\n\n      yThread.set(\"updatedAt\", new Date().getTime());\n    },\n  );\n\n  public deleteThread = this.transact((options: { threadId: string }) => {\n    if (\n      !this.auth.canDeleteThread(\n        yMapToThread(this.threadsYMap.get(options.threadId)),\n      )\n    ) {\n      throw new Error(\"Not authorized\");\n    }\n\n    this.threadsYMap.delete(options.threadId);\n  });\n\n  public resolveThread = this.transact((options: { threadId: string }) => {\n    const yThread = this.threadsYMap.get(options.threadId);\n    if (!yThread) {\n      throw new Error(\"Thread not found\");\n    }\n\n    if (!this.auth.canResolveThread(yMapToThread(yThread))) {\n      throw new Error(\"Not authorized\");\n    }\n\n    yThread.set(\"resolved\", true);\n    yThread.set(\"resolvedUpdatedAt\", new Date().getTime());\n    yThread.set(\"resolvedBy\", this.userId);\n  });\n\n  public unresolveThread = this.transact((options: { threadId: string }) => {\n    const yThread = this.threadsYMap.get(options.threadId);\n    if (!yThread) {\n      throw new Error(\"Thread not found\");\n    }\n\n    if (!this.auth.canUnresolveThread(yMapToThread(yThread))) {\n      throw new Error(\"Not authorized\");\n    }\n\n    yThread.set(\"resolved\", false);\n    yThread.set(\"resolvedUpdatedAt\", new Date().getTime());\n  });\n\n  public addReaction = this.transact(\n    (options: { threadId: string; commentId: string; emoji: string }) => {\n      const yThread = this.threadsYMap.get(options.threadId);\n      if (!yThread) {\n        throw new Error(\"Thread not found\");\n      }\n\n      const yCommentIndex = yArrayFindIndex(\n        yThread.get(\"comments\"),\n        (comment) => comment.get(\"id\") === options.commentId,\n      );\n\n      if (yCommentIndex === -1) {\n        throw new Error(\"Comment not found\");\n      }\n\n      const yComment = yThread.get(\"comments\").get(yCommentIndex);\n\n      if (!this.auth.canAddReaction(yMapToComment(yComment), options.emoji)) {\n        throw new Error(\"Not authorized\");\n      }\n\n      const date = new Date();\n\n      const key = `${this.userId}-${options.emoji}`;\n\n      const reactionsByUser = yComment.get(\"reactionsByUser\");\n\n      if (reactionsByUser.has(key)) {\n        // already exists\n        return;\n      } else {\n        const reaction = new Y.Map();\n        reaction.set(\"emoji\", options.emoji);\n        reaction.set(\"createdAt\", date.getTime());\n        reaction.set(\"userId\", this.userId);\n        reactionsByUser.set(key, reaction);\n      }\n    },\n  );\n\n  public deleteReaction = this.transact(\n    (options: { threadId: string; commentId: string; emoji: string }) => {\n      const yThread = this.threadsYMap.get(options.threadId);\n      if (!yThread) {\n        throw new Error(\"Thread not found\");\n      }\n\n      const yCommentIndex = yArrayFindIndex(\n        yThread.get(\"comments\"),\n        (comment) => comment.get(\"id\") === options.commentId,\n      );\n\n      if (yCommentIndex === -1) {\n        throw new Error(\"Comment not found\");\n      }\n\n      const yComment = yThread.get(\"comments\").get(yCommentIndex);\n\n      if (\n        !this.auth.canDeleteReaction(yMapToComment(yComment), options.emoji)\n      ) {\n        throw new Error(\"Not authorized\");\n      }\n\n      const key = `${this.userId}-${options.emoji}`;\n\n      const reactionsByUser = yComment.get(\"reactionsByUser\");\n\n      reactionsByUser.delete(key);\n    },\n  );\n}\n\nfunction yArrayFindIndex(\n  yArray: Y.Array<any>,\n  predicate: (item: any) => boolean,\n) {\n  for (let i = 0; i < yArray.length; i++) {\n    if (predicate(yArray.get(i))) {\n      return i;\n    }\n  }\n  return -1;\n}\n"],"names":["ThreadStoreAuth","DefaultThreadStoreAuth","userId","role","_thread","comment","emoji","reaction","ThreadStore","auth","__publicField","TiptapThreadStore","provider","options","thread","reactions","_a","existingReaction","r","_b","_c","threadId","cb","newCb","commentToYMap","yMap","Y","threadToYMap","commentsArray","yMapToReaction","yMapToReactions","acc","yMapToComment","yMapToThread","YjsThreadStoreBase","threadsYMap","yThread","threadMap","id","observer","RESTYjsThreadStore","BASE_URL","headers","path","method","body","response","rest","commentId","YjsThreadStore","fn","date","v4","yCommentIndex","yArrayFindIndex","yComment","key","reactionsByUser","yArray","predicate","i"],"mappings":"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"}