From 852efaea50dca7336e4de129b2be91e152c36d9b Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Sun, 10 Mar 2024 13:25:44 -1000 Subject: [PATCH] Rewrite every route to use the new framework --- server/api/api/v1/accounts/[id]/block.ts | 17 ++--- server/api/api/v1/accounts/[id]/follow.ts | 28 +++----- server/api/api/v1/accounts/[id]/followers.ts | 27 +++----- server/api/api/v1/accounts/[id]/following.ts | 27 +++----- server/api/api/v1/accounts/[id]/index.ts | 18 ++---- server/api/api/v1/accounts/[id]/mute.ts | 26 +++----- server/api/api/v1/accounts/[id]/note.ts | 24 +++---- server/api/api/v1/accounts/[id]/pin.ts | 17 ++--- .../v1/accounts/[id]/remove_from_followers.ts | 17 ++--- server/api/api/v1/accounts/[id]/statuses.ts | 34 +++++----- server/api/api/v1/accounts/[id]/unblock.ts | 17 ++--- server/api/api/v1/accounts/[id]/unfollow.ts | 17 ++--- server/api/api/v1/accounts/[id]/unmute.ts | 17 ++--- server/api/api/v1/accounts/[id]/unpin.ts | 17 ++--- .../v1/accounts/familiar_followers/index.ts | 21 +++--- server/api/api/v1/accounts/index.ts | 17 ++--- .../api/v1/accounts/relationships/index.ts | 16 ++--- server/api/api/v1/accounts/search/index.ts | 11 ++-- .../v1/accounts/update_credentials/index.ts | 20 +++--- .../v1/accounts/verify_credentials/index.ts | 11 +--- server/api/api/v1/apps/index.ts | 20 +++--- .../api/v1/apps/verify_credentials/index.ts | 9 ++- server/api/api/v1/blocks/index.ts | 14 ++-- server/api/api/v1/custom_emojis/index.ts | 10 +-- server/api/api/v1/favourites/index.ts | 27 +++----- .../follow_requests/[account_id]/authorize.ts | 14 ++-- .../v1/follow_requests/[account_id]/reject.ts | 14 ++-- server/api/api/v1/follow_requests/index.ts | 32 ++++------ server/api/api/v1/instance/index.ts | 13 ++-- server/api/api/v1/media/[id]/index.ts | 27 +++----- server/api/api/v1/media/index.ts | 29 ++++----- server/api/api/v1/mutes/index.ts | 14 ++-- server/api/api/v1/notifications/index.ts | 34 +++++----- server/api/api/v1/profile/avatar.ts | 14 ++-- server/api/api/v1/profile/header.ts | 14 ++-- server/api/api/v1/statuses/[id]/context.ts | 13 ++-- server/api/api/v1/statuses/[id]/favourite.ts | 13 ++-- .../api/api/v1/statuses/[id]/favourited_by.ts | 32 ++++------ server/api/api/v1/statuses/[id]/index.ts | 49 ++++++-------- server/api/api/v1/statuses/[id]/pin.ts | 13 ++-- server/api/api/v1/statuses/[id]/reblog.ts | 27 +++----- .../api/api/v1/statuses/[id]/reblogged_by.ts | 32 ++++------ server/api/api/v1/statuses/[id]/source.ts | 21 ++---- .../api/api/v1/statuses/[id]/unfavourite.ts | 13 ++-- server/api/api/v1/statuses/[id]/unpin.ts | 14 ++-- server/api/api/v1/statuses/[id]/unreblog.ts | 14 ++-- server/api/api/v1/statuses/index.ts | 64 ++++++++----------- server/api/api/v1/timelines/home.ts | 28 +++----- server/api/api/v1/timelines/public.ts | 34 +++++----- server/api/api/v2/media/index.ts | 29 ++++----- server/api/api/v2/search/index.ts | 40 +++++------- 51 files changed, 413 insertions(+), 707 deletions(-) diff --git a/server/api/api/v1/accounts/[id]/block.ts b/server/api/api/v1/accounts/[id]/block.ts index e0e55252..d1fee876 100644 --- a/server/api/api/v1/accounts/[id]/block.ts +++ b/server/api/api/v1/accounts/[id]/block.ts @@ -1,14 +1,10 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -26,13 +22,10 @@ export const meta = applyConfig({ /** * Blocks a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); @@ -84,4 +77,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/follow.ts b/server/api/api/v1/accounts/[id]/follow.ts index 3d0b37d8..abd75e74 100644 --- a/server/api/api/v1/accounts/[id]/follow.ts +++ b/server/api/api/v1/accounts/[id]/follow.ts @@ -1,15 +1,10 @@ -import { parseRequest } from "@request"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -27,21 +22,18 @@ export const meta = applyConfig({ /** * Follow a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + reblogs?: boolean; + notify?: boolean; + languages?: string[]; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); - const { languages, notify, reblogs } = await parseRequest<{ - reblogs?: boolean; - notify?: boolean; - languages?: string[]; - }>(req); + const { languages, notify, reblogs } = extraData.parsedRequest; const user = await client.user.findUnique({ where: { id }, @@ -103,4 +95,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/followers.ts b/server/api/api/v1/accounts/[id]/followers.ts index af85ffdf..1de86d63 100644 --- a/server/api/api/v1/accounts/[id]/followers.ts +++ b/server/api/api/v1/accounts/[id]/followers.ts @@ -1,8 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { userRelations, userToAPI } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -20,24 +19,16 @@ export const meta = applyConfig({ /** * Fetch all statuses for a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; // TODO: Add pinned - const { - max_id, - min_id, - since_id, - limit = 20, - }: { - max_id?: string; - since_id?: string; - min_id?: string; - limit?: number; - } = matchedRoute.query; + const { max_id, min_id, since_id, limit = 20 } = extraData.parsedRequest; const user = await client.user.findUnique({ where: { id }, @@ -86,4 +77,4 @@ export default async ( Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/following.ts b/server/api/api/v1/accounts/[id]/following.ts index 2f9d8142..a6c25988 100644 --- a/server/api/api/v1/accounts/[id]/following.ts +++ b/server/api/api/v1/accounts/[id]/following.ts @@ -1,8 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { userRelations, userToAPI } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -20,24 +19,16 @@ export const meta = applyConfig({ /** * Fetch all statuses for a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; // TODO: Add pinned - const { - max_id, - min_id, - since_id, - limit = 20, - }: { - max_id?: string; - since_id?: string; - min_id?: string; - limit?: number; - } = matchedRoute.query; + const { max_id, min_id, since_id, limit = 20 } = extraData.parsedRequest; const user = await client.user.findUnique({ where: { id }, @@ -86,4 +77,4 @@ export default async ( Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/index.ts b/server/api/api/v1/accounts/[id]/index.ts index ee3763cb..b1527eb6 100644 --- a/server/api/api/v1/accounts/[id]/index.ts +++ b/server/api/api/v1/accounts/[id]/index.ts @@ -1,12 +1,7 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import type { UserWithRelations } from "~database/entities/User"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations, userToAPI } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -24,17 +19,14 @@ export const meta = applyConfig({ /** * Fetch a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; // Check if ID is valid UUID if (!id.match(/^[0-9a-fA-F]{24}$/)) { return errorResponse("Invalid ID", 404); } - const { user } = await getFromRequest(req); + const { user } = extraData.auth; let foundUser: UserWithRelations | null; try { @@ -49,4 +41,4 @@ export default async ( if (!foundUser) return errorResponse("User not found", 404); return jsonResponse(userToAPI(foundUser, user?.id === foundUser.id)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/mute.ts b/server/api/api/v1/accounts/[id]/mute.ts index 54dba828..e0790e8c 100644 --- a/server/api/api/v1/accounts/[id]/mute.ts +++ b/server/api/api/v1/accounts/[id]/mute.ts @@ -1,15 +1,10 @@ -import { parseRequest } from "@request"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -27,21 +22,18 @@ export const meta = applyConfig({ /** * Mute a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + notifications: boolean; + duration: number; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { notifications, duration } = await parseRequest<{ - notifications: boolean; - duration: number; - }>(req); + const { notifications, duration } = extraData.parsedRequest; const user = await client.user.findUnique({ where: { id }, @@ -97,4 +89,4 @@ export default async ( // TODO: Implement duration return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/note.ts b/server/api/api/v1/accounts/[id]/note.ts index d67d6bda..b1dc07aa 100644 --- a/server/api/api/v1/accounts/[id]/note.ts +++ b/server/api/api/v1/accounts/[id]/note.ts @@ -1,15 +1,10 @@ -import { parseRequest } from "@request"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -27,19 +22,16 @@ export const meta = applyConfig({ /** * Sets a user note */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + comment: string; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); - const { comment } = await parseRequest<{ - comment: string; - }>(req); + const { comment } = extraData.parsedRequest; const user = await client.user.findUnique({ where: { id }, @@ -87,4 +79,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/pin.ts b/server/api/api/v1/accounts/[id]/pin.ts index 04cdb68e..4e3f398c 100644 --- a/server/api/api/v1/accounts/[id]/pin.ts +++ b/server/api/api/v1/accounts/[id]/pin.ts @@ -1,14 +1,10 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -26,13 +22,10 @@ export const meta = applyConfig({ /** * Pin a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); @@ -84,4 +77,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/remove_from_followers.ts b/server/api/api/v1/accounts/[id]/remove_from_followers.ts index 94e2ddb0..3a3495f3 100644 --- a/server/api/api/v1/accounts/[id]/remove_from_followers.ts +++ b/server/api/api/v1/accounts/[id]/remove_from_followers.ts @@ -1,14 +1,10 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -26,13 +22,10 @@ export const meta = applyConfig({ /** * Removes an account from your followers list */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); @@ -98,4 +91,4 @@ export default async ( } return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/statuses.ts b/server/api/api/v1/accounts/[id]/statuses.ts index 5ba37ec3..b4b5963b 100644 --- a/server/api/api/v1/accounts/[id]/statuses.ts +++ b/server/api/api/v1/accounts/[id]/statuses.ts @@ -1,9 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; import { userRelations } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -21,10 +20,18 @@ export const meta = applyConfig({ /** * Fetch all statuses for a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: string; + only_media?: boolean; + exclude_replies?: boolean; + exclude_reblogs?: boolean; + // TODO: Add with_muted + pinned?: boolean; + tagged?: string; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; // TODO: Add pinned @@ -35,18 +42,7 @@ export default async ( limit = "20", exclude_reblogs, pinned, - }: { - max_id?: string; - since_id?: string; - min_id?: string; - limit?: string; - only_media?: boolean; - exclude_replies?: boolean; - exclude_reblogs?: boolean; - // TODO: Add with_muted - pinned?: boolean; - tagged?: string; - } = matchedRoute.query; + } = extraData.parsedRequest; const user = await client.user.findUnique({ where: { id }, @@ -131,4 +127,4 @@ export default async ( Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/unblock.ts b/server/api/api/v1/accounts/[id]/unblock.ts index ea0139c2..ebfdeeb5 100644 --- a/server/api/api/v1/accounts/[id]/unblock.ts +++ b/server/api/api/v1/accounts/[id]/unblock.ts @@ -1,14 +1,10 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -26,13 +22,10 @@ export const meta = applyConfig({ /** * Blocks a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); @@ -84,4 +77,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/unfollow.ts b/server/api/api/v1/accounts/[id]/unfollow.ts index de6ba90a..56fc0f8d 100644 --- a/server/api/api/v1/accounts/[id]/unfollow.ts +++ b/server/api/api/v1/accounts/[id]/unfollow.ts @@ -1,14 +1,10 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -26,13 +22,10 @@ export const meta = applyConfig({ /** * Unfollows a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); @@ -84,4 +77,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/unmute.ts b/server/api/api/v1/accounts/[id]/unmute.ts index 5a498a24..b5c64fde 100644 --- a/server/api/api/v1/accounts/[id]/unmute.ts +++ b/server/api/api/v1/accounts/[id]/unmute.ts @@ -1,14 +1,10 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -26,13 +22,10 @@ export const meta = applyConfig({ /** * Unmute a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); @@ -86,4 +79,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/[id]/unpin.ts b/server/api/api/v1/accounts/[id]/unpin.ts index ee52384e..1e1ea84d 100644 --- a/server/api/api/v1/accounts/[id]/unpin.ts +++ b/server/api/api/v1/accounts/[id]/unpin.ts @@ -1,14 +1,10 @@ import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { - getFromRequest, - getRelationshipToOtherUser, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { getRelationshipToOtherUser } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -26,13 +22,10 @@ export const meta = applyConfig({ /** * Unpin a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user: self } = await getFromRequest(req); + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); @@ -84,4 +77,4 @@ export default async ( }); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/accounts/familiar_followers/index.ts b/server/api/api/v1/accounts/familiar_followers/index.ts index f3667b00..be288959 100644 --- a/server/api/api/v1/accounts/familiar_followers/index.ts +++ b/server/api/api/v1/accounts/familiar_followers/index.ts @@ -1,11 +1,6 @@ -import { parseRequest } from "@request"; import { errorResponse, jsonResponse } from "@response"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations, userToAPI } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -23,14 +18,14 @@ export const meta = applyConfig({ /** * Find familiar followers (followers of a user that you also follow) */ -export default async (req: Request): Promise => { - const { user: self } = await getFromRequest(req); +export default apiRoute<{ + "id[]": string[]; +}>(async (req, matchedRoute, extraData) => { + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); - const { "id[]": ids } = await parseRequest<{ - "id[]": string[]; - }>(req); + const { "id[]": ids } = extraData.parsedRequest; // Minimum id count 1, maximum 10 if (!ids || ids.length < 1 || ids.length > 10) { @@ -67,4 +62,4 @@ export default async (req: Request): Promise => { }); return jsonResponse(output.map(o => userToAPI(o))); -}; +}); diff --git a/server/api/api/v1/accounts/index.ts b/server/api/api/v1/accounts/index.ts index bd5ec124..9a6e8925 100644 --- a/server/api/api/v1/accounts/index.ts +++ b/server/api/api/v1/accounts/index.ts @@ -1,11 +1,9 @@ -import { getConfig } from "~classes/configmanager"; import { jsonResponse } from "@response"; import { tempmailDomains } from "@tempmail"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; import { createNewLocalUser } from "~database/entities/User"; import ISO6391 from "iso-639-1"; -import type { RouteHandler } from "~server/api/routes.type"; export const meta = applyConfig({ allowedMethods: ["POST"], @@ -19,19 +17,19 @@ export const meta = applyConfig({ }, }); -const handler: RouteHandler<{ +export default apiRoute<{ username: string; email: string; password: string; agreement: boolean; locale: string; reason: string; -}> = async (req, matchedRoute, extraData) => { +}>(async (req, matchedRoute, extraData) => { // TODO: Add Authorization check const body = extraData.parsedRequest; - const config = getConfig(); + const config = await extraData.configManager.getConfig(); if (!config.signups.registration) { return jsonResponse( @@ -200,9 +198,4 @@ const handler: RouteHandler<{ return new Response("", { status: 200, }); -}; - -/** - * Creates a new user - */ -export default handler; +}); diff --git a/server/api/api/v1/accounts/relationships/index.ts b/server/api/api/v1/accounts/relationships/index.ts index 89b32f0e..a556d76f 100644 --- a/server/api/api/v1/accounts/relationships/index.ts +++ b/server/api/api/v1/accounts/relationships/index.ts @@ -1,11 +1,9 @@ -import { parseRequest } from "@request"; import { errorResponse, jsonResponse } from "@response"; import { createNewRelationship, relationshipToAPI, } from "~database/entities/Relationship"; -import { getFromRequest } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -23,14 +21,14 @@ export const meta = applyConfig({ /** * Find relationships */ -export default async (req: Request): Promise => { - const { user: self } = await getFromRequest(req); +export default apiRoute<{ + "id[]": string[]; +}>(async (req, matchedRoute, extraData) => { + const { user: self } = extraData.auth; if (!self) return errorResponse("Unauthorized", 401); - const { "id[]": ids } = await parseRequest<{ - "id[]": string[]; - }>(req); + const { "id[]": ids } = extraData.parsedRequest; // Minimum id count 1, maximum 10 if (!ids || ids.length < 1 || ids.length > 10) { @@ -64,4 +62,4 @@ export default async (req: Request): Promise => { ); return jsonResponse(relationships.map(r => relationshipToAPI(r))); -}; +}); diff --git a/server/api/api/v1/accounts/search/index.ts b/server/api/api/v1/accounts/search/index.ts index 3aa51910..15c6b529 100644 --- a/server/api/api/v1/accounts/search/index.ts +++ b/server/api/api/v1/accounts/search/index.ts @@ -1,8 +1,7 @@ import { errorResponse, jsonResponse } from "@response"; import { userRelations, userToAPI } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; -import type { RouteHandler } from "~server/api/routes.type"; export const meta = applyConfig({ allowedMethods: ["GET"], @@ -16,13 +15,13 @@ export const meta = applyConfig({ }, }); -const handler: RouteHandler<{ +export default apiRoute<{ q?: string; limit?: number; offset?: number; resolve?: boolean; following?: boolean; -}> = async (req, matchedRoute, extraData) => { +}>(async (req, matchedRoute, extraData) => { // TODO: Add checks for disabled or not email verified accounts const { user } = extraData.auth; @@ -71,6 +70,4 @@ const handler: RouteHandler<{ }); return jsonResponse(accounts.map(acct => userToAPI(acct))); -}; - -export default handler; +}); diff --git a/server/api/api/v1/accounts/update_credentials/index.ts b/server/api/api/v1/accounts/update_credentials/index.ts index 4ce1142b..fc66d92c 100644 --- a/server/api/api/v1/accounts/update_credentials/index.ts +++ b/server/api/api/v1/accounts/update_credentials/index.ts @@ -1,7 +1,6 @@ -import { getConfig } from "~classes/configmanager"; import { errorResponse, jsonResponse } from "@response"; import { userRelations, userToAPI } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { sanitize } from "isomorphic-dompurify"; import { sanitizeHtml } from "@sanitization"; import { uploadFile } from "~classes/media"; @@ -10,7 +9,6 @@ import { parseEmojis } from "~database/entities/Emoji"; import { client } from "~database/datasource"; import type { APISource } from "~types/entities/source"; import { convertTextToHtml } from "@formatting"; -import type { RouteHandler } from "~server/api/routes.type"; export const meta = applyConfig({ allowedMethods: ["PATCH"], @@ -24,7 +22,7 @@ export const meta = applyConfig({ }, }); -const handler: RouteHandler<{ +export default apiRoute<{ display_name: string; note: string; avatar: File; @@ -35,12 +33,12 @@ const handler: RouteHandler<{ "source[privacy]": string; "source[sensitive]": string; "source[language]": string; -}> = async (req, matchedRoute, extraData) => { +}>(async (req, matchedRoute, extraData) => { const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); - const config = getConfig(); + const config = await extraData.configManager.getConfig(); const { display_name, @@ -134,7 +132,7 @@ const handler: RouteHandler<{ ); } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + // @ts-expect-error Prisma Typescript doesn't include relations user.source.privacy = source_privacy; } @@ -144,7 +142,7 @@ const handler: RouteHandler<{ return errorResponse("Sensitive must be a boolean", 422); } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + // @ts-expect-error Prisma Typescript doesn't include relations user.source.sensitive = source_sensitive === "true"; } @@ -156,7 +154,7 @@ const handler: RouteHandler<{ ); } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + // @ts-expect-error Prisma Typescript doesn't include relations user.source.language = source_language; } @@ -251,6 +249,4 @@ const handler: RouteHandler<{ }); return jsonResponse(userToAPI(output)); -}; - -export default handler; +}); diff --git a/server/api/api/v1/accounts/verify_credentials/index.ts b/server/api/api/v1/accounts/verify_credentials/index.ts index 1a56825b..e317389f 100644 --- a/server/api/api/v1/accounts/verify_credentials/index.ts +++ b/server/api/api/v1/accounts/verify_credentials/index.ts @@ -1,7 +1,6 @@ import { errorResponse, jsonResponse } from "@response"; import { userToAPI } from "~database/entities/User"; -import { applyConfig } from "@api"; -import type { RouteHandler } from "~server/api/routes.type"; +import { apiRoute, applyConfig } from "@api"; export const meta = applyConfig({ allowedMethods: ["GET"], @@ -15,9 +14,7 @@ export const meta = applyConfig({ }, }); -const handler: RouteHandler<> = (req, matchedRoute, extraData) => {}; - -const handler: RouteHandler<""> = (req, matchedRoute, extraData) => { +export default apiRoute((req, matchedRoute, extraData) => { // TODO: Add checks for disabled or not email verified accounts const { user } = extraData.auth; @@ -27,6 +24,4 @@ const handler: RouteHandler<""> = (req, matchedRoute, extraData) => { return jsonResponse({ ...userToAPI(user, true), }); -}; - -export default handler; +}); diff --git a/server/api/api/v1/apps/index.ts b/server/api/api/v1/apps/index.ts index 175599f8..c3e3bff8 100644 --- a/server/api/api/v1/apps/index.ts +++ b/server/api/api/v1/apps/index.ts @@ -1,5 +1,4 @@ -import { applyConfig } from "@api"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { randomBytes } from "crypto"; import { client } from "~database/datasource"; @@ -19,13 +18,14 @@ export const meta = applyConfig({ /** * Creates a new application to obtain OAuth 2 credentials */ -export default async (req: Request): Promise => { - const { client_name, redirect_uris, scopes, website } = await parseRequest<{ - client_name: string; - redirect_uris: string; - scopes: string; - website: string; - }>(req); +export default apiRoute<{ + client_name: string; + redirect_uris: string; + scopes: string; + website: string; +}>(async (req, matchedRoute, extraData) => { + const { client_name, redirect_uris, scopes, website } = + extraData.parsedRequest; // Check if redirect URI is a valid URI, and also an absolute URI if (redirect_uris) { @@ -62,4 +62,4 @@ export default async (req: Request): Promise => { redirect_uri: application.redirect_uris, vapid_link: application.vapid_key, }); -}; +}); diff --git a/server/api/api/v1/apps/verify_credentials/index.ts b/server/api/api/v1/apps/verify_credentials/index.ts index a281be66..4444213e 100644 --- a/server/api/api/v1/apps/verify_credentials/index.ts +++ b/server/api/api/v1/apps/verify_credentials/index.ts @@ -1,7 +1,6 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { getFromToken } from "~database/entities/Application"; -import { getFromRequest } from "~database/entities/User"; export const meta = applyConfig({ allowedMethods: ["GET"], @@ -18,8 +17,8 @@ export const meta = applyConfig({ /** * Returns OAuth2 credentials */ -export default async (req: Request): Promise => { - const { user, token } = await getFromRequest(req); +export default apiRoute(async (req, matchedRoute, extraData) => { + const { user, token } = extraData.auth; const application = await getFromToken(token); if (!user) return errorResponse("Unauthorized", 401); @@ -32,4 +31,4 @@ export default async (req: Request): Promise => { redirect_uris: application.redirect_uris, scopes: application.scopes, }); -}; +}); diff --git a/server/api/api/v1/blocks/index.ts b/server/api/api/v1/blocks/index.ts index 99ee967f..0bbfa26b 100644 --- a/server/api/api/v1/blocks/index.ts +++ b/server/api/api/v1/blocks/index.ts @@ -1,10 +1,6 @@ import { errorResponse, jsonResponse } from "@response"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations, userToAPI } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -19,8 +15,8 @@ export const meta = applyConfig({ }, }); -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -37,4 +33,4 @@ export default async (req: Request): Promise => { }); return jsonResponse(blocks.map(u => userToAPI(u))); -}; +}); diff --git a/server/api/api/v1/custom_emojis/index.ts b/server/api/api/v1/custom_emojis/index.ts index 1590bbc0..224da926 100644 --- a/server/api/api/v1/custom_emojis/index.ts +++ b/server/api/api/v1/custom_emojis/index.ts @@ -1,4 +1,4 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { jsonResponse } from "@response"; import { client } from "~database/datasource"; import { emojiToAPI } from "~database/entities/Emoji"; @@ -15,11 +15,7 @@ export const meta = applyConfig({ }, }); -/** - * S - */ -// eslint-disable-next-line @typescript-eslint/require-await -export default async (): Promise => { +export default apiRoute(async () => { const emojis = await client.emoji.findMany({ where: { instanceId: null, @@ -29,4 +25,4 @@ export default async (): Promise => { return jsonResponse( await Promise.all(emojis.map(emoji => emojiToAPI(emoji))) ); -}; +}); diff --git a/server/api/api/v1/favourites/index.ts b/server/api/api/v1/favourites/index.ts index 55e0a672..7e0b1dbb 100644 --- a/server/api/api/v1/favourites/index.ts +++ b/server/api/api/v1/favourites/index.ts @@ -1,8 +1,6 @@ import { errorResponse, jsonResponse } from "@response"; -import { getFromRequest } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; -import { parseRequest } from "@request"; import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; export const meta = applyConfig({ @@ -17,20 +15,15 @@ export const meta = applyConfig({ }, }); -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; - const { - limit = 20, - max_id, - min_id, - since_id, - } = await parseRequest<{ - max_id?: string; - since_id?: string; - min_id?: string; - limit?: number; - }>(req); + const { limit = 20, max_id, min_id, since_id } = extraData.parsedRequest; if (limit < 1 || limit > 40) { return errorResponse("Limit must be between 1 and 40", 400); @@ -77,4 +70,4 @@ export default async (req: Request): Promise => { Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/follow_requests/[account_id]/authorize.ts b/server/api/api/v1/follow_requests/[account_id]/authorize.ts index 074aae92..874633da 100644 --- a/server/api/api/v1/follow_requests/[account_id]/authorize.ts +++ b/server/api/api/v1/follow_requests/[account_id]/authorize.ts @@ -1,8 +1,7 @@ import { errorResponse, jsonResponse } from "@response"; -import { getFromRequest, userRelations } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; -import type { MatchedRoute } from "bun"; import { checkForBidirectionalRelationships, relationshipToAPI, @@ -20,11 +19,8 @@ export const meta = applyConfig({ }, }); -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -76,4 +72,4 @@ export default async ( if (!relationship) return errorResponse("Relationship not found", 404); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/follow_requests/[account_id]/reject.ts b/server/api/api/v1/follow_requests/[account_id]/reject.ts index 6a667e79..41d4105c 100644 --- a/server/api/api/v1/follow_requests/[account_id]/reject.ts +++ b/server/api/api/v1/follow_requests/[account_id]/reject.ts @@ -1,8 +1,7 @@ import { errorResponse, jsonResponse } from "@response"; -import { getFromRequest, userRelations } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; -import type { MatchedRoute } from "bun"; import { checkForBidirectionalRelationships, relationshipToAPI, @@ -20,11 +19,8 @@ export const meta = applyConfig({ }, }); -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -64,4 +60,4 @@ export default async ( if (!relationship) return errorResponse("Relationship not found", 404); return jsonResponse(relationshipToAPI(relationship)); -}; +}); diff --git a/server/api/api/v1/follow_requests/index.ts b/server/api/api/v1/follow_requests/index.ts index d465c61d..ac937d46 100644 --- a/server/api/api/v1/follow_requests/index.ts +++ b/server/api/api/v1/follow_requests/index.ts @@ -1,12 +1,7 @@ import { errorResponse, jsonResponse } from "@response"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations, userToAPI } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; -import { parseRequest } from "@request"; export const meta = applyConfig({ allowedMethods: ["GET"], @@ -20,20 +15,15 @@ export const meta = applyConfig({ }, }); -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; - const { - limit = 20, - max_id, - min_id, - since_id, - } = await parseRequest<{ - max_id?: string; - since_id?: string; - min_id?: string; - limit?: number; - }>(req); + const { limit = 20, max_id, min_id, since_id } = extraData.parsedRequest; if (limit < 1 || limit > 40) { return errorResponse("Limit must be between 1 and 40", 400); @@ -79,4 +69,4 @@ export default async (req: Request): Promise => { Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/instance/index.ts b/server/api/api/v1/instance/index.ts index 259dbe0b..4fabefd0 100644 --- a/server/api/api/v1/instance/index.ts +++ b/server/api/api/v1/instance/index.ts @@ -1,5 +1,4 @@ -import { applyConfig } from "@api"; -import { getConfig } from "~classes/configmanager"; +import { apiRoute, applyConfig } from "@api"; import { jsonResponse } from "@response"; import { client } from "~database/datasource"; import { userRelations, userToAPI } from "~database/entities/User"; @@ -18,12 +17,8 @@ export const meta = applyConfig({ }, }); -/** - * Creates a new user - */ -// eslint-disable-next-line @typescript-eslint/require-await -export default async (): Promise => { - const config = getConfig(); +export default apiRoute(async (req, matchedRoute, extraData) => { + const config = await extraData.configManager.getConfig(); // Get software version from package.json const version = manifest.version; @@ -159,4 +154,4 @@ export default async (): Promise => { }, contact_account: contactAccount ? userToAPI(contactAccount) : null, } as APIInstance); -}; +}); diff --git a/server/api/api/v1/media/[id]/index.ts b/server/api/api/v1/media/[id]/index.ts index f1e16511..bec0e978 100644 --- a/server/api/api/v1/media/[id]/index.ts +++ b/server/api/api/v1/media/[id]/index.ts @@ -1,13 +1,9 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; import { uploadFile } from "~classes/media"; -import { getConfig } from "~classes/configmanager"; import { attachmentToAPI, getUrl } from "~database/entities/Attachment"; -import type { MatchedRoute } from "bun"; -import { parseRequest } from "@request"; export const meta: APIRouteMeta = applyConfig({ allowedMethods: ["GET", "PUT"], @@ -25,11 +21,12 @@ export const meta: APIRouteMeta = applyConfig({ /** * Get media information */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + thumbnail?: File; + description?: string; + focus?: string; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) { return errorResponse("Unauthorized", 401); @@ -47,7 +44,7 @@ export default async ( return errorResponse("Media not found", 404); } - const config = getConfig(); + const config = await extraData.configManager.getConfig(); switch (req.method) { case "GET": { @@ -60,11 +57,7 @@ export default async ( } } case "PUT": { - const { description, thumbnail } = await parseRequest<{ - thumbnail?: File; - description?: string; - focus?: string; - }>(req); + const { description, thumbnail } = extraData.parsedRequest; let thumbnailUrl = attachment.thumbnail_url; @@ -101,4 +94,4 @@ export default async ( } return errorResponse("Method not allowed", 405); -}; +}); diff --git a/server/api/api/v1/media/index.ts b/server/api/api/v1/media/index.ts index 568d3bf1..0119a7d4 100644 --- a/server/api/api/v1/media/index.ts +++ b/server/api/api/v1/media/index.ts @@ -1,12 +1,10 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; import { encode } from "blurhash"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; import sharp from "sharp"; import { uploadFile } from "~classes/media"; -import { getConfig } from "~classes/configmanager"; import { attachmentToAPI, getUrl } from "~database/entities/Attachment"; export const meta: APIRouteMeta = applyConfig({ @@ -25,27 +23,26 @@ export const meta: APIRouteMeta = applyConfig({ /** * Upload new media */ -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + file: File; + thumbnail?: File; + description?: string; + // TODO: Add focus + focus?: string; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) { return errorResponse("Unauthorized", 401); } - const form = await req.formData(); - - const file = form.get("file") as unknown as File | undefined; - const thumbnail = form.get("thumbnail"); - const description = form.get("description") as string | undefined; - - // Floating point numbers from -1.0 to 1.0, comma delimited - // const focus = form.get("focus"); + const { file, thumbnail, description } = extraData.parsedRequest; if (!file) { return errorResponse("No file provided", 400); } - const config = getConfig(); + const config = await extraData.configManager.getConfig(); if (file.size > config.validation.max_media_size) { return errorResponse( @@ -86,7 +83,7 @@ export default async (req: Request): Promise => { metadata?.height ?? 0, 4, 4 - ) + ) : null; let url = ""; @@ -120,4 +117,4 @@ export default async (req: Request): Promise => { // TODO: Add job to process videos and other media return jsonResponse(attachmentToAPI(newAttachment)); -}; +}); diff --git a/server/api/api/v1/mutes/index.ts b/server/api/api/v1/mutes/index.ts index dfa48057..702cc434 100644 --- a/server/api/api/v1/mutes/index.ts +++ b/server/api/api/v1/mutes/index.ts @@ -1,10 +1,6 @@ import { errorResponse, jsonResponse } from "@response"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations, userToAPI } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; export const meta = applyConfig({ @@ -19,8 +15,8 @@ export const meta = applyConfig({ }, }); -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -37,4 +33,4 @@ export default async (req: Request): Promise => { }); return jsonResponse(blocks.map(u => userToAPI(u))); -}; +}); diff --git a/server/api/api/v1/notifications/index.ts b/server/api/api/v1/notifications/index.ts index b5eb1c3b..b8971a27 100644 --- a/server/api/api/v1/notifications/index.ts +++ b/server/api/api/v1/notifications/index.ts @@ -1,9 +1,8 @@ import { errorResponse, jsonResponse } from "@response"; -import { getFromRequest, userRelations } from "~database/entities/User"; -import { applyConfig } from "@api"; +import { userRelations } from "~database/entities/User"; +import { apiRoute, applyConfig } from "@api"; import { client } from "~database/datasource"; import { statusAndUserRelations } from "~database/entities/Status"; -import { parseRequest } from "@request"; import { notificationToAPI } from "~database/entities/Notification"; export const meta = applyConfig({ @@ -18,8 +17,16 @@ export const meta = applyConfig({ }, }); -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; + exclude_types?: string[]; + types?: string[]; + account_id?: string; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -31,15 +38,7 @@ export default async (req: Request): Promise => { min_id, since_id, types, - } = await parseRequest<{ - max_id?: string; - since_id?: string; - min_id?: string; - limit?: number; - exclude_types?: string[]; - types?: string[]; - account_id?: string; - }>(req); + } = extraData.parsedRequest; if (limit > 30) return errorResponse("Limit too high", 400); @@ -85,8 +84,9 @@ export default async (req: Request): Promise => { `<${urlWithoutQuery}?max_id=${objects[0].id}&limit=${limit}>; rel="next"` ); linkHeader.push( - `<${urlWithoutQuery}?since_id=${objects.at(-1) - ?.id}&limit=${limit}>; rel="prev"` + `<${urlWithoutQuery}?since_id=${ + objects.at(-1)?.id + }&limit=${limit}>; rel="prev"` ); } @@ -97,4 +97,4 @@ export default async (req: Request): Promise => { Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/profile/avatar.ts b/server/api/api/v1/profile/avatar.ts index c263718d..f65ce264 100644 --- a/server/api/api/v1/profile/avatar.ts +++ b/server/api/api/v1/profile/avatar.ts @@ -1,11 +1,7 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; +import { userRelations, userToAPI } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -23,8 +19,8 @@ export const meta: APIRouteMeta = applyConfig({ /** * Deletes a user avatar */ -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -40,4 +36,4 @@ export default async (req: Request): Promise => { }); return jsonResponse(userToAPI(newUser)); -}; +}); diff --git a/server/api/api/v1/profile/header.ts b/server/api/api/v1/profile/header.ts index 9c9f9ec3..6a53e6d5 100644 --- a/server/api/api/v1/profile/header.ts +++ b/server/api/api/v1/profile/header.ts @@ -1,11 +1,7 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; +import { userRelations, userToAPI } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -23,8 +19,8 @@ export const meta: APIRouteMeta = applyConfig({ /** * Deletes a user header */ -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -40,4 +36,4 @@ export default async (req: Request): Promise => { }); return jsonResponse(userToAPI(newUser)); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/context.ts b/server/api/api/v1/statuses/[id]/context.ts index ab9aadab..518b9493 100644 --- a/server/api/api/v1/statuses/[id]/context.ts +++ b/server/api/api/v1/statuses/[id]/context.ts @@ -1,6 +1,5 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { getAncestors, @@ -8,7 +7,6 @@ import { statusAndUserRelations, statusToAPI, } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -26,15 +24,12 @@ export const meta: APIRouteMeta = applyConfig({ /** * Fetch a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { // Public for public statuses limited to 40 ancestors and 60 descendants with a maximum depth of 20. // User token + read:statuses for up to 4,096 ancestors, 4,096 descendants, unlimited depth, and private statuses. const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; const foundStatus = await client.status.findUnique({ where: { id }, @@ -55,4 +50,4 @@ export default async ( descendants.map(status => statusToAPI(status, user || undefined)) ), }); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/favourite.ts b/server/api/api/v1/statuses/[id]/favourite.ts index d1f8c39a..8557a7b2 100644 --- a/server/api/api/v1/statuses/[id]/favourite.ts +++ b/server/api/api/v1/statuses/[id]/favourite.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { createLike } from "~database/entities/Like"; import { @@ -9,7 +8,6 @@ import { statusAndUserRelations, statusToAPI, } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; import type { APIStatus } from "~types/entities/status"; @@ -28,13 +26,10 @@ export const meta: APIRouteMeta = applyConfig({ /** * Favourite a post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -63,4 +58,4 @@ export default async ( favourited: true, favourites_count: status._count.likes + 1, } as APIStatus); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/favourited_by.ts b/server/api/api/v1/statuses/[id]/favourited_by.ts index edbb0fdc..3d61969f 100644 --- a/server/api/api/v1/statuses/[id]/favourited_by.ts +++ b/server/api/api/v1/statuses/[id]/favourited_by.ts @@ -1,18 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { isViewableByUser, statusAndUserRelations, } from "~database/entities/Status"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; +import { userRelations, userToAPI } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -30,13 +23,15 @@ export const meta: APIRouteMeta = applyConfig({ /** * Fetch users who favourited the post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + max_id?: string; + min_id?: string; + since_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; const status = await client.status.findUnique({ where: { id }, @@ -52,12 +47,7 @@ export default async ( min_id = null, since_id = null, limit = 40, - } = await parseRequest<{ - max_id?: string; - min_id?: string; - since_id?: string; - limit?: number; - }>(req); + } = extraData.parsedRequest; // Check for limit limits if (limit > 80) return errorResponse("Invalid limit (maximum is 80)", 400); @@ -111,4 +101,4 @@ export default async ( Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/index.ts b/server/api/api/v1/statuses/[id]/index.ts index 22e335ed..d0fae956 100644 --- a/server/api/api/v1/statuses/[id]/index.ts +++ b/server/api/api/v1/statuses/[id]/index.ts @@ -1,9 +1,6 @@ -import { applyConfig } from "@api"; -import { getConfig } from "~classes/configmanager"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { sanitizeHtml } from "@sanitization"; -import type { MatchedRoute } from "bun"; import { parse } from "marked"; import { client } from "~database/datasource"; import { @@ -12,7 +9,6 @@ import { statusAndUserRelations, statusToAPI, } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -31,20 +27,28 @@ export const meta: APIRouteMeta = applyConfig({ /** * Fetch a user */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + status?: string; + spoiler_text?: string; + sensitive?: boolean; + language?: string; + content_type?: string; + "media_ids[]"?: string[]; + "poll[options][]"?: string[]; + "poll[expires_in]"?: number; + "poll[multiple]"?: boolean; + "poll[hide_totals]"?: boolean; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; const status = await client.status.findUnique({ where: { id }, include: statusAndUserRelations, }); - const config = getConfig(); + const config = await extraData.configManager.getConfig(); // Check if user is authorized to view this status (if it's private) if (!status || !isViewableByUser(status, user)) @@ -89,18 +93,7 @@ export default async ( "media_ids[]": media_ids, spoiler_text, sensitive, - } = await parseRequest<{ - status?: string; - spoiler_text?: string; - sensitive?: boolean; - language?: string; - content_type?: string; - "media_ids[]"?: string[]; - "poll[options][]"?: string[]; - "poll[expires_in]"?: number; - "poll[multiple]"?: boolean; - "poll[hide_totals]"?: boolean; - }>(req); + } = extraData.parsedRequest; // TODO: Add Poll support // Validate status @@ -171,11 +164,11 @@ export default async ( let sanitizedStatus: string; if (content_type === "text/markdown") { - sanitizedStatus = await sanitizeHtml(parse(statusText ?? "")); + sanitizedStatus = await sanitizeHtml(await parse(statusText ?? "")); } else if (content_type === "text/x.misskeymarkdown") { // Parse as MFM // TODO: Parse as MFM - sanitizedStatus = await sanitizeHtml(parse(statusText ?? "")); + sanitizedStatus = await sanitizeHtml(await parse(statusText ?? "")); } else { sanitizedStatus = await sanitizeHtml(statusText ?? ""); } @@ -189,8 +182,8 @@ export default async ( // Check if status body doesnt match filters if ( - config.filters.note_filters.some( - filter => statusText?.match(filter) + config.filters.note_filters.some(filter => + statusText?.match(filter) ) ) { return errorResponse("Status contains blocked words", 422); @@ -223,4 +216,4 @@ export default async ( } return jsonResponse({}); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/pin.ts b/server/api/api/v1/statuses/[id]/pin.ts index 72eceee6..1d3a2e56 100644 --- a/server/api/api/v1/statuses/[id]/pin.ts +++ b/server/api/api/v1/statuses/[id]/pin.ts @@ -1,10 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -22,13 +20,10 @@ export const meta: APIRouteMeta = applyConfig({ /** * Pin a post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -62,4 +57,4 @@ export default async ( if (!status) return errorResponse("Record not found", 404); return jsonResponse(statusToAPI(status, user)); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/reblog.ts b/server/api/api/v1/statuses/[id]/reblog.ts index 9cf3716e..b93846ed 100644 --- a/server/api/api/v1/statuses/[id]/reblog.ts +++ b/server/api/api/v1/statuses/[id]/reblog.ts @@ -1,19 +1,13 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; -import { getConfig } from "~classes/configmanager"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { isViewableByUser, statusAndUserRelations, statusToAPI, } from "~database/entities/Status"; -import { - getFromRequest, - type UserWithRelations, -} from "~database/entities/User"; +import { type UserWithRelations } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -31,20 +25,17 @@ export const meta: APIRouteMeta = applyConfig({ /** * Reblogs a post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + visibility: "public" | "unlisted" | "private"; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const config = getConfig(); + const config = await extraData.configManager.getConfig(); - const { user } = await getFromRequest(req); + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); - const { visibility = "public" } = await parseRequest<{ - visibility: "public" | "unlisted" | "private"; - }>(req); + const { visibility = "public" } = extraData.parsedRequest; const status = await client.status.findUnique({ where: { id }, @@ -107,4 +98,4 @@ export default async ( user ) ); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/reblogged_by.ts b/server/api/api/v1/statuses/[id]/reblogged_by.ts index d51fa975..9af70f36 100644 --- a/server/api/api/v1/statuses/[id]/reblogged_by.ts +++ b/server/api/api/v1/statuses/[id]/reblogged_by.ts @@ -1,18 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { isViewableByUser, statusAndUserRelations, } from "~database/entities/Status"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; +import { userRelations, userToAPI } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -30,13 +23,15 @@ export const meta: APIRouteMeta = applyConfig({ /** * Fetch users who reblogged the post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute<{ + max_id?: string; + min_id?: string; + since_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; const status = await client.status.findUnique({ where: { id }, @@ -52,12 +47,7 @@ export default async ( min_id = null, since_id = null, limit = 40, - } = await parseRequest<{ - max_id?: string; - min_id?: string; - since_id?: string; - limit?: number; - }>(req); + } = extraData.parsedRequest; // Check for limit limits if (limit > 80) return errorResponse("Invalid limit (maximum is 80)", 400); @@ -112,4 +102,4 @@ export default async ( Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/source.ts b/server/api/api/v1/statuses/[id]/source.ts index ae9defbc..02d3fe27 100644 --- a/server/api/api/v1/statuses/[id]/source.ts +++ b/server/api/api/v1/statuses/[id]/source.ts @@ -1,17 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; -import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; +import { apiRoute, applyConfig } from "@api"; +import { errorResponse } from "@response"; import { client } from "~database/datasource"; -import { createLike } from "~database/entities/Like"; import { isViewableByUser, statusAndUserRelations, - statusToAPI, } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; -import type { APIStatus } from "~types/entities/status"; export const meta: APIRouteMeta = applyConfig({ allowedMethods: ["GET"], @@ -28,13 +22,10 @@ export const meta: APIRouteMeta = applyConfig({ /** * Favourite a post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -46,4 +37,6 @@ export default async ( // Check if user is authorized to view this status (if it's private) if (!status || !isViewableByUser(status, user)) return errorResponse("Record not found", 404); -}; + + return errorResponse("Not implemented yet"); +}); diff --git a/server/api/api/v1/statuses/[id]/unfavourite.ts b/server/api/api/v1/statuses/[id]/unfavourite.ts index 36de4fe2..7d02a30d 100644 --- a/server/api/api/v1/statuses/[id]/unfavourite.ts +++ b/server/api/api/v1/statuses/[id]/unfavourite.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { deleteLike } from "~database/entities/Like"; import { @@ -9,7 +8,6 @@ import { statusAndUserRelations, statusToAPI, } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; import type { APIStatus } from "~types/entities/status"; @@ -28,13 +26,10 @@ export const meta: APIRouteMeta = applyConfig({ /** * Unfavourite a post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -54,4 +49,4 @@ export default async ( favourited: false, favourites_count: status._count.likes - 1, } as APIStatus); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/unpin.ts b/server/api/api/v1/statuses/[id]/unpin.ts index af8f4a7a..8d10af6a 100644 --- a/server/api/api/v1/statuses/[id]/unpin.ts +++ b/server/api/api/v1/statuses/[id]/unpin.ts @@ -1,10 +1,7 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -22,13 +19,10 @@ export const meta: APIRouteMeta = applyConfig({ /** * Unpins a post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -62,4 +56,4 @@ export default async ( if (!status) return errorResponse("Record not found", 404); return jsonResponse(statusToAPI(status, user)); -}; +}); diff --git a/server/api/api/v1/statuses/[id]/unreblog.ts b/server/api/api/v1/statuses/[id]/unreblog.ts index 56a1f82a..78179bc1 100644 --- a/server/api/api/v1/statuses/[id]/unreblog.ts +++ b/server/api/api/v1/statuses/[id]/unreblog.ts @@ -1,14 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; -import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { isViewableByUser, statusAndUserRelations, statusToAPI, } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; import type { APIStatus } from "~types/entities/status"; @@ -27,13 +24,10 @@ export const meta: APIRouteMeta = applyConfig({ /** * Unreblogs a post */ -export default async ( - req: Request, - matchedRoute: MatchedRoute -): Promise => { +export default apiRoute(async (req, matchedRoute, extraData) => { const id = matchedRoute.params.id; - const { user } = await getFromRequest(req); + const { user } = extraData.auth; if (!user) return errorResponse("Unauthorized", 401); @@ -66,4 +60,4 @@ export default async ( reblogged: false, reblogs_count: status._count.reblogs - 1, } as APIStatus); -}; +}); diff --git a/server/api/api/v1/statuses/index.ts b/server/api/api/v1/statuses/index.ts index 0aa39329..c51f5256 100644 --- a/server/api/api/v1/statuses/index.ts +++ b/server/api/api/v1/statuses/index.ts @@ -1,12 +1,6 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { applyConfig } from "@api"; -import { getConfig } from "~classes/configmanager"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { sanitizeHtml } from "@sanitization"; -import type { MatchedRoute } from "bun"; import { parse } from "marked"; import { client } from "~database/datasource"; import { getFromToken } from "~database/entities/Application"; @@ -16,7 +10,7 @@ import { statusAndUserRelations, statusToAPI, } from "~database/entities/Status"; -import type { AuthData, UserWithRelations } from "~database/entities/User"; +import type { UserWithRelations } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -34,50 +28,46 @@ export const meta: APIRouteMeta = applyConfig({ /** * Post new status */ -export default async ( - req: Request, - matchedRoute: MatchedRoute, - authData: AuthData -): Promise => { - const { user, token } = authData; +export default apiRoute<{ + status: string; + media_ids?: string[]; + "poll[options]"?: string[]; + "poll[expires_in]"?: number; + "poll[multiple]"?: boolean; + "poll[hide_totals]"?: boolean; + in_reply_to_id?: string; + quote_id?: string; + sensitive?: boolean; + spoiler_text?: string; + visibility?: "public" | "unlisted" | "private" | "direct"; + language?: string; + scheduled_at?: string; + local_only?: boolean; + content_type?: string; +}>(async (req, matchedRoute, extraData) => { + const { user, token } = extraData.auth; const application = await getFromToken(token); if (!user) return errorResponse("Unauthorized", 401); - const config = getConfig(); + const config = await extraData.configManager.getConfig(); const { status, media_ids, "poll[expires_in]": expires_in, - "poll[hide_totals]": hide_totals, - "poll[multiple]": multiple, + // "poll[hide_totals]": hide_totals, + // "poll[multiple]": multiple, "poll[options]": options, in_reply_to_id, quote_id, - language, + // language, scheduled_at, sensitive, spoiler_text, visibility, content_type, - } = await parseRequest<{ - status: string; - media_ids?: string[]; - "poll[options]"?: string[]; - "poll[expires_in]"?: number; - "poll[multiple]"?: boolean; - "poll[hide_totals]"?: boolean; - in_reply_to_id?: string; - quote_id?: string; - sensitive?: boolean; - spoiler_text?: string; - visibility?: "public" | "unlisted" | "private" | "direct"; - language?: string; - scheduled_at?: string; - local_only?: boolean; - content_type?: string; - }>(req); + } = extraData.parsedRequest; // Validate status if (!status && !(media_ids && media_ids.length > 0)) { @@ -246,7 +236,7 @@ export default async ( ? { user: replyUser, status: replyStatus, - } + } : undefined, quote: quote || undefined, }); @@ -254,4 +244,4 @@ export default async ( // TODO: add database jobs to deliver the post return jsonResponse(await statusToAPI(newStatus, user)); -}; +}); diff --git a/server/api/api/v1/timelines/home.ts b/server/api/api/v1/timelines/home.ts index cb1374c4..014d6f28 100644 --- a/server/api/api/v1/timelines/home.ts +++ b/server/api/api/v1/timelines/home.ts @@ -1,10 +1,7 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { applyConfig } from "@api"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -22,20 +19,15 @@ export const meta: APIRouteMeta = applyConfig({ /** * Fetch home timeline statuses */ -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; - const { - limit = 20, - max_id, - min_id, - since_id, - } = await parseRequest<{ - max_id?: string; - since_id?: string; - min_id?: string; - limit?: number; - }>(req); + const { limit = 20, max_id, min_id, since_id } = extraData.parsedRequest; if (limit < 1 || limit > 40) { return errorResponse("Limit must be between 1 and 40", 400); @@ -104,4 +96,4 @@ export default async (req: Request): Promise => { Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v1/timelines/public.ts b/server/api/api/v1/timelines/public.ts index 6c1e418e..62c3b72f 100644 --- a/server/api/api/v1/timelines/public.ts +++ b/server/api/api/v1/timelines/public.ts @@ -1,9 +1,7 @@ -import { applyConfig } from "@api"; -import { parseRequest } from "@request"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -18,8 +16,16 @@ export const meta: APIRouteMeta = applyConfig({ }, }); -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + local?: boolean; + only_media?: boolean; + remote?: boolean; + max_id?: string; + since_id?: string; + min_id?: string; + limit?: number; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; const { local, limit = 20, @@ -28,15 +34,7 @@ export default async (req: Request): Promise => { // only_media, remote, since_id, - } = await parseRequest<{ - local?: boolean; - only_media?: boolean; - remote?: boolean; - max_id?: string; - since_id?: string; - min_id?: string; - limit?: number; - }>(req); + } = extraData.parsedRequest; if (limit < 1 || limit > 40) { return errorResponse("Limit must be between 1 and 40", 400); @@ -56,10 +54,10 @@ export default async (req: Request): Promise => { instanceId: remote ? { not: null, - } + } : local - ? null - : undefined, + ? null + : undefined, }, include: statusAndUserRelations, take: limit, @@ -87,4 +85,4 @@ export default async (req: Request): Promise => { Link: linkHeader.join(", "), } ); -}; +}); diff --git a/server/api/api/v2/media/index.ts b/server/api/api/v2/media/index.ts index 32585cdf..eeadcbc6 100644 --- a/server/api/api/v2/media/index.ts +++ b/server/api/api/v2/media/index.ts @@ -1,12 +1,10 @@ -import { applyConfig } from "@api"; +import { apiRoute, applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; import { encode } from "blurhash"; -import { getFromRequest } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; import sharp from "sharp"; import { uploadFile } from "~classes/media"; -import { getConfig } from "~classes/configmanager"; import { attachmentToAPI, getUrl } from "~database/entities/Attachment"; export const meta: APIRouteMeta = applyConfig({ @@ -25,27 +23,26 @@ export const meta: APIRouteMeta = applyConfig({ /** * Upload new media */ -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + file: File; + thumbnail: File; + description: string; + // TODO: Implement focus storage + focus: string; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; if (!user) { return errorResponse("Unauthorized", 401); } - const form = await req.formData(); - - const file = form.get("file") as unknown as File | undefined; - const thumbnail = form.get("thumbnail"); - const description = form.get("description") as string | undefined; - - // Floating point numbers from -1.0 to 1.0, comma delimited - // const focus = form.get("focus"); + const { file, thumbnail, description } = extraData.parsedRequest; if (!file) { return errorResponse("No file provided", 400); } - const config = getConfig(); + const config = await extraData.configManager.getConfig(); if (file.size > config.validation.max_media_size) { return errorResponse( @@ -86,7 +83,7 @@ export default async (req: Request): Promise => { metadata?.height ?? 0, 4, 4 - ) + ) : null; let url = ""; @@ -132,4 +129,4 @@ export default async (req: Request): Promise => { 202 ); } -}; +}); diff --git a/server/api/api/v2/search/index.ts b/server/api/api/v2/search/index.ts index c40f7a92..6a4d4a9c 100644 --- a/server/api/api/v2/search/index.ts +++ b/server/api/api/v2/search/index.ts @@ -1,15 +1,9 @@ -import { applyConfig } from "@api"; -import { getConfig } from "~classes/configmanager"; +import { apiRoute, applyConfig } from "@api"; import { MeiliIndexType, meilisearch } from "@meilisearch"; -import { parseRequest } from "@request"; import { errorResponse, jsonResponse } from "@response"; import { client } from "~database/datasource"; import { statusAndUserRelations, statusToAPI } from "~database/entities/Status"; -import { - getFromRequest, - userRelations, - userToAPI, -} from "~database/entities/User"; +import { userRelations, userToAPI } from "~database/entities/User"; import type { APIRouteMeta } from "~types/api"; export const meta: APIRouteMeta = applyConfig({ @@ -28,8 +22,18 @@ export const meta: APIRouteMeta = applyConfig({ /** * Upload new media */ -export default async (req: Request): Promise => { - const { user } = await getFromRequest(req); +export default apiRoute<{ + q?: string; + type?: string; + resolve?: boolean; + following?: boolean; + account_id?: string; + max_id?: string; + min_id?: string; + limit?: number; + offset?: number; +}>(async (req, matchedRoute, extraData) => { + const { user } = extraData.auth; const { q, @@ -41,19 +45,9 @@ export default async (req: Request): Promise => { // min_id, limit = 20, offset, - } = await parseRequest<{ - q?: string; - type?: string; - resolve?: boolean; - following?: boolean; - account_id?: string; - max_id?: string; - min_id?: string; - limit?: number; - offset?: number; - }>(req); + } = extraData.parsedRequest; - const config = getConfig(); + const config = await extraData.configManager.getConfig(); if (!config.meilisearch.enabled) { return errorResponse("Meilisearch is not enabled", 501); @@ -143,4 +137,4 @@ export default async (req: Request): Promise => { ), hashtags: [], }); -}; +});