chore: sync backend and deployment changes

This commit is contained in:
2026-05-25 17:25:52 +09:00
parent d38d022872
commit fb5ec649cd
58 changed files with 17575 additions and 378 deletions

View File

@@ -74,7 +74,13 @@ async function requestOnce<T>(baseUrl: string, path: string, init?: RequestInit)
const controller = new AbortController();
const abortFromExternalSignal = () => controller.abort(init?.signal?.reason);
const hasExternalSignal = Boolean(init?.signal);
const timeoutId = globalThis.setTimeout(() => controller.abort(), 8000);
const extendedInit = init as (RequestInit & { timeoutMs?: number }) | undefined;
const timeoutMs = typeof init?.keepalive === 'boolean'
? 8000
: typeof extendedInit?.timeoutMs === 'number'
? Math.max(1000, extendedInit.timeoutMs ?? 8000)
: 8000;
const timeoutId = globalThis.setTimeout(() => controller.abort(), timeoutMs);
if (init?.signal) {
if (init.signal.aborted) {
@@ -163,7 +169,17 @@ async function requestOnce<T>(baseUrl: string, path: string, init?: RequestInit)
throw new ServerCommandApiError(text || '서버 명령 요청에 실패했습니다.', response.status);
}
return response.json() as Promise<T>;
const responseText = await response.text();
if (!responseText.trim()) {
throw new ServerCommandApiError('서버 명령 응답이 비어 있습니다.', 502);
}
try {
return JSON.parse(responseText) as T;
} catch {
throw new ServerCommandApiError('서버 명령 응답을 해석하지 못했습니다.', 502);
}
}
async function request<T>(path: string, init?: RequestInit): Promise<T> {
@@ -238,7 +254,19 @@ function normalizeServerCommandItem(value: unknown): ServerCommandItem {
function extractServerCommandItems(response: unknown) {
if (Array.isArray(response)) {
return response.map((item) => normalizeServerCommandItem(item));
const normalizedItems = response.flatMap((item) => {
try {
return [normalizeServerCommandItem(item)];
} catch {
return [];
}
});
if (normalizedItems.length === 0) {
throw new Error('서버 명령 목록을 읽지 못했습니다.');
}
return normalizedItems;
}
if (!response || typeof response !== 'object') {
@@ -247,21 +275,51 @@ function extractServerCommandItems(response: unknown) {
const payload = response as {
items?: unknown;
data?: { items?: unknown } | unknown[];
data?: { items?: unknown; data?: { items?: unknown } | unknown[] } | unknown[];
result?: { items?: unknown; data?: { items?: unknown } | unknown[] } | unknown[];
};
const payloadData =
payload.data && typeof payload.data === 'object' && !Array.isArray(payload.data) ? payload.data : null;
const payloadResult =
payload.result && typeof payload.result === 'object' && !Array.isArray(payload.result) ? payload.result : null;
const nestedPayloadData =
payloadData?.data && typeof payloadData.data === 'object' && !Array.isArray(payloadData.data) ? payloadData.data : null;
const nestedPayloadResult =
payloadResult?.data && typeof payloadResult.data === 'object' && !Array.isArray(payloadResult.data) ? payloadResult.data : null;
const items = Array.isArray(payload.items)
? payload.items
: payload.data && typeof payload.data === 'object' && !Array.isArray(payload.data) && Array.isArray(payload.data.items)
? payload.data.items
: Array.isArray(payload.data)
? payload.data
: null;
: Array.isArray(payloadData?.items)
? payloadData.items
: Array.isArray(payloadResult?.items)
? payloadResult.items
: Array.isArray(nestedPayloadData?.items)
? nestedPayloadData.items
: Array.isArray(nestedPayloadResult?.items)
? nestedPayloadResult.items
: Array.isArray(payload.data)
? payload.data
: Array.isArray(payload.result)
? payload.result
: null;
if (!items) {
throw new Error('서버 명령 목록을 읽지 못했습니다.');
}
return items.map((item) => normalizeServerCommandItem(item));
const normalizedItems = items.flatMap((item) => {
try {
return [normalizeServerCommandItem(item)];
} catch {
return [];
}
});
if (normalizedItems.length === 0) {
throw new Error('서버 명령 목록을 읽지 못했습니다.');
}
return normalizedItems;
}
function extractServerCommandActionResult(response: unknown): ServerCommandActionResult {
@@ -464,6 +522,7 @@ export async function restartServerCommand(key: ServerCommandKey, options?: { si
method: 'POST',
body: JSON.stringify({}),
signal: options?.signal,
timeoutMs: key === 'test' || key === 'rel' ? 30000 : 12000,
});
return extractServerCommandActionResult(response);