import { http, HttpResponse } from "msw"; import camelcaseKeys from "camelcase-keys"; import Fuse from "fuse.js"; import rawData from "./data/titles.json"; import { Title } from "../types"; const data: Title[] = camelcaseKeys(rawData, { deep: true }) as unknown as Title[]; let requestCount = 0; const RATE_LIMIT = 5; const TIMEOUT = 10; const RESET_INTERVAL = 100; const handleRateLimit = async (): Promise => { requestCount++; if (requestCount > RATE_LIMIT) { return HttpResponse.json({ error: "Rate limit exceeded. Please try again later." }, { status: 429 }); } await new Promise((resolve) => setTimeout(resolve, TIMEOUT)); }; setInterval(() => { requestCount = 0; }, RESET_INTERVAL); interface HandlerContext { params: Record; request: Request; } const createHandler = (handler: (context: HandlerContext) => Promise) => async (context: HandlerContext): Promise => { const rateLimitResponse = await handleRateLimit(); if (rateLimitResponse) return rateLimitResponse; return handler(context); }; export const handlers = [ http.get("http://localhost:4004/titles/object_type/:object_type/locale/:locale", createHandler(async ({ params, request }) => { try { const { objectType } = camelcaseKeys(params); const url = new URL(request.url); const token = url.searchParams.get("token"); if (!token) { return HttpResponse.json({ error: "Missing API token" }, { status: 403 }); } if (token === '401') { return HttpResponse.json({ error: "Unauthorized" }, { status: 401 }); } const query = url.searchParams.get("query")?.toLowerCase() || ""; const page = parseInt(url.searchParams.get("page") || "1", 10); const pageSize = parseInt(url.searchParams.get("page_size") || "10", 10); if (page < 1 || pageSize < 1) { return HttpResponse.json({ error: "Invalid pagination parameters" }, { status: 400 }); } // Filter data by object_type let dataset = data; if (objectType !== "all") { dataset = data.filter(t => t.objectType === objectType); } // Fuse.js setup for fuzzy searching const fuse = new Fuse(dataset, { keys: ["title", "originalTitle", "originalReleaseYear", "director"], threshold: 0.3, distance: 100, }); // Fuse.js fuzzy search const results: Title[] = query ? fuse.search(query).map(result => result.item) : dataset; const totalResults = results.length; const totalPages = Math.ceil(totalResults / pageSize); const pagedResults = results.slice((page - 1) * pageSize, page * pageSize); return HttpResponse.json({ total_results: totalResults, total_pages: totalPages, items: pagedResults.map(item => camelcaseKeys(item, { deep: true })), }); } catch (error) { return HttpResponse.json({ error: (error as Error).message }, { status: 500 }); } })), // Query titles by ID http.get("http://localhost:4004/offers/object_type/:object_type/id_type/:id_type/locale/:locale", createHandler(async ({ params, request }) => { const { objectType, idType } = camelcaseKeys(params) as unknown as { objectType: string; idType: string }; const url = new URL(request.url); const token = url.searchParams.get("token"); if (!token) { return HttpResponse.json({ error: "Missing API token" }, { status: 403 }); } if (token === '401') { return HttpResponse.json({ error: "Unauthorized" }, { status: 401 }); } const id = url.searchParams.get("id"); const dataset = data.filter(t => t.objectType === objectType); const title = dataset.find(t => t[`${idType}Id` as keyof Title] == id); if (!title) { return HttpResponse.json({ error: "Not Found" }, { status: 404 }); } return HttpResponse.json(title); })), ];