codex specify

This commit is contained in:
2026-02-25 21:19:48 +03:00
parent e043253e5d
commit 669ed92642
40 changed files with 3535 additions and 238 deletions

View File

@@ -7,7 +7,39 @@
import { addToast } from './toasts.js';
import { PUBLIC_WS_URL } from '$env/static/public';
const API_BASE_URL = '/api';
const API_BASE_URL = '/api';
// [DEF:buildApiError:Function]
// @PURPOSE: Creates a normalized Error object for failed API responses.
// @PRE: response is a failed fetch Response object.
// @POST: Returned error contains message and status fields.
async function buildApiError(response) {
const errorData = await response.json().catch(() => ({}));
const message = errorData.detail
? (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail))
: `API request failed with status ${response.status}`;
const error = new Error(message);
error.status = response.status;
return error;
}
// [/DEF:buildApiError:Function]
// [DEF:notifyApiError:Function]
// @PURPOSE: Shows toast for API errors with explicit handling of critical statuses.
// @PRE: error is an Error instance.
// @POST: User gets visible toast feedback for request failure.
function notifyApiError(error) {
if (error?.status === 401) {
addToast(`401 Unauthorized: ${error.message}`, 'error');
return;
}
if (error?.status >= 500) {
addToast(`Server error (${error.status}): ${error.message}`, 'error');
return;
}
addToast(error.message, 'error');
}
// [/DEF:notifyApiError:Function]
// [DEF:getWsUrl:Function]
// @PURPOSE: Returns the WebSocket URL for a specific task, with fallback logic.
@@ -54,22 +86,18 @@ async function fetchApi(endpoint) {
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
headers: getAuthHeaders()
});
console.log(`[api.fetchApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
const message = errorData.detail
? (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail))
: `API request failed with status ${response.status}`;
throw new Error(message);
}
if (response.status === 204) return null;
return await response.json();
} catch (error) {
console.error(`[api.fetchApi][Coherence:Failed] Error fetching from ${endpoint}:`, error);
addToast(error.message, 'error');
throw error;
}
}
console.log(`[api.fetchApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
if (!response.ok) {
throw await buildApiError(response);
}
if (response.status === 204) return null;
return await response.json();
} catch (error) {
console.error(`[api.fetchApi][Coherence:Failed] Error fetching from ${endpoint}:`, error);
notifyApiError(error);
throw error;
}
}
// [/DEF:fetchApi:Function]
// [DEF:postApi:Function]
@@ -87,22 +115,18 @@ async function postApi(endpoint, body) {
headers: getAuthHeaders(),
body: JSON.stringify(body),
});
console.log(`[api.postApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
const message = errorData.detail
? (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail))
: `API request failed with status ${response.status}`;
throw new Error(message);
}
if (response.status === 204) return null;
return await response.json();
} catch (error) {
console.error(`[api.postApi][Coherence:Failed] Error posting to ${endpoint}:`, error);
addToast(error.message, 'error');
throw error;
}
}
console.log(`[api.postApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
if (!response.ok) {
throw await buildApiError(response);
}
if (response.status === 204) return null;
return await response.json();
} catch (error) {
console.error(`[api.postApi][Coherence:Failed] Error posting to ${endpoint}:`, error);
notifyApiError(error);
throw error;
}
}
// [/DEF:postApi:Function]
// [DEF:requestApi:Function]
@@ -119,27 +143,24 @@ async function requestApi(endpoint, method = 'GET', body = null) {
if (body) {
options.body = JSON.stringify(body);
}
const response = await fetch(`${API_BASE_URL}${endpoint}`, options);
console.log(`[api.requestApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
const message = errorData.detail
? (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail))
: `API request failed with status ${response.status}`;
console.error(`[api.requestApi][Action] Request failed context={{'status': ${response.status}, 'message': '${message}'}}`);
throw new Error(message);
}
if (response.status === 204) {
console.log('[api.requestApi][Action] 204 No Content received');
return null;
}
return await response.json();
} catch (error) {
console.error(`[api.requestApi][Coherence:Failed] Error ${method} to ${endpoint}:`, error);
addToast(error.message, 'error');
throw error;
}
}
const response = await fetch(`${API_BASE_URL}${endpoint}`, options);
console.log(`[api.requestApi][Action] Received response context={{'status': ${response.status}, 'ok': ${response.ok}}}`);
if (!response.ok) {
const error = await buildApiError(response);
console.error(`[api.requestApi][Action] Request failed context={{'status': ${response.status}, 'message': '${error.message}'}}`);
throw error;
}
if (response.status === 204) {
console.log('[api.requestApi][Action] 204 No Content received');
return null;
}
return await response.json();
} catch (error) {
console.error(`[api.requestApi][Coherence:Failed] Error ${method} to ${endpoint}:`, error);
notifyApiError(error);
throw error;
}
}
// [/DEF:requestApi:Function]
// [DEF:api:Data]