Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 5x 5x 5x 56x 56x 56x 1x 56x 56x 56x 6x 6x 6x 6x 57x 57x 56x 56x 56x 6x 1x 1x 57x | import axios from "axios";
import { z } from 'zod'
import { apiSchemas, ApiResponse, ApiMethod } from '../../types'
axios.defaults.timeout = 30000
axios.defaults.timeoutErrorMessage='timeout'
// Module-level state for message handlers (private to this module)
const messageHandlers: { [key: string]: Array<(data: unknown) => void> } = {};
interface RequestOptions {
timeout: number
}
function validateApiResponse(method: ApiMethod, response: unknown): unknown {
const schema = apiSchemas[method];
// Handle void schemas: axios returns empty string for undefined/null responses
// Convert empty string to undefined for void schema validation
let dataToValidate = response;
if (schema instanceof z.ZodVoid && response === "") {
dataToValidate = undefined;
}
try {
const validated = schema.parse(dataToValidate);
return validated;
} catch (error) {
Eif (error instanceof z.ZodError) {
console.error(`[API Validation] Schema validation failed for ${method}:`, error.errors);
console.error('Response data:', JSON.stringify(response, null, 2));
throw new Error(`API response validation failed for ${method}: ${error.message}`);
}
throw error;
}
}
/**
* Register a handler for push notifications from the backend.
* Currently a no-op until WebSocket integration is implemented.
* See NEXTSTEPS.md for the planned WebSocket push notification system.
*/
export function addMessageHandler(type: string, handler: (data: unknown) => void) {
let handlers = messageHandlers[type];
if (handlers === undefined) {
handlers = [];
messageHandlers[type] = handlers;
}
handlers.push(handler);
}
export function removeMessageHandler(type: string, handler: (data: unknown) => void) {
const handlers = messageHandlers[type];
if (handlers === undefined) {
return;
}
handlers.splice(handlers.indexOf(handler), 1);
}
/**
* Dispatch a message to registered handlers.
* This will be called by the future WebSocket client.
*/
export function dispatchMessage(type: string, data: unknown) {
const handlers = messageHandlers[type];
if (handlers) {
for (const handler of handlers) {
handler(data);
}
}
}
export function request<M extends ApiMethod>(method: M, data?: unknown, opts: RequestOptions = {timeout:90000}): Promise<ApiResponse<M>> {
const promise = new Promise<ApiResponse<M>>((resolve, reject)=>{
axios
.post("/api/"+method, {
data: data,
}, {
timeout: opts.timeout
})
.then((response) => {
// Validate response with Zod schema
try {
const validatedData = validateApiResponse(method, response.data);
// this typecast is safe, because we just validated the data using zod
resolve(validatedData as ApiResponse<M>);
} catch (validationError) {
// Validation failed - reject the promise
reject(validationError);
}
})
.catch((error) => {
console.error("Error sending data:", error);
reject(error);
});
});
return promise;
}
|