Skip to content

Commit de9631c

Browse files
authored
Merge pull request #15 from mojisdev/r2
feat: use r2 for data storage
2 parents 955e4d9 + 93643f2 commit de9631c

13 files changed

+124
-66
lines changed

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "api.mojis.dev",
33
"type": "module",
44
"private": true,
5-
"packageManager": "[email protected].4",
5+
"packageManager": "[email protected].5",
66
"scripts": {
77
"dev": "wrangler dev",
88
"build": "wrangler deploy --dry-run --outdir=dist",
@@ -18,20 +18,20 @@
1818
"dependencies": {
1919
"@hono/zod-openapi": "^0.19.2",
2020
"@mojis/internal-utils": "^0.0.5",
21-
"@scalar/hono-api-reference": "^0.7.1",
21+
"@scalar/hono-api-reference": "^0.7.2",
2222
"hono": "^4.7.4",
2323
"zod": "^3.24.2"
2424
},
2525
"devDependencies": {
26-
"@cloudflare/vitest-pool-workers": "^0.8.1",
26+
"@cloudflare/vitest-pool-workers": "^0.8.2",
2727
"@luxass/eslint-config": "^4.17.1",
2828
"@stoplight/spectral-cli": "^6.14.3",
2929
"eslint": "^9.22.0",
3030
"eslint-plugin-format": "^1.0.1",
3131
"tsx": "^4.19.3",
3232
"typescript": "^5.8.2",
3333
"vitest": "^3.0.9",
34-
"wrangler": "^4.1.0"
34+
"wrangler": "^4.2.0"
3535
},
3636
"pnpm": {
3737
"onlyBuiltDependencies": [

pnpm-lock.yaml

+29-29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cache.ts

-1
This file was deleted.

src/routes/gateway_github.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import type { HonoContext } from "../types";
22
import { OpenAPIHono } from "@hono/zod-openapi";
3-
import { cache, createError } from "../utils";
3+
import { cache } from "hono/cache";
4+
import { createError } from "../utils";
45
import { GITHUB_EMOJIS_ROUTE } from "./gateway_github.openapi";
56

67
export const GATEWAY_GITHUB_ROUTER = new OpenAPIHono<HonoContext>().basePath("/api/gateway/github");
78

9+
GATEWAY_GITHUB_ROUTER.get("*", cache({
10+
cacheName: "github-emojis",
11+
cacheControl: "max-age=3600, immutable",
12+
}));
813
GATEWAY_GITHUB_ROUTER.openapi(GITHUB_EMOJIS_ROUTE, async (c) => {
914
const response = await fetch("https://api.github.com/emojis", {
1015
headers: {
@@ -24,7 +29,5 @@ GATEWAY_GITHUB_ROUTER.openapi(GITHUB_EMOJIS_ROUTE, async (c) => {
2429

2530
const emojis = await response.json<Record<string, string>>();
2631

27-
cache(c, 3600, true);
28-
2932
return c.json(emojis, 200);
3033
});

src/routes/random-emoji.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import type { HonoContext } from "../types";
22
import { Hono } from "hono";
3-
import { cache } from "../utils";
3+
import { cache } from "hono/cache";
44

55
export const RANDOM_EMOJI_ROUTER = new Hono<HonoContext>();
66

7-
RANDOM_EMOJI_ROUTER.get("/random-emoji.png", async (c) => {
8-
cache(c, 60 * 60);
9-
return c.redirect("https://image.luxass.dev/api/image/emoji");
10-
});
7+
RANDOM_EMOJI_ROUTER.get(
8+
"/random-emoji.png",
9+
cache({
10+
cacheName: "random-emoji",
11+
cacheControl: "max-age=3600, immutable",
12+
}),
13+
async (c) => {
14+
return c.redirect("https://image.luxass.dev/api/image/emoji");
15+
},
16+
);

src/routes/v1_categories.ts

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { HonoContext } from "../types";
22
import { OpenAPIHono, z } from "@hono/zod-openapi";
3+
import { cache } from "hono/cache";
4+
import { HTTPException } from "hono/http-exception";
35
import { versionMiddleware } from "../middlewares/version";
46
import { EmojiCategorySchema } from "../schemas";
57
import { createError } from "../utils";
@@ -9,19 +11,24 @@ export const V1_CATEGORIES_ROUTER = new OpenAPIHono<HonoContext>().basePath("/ap
911

1012
V1_CATEGORIES_ROUTER.use(versionMiddleware);
1113

14+
V1_CATEGORIES_ROUTER.get("*", cache({
15+
cacheName: "v1-categories",
16+
cacheControl: "max-age=3600, immutable",
17+
}));
18+
1219
V1_CATEGORIES_ROUTER.openapi(ALL_CATEGORIES_ROUTE, async (c) => {
1320
const version = c.req.param("version");
1421

15-
const res = await fetch(`https://raw.githubusercontent.com/mojisdev/emoji-data/refs/heads/main/data/v${version}/groups.json`);
16-
17-
if (!res.ok) {
18-
return createError(c, 500, "failed to fetch categories");
22+
const res = await c.env.EMOJI_DATA.get(`v${version}/groups.json`);
23+
if (res == null) {
24+
throw new HTTPException(500, {
25+
message: "failed to fetch categories",
26+
});
1927
}
2028

2129
const data = await res.json();
2230

2331
const result = z.array(EmojiCategorySchema).safeParse(data);
24-
2532
if (!result.success) {
2633
return createError(c, 500, "failed to parse categories");
2734
}
@@ -38,10 +45,12 @@ V1_CATEGORIES_ROUTER.openapi(GET_CATEGORY_ROUTE, async (c) => {
3845
const version = c.req.param("version");
3946
const categorySlug = c.req.param("category");
4047

41-
const res = await fetch(`https://raw.githubusercontent.com/mojisdev/emoji-data/refs/heads/main/data/v${version}/groups.json`);
48+
const res = await c.env.EMOJI_DATA.get(`v${version}/groups.json`);
4249

43-
if (!res.ok) {
44-
return createError(c, 500, "failed to fetch categories");
50+
if (res == null) {
51+
throw new HTTPException(500, {
52+
message: "failed to fetch categories",
53+
});
4554
}
4655

4756
const data = await res.json();

src/utils.ts

-12
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,3 @@ export async function getAvailableVersions(): Promise<EmojiLock["versions"]> {
3232

3333
return result.data.versions;
3434
}
35-
36-
export function cache<TCtx extends Context>(ctx: TCtx, age: number, immutable = false) {
37-
if (age === -1) {
38-
ctx.header("Expires", "0");
39-
ctx.header("Pragma", "no-cache");
40-
ctx.header("Cache-Control", "no-cache, no-store, must-revalidate");
41-
return;
42-
}
43-
44-
ctx.header("Expires", new Date(Date.now() + age * 1000).toUTCString());
45-
ctx.header("Cache-Control", ["public", `max-age=${age}`, immutable ? "immutable" : null].filter((x) => !!x).join(", "));
46-
};

test/routes/v1_categories.test.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,36 @@ import {
44
env,
55
waitOnExecutionContext,
66
} from "cloudflare:test";
7-
import { describe, expect, it } from "vitest";
7+
import { beforeAll, describe, expect, it } from "vitest";
88
import worker from "../../src";
99

10+
beforeAll(async () => {
11+
await env.EMOJI_DATA.put("v15.1/groups.json", JSON.stringify([
12+
{
13+
name: "Smileys & Emotion",
14+
slug: "smileys-emotion",
15+
subgroups: [
16+
"face-smiling",
17+
"face-affection",
18+
"face-tongue",
19+
"face-hand",
20+
"face-neutral-skeptical",
21+
"face-sleepy",
22+
"face-unwell",
23+
"face-hat",
24+
"face-glasses",
25+
"face-concerned",
26+
"face-negative",
27+
"face-costume",
28+
"cat-face",
29+
"monkey-face",
30+
"heart",
31+
"emotion",
32+
],
33+
},
34+
]));
35+
});
36+
1037
describe("v1_categories", () => {
1138
it("should return 404 for non-existent version", async () => {
1239
const request = new Request("https://api.mojis.dev/api/v1/categories/999.0");

tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"resolveJsonModule": true,
88
"types": [
99
"./worker-configuration.d.ts",
10+
"./worker-configuration-test.d.ts",
1011
// for `cloudflare:test` types
1112
"@cloudflare/vitest-pool-workers"
1213
],

vitest.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default defineWorkersProject({
66
poolOptions: {
77
workers: {
88
singleWorker: true,
9+
isolatedStorage: true,
910
miniflare: {
1011
compatibilityFlags: ["nodejs_compat"],
1112
bindings: {

worker-configuration-test.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module "cloudflare:test" {
2+
// eslint-disable-next-line ts/no-empty-object-type
3+
interface ProvidedEnv extends CloudflareBindings {
4+
}
5+
}

worker-configuration.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Generated by Wrangler by running `wrangler types --env-interface CloudflareBindings` (hash: e71cf0de9c927e7e3f2e02a5b583aba3)
1+
// Generated by Wrangler by running `wrangler types --env-interface CloudflareBindings` (hash: c476c03844aa0429b0aacf2d2d7c8815)
22
// Runtime types generated with [email protected] 2025-03-13
33
declare namespace Cloudflare {
44
interface Env {
55
API_VERSION: "x.y.z";
66
ENVIRONMENT: "preview" | "production";
77
GITHUB_TOKEN: string;
8+
EMOJI_DATA: R2Bucket;
89
}
910
}
1011
interface CloudflareBindings extends Cloudflare.Env {}

0 commit comments

Comments
 (0)