This commit is contained in:
Mateusz Gruszczyński committed 2026-10-10 21:48:39 +02:00
1 parent 76b8bb7ee2
commit 24af7478b8
29 files changed
+321 -171

No files matched your search

+1
View File
@@ -244,6 +244,7 @@ pub(super) static READER_DOCUMENTS: &[(&str, &str, &str)] = &[
"guides",
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/STREAMS.md")),
),
reader_doc!("docs/IMPLEMENTATION_0.31.1.md", "technical"),
reader_doc!("docs/IMPLEMENTATION_0.31.0.md", "technical"),
(
"docs/TEST_REPORT.md",
+1 -1
View File
@@ -2,7 +2,7 @@
"openapi": "3.0.3",
"info": {
"title": "RustProxy Administration API",
"version": "0.31.0",
"version": "0.31.1",
"description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust."
},
"servers": [
+16
View File
@@ -40,6 +40,22 @@ fn admin_app_javascript() -> &'static str {
include_str!("web/app/config-history.js"),
include_str!("web/app/runtime.js"),
include_str!("web/app/settings.js"),
include_str!("web/management.js"),
include_str!("web/drafts.js"),
include_str!("web/integrations.js"),
admin_vhosts_javascript(),
include_str!("web/web-server-profiles.js"),
include_str!("web/web-server.js"),
include_str!("web/docker.js"),
include_str!("web/streams.js"),
include_str!("web/redirects.js"),
include_str!("web/host404.js"),
include_str!("web/traffic-panel.js"),
include_str!("web/cache-panel.js"),
include_str!("web/transform-panel.js"),
include_str!("web/acme.js"),
include_str!("web/settings.js"),
include_str!("web/file-logs.js"),
]
.join("\n")
});
+7 -6
View File
@@ -396,12 +396,13 @@ async function activate(info) {
window.rustProxyRedirects?.applyPreferences(preferences);
window.rustProxyNotFound?.applyPreferences(preferences);
window.rustProxyStreams?.applyPreferences(preferences);
// The live SSE stream is already running. Configuration can load behind the
// visible shell; it does not belong in the live refresh cycle.
try { await loadConfig(); }
catch (error) {
if (authenticated && epoch === authEpoch) toast(error.message, true);
return;
for (let attempt = 0; attempt < 3 && authenticated && epoch === authEpoch; attempt++) {
try { await loadConfig(); break; }
catch (error) {
if (!authenticated || epoch !== authEpoch || error?.status === 401) return;
if (attempt === 2) { showStartupFailure(error); return; }
await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 400));
}
}
if (!authenticated || epoch !== authEpoch) return;
// A single full snapshot seeds non-live diagnostics; subsequent updates
+24 -2
View File
@@ -1,5 +1,22 @@
(async () => {
// All modules must be available before any asynchronous session/config work can
// render the panel. DOMContentLoaded also waits for the complete deferred bundle.
function verifyAdminModules() {
const required = [
["rustProxyIntegrations", "bindings"],
["rustProxyVhosts", "render"],
["rustProxySettings", "render"],
["rustProxyCachePanel", "refresh"],
["rustProxyTrafficPanel", "refresh"],
["rustProxyPreferences", "load"],
["rustProxyRefresh", "start"],
];
const missing = required.find(([module, method]) => typeof window[module]?.[method] !== "function");
if (missing) throw new Error(`Panel resources incomplete (${missing[0]}). Reload to retry.`);
}
async function startAdminPanel() {
try {
verifyAdminModules();
// Revalidate the session first. The anonymous document has its own login.js;
// app.js belongs to the authenticated shell and must not fall back to its
// legacy embedded sign-in form when another startup step fails.
@@ -18,7 +35,12 @@
}
showStartupFailure(e);
}
})();
}
// The previous bootstrap ran while sibling deferred scripts were still loading.
// Starting only after DOMContentLoaded prevents fast API responses from racing
// against a slower or failed JS resource on mobile/reverse-proxied connections.
if (document.readyState === "complete") startAdminPanel();
else document.addEventListener("DOMContentLoaded", startAdminPanel, { once: true });
function certificateUsesExternalFiles(cert) {
return String(cert?.cert_file || "").startsWith("/") && String(cert?.key_file || "").startsWith("/");
+3 -18
View File
@@ -7,24 +7,9 @@
<meta content="width=device-width, initial-scale=1" name="viewport" />
<title>RustProxy / Control room</title>
<link href="/favicon.svg" rel="icon" />
<link href="/assets/style.css" rel="stylesheet" />
<script defer="" src="/assets/app.js"></script>
<script defer="" src="/assets/management.js"></script>
<script defer="" src="/assets/drafts.js"></script>
<script defer="" src="/assets/integrations.js"></script>
<script defer="" src="/assets/vhosts.js"></script>
<script defer="" src="/assets/web-server-profiles.js"></script>
<script defer="" src="/assets/web-server.js"></script>
<script defer="" src="/assets/docker.js"></script>
<script defer="" src="/assets/streams.js"></script>
<script defer="" src="/assets/redirects.js"></script>
<script defer="" src="/assets/host404.js"></script>
<script defer="" src="/assets/traffic-panel.js"></script>
<script defer="" src="/assets/cache-panel.js"></script>
<script defer="" src="/assets/transform-panel.js"></script>
<script defer="" src="/assets/acme.js"></script>
<script defer="" src="/assets/settings.js"></script>
<script defer="" src="/assets/file-logs.js"></script>
<link href="/assets/style.css?v=__RUSTPROXY_VERSION__" rel="stylesheet" />
<!-- One ordered JS payload: no race between module fetches and session/config API. -->
<script defer="" src="/assets/app.js?v=__RUSTPROXY_VERSION__"></script>
</head>
<body>