diff --git a/jsrepo.json b/jsrepo.json index 0ed3231..1a79699 100644 --- a/jsrepo.json +++ b/jsrepo.json @@ -8,6 +8,7 @@ "paths": { "*": "$lib/blocks", "utils": "$lib/utils", + "ts": "$lib/utils", "ui": "$lib/components/ui", "actions": "$lib/actions", "hooks": "$lib/hooks" diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 7a96061..217cc86 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -14,5 +14,14 @@ export const auth = betterAuth({ clientSecret: process.env.GITHUB_CLIENT_SECRET!, }, }, + databaseHooks: { + user: { + create: { + after: async ({ user }) => { + // TODO: automatically enable default models for the user + }, + }, + }, + }, plugins: [], }); diff --git a/src/lib/backend/convex/schema.ts b/src/lib/backend/convex/schema.ts index a652632..c89c64c 100644 --- a/src/lib/backend/convex/schema.ts +++ b/src/lib/backend/convex/schema.ts @@ -6,14 +6,14 @@ export const providerValidator = v.union(...Object.values(Provider).map((p) => v export default defineSchema({ user_keys: defineTable({ - user_id: v.id('users'), + user_id: v.string(), provider: providerValidator, key: v.string(), }) .index('by_user', ['user_id']) .index('by_provider_user', ['provider', 'user_id']), user_enabled_models: defineTable({ - user_id: v.id('users'), + user_id: v.string(), provider: providerValidator, /** Different providers may use different ids for the same model */ model_id: v.string(), diff --git a/src/lib/backend/convex/user_enabled_models.ts b/src/lib/backend/convex/user_enabled_models.ts index 4bc2f47..ebdc635 100644 --- a/src/lib/backend/convex/user_enabled_models.ts +++ b/src/lib/backend/convex/user_enabled_models.ts @@ -1,16 +1,19 @@ -import { mutation } from './_generated/server'; +import { query, mutation } from './_generated/server'; import { v } from 'convex/values'; import { providerValidator } from './schema'; +import * as array from '../../utils/array'; -export const get = mutation({ +export const get_enabled = query({ args: { - user_id: v.id('users'), + user_id: v.string(), }, handler: async (ctx, args) => { - return await ctx.db + const models = await ctx.db .query('user_enabled_models') .withIndex('by_user', (q) => q.eq('user_id', args.user_id)) .collect(); + + return array.toMap(models, (m) => [`${m.provider}:${m.model_id}`, m]); }, }); @@ -18,7 +21,8 @@ export const set = mutation({ args: { provider: providerValidator, model_id: v.string(), - user_id: v.id('users'), + user_id: v.string(), + enabled: v.boolean(), }, handler: async (ctx, args) => { const existing = await ctx.db @@ -28,8 +32,15 @@ export const set = mutation({ ) .first(); - if (existing) return; + if (args.enabled && existing) return; // nothing to do here - await ctx.db.insert('user_enabled_models', { ...args, pinned: null }); + if (existing) { + await ctx.db.delete(existing._id); + } else { + await ctx.db.insert('user_enabled_models', { + ...{ ...args, enabled: undefined }, + pinned: null, + }); + } }, }); diff --git a/src/lib/backend/convex/user_keys.ts b/src/lib/backend/convex/user_keys.ts index 0839854..c685509 100644 --- a/src/lib/backend/convex/user_keys.ts +++ b/src/lib/backend/convex/user_keys.ts @@ -5,7 +5,7 @@ import { providerValidator } from './schema'; export const get = query({ args: { - user_id: v.id('users'), + user_id: v.string(), }, handler: async (ctx, args) => { const allKeys = await ctx.db @@ -26,7 +26,7 @@ export const get = query({ export const set = mutation({ args: { provider: providerValidator, - user_id: v.id('users'), + user_id: v.string(), key: v.string(), }, handler: async (ctx, args) => { diff --git a/src/lib/components/ui/switch/index.ts b/src/lib/components/ui/switch/index.ts new file mode 100644 index 0000000..42ac3b6 --- /dev/null +++ b/src/lib/components/ui/switch/index.ts @@ -0,0 +1,3 @@ +import Switch from './switch.svelte'; + +export { Switch }; \ No newline at end of file diff --git a/src/lib/components/ui/switch/switch.svelte b/src/lib/components/ui/switch/switch.svelte new file mode 100644 index 0000000..a9d77db --- /dev/null +++ b/src/lib/components/ui/switch/switch.svelte @@ -0,0 +1,24 @@ + + + diff --git a/src/lib/utils/array.ts b/src/lib/utils/array.ts new file mode 100644 index 0000000..9608d3f --- /dev/null +++ b/src/lib/utils/array.ts @@ -0,0 +1,80 @@ +/* + Installed from @ieedan/std +*/ + +/** Maps the provided map into an array using the provided mapping function. + * + * @param map Map to be entered into an array + * @param fn A mapping function to transform each pair into an item + * @returns + * + * ## Usage + * ```ts + * console.log(map); // Map(5) { 0 => 5, 1 => 4, 2 => 3, 3 => 2, 4 => 1 } + * + * const arr = fromMap(map, (_, value) => value); + * + * console.log(arr); // [5, 4, 3, 2, 1] + * ``` + */ +export function fromMap(map: Map, fn: (key: K, value: V) => T): T[] { + const items: T[] = []; + + for (const [key, value] of map) { + items.push(fn(key, value)); + } + + return items; +} + +/** Calculates the sum of all elements in the array based on the provided function. + * + * @param arr Array of items to be summed. + * @param fn Summing function + * @returns + * + * ## Usage + * + * ```ts + * const total = sum([1, 2, 3, 4, 5], (num) => num); + * + * console.log(total); // 15 + * ``` + */ +export function sum(arr: T[], fn: (item: T) => number): number { + let total = 0; + + for (const item of arr) { + total = total + fn(item); + } + + return total; +} + +/** Maps the provided array into a map + * + * @param arr Array of items to be entered into a map + * @param fn A mapping function to transform each item into a key value pair + * @returns + * + * ## Usage + * ```ts + * const map = toMap([5, 4, 3, 2, 1], (item, i) => [i, item]); + * + * console.log(map); // Map(5) { 0 => 5, 1 => 4, 2 => 3, 3 => 2, 4 => 1 } + * ``` + */ +export function toMap( + arr: T[], + fn: (item: T, index: number) => [key: string, value: V] +): Record { + const map: Record = {}; + + for (let i = 0; i < arr.length; i++) { + const [key, value] = fn(arr[i], i); + + map[key] = value; + } + + return map; +} diff --git a/src/routes/account/api-keys/provider-card.svelte b/src/routes/account/api-keys/provider-card.svelte index d3e6998..d207c42 100644 --- a/src/routes/account/api-keys/provider-card.svelte +++ b/src/routes/account/api-keys/provider-card.svelte @@ -39,7 +39,7 @@ const key = formData.get('key'); if (key === null || !session.current?.user.id) return; - const res = await client.mutation(api.user_keys.set, { + await client.mutation(api.user_keys.set, { provider, user_id: session.current?.user.id ?? '', key: `${key}`, diff --git a/src/routes/account/models/+page.svelte b/src/routes/account/models/+page.svelte index b72ab12..83df142 100644 --- a/src/routes/account/models/+page.svelte +++ b/src/routes/account/models/+page.svelte @@ -1,11 +1,15 @@ @@ -20,5 +24,6 @@ {#each data.openRouterModels as model} - + {@const enabled = enabledModels.data?.[`${Provider.OpenRouter}:${model.id}`] !== undefined} + {/each} diff --git a/src/routes/account/models/model.svelte b/src/routes/account/models/model.svelte index 0459bda..dbeabbe 100644 --- a/src/routes/account/models/model.svelte +++ b/src/routes/account/models/model.svelte @@ -1,6 +1,10 @@ - {model.name} - {showMore ? fullDescription : shortDescription ?? fullDescription} +
+ {model.name} + + +
+ {showMore ? fullDescription : (shortDescription ?? fullDescription)} {#if shortDescription !== null} {/if}
- - - +