@hamzasaleemorg/convex-comments 1.0.0

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.
Files changed (114) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +201 -0
  3. package/README.md +581 -0
  4. package/dist/client/_generated/_ignore.d.ts +1 -0
  5. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  6. package/dist/client/_generated/_ignore.js +3 -0
  7. package/dist/client/_generated/_ignore.js.map +1 -0
  8. package/dist/client/index.d.ts +745 -0
  9. package/dist/client/index.d.ts.map +1 -0
  10. package/dist/client/index.js +579 -0
  11. package/dist/client/index.js.map +1 -0
  12. package/dist/component/_generated/api.d.ts +44 -0
  13. package/dist/component/_generated/api.d.ts.map +1 -0
  14. package/dist/component/_generated/api.js +31 -0
  15. package/dist/component/_generated/api.js.map +1 -0
  16. package/dist/component/_generated/component.d.ts +673 -0
  17. package/dist/component/_generated/component.d.ts.map +1 -0
  18. package/dist/component/_generated/component.js +11 -0
  19. package/dist/component/_generated/component.js.map +1 -0
  20. package/dist/component/_generated/dataModel.d.ts +46 -0
  21. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  22. package/dist/component/_generated/dataModel.js +11 -0
  23. package/dist/component/_generated/dataModel.js.map +1 -0
  24. package/dist/component/_generated/server.d.ts +121 -0
  25. package/dist/component/_generated/server.d.ts.map +1 -0
  26. package/dist/component/_generated/server.js +78 -0
  27. package/dist/component/_generated/server.js.map +1 -0
  28. package/dist/component/convex.config.d.ts +3 -0
  29. package/dist/component/convex.config.d.ts.map +1 -0
  30. package/dist/component/convex.config.js +3 -0
  31. package/dist/component/convex.config.js.map +1 -0
  32. package/dist/component/lib.d.ts +17 -0
  33. package/dist/component/lib.d.ts.map +1 -0
  34. package/dist/component/lib.js +18 -0
  35. package/dist/component/lib.js.map +1 -0
  36. package/dist/component/messages.d.ts +173 -0
  37. package/dist/component/messages.d.ts.map +1 -0
  38. package/dist/component/messages.js +410 -0
  39. package/dist/component/messages.js.map +1 -0
  40. package/dist/component/reactions.d.ts +51 -0
  41. package/dist/component/reactions.d.ts.map +1 -0
  42. package/dist/component/reactions.js +191 -0
  43. package/dist/component/reactions.js.map +1 -0
  44. package/dist/component/schema.d.ts +274 -0
  45. package/dist/component/schema.d.ts.map +1 -0
  46. package/dist/component/schema.js +159 -0
  47. package/dist/component/schema.js.map +1 -0
  48. package/dist/component/threads.d.ts +110 -0
  49. package/dist/component/threads.d.ts.map +1 -0
  50. package/dist/component/threads.js +276 -0
  51. package/dist/component/threads.js.map +1 -0
  52. package/dist/component/typing.d.ts +31 -0
  53. package/dist/component/typing.d.ts.map +1 -0
  54. package/dist/component/typing.js +147 -0
  55. package/dist/component/typing.js.map +1 -0
  56. package/dist/component/zones.d.ts +63 -0
  57. package/dist/component/zones.d.ts.map +1 -0
  58. package/dist/component/zones.js +159 -0
  59. package/dist/component/zones.js.map +1 -0
  60. package/dist/react/AddComment.d.ts +57 -0
  61. package/dist/react/AddComment.d.ts.map +1 -0
  62. package/dist/react/AddComment.js +285 -0
  63. package/dist/react/AddComment.js.map +1 -0
  64. package/dist/react/Comment.d.ts +70 -0
  65. package/dist/react/Comment.d.ts.map +1 -0
  66. package/dist/react/Comment.js +259 -0
  67. package/dist/react/Comment.js.map +1 -0
  68. package/dist/react/Comments.d.ts +74 -0
  69. package/dist/react/Comments.d.ts.map +1 -0
  70. package/dist/react/Comments.js +108 -0
  71. package/dist/react/Comments.js.map +1 -0
  72. package/dist/react/CommentsProvider.d.ts +104 -0
  73. package/dist/react/CommentsProvider.d.ts.map +1 -0
  74. package/dist/react/CommentsProvider.js +98 -0
  75. package/dist/react/CommentsProvider.js.map +1 -0
  76. package/dist/react/ReactionPicker.d.ts +28 -0
  77. package/dist/react/ReactionPicker.d.ts.map +1 -0
  78. package/dist/react/ReactionPicker.js +56 -0
  79. package/dist/react/ReactionPicker.js.map +1 -0
  80. package/dist/react/Thread.d.ts +84 -0
  81. package/dist/react/Thread.d.ts.map +1 -0
  82. package/dist/react/Thread.js +124 -0
  83. package/dist/react/Thread.js.map +1 -0
  84. package/dist/react/TypingIndicator.d.ts +25 -0
  85. package/dist/react/TypingIndicator.d.ts.map +1 -0
  86. package/dist/react/TypingIndicator.js +99 -0
  87. package/dist/react/TypingIndicator.js.map +1 -0
  88. package/dist/react/index.d.ts +15 -0
  89. package/dist/react/index.d.ts.map +1 -0
  90. package/dist/react/index.js +15 -0
  91. package/dist/react/index.js.map +1 -0
  92. package/package.json +106 -0
  93. package/src/client/_generated/_ignore.ts +1 -0
  94. package/src/client/index.ts +813 -0
  95. package/src/component/_generated/api.ts +60 -0
  96. package/src/component/_generated/component.ts +784 -0
  97. package/src/component/_generated/dataModel.ts +60 -0
  98. package/src/component/_generated/server.ts +156 -0
  99. package/src/component/convex.config.ts +3 -0
  100. package/src/component/lib.ts +57 -0
  101. package/src/component/messages.ts +476 -0
  102. package/src/component/reactions.ts +222 -0
  103. package/src/component/schema.ts +169 -0
  104. package/src/component/threads.ts +319 -0
  105. package/src/component/typing.ts +168 -0
  106. package/src/component/zones.ts +180 -0
  107. package/src/react/AddComment.tsx +463 -0
  108. package/src/react/Comment.tsx +519 -0
  109. package/src/react/Comments.tsx +276 -0
  110. package/src/react/CommentsProvider.tsx +197 -0
  111. package/src/react/ReactionPicker.tsx +95 -0
  112. package/src/react/Thread.tsx +336 -0
  113. package/src/react/TypingIndicator.tsx +144 -0
  114. package/src/react/index.ts +45 -0
@@ -0,0 +1,276 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server.js";
3
+ // ============================================================================
4
+ // Thread Validators
5
+ // ============================================================================
6
+ const positionValidator = v.object({
7
+ x: v.number(),
8
+ y: v.number(),
9
+ anchor: v.optional(v.string()),
10
+ });
11
+ const threadValidator = v.object({
12
+ _id: v.id("threads"),
13
+ _creationTime: v.number(),
14
+ zoneId: v.id("zones"),
15
+ resolved: v.boolean(),
16
+ resolvedBy: v.optional(v.string()),
17
+ resolvedAt: v.optional(v.number()),
18
+ createdAt: v.number(),
19
+ lastActivityAt: v.number(),
20
+ position: v.optional(positionValidator),
21
+ metadata: v.optional(v.any()),
22
+ });
23
+ const messagePreviewValidator = v.object({
24
+ _id: v.id("messages"),
25
+ body: v.string(),
26
+ authorId: v.string(),
27
+ createdAt: v.number(),
28
+ });
29
+ const threadWithPreviewValidator = v.object({
30
+ thread: threadValidator,
31
+ firstMessage: v.union(v.null(), messagePreviewValidator),
32
+ messageCount: v.number(),
33
+ });
34
+ // ============================================================================
35
+ // Thread Functions
36
+ // ============================================================================
37
+ /**
38
+ * Create a new thread in a zone.
39
+ */
40
+ export const addThread = mutation({
41
+ args: {
42
+ zoneId: v.id("zones"),
43
+ position: v.optional(positionValidator),
44
+ metadata: v.optional(v.any()),
45
+ },
46
+ returns: v.id("threads"),
47
+ handler: async (ctx, args) => {
48
+ // Verify zone exists
49
+ const zone = await ctx.db.get(args.zoneId);
50
+ if (!zone) {
51
+ throw new Error(`Zone ${args.zoneId} not found`);
52
+ }
53
+ const now = Date.now();
54
+ const threadId = await ctx.db.insert("threads", {
55
+ zoneId: args.zoneId,
56
+ resolved: false,
57
+ createdAt: now,
58
+ lastActivityAt: now,
59
+ position: args.position,
60
+ metadata: args.metadata,
61
+ });
62
+ return threadId;
63
+ },
64
+ });
65
+ /**
66
+ * Get a thread by ID.
67
+ */
68
+ export const getThread = query({
69
+ args: {
70
+ threadId: v.id("threads"),
71
+ },
72
+ returns: v.union(v.null(), threadValidator),
73
+ handler: async (ctx, args) => {
74
+ return await ctx.db.get(args.threadId);
75
+ },
76
+ });
77
+ /**
78
+ * Get all threads in a zone with optional pagination and filtering.
79
+ */
80
+ export const getThreads = query({
81
+ args: {
82
+ zoneId: v.id("zones"),
83
+ limit: v.optional(v.number()),
84
+ includeResolved: v.optional(v.boolean()),
85
+ cursor: v.optional(v.string()),
86
+ },
87
+ returns: v.object({
88
+ threads: v.array(threadWithPreviewValidator),
89
+ nextCursor: v.optional(v.string()),
90
+ hasMore: v.boolean(),
91
+ }),
92
+ handler: async (ctx, args) => {
93
+ const limit = args.limit ?? 50;
94
+ const includeResolved = args.includeResolved ?? true;
95
+ // Build query
96
+ let query = ctx.db
97
+ .query("threads")
98
+ .withIndex("zoneId_lastActivity", (q) => q.eq("zoneId", args.zoneId))
99
+ .order("desc");
100
+ // Apply cursor if provided
101
+ if (args.cursor) {
102
+ // Cursor is the lastActivityAt timestamp
103
+ const cursorTime = parseInt(args.cursor, 10);
104
+ query = ctx.db
105
+ .query("threads")
106
+ .withIndex("zoneId_lastActivity", (q) => q.eq("zoneId", args.zoneId).lt("lastActivityAt", cursorTime))
107
+ .order("desc");
108
+ }
109
+ // Fetch one extra to check if there are more
110
+ const threads = await query.take(limit + 1);
111
+ // Filter by resolved status if needed
112
+ const filteredThreads = includeResolved
113
+ ? threads
114
+ : threads.filter((t) => !t.resolved);
115
+ const hasMore = filteredThreads.length > limit;
116
+ const resultThreads = filteredThreads.slice(0, limit);
117
+ // Get first message preview and count for each thread
118
+ const threadsWithPreviews = await Promise.all(resultThreads.map(async (thread) => {
119
+ const messages = await ctx.db
120
+ .query("messages")
121
+ .withIndex("threadId_createdAt", (q) => q.eq("threadId", thread._id))
122
+ .order("asc")
123
+ .take(1);
124
+ const firstMessage = messages[0] ?? null;
125
+ // Get message count
126
+ const allMessages = await ctx.db
127
+ .query("messages")
128
+ .withIndex("threadId", (q) => q.eq("threadId", thread._id))
129
+ .collect();
130
+ const messageCount = allMessages.filter((m) => !m.isDeleted).length;
131
+ return {
132
+ thread,
133
+ firstMessage: firstMessage
134
+ ? {
135
+ _id: firstMessage._id,
136
+ body: firstMessage.body,
137
+ authorId: firstMessage.authorId,
138
+ createdAt: firstMessage.createdAt,
139
+ }
140
+ : null,
141
+ messageCount,
142
+ };
143
+ }));
144
+ // Generate next cursor
145
+ const lastThread = resultThreads[resultThreads.length - 1];
146
+ const nextCursor = hasMore && lastThread
147
+ ? lastThread.lastActivityAt.toString()
148
+ : undefined;
149
+ return {
150
+ threads: threadsWithPreviews,
151
+ nextCursor,
152
+ hasMore,
153
+ };
154
+ },
155
+ });
156
+ /**
157
+ * Resolve a thread.
158
+ */
159
+ export const resolveThread = mutation({
160
+ args: {
161
+ threadId: v.id("threads"),
162
+ userId: v.string(),
163
+ },
164
+ returns: v.null(),
165
+ handler: async (ctx, args) => {
166
+ const thread = await ctx.db.get(args.threadId);
167
+ if (!thread) {
168
+ throw new Error(`Thread ${args.threadId} not found`);
169
+ }
170
+ await ctx.db.patch(args.threadId, {
171
+ resolved: true,
172
+ resolvedBy: args.userId,
173
+ resolvedAt: Date.now(),
174
+ });
175
+ return null;
176
+ },
177
+ });
178
+ /**
179
+ * Unresolve a thread.
180
+ */
181
+ export const unresolveThread = mutation({
182
+ args: {
183
+ threadId: v.id("threads"),
184
+ },
185
+ returns: v.null(),
186
+ handler: async (ctx, args) => {
187
+ const thread = await ctx.db.get(args.threadId);
188
+ if (!thread) {
189
+ throw new Error(`Thread ${args.threadId} not found`);
190
+ }
191
+ await ctx.db.patch(args.threadId, {
192
+ resolved: false,
193
+ resolvedBy: undefined,
194
+ resolvedAt: undefined,
195
+ });
196
+ return null;
197
+ },
198
+ });
199
+ /**
200
+ * Update thread position (for positioned comments).
201
+ */
202
+ export const updateThreadPosition = mutation({
203
+ args: {
204
+ threadId: v.id("threads"),
205
+ position: v.optional(positionValidator),
206
+ },
207
+ returns: v.null(),
208
+ handler: async (ctx, args) => {
209
+ await ctx.db.patch(args.threadId, {
210
+ position: args.position,
211
+ });
212
+ return null;
213
+ },
214
+ });
215
+ /**
216
+ * Delete a thread and all its messages.
217
+ */
218
+ export const deleteThread = mutation({
219
+ args: {
220
+ threadId: v.id("threads"),
221
+ },
222
+ returns: v.object({
223
+ deletedMessages: v.number(),
224
+ deletedReactions: v.number(),
225
+ }),
226
+ handler: async (ctx, args) => {
227
+ let deletedMessages = 0;
228
+ let deletedReactions = 0;
229
+ // Get all messages in this thread
230
+ const messages = await ctx.db
231
+ .query("messages")
232
+ .withIndex("threadId", (q) => q.eq("threadId", args.threadId))
233
+ .collect();
234
+ for (const message of messages) {
235
+ // Delete reactions on this message
236
+ const reactions = await ctx.db
237
+ .query("reactions")
238
+ .withIndex("messageId", (q) => q.eq("messageId", message._id))
239
+ .collect();
240
+ for (const reaction of reactions) {
241
+ await ctx.db.delete(reaction._id);
242
+ deletedReactions++;
243
+ }
244
+ // Delete the message
245
+ await ctx.db.delete(message._id);
246
+ deletedMessages++;
247
+ }
248
+ // Delete typing indicators
249
+ const typingIndicators = await ctx.db
250
+ .query("typingIndicators")
251
+ .withIndex("threadId", (q) => q.eq("threadId", args.threadId))
252
+ .collect();
253
+ for (const indicator of typingIndicators) {
254
+ await ctx.db.delete(indicator._id);
255
+ }
256
+ // Delete the thread
257
+ await ctx.db.delete(args.threadId);
258
+ return { deletedMessages, deletedReactions };
259
+ },
260
+ });
261
+ /**
262
+ * Internal function to update thread's lastActivityAt.
263
+ */
264
+ export const updateThreadActivity = mutation({
265
+ args: {
266
+ threadId: v.id("threads"),
267
+ },
268
+ returns: v.null(),
269
+ handler: async (ctx, args) => {
270
+ await ctx.db.patch(args.threadId, {
271
+ lastActivityAt: Date.now(),
272
+ });
273
+ return null;
274
+ },
275
+ });
276
+ //# sourceMappingURL=threads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threads.js","sourceRoot":"","sources":["../../src/component/threads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Set typing indicator for a user in a thread.
3
+ * Automatically schedules expiry cleanup.
4
+ */
5
+ export declare const setIsTyping: import("convex/server").RegisteredMutation<"public", {
6
+ threadId: import("convex/values").GenericId<"threads">;
7
+ userId: string;
8
+ isTyping: boolean;
9
+ }, Promise<null>>;
10
+ /**
11
+ * Get all users currently typing in a thread.
12
+ */
13
+ export declare const getTypingUsers: import("convex/server").RegisteredQuery<"public", {
14
+ excludeUserId?: string | undefined;
15
+ threadId: import("convex/values").GenericId<"threads">;
16
+ }, Promise<{
17
+ userId: string;
18
+ updatedAt: number;
19
+ }[]>>;
20
+ /**
21
+ * Internal function to cleanup expired typing indicators.
22
+ */
23
+ export declare const cleanupExpiredIndicators: import("convex/server").RegisteredMutation<"internal", {}, Promise<number>>;
24
+ /**
25
+ * Clear all typing indicators for a user across all threads.
26
+ * Useful when a user disconnects.
27
+ */
28
+ export declare const clearUserTyping: import("convex/server").RegisteredMutation<"public", {
29
+ userId: string;
30
+ }, Promise<number>>;
31
+ //# sourceMappingURL=typing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typing.d.ts","sourceRoot":"","sources":["../../src/component/typing.ts"],"names":[],"mappings":"AAwBA;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;iBAyDtB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;KA0BzB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,wBAAwB,6EAoBnC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe;;mBAoB1B,CAAC"}
@@ -0,0 +1,147 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query, internalMutation } from "./_generated/server.js";
3
+ import { internal } from "./_generated/api.js";
4
+ // ============================================================================
5
+ // Typing Indicator Configuration
6
+ // ============================================================================
7
+ /** How long (in ms) before a typing indicator expires */
8
+ const TYPING_EXPIRY_MS = 5000; // 5 seconds
9
+ // ============================================================================
10
+ // Typing Indicator Validators
11
+ // ============================================================================
12
+ const typingUserValidator = v.object({
13
+ userId: v.string(),
14
+ updatedAt: v.number(),
15
+ });
16
+ // ============================================================================
17
+ // Typing Indicator Functions
18
+ // ============================================================================
19
+ /**
20
+ * Set typing indicator for a user in a thread.
21
+ * Automatically schedules expiry cleanup.
22
+ */
23
+ export const setIsTyping = mutation({
24
+ args: {
25
+ threadId: v.id("threads"),
26
+ userId: v.string(),
27
+ isTyping: v.boolean(),
28
+ },
29
+ returns: v.null(),
30
+ handler: async (ctx, args) => {
31
+ // Verify thread exists
32
+ const thread = await ctx.db.get(args.threadId);
33
+ if (!thread) {
34
+ throw new Error(`Thread ${args.threadId} not found`);
35
+ }
36
+ const now = Date.now();
37
+ const expiresAt = now + TYPING_EXPIRY_MS;
38
+ // Find existing indicator
39
+ const existing = await ctx.db
40
+ .query("typingIndicators")
41
+ .withIndex("threadId_userId", (q) => q.eq("threadId", args.threadId).eq("userId", args.userId))
42
+ .first();
43
+ if (args.isTyping) {
44
+ if (existing) {
45
+ // Update existing indicator
46
+ await ctx.db.patch(existing._id, {
47
+ updatedAt: now,
48
+ expiresAt,
49
+ });
50
+ }
51
+ else {
52
+ // Create new indicator
53
+ await ctx.db.insert("typingIndicators", {
54
+ threadId: args.threadId,
55
+ userId: args.userId,
56
+ updatedAt: now,
57
+ expiresAt,
58
+ });
59
+ }
60
+ // Schedule cleanup
61
+ await ctx.scheduler.runAfter(TYPING_EXPIRY_MS + 1000, // Add a small buffer
62
+ internal.typing.cleanupExpiredIndicators, {});
63
+ }
64
+ else {
65
+ // Remove indicator if exists
66
+ if (existing) {
67
+ await ctx.db.delete(existing._id);
68
+ }
69
+ }
70
+ return null;
71
+ },
72
+ });
73
+ /**
74
+ * Get all users currently typing in a thread.
75
+ */
76
+ export const getTypingUsers = query({
77
+ args: {
78
+ threadId: v.id("threads"),
79
+ excludeUserId: v.optional(v.string()),
80
+ },
81
+ returns: v.array(typingUserValidator),
82
+ handler: async (ctx, args) => {
83
+ const now = Date.now();
84
+ const indicators = await ctx.db
85
+ .query("typingIndicators")
86
+ .withIndex("threadId", (q) => q.eq("threadId", args.threadId))
87
+ .collect();
88
+ // Filter to only non-expired indicators and optionally exclude current user
89
+ return indicators
90
+ .filter((i) => {
91
+ if (i.expiresAt < now)
92
+ return false;
93
+ if (args.excludeUserId && i.userId === args.excludeUserId)
94
+ return false;
95
+ return true;
96
+ })
97
+ .map((i) => ({
98
+ userId: i.userId,
99
+ updatedAt: i.updatedAt,
100
+ }));
101
+ },
102
+ });
103
+ /**
104
+ * Internal function to cleanup expired typing indicators.
105
+ */
106
+ export const cleanupExpiredIndicators = internalMutation({
107
+ args: {},
108
+ returns: v.number(),
109
+ handler: async (ctx) => {
110
+ const now = Date.now();
111
+ let deleted = 0;
112
+ // Get all expired indicators
113
+ const expired = await ctx.db
114
+ .query("typingIndicators")
115
+ .withIndex("expiresAt", (q) => q.lt("expiresAt", now))
116
+ .collect();
117
+ for (const indicator of expired) {
118
+ await ctx.db.delete(indicator._id);
119
+ deleted++;
120
+ }
121
+ return deleted;
122
+ },
123
+ });
124
+ /**
125
+ * Clear all typing indicators for a user across all threads.
126
+ * Useful when a user disconnects.
127
+ */
128
+ export const clearUserTyping = mutation({
129
+ args: {
130
+ userId: v.string(),
131
+ },
132
+ returns: v.number(),
133
+ handler: async (ctx, args) => {
134
+ // We need to scan all indicators since we don't have a userId index
135
+ // In production, you might want to add an index on userId
136
+ const allIndicators = await ctx.db.query("typingIndicators").collect();
137
+ let deleted = 0;
138
+ for (const indicator of allIndicators) {
139
+ if (indicator.userId === args.userId) {
140
+ await ctx.db.delete(indicator._id);
141
+ deleted++;
142
+ }
143
+ }
144
+ return deleted;
145
+ },
146
+ });
147
+ //# sourceMappingURL=typing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typing.js","sourceRoot":"","sources":["../../src/component/typing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,+EAA+E;AAC/E,iCAAiC;AACjC,+EAA+E;AAE/E,yDAAyD;AACzD,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,YAAY;AAE3C,+EAA+E;AAC/E,8BAA8B;AAC9B,+EAA+E;AAE/E,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAEH,+EAA+E;AAC/E,6BAA6B;AAC7B,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;IAChC,IAAI,EAAE;QACF,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;QACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;KACxB;IACD,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;IACjB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,uBAAuB;QACvB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,QAAQ,YAAY,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,GAAG,GAAG,gBAAgB,CAAC;QAEzC,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,EAAE;aACxB,KAAK,CAAC,kBAAkB,CAAC;aACzB,SAAS,CAAC,iBAAiB,EAAE,CAAC,CAAC,EAAE,EAAE,CAChC,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAC5D;aACA,KAAK,EAAE,CAAC;QAEb,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,IAAI,QAAQ,EAAE,CAAC;gBACX,4BAA4B;gBAC5B,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE;oBAC7B,SAAS,EAAE,GAAG;oBACd,SAAS;iBACZ,CAAC,CAAC;YACP,CAAC;iBAAM,CAAC;gBACJ,uBAAuB;gBACvB,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,EAAE;oBACpC,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,SAAS,EAAE,GAAG;oBACd,SAAS;iBACZ,CAAC,CAAC;YACP,CAAC;YAED,mBAAmB;YACnB,MAAM,GAAG,CAAC,SAAS,CAAC,QAAQ,CACxB,gBAAgB,GAAG,IAAI,EAAE,qBAAqB;YAC9C,QAAQ,CAAC,MAAM,CAAC,wBAAwB,EACxC,EAAE,CACL,CAAC;QACN,CAAC;aAAM,CAAC;YACJ,6BAA6B;YAC7B,IAAI,QAAQ,EAAE,CAAC;gBACX,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACtC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;IAChC,IAAI,EAAE;QACF,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC;QACzB,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;KACxC;IACD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IACrC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,EAAE;aAC1B,KAAK,CAAC,kBAAkB,CAAC;aACzB,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;aAC7D,OAAO,EAAE,CAAC;QAEf,4EAA4E;QAC5E,OAAO,UAAU;aACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;gBAAE,OAAO,KAAK,CAAC;YACpC,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,aAAa;gBAAE,OAAO,KAAK,CAAC;YACxE,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC;aACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACT,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,SAAS,EAAE,CAAC,CAAC,SAAS;SACzB,CAAC,CAAC,CAAC;IACZ,CAAC;CACJ,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,gBAAgB,CAAC;IACrD,IAAI,EAAE,EAAE;IACR,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,6BAA6B;QAC7B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,EAAE;aACvB,KAAK,CAAC,kBAAkB,CAAC;aACzB,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;aACrD,OAAO,EAAE,CAAC;QAEf,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;YAC9B,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnC,OAAO,EAAE,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;CACJ,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;IACpC,IAAI,EAAE;QACF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;KACrB;IACD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,oEAAoE;QACpE,0DAA0D;QAC1D,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,OAAO,EAAE,CAAC;QACvE,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,KAAK,MAAM,SAAS,IAAI,aAAa,EAAE,CAAC;YACpC,IAAI,SAAS,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBACnC,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnC,OAAO,EAAE,CAAC;YACd,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;CACJ,CAAC,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Get or create a zone for an entity.
3
+ * This is the main entry point - lazily creates a zone if it doesn't exist.
4
+ */
5
+ export declare const getOrCreateZone: import("convex/server").RegisteredMutation<"public", {
6
+ metadata?: any;
7
+ entityId: string;
8
+ }, Promise<import("convex/values").GenericId<"zones">>>;
9
+ /**
10
+ * List all zones with optional pagination.
11
+ */
12
+ export declare const listZones: import("convex/server").RegisteredQuery<"public", {
13
+ limit?: number | undefined;
14
+ }, Promise<{
15
+ _id: import("convex/values").GenericId<"zones">;
16
+ _creationTime: number;
17
+ metadata?: any;
18
+ entityId: string;
19
+ createdAt: number;
20
+ }[]>>;
21
+ /**
22
+ * Get a zone by entity ID (without creating).
23
+ */
24
+ export declare const getZone: import("convex/server").RegisteredQuery<"public", {
25
+ entityId: string;
26
+ }, Promise<{
27
+ _id: import("convex/values").GenericId<"zones">;
28
+ _creationTime: number;
29
+ metadata?: any;
30
+ entityId: string;
31
+ createdAt: number;
32
+ } | null>>;
33
+ /**
34
+ * Get a zone by its ID.
35
+ */
36
+ export declare const getZoneById: import("convex/server").RegisteredQuery<"public", {
37
+ zoneId: import("convex/values").GenericId<"zones">;
38
+ }, Promise<{
39
+ _id: import("convex/values").GenericId<"zones">;
40
+ _creationTime: number;
41
+ metadata?: any;
42
+ entityId: string;
43
+ createdAt: number;
44
+ } | null>>;
45
+ /**
46
+ * Update zone metadata.
47
+ */
48
+ export declare const updateZoneMetadata: import("convex/server").RegisteredMutation<"public", {
49
+ metadata: any;
50
+ zoneId: import("convex/values").GenericId<"zones">;
51
+ }, Promise<null>>;
52
+ /**
53
+ * Delete a zone and all its threads/messages.
54
+ * Use with caution - this is a destructive operation.
55
+ */
56
+ export declare const deleteZone: import("convex/server").RegisteredMutation<"public", {
57
+ zoneId: import("convex/values").GenericId<"zones">;
58
+ }, Promise<{
59
+ deletedThreads: number;
60
+ deletedMessages: number;
61
+ deletedReactions: number;
62
+ }>>;
63
+ //# sourceMappingURL=zones.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zones.d.ts","sourceRoot":"","sources":["../../src/component/zones.ts"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,eAAO,MAAM,eAAe;;;uDA0B1B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;KASpB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,OAAO;;;;;;;;UAWlB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;UAQtB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;iBAY7B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;GAgErB,CAAC"}