fix(admin): use absolute API URL for cross-origin admin fetches
This commit is contained in:
1 parent
c2f9f9ed62
commit
9a0511b36b
1 file changed
+21
-17
+21
-17
@@ -31,6 +31,7 @@ const adminConfig = {
|
||||
const MAX_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
|
||||
const UPLOAD_CHUNK_BYTES = 8 * 1024 * 1024;
|
||||
const UPLOAD_RESUME_KEY_PREFIX = "linearvoid-upload-resume:";
|
||||
const API_URL = import.meta.env.VITE_PUBLIC_APP_URL?.trim() || window.location.origin;
|
||||
|
||||
const state = {
|
||||
mediaUploading: false,
|
||||
@@ -131,7 +132,7 @@ const pageCache: Record<string, string> = {};
|
||||
async function loadPageContent(tabName: string): Promise<string> {
|
||||
if (pageCache[tabName]) return pageCache[tabName];
|
||||
|
||||
const response = await fetch(`/admin/${tabName}.html`);
|
||||
const response = await fetch(`${API_URL}/admin/${tabName}.html`);
|
||||
if (!response.ok) throw new Error(`Failed to load page: ${tabName}`);
|
||||
const html = await response.text();
|
||||
pageCache[tabName] = html;
|
||||
@@ -175,7 +176,7 @@ async function switchTab(tabName: string) {
|
||||
|
||||
export async function refreshOverview() {
|
||||
try {
|
||||
const response = await fetch("/api/admin/overview");
|
||||
const response = await fetch(`${API_URL}/api/admin/overview`);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
|
||||
const payload = await response.json();
|
||||
@@ -202,7 +203,7 @@ export async function refreshOverview() {
|
||||
export async function refreshAnalytics() {
|
||||
setStatus("analytics-status", "Loading analytics...");
|
||||
try {
|
||||
const response = await fetch("/api/admin/analytics");
|
||||
const response = await fetch(`${API_URL}/api/admin/analytics`);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
|
||||
const payload = await response.json();
|
||||
@@ -240,7 +241,7 @@ export async function refreshAnalytics() {
|
||||
async function refreshPlaylist() {
|
||||
setStatus("playlist-status", "Loading playlist...");
|
||||
try {
|
||||
const response = await fetch("/api/admin/playlist");
|
||||
const response = await fetch(`${API_URL}/api/admin/playlist`);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
|
||||
const payload = await response.json();
|
||||
@@ -522,7 +523,7 @@ async function submitOverride(e: Event) {
|
||||
const endTime = (document.getElementById("override-end") as HTMLInputElement).value;
|
||||
const reason = (document.getElementById("override-reason") as HTMLInputElement).value;
|
||||
try {
|
||||
const resp = await fetch("/api/admin/schedule/overrides", {
|
||||
const resp = await fetch(`${API_URL}/api/admin/schedule/overrides`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
@@ -551,7 +552,7 @@ async function submitOverride(e: Event) {
|
||||
|
||||
async function deleteOverride(id: number) {
|
||||
try {
|
||||
await fetch(`/api/admin/schedule/overrides?id=${id}`, { method: "DELETE" });
|
||||
await fetch(`${API_URL}/api/admin/schedule/overrides?id=${id}`, { method: "DELETE" });
|
||||
refreshOverrides();
|
||||
} catch {
|
||||
/* ignore */
|
||||
@@ -749,9 +750,12 @@ async function uploadVideo(file: File) {
|
||||
setStatus("media-status", `Uploading ${file.name} (${chunkIndex + 1}/${effectiveTotalChunks} chunks)...`);
|
||||
}
|
||||
|
||||
const completeResponse = await fetch(`/api/admin/media/uploads/${encodeURIComponent(uploadId)}/complete`, {
|
||||
method: "POST",
|
||||
});
|
||||
const completeResponse = await fetch(
|
||||
`${API_URL}/api/admin/media/uploads/${encodeURIComponent(uploadId)}/complete`,
|
||||
{
|
||||
method: "POST",
|
||||
},
|
||||
);
|
||||
|
||||
if (!completeResponse.ok) {
|
||||
throw new Error(await readErrorMessage(completeResponse));
|
||||
@@ -791,7 +795,7 @@ async function editMedia(file: MediaEntry) {
|
||||
|
||||
setStatus("media-status", `Saving metadata for ${file.name}...`);
|
||||
try {
|
||||
const response = await fetch(`/api/admin/media/${file.id}`, {
|
||||
const response = await fetch(`${API_URL}/api/admin/media/${file.id}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ title, status, tags }),
|
||||
@@ -816,7 +820,7 @@ async function normalizeMedia(file: MediaEntry) {
|
||||
|
||||
setStatus("media-status", `Normalizing ${file.name}...`);
|
||||
try {
|
||||
const response = await fetch(`/api/admin/media/${file.id}/normalize`, { method: "POST" });
|
||||
const response = await fetch(`${API_URL}/api/admin/media/${file.id}/normalize`, { method: "POST" });
|
||||
if (!response.ok) throw new Error(await readErrorMessage(response));
|
||||
|
||||
setStatus("media-status", `Normalization started for ${file.name}.`);
|
||||
@@ -836,7 +840,7 @@ function pollNormalizationStatus(id: number, attempt: number) {
|
||||
}
|
||||
window.setTimeout(async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/admin/media/${id}`);
|
||||
const response = await fetch(`${API_URL}/api/admin/media/${id}`);
|
||||
if (!response.ok) return;
|
||||
const file = (await response.json()) as MediaEntry;
|
||||
if (file.status === "normalizing" || file.status === "needs_normalization") {
|
||||
@@ -869,7 +873,7 @@ async function deleteMedia(file: MediaEntry) {
|
||||
|
||||
setStatus("media-status", `Deleting ${file.name}...`);
|
||||
try {
|
||||
const response = await fetch(`/api/admin/media/${file.id}`, {
|
||||
const response = await fetch(`${API_URL}/api/admin/media/${file.id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
@@ -887,7 +891,7 @@ async function deleteMedia(file: MediaEntry) {
|
||||
async function refreshModerationLogs() {
|
||||
setStatus("moderation-status", "Loading moderation logs...");
|
||||
try {
|
||||
const response = await fetch(`/api/admin/moderation/logs?limit=${adminConfig.moderationLogLimit}`);
|
||||
const response = await fetch(`${API_URL}/api/admin/moderation/logs?limit=${adminConfig.moderationLogLimit}`);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
|
||||
const payload = await response.json();
|
||||
@@ -988,7 +992,7 @@ async function refreshChatLog() {
|
||||
if (chatLogState.username) params.set("username", chatLogState.username);
|
||||
if (chatLogState.text) params.set("text", chatLogState.text);
|
||||
|
||||
const response = await fetch(`/api/admin/chat-log?${params}`);
|
||||
const response = await fetch(`${API_URL}/api/admin/chat-log?${params}`);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
|
||||
const payload = await response.json();
|
||||
@@ -1118,7 +1122,7 @@ async function deleteChatEntry(id: number) {
|
||||
|
||||
setStatus("chat-log-status", `Deleting message #${id}...`);
|
||||
try {
|
||||
const response = await fetch(`/api/admin/chat-log/${id}`, {
|
||||
const response = await fetch(`${API_URL}/api/admin/chat-log/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
@@ -1268,7 +1272,7 @@ async function restartService(service: string) {
|
||||
const status = document.getElementById("restart-status");
|
||||
if (status) status.textContent = `Requesting restart of ${service}...`;
|
||||
try {
|
||||
const resp = await fetch(`/api/admin/restart?service=${service}`, { method: "POST" });
|
||||
const resp = await fetch(`${API_URL}/api/admin/restart?service=${service}`, { method: "POST" });
|
||||
const data = await resp.json();
|
||||
if (status) status.textContent = data.message;
|
||||
} catch (err) {
|
||||
|
||||
Reference in new issue
Block a user