import { ConvexError, v } from 'convex/values'; import type { Doc } from './_generated/dataModel'; import { internalMutation, mutation, query } from './_generated/server'; import { getOwnedSpoon, getRequiredUserId } from './model'; const publicSecret = (secret: Doc<'spoonSecrets'>) => ({ _id: secret._id, _creationTime: secret._creationTime, spoonId: secret.spoonId, ownerId: secret.ownerId, name: secret.name, valuePreview: secret.valuePreview, description: secret.description, createdAt: secret.createdAt, updatedAt: secret.updatedAt, }); export const listForSpoon = query({ args: { spoonId: v.id('spoons') }, handler: async (ctx, { spoonId }) => { const ownerId = await getRequiredUserId(ctx); await getOwnedSpoon(ctx, spoonId, ownerId); const secrets = await ctx.db .query('spoonSecrets') .withIndex('by_spoon', (q) => q.eq('spoonId', spoonId)) .order('asc') .collect(); return secrets.map(publicSecret); }, }); export const remove = mutation({ args: { secretId: v.id('spoonSecrets') }, handler: async (ctx, { secretId }) => { const ownerId = await getRequiredUserId(ctx); const secret = await ctx.db.get(secretId); if (secret?.ownerId !== ownerId) { throw new ConvexError('Spoon secret not found.'); } await ctx.db.delete(secretId); return { success: true }; }, }); export const upsertEncryptedInternal = internalMutation({ args: { spoonId: v.id('spoons'), ownerId: v.id('users'), name: v.string(), encryptedValue: v.string(), valuePreview: v.string(), description: v.optional(v.string()), }, handler: async (ctx, args) => { const now = Date.now(); const existing = await ctx.db .query('spoonSecrets') .withIndex('by_name', (q) => q.eq('spoonId', args.spoonId).eq('name', args.name), ) .first(); if (existing) { if (existing.ownerId !== args.ownerId) { throw new ConvexError('Spoon secret not found.'); } await ctx.db.patch(existing._id, { encryptedValue: args.encryptedValue, valuePreview: args.valuePreview, description: args.description, updatedAt: now, }); return existing._id; } return await ctx.db.insert('spoonSecrets', { ...args, createdAt: now, updatedAt: now, }); }, }); export const patchEncryptedInternal = internalMutation({ args: { secretId: v.id('spoonSecrets'), ownerId: v.id('users'), encryptedValue: v.optional(v.string()), valuePreview: v.optional(v.string()), description: v.optional(v.string()), }, handler: async (ctx, args) => { const secret = await ctx.db.get(args.secretId); if (secret?.ownerId !== args.ownerId) { throw new ConvexError('Spoon secret not found.'); } await ctx.db.patch(args.secretId, { encryptedValue: args.encryptedValue ?? secret.encryptedValue, valuePreview: args.valuePreview ?? secret.valuePreview, description: args.description, updatedAt: Date.now(), }); return { success: true }; }, });