All files / frontend/src/utils main-process-bridge.ts

62.16% Statements 23/37
46.15% Branches 6/13
62.5% Functions 5/8
62.16% Lines 23/37

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;
}