Skip to content

Commit a9dd91d

Browse files
authored
feat: Improved memory managment and cleanup (#11)
1 parent a0300ae commit a9dd91d

19 files changed

Lines changed: 207 additions & 143 deletions

scripts/generate-gql-types.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,16 @@ function capitalizeFirstLetter(str: string): string {
7676
return str[0]!.toUpperCase() + str.substring(1);
7777
}
7878

79-
function getTsTypeString(gqlType: any): string {
79+
function getTsTypeString(gqlType: any, isReturn?: boolean): string {
8080
if (gqlType.kind === "NON_NULL")
81-
return `NonNullable<${getTsTypeString(gqlType.ofType)}>`;
81+
return getTsTypeString(gqlType.ofType, isReturn).replace(
82+
" | undefined",
83+
"",
84+
);
8285
if (gqlType.kind === "LIST")
83-
return `Array<${getTsTypeString(gqlType.ofType)}> | undefined`;
86+
return `Array<${getTsTypeString(gqlType.ofType, isReturn)}> | undefined`;
8487
if (gqlType.kind === "SCALAR" || gqlType.kind === "OBJECT")
85-
return `${gqlType.name} | undefined`;
88+
return `${gqlType.name}${isReturn ? " | Error" : ""} | undefined`;
8689

8790
logger.warn("Unknown GQL -> TS type", { gqlType });
8891
return "unknown";
@@ -114,6 +117,7 @@ function writeObjectType(code: CodeBlockWriter, argTypes: any[], type: any) {
114117
};
115118
args = `(args: ${argsType.name}, ctx: WxtQueueCtx)`;
116119
argTypes.push(argsType);
120+
returnTypeStr = getTsTypeString(field.type, true);
117121
returnTypeStr = `Promise<${returnTypeStr}> | ${returnTypeStr}`;
118122
}
119123
code.writeLine(`"${field.name}"${args}: ${returnTypeStr}`);

src/@types/gql-ctx.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
declare namespace Gql {
2-
export type WxtQueueCtx = import("../dependencies").Dependencies;
2+
export type WxtQueueCtx = {
3+
deps: import("../dependencies").Dependencies;
4+
};
35
}

src/apis/extension-store-apis.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ export const extensionStoreApis = createApp({
2222
index: z.coerce.number().int().min(0),
2323
}),
2424
},
25-
async ({ params, stores, set }) => {
26-
const screenshotUrl = await stores[params.storeName].getScreenshotUrl(
27-
params.id,
28-
params.index,
29-
);
25+
async ({ params, deps, set }) => {
26+
const screenshotUrl = await deps.stores[
27+
params.storeName
28+
].getScreenshotUrl(params.id, params.index);
3029
if (!screenshotUrl)
3130
throw new NotFoundHttpError("Extension or screenshot not found");
3231

src/dependencies.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1-
import { createIocContainer } from "@aklinker1/zero-ioc";
1+
import { createIocContainer, transient } from "@aklinker1/zero-ioc";
22
import { createChromeWebStore } from "./services/chrome-web-store";
33
import { createFirefoxAddonStore } from "./services/firefox-addon-store";
44
import { createEdgeAddonStore } from "./services/edge-addon-store";
55
import type { ExtensionStores } from "./services/extension-stores";
66
import { ExtensionStoreName } from "./enums";
7+
import { createRedisCache } from "./services/redis-cache";
8+
import { createInMemoryCache } from "./services/in-memory-cache";
9+
import { createEdgeApi } from "./services/edge-api";
10+
import { createFirefoxApi } from "./services/firefox-api";
711

812
export const container = createIocContainer()
9-
.register("chromeWebStore", createChromeWebStore)
10-
.register("firefoxAddonStore", createFirefoxAddonStore)
11-
.register("edgeAddonStore", createEdgeAddonStore)
13+
.register(
14+
"cache",
15+
Bun.redis.connected ? createRedisCache : createInMemoryCache,
16+
)
17+
.register("edgeApi", createEdgeApi)
18+
.register("firefoxApi", createFirefoxApi)
19+
.register("chromeWebStore", transient(createChromeWebStore))
20+
.register("firefoxAddonStore", transient(createFirefoxAddonStore))
21+
.register("edgeAddonStore", transient(createEdgeAddonStore))
1222
.register(
1323
"stores",
1424
(deps) =>

src/graphql/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ export function createGraphql() {
1919

2020
logger.debug("Running query", { id, method, operationName });
2121

22+
const ctx: Gql.WxtQueueCtx = {
23+
deps: container.registrations,
24+
};
25+
2226
const response = await graphql({
2327
schema,
2428
source: query,
25-
contextValue: container.registrations,
29+
contextValue: ctx,
2630
variableValues: variables,
2731
rootValue: rootResolver,
2832
});

src/graphql/resolvers.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
export const rootResolver: Gql.RootResolver = {
2-
chromeExtension: ({ id }, ctx) => ctx.chromeWebStore.getExtension(id),
3-
chromeExtensions: ({ ids }, ctx) => ctx.chromeWebStore.getExtensions(ids),
4-
firefoxAddon: ({ id }, ctx) => ctx.firefoxAddonStore.getExtension(id),
5-
firefoxAddons: ({ ids }, ctx) => ctx.firefoxAddonStore.getExtensions(ids),
6-
edgeAddon: ({ id }, ctx) => ctx.edgeAddonStore.getExtension(id),
7-
edgeAddons: ({ ids }, ctx) => ctx.edgeAddonStore.getExtensions(ids),
2+
chromeExtension: ({ id }, ctx) => ctx.deps.chromeWebStore.getExtension(id),
3+
chromeExtensions: ({ ids }, ctx) =>
4+
ctx.deps.chromeWebStore.getExtensions(ids),
5+
firefoxAddon: ({ id }, ctx) => ctx.deps.firefoxAddonStore.getExtension(id),
6+
firefoxAddons: ({ ids }, ctx) =>
7+
ctx.deps.firefoxAddonStore.getExtensions(ids),
8+
edgeAddon: ({ id }, ctx) => ctx.deps.edgeAddonStore.getExtension(id),
9+
edgeAddons: ({ ids }, ctx) => ctx.deps.edgeAddonStore.getExtensions(ids),
810
};

src/plugins/context-plugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ import { createApp } from "@aklinker1/zeta";
22
import { container } from "../dependencies";
33

44
export const contextPlugin = createApp()
5-
.decorate(container.resolveAll())
5+
.decorate({ deps: container.registrations })
66
.export();

src/services/cache.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface Cache {
2+
get<T>(key: string): Promise<T | undefined>;
3+
set<T>(key: string, value: T): Promise<void>;
4+
}

src/services/chrome-crawler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ function tryExtract<T>(
204204
errors.push(error as Error);
205205
}
206206
}
207-
errors.forEach((err) => console.error(err));
207+
if (errors.length > 0) logger.error("Crawl errors", { errors });
208208
throw new Error(`Could not extract "${field}" from HTML`, { cause: errors });
209209
}
210210

src/services/chrome-web-store.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
import type { Cache } from "./cache";
12
import { crawlExtension } from "./chrome-crawler";
2-
import { defineExtensionStore, type ExtensionStore } from "./extension-store";
3+
import { ExtensionStore } from "./extension-store";
34

45
export type ChromeWebStore = ExtensionStore<Gql.ChromeExtension>;
56

6-
export function createChromeWebStore() {
7-
return defineExtensionStore((id) => crawlExtension(String(id), "en"));
7+
export function createChromeWebStore({
8+
cache,
9+
}: {
10+
cache: Cache;
11+
}): ChromeWebStore {
12+
return new ExtensionStore({
13+
fetch: (id) => crawlExtension(String(id), "en"),
14+
cacheKeyPrefix: "chrome-extension-",
15+
cache,
16+
});
817
}

0 commit comments

Comments
 (0)