Files
root-org/src/lib/api/documents.ts
2026-02-07 01:31:55 +02:00

162 lines
4.1 KiB
TypeScript

import type { SupabaseClient } from '@supabase/supabase-js';
import type { Database, Document } from '$lib/supabase/types';
import { createLogger } from '$lib/utils/logger';
const log = createLogger('api.documents');
export async function fetchDocuments(
supabase: SupabaseClient<Database>,
orgId: string
): Promise<Document[]> {
const { data, error } = await supabase
.from('documents')
.select('*')
.eq('org_id', orgId)
.order('type', { ascending: false }) // folders first
.order('name');
if (error) {
log.error('fetchDocuments failed', { error, data: { orgId } });
throw error;
}
log.debug('fetchDocuments ok', { data: { count: data?.length ?? 0 } });
return data ?? [];
}
export async function createDocument(
supabase: SupabaseClient<Database>,
orgId: string,
name: string,
type: 'folder' | 'document' | 'kanban',
parentId: string | null = null,
userId: string,
options?: { id?: string; content?: import('$lib/supabase/types').Json }
): Promise<Document> {
let content: import('$lib/supabase/types').Json | null = options?.content ?? null;
if (!content && type === 'document') {
content = { type: 'doc', content: [] };
}
const { data, error } = await supabase
.from('documents')
.insert({
...(options?.id ? { id: options.id } : {}),
org_id: orgId,
name,
type,
parent_id: parentId,
created_by: userId,
content,
})
.select()
.single();
if (error) {
log.error('createDocument failed', { error, data: { orgId, name, type, parentId } });
throw error;
}
log.info('createDocument ok', { data: { id: data.id, name, type } });
return data;
}
export async function updateDocument(
supabase: SupabaseClient<Database>,
id: string,
updates: Partial<Pick<Document, 'name' | 'content' | 'parent_id'>>
): Promise<Document> {
const { data, error } = await supabase
.from('documents')
.update({ ...updates, updated_at: new Date().toISOString() })
.eq('id', id)
.select()
.single();
if (error) {
log.error('updateDocument failed', { error, data: { id, updates } });
throw error;
}
return data;
}
export async function deleteDocument(
supabase: SupabaseClient<Database>,
id: string
): Promise<void> {
const { error } = await supabase.from('documents').delete().eq('id', id);
if (error) {
log.error('deleteDocument failed', { error, data: { id } });
throw error;
}
}
export async function moveDocument(
supabase: SupabaseClient<Database>,
id: string,
newParentId: string | null
): Promise<void> {
const { error } = await supabase
.from('documents')
.update({ parent_id: newParentId, updated_at: new Date().toISOString() })
.eq('id', id);
if (error) {
log.error('moveDocument failed', { error, data: { id, newParentId } });
throw error;
}
}
export async function copyDocument(
supabase: SupabaseClient<Database>,
doc: Pick<Document, 'name' | 'type' | 'parent_id' | 'content'>,
orgId: string,
userId: string
): Promise<Document> {
const { data, error } = await supabase
.from('documents')
.insert({
org_id: orgId,
name: `${doc.name} (copy)`,
type: doc.type,
parent_id: doc.parent_id,
created_by: userId,
content: doc.content,
})
.select()
.single();
if (error) {
log.error('copyDocument failed', { error, data: { orgId, name: doc.name } });
throw error;
}
log.info('copyDocument ok', { data: { id: data.id, name: data.name } });
return data;
}
export function subscribeToDocuments(
supabase: SupabaseClient<Database>,
orgId: string,
onInsert: (doc: Document) => void,
onUpdate: (doc: Document) => void,
onDelete: (id: string) => void
) {
return supabase
.channel(`documents:${orgId}`)
.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'documents', filter: `org_id=eq.${orgId}` },
(payload) => onInsert(payload.new as Document)
)
.on(
'postgres_changes',
{ event: 'UPDATE', schema: 'public', table: 'documents', filter: `org_id=eq.${orgId}` },
(payload) => onUpdate(payload.new as Document)
)
.on(
'postgres_changes',
{ event: 'DELETE', schema: 'public', table: 'documents', filter: `org_id=eq.${orgId}` },
(payload) => onDelete((payload.old as { id: string }).id)
)
.subscribe();
}