Also apply basic linting to Netlify functions

This commit is contained in:
Taevas 2024-04-27 18:45:18 +02:00
parent 3d38ba1768
commit eb85319f73
11 changed files with 272 additions and 258 deletions

View file

@ -15,6 +15,10 @@ export default [
...compat.extends("xo-typescript"), ...compat.extends("xo-typescript"),
pluginReactConfig, pluginReactConfig,
{ {
files: [
"**/*.ts",
"**/*.tsx"
],
languageOptions: { languageOptions: {
globals: globals.node globals: globals.node
}, },
@ -33,13 +37,10 @@ export default [
}, },
{ {
ignores: [ ignores: [
"**/.netlify/*", ".netlify/*",
"**/dist/*", "dist/*",
"eslint.config.js", "*.js",
"eslintrc.js", "*.cjs"
"postcss.config.cjs", ],
"tailwind.config.js",
"vite.config.js"
]
} }
]; ];

View file

@ -1,6 +0,0 @@
module.exports = {
"extends": [
"eslint:recommended",
"plugin:react/recommended"
]
}

View file

@ -1,13 +1,13 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import fetch from "node-fetch" import fetch from "node-fetch";
import { AnilistInfo } from '../../src/components/infos/Anilist' import {type AnilistInfo} from "../../src/components/Info/Anilist.js";
const handler: Handler = async () => { const handler: Handler = async () => {
const anilist = await fetch("https://graphql.anilist.co", { const anilist = await fetch("https://graphql.anilist.co", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"Accept": "application/json" "Accept": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
query: ` query: `
@ -40,21 +40,21 @@ const handler: Handler = async () => {
} }
`, `,
variables: { variables: {
userName: "Taevas" userName: "Taevas",
} },
}) }),
}) });
if (anilist.status !== 200) { if (anilist.status !== 200) {
// log the issue in netlify, return 404 to the user anyway // log the issue in netlify, return 404 to the user anyway
console.log(await anilist.json()) console.log(await anilist.json());
return { return {
statusCode: 404, statusCode: 404,
body: "" body: "",
} };
} }
const p_json = await anilist.json() as {[key: string]: any} const p_json = await anilist.json() as Record<string, any>;
const json = p_json.data.MediaList const json = p_json.data.MediaList;
const anime: AnilistInfo = { const anime: AnilistInfo = {
title: json.media.title.romaji, title: json.media.title.romaji,
episodes: { episodes: {
@ -66,17 +66,17 @@ const handler: Handler = async () => {
updateDate: new Date(json.updatedAt * 1000).toISOString(), updateDate: new Date(json.updatedAt * 1000).toISOString(),
endDate: json.completedAt.year ? new Date(`${json.completedAt.year}-${json.completedAt.month}-${json.completedAt.day}`).toISOString() : new Date().toISOString(), endDate: json.completedAt.year ? new Date(`${json.completedAt.year}-${json.completedAt.month}-${json.completedAt.day}`).toISOString() : new Date().toISOString(),
cover: json.media.coverImage.medium, cover: json.media.coverImage.medium,
url: json.media.siteUrl url: json.media.siteUrl,
} };
anime.startDate = anime.startDate.substring(0, anime.startDate.indexOf("T")) anime.startDate = anime.startDate.substring(0, anime.startDate.indexOf("T"));
anime.updateDate = anime.updateDate.substring(0, anime.updateDate.indexOf("T")) anime.updateDate = anime.updateDate.substring(0, anime.updateDate.indexOf("T"));
anime.endDate = anime.endDate.substring(0, anime.endDate.indexOf("T")) anime.endDate = anime.endDate.substring(0, anime.endDate.indexOf("T"));
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(anime) body: JSON.stringify(anime),
} };
} };
export { handler } export {handler};

View file

@ -1,40 +1,40 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import { Octokit } from '@octokit/core' import {Octokit} from "@octokit/core";
import { GithubInfo } from '../../src/components/infos/Git' import {type GithubInfo} from "../../src/components/Info/Git.js";
const handler: Handler = async () => { const handler: Handler = async () => {
const octokit = new Octokit({auth: process.env.API_GITHUB}) const octokit = new Octokit({auth: process.env.API_GITHUB});
const github = await octokit.request("GET /users/TTTaevas/events", {per_page: 100}) const github = await octokit.request("GET /users/TTTaevas/events", {per_page: 100});
if (github.status !== 200) { if (github.status !== 200) {
return { return {
statusCode: 404, statusCode: 404,
body: "" body: "",
} };
} }
const public_push = github.data.find((e: {type: string, public: boolean}) => e.type === "PushEvent" && e.public === true) const public_push = github.data.find((e: {type: string; public: boolean}) => e.type === "PushEvent" && e.public);
const private_push = github.data.find((e: {type: string, public: boolean}) => e.type === "PushEvent" && e.public === false) const private_push = github.data.find((e: {type: string; public: boolean}) => e.type === "PushEvent" && !e.public);
if (!public_push || !private_push) { if (!public_push || !private_push) {
return { return {
statusCode: 404, statusCode: 404,
body: "" body: "",
} };
} }
const info: GithubInfo = { const info: GithubInfo = {
public: { public: {
repo: public_push.repo.name, repo: public_push.repo.name,
date: public_push.created_at.substring(0, public_push.created_at.indexOf("T")) date: public_push.created_at.substring(0, public_push.created_at.indexOf("T")),
}, },
private: { private: {
date: private_push.created_at.substring(0, private_push.created_at.indexOf("T")) date: private_push.created_at.substring(0, private_push.created_at.indexOf("T")),
} },
} };
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(info) body: JSON.stringify(info),
} };
} };
export { handler } export {handler};

View file

@ -1,6 +1,6 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import fetch from "node-fetch" import fetch from "node-fetch";
import { GitlabInfo } from '../../src/components/infos/Git' import {type GitlabInfo} from "../../src/components/Info/Git.js";
const handler: Handler = async () => { const handler: Handler = async () => {
const gitlab = await fetch("https://gitlab.com/api/v4/events?action=pushed", { const gitlab = await fetch("https://gitlab.com/api/v4/events?action=pushed", {
@ -8,26 +8,26 @@ const handler: Handler = async () => {
headers: { headers: {
"PRIVATE-TOKEN": process.env.API_GITLAB!, "PRIVATE-TOKEN": process.env.API_GITLAB!,
"Content-Type": "application/json", "Content-Type": "application/json",
"Accept": "application/json" "Accept": "application/json",
} },
}) });
if (gitlab.status !== 200) { if (gitlab.status !== 200) {
return { return {
statusCode: 404, statusCode: 404,
body: "" body: "",
} };
} }
const json = await gitlab.json() as {[key: string]: any} const json = await gitlab.json() as Record<string, any>;
const activity: GitlabInfo = { const activity: GitlabInfo = {
date: json[0].created_at.substring(0, json[0].created_at.indexOf("T")) date: json[0].created_at.substring(0, json[0].created_at.indexOf("T")),
} };
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(activity) body: JSON.stringify(activity),
} };
} };
export { handler } export {handler};

View file

@ -1,30 +1,30 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import { api } from "./shared/api" import {api} from "./shared/api.js";
import { HacktheboxInfo } from '../../src/components/infos/Hackthebox' import {type HacktheboxInfo} from "../../src/components/Info/Hackthebox.js";
const handler: Handler = async () => { const handler: Handler = async () => {
const hackthebox: {profile: {activity: HacktheboxInfo[]}} = await api<{ const hackthebox: {profile: {activity: HacktheboxInfo[]}} = await api<{
profile: { profile: {
activity: HacktheboxInfo[] activity: HacktheboxInfo[];
} };
}> }>
(`https://www.hackthebox.com/api/v4/profile/activity/1063999`) ("https://www.hackthebox.com/api/v4/profile/activity/1063999");
const pwn = hackthebox.profile.activity.find((a: HacktheboxInfo) => a!.object_type === "machine") const pwn = hackthebox.profile.activity.find((a: HacktheboxInfo) => a!.object_type === "machine");
if (!pwn) { if (!pwn) {
return { return {
statusCode: 404, statusCode: 404,
body: "" body: "",
} };
} }
pwn.machine_avatar = `https://www.hackthebox.com${pwn.machine_avatar}` pwn.machine_avatar = `https://www.hackthebox.com${pwn.machine_avatar}`;
pwn.date = pwn.date.substring(0, pwn.date.indexOf("T")) pwn.date = pwn.date.substring(0, pwn.date.indexOf("T"));
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(pwn) body: JSON.stringify(pwn),
} };
} };
export { handler } export {handler};

View file

@ -1,45 +1,45 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import { api } from "./shared/api" import {api} from "./shared/api.js";
import { LastfmInfo } from '../../src/components/infos/Lastfm' import {type LastfmInfo} from "../../src/components/Info/Lastfm.js";
const handler: Handler = async () => { const handler: Handler = async () => {
const lastfm = await api<{ const lastfm = await api<{
recenttracks: { recenttracks: {
track: { track: Array<{
artist: { artist: {
"#text": string "#text": string;
}, };
image: { image: Array<{
size: string, size: string;
"#text": string "#text": string;
}[] }>;
album: { album: {
"#text": string "#text": string;
}, };
name: string, name: string;
"@attr"?: { "@attr"?: {
nowplaying?: string nowplaying?: string;
} };
url: string url: string;
}[] }>;
} };
}> }>
(`http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=TTTaevas&api_key=${process.env["API_LASTFM"]}&format=json&limit=1`) (`http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=TTTaevas&api_key=${process.env.API_LASTFM}&format=json&limit=1`);
const image = lastfm.recenttracks.track[0].image.find((i) => i.size == "large") const image = lastfm.recenttracks.track[0].image.find((i) => i.size == "large");
const track: LastfmInfo = { const track: LastfmInfo = {
artist: lastfm.recenttracks.track[0].artist['#text'], artist: lastfm.recenttracks.track[0].artist["#text"],
name: lastfm.recenttracks.track[0].name, name: lastfm.recenttracks.track[0].name,
album: lastfm.recenttracks.track[0].album['#text'], album: lastfm.recenttracks.track[0].album["#text"],
image: image ? image['#text'] : "", image: image ? image["#text"] : "",
listening: Boolean(lastfm.recenttracks.track[0]['@attr']?.nowplaying), listening: Boolean(lastfm.recenttracks.track[0]["@attr"]?.nowplaying),
url: lastfm.recenttracks.track[0].url url: lastfm.recenttracks.track[0].url,
} };
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(track) body: JSON.stringify(track),
} };
} };
export { handler } export {handler};

View file

@ -1,40 +1,48 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import * as osu from 'osu-api-v2-js' import * as osu from "osu-api-v2-js";
import { OsuInfo } from '../../src/components/infos/Osu' import {type OsuInfo} from "../../src/components/Info/Osu.js";
const handler: Handler = async () => { const handler: Handler = async () => {
const api = await osu.API.createAsync({id: 11451, secret: process.env.API_OSU!}) const api = await osu.API.createAsync({id: 11451, secret: process.env.API_OSU!});
const profile = await Promise.all([ const profile = await Promise.all([
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.osu))), new Promise((resolve) => {
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.taiko))), resolve(api.getUser(7276846, osu.Ruleset.osu));
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.fruits))), }),
new Promise((resolve) => resolve(api.getUser(7276846, osu.Ruleset.mania))) new Promise((resolve) => {
]) as osu.User.Extended[] resolve(api.getUser(7276846, osu.Ruleset.taiko));
}),
new Promise((resolve) => {
resolve(api.getUser(7276846, osu.Ruleset.fruits));
}),
new Promise((resolve) => {
resolve(api.getUser(7276846, osu.Ruleset.mania));
}),
]) as osu.User.Extended[];
const info: OsuInfo = { const info: OsuInfo = {
country: (profile[0]).country.name || "Unknown", country: (profile[0]).country.name || "Unknown",
osu: {global: 0, country: 0}, osu: {global: 0, country: 0},
taiko: {global: 0, country: 0}, taiko: {global: 0, country: 0},
fruits: {global: 0, country: 0}, fruits: {global: 0, country: 0},
mania: {global: 0, country: 0} mania: {global: 0, country: 0},
} };
for (let i = 0; i < profile.length; i++) { for (let i = 0; i < profile.length; i++) {
const ruleset = profile[i] const ruleset = profile[i];
if (ruleset.rank_history) { if (ruleset.rank_history) {
const stats = ruleset.statistics const stats = ruleset.statistics;
info[ruleset.rank_history.mode].global = stats.global_rank || 0 info[ruleset.rank_history.mode].global = stats.global_rank || 0;
info[ruleset.rank_history.mode].country = stats.country_rank || 0 info[ruleset.rank_history.mode].country = stats.country_rank || 0;
} }
} }
api.revokeToken() api.revokeToken();
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(info) body: JSON.stringify(info),
} };
} };
export { handler } export {handler};

View file

@ -1,12 +1,14 @@
import fetch from "node-fetch" import fetch from "node-fetch";
export async function api<T>(url: string, restful_token?: string): Promise<T> { export async function api<T>(url: string, restful_token?: string): Promise<T> {
// eslint-disable-next-line @typescript-eslint/naming-convention
return (restful_token ? fetch(url, {headers: {"Authorization": `Bearer ${restful_token}`}}) : fetch(url)) return (restful_token ? fetch(url, {headers: {"Authorization": `Bearer ${restful_token}`}}) : fetch(url))
.then(response => { .then(async response => {
if (!response.ok) { if (!response.ok) {
console.error(response.status, response.statusText) console.error(response.status, response.statusText);
throw new Error("Request failed :(") throw new Error("Request failed :(");
} }
return response.json() as Promise<T>
}) return response.json() as Promise<T>;
});
} }

View file

@ -1,62 +1,62 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import { api } from "./shared/api" import {api} from "./shared/api.js";
import { SpeedruncomInfo } from '../../src/components/infos/Speedruncom' import {type SpeedruncomInfo} from "../../src/components/Info/Speedruncom.js";
const handler: Handler = async () => { const handler: Handler = async () => {
// using the API's embedding would be stupid here, as that'd create lag due to irrelevant runs // using the API's embedding would be stupid here, as that'd create lag due to irrelevant runs
const speedruncom = await api<{ const speedruncom = await api<{
data: { data: Array<{
place: number, place: number;
run: { run: {
weblink: string weblink: string;
game: string game: string;
level: string | null level: string | undefined;
category: string | null category: string | undefined;
date: string date: string;
} };
}[] }>;
}> }>
(`https://www.speedrun.com/api/v1/users/j03v45mj/personal-bests`) ("https://www.speedrun.com/api/v1/users/j03v45mj/personal-bests");
const details_to_request = [new Promise((resolve) => { const details_to_request = [new Promise((resolve) => {
resolve(api<{ resolve(api<{
data: { data: {
names: { names: {
international: string international: string;
} };
assets: { assets: {
"cover-tiny": { "cover-tiny": {
uri: string uri: string;
} };
} };
} };
}> }>
(`https://www.speedrun.com/api/v1/games/${speedruncom.data[0].run.game}`)) (`https://www.speedrun.com/api/v1/games/${speedruncom.data[0].run.game}`));
})] })];
if (speedruncom.data[0].run.level) { if (speedruncom.data[0].run.level) {
details_to_request.push(new Promise((resolve) => { details_to_request.push(new Promise((resolve) => {
resolve(api<{ resolve(api<{
data: { data: {
name: string name: string;
} };
}> }>
(`https://www.speedrun.com/api/v1/levels/${speedruncom.data[0].run.level}`)) (`https://www.speedrun.com/api/v1/levels/${speedruncom.data[0].run.level}`));
})) }));
} }
if (speedruncom.data[0].run.category) { if (speedruncom.data[0].run.category) {
details_to_request.push(new Promise((resolve) => { details_to_request.push(new Promise((resolve) => {
resolve(api<{ resolve(api<{
data: { data: {
name: string name: string;
} };
}> }>
(`https://www.speedrun.com/api/v1/categories/${speedruncom.data[0].run.category}`)) (`https://www.speedrun.com/api/v1/categories/${speedruncom.data[0].run.category}`));
})) }));
} }
const details = await Promise.all(details_to_request) as [{[key: string]: any}] const details = await Promise.all(details_to_request) as [Record<string, any>];
const run: SpeedruncomInfo = { const run: SpeedruncomInfo = {
place: speedruncom.data[0].place, place: speedruncom.data[0].place,
@ -64,13 +64,13 @@ const handler: Handler = async () => {
date: speedruncom.data[0].run.date, date: speedruncom.data[0].run.date,
thumbnail: details[0].data.assets["cover-tiny"].uri, thumbnail: details[0].data.assets["cover-tiny"].uri,
game: details[0].data.names.international, game: details[0].data.names.international,
details: details.slice(1).map((d) => d.data.name) || [] details: details.slice(1).map((d) => d.data.name) || [],
} };
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(run) body: JSON.stringify(run),
} };
} };
export { handler } export {handler};

View file

@ -1,37 +1,37 @@
import { Handler } from '@netlify/functions' import {type Handler} from "@netlify/functions";
import { api } from "./shared/api" import {api} from "./shared/api.js";
import { WanikaniInfo } from '../../src/components/infos/Wanikani' import {type WanikaniInfo} from "../../src/components/Info/Wanikani.js";
type Subject = { type Subject = {
id: number id: number;
object: string object: string;
data: { data: {
characters: string characters: string;
slug: string slug: string;
document_url: string document_url: string;
meanings: { meanings: Array<{
meaning: string meaning: string;
}[] }>;
} };
} };
function addStuffToLearn(ids: number[], data: {available_at: string, subject_ids: number[]}[], subjects: Subject[]): { function addStuffToLearn(ids: number[], data: Array<{available_at: string; subject_ids: number[]}>, subjects: Subject[]): Array<{
available_at: string available_at: string;
type: string type: string;
writing: string writing: string;
meanings: [{ meanings: [{
meaning: string meaning: string;
}] }];
url: string url: string;
}[] { }> {
const arr: any[] = [] const arr: any[] = [];
for (let i = 0; i < ids.length; i++) { for (let i = 0; i < ids.length; i++) {
const summary_data = data.find(lesson => lesson.subject_ids.includes(ids[i])) const summary_data = data.find(lesson => lesson.subject_ids.includes(ids[i]));
const subject = subjects.find(subject => subject.id === ids[i]) const subject = subjects.find(subject => subject.id === ids[i]);
if (!summary_data || !subject) { if (!summary_data || !subject) {
console.error("Failed: ", summary_data, subject) console.error("Failed: ", summary_data, subject);
continue continue;
} }
arr.push({ arr.push({
@ -39,95 +39,104 @@ function addStuffToLearn(ids: number[], data: {available_at: string, subject_ids
type: subject.object, type: subject.object,
writing: subject.data.characters || subject.data.slug || subject.data.meanings[0].meaning, writing: subject.data.characters || subject.data.slug || subject.data.meanings[0].meaning,
meanings: subject.data.meanings, meanings: subject.data.meanings,
url: subject.data.document_url url: subject.data.document_url,
}) });
} }
return arr return arr;
} }
const handler: Handler = async () => { const handler: Handler = async () => {
const data: any[] = await Promise.all([ const data: any[] = await Promise.all([
new Promise((resolve) => resolve(api("https://api.wanikani.com/v2/level_progressions", process.env["API_WANIKANI"]))), new Promise((resolve) => {
new Promise((resolve) => resolve(api("https://api.wanikani.com/v2/resets", process.env["API_WANIKANI"]))), resolve(api("https://api.wanikani.com/v2/level_progressions", process.env.API_WANIKANI));
new Promise((resolve) => resolve(api("https://api.wanikani.com/v2/summary", process.env["API_WANIKANI"]))) }),
]) new Promise((resolve) => {
resolve(api("https://api.wanikani.com/v2/resets", process.env.API_WANIKANI));
}),
new Promise((resolve) => {
resolve(api("https://api.wanikani.com/v2/summary", process.env.API_WANIKANI));
}),
]);
const progression: { const progression: {
total_count: number total_count: number;
data: Array<{
data: { data: {
data: { level: number;
level: number unlocked_at: undefined | string;
unlocked_at: null | string completed_at: undefined | string;
completed_at: null | string abandoned_at: undefined | string;
abandoned_at: null| string };
} }>;
}[] } = data[0];
} = data[0]
const resets: { const resets: {
data: [{ data: [{
data: { data: {
created_at: string created_at: string;
original_level: number original_level: number;
target_level: number target_level: number;
} };
}] }];
} = data[1] } = data[1];
const summary: { const summary: {
data: { data: {
lessons: { lessons: Array<{
available_at: string available_at: string;
subject_ids: number[] subject_ids: number[];
}[], }>;
reviews: { reviews: Array<{
available_at: string available_at: string;
subject_ids: number[] subject_ids: number[];
}[], }>;
next_reviews_at: null | string next_reviews_at: undefined | string;
} };
} = data[2] } = data[2];
const subject_ids_lessons: number[] = [] const subject_ids_lessons: number[] = [];
const subject_ids_reviews: number[] = [] const subject_ids_reviews: number[] = [];
for (let i = 0; i < summary.data.lessons.length; i++) { for (let i = 0; i < summary.data.lessons.length; i++) {
for (let e = 0; e < summary.data.lessons[i].subject_ids.length; e++) { for (let e = 0; e < summary.data.lessons[i].subject_ids.length; e++) {
subject_ids_lessons.push(summary.data.lessons[i].subject_ids[e]) subject_ids_lessons.push(summary.data.lessons[i].subject_ids[e]);
}
}
for (let i = 0; i < summary.data.reviews.length; i++) {
for (let e = 0; e < summary.data.reviews[i].subject_ids.length; e++) {
subject_ids_reviews.push(summary.data.reviews[i].subject_ids[e])
} }
} }
const now = new Date() for (let i = 0; i < summary.data.reviews.length; i++) {
for (let e = 0; e < summary.data.reviews[i].subject_ids.length; e++) {
subject_ids_reviews.push(summary.data.reviews[i].subject_ids[e]);
}
}
const now = new Date();
// next_reviews checks what reviews will be available in the next 23 hours // next_reviews checks what reviews will be available in the next 23 hours
// summary.data.next_reviews_at checks beyond that, but will be the current time if a review is already available // summary.data.next_reviews_at checks beyond that, but will be the current time if a review is already available
const next_reviews = summary.data.reviews const next_reviews = summary.data.reviews
.map((r: {subject_ids: number[], available_at: Date | string}) => {r.available_at = new Date(r.available_at); return r}) .map((r: {subject_ids: number[]; available_at: Date | string}) => {
.filter((r) => r.available_at > now && r.subject_ids.length) as {subject_ids: number[], available_at: Date}[] r.available_at = new Date(r.available_at); return r;
const more_things_to_review_at = next_reviews[0] ? next_reviews[0].available_at.toISOString() : summary.data.next_reviews_at ? summary.data.next_reviews_at : null })
.filter((r) => r.available_at > now && r.subject_ids.length) as Array<{subject_ids: number[]; available_at: Date}>;
const more_things_to_review_at = next_reviews[0] ? next_reviews[0].available_at.toISOString() : summary.data.next_reviews_at ? summary.data.next_reviews_at : null;
const subject_ids_all = subject_ids_lessons.concat(subject_ids_reviews) const subject_ids_all = subject_ids_lessons.concat(subject_ids_reviews);
const subjects = await api<{data: Subject[]}>(`https://api.wanikani.com/v2/subjects?ids=${subject_ids_all.toString()}`, process.env["API_WANIKANI"]) const subjects = await api<{data: Subject[]}>(`https://api.wanikani.com/v2/subjects?ids=${subject_ids_all.toString()}`, process.env.API_WANIKANI);
const lessons = addStuffToLearn(subject_ids_lessons, summary.data.lessons, subjects.data) const lessons = addStuffToLearn(subject_ids_lessons, summary.data.lessons, subjects.data);
const reviews = addStuffToLearn(subject_ids_reviews, summary.data.reviews, subjects.data) const reviews = addStuffToLearn(subject_ids_reviews, summary.data.reviews, subjects.data);
const info: WanikaniInfo = { const info: WanikaniInfo = {
progression, progression,
resets: resets.data, resets: resets.data,
lessons, lessons,
reviews, reviews,
more_things_to_review_at more_things_to_review_at,
} };
return { return {
statusCode: 200, statusCode: 200,
body: JSON.stringify(info) body: JSON.stringify(info),
} };
} };
export { handler } export {handler};