@@ -19,13 +19,20 @@ const findTodoByUuid = async (params: { db: DatabaseReader; uuid: string }) => {
1919 . first ( ) ;
2020} ;
2121
22+ /**
23+ * Public todo mutations use `list_uuid` from the local-first client and resolve
24+ * the Convex `list_id` server-side after checking list ownership. This keeps
25+ * callers from directly assigning a todo to an arbitrary Convex list document.
26+ */
27+ const publicTodoValidator = schema . tables . todos . validator . omit ( 'list_id' ) ;
28+
2229/**
2330 * Create a todo record given its record data.
2431 * The `list_id` is resolved here on the backend.
2532 */
2633export const create = mutation ( {
2734 // This does not include an `id` field. The local uuid is presented in the `uuid` field
28- args : schema . tables . todos . validator . omit ( 'list_id' ) ,
35+ args : publicTodoValidator ,
2936 handler : async ( ctx , args ) => {
3037 const { db } = ctx ;
3138 const ownerId = await requireOwnerId ( ctx ) ;
@@ -48,7 +55,7 @@ export const create = mutation({
4855 */
4956export const update = mutation ( {
5057 // The uuid is required, every other field is an optional patch
51- args : v . object ( { uuid : v . string ( ) } ) . extend ( schema . tables . todos . validator . partial ( ) . fields ) ,
58+ args : v . object ( { uuid : v . string ( ) } ) . extend ( publicTodoValidator . partial ( ) . fields ) ,
5259 handler : async ( ctx , { uuid, ...fields } ) => {
5360 const { db } = ctx ;
5461 const ownerId = await requireOwnerId ( ctx ) ;
@@ -62,16 +69,17 @@ export const update = mutation({
6269 }
6370 assertListOwner ( currentList , ownerId ) ;
6471
72+ const patch : Partial < typeof matching > = fields ;
6573 if ( fields . list_uuid !== undefined ) {
6674 const nextList = await findListByUuid ( { db, uuid : fields . list_uuid } ) ;
6775 if ( ! nextList ) {
6876 throw mutationError ( MUTATION_ERROR_CODES . NOT_FOUND , `No matching list found for uuid=${ fields . list_uuid } ` ) ;
6977 }
7078 assertListOwner ( nextList , ownerId ) ;
71- fields . list_id = nextList . _id ;
79+ patch . list_id = nextList . _id ;
7280 }
7381
74- await db . patch ( matching . _id , fields ) ;
82+ await db . patch ( matching . _id , patch ) ;
7583 }
7684} ) ;
7785
0 commit comments