import { v } from "convex/values"; import { filterSafeSettingsRows, isSafeSettingsKey, normalizeListLimit, } from "./domain"; import { mutation, query } from "./_generated/server"; const settingsValue = v.union(v.string(), v.number(), v.boolean(), v.null()); function assertSafeSettingsKey(key: string) { if (!isSafeSettingsKey(key)) { throw new Error("Settings metadata cannot store secrets or credentials."); } } export const get = query({ args: { key: v.string() }, handler: async (ctx, args) => { assertSafeSettingsKey(args.key); return await ctx.db .query("settings") .withIndex("by_key", (q) => q.eq("key", args.key)) .unique(); }, }); export const list = query({ args: { limit: v.optional(v.number()) }, handler: async (ctx, args) => { const rows = await ctx.db .query("settings") .order("desc") .take(normalizeListLimit(args.limit)); return filterSafeSettingsRows(rows); }, }); export const set = mutation({ args: { key: v.string(), value: settingsValue, description: v.optional(v.string()), }, handler: async (ctx, args) => { assertSafeSettingsKey(args.key); const now = Date.now(); const existing = await ctx.db .query("settings") .withIndex("by_key", (q) => q.eq("key", args.key)) .unique(); if (existing) { await ctx.db.patch(existing._id, { value: args.value, description: args.description, updatedAt: now, }); return existing._id; } return await ctx.db.insert("settings", { key: args.key, value: args.value, description: args.description, createdAt: now, updatedAt: now, }); }, });