const endpoint = process.env.APPWRITE_SELF_HOSTED_URL || 'https://app.friborg.uk/v1' const projectId = process.env.APPWRITE_SELF_HOSTED_PROJECT_ID || 'freecastle' export const BUILDPULSE_DATABASE_ID = process.env.BUILDPULSE_APPWRITE_DATABASE_ID || process.env.APPWRITE_SELF_HOSTED_DATABASE_ID || 'freecastle' export const BUILDPULSE_COLLECTION_ID = process.env.BUILDPULSE_APPWRITE_COLLECTION_ID || 'runtime' export const BUILDPULSE_DOCUMENT_ID = process.env.BUILDPULSE_APPWRITE_DOCUMENT_ID || 'buildpulse_state' export const BUILDPULSE_DOCUMENT_KEY = process.env.BUILDPULSE_APPWRITE_DOCUMENT_KEY || 'buildpulse_state' const baseHeaders = { 'Content-Type': 'application/json', 'X-Appwrite-Project': projectId, } const REQUEST_TIMEOUT_MS = Number(process.env.BUILDPULSE_APPWRITE_TIMEOUT_MS || 4500) const documentUrl = `${endpoint}/databases/${BUILDPULSE_DATABASE_ID}/collections/${BUILDPULSE_COLLECTION_ID}/documents/${BUILDPULSE_DOCUMENT_ID}` const collectionUrl = `${endpoint}/databases/${BUILDPULSE_DATABASE_ID}/collections/${BUILDPULSE_COLLECTION_ID}/documents` async function appwriteFetch(url, init = {}) { const controller = new AbortController() const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS) let response try { response = await fetch(url, { ...init, signal: init.signal || controller.signal, headers: { ...baseHeaders, ...(init.headers || {}), }, }) } catch (error) { if (error?.name === 'AbortError') { const timeoutError = new Error(`Appwrite request timed out after ${REQUEST_TIMEOUT_MS}ms`) timeoutError.status = 504 throw timeoutError } throw error } finally { clearTimeout(timeout) } if (response.status === 204) return null const text = await response.text() const payload = text ? JSON.parse(text) : null if (!response.ok) { const error = new Error(payload?.message || `Appwrite request failed with ${response.status}`) error.status = response.status error.payload = payload throw error } return payload } export async function fetchStoredAppState() { try { const document = await appwriteFetch(documentUrl) return document?.value ? JSON.parse(document.value) : null } catch (error) { if (error?.status === 404) return null throw error } } export async function persistAppState(state) { const body = { data: { key: BUILDPULSE_DOCUMENT_KEY, value: JSON.stringify(state), updatedAt: new Date().toISOString(), }, } try { return await appwriteFetch(documentUrl, { method: 'PATCH', body: JSON.stringify(body), }) } catch (error) { if (error?.status !== 404) throw error } return appwriteFetch(collectionUrl, { method: 'POST', body: JSON.stringify({ documentId: BUILDPULSE_DOCUMENT_ID, ...body, }), }) } export async function checkBackendHealth() { const document = await appwriteFetch(documentUrl).catch((error) => { if (error?.status === 404) return null throw error }) return { ok: true, backend: 'appwrite', endpoint, databaseId: BUILDPULSE_DATABASE_ID, collectionId: BUILDPULSE_COLLECTION_ID, documentPresent: Boolean(document), } }