RohanVashisht commited on
Commit
e4feb9d
·
1 Parent(s): 33ffc9c
Files changed (1) hide show
  1. src/index.ts +67 -51
src/index.ts CHANGED
@@ -1,85 +1,78 @@
1
  import { serve } from "bun";
2
- import packages from "../database/database/packages.json" assert { type: "json" };
3
- import programs from "../database/database/programs.json" assert { type: "json" };
4
 
5
- const typedPackages: Item[] = packages as Item[];
6
- const typedPrograms: Item[] = programs as Item[];
7
-
8
- type Item = {
9
  name?: string;
10
  full_name?: string;
11
  owner?: string;
12
- description?: string | null;
13
  topics?: string[];
14
  created_at?: string;
15
  usage_count?: number;
16
- };
17
 
18
  const corsHeaders = {
19
  "Content-Type": "application/json",
20
  "Access-Control-Allow-Origin": "*",
21
  };
22
 
23
- const sortByDate = (a: Item, b: Item) =>
24
- new Date(b.created_at ?? "").getTime() - new Date(a.created_at ?? "").getTime();
25
 
26
- const sortByUsage = (a: Item, b: Item) =>
27
- (b.usage_count ?? 0) - (a.usage_count ?? 0);
28
 
29
  const sorted = {
30
  packages: {
31
- latest: [...typedPackages].sort(sortByDate),
32
- mostUsed: [...typedPackages].sort(sortByUsage),
33
  },
34
  programs: {
35
- latest: [...typedPrograms].sort(sortByDate),
36
- mostUsed: [...typedPrograms].sort(sortByUsage),
37
- },
38
- };
39
  mostUsed: [...programs].sort(sortByUsage),
40
  },
41
  };
42
 
43
- function filterItems(items: Item[], q: string | null, filter: string | null) {
44
  return items.filter(({ name, full_name, description, topics }) => {
45
  if (filter && !topics?.some(t => t.toLowerCase() === filter)) return false;
46
  if (!q) return true;
47
- const qlc = q.toLowerCase();
48
- return [name, full_name, description, ...(topics ?? [])].some(
49
- field => field?.toLowerCase().includes(qlc)
50
- );
51
  });
52
  }
53
 
54
- function getPaginated(items: Item[], page = 0, size = 10) {
55
- return items.slice(page * size, page * size + size);
 
56
  }
57
 
58
- function findItem(items: Item[], owner: string, repo: string) {
59
- owner = owner.toLowerCase();
60
- repo = repo.toLowerCase();
61
- return items.find(
62
- ({ owner: o, name, full_name }) =>
63
- (o?.toLowerCase() === owner && name?.toLowerCase() === repo) ||
64
- full_name?.toLowerCase() === `${owner}/${repo}`
65
  );
66
  }
67
 
68
  function parseRange(str: string | null, max: number): [number, number] {
69
- const m = str?.match(/^(\d+)\.\.(\d+)$/);
70
- const [start, end] = m ? [parseInt(m[1]), parseInt(m[2])] : [0, 10];
 
 
71
  return [Math.max(0, start), Math.min(max, end)];
72
  }
73
 
74
  serve({
75
  port: 7860,
76
- fetch(req) {
77
  const url = new URL(req.url);
78
  const { pathname, searchParams } = url;
79
  const q = searchParams.get("q")?.trim().toLowerCase() ?? null;
80
  const filter = searchParams.get("filter")?.trim().toLowerCase() ?? null;
81
 
82
- if (req.method === "OPTIONS")
83
  return new Response(null, {
84
  status: 204,
85
  headers: {
@@ -88,17 +81,23 @@ serve({
88
  "Access-Control-Allow-Headers": "Content-Type",
89
  },
90
  });
 
91
 
92
- if (pathname === "/api/searchPackages")
93
- return Response.json(filterItems(packages, q, filter).slice(0, 25), { headers: corsHeaders });
 
 
94
 
95
- if (pathname === "/api/searchPrograms")
96
- return Response.json(filterItems(programs, q, filter).slice(0, 25), { headers: corsHeaders });
 
 
97
 
98
  if (pathname === "/api/infiniteScrollPackages") {
99
  const page = parseInt(searchParams.get("pageNumber") || "0", 10);
100
  if (isNaN(page) || page < 0)
101
  return Response.json({ error: "Invalid page number" }, { status: 400, headers: corsHeaders });
 
102
  return Response.json(getPaginated(packages, page), { headers: corsHeaders });
103
  }
104
 
@@ -106,12 +105,13 @@ serve({
106
  const page = parseInt(searchParams.get("pageNumber") || "0", 10);
107
  if (isNaN(page) || page < 0)
108
  return Response.json({ error: "Invalid page number" }, { status: 400, headers: corsHeaders });
 
109
  return Response.json(getPaginated(programs, page), { headers: corsHeaders });
110
  }
111
 
112
- const programMatch = pathname.match(/^\/api\/programs\/([^/]+)\/([^/]+)$/);
113
  if (programMatch) {
114
- const [, owner, repo] = programMatch.map(s => s.toLowerCase());
115
  const found = findItem(programs, owner, repo);
116
  return Response.json(found || { error: "Program not found" }, {
117
  status: found ? 200 : 404,
@@ -119,9 +119,9 @@ serve({
119
  });
120
  }
121
 
122
- const packageMatch = pathname.match(/^\/api\/packages\/([^/]+)\/([^/]+)$/);
123
  if (packageMatch) {
124
- const [, owner, repo] = packageMatch.map(s => s.toLowerCase());
125
  const found = findItem(packages, owner, repo);
126
  return Response.json(found || { error: "Package not found" }, {
127
  status: found ? 200 : 404,
@@ -129,18 +129,34 @@ serve({
129
  });
130
  }
131
 
132
- if (pathname === "/api/indexDetailsPackages" || pathname === "/api/indexDetailsPrograms") {
133
- const section = searchParams.get("section");
134
- if (section !== "latestRepos" && section !== "mostUsed")
 
 
 
 
 
 
 
 
 
 
 
 
135
  return Response.json({ error: "Invalid section" }, { status: 400, headers: corsHeaders });
136
- const key = section === "latestRepos" ? "latest" : "mostUsed";
137
- const which = pathname.includes("Packages") ? "packages" : "programs";
138
- const data = sorted[which as "packages" | "programs"][key as "latest" | "mostUsed"] ?? (which === "packages" ? packages : programs);
 
139
  const [start, end] = parseRange(searchParams.get("range"), data.length);
140
  return Response.json(data.slice(start, end), { headers: corsHeaders });
141
  }
142
 
143
- return new Response("Not Found", { status: 404, headers: corsHeaders });
 
 
 
144
  },
145
  });
146
 
 
1
  import { serve } from "bun";
2
+ import packages from "../database/database/packages.json";
3
+ import programs from "../database/database/programs.json";
4
 
5
+ interface Item {
 
 
 
6
  name?: string;
7
  full_name?: string;
8
  owner?: string;
9
+ description?: string;
10
  topics?: string[];
11
  created_at?: string;
12
  usage_count?: number;
13
+ }
14
 
15
  const corsHeaders = {
16
  "Content-Type": "application/json",
17
  "Access-Control-Allow-Origin": "*",
18
  };
19
 
20
+ const sortByDate = (a: Item, b: Item): number =>
21
+ new Date(b.created_at || "").getTime() - new Date(a.created_at || "").getTime();
22
 
23
+ const sortByUsage = (a: Item, b: Item): number =>
24
+ (b.usage_count || 0) - (a.usage_count || 0);
25
 
26
  const sorted = {
27
  packages: {
28
+ latest: [...packages].sort(sortByDate),
29
+ mostUsed: [...packages].sort(sortByUsage),
30
  },
31
  programs: {
32
+ latest: [...programs].sort(sortByDate),
 
 
 
33
  mostUsed: [...programs].sort(sortByUsage),
34
  },
35
  };
36
 
37
+ function filterItems(items: Item[], q: string | null, filter: string | null): Item[] {
38
  return items.filter(({ name, full_name, description, topics }) => {
39
  if (filter && !topics?.some(t => t.toLowerCase() === filter)) return false;
40
  if (!q) return true;
41
+ const lowerQ = q.toLowerCase();
42
+ return [name, full_name, description, ...(topics || [])]
43
+ .some(field => field?.toLowerCase().includes(lowerQ));
 
44
  });
45
  }
46
 
47
+ function getPaginated(items: Item[], page: number = 0, size: number = 10): Item[] {
48
+ const start = page * size;
49
+ return items.slice(start, start + size);
50
  }
51
 
52
+ function findItem(items: Item[], owner: string, repo: string): Item | undefined {
53
+ return items.find(({ owner: o, name, full_name }) =>
54
+ (o?.toLowerCase() === owner && name?.toLowerCase() === repo) ||
55
+ full_name?.toLowerCase() === `${owner}/${repo}`
 
 
 
56
  );
57
  }
58
 
59
  function parseRange(str: string | null, max: number): [number, number] {
60
+ const match = str?.match(/^(\d+)\.\.(\d+)$/);
61
+ const [start, end] = match
62
+ ? [parseInt(match[1]), parseInt(match[2])]
63
+ : [0, 10];
64
  return [Math.max(0, start), Math.min(max, end)];
65
  }
66
 
67
  serve({
68
  port: 7860,
69
+ fetch(req: Request): Response | Promise<Response> {
70
  const url = new URL(req.url);
71
  const { pathname, searchParams } = url;
72
  const q = searchParams.get("q")?.trim().toLowerCase() ?? null;
73
  const filter = searchParams.get("filter")?.trim().toLowerCase() ?? null;
74
 
75
+ if (req.method === "OPTIONS") {
76
  return new Response(null, {
77
  status: 204,
78
  headers: {
 
81
  "Access-Control-Allow-Headers": "Content-Type",
82
  },
83
  });
84
+ }
85
 
86
+ if (pathname === "/api/searchPackages") {
87
+ const result = filterItems(packages, q, filter).slice(0, 25);
88
+ return Response.json(result, { headers: corsHeaders });
89
+ }
90
 
91
+ if (pathname === "/api/searchPrograms") {
92
+ const result = filterItems(programs, q, filter).slice(0, 25);
93
+ return Response.json(result, { headers: corsHeaders });
94
+ }
95
 
96
  if (pathname === "/api/infiniteScrollPackages") {
97
  const page = parseInt(searchParams.get("pageNumber") || "0", 10);
98
  if (isNaN(page) || page < 0)
99
  return Response.json({ error: "Invalid page number" }, { status: 400, headers: corsHeaders });
100
+
101
  return Response.json(getPaginated(packages, page), { headers: corsHeaders });
102
  }
103
 
 
105
  const page = parseInt(searchParams.get("pageNumber") || "0", 10);
106
  if (isNaN(page) || page < 0)
107
  return Response.json({ error: "Invalid page number" }, { status: 400, headers: corsHeaders });
108
+
109
  return Response.json(getPaginated(programs, page), { headers: corsHeaders });
110
  }
111
 
112
+ const programMatch = pathname.match(/^\/api\/programs\/([^\/]+)\/([^\/]+)$/);
113
  if (programMatch) {
114
+ const [_, owner, repo] = programMatch.map(s => s.toLowerCase());
115
  const found = findItem(programs, owner, repo);
116
  return Response.json(found || { error: "Program not found" }, {
117
  status: found ? 200 : 404,
 
119
  });
120
  }
121
 
122
+ const packageMatch = pathname.match(/^\/api\/packages\/([^\/]+)\/([^\/]+)$/);
123
  if (packageMatch) {
124
+ const [_, owner, repo] = packageMatch.map(s => s.toLowerCase());
125
  const found = findItem(packages, owner, repo);
126
  return Response.json(found || { error: "Package not found" }, {
127
  status: found ? 200 : 404,
 
129
  });
130
  }
131
 
132
+ if (pathname === "/api/indexDetailsPackages") {
133
+ let section = searchParams.get("section");
134
+ if (section !== "latestRepos" && section !== "mostUsed") {
135
+ return Response.json({ error: "Invalid section" }, { status: 400, headers: corsHeaders });
136
+ }
137
+ // Map 'latestRepos' to 'latest' for sorting
138
+ const sortKey = section === "latestRepos" ? "latest" : "mostUsed";
139
+ let data = sorted.packages[sortKey as keyof typeof sorted.packages] ?? packages;
140
+ const [start, end] = parseRange(searchParams.get("range"), data.length);
141
+ return Response.json(data.slice(start, end), { headers: corsHeaders });
142
+ }
143
+
144
+ if (pathname === "/api/indexDetailsPrograms") {
145
+ let section = searchParams.get("section");
146
+ if (section !== "latestRepos" && section !== "mostUsed") {
147
  return Response.json({ error: "Invalid section" }, { status: 400, headers: corsHeaders });
148
+ }
149
+ // Map 'latestRepos' to 'latest' for sorting
150
+ const sortKey = section === "latestRepos" ? "latest" : "mostUsed";
151
+ let data = sorted.programs[sortKey as keyof typeof sorted.programs] ?? programs;
152
  const [start, end] = parseRange(searchParams.get("range"), data.length);
153
  return Response.json(data.slice(start, end), { headers: corsHeaders });
154
  }
155
 
156
+ return new Response("Not Found", {
157
+ status: 404,
158
+ headers: corsHeaders,
159
+ });
160
  },
161
  });
162