@hamzasaleemorg/convex-comments 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +4 -0
- package/dist/client/index.d.ts +153 -37
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +153 -42
- package/dist/client/index.js.map +1 -1
- package/package.json +4 -1
- package/src/client/index.ts +153 -42
package/src/client/index.ts
CHANGED
|
@@ -82,10 +82,15 @@ interface MentionCallbacks {
|
|
|
82
82
|
*
|
|
83
83
|
* Usage:
|
|
84
84
|
* ```ts
|
|
85
|
-
* import { Comments } from "@
|
|
85
|
+
* import { Comments } from "@hamzasaleemorg/convex-comments";
|
|
86
86
|
* import { components } from "./_generated/api";
|
|
87
87
|
*
|
|
88
|
-
* const comments = new Comments(components.comments
|
|
88
|
+
* const comments = new Comments(components.comments, {
|
|
89
|
+
* onMention: async ({ mentionedUserId, authorId, body }) => {
|
|
90
|
+
* // Send email or push notification to the mentioned user
|
|
91
|
+
* console.log(`${authorId} mentioned ${mentionedUserId}: ${body}`);
|
|
92
|
+
* }
|
|
93
|
+
* });
|
|
89
94
|
*
|
|
90
95
|
* // In a mutation/query handler:
|
|
91
96
|
* const zoneId = await comments.getOrCreateZone(ctx, { entityId: "doc_123" });
|
|
@@ -103,7 +108,18 @@ export class Comments {
|
|
|
103
108
|
// ==========================================================================
|
|
104
109
|
|
|
105
110
|
/**
|
|
106
|
-
* Get or create a
|
|
111
|
+
* Get or create a "Zone" for a specific entity.
|
|
112
|
+
*
|
|
113
|
+
* A Zone is the top-level container for all threads and messages related to a specific
|
|
114
|
+
* resource in your app (e.g., a specific document ID, a task ID, or a project page).
|
|
115
|
+
*
|
|
116
|
+
* This method uses a "get or create" pattern, making it ideal for lazy-initializing
|
|
117
|
+
* the comment system for an entity the first time a user interacts with it.
|
|
118
|
+
*
|
|
119
|
+
* @param ctx - The mutation context (requires runMutation)
|
|
120
|
+
* @param args.entityId - A unique string identifying your resource (e.g., "doc_123")
|
|
121
|
+
* @param args.metadata - Optional arbitrary data to store with the zone
|
|
122
|
+
* @returns The unique ID of the zone
|
|
107
123
|
*/
|
|
108
124
|
async getOrCreateZone(
|
|
109
125
|
ctx: MutationCtx,
|
|
@@ -113,21 +129,33 @@ export class Comments {
|
|
|
113
129
|
}
|
|
114
130
|
|
|
115
131
|
/**
|
|
116
|
-
*
|
|
132
|
+
* Retrieves an existing zone by its entity ID.
|
|
133
|
+
*
|
|
134
|
+
* Unlike `getOrCreateZone`, this will return `null` if the zone doesn't exist yet.
|
|
135
|
+
* Use this when you want to check if an entity has any comments without creating a container.
|
|
136
|
+
*
|
|
137
|
+
* @param ctx - The query context
|
|
138
|
+
* @param args.entityId - The unique resource identifier
|
|
117
139
|
*/
|
|
118
140
|
async getZone(ctx: QueryCtx, args: { entityId: string }) {
|
|
119
141
|
return await ctx.runQuery(this.component.lib.getZone, args);
|
|
120
142
|
}
|
|
121
143
|
|
|
122
144
|
/**
|
|
123
|
-
*
|
|
145
|
+
* Retrieves a zone by its internal Convex ID.
|
|
146
|
+
*
|
|
147
|
+
* Useful when you already have a `zoneId` (e.g., from a thread reference) and
|
|
148
|
+
* need to fetch its associated metadata or entity identifier.
|
|
124
149
|
*/
|
|
125
150
|
async getZoneById(ctx: QueryCtx, args: { zoneId: string }) {
|
|
126
151
|
return await ctx.runQuery(this.component.lib.getZoneById, { zoneId: args.zoneId });
|
|
127
152
|
}
|
|
128
153
|
|
|
129
154
|
/**
|
|
130
|
-
*
|
|
155
|
+
* Permanently deletes a zone and every thread, message, and reaction within it.
|
|
156
|
+
*
|
|
157
|
+
* This is a destructive operation often used when the parent resource
|
|
158
|
+
* (e.g., a document) is being deleted from your system.
|
|
131
159
|
*/
|
|
132
160
|
async deleteZone(ctx: MutationCtx, args: { zoneId: string }) {
|
|
133
161
|
return await ctx.runMutation(this.component.lib.deleteZone, { zoneId: args.zoneId });
|
|
@@ -138,7 +166,14 @@ export class Comments {
|
|
|
138
166
|
// ==========================================================================
|
|
139
167
|
|
|
140
168
|
/**
|
|
141
|
-
*
|
|
169
|
+
* Creates a new conversation thread within a specific zone.
|
|
170
|
+
*
|
|
171
|
+
* Threads act as a grouping for related messages. They support "positioned"
|
|
172
|
+
* comments (e.g., pins on a PDF or coordinates on a canvas) via the `position` argument.
|
|
173
|
+
*
|
|
174
|
+
* @param args.zoneId - The ID of the zone to contain this thread
|
|
175
|
+
* @param args.position - Optional coordinates {x, y} and an anchor point for UI placement
|
|
176
|
+
* @param args.metadata - Optional data (e.g., the specific version of a document)
|
|
142
177
|
*/
|
|
143
178
|
async addThread(
|
|
144
179
|
ctx: MutationCtx,
|
|
@@ -156,14 +191,19 @@ export class Comments {
|
|
|
156
191
|
}
|
|
157
192
|
|
|
158
193
|
/**
|
|
159
|
-
*
|
|
194
|
+
* Retrieves full details for a specific thread, including its position and resolution status.
|
|
160
195
|
*/
|
|
161
196
|
async getThread(ctx: QueryCtx, args: { threadId: string }) {
|
|
162
197
|
return await ctx.runQuery(this.component.lib.getThread, { threadId: args.threadId });
|
|
163
198
|
}
|
|
164
199
|
|
|
165
200
|
/**
|
|
166
|
-
*
|
|
201
|
+
* Lists threads within a zone, typically used for a "Sidebar" or "Activity" view.
|
|
202
|
+
*
|
|
203
|
+
* Supports pagination and filtering by resolution status.
|
|
204
|
+
*
|
|
205
|
+
* @param args.includeResolved - If true, returns both open and resolved threads. Defaults to false.
|
|
206
|
+
* @param args.limit - Maximum number of threads to return in one page.
|
|
167
207
|
*/
|
|
168
208
|
async getThreads(
|
|
169
209
|
ctx: QueryCtx,
|
|
@@ -183,7 +223,11 @@ export class Comments {
|
|
|
183
223
|
}
|
|
184
224
|
|
|
185
225
|
/**
|
|
186
|
-
*
|
|
226
|
+
* Marks a thread as resolved.
|
|
227
|
+
*
|
|
228
|
+
* Resolved threads are effectively "closed" and are hidden from the default `getThreads` view.
|
|
229
|
+
*
|
|
230
|
+
* @param args.userId - The ID of the user who resolved the thread.
|
|
187
231
|
*/
|
|
188
232
|
async resolveThread(
|
|
189
233
|
ctx: MutationCtx,
|
|
@@ -193,14 +237,16 @@ export class Comments {
|
|
|
193
237
|
}
|
|
194
238
|
|
|
195
239
|
/**
|
|
196
|
-
*
|
|
240
|
+
* Re-opens a previously resolved thread.
|
|
197
241
|
*/
|
|
198
242
|
async unresolveThread(ctx: MutationCtx, args: { threadId: string }) {
|
|
199
243
|
return await ctx.runMutation(this.component.lib.unresolveThread, args);
|
|
200
244
|
}
|
|
201
245
|
|
|
202
246
|
/**
|
|
203
|
-
*
|
|
247
|
+
* Updates the visual position of a thread.
|
|
248
|
+
*
|
|
249
|
+
* Useful for "draggable" comment pins or when the underlying content changes layout.
|
|
204
250
|
*/
|
|
205
251
|
async updateThreadPosition(
|
|
206
252
|
ctx: MutationCtx,
|
|
@@ -213,7 +259,7 @@ export class Comments {
|
|
|
213
259
|
}
|
|
214
260
|
|
|
215
261
|
/**
|
|
216
|
-
*
|
|
262
|
+
* Permanently deletes a thread and all its messages.
|
|
217
263
|
*/
|
|
218
264
|
async deleteThread(ctx: MutationCtx, args: { threadId: string }) {
|
|
219
265
|
return await ctx.runMutation(this.component.lib.deleteThread, { threadId: args.threadId });
|
|
@@ -224,8 +270,16 @@ export class Comments {
|
|
|
224
270
|
// ==========================================================================
|
|
225
271
|
|
|
226
272
|
/**
|
|
227
|
-
*
|
|
228
|
-
*
|
|
273
|
+
* Adds a new comment (message) to a thread.
|
|
274
|
+
*
|
|
275
|
+
* This method automatically parses the body for `@user` mentions and URLs.
|
|
276
|
+
* If the `Comments` client was initialized with callbacks, `onNewMessage` and
|
|
277
|
+
* `onMention` will be triggered automatically.
|
|
278
|
+
*
|
|
279
|
+
* @param args.authorId - The ID of the user sending the comment
|
|
280
|
+
* @param args.body - The text content (supports markdown)
|
|
281
|
+
* @param args.attachments - Optional array of file/url attachments
|
|
282
|
+
* @returns The generated message ID and the list of detected mentions/links
|
|
229
283
|
*/
|
|
230
284
|
async addComment(
|
|
231
285
|
ctx: MutationCtx,
|
|
@@ -269,7 +323,10 @@ export class Comments {
|
|
|
269
323
|
}
|
|
270
324
|
|
|
271
325
|
/**
|
|
272
|
-
*
|
|
326
|
+
* Fetches a specific message, including its reaction and resolution status.
|
|
327
|
+
*
|
|
328
|
+
* @param args.currentUserId - Optional. If provided, the response will include
|
|
329
|
+
* `includesMe` flags for reactions.
|
|
273
330
|
*/
|
|
274
331
|
async getMessage(
|
|
275
332
|
ctx: QueryCtx,
|
|
@@ -279,7 +336,12 @@ export class Comments {
|
|
|
279
336
|
}
|
|
280
337
|
|
|
281
338
|
/**
|
|
282
|
-
*
|
|
339
|
+
* Retrieves a paginated list of messages for a thread.
|
|
340
|
+
*
|
|
341
|
+
* Typically used to populate the main comment list for a conversation.
|
|
342
|
+
*
|
|
343
|
+
* @param args.order - "asc" for chronological (chat style) or "desc" for newest first.
|
|
344
|
+
* @param args.includeDeleted - If true, includes placeholders for deleted messages.
|
|
283
345
|
*/
|
|
284
346
|
async getMessages(
|
|
285
347
|
ctx: QueryCtx,
|
|
@@ -296,7 +358,9 @@ export class Comments {
|
|
|
296
358
|
}
|
|
297
359
|
|
|
298
360
|
/**
|
|
299
|
-
*
|
|
361
|
+
* Edits the content of an existing message.
|
|
362
|
+
*
|
|
363
|
+
* The message will be marked as `isEdited: true`.
|
|
300
364
|
*/
|
|
301
365
|
async editMessage(
|
|
302
366
|
ctx: MutationCtx,
|
|
@@ -306,7 +370,9 @@ export class Comments {
|
|
|
306
370
|
}
|
|
307
371
|
|
|
308
372
|
/**
|
|
309
|
-
* Soft
|
|
373
|
+
* Soft-deletes a message.
|
|
374
|
+
*
|
|
375
|
+
* The message record remains but its `body` is cleared and `isDeleted` is set to true.
|
|
310
376
|
*/
|
|
311
377
|
async deleteMessage(
|
|
312
378
|
ctx: MutationCtx,
|
|
@@ -320,7 +386,7 @@ export class Comments {
|
|
|
320
386
|
// ==========================================================================
|
|
321
387
|
|
|
322
388
|
/**
|
|
323
|
-
*
|
|
389
|
+
* Adds an emoji reaction to a message for a specific user.
|
|
324
390
|
*/
|
|
325
391
|
async addReaction(
|
|
326
392
|
ctx: MutationCtx,
|
|
@@ -330,7 +396,7 @@ export class Comments {
|
|
|
330
396
|
}
|
|
331
397
|
|
|
332
398
|
/**
|
|
333
|
-
*
|
|
399
|
+
* Removes an emoji reaction from a message.
|
|
334
400
|
*/
|
|
335
401
|
async removeReaction(
|
|
336
402
|
ctx: MutationCtx,
|
|
@@ -340,7 +406,8 @@ export class Comments {
|
|
|
340
406
|
}
|
|
341
407
|
|
|
342
408
|
/**
|
|
343
|
-
*
|
|
409
|
+
* Toggles a reaction. If the user already reacted with this emoji,
|
|
410
|
+
* it removes it; otherwise, it adds it.
|
|
344
411
|
*/
|
|
345
412
|
async toggleReaction(
|
|
346
413
|
ctx: MutationCtx,
|
|
@@ -350,7 +417,7 @@ export class Comments {
|
|
|
350
417
|
}
|
|
351
418
|
|
|
352
419
|
/**
|
|
353
|
-
*
|
|
420
|
+
* Retrieves a summary of all reactions for a message.
|
|
354
421
|
*/
|
|
355
422
|
async getReactions(
|
|
356
423
|
ctx: QueryCtx,
|
|
@@ -364,7 +431,17 @@ export class Comments {
|
|
|
364
431
|
// ==========================================================================
|
|
365
432
|
|
|
366
433
|
/**
|
|
367
|
-
*
|
|
434
|
+
* Updates the "isTyping" status for a user in a specific thread.
|
|
435
|
+
*
|
|
436
|
+
* This is used to drive real-time typing indicators in your UI. The typing status
|
|
437
|
+
* automatically expires after a short period (typically 5-10 seconds of inactivity).
|
|
438
|
+
*
|
|
439
|
+
* For the best user experience, call this whenever the user types a character
|
|
440
|
+
* (debounced) or when the input field loses focus.
|
|
441
|
+
*
|
|
442
|
+
* @param args.threadId - Internal ID of the thread
|
|
443
|
+
* @param args.userId - The ID of the user who is typing
|
|
444
|
+
* @param args.isTyping - true to show as typing, false to immediately clear
|
|
368
445
|
*/
|
|
369
446
|
async setIsTyping(
|
|
370
447
|
ctx: MutationCtx,
|
|
@@ -374,7 +451,12 @@ export class Comments {
|
|
|
374
451
|
}
|
|
375
452
|
|
|
376
453
|
/**
|
|
377
|
-
*
|
|
454
|
+
* Returns a list of user IDs currently typing in a thread.
|
|
455
|
+
*
|
|
456
|
+
* Use this in a reactive query to show "User A, User B are typing..." in your UI.
|
|
457
|
+
*
|
|
458
|
+
* @param args.excludeUserId - Optional. Exclude the current user from the list to avoid
|
|
459
|
+
* showing an "I am typing" indicator to yourself.
|
|
378
460
|
*/
|
|
379
461
|
async getTypingUsers(
|
|
380
462
|
ctx: QueryCtx,
|
|
@@ -384,14 +466,23 @@ export class Comments {
|
|
|
384
466
|
}
|
|
385
467
|
|
|
386
468
|
/**
|
|
387
|
-
*
|
|
469
|
+
* Immediately clears all typing indicators for a specific user across all threads.
|
|
470
|
+
*
|
|
471
|
+
* Useful to call when a user logs out or closes their browser tab to ensure
|
|
472
|
+
* typing indicators don't linger for the timeout duration.
|
|
388
473
|
*/
|
|
389
474
|
async clearUserTyping(ctx: MutationCtx, args: { userId: string }) {
|
|
390
475
|
return await ctx.runMutation(this.component.lib.clearUserTyping, args);
|
|
391
476
|
}
|
|
392
477
|
|
|
393
478
|
/**
|
|
394
|
-
*
|
|
479
|
+
* Resolves an individual message.
|
|
480
|
+
*
|
|
481
|
+
* While `resolveThread` marks an entire conversation as closed, `resolveMessage`
|
|
482
|
+
* is useful for "task-style" comments where each message might represent a
|
|
483
|
+
* specific action item that can be checked off.
|
|
484
|
+
*
|
|
485
|
+
* @param args.userId - The ID of the user who resolved the message.
|
|
395
486
|
*/
|
|
396
487
|
async resolveMessage(
|
|
397
488
|
ctx: MutationCtx,
|
|
@@ -401,7 +492,7 @@ export class Comments {
|
|
|
401
492
|
}
|
|
402
493
|
|
|
403
494
|
/**
|
|
404
|
-
*
|
|
495
|
+
* Re-opens a previously resolved message.
|
|
405
496
|
*/
|
|
406
497
|
async unresolveMessage(ctx: MutationCtx, args: { messageId: string }) {
|
|
407
498
|
return await ctx.runMutation(this.component.lib.unresolveMessage, args);
|
|
@@ -421,19 +512,24 @@ export class Comments {
|
|
|
421
512
|
* Usage:
|
|
422
513
|
* ```ts
|
|
423
514
|
* // In convex/comments.ts
|
|
424
|
-
* import { exposeApi } from "@
|
|
515
|
+
* import { exposeApi } from "@hamzasaleemorg/convex-comments";
|
|
425
516
|
* import { components } from "./_generated/api";
|
|
426
517
|
*
|
|
427
|
-
* export const { getThreads, addComment, toggleReaction } = exposeApi(
|
|
518
|
+
* export const { getThreads, addComment, toggleReaction, setIsTyping } = exposeApi(
|
|
428
519
|
* components.comments,
|
|
429
520
|
* {
|
|
430
521
|
* auth: async (ctx, operation) => {
|
|
431
|
-
* const
|
|
432
|
-
* if (!
|
|
522
|
+
* const identity = await ctx.auth.getUserIdentity();
|
|
523
|
+
* if (!identity && operation.type !== "read") {
|
|
433
524
|
* throw new Error("Authentication required");
|
|
434
525
|
* }
|
|
435
|
-
* return
|
|
526
|
+
* return identity?.subject ?? "anonymous";
|
|
436
527
|
* },
|
|
528
|
+
* callbacks: {
|
|
529
|
+
* onMention: async ({ mentionedUserId }) => {
|
|
530
|
+
* // Handle notification logic here
|
|
531
|
+
* }
|
|
532
|
+
* }
|
|
437
533
|
* }
|
|
438
534
|
* );
|
|
439
535
|
* ```
|
|
@@ -448,7 +544,7 @@ export function exposeApi(
|
|
|
448
544
|
}
|
|
449
545
|
) {
|
|
450
546
|
return {
|
|
451
|
-
|
|
547
|
+
/** Initialize or fetch a zone for an entity. Access: create/admin. */
|
|
452
548
|
getOrCreateZone: mutationGeneric({
|
|
453
549
|
args: { entityId: v.string(), metadata: v.optional(v.any()) },
|
|
454
550
|
handler: async (ctx, args) => {
|
|
@@ -457,6 +553,7 @@ export function exposeApi(
|
|
|
457
553
|
},
|
|
458
554
|
}),
|
|
459
555
|
|
|
556
|
+
/** Get zone by entity ID. Access: read. */
|
|
460
557
|
getZone: queryGeneric({
|
|
461
558
|
args: { entityId: v.string() },
|
|
462
559
|
handler: async (ctx, args) => {
|
|
@@ -465,7 +562,7 @@ export function exposeApi(
|
|
|
465
562
|
},
|
|
466
563
|
}),
|
|
467
564
|
|
|
468
|
-
|
|
565
|
+
/** Start a new thread. Access: create/write. */
|
|
469
566
|
addThread: mutationGeneric({
|
|
470
567
|
args: {
|
|
471
568
|
zoneId: v.string(),
|
|
@@ -488,6 +585,7 @@ export function exposeApi(
|
|
|
488
585
|
},
|
|
489
586
|
}),
|
|
490
587
|
|
|
588
|
+
/** Fetch single thread details. Access: read. */
|
|
491
589
|
getThread: queryGeneric({
|
|
492
590
|
args: { threadId: v.string() },
|
|
493
591
|
handler: async (ctx, args) => {
|
|
@@ -496,6 +594,7 @@ export function exposeApi(
|
|
|
496
594
|
},
|
|
497
595
|
}),
|
|
498
596
|
|
|
597
|
+
/** List threads in a zone. Access: read. */
|
|
499
598
|
getThreads: queryGeneric({
|
|
500
599
|
args: {
|
|
501
600
|
zoneId: v.string(),
|
|
@@ -514,6 +613,7 @@ export function exposeApi(
|
|
|
514
613
|
},
|
|
515
614
|
}),
|
|
516
615
|
|
|
616
|
+
/** Close a thread. Access: update/owner. */
|
|
517
617
|
resolveThread: mutationGeneric({
|
|
518
618
|
args: { threadId: v.string() },
|
|
519
619
|
handler: async (ctx, args) => {
|
|
@@ -525,6 +625,7 @@ export function exposeApi(
|
|
|
525
625
|
},
|
|
526
626
|
}),
|
|
527
627
|
|
|
628
|
+
/** Re-open a thread. Access: update/owner. */
|
|
528
629
|
unresolveThread: mutationGeneric({
|
|
529
630
|
args: { threadId: v.string() },
|
|
530
631
|
handler: async (ctx, args) => {
|
|
@@ -533,7 +634,7 @@ export function exposeApi(
|
|
|
533
634
|
},
|
|
534
635
|
}),
|
|
535
636
|
|
|
536
|
-
|
|
637
|
+
/** Post a new comment. Access: write. Mentions are parsed automatically. */
|
|
537
638
|
addComment: mutationGeneric({
|
|
538
639
|
args: {
|
|
539
640
|
threadId: v.string(),
|
|
@@ -585,6 +686,7 @@ export function exposeApi(
|
|
|
585
686
|
},
|
|
586
687
|
}),
|
|
587
688
|
|
|
689
|
+
/** Fetch single message. Access: read. */
|
|
588
690
|
getMessage: queryGeneric({
|
|
589
691
|
args: { messageId: v.string() },
|
|
590
692
|
handler: async (ctx, args) => {
|
|
@@ -596,6 +698,7 @@ export function exposeApi(
|
|
|
596
698
|
},
|
|
597
699
|
}),
|
|
598
700
|
|
|
701
|
+
/** Fetch conversation history. Access: read. */
|
|
599
702
|
getMessages: queryGeneric({
|
|
600
703
|
args: {
|
|
601
704
|
threadId: v.string(),
|
|
@@ -617,6 +720,7 @@ export function exposeApi(
|
|
|
617
720
|
},
|
|
618
721
|
}),
|
|
619
722
|
|
|
723
|
+
/** Update message content. Access: update/owner. */
|
|
620
724
|
editMessage: mutationGeneric({
|
|
621
725
|
args: { messageId: v.string(), body: v.string() },
|
|
622
726
|
handler: async (ctx, args) => {
|
|
@@ -629,6 +733,7 @@ export function exposeApi(
|
|
|
629
733
|
},
|
|
630
734
|
}),
|
|
631
735
|
|
|
736
|
+
/** Soft-delete message. Access: delete/owner. */
|
|
632
737
|
deleteMessage: mutationGeneric({
|
|
633
738
|
args: { messageId: v.string() },
|
|
634
739
|
handler: async (ctx, args) => {
|
|
@@ -640,7 +745,7 @@ export function exposeApi(
|
|
|
640
745
|
},
|
|
641
746
|
}),
|
|
642
747
|
|
|
643
|
-
|
|
748
|
+
/** Add/remove reaction. Access: react. */
|
|
644
749
|
toggleReaction: mutationGeneric({
|
|
645
750
|
args: { messageId: v.string(), emoji: v.string() },
|
|
646
751
|
handler: async (ctx, args) => {
|
|
@@ -653,6 +758,7 @@ export function exposeApi(
|
|
|
653
758
|
},
|
|
654
759
|
}),
|
|
655
760
|
|
|
761
|
+
/** List reactions for message. Access: read. */
|
|
656
762
|
getReactions: queryGeneric({
|
|
657
763
|
args: { messageId: v.string() },
|
|
658
764
|
handler: async (ctx, args) => {
|
|
@@ -664,7 +770,7 @@ export function exposeApi(
|
|
|
664
770
|
},
|
|
665
771
|
}),
|
|
666
772
|
|
|
667
|
-
|
|
773
|
+
/** Signal typing intent. Access: write. Indicators expire automatically. */
|
|
668
774
|
setIsTyping: mutationGeneric({
|
|
669
775
|
args: { threadId: v.string(), isTyping: v.boolean() },
|
|
670
776
|
handler: async (ctx, args) => {
|
|
@@ -677,6 +783,7 @@ export function exposeApi(
|
|
|
677
783
|
},
|
|
678
784
|
}),
|
|
679
785
|
|
|
786
|
+
/** List current typists. Access: read. */
|
|
680
787
|
getTypingUsers: queryGeneric({
|
|
681
788
|
args: { threadId: v.string() },
|
|
682
789
|
handler: async (ctx, args) => {
|
|
@@ -698,18 +805,22 @@ export function exposeApi(
|
|
|
698
805
|
* Register HTTP routes for the Comments component.
|
|
699
806
|
*
|
|
700
807
|
* Provides REST-like endpoints for the comments API:
|
|
701
|
-
* - GET /comments/zones
|
|
702
|
-
* - GET /comments/threads
|
|
703
|
-
* - GET /comments/messages
|
|
808
|
+
* - GET /comments/zones?entityId=...
|
|
809
|
+
* - GET /comments/threads?zoneId=...
|
|
810
|
+
* - GET /comments/messages?threadId=...
|
|
704
811
|
*
|
|
705
812
|
* Usage:
|
|
706
813
|
* ```ts
|
|
707
814
|
* // In convex/http.ts
|
|
708
|
-
* import {
|
|
815
|
+
* import { httpRouter } from "convex/server";
|
|
816
|
+
* import { registerRoutes } from "@hamzasaleemorg/convex-comments";
|
|
709
817
|
* import { components } from "./_generated/api";
|
|
710
818
|
*
|
|
711
819
|
* const http = httpRouter();
|
|
820
|
+
*
|
|
821
|
+
* // Mount the comments API at /api/comments/*
|
|
712
822
|
* registerRoutes(http, components.comments, { pathPrefix: "/api/comments" });
|
|
823
|
+
*
|
|
713
824
|
* export default http;
|
|
714
825
|
* ```
|
|
715
826
|
*/
|