feat: API-Key Health-Check für Anthropic-Keys
- POST /api/admin/api-keys/{keyId}/check Endpoint
- Sendet minimale Anfrage an Anthropic API, liest Rate-Limit-Headers
- Plan-Erkennung: Max (Overage > 0), Pro (kein Fallback-Header), Pro/Max (sonst), API Console
- Budget-Auslastung: 5h + 7d + Overage mit Status-Warnings
- Frontend: Heartbeat-Button zeigt Ergebnis inline unter dem Key-Eintrag
- apiCheckApiKey() API-Funktion
This commit is contained in:
1 parent
fa8deb15b6
commit
8dc52c1337
3 files changed
+186
-1
No files matched your search
@@ -645,6 +645,15 @@ async function apiDeleteApiKey(keyId) {
|
||||
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();
|
||||
}
|
||||
|
||||
// ── Krea Image API ──
|
||||
|
||||
async function apiKreaStatus() {
|
||||
|
||||
@@ -32,6 +32,8 @@ registerPage('api-keys', {
|
||||
}
|
||||
|
||||
keys.forEach(function(key) {
|
||||
var wrapper = document.createElement('div');
|
||||
|
||||
var row = document.createElement('div');
|
||||
row.className = 'admin-user-row';
|
||||
|
||||
@@ -54,6 +56,21 @@ registerPage('api-keys', {
|
||||
var actions = document.createElement('div');
|
||||
actions.className = 'admin-user-actions';
|
||||
|
||||
// Status-Zeile (für Check-Ergebnis)
|
||||
var statusLine = document.createElement('div');
|
||||
statusLine.className = 'admin-user-meta';
|
||||
statusLine.style.cssText = 'padding:0 var(--box-padding) .5rem;display:none;font-size:.85em';
|
||||
|
||||
// Check (nur Anthropic)
|
||||
if (key.provider === 'anthropic') {
|
||||
var checkBtn = document.createElement('button');
|
||||
checkBtn.className = 'icon-btn';
|
||||
checkBtn.title = 'Key prüfen';
|
||||
checkBtn.innerHTML = '<i class="fa fa-heartbeat"></i>';
|
||||
checkBtn.addEventListener('click', function() { checkKey(key, checkBtn, statusLine); });
|
||||
actions.appendChild(checkBtn);
|
||||
}
|
||||
|
||||
// Bearbeiten
|
||||
var editBtn = document.createElement('button');
|
||||
editBtn.className = 'icon-btn';
|
||||
@@ -89,7 +106,9 @@ registerPage('api-keys', {
|
||||
|
||||
row.appendChild(info);
|
||||
row.appendChild(actions);
|
||||
list.appendChild(row);
|
||||
wrapper.appendChild(row);
|
||||
wrapper.appendChild(statusLine);
|
||||
list.appendChild(wrapper);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -102,6 +121,39 @@ registerPage('api-keys', {
|
||||
}
|
||||
}
|
||||
|
||||
async function checkKey(key, btn, statusLine) {
|
||||
var origHtml = btn.innerHTML;
|
||||
btn.innerHTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||
btn.disabled = true;
|
||||
statusLine.style.display = 'block';
|
||||
statusLine.textContent = 'Prüfe…';
|
||||
statusLine.style.opacity = '0.5';
|
||||
try {
|
||||
var result = await apiCheckApiKey(key.keyId);
|
||||
statusLine.style.opacity = '1';
|
||||
if (result.status === 'ok') {
|
||||
var parts = ['✅ Gültig', result.keyType];
|
||||
if (result.usage5h != null) parts.push('5h: ' + result.usage5h + '%');
|
||||
if (result.usage7d != null) {
|
||||
var s7d = '7d: ' + result.usage7d + '%';
|
||||
if (result.status7d === 'allowed_warning') s7d += ' ⚠️';
|
||||
else if (result.status7d === 'exceeded') s7d += ' 🛑';
|
||||
parts.push(s7d);
|
||||
}
|
||||
if (result.overage != null && result.overage > 0) parts.push('Overage: ' + result.overage + '%');
|
||||
statusLine.textContent = parts.join(' · ');
|
||||
} else {
|
||||
statusLine.textContent = '❌ ' + (result.message || 'Unbekannter Fehler');
|
||||
}
|
||||
} catch (err) {
|
||||
statusLine.style.opacity = '1';
|
||||
statusLine.textContent = '❌ ' + err.message;
|
||||
} finally {
|
||||
btn.innerHTML = origHtml;
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function startEdit(key) {
|
||||
editingKeyId = key.keyId;
|
||||
formTitle.textContent = 'API-Key bearbeiten';
|
||||
|
||||
Reference in new issue
Block a user