All files / src/middleware harRecorder.ts

83.33% Statements 40/48
37.5% Branches 3/8
100% Functions 1/1
83.33% Lines 40/48

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  1x                                                         4x 4x     4x 4x                   4x 4x 4x 2x 2x     4x 4x 8x 8x 8x 4x     4x     4x     4x 4x 4x 4x         4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x     4x 4x
import { Context, Next } from 'hono';
import { openApiStore } from '../store/openApiStore.js';
 
interface HAREntry {
  startedDateTime: string;
  time: number;
  request: {
    method: string;
    url: string;
    httpVersion: string;
    headers: Array<{ name: string; value: string }>;
    queryString: Array<{ name: string; value: string }>;
    postData?: {
      mimeType: string;
      text: string;
    };
  };
  response: {
    status: number;
    statusText: string;
    httpVersion: string;
    headers: Array<{ name: string; value: string }>;
    content: {
      size: number;
      mimeType: string;
      text: string;
    };
  };
}
 
export async function harRecorder(c: Context, next: Next) {
  const startTime = Date.now();
 
  // Get request body if present
  let requestBody: any;
  if (c.req.method !== 'GET' && c.req.method !== 'HEAD') {
    try {
      requestBody = await c.req.json();
    } catch (e) {
      // Body might not be JSON
      requestBody = await c.req.text();
    }
  }
 
  // Get query parameters from URL
  const url = new URL(c.req.url);
  const queryParams: Record<string, string> = {};
  for (const [key, value] of url.searchParams.entries()) {
    queryParams[key] = value;
  }
 
  // Get all request headers
  const requestHeaders: Record<string, string> = {};
  Object.entries(c.req.header()).forEach(([key, value]) => {
    if (typeof value === 'string') {
      requestHeaders[key] = value;
    }
  });
 
  // Call next middleware
  await next();
 
  // Calculate response time
  const responseTime = Date.now() - startTime;
 
  // Get response body
  let responseBody: any;
  try {
    responseBody = await c.res.clone().json();
  } catch (e) {
    responseBody = await c.res.clone().text();
  }
 
  // Record the request/response in OpenAPI format
  openApiStore.recordEndpoint(
    c.req.path,
    c.req.method.toLowerCase(),
    {
      query: queryParams,
      body: requestBody,
      contentType: c.req.header('content-type') || 'application/json',
      headers: requestHeaders
    },
    {
      status: c.res.status,
      body: responseBody,
      contentType: c.res.headers.get('content-type') || 'application/json',
      headers: Object.fromEntries(c.res.headers.entries())
    }
  );
 
  // Set HAR data in context
  c.set('har', openApiStore.generateHAR());
}