feat: ditch triplit, move to postgresql + drizzle orm

This commit is contained in:
Zoe
2026-04-08 17:03:07 -05:00
parent c341c96798
commit e2e3ac6e86
121 changed files with 6680 additions and 4373 deletions
+143 -47
View File
@@ -1,54 +1,37 @@
import type { Entity } from '@triplit/client';
import type schema from '#triplit/schema';
import { nanoid } from 'nanoid';
import * as schema from '~~/drizzle/schema';
type Provider = Entity<typeof schema, 'providers'>;
type Model = Entity<typeof schema, 'models'>;
export type Model = typeof schema.models.$inferSelect;
export type Provider = typeof schema.providers.$inferSelect;
export interface ModelWithProvider extends Model {
provider: Provider;
}
export interface ProviderWithModels extends Provider {
export type ProviderWithModels = Provider & {
models: Model[];
}
};
export const useModels = () => {
const nuxtApp = useNuxtApp();
const triplit = useTriplitClient();
export type ModelWithProvider = Model & {
provider: Provider;
};
if (!nuxtApp._modelsState) {
nuxtApp._modelsState = {
providers: shallowRef([]),
isReady: ref(false)
};
}
export const useModels = async () => {
const providers = useState<ProviderWithModels[]>('models_state', () => []);
const loaded = useState('models_loaded', () => false);
const state = nuxtApp._modelsState as {
providers: Ref<ProviderWithModels[]>;
initPromise: Promise<void> | null;
};
const init = (): Promise<void> => {
if (state.initPromise) return state.initPromise;
state.initPromise = (async () => {
const query = triplit.query('providers').Include('models');
const { results } = await useQuery('providers', triplit, query)
watch(results, (newProviders) => {
if (newProviders && newProviders.length > 0) {
state.providers.value = newProviders as unknown as ProviderWithModels[];
}
}, { immediate: true, flush: 'sync' });
})();
return state.initPromise;
};
const { refresh } = await useFetch<ProviderWithModels[]>('/api/providers', {
key: 'models_request',
immediate: !loaded.value,
onRequest() {
loaded.value = true;
},
onResponse({ response }) {
if (response.ok) {
providers.value = response._data ?? [];
}
}
});
const allModels = computed<ModelWithProvider[]>(() => {
const result: ModelWithProvider[] = [];
for (const provider of state.providers.value) {
for (const provider of providers.value) {
if (!provider.enabled) continue;
for (const model of provider.models || []) {
if (!model.enabled) continue;
@@ -63,19 +46,132 @@ export const useModels = () => {
};
const getProvider = (id: string): ProviderWithModels | undefined => {
return state.providers.value.find((provider) => provider.id === id);
return providers.value.find((provider) => provider.id === id);
};
const getFirstAvailableModel = () => {
return allModels.value[0] ?? null;
};
const createModel = async (model: Model) => {
model.id = nanoid();
await $fetch(`/api/model`, {
method: 'POST',
body: model,
onRequest() {
providers.value = providers.value.map(p => ({
...p,
models: p.id === model.providerId ? [...p.models, model] : p.models
}));
},
onResponseError() {
providers.value = providers.value.map(p => ({
...p,
models: p.id === model.providerId ? p.models.filter(m => m.id !== model.id) : p.models
}));
},
});
}
const updateModel = async (id: string, updates: Partial<Model>) => {
const model = providers.value.find(p => p.models.find(m => m.id === id));
if (!model) return;
const original = model;
await $fetch(`/api/model/${id}`, {
method: 'PATCH',
body: updates,
onRequest() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.map(m =>
m.id === id ? { ...m, ...updates } : m
)
}));
},
onRequestError() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.map(m =>
m.id === id ? original : m
)
}) as ProviderWithModels);
},
onResponseError() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.map(m =>
m.id === id ? original : m
)
}) as ProviderWithModels);
},
// async onResponse() {
// await refresh();
// }
});
};
const deleteModel = async (id: string) => {
const model = providers.value.find(p => p.models.find(m => m.id === id));
if (!model) return;
await $fetch(`/api/model/${id}`, {
method: 'DELETE',
onRequest() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.filter(m => m.id !== id)
}));
},
onResponseError() {
providers.value.push(model);
},
async onResponse() {
await refresh();
}
});
}
const updateProvider = async (id: string, updates: Partial<Provider>) => {
const provider = providers.value.find(p => p.id === id);
if (!provider) return;
const original = provider;
await $fetch(`/api/provider/${id}`, {
method: 'PATCH',
body: updates,
onRequest() {
providers.value = providers.value.map(p =>
p.id === id ? { ...p, ...updates } : p
);
},
onRequestError() {
providers.value = providers.value.map(p =>
p.id === id ? original : p
);
},
onResponseError() {
providers.value = providers.value.map(p =>
p.id === id ? original : p
);
},
async onResponse() {
await refresh();
}
});
};
return {
init,
providers: state.providers,
providers,
allModels,
getModel,
getProvider,
getFirstAvailableModel
getFirstAvailableModel,
createModel,
updateModel,
updateProvider,
deleteModel
};
};
}