feat: wire BuildPulse to Appwrite-backed persistence

This commit is contained in:
OpenClaw Bot
2026-05-07 00:31:33 +02:00
parent bdf8773797
commit 63c5a23b48
19 changed files with 1427 additions and 93 deletions
+92
View File
@@ -0,0 +1,92 @@
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 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 response = await fetch(url, {
...init,
headers: {
...baseHeaders,
...(init.headers || {}),
},
})
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),
}
}