Skip to content

Commit 4fd2e80

Browse files
committed
feat: firefoxAddon and firefoxAddons queries
1 parent 08d9f51 commit 4fd2e80

9 files changed

Lines changed: 91 additions & 3 deletions

File tree

src/@types/ctx.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ interface WxtQueueCtx {
22
chrome: ReturnType<
33
typeof import("../services/chrome-service").createChromeService
44
>;
5+
firefox: ReturnType<
6+
typeof import("../services/firefox-service").createFirefoxService
7+
>;
58
}

src/apis/firefox-api.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export function createFirefoxApiClient() {
2+
return {
3+
getAddon: async (
4+
idOrSlugOrGuid: number | string
5+
): Promise<Gql.FirefoxAddon> => {
6+
const url = new URL(
7+
`https://addons.mozilla.org/api/v5/addons/addon/${idOrSlugOrGuid}`
8+
);
9+
const res = await fetch(url);
10+
if (res.status !== 200)
11+
throw Error(
12+
`${url.href} failed with status: ${res.status} ${res.statusText}`
13+
);
14+
15+
const json = await res.json();
16+
17+
return {
18+
id: json.id,
19+
iconUrl: json.icon_url,
20+
lastUpdated: json.last_updated,
21+
longDescription: Object.values<string>(json.description)[0],
22+
name: Object.values<string>(json.name)[0],
23+
rating: json.ratings.average,
24+
reviewCount: json.ratings.count,
25+
shortDescription: Object.values<string>(json.summary)[0],
26+
storeUrl: json.url,
27+
version: json.current_version.version,
28+
dailyActiveUsers: json.average_daily_users,
29+
};
30+
},
31+
};
32+
}

src/apis/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./firefox-api";

src/crawlers/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * as chrome from "./chrome";
1+
export * as chrome from "./chrome-crawler";

src/resolvers/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export const rootResolver: Gql.RootResolver = {
22
chromeExtension: ({ id }, ctx) => ctx.chrome.getExtension(id),
33
chromeExtensions: ({ ids }, ctx) => ctx.chrome.getExtensions(ids),
4+
firefoxAddon: ({ id }, ctx) => ctx.firefox.getAddon(id),
5+
firefoxAddons: ({ ids }, ctx) => ctx.firefox.getAddons(ids),
46
};

src/schema.gql

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,21 @@ schema {
44

55
type Query {
66
"""
7-
Returns information about a chrome extension based on it's ID and language (defaults to "en")
7+
Returns information about a Chrome extension based on it's ID and language (defaults to "en").
88
"""
99
chromeExtension(id: String!): ChromeExtension
1010
"""
11-
Returns information about a list of chrome extension ids
11+
Returns information about a list of Chrome extension ids.
1212
"""
1313
chromeExtensions(ids: [String!]!): [ChromeExtension]!
14+
"""
15+
Returns information about a Firefox addon based on it's ID/GUID/slug.
16+
"""
17+
firefoxAddon(id: String!): FirefoxAddon
18+
"""
19+
Returns information about a list of Firefox addon ID/GUID/slugs.
20+
"""
21+
firefoxAddons(ids: [String!]!): [FirefoxAddon]!
1422
}
1523

1624
type ChromeExtension {
@@ -26,3 +34,17 @@ type ChromeExtension {
2634
rating: Float
2735
reviewCount: Int
2836
}
37+
38+
type FirefoxAddon {
39+
id: String!
40+
name: String!
41+
iconUrl: String!
42+
storeUrl: String!
43+
shortDescription: String!
44+
longDescription: String!
45+
dailyActiveUsers: Int!
46+
version: String!
47+
lastUpdated: String!
48+
rating: Float
49+
reviewCount: Int
50+
}

src/server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createGraphql } from "./graphql";
44
import playgroundHtmlTemplate from "./public/playground.html";
55
import consola from "consola";
66
import { createChromeService } from "./services/chrome-service";
7+
import { createFirefoxService } from "./services/firefox-service";
78

89
const playgroundHtml = playgroundHtmlTemplate.replace(
910
"{{VERSION}}",
@@ -15,8 +16,10 @@ export function createServer(config?: ServerConfig) {
1516
if (port == null) port = Number(process.env.PORT ?? "3000");
1617

1718
const chrome = createChromeService();
19+
const firefox = createFirefoxService();
1820
const graphql = createGraphql({
1921
chrome,
22+
firefox,
2023
});
2124

2225
const httpServer = Bun.serve({

src/services/firefox-service.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import DataLoader from "dataloader";
2+
import { createFirefoxApiClient } from "../apis";
3+
4+
export function createFirefoxService() {
5+
const firefox = createFirefoxApiClient();
6+
7+
const loader = new DataLoader<string | number, Gql.FirefoxAddon | undefined>(
8+
(ids) => Promise.all(ids.map((id) => firefox.getAddon(id)))
9+
);
10+
11+
return {
12+
getAddon: (id: string | number) => loader.load(id),
13+
getAddons: async (ids: Array<string | number>) => {
14+
const result = await loader.loadMany(ids);
15+
return result.map((item) => {
16+
if (item == null) return undefined;
17+
if (item instanceof Error) {
18+
console.warn("Error fetching multiple addons:", item);
19+
return undefined;
20+
}
21+
return item;
22+
});
23+
},
24+
};
25+
}

0 commit comments

Comments
 (0)