import { Hono } from "hono"; import { env } from "hono/adapter"; import mapKeys from "lodash.mapkeys"; import { DateTime } from "luxon"; import { Case, changeStringCase } from "~/libs/changeStringCase"; import type { AdminSdkCredentials } from "~/libs/fcm/getGoogleAuthToken"; import { sendFcmMessage } from "~/libs/fcm/sendFcmMessage"; import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader"; import { readEnvVariable } from "~/libs/readEnvVariable"; import type { Env } from "~/types/env"; import { ErrorResponse, SuccessResponse } from "~/types/schema"; import { getUpcomingTitlesFromAnilist } from "./anilist"; const app = new Hono(); app.post("/", async (c) => { if ( !(await verifyQstashHeader( env(c, "workerd"), c.req.path, c.req.header("Upstash-Signature"), await c.req.text(), )) ) { return c.json(ErrorResponse, { status: 401 }); } const titles = await getUpcomingTitlesFromAnilist( env(c, "workerd"), ); await Promise.all( titles.map(async (title) => { const titleName = title.media.title?.userPreferred ?? title.media.title?.english ?? "Unknown Title"; return sendFcmMessage( mapKeys( readEnvVariable(c.env, "ADMIN_SDK_JSON"), (_, key) => changeStringCase(key, Case.snake_case, Case.camelCase), ) as unknown as AdminSdkCredentials, { topic: "newTitles", data: { type: "new_title", aniListId: title.media.id.toString(), title: titleName, airingAt: title.airingAt.toString(), }, notification: { title: "New Series Alert", body: `${titleName} will be released ${DateTime.fromSeconds(title.airingAt).toRelative({ unit: ["days", "hours", "minutes"] })}`, image: title.media.coverImage?.medium ?? title.media.coverImage?.large ?? title.media.coverImage?.extraLarge ?? undefined, }, android: { notification: { click_action: "HANDLE_FCM_NOTIFICATION", }, }, }, ); }), ); return c.json(SuccessResponse, 200); }); export default app;