laster 0.0.1

This commit is contained in:
2026-05-25 15:49:42 +07:00
parent 14d3a3152a
commit e2c4881bb7
22 changed files with 1139 additions and 158 deletions

View File

@@ -23,11 +23,12 @@ async function requestJson(baseUrl, path, options = {}) {
headers,
...fetchOptions
} = options;
const url = joinUrl(baseUrl, path);
const controller = new AbortController();
const timeout = window.setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(joinUrl(baseUrl, path), {
const response = await fetch(url, {
...fetchOptions,
headers: {
Accept: 'application/json',
@@ -50,13 +51,16 @@ async function requestJson(baseUrl, path, options = {}) {
if (!response.ok) {
const detail = payload?.detail || payload?.error || payload || response.statusText;
throw new Error(`${response.status} ${detail}`);
throw new Error(`${response.status} ${formatErrorDetail(detail)}`);
}
return payload;
} catch (error) {
if (error?.name === 'AbortError') {
throw new Error(`Request timeout: ${joinUrl(baseUrl, path)}`);
throw new Error(`Request timeout: ${url}`);
}
if (error instanceof TypeError) {
throw new Error(`Cannot fetch ${url}. Check endpoint reachability and CORS for this Web Client origin.`);
}
throw error;
} finally {
@@ -64,11 +68,41 @@ async function requestJson(baseUrl, path, options = {}) {
}
}
function formatErrorDetail(detail) {
if (Array.isArray(detail)) {
return detail.map(formatErrorDetail).filter(Boolean).join('; ');
}
if (detail && typeof detail === 'object') {
const location = Array.isArray(detail.loc) ? detail.loc.join('.') : '';
const message = detail.msg || detail.message || detail.detail || detail.error;
if (message) {
return location ? `${location}: ${message}` : String(message);
}
try {
return JSON.stringify(detail);
} catch {
return String(detail);
}
}
return String(detail || 'Request failed');
}
export async function fetchPackageApps(packageBaseUrl) {
const payload = await requestJson(packageBaseUrl, '/api/apps', { timeoutMs: 10000 });
return Array.isArray(payload?.apps) ? payload.apps.map(normalizePackageApp) : [];
}
export async function fetchLatestAgentPackage(packageBaseUrl, arch = 'amd64') {
const query = arch ? `?arch=${encodeURIComponent(arch)}` : '';
return normalizeLatestAgentPackage(
await requestJson(packageBaseUrl, `/api/agent/latest${query}`, { timeoutMs: 7000 })
);
}
export async function fetchApplicationDetail(packageBaseUrl, appId) {
return requestJson(packageBaseUrl, `/api/apps/${encodeURIComponent(appId)}`, { timeoutMs: 10000 });
}
@@ -146,7 +180,8 @@ export async function fetchTaskComponents(agentBaseUrl, taskId) {
function normalizePackageApp(app) {
return {
appId: String(app.appId || app.app_id || '').trim(),
appId: String(app.appId || app.app_id || app.id || '').trim(),
appCode: String(app.appCode || app.app_code || app.code || app.appId || app.app_id || '').trim(),
appName: String(app.appName || app.app_name || app.name || '').trim(),
version: String(app.version || '').trim(),
status: String(app.status || 'Released').trim(),
@@ -165,6 +200,17 @@ function normalizeInstalledApp(app) {
};
}
function normalizeLatestAgentPackage(agentPackage) {
return {
version: String(agentPackage?.version || '').trim(),
arch: String(agentPackage?.arch || '').trim(),
fileName: String(agentPackage?.fileName || agentPackage?.file_name || '').trim(),
sizeLabel: String(agentPackage?.sizeLabel || agentPackage?.size_label || '').trim(),
downloadUrl: String(agentPackage?.downloadUrl || agentPackage?.download_url || '').trim(),
installCommand: String(agentPackage?.installCommand || agentPackage?.install_command || '').trim()
};
}
function normalizeTask(task) {
return {
taskId: task.taskId || task.task_id,