import { randomUUID } from 'node:crypto' import { config, WOMS_DATABASE_ID } from '../config.js' function buildQueries(queries = []) { return queries.map((q) => { if (typeof q === 'string') return q return JSON.stringify(q) }) } function adminHeaders() { return { 'Content-Type': 'application/json', 'X-Appwrite-Project': config.appwrite.projectId, 'X-Appwrite-Key': config.appwrite.apiKey, } } function formatRequestBody(body, method) { if (!body || method === 'GET' || method === 'DELETE') return body if (body.data !== undefined) return body const { documentId, ...fields } = body const payload = { data: fields } if (documentId) payload.documentId = documentId return payload } async function adminFetch(path, { method = 'GET', body, queries = [] } = {}) { if (!config.appwrite.apiKey) { const error = new Error('APPWRITE_API_KEY fehlt in .env') error.status = 500 throw error } const url = new URL(`${config.appwrite.endpoint}${path}`) for (const q of buildQueries(queries)) { url.searchParams.append('queries[]', q) } const requestBody = formatRequestBody(body, method) const response = await fetch(url.toString(), { method, headers: adminHeaders(), body: requestBody ? JSON.stringify(requestBody) : undefined, }) const text = await response.text() let data = null if (text) { try { data = JSON.parse(text) } catch { data = { message: text } } } if (!response.ok) { const error = new Error(data?.message || `Appwrite ${response.status}`) error.status = response.status >= 500 ? 500 : response.status error.code = data?.code error.type = data?.type throw error } return data } /** Appwrite Query-Helper (kompatibel zu bisherigen Aufrufen) */ export const Query = { equal: (attribute, value) => ({ method: 'equal', attribute, values: Array.isArray(value) ? value : [value], }), limit: (n) => ({ method: 'limit', values: [n] }), orderDesc: (attribute) => ({ method: 'orderDesc', attribute }), orderAsc: (attribute) => ({ method: 'orderAsc', attribute }), } export const ID = { unique: () => randomUUID(), } function collectionPath(collectionId) { return `/databases/${config.appwrite.databaseId}/collections/${collectionId}/documents` } export async function getUserById(userId) { return adminFetch(`/users/${userId}`) } export async function deleteUserSession(userId, sessionId) { return adminFetch(`/users/${userId}/sessions/${sessionId}`, { method: 'DELETE' }) } export async function listDocuments(collectionId, queries = []) { const result = await adminFetch(collectionPath(collectionId), { queries }) return result.documents } export async function getCustomerByAppwriteUserId(appwriteUserId) { const docs = await listDocuments(config.collections.customers, [ Query.equal('appwriteUserId', appwriteUserId), Query.limit(1), ]) return docs[0] || null } export async function getCustomerByEmail(email) { if (!email) return null const docs = await listDocuments(config.collections.customers, [ Query.equal('email', email.trim()), Query.limit(1), ]) return docs[0] || null } export async function getPortalAccessByCustomerId(customerId) { const docs = await listDocuments(config.collections.customerPortalAccess, [ Query.equal('customerId', customerId), Query.limit(1), ]) return docs[0] || null } export async function updateDocument(collectionId, documentId, data) { return adminFetch(`${collectionPath(collectionId)}/${documentId}`, { method: 'PATCH', body: data, }) } export async function upsertWebsiteProjectByRepo(repoFullName, data) { const existing = await listDocuments(config.collections.websiteProjects, [ Query.equal('repoFullName', repoFullName), Query.limit(1), ]) const now = new Date().toISOString() const payload = { ...data, updatedAt: now } if (existing[0]) { return updateDocument( config.collections.websiteProjects, existing[0].$id, payload ) } return adminFetch(collectionPath(config.collections.websiteProjects), { method: 'POST', body: { ...payload, createdAt: now, documentId: ID.unique() }, }) } export async function verifyDatabaseAccess() { if (!config.appwrite.apiKey) { return { ok: false, reason: 'APPWRITE_API_KEY fehlt' } } try { await listDocuments(config.collections.customers, [Query.limit(1)]) return { ok: true } } catch (err) { return { ok: false, reason: err.message, code: err.code, type: err.type, status: err.status, } } } export function createAdminClient() { return { usesNativeFetch: true, databaseId: WOMS_DATABASE_ID } } export function createUserClient() { return { usesNativeFetch: true } }