Skip to content

Commit 136a2b5

Browse files
committed
refactor: move to monorepo and use hono for workers
and update deps
1 parent b9782dc commit 136a2b5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+6090
-3704
lines changed

eslint.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ export default tseslint.config(
99
...tseslint.configs.recommended,
1010
prettier,
1111
{
12-
ignores: ["dist/**.js", "lib/**.js"],
12+
ignores: ["packages/*/dist", "packages/cloudflare-worker/worker-configuration.d.ts"],
1313
},
1414
);

package.json

+23-33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"name": "leetcode-card",
2+
"private": true,
3+
"name": "leetcode-card-monorepo",
34
"version": "1.0.1",
45
"description": "Show your dynamically generated LeetCode stats on your GitHub profile or your website!",
56
"license": "MIT",
@@ -13,48 +14,37 @@
1314
"lib"
1415
],
1516
"scripts": {
16-
"test": "vitest --coverage --coverage.include src",
1717
"prepare": "husky",
18-
"dev": "wrangler dev",
19-
"build:worker": "esbuild src/cloudflare-worker/index.ts --outfile=dist/worker.js --bundle --minify --format=esm --loader:.html=text --keep-names",
20-
"build:package": "esbuild src/core/index.ts --outfile=lib/index.js --bundle --format=esm --keep-names",
21-
"build:image": "selflare compile --script dist/worker.js && docker compose build",
22-
"build": "npm run build:worker && npm run build:package",
18+
"test": "vitest --coverage --coverage.include packages/*/src",
19+
"build:worker": "pnpm run --filter cloudflare-worker build",
20+
"build:package": "pnpm run --filter leetcode-card build",
21+
"build:image": "selflare compile --script packages/cloudflare-worker/dist/worker.js && docker compose build",
22+
"build": "pnpm -r build",
2323
"format": "prettier --write . --ignore-path .gitignore",
24-
"lint": "eslint .",
25-
"deploy": "wrangler deploy",
26-
"tail": "wrangler tail"
24+
"lint": "eslint ."
2725
},
2826
"keywords": [
2927
"leetcode",
3028
"stats",
3129
"card"
3230
],
33-
"dependencies": {
34-
"itty-router": "4.0.27",
35-
"leetcode-query": "1.1.0",
36-
"nano-font": "0.3.1"
37-
},
3831
"devDependencies": {
39-
"@cloudflare/workers-types": "^4.20240222.0",
40-
"@eslint/js": "^8.57.0",
41-
"@types/node": "^20.11.24",
42-
"@typescript-eslint/eslint-plugin": "^7.1.0",
43-
"@typescript-eslint/parser": "^7.1.0",
44-
"@vitest/coverage-v8": "^1.3.1",
45-
"esbuild": "^0.20.1",
46-
"eslint": "^8.57.0",
32+
"@eslint/js": "^9.17.0",
33+
"@types/node": "^22.10.2",
34+
"@typescript-eslint/eslint-plugin": "^8.18.0",
35+
"@typescript-eslint/parser": "^8.18.0",
36+
"@vitest/coverage-v8": "^2.1.8",
37+
"eslint": "^9.17.0",
4738
"eslint-config-prettier": "^9.1.0",
48-
"husky": "^9.0.11",
49-
"lint-staged": "^15.2.2",
50-
"prettier": "^3.2.5",
51-
"prettier-plugin-organize-imports": "^3.2.4",
52-
"selflare": "^1.0.0",
39+
"husky": "^9.1.7",
40+
"lint-staged": "^15.2.11",
41+
"prettier": "^3.4.2",
42+
"prettier-plugin-organize-imports": "^4.1.0",
43+
"selflare": "^1.1.2",
5344
"tsup": "8.0.2",
54-
"typescript": "^5.3.3",
55-
"typescript-eslint": "^7.1.0",
56-
"vitest": "^1.3.1",
57-
"wrangler": "^3.30.1"
45+
"typescript": "^5.7.2",
46+
"typescript-eslint": "^8.18.0",
47+
"vitest": "^2.1.8"
5848
},
5949
"repository": {
6050
"type": "git",
@@ -64,7 +54,7 @@
6454
"url": "https://github.com/JacobLinCool/LeetCode-Stats-Card/issues"
6555
},
6656
"homepage": "https://github.com/JacobLinCool/LeetCode-Stats-Card#readme",
67-
"packageManager": "pnpm@8.15.4",
57+
"packageManager": "pnpm@9.15.0",
6858
"lint-staged": {
6959
"*.{js,ts}": [
7060
"eslint --fix",

packages/cloudflare-worker/.gitignore

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Logs
2+
3+
logs
4+
_.log
5+
npm-debug.log_
6+
yarn-debug.log*
7+
yarn-error.log*
8+
lerna-debug.log*
9+
.pnpm-debug.log*
10+
11+
# Diagnostic reports (https://nodejs.org/api/report.html)
12+
13+
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
14+
15+
# Runtime data
16+
17+
pids
18+
_.pid
19+
_.seed
20+
\*.pid.lock
21+
22+
# Directory for instrumented libs generated by jscoverage/JSCover
23+
24+
lib-cov
25+
26+
# Coverage directory used by tools like istanbul
27+
28+
coverage
29+
\*.lcov
30+
31+
# nyc test coverage
32+
33+
.nyc_output
34+
35+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
36+
37+
.grunt
38+
39+
# Bower dependency directory (https://bower.io/)
40+
41+
bower_components
42+
43+
# node-waf configuration
44+
45+
.lock-wscript
46+
47+
# Compiled binary addons (https://nodejs.org/api/addons.html)
48+
49+
build/Release
50+
51+
# Dependency directories
52+
53+
node_modules/
54+
jspm_packages/
55+
56+
# Snowpack dependency directory (https://snowpack.dev/)
57+
58+
web_modules/
59+
60+
# TypeScript cache
61+
62+
\*.tsbuildinfo
63+
64+
# Optional npm cache directory
65+
66+
.npm
67+
68+
# Optional eslint cache
69+
70+
.eslintcache
71+
72+
# Optional stylelint cache
73+
74+
.stylelintcache
75+
76+
# Microbundle cache
77+
78+
.rpt2_cache/
79+
.rts2_cache_cjs/
80+
.rts2_cache_es/
81+
.rts2_cache_umd/
82+
83+
# Optional REPL history
84+
85+
.node_repl_history
86+
87+
# Output of 'npm pack'
88+
89+
\*.tgz
90+
91+
# Yarn Integrity file
92+
93+
.yarn-integrity
94+
95+
# dotenv environment variable files
96+
97+
.env
98+
.env.development.local
99+
.env.test.local
100+
.env.production.local
101+
.env.local
102+
103+
# parcel-bundler cache (https://parceljs.org/)
104+
105+
.cache
106+
.parcel-cache
107+
108+
# Next.js build output
109+
110+
.next
111+
out
112+
113+
# Nuxt.js build / generate output
114+
115+
.nuxt
116+
dist
117+
118+
# Gatsby files
119+
120+
.cache/
121+
122+
# Comment in the public line in if your project uses Gatsby and not Next.js
123+
124+
# https://nextjs.org/blog/next-9-1#public-directory-support
125+
126+
# public
127+
128+
# vuepress build output
129+
130+
.vuepress/dist
131+
132+
# vuepress v2.x temp and cache directory
133+
134+
.temp
135+
.cache
136+
137+
# Docusaurus cache and generated files
138+
139+
.docusaurus
140+
141+
# Serverless directories
142+
143+
.serverless/
144+
145+
# FuseBox cache
146+
147+
.fusebox/
148+
149+
# DynamoDB Local files
150+
151+
.dynamodb/
152+
153+
# TernJS port file
154+
155+
.tern-port
156+
157+
# Stores VSCode versions used for testing VSCode extensions
158+
159+
.vscode-test
160+
161+
# yarn v2
162+
163+
.yarn/cache
164+
.yarn/unplugged
165+
.yarn/build-state.yml
166+
.yarn/install-state.gz
167+
.pnp.\*
168+
169+
# wrangler project
170+
171+
.dev.vars
172+
.wrangler/

packages/cloudflare-worker/env.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module "*.html" {
2+
const content: string;
3+
export default content;
4+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"private": true,
3+
"name": "cloudflare-worker",
4+
"version": "0.0.0",
5+
"scripts": {
6+
"deploy": "wrangler deploy",
7+
"dev": "wrangler dev",
8+
"start": "wrangler dev",
9+
"build": "esbuild src/index.ts --outfile=dist/worker.js --bundle --format=esm --loader:.html=text --keep-names",
10+
"test": "vitest",
11+
"cf-typegen": "wrangler types"
12+
},
13+
"devDependencies": {
14+
"@cloudflare/vitest-pool-workers": "^0.5.36",
15+
"@cloudflare/workers-types": "^4.20241205.0",
16+
"esbuild": "^0.24.0",
17+
"typescript": "^5.7.2",
18+
"vitest": "2.1.8",
19+
"wrangler": "^3.95.0"
20+
},
21+
"dependencies": {
22+
"hono": "^4.6.14",
23+
"leetcode-card": "workspace:*"
24+
}
25+
}

src/cloudflare-worker/demo/index.ts packages/cloudflare-worker/src/demo/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { supported as themes } from "../../core/exts/theme";
1+
import { supported as themes } from "leetcode-card";
22
import html from "./demo.html";
33
import { fonts } from "./google-fonts";
44

Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
import { Router } from "itty-router";
2-
import { Config, Generator } from "../core";
1+
import { Hono } from "hono";
2+
import { cors } from "hono/cors";
3+
import { Config, Generator } from "leetcode-card";
34
import demo from "./demo";
45
import Header from "./headers";
56
import { sanitize } from "./sanitize";
67

7-
const router = Router();
8+
const app = new Hono().use("*", cors());
89

9-
router.get("/favicon.ico", async () => {
10-
return Response.redirect(
10+
app.get("/favicon.ico", (c) => {
11+
return c.redirect(
1112
"https://raw.githubusercontent.com/JacobLinCool/leetcode-stats-card/main/favicon/leetcode.ico",
1213
301,
1314
);
1415
});
1516

16-
async function generate(config: Record<string, string>, req: Request): Promise<Response> {
17+
async function generate(
18+
config: Record<string, string>,
19+
header: Record<string, string>,
20+
): Promise<Response> {
1721
let sanitized: Config;
1822
try {
1923
sanitized = sanitize(config);
@@ -27,9 +31,7 @@ async function generate(config: Record<string, string>, req: Request): Promise<R
2731
const cache_time = parseInt(config.cache || "300") ?? 300;
2832
const cache = await caches.open("leetcode");
2933

30-
const generator = new Generator(cache, {
31-
"user-agent": req.headers.get("user-agent") || "Unknown",
32-
});
34+
const generator = new Generator(cache, header);
3335
generator.verbose = true;
3436

3537
const headers = new Header().add("cors", "svg");
@@ -39,26 +41,34 @@ async function generate(config: Record<string, string>, req: Request): Promise<R
3941
}
4042

4143
// handle path variable
42-
router.get("/:username", async (request) => {
43-
request.query.username = request.params.username;
44-
return await generate(request.query as never, request);
44+
app.get("/:username", async (c) => {
45+
const username = c.req.param("username");
46+
const query = Object.fromEntries(new URL(c.req.url).searchParams);
47+
query.username = username;
48+
return await generate(query, {
49+
"user-agent": c.req.header("user-agent") || "Unknown",
50+
});
4551
});
4652

4753
// handle query string
48-
router.get("*", async (req: { query: Record<string, string> }) => {
49-
if (!req.query.username) {
54+
app.get("*", async (c) => {
55+
const query = Object.fromEntries(new URL(c.req.url).searchParams);
56+
57+
if (!query.username) {
5058
return new Response(demo, {
5159
headers: new Header().add("cors", "html"),
5260
});
5361
}
5462

55-
return await generate(req.query, req as unknown as Request);
63+
return await generate(query, {
64+
"user-agent": c.req.header("user-agent") || "Unknown",
65+
});
5666
});
5767

5868
// 404 for all other routes
59-
router.all("*", () => new Response("Not Found.", { status: 404 }));
69+
app.all("*", () => new Response("Not Found.", { status: 404 }));
6070

6171
export async function handle(request: Request): Promise<Response> {
6272
console.log(`${request.method} ${request.url}`);
63-
return router.handle(request);
73+
return app.fetch(request);
6474
}
File renamed without changes.
File renamed without changes.

src/cloudflare-worker/sanitize.ts packages/cloudflare-worker/src/sanitize.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
HeatmapExtension,
88
RemoteStyleExtension,
99
ThemeExtension,
10-
} from "../core";
10+
} from "leetcode-card";
1111
import { booleanize, normalize } from "./utils";
1212

1313
export function sanitize(config: Record<string, string>): Config {
File renamed without changes.

0 commit comments

Comments
 (0)