feat(userbot): prereqs at startup, SPA path guard, provision lock
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
deploy / redeploy (push) Failing after 0s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
ci / lint-prettier (push) Failing after 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Failing after 7s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 5s
deploy / redeploy (push) Failing after 0s
ci / build (push) Has been skipped
ci / deploy-userbot-panel (push) Has been skipped
- ensure_prerequisites runs on startup, not per-request; kube config errors surface as 503 PanelError - serialize provisioning with a lock; drop per-endpoint prereq checks - guard SPA fallback against path traversal (relative_to) - add backend tests for auth flow, k8s service, spa routing; ci comment for legacy userbot deployments
This commit is contained in:
1 parent
861d89d36a
commit
d9f1c8325a
10 files changed
+191
-34
No files matched your search
@@ -26,6 +26,7 @@
|
||||
let addOpen = false;
|
||||
let menuOpen = false;
|
||||
let busyId = '';
|
||||
let pollTimer: number | null = null;
|
||||
|
||||
$: visibleInstances = filterInstances(instances, query, status);
|
||||
$: running = instances.filter((item) => item.status === 'running').length;
|
||||
@@ -34,10 +35,35 @@
|
||||
|
||||
onMount(() => {
|
||||
refresh();
|
||||
const timer = window.setInterval(() => refresh(true), 5000);
|
||||
return () => window.clearInterval(timer);
|
||||
startPolling();
|
||||
document.addEventListener('visibilitychange', handleVisibility);
|
||||
return () => {
|
||||
stopPolling();
|
||||
document.removeEventListener('visibilitychange', handleVisibility);
|
||||
};
|
||||
});
|
||||
|
||||
function startPolling() {
|
||||
stopPolling();
|
||||
pollTimer = window.setInterval(() => refresh(true), 5000);
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollTimer !== null) {
|
||||
window.clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function handleVisibility() {
|
||||
if (document.visibilityState === 'visible') {
|
||||
refresh(true);
|
||||
startPolling();
|
||||
} else {
|
||||
stopPolling();
|
||||
}
|
||||
}
|
||||
|
||||
async function refresh(silent = false) {
|
||||
if (!silent) refreshing = true;
|
||||
try {
|
||||
|
||||
@@ -3,8 +3,15 @@ import type { AccountDraft, AuthResult, Instance } from "./types";
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const response = await fetch(path, init);
|
||||
if (!response.ok) {
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
throw new Error(payload.detail || response.statusText || "Request failed");
|
||||
let message = response.statusText || "Request failed";
|
||||
try {
|
||||
const payload = await response.json();
|
||||
if (payload?.detail) message = typeof payload.detail === "string" ? payload.detail : JSON.stringify(payload.detail);
|
||||
} catch {
|
||||
const text = await response.text().catch(() => "");
|
||||
if (text) message = text;
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
if (response.status === 204) return undefined as T;
|
||||
return response.json();
|
||||
|
||||
Reference in new issue
Block a user