Refactoring + Dokumentation: api.js komprimiert (745→267 Zeilen), SseHelper extrahiert, DatabaseService in Partial Classes aufgeteilt, unbenutztes CSS entfernt, ARCHITECTURE.md/ARCHITECTURE_QUICK.md/README.md aktualisiert (neue Features: Embedding, Remote, API-Keys, 16 Tools)

This commit is contained in:
Meleki committed 2026-03-12 13:29:19 +01:00
1 parent 8dc52c1337
commit db1a7c7f64
18 files changed
+1701 -2007

No files matched your search

+165 -643
View File
@@ -14,728 +14,250 @@
};
})();
// ── Auth API ──
// ── Internal Fetch Helpers ──
async function apiLogin(username, password) {
const resp = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
var _jsonHeaders = { 'Content-Type': 'application/json' };
/** GET → JSON (returns fallback on error, default: throws) */
async function _get(url, fallback) {
var resp = await fetch(url);
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Login failed');
if (arguments.length >= 2) return fallback;
throw new Error('Fehler beim Laden');
}
return resp.json();
}
async function apiLogout() {
await fetch('/api/auth/logout', { method: 'POST' });
}
async function apiMe() {
const resp = await fetch('/api/auth/me');
if (!resp.ok) return null;
/** POST/PUT/DELETE with JSON body → JSON (throws on error) */
async function _send(method, url, body, errMsg) {
var opts = { method: method };
if (body !== undefined) {
opts.headers = _jsonHeaders;
opts.body = JSON.stringify(body);
}
var resp = await fetch(url, opts);
if (!resp.ok) {
var err = await resp.json().catch(function() { return {}; });
throw new Error(err.error || errMsg || 'Anfrage fehlgeschlagen');
}
return resp.json();
}
// ── API Calls ──
/** POST with JSON body → JSON */
function _post(url, body, errMsg) { return _send('POST', url, body, errMsg); }
async function apiChat(content, sessionId, signal, planMode) {
var payload = { content, sessionId };
/** PUT with JSON body → JSON */
function _put(url, body, errMsg) { return _send('PUT', url, body, errMsg); }
/** DELETE → JSON */
function _del(url, errMsg) { return _send('DELETE', url, undefined, errMsg); }
// ── Auth API ──
function apiLogin(u, p) { return _post('/api/auth/login', { username: u, password: p }, 'Login fehlgeschlagen'); }
function apiLogout() { return fetch('/api/auth/logout', { method: 'POST' }); }
function apiMe() { return _get('/api/auth/me', null); }
// ── Chat API ──
function apiChat(content, sessionId, signal, planMode) {
var payload = { content: content, sessionId: sessionId };
if (planMode) payload.planMode = true;
return fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal
});
return fetch('/api/chat', { method: 'POST', headers: _jsonHeaders, body: JSON.stringify(payload), signal: signal });
}
async function apiChatChoice(sessionId, choiceToolCallId, choiceResult, signal, planMode) {
var payload = { sessionId, choiceToolCallId, choiceResult };
function apiChatChoice(sessionId, choiceToolCallId, choiceResult, signal, planMode) {
var payload = { sessionId: sessionId, choiceToolCallId: choiceToolCallId, choiceResult: choiceResult };
if (planMode) payload.planMode = true;
return fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal
});
return fetch('/api/chat', { method: 'POST', headers: _jsonHeaders, body: JSON.stringify(payload), signal: signal });
}
function apiStopChat(sessionId) { return _post('/api/chat/stop', { sessionId: sessionId }); }
// ── Agent API ──
async function apiGetAgents() {
const resp = await fetch('/api/agents');
return resp.json();
}
async function apiGetAvailableAgents() {
const resp = await fetch('/api/agents/available');
if (!resp.ok) return [];
return resp.json();
}
async function apiGetAgent(agentId) {
const resp = await fetch(`/api/agents/${agentId}`);
if (!resp.ok) return null;
return resp.json();
}
async function apiCreateAgent(data) {
const resp = await fetch('/api/agents', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return resp.json();
}
async function apiUpdateAgent(agentId, data) {
const resp = await fetch(`/api/agents/${agentId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return resp.json();
}
async function apiDeleteAgent(agentId) {
return fetch(`/api/agents/${agentId}`, { method: 'DELETE' });
}
async function apiHistory(sessionId, beforeSortKey, includeDeleted = false) {
let url = `/api/history?sessionId=${sessionId}`;
if (beforeSortKey) url += `&beforeSortKey=${beforeSortKey}`;
if (includeDeleted) url += `&includeDeleted=true`;
const resp = await fetch(url);
return resp.json();
}
async function apiHistoryPoll(sessionId, afterSortKey, includeDeleted = false) {
let url = `/api/history/poll?sessionId=${sessionId}&afterSortKey=${afterSortKey}`;
if (includeDeleted) url += `&includeDeleted=true`;
const resp = await fetch(url);
return resp.json();
}
async function apiArchive(sessionId) {
const resp = await fetch(`/api/archive?sessionId=${sessionId}`, { method: 'POST' });
if (resp.status === 204) return null;
return resp.json();
}
async function apiListArchives(sessionId) {
const resp = await fetch(`/api/archives?sessionId=${sessionId}`);
return resp.json();
}
async function apiGetArchive(archiveId) {
const resp = await fetch(`/api/archive/${archiveId}`);
return resp.json();
}
function apiGetAgents() { return _get('/api/agents'); }
function apiGetAvailableAgents() { return _get('/api/agents/available', []); }
function apiGetAgent(id) { return _get('/api/agents/' + id, null); }
function apiCreateAgent(data) { return _post('/api/agents', data); }
function apiUpdateAgent(id, data) { return _put('/api/agents/' + id, data); }
function apiDeleteAgent(id) { return fetch('/api/agents/' + id, { method: 'DELETE' }); }
// ── Session API ──
async function apiGetSessions() {
const resp = await fetch('/api/sessions');
return resp.json();
}
function apiGetSessions() { return _get('/api/sessions'); }
function apiGetSession(id) { return _get('/api/sessions/' + id, null); }
function apiCreateSession(data) { return _post('/api/sessions', data || {}); }
function apiUpdateSession(id, data) { return _put('/api/sessions/' + id, data); }
function apiDeleteSession(id) { return fetch('/api/sessions/' + id, { method: 'DELETE' }); }
async function apiCreateSession(data = {}) {
const resp = await fetch('/api/sessions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
function apiExecCommand(sessionId, command, mode) {
mode = mode || 'background';
var resp = fetch('/api/sessions/' + sessionId + '/exec', {
method: 'POST', headers: _jsonHeaders, body: JSON.stringify({ command: command, mode: mode })
});
return resp.json();
return mode === 'foreground' ? resp.then(function(r) { return r.json(); }) : resp;
}
async function apiGetSession(sessionId) {
const resp = await fetch(`/api/sessions/${sessionId}`);
if (!resp.ok) return null;
return resp.json();
}
async function apiDeleteSession(sessionId) {
return fetch(`/api/sessions/${sessionId}`, { method: 'DELETE' });
}
async function apiUpdateSession(sessionId, data) {
const resp = await fetch(`/api/sessions/${sessionId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
function apiGetSystemPrompt(sessionId) {
return fetch('/api/sessions/' + sessionId + '/system-prompt').then(function(r) {
if (!r.ok) throw new Error('System-Prompt konnte nicht geladen werden');
return r.text();
});
return resp.json();
}
async function apiExecCommand(sessionId, command, mode = 'background') {
const resp = await fetch(`/api/sessions/${sessionId}/exec`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ command, mode })
function apiGetSystemPromptBlocks(sessionId, planMode) {
var url = '/api/sessions/' + sessionId + '/system-prompt-blocks' + (planMode ? '?planMode=true' : '');
return _get(url);
}
function apiIsStreaming(sessionId) { return _get('/api/sessions/' + sessionId + '/streaming'); }
function apiGitStatus(sessionId) { return _get('/api/sessions/' + sessionId + '/git-status', null); }
// ── History API ──
function apiHistory(sessionId, beforeSortKey, includeDeleted) {
var url = '/api/history?sessionId=' + sessionId;
if (beforeSortKey) url += '&beforeSortKey=' + beforeSortKey;
if (includeDeleted) url += '&includeDeleted=true';
return _get(url);
}
function apiHistoryPoll(sessionId, afterSortKey, includeDeleted) {
var url = '/api/history/poll?sessionId=' + sessionId + '&afterSortKey=' + afterSortKey;
if (includeDeleted) url += '&includeDeleted=true';
return _get(url);
}
// ── Archive API ──
function apiArchive(sessionId) {
return fetch('/api/archive?sessionId=' + sessionId, { method: 'POST' }).then(function(r) {
return r.status === 204 ? null : r.json();
});
if (mode === 'foreground') return resp.json();
return resp;
}
async function apiGetSystemPrompt(sessionId) {
const resp = await fetch(`/api/sessions/${sessionId}/system-prompt`);
if (!resp.ok) throw new Error('System-Prompt konnte nicht geladen werden');
return resp.text();
}
function apiListArchives(sessionId) { return _get('/api/archives?sessionId=' + sessionId); }
function apiGetArchive(id) { return _get('/api/archive/' + id); }
async function apiGetSystemPromptBlocks(sessionId, planMode) {
const url = `/api/sessions/${sessionId}/system-prompt-blocks` + (planMode ? '?planMode=true' : '');
const resp = await fetch(url);
if (!resp.ok) throw new Error('System-Prompt konnte nicht geladen werden');
return resp.json();
}
// ── Chain / Message API ──
async function apiIsStreaming(sessionId) {
const resp = await fetch(`/api/sessions/${sessionId}/streaming`);
return resp.json();
}
async function apiStopChat(sessionId) {
const resp = await fetch('/api/chat/stop', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionId })
});
return resp.json();
}
async function apiGetChain(chainId) {
const resp = await fetch(`/api/chains/${chainId}`);
if (!resp.ok) return null;
return resp.json();
}
async function apiToggleMessageMark(messageId) {
const resp = await fetch(`/api/messages/${messageId}/mark`, { method: 'PUT' });
return resp.json();
}
async function apiToggleMessageDelete(messageId) {
const resp = await fetch(`/api/messages/${messageId}/delete`, { method: 'PUT' });
return resp.json();
}
async function apiGitStatus(sessionId) {
const resp = await fetch(`/api/sessions/${sessionId}/git-status`);
if (!resp.ok) return null;
return resp.json();
}
function apiGetChain(id) { return _get('/api/chains/' + id, null); }
function apiToggleMessageMark(id) { return _put('/api/messages/' + id + '/mark'); }
function apiToggleMessageDelete(id) { return _put('/api/messages/' + id + '/delete'); }
// ── Skills API ──
async function apiGetSkills() {
const resp = await fetch('/api/skills');
return resp.json();
}
async function apiGetAgentSkills(agentId) {
const resp = await fetch(`/api/agents/${agentId}/skills`);
return resp.json();
}
async function apiSetAgentSkills(agentId, skills) {
const resp = await fetch(`/api/agents/${agentId}/skills`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ skills })
});
return resp.json();
}
async function apiAddAgentSkill(agentId, slug) {
return fetch(`/api/agents/${agentId}/skills/${slug}`, { method: 'POST' });
}
async function apiRemoveAgentSkill(agentId, slug) {
return fetch(`/api/agents/${agentId}/skills/${slug}`, { method: 'DELETE' });
}
function apiGetSkills() { return _get('/api/skills'); }
function apiGetAgentSkills(agentId) { return _get('/api/agents/' + agentId + '/skills'); }
function apiSetAgentSkills(agentId, skills) { return _put('/api/agents/' + agentId + '/skills', { skills: skills }); }
function apiAddAgentSkill(agentId, slug) { return fetch('/api/agents/' + agentId + '/skills/' + slug, { method: 'POST' }); }
function apiRemoveAgentSkill(agentId, slug) { return fetch('/api/agents/' + agentId + '/skills/' + slug, { method: 'DELETE' }); }
// ── Profile API ──
async function apiGetProfile() {
const resp = await fetch('/api/profile');
if (!resp.ok) return null;
return resp.json();
}
async function apiUpdateProfile(data) {
const resp = await fetch('/api/profile', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Speichern');
}
return resp.json();
}
async function apiChangePassword(currentPassword, newPassword) {
const resp = await fetch('/api/profile/password', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ currentPassword, newPassword })
});
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Ändern');
}
return resp.json();
}
function apiGetProfile() { return _get('/api/profile', null); }
function apiUpdateProfile(data) { return _put('/api/profile', data, 'Fehler beim Speichern'); }
function apiChangePassword(cur, pw) { return _put('/api/profile/password', { currentPassword: cur, newPassword: pw }, 'Fehler beim Ändern'); }
// ── Telegram Bot API ──
async function apiGetTelegramBots() {
const resp = await fetch('/api/telegram/bots');
return resp.json();
}
async function apiGetTelegramBot(botId) {
const resp = await fetch(`/api/telegram/bots/${botId}`);
if (!resp.ok) return null;
return resp.json();
}
async function apiCreateTelegramBot(name, botToken) {
const resp = await fetch('/api/telegram/bots', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, botToken })
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Bot erstellen fehlgeschlagen');
}
return resp.json();
}
async function apiGetAvailableTelegramBots() {
const resp = await fetch('/api/telegram/bots/available');
return resp.json();
}
async function apiUpdateTelegramBot(botId, name, botToken, isPublic) {
const resp = await fetch(`/api/telegram/bots/${botId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, botToken, isPublic })
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Bot speichern fehlgeschlagen');
}
return resp.json();
}
async function apiDeleteTelegramBot(botId) {
const resp = await fetch(`/api/telegram/bots/${botId}`, { method: 'DELETE' });
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Bot löschen fehlgeschlagen');
}
return resp.json();
}
async function apiTelegramBotRegisterWebhook(botId, baseUrl) {
const resp = await fetch(`/api/telegram/bots/${botId}/register-webhook`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ baseUrl })
});
if (!resp.ok) throw new Error('Webhook-Registrierung fehlgeschlagen');
return resp.json();
}
async function apiTelegramBotWebhookInfo(botId) {
const resp = await fetch(`/api/telegram/bots/${botId}/webhook-info`);
if (!resp.ok) throw new Error('Webhook-Info fehlgeschlagen');
return resp.json();
}
async function apiTelegramBotDeleteWebhook(botId) {
const resp = await fetch(`/api/telegram/bots/${botId}/webhook`, { method: 'DELETE' });
if (!resp.ok) throw new Error('Webhook-Löschung fehlgeschlagen');
return resp.json();
}
function apiGetTelegramBots() { return _get('/api/telegram/bots'); }
function apiGetTelegramBot(id) { return _get('/api/telegram/bots/' + id, null); }
function apiGetAvailableTelegramBots() { return _get('/api/telegram/bots/available'); }
function apiCreateTelegramBot(name, token) { return _post('/api/telegram/bots', { name: name, botToken: token }, 'Bot erstellen fehlgeschlagen'); }
function apiUpdateTelegramBot(id, name, token, isPublic) { return _put('/api/telegram/bots/' + id, { name: name, botToken: token, isPublic: isPublic }, 'Bot speichern fehlgeschlagen'); }
function apiDeleteTelegramBot(id) { return _del('/api/telegram/bots/' + id, 'Bot löschen fehlgeschlagen'); }
function apiTelegramBotRegisterWebhook(id, baseUrl) { return _post('/api/telegram/bots/' + id + '/register-webhook', { baseUrl: baseUrl }, 'Webhook-Registrierung fehlgeschlagen'); }
function apiTelegramBotWebhookInfo(id) { return _get('/api/telegram/bots/' + id + '/webhook-info'); }
function apiTelegramBotDeleteWebhook(id) { return _del('/api/telegram/bots/' + id + '/webhook', 'Webhook-Löschung fehlgeschlagen'); }
// ── Session Telegram Config ──
async function apiSessionTelegramGet(sessionId) {
const resp = await fetch(`/api/sessions/${sessionId}/telegram`);
if (!resp.ok) return { configured: false };
return resp.json();
}
function apiSessionTelegramGet(sessionId) { return _get('/api/sessions/' + sessionId + '/telegram', { configured: false }); }
function apiSessionTelegramSave(sessionId, botId, chatId) { return _put('/api/sessions/' + sessionId + '/telegram', { telegramBotId: botId, chatId: chatId }, 'Telegram-Config speichern fehlgeschlagen'); }
async function apiSessionTelegramSave(sessionId, telegramBotId, chatId) {
const resp = await fetch(`/api/sessions/${sessionId}/telegram`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ telegramBotId, chatId })
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Telegram-Config speichern fehlgeschlagen');
}
return resp.json();
}
// ── Settings API ──
async function apiGetSettings() {
const resp = await fetch('/api/settings');
if (!resp.ok) return {};
return resp.json();
}
async function apiSaveSettings(settings) {
const resp = await fetch('/api/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(settings)
});
return resp.json();
}
function apiGetSettings() { return _get('/api/settings', {}); }
function apiSaveSettings(settings) { return _put('/api/settings', settings); }
// ── Cronjob API ──
async function apiGetCronjobs() {
const resp = await fetch('/api/cronjobs');
return resp.json();
}
async function apiGetCronjob(id) {
const resp = await fetch(`/api/cronjobs/${id}`);
if (!resp.ok) return null;
return resp.json();
}
async function apiCreateCronjob(data) {
const resp = await fetch('/api/cronjobs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Cronjob erstellen fehlgeschlagen');
}
return resp.json();
}
async function apiUpdateCronjob(id, data) {
const resp = await fetch(`/api/cronjobs/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Cronjob speichern fehlgeschlagen');
}
return resp.json();
}
async function apiDeleteCronjob(id) {
return fetch(`/api/cronjobs/${id}`, { method: 'DELETE' });
}
async function apiToggleCronjob(id) {
const resp = await fetch(`/api/cronjobs/${id}/toggle`, { method: 'POST' });
return resp.json();
}
async function apiRunCronjob(id) {
const resp = await fetch(`/api/cronjobs/${id}/run`, { method: 'POST' });
return resp.json();
}
function apiGetCronjobs() { return _get('/api/cronjobs'); }
function apiGetCronjob(id) { return _get('/api/cronjobs/' + id, null); }
function apiCreateCronjob(data) { return _post('/api/cronjobs', data, 'Cronjob erstellen fehlgeschlagen'); }
function apiUpdateCronjob(id, data) { return _put('/api/cronjobs/' + id, data, 'Cronjob speichern fehlgeschlagen'); }
function apiDeleteCronjob(id) { return fetch('/api/cronjobs/' + id, { method: 'DELETE' }); }
function apiToggleCronjob(id) { return _post('/api/cronjobs/' + id + '/toggle'); }
function apiRunCronjob(id) { return _post('/api/cronjobs/' + id + '/run'); }
// ── Shared Message API ──
async function apiListShares() {
const resp = await fetch('/api/shared');
return resp.json();
}
function apiListShares() { return _get('/api/shared'); }
function apiShareMessage(id, includeContext) { return _post('/api/messages/' + id + '/share', { includeContext: includeContext || false }, 'Teilen fehlgeschlagen'); }
function apiGetShared(token) { return _get('/api/shared/' + token); }
function apiDeleteShare(token) { return fetch('/api/shared/' + token, { method: 'DELETE' }); }
async function apiShareMessage(messageId, includeContext = false) {
const resp = await fetch(`/api/messages/${messageId}/share`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ includeContext })
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Teilen fehlgeschlagen');
}
return resp.json();
}
// ── Admin User API ──
async function apiGetShared(token) {
const resp = await fetch(`/api/shared/${token}`);
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Geteilte Nachricht nicht gefunden');
}
return resp.json();
}
async function apiDeleteShare(token) {
return fetch(`/api/shared/${token}`, { method: 'DELETE' });
}
// ── Admin API ──
async function apiAdminGetUsers() {
const resp = await fetch('/api/admin/users');
if (!resp.ok) throw new Error('Fehler beim Laden der Benutzer');
return resp.json();
}
async function apiAdminCreateUser(data) {
const resp = await fetch('/api/admin/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Erstellen');
}
return resp.json();
}
async function apiAdminUpdateUser(userId, data) {
const resp = await fetch('/api/admin/users/' + userId, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Aktualisieren');
}
return resp.json();
}
async function apiAdminResetPassword(userId, password) {
const resp = await fetch('/api/admin/users/' + userId + '/password', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password })
});
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Zurücksetzen');
}
return resp.json();
}
async function apiAdminDeleteUser(userId) {
const resp = await fetch('/api/admin/users/' + userId, { method: 'DELETE' });
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Löschen');
}
return resp.json();
}
async function apiAdminImpersonate(userId) {
const resp = await fetch('/api/admin/users/' + userId + '/impersonate', { method: 'POST' });
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Anmelden');
}
return resp.json();
}
async function apiAdminGetLoginLink(userId) {
const resp = await fetch('/api/admin/users/' + userId + '/login-link', { method: 'POST' });
if (!resp.ok) {
const err = await resp.json();
throw new Error(err.error || 'Fehler beim Erstellen des Login-Links');
}
return resp.json();
}
function apiAdminGetUsers() { return _get('/api/admin/users'); }
function apiAdminCreateUser(data) { return _post('/api/admin/users', data, 'Fehler beim Erstellen'); }
function apiAdminUpdateUser(id, data) { return _put('/api/admin/users/' + id, data, 'Fehler beim Aktualisieren'); }
function apiAdminResetPassword(id, pw) { return _put('/api/admin/users/' + id + '/password', { password: pw }, 'Fehler beim Zurücksetzen'); }
function apiAdminDeleteUser(id) { return _del('/api/admin/users/' + id, 'Fehler beim Löschen'); }
function apiAdminImpersonate(id) { return _post('/api/admin/users/' + id + '/impersonate', undefined, 'Fehler beim Anmelden'); }
function apiAdminGetLoginLink(id) { return _post('/api/admin/users/' + id + '/login-link', undefined, 'Fehler beim Erstellen des Login-Links'); }
// ── Server Settings API (Admin) ──
async function apiGetServerSettings() {
const resp = await fetch('/api/admin/server-settings');
if (!resp.ok) throw new Error('Fehler beim Laden der Servereinstellungen');
return resp.json();
}
async function apiSaveServerSettings(data) {
const resp = await fetch('/api/admin/server-settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Fehler beim Speichern');
}
return resp.json();
}
function apiGetServerSettings() { return _get('/api/admin/server-settings'); }
function apiSaveServerSettings(data) { return _put('/api/admin/server-settings', data, 'Fehler beim Speichern'); }
// ── API Keys (Admin) ──
async function apiGetApiKeys() {
const resp = await fetch('/api/admin/api-keys');
if (!resp.ok) throw new Error('Fehler beim Laden der API-Keys');
return resp.json();
}
async function apiCreateApiKey(data) {
const resp = await fetch('/api/admin/api-keys', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Fehler beim Erstellen');
}
return resp.json();
}
async function apiUpdateApiKey(keyId, data) {
const resp = await fetch('/api/admin/api-keys/' + keyId, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Fehler beim Aktualisieren');
}
return resp.json();
}
async function apiActivateApiKey(keyId) {
const resp = await fetch('/api/admin/api-keys/' + keyId + '/activate', { method: 'PUT' });
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Fehler beim Aktivieren');
}
return resp.json();
}
async function apiDeactivateApiKey(keyId) {
const resp = await fetch('/api/admin/api-keys/' + keyId + '/deactivate', { method: 'PUT' });
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Fehler beim Deaktivieren');
}
return resp.json();
}
async function apiDeleteApiKey(keyId) {
const resp = await fetch('/api/admin/api-keys/' + keyId, { method: 'DELETE' });
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Fehler beim Löschen');
}
return resp.json();
}
async function apiCheckApiKey(keyId) {
const resp = await fetch('/api/admin/api-keys/' + keyId + '/check', { method: 'POST' });
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Fehler beim Prüfen');
}
return resp.json();
}
function apiGetApiKeys() { return _get('/api/admin/api-keys'); }
function apiCreateApiKey(data) { return _post('/api/admin/api-keys', data, 'Fehler beim Erstellen'); }
function apiUpdateApiKey(id, data) { return _put('/api/admin/api-keys/' + id, data, 'Fehler beim Aktualisieren'); }
function apiActivateApiKey(id) { return _put('/api/admin/api-keys/' + id + '/activate', undefined, 'Fehler beim Aktivieren'); }
function apiDeactivateApiKey(id) { return _put('/api/admin/api-keys/' + id + '/deactivate', undefined, 'Fehler beim Deaktivieren'); }
function apiDeleteApiKey(id) { return _del('/api/admin/api-keys/' + id, 'Fehler beim Löschen'); }
function apiCheckApiKey(id) { return _post('/api/admin/api-keys/' + id + '/check', undefined, 'Fehler beim Prüfen'); }
// ── Krea Image API ──
async function apiKreaStatus() {
const resp = await fetch('/api/images/status');
if (!resp.ok) return { configured: false };
return resp.json();
}
async function apiKreaGenerate(prompt, model, width, height) {
const resp = await fetch('/api/images/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt, model: model || 'flux', width: width || 512, height: height || 512, batchSize: 1 })
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Bildgenerierung fehlgeschlagen');
}
return resp.json();
function apiKreaStatus() { return _get('/api/images/status', { configured: false }); }
function apiKreaGenerate(prompt, model, width, height) {
return _post('/api/images/generate', {
prompt: prompt, model: model || 'flux', width: width || 512, height: height || 512, batchSize: 1
}, 'Bildgenerierung fehlgeschlagen');
}
// ── OpenClaw Import API ──
async function apiGetOpenclawSessions() {
const resp = await fetch('/api/openclaw/sessions');
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'OpenClaw-Sessions konnten nicht geladen werden');
}
return resp.json();
}
async function apiImportOpenclawSession(openclawSessionId, sessionId) {
const resp = await fetch('/api/openclaw/import', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ openclawSessionId, sessionId })
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(err.error || 'Import fehlgeschlagen');
}
return resp.json();
function apiGetOpenclawSessions() { return _get('/api/openclaw/sessions'); }
function apiImportOpenclawSession(openclawSessionId, sessionId) {
return _post('/api/openclaw/import', { openclawSessionId: openclawSessionId, sessionId: sessionId }, 'Import fehlgeschlagen');
}
// ── Remote API ──
async function apiGetRemoteConnections() {
const resp = await fetch('/api/remote/connections');
return resp.json();
}
async function apiAssignRemote(connectionId, sessionId) {
const resp = await fetch('/api/remote/assign', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ connectionId, sessionId })
});
return resp.json();
}
async function apiUnassignRemote(connectionId) {
const resp = await fetch('/api/remote/unassign', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ connectionId })
});
return resp.json();
}
function apiGetRemoteConnections() { return _get('/api/remote/connections', []); }
function apiAssignRemote(connectionId, sessionId) { return _post('/api/remote/assign', { connectionId: connectionId, sessionId: sessionId }); }
function apiUnassignRemote(connectionId) { return _post('/api/remote/unassign', { connectionId: connectionId }); }
// ── Backup API ──
async function apiBackupDb() {
const resp = await fetch('/api/backup', { method: 'POST', credentials: 'include' });
var resp = await fetch('/api/backup', { method: 'POST', credentials: 'include' });
if (!resp.ok) throw new Error('Backup fehlgeschlagen');
const blob = await resp.blob();
const cd = resp.headers.get('content-disposition') || '';
const filename = cd.match(/filename\*=UTF-8''(.+?)(?:;|$)/i)?.[1]
var blob = await resp.blob();
var cd = resp.headers.get('content-disposition') || '';
var filename = cd.match(/filename\*=UTF-8''(.+?)(?:;|$)/i)?.[1]
|| cd.match(/filename="?([^";]+)"?/)?.[1]
|| 'gott-backup.tar.gz';
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);