@@ -9,6 +9,7 @@ import { ConvexError, v } from 'convex/values'
99import { api , internal } from './_generated/api'
1010import { action , internalMutation , mutation , query } from './_generated/server'
1111
12+ // TODO: maybe allow threads sharing of a whole account or remove userId arg
1213export const list = query ( {
1314 args : {
1415 userId : v . optional ( v . string ( ) ) ,
@@ -27,7 +28,21 @@ export const list = query({
2728 . query ( 'threads' )
2829 . withIndex ( 'by_last_message' , q => q )
2930 . order ( 'desc' )
30- . take ( 50 )
31+ . collect ( )
32+ } ,
33+ } )
34+
35+ export const listBySessionId = query ( {
36+ args : {
37+ sessionId : v . string ( ) ,
38+ } ,
39+ handler : async ( ctx , args ) => {
40+ return await ctx . db
41+ . query ( 'threads' )
42+ . withIndex ( 'by_session_id' , q => q . eq ( 'sessionId' , args . sessionId ) )
43+ . order ( 'desc' )
44+ . collect ( )
45+ . then ( threads => threads . map ( t => ( { ...t , lockerKey : undefined } ) ) )
3146 } ,
3247} )
3348
@@ -50,12 +65,12 @@ export const get = query({
5065export const create = mutation ( {
5166 args : {
5267 title : v . string ( ) ,
53- initSessionId : v . string ( ) ,
68+ sessionId : v . string ( ) ,
5469 lockerKey : v . optional ( v . string ( ) ) ,
5570 } ,
5671 handler : async ( ctx , args ) => {
5772 return await ctx . db . insert ( 'threads' , {
58- initSessionId : args . initSessionId ,
73+ sessionId : args . sessionId ,
5974 title : args . title ,
6075 lastMessageAt : Date . now ( ) ,
6176 lockerKey : args . lockerKey ,
@@ -67,13 +82,18 @@ export const create = mutation({
6782export const del = mutation ( {
6883 args : {
6984 threadId : v . id ( 'threads' ) ,
85+ lockerKey : v . optional ( v . string ( ) ) ,
7086 } ,
7187 handler : async ( ctx , args ) => {
7288 const thread = await ctx . db . get ( args . threadId )
7389 if ( ! thread )
7490 throw new ConvexError ( 'Thread not found' )
7591
76- await assertThreadAccess ( ctx , { thread } )
92+ // Only allow thread to be deleted via lockerKey if its anonymous
93+ if ( thread . userId && args . lockerKey )
94+ throw new ConvexError ( `"lockerKey" is not allowed to use to delete a thread that is assigned to a user` )
95+
96+ await assertThreadAccess ( ctx , { thread, lockerKey : args . lockerKey } )
7797
7898 await ctx . db . delete ( args . threadId )
7999 } ,
@@ -94,7 +114,7 @@ export const generateThreadTitle = action({
94114 const { text } = await generateText ( {
95115 model : openrouter ( 'qwen/qwen3-8b:free' ) ,
96116 system : `You are a helpful assistant, generating concise, informative, and clear titles for a given context, keep the generated title under 40 characters, do not use any quotes and markdown syntax.` ,
97- prompt : `Generate a new title for this thread, here is the previous info: \n${ [
117+ prompt : `Generate a new title for this thread, infer the language from the info's detail, here is the structured previous info: \n${ [
98118 `Title: "${ thread . title } "` ,
99119 ...( messages . length
100120 ? [ `Messages:\n${ await simpleMessagesToString ( messages . map ( m => ( {
@@ -109,7 +129,6 @@ export const generateThreadTitle = action({
109129 await ctx . runMutation ( internal . threads . updateThreadInfo , {
110130 title : text . trim ( ) ,
111131 threadId : args . threadId ,
112- lockerKey : args . lockerKey ,
113132 } )
114133 } ,
115134} )
@@ -119,15 +138,12 @@ export const updateThreadInfo = internalMutation({
119138 threadId : v . id ( 'threads' ) ,
120139 title : v . optional ( v . string ( ) ) ,
121140 lastMessageAt : v . optional ( v . number ( ) ) ,
122- lockerKey : v . optional ( v . string ( ) ) ,
123141 } ,
124142 handler : async ( ctx , args ) => {
125143 const thread = await ctx . db . get ( args . threadId )
126144 if ( ! thread )
127145 throw new Error ( 'Thread not found' )
128146
129- await assertThreadAccess ( ctx , { thread, lockerKey : args . lockerKey } )
130-
131147 await ctx . db . patch ( args . threadId , {
132148 ...clearUndefined ( {
133149 title : args . title ,
@@ -147,11 +163,14 @@ export async function assertThreadAccess(ctx: GenericCtx, { thread, lockerKey, u
147163 if ( lockerKey && thread . lockerKey === lockerKey ) {
148164 ;
149165 }
150- // Check permission other means
166+ // Check permission by other means (JWT)
151167 else {
152168 userIdentity ??= await ctx . auth . getUserIdentity ( )
153- if ( ! userIdentity || ( thread . userId !== userIdentity . subject ) )
169+ if ( ! userIdentity || ( thread . userId !== userIdentity . subject ) ) {
170+ if ( lockerKey )
171+ console . error ( `"lockerKey" available but incorrect` )
154172 throw new ConvexError ( 'You are not authorized to view this thread' )
173+ }
155174 }
156175}
157176
0 commit comments