File size: 5,398 Bytes
7a5aa35 33ffc9c cecb963 7a5aa35 3bd1a1b 7a5aa35 33ffc9c 7a5aa35 33ffc9c 7a5aa35 33ffc9c 7a5aa35 33ffc9c 7a5aa35 33ffc9c 7a5aa35 33ffc9c 7a5aa35 33ffc9c cecb963 33ffc9c cecb963 33ffc9c cecb963 7a5aa35 33ffc9c cecb963 33ffc9c cecb963 33ffc9c cecb963 33ffc9c 7a5aa35 33ffc9c |
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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
import { serve } from "bun";
import packages from "../database/database/packages.json" assert { type: "json" };
import programs from "../database/database/programs.json" assert { type: "json" };
const typedPackages: Item[] = packages as Item[];
const typedPrograms: Item[] = programs as Item[];
type Item = {
name?: string;
full_name?: string;
owner?: string;
description?: string | null;
topics?: string[];
created_at?: string;
usage_count?: number;
};
const corsHeaders = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
};
const sortByDate = (a: Item, b: Item) =>
new Date(b.created_at ?? "").getTime() - new Date(a.created_at ?? "").getTime();
const sortByUsage = (a: Item, b: Item) =>
(b.usage_count ?? 0) - (a.usage_count ?? 0);
const sorted = {
packages: {
latest: [...typedPackages].sort(sortByDate),
mostUsed: [...typedPackages].sort(sortByUsage),
},
programs: {
latest: [...typedPrograms].sort(sortByDate),
mostUsed: [...typedPrograms].sort(sortByUsage),
},
};
mostUsed: [...programs].sort(sortByUsage),
},
};
function filterItems(items: Item[], q: string | null, filter: string | null) {
return items.filter(({ name, full_name, description, topics }) => {
if (filter && !topics?.some(t => t.toLowerCase() === filter)) return false;
if (!q) return true;
const qlc = q.toLowerCase();
return [name, full_name, description, ...(topics ?? [])].some(
field => field?.toLowerCase().includes(qlc)
);
});
}
function getPaginated(items: Item[], page = 0, size = 10) {
return items.slice(page * size, page * size + size);
}
function findItem(items: Item[], owner: string, repo: string) {
owner = owner.toLowerCase();
repo = repo.toLowerCase();
return items.find(
({ owner: o, name, full_name }) =>
(o?.toLowerCase() === owner && name?.toLowerCase() === repo) ||
full_name?.toLowerCase() === `${owner}/${repo}`
);
}
function parseRange(str: string | null, max: number): [number, number] {
const m = str?.match(/^(\d+)\.\.(\d+)$/);
const [start, end] = m ? [parseInt(m[1]), parseInt(m[2])] : [0, 10];
return [Math.max(0, start), Math.min(max, end)];
}
serve({
port: 7860,
fetch(req) {
const url = new URL(req.url);
const { pathname, searchParams } = url;
const q = searchParams.get("q")?.trim().toLowerCase() ?? null;
const filter = searchParams.get("filter")?.trim().toLowerCase() ?? null;
if (req.method === "OPTIONS")
return new Response(null, {
status: 204,
headers: {
...corsHeaders,
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
},
});
if (pathname === "/api/searchPackages")
return Response.json(filterItems(packages, q, filter).slice(0, 25), { headers: corsHeaders });
if (pathname === "/api/searchPrograms")
return Response.json(filterItems(programs, q, filter).slice(0, 25), { headers: corsHeaders });
if (pathname === "/api/infiniteScrollPackages") {
const page = parseInt(searchParams.get("pageNumber") || "0", 10);
if (isNaN(page) || page < 0)
return Response.json({ error: "Invalid page number" }, { status: 400, headers: corsHeaders });
return Response.json(getPaginated(packages, page), { headers: corsHeaders });
}
if (pathname === "/api/infiniteScrollPrograms") {
const page = parseInt(searchParams.get("pageNumber") || "0", 10);
if (isNaN(page) || page < 0)
return Response.json({ error: "Invalid page number" }, { status: 400, headers: corsHeaders });
return Response.json(getPaginated(programs, page), { headers: corsHeaders });
}
const programMatch = pathname.match(/^\/api\/programs\/([^/]+)\/([^/]+)$/);
if (programMatch) {
const [, owner, repo] = programMatch.map(s => s.toLowerCase());
const found = findItem(programs, owner, repo);
return Response.json(found || { error: "Program not found" }, {
status: found ? 200 : 404,
headers: corsHeaders,
});
}
const packageMatch = pathname.match(/^\/api\/packages\/([^/]+)\/([^/]+)$/);
if (packageMatch) {
const [, owner, repo] = packageMatch.map(s => s.toLowerCase());
const found = findItem(packages, owner, repo);
return Response.json(found || { error: "Package not found" }, {
status: found ? 200 : 404,
headers: corsHeaders,
});
}
if (pathname === "/api/indexDetailsPackages" || pathname === "/api/indexDetailsPrograms") {
const section = searchParams.get("section");
if (section !== "latestRepos" && section !== "mostUsed")
return Response.json({ error: "Invalid section" }, { status: 400, headers: corsHeaders });
const key = section === "latestRepos" ? "latest" : "mostUsed";
const which = pathname.includes("Packages") ? "packages" : "programs";
const data = sorted[which as "packages" | "programs"][key as "latest" | "mostUsed"] ?? (which === "packages" ? packages : programs);
const [start, end] = parseRange(searchParams.get("range"), data.length);
return Response.json(data.slice(start, end), { headers: corsHeaders });
}
return new Response("Not Found", { status: 404, headers: corsHeaders });
},
});
console.log("Server running on http://localhost:7860"); |