diff --git a/bun.lockb b/bun.lockb index 4747f73c..bcb09639 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/database/entities/Object.ts b/database/entities/Object.ts deleted file mode 100644 index 7fb5128c..00000000 --- a/database/entities/Object.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { InferSelectModel } from "drizzle-orm"; -import type * as Lysand from "lysand-types"; -import { db } from "~drizzle/db"; -import { LysandObjects } from "~drizzle/schema"; -import { findFirstUser } from "./User"; - -export type LysandObject = InferSelectModel; - -/** - * Represents a Lysand object in the database. - */ - -export const createFromObject = async ( - object: Lysand.Entity, - authorUri: string, -) => { - const foundObject = await db.query.LysandObjects.findFirst({ - where: (o, { eq }) => eq(o.remoteId, object.id), - with: { - author: true, - }, - }); - - if (foundObject) { - return foundObject; - } - - const author = await findFirstUser({ - where: (user, { eq }) => eq(user.uri, authorUri), - }); - - return await db.insert(LysandObjects).values({ - authorId: author?.id, - createdAt: new Date(object.created_at).toISOString(), - extensions: object.extensions, - remoteId: object.id, - type: object.type, - uri: object.uri, - // Rest of data (remove id, author, created_at, extensions, type, uri) - extraData: Object.fromEntries( - Object.entries(object).filter( - ([key]) => - ![ - "id", - "author", - "created_at", - "extensions", - "type", - "uri", - ].includes(key), - ), - ), - }); -}; - -export const toLysand = (lyObject: LysandObject): Lysand.Entity => { - return { - id: lyObject.remoteId || lyObject.id, - created_at: new Date(lyObject.createdAt).toISOString(), - type: lyObject.type, - uri: lyObject.uri, - ...(lyObject.extraData as object), - // @ts-expect-error Assume stored JSON is valid - extensions: lyObject.extensions as object, - }; -}; - -export const isPublication = (lyObject: LysandObject): boolean => { - return lyObject.type === "Note" || lyObject.type === "Patch"; -}; - -export const isAction = (lyObject: LysandObject): boolean => { - return [ - "Like", - "Follow", - "Dislike", - "FollowAccept", - "FollowReject", - "Undo", - "Announce", - ].includes(lyObject.type); -}; - -export const isActor = (lyObject: LysandObject): boolean => { - return lyObject.type === "User"; -}; - -export const isExtension = (lyObject: LysandObject): boolean => { - return lyObject.type === "Extension"; -}; diff --git a/database/entities/Queue.ts b/database/entities/Queue.ts deleted file mode 100644 index c44718ea..00000000 --- a/database/entities/Queue.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { config } from "config-manager"; -// import { Worker } from "bullmq"; - -/* export const federationWorker = new Worker( - "federation", - async job => { - await job.updateProgress(0); - - switch (job.name) { - case "federation": { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - const statusId = job.data.id as string; - - const status = await client.status.findUnique({ - where: { id: statusId }, - include: statusAndUserRelations, - }); - - if (!status) return; - - // Only get remote users that follow the author of the status, and the remote mentioned users - const peopleToSendTo = await client.user.findMany({ - where: { - OR: [ - ["public", "unlisted", "private"].includes( - status.visibility - ) - ? { - relationships: { - some: { - subjectId: status.authorId, - following: true, - }, - }, - instanceId: { - not: null, - }, - } - : {}, - // Mentioned users - { - id: { - in: status.mentions.map(m => m.id), - }, - instanceId: { - not: null, - }, - }, - ], - }, - }); - - let peopleDone = 0; - - // Spawn sendToServer job for each user - for (const person of peopleToSendTo) { - await federationQueue.add("sendToServer", { - id: statusId, - user: person, - }); - - peopleDone++; - - await job.updateProgress( - Math.round((peopleDone / peopleToSendTo.length) * 100) - ); - } - break; - } - case "sendToServer": { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - const statusId = job.data.id as string; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - const user = job.data.user as User; - - const status = await client.status.findUnique({ - where: { id: statusId }, - include: statusAndUserRelations, - }); - - if (!status) return; - - const response = await federateStatusTo( - status, - status.author, - user - ); - - if (response.status !== 200) { - throw new Error( - `Federation error: ${response.status} ${response.statusText}` - ); - } - - break; - } - } - - await job.updateProgress(100); - - return true; - }, - { - connection: { - host: config.redis.queue.host, - port: config.redis.queue.port, - password: config.redis.queue.password, - db: config.redis.queue.database || undefined, - }, - removeOnComplete: { - count: 400, - }, - removeOnFail: { - count: 3000, - }, - } -); */ - -export const addStatusFederationJob = async (statusId: string) => { - /* await federationQueue.add("federation", { - id: statusId, - }); */ -}; diff --git a/database/entities/Status.ts b/database/entities/Status.ts index 9e88a72f..06806f48 100644 --- a/database/entities/Status.ts +++ b/database/entities/Status.ts @@ -647,10 +647,3 @@ export const federateNote = async (note: Note) => { } } }; - -export const isFavouritedBy = async (status: Status, user: UserType) => { - return !!(await db.query.Likes.findFirst({ - where: (like, { and, eq }) => - and(eq(like.likerId, user.id), eq(like.likedId, status.id)), - })); -}; diff --git a/database/entities/User.ts b/database/entities/User.ts index 61e75107..467a1d18 100644 --- a/database/entities/User.ts +++ b/database/entities/User.ts @@ -34,11 +34,6 @@ export type UserWithRelations = UserType & { statusCount: number; }; -export type UserWithRelationsAndRelationships = UserWithRelations & { - relationships: InferSelectModel[]; - relationshipSubjects: InferSelectModel[]; -}; - export const userRelations: { instance: true; emojis: { @@ -99,16 +94,6 @@ export interface AuthData { application: Application | null; } -export const getFromRequest = async (req: Request): Promise => { - // Check auth token - const token = req.headers.get("Authorization")?.split(" ")[1] || ""; - - const { user, application } = - await retrieveUserAndApplicationFromToken(token); - - return { user, token, application }; -}; - export const getFromHeader = async (value: string): Promise => { const token = value.split(" ")[1]; @@ -388,15 +373,6 @@ export const resolveWebFinger = async ( return User.resolve(relevantLink.href); }; -/** - * Parses mentions from a list of URIs - */ -export const parseMentionsUris = async ( - mentions: string[], -): Promise => { - return await User.manyFromSql(inArray(Users.uri, mentions)); -}; - /** * Retrieves a user from a token. * @param access_token The access token to retrieve the user from. diff --git a/drizzle/types.ts b/drizzle/types.ts deleted file mode 100644 index c6f5db2c..00000000 --- a/drizzle/types.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { - BuildQueryResult, - DBQueryConfig, - ExtractTablesWithRelations, -} from "drizzle-orm"; - -import type * as schema from "./schema"; - -type Schema = typeof schema; -type TablesWithRelations = ExtractTablesWithRelations; - -export type IncludeRelation = - DBQueryConfig< - "one" | "many", - boolean, - TablesWithRelations, - TablesWithRelations[TableName] - >["with"]; - -export type IncludeColumns = - DBQueryConfig< - "one" | "many", - boolean, - TablesWithRelations, - TablesWithRelations[TableName] - >["columns"]; - -export type InferQueryModel< - TableName extends keyof TablesWithRelations, - Columns extends IncludeColumns | undefined = undefined, - With extends IncludeRelation | undefined = undefined, -> = BuildQueryResult< - TablesWithRelations, - TablesWithRelations[TableName], - { - columns: Columns; - with: With; - } ->; diff --git a/index.ts b/index.ts index ff785e75..16105825 100644 --- a/index.ts +++ b/index.ts @@ -11,9 +11,9 @@ import { ipBans } from "~middlewares/ip-bans"; import { logger } from "~middlewares/logger"; import { Note } from "~packages/database-interface/note"; import { handleGlitchRequest } from "~packages/glitch-server/main"; -import type { APIRouteExports } from "~packages/server-handler"; import { routes } from "~routes"; import { createServer } from "~server"; +import type { APIRouteExports } from "~types/api"; const timeAtStart = performance.now(); diff --git a/package.json b/package.json index 86dd24fd..752e6767 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,11 @@ "dev": "bun run --hot index.ts", "start": "NODE_ENV=production bun run dist/index.js --prod", "lint": "bunx @biomejs/biome check .", - "prod-build": "bun run build.ts", - "benchmark:timeline": "bun run benchmarks/timelines.ts", + "build": "bun run build.ts", "cloc": "cloc . --exclude-dir node_modules,dist,.output,.nuxt,meta,logs,glitch,glitch-dev --exclude-ext sql,log,pem", "wc": "find server database *.ts docs packages types utils drizzle tests -type f -print0 | wc -m --files0-from=-", - "cli": "bun run cli.ts" + "cli": "bun run cli.ts", + "prune": "ts-prune | grep -v server/ | grep -v dist/ | grep -v '(used in module)'" }, "trustedDependencies": [ "@biomejs/biome", @@ -62,6 +62,7 @@ "@types/pg": "^8.11.5", "bun-types": "latest", "drizzle-kit": "^0.20.14", + "ts-prune": "^0.10.3", "typescript": "latest" }, "peerDependencies": { @@ -71,7 +72,6 @@ "@hackmd/markdown-it-task-lists": "^2.1.4", "@hono/zod-validator": "^0.2.1", "@json2csv/plainjs": "^7.0.6", - "@shikijs/markdown-it": "^1.3.0", "@tufjs/canonical-json": "^2.0.0", "blurhash": "^2.0.5", "bullmq": "^5.7.1", @@ -102,7 +102,6 @@ "oauth4webapi": "^2.4.0", "pg": "^8.11.5", "qs": "^6.12.1", - "request-parser": "workspace:*", "sharp": "^0.33.3", "string-comparison": "^1.3.0", "stringify-entities": "^4.0.4", diff --git a/packages/request-parser/index.ts b/packages/request-parser/index.ts deleted file mode 100644 index 9559978b..00000000 --- a/packages/request-parser/index.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { parse } from "qs"; - -/** - * RequestParser - * Parses Request object into a JavaScript object - * based on the Content-Type header - * @param request Request object - * @returns JavaScript object of type T - */ -export class RequestParser { - constructor(public request: Request) {} - - /** - * Parse request body into a JavaScript object - * @returns JavaScript object of type T - * @throws Error if body is invalid - */ - async toObject() { - switch (await this.determineContentType()) { - case "application/json": - return { - ...(await this.parseJson()), - ...this.parseQuery(), - }; - case "application/x-www-form-urlencoded": - return { - ...(await this.parseFormUrlencoded()), - ...this.parseQuery(), - }; - case "multipart/form-data": - return { - ...(await this.parseFormData()), - ...this.parseQuery(), - }; - default: - return { ...this.parseQuery() } as T; - } - } - - /** - * Determine body content type - * If there is no Content-Type header, automatically - * guess content type. Cuts off after ";" character - * @returns Content-Type header value, or empty string if there is no body - * @throws Error if body is invalid - * @private - */ - private async determineContentType() { - const content_type = this.request.headers.get("Content-Type"); - - if (content_type?.startsWith("application/json")) { - return "application/json"; - } - - if (content_type?.startsWith("application/x-www-form-urlencoded")) { - return "application/x-www-form-urlencoded"; - } - - if (content_type?.startsWith("multipart/form-data")) { - return "multipart/form-data"; - } - - // Check if body is valid JSON - try { - await this.request.clone().json(); - return "application/json"; - } catch { - // This is not JSON - } - - // Check if body is valid FormData - try { - await this.request.clone().formData(); - return "multipart/form-data"; - } catch { - // This is not FormData - } - - if (content_type) { - return content_type.split(";")[0] ?? ""; - } - - if (this.request.body) { - throw new Error("Invalid body"); - } - - // If there is no body, return query parameters - return ""; - } - - /** - * Parse FormData body into a JavaScript object - * @returns JavaScript object of type T - * @private - * @throws Error if body is invalid - */ - private async parseFormData(): Promise> { - const formData = await this.request.clone().formData(); - const result: Partial = {}; - - // Extract the files from the FormData - for (const [key, value] of formData.entries()) { - if (value instanceof Blob) { - result[key as keyof T] = value as T[keyof T]; - } - } - - const formDataWithoutFiles = new FormData(); - for (const [key, value] of formData.entries()) { - if (!(value instanceof Blob)) { - formDataWithoutFiles.append(key, value); - } - } - - // Convert to URLSearchParams and parse as query - const searchParams = new URLSearchParams([ - ...formDataWithoutFiles.entries(), - ] as [string, string][]); - - const parsed = parse(searchParams.toString(), { - parseArrays: true, - interpretNumericEntities: true, - }); - - const casted = castBooleanObject( - parsed as PossiblyRecursiveObject, - ) as Partial; - - return { ...result, ...casted }; - } - - /** - * Parse application/x-www-form-urlencoded body into a JavaScript object - * @returns JavaScript object of type T - * @private - * @throws Error if body is invalid - */ - private async parseFormUrlencoded(): Promise> { - const parsed = parse(await this.request.text(), { - parseArrays: true, - interpretNumericEntities: true, - }); - - return castBooleanObject( - parsed as PossiblyRecursiveObject, - ) as Partial; - } - - /** - * Parse JSON body into a JavaScript object - * @returns JavaScript object of type T - * @private - * @throws Error if body is invalid - */ - private async parseJson(): Promise { - return (await this.request.json()) as T; - } - - /** - * Parse query parameters into a JavaScript object - * @private - * @throws Error if body is invalid - * @returns JavaScript object of type T - */ - parseQuery(): Partial { - const parsed = parse( - new URL(this.request.url).searchParams.toString(), - { - parseArrays: true, - interpretNumericEntities: true, - }, - ); - - return castBooleanObject( - parsed as PossiblyRecursiveObject, - ) as Partial; - } -} - -interface PossiblyRecursiveObject { - [key: string]: - | PossiblyRecursiveObject[] - | PossiblyRecursiveObject - | string - | string[] - | boolean; -} - -// Recursive -const castBooleanObject = (value: PossiblyRecursiveObject | string) => { - if (typeof value === "string") { - return castBoolean(value); - } - - for (const key in value) { - const child = value[key]; - if (Array.isArray(child)) { - value[key] = child.map((v) => castBooleanObject(v)) as string[]; - } else if (typeof child === "object") { - value[key] = castBooleanObject(child); - } else { - value[key] = castBoolean(child as string); - } - } - - return value; -}; - -const castBoolean = (value: string) => { - if (["true"].includes(value)) { - return true; - } - - if (["false"].includes(value)) { - return false; - } - - return value; -}; diff --git a/packages/request-parser/package.json b/packages/request-parser/package.json deleted file mode 100644 index 4697e599..00000000 --- a/packages/request-parser/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "request-parser", - "version": "0.0.0", - "main": "index.ts", - "dependencies": { "qs": "^6.12.1" }, - "devDependencies": { - "@types/qs": "^6.9.15" - } -} diff --git a/packages/request-parser/tests/request-parser.test.ts b/packages/request-parser/tests/request-parser.test.ts deleted file mode 100644 index e0eb2a61..00000000 --- a/packages/request-parser/tests/request-parser.test.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { describe, expect, it, test } from "bun:test"; -import { RequestParser } from ".."; - -describe("RequestParser", () => { - describe("Should parse query parameters correctly", () => { - test("With text parameters", async () => { - const request = new Request( - "http://localhost?param1=value1¶m2=value2", - ); - const result = await new RequestParser(request).parseQuery<{ - param1: string; - param2: string; - }>(); - expect(result).toEqual({ param1: "value1", param2: "value2" }); - }); - - test("With Array", async () => { - const request = new Request( - "http://localhost?test[]=value1&test[]=value2", - ); - const result = await new RequestParser(request).parseQuery<{ - test: string[]; - }>(); - expect(result?.test).toEqual(["value1", "value2"]); - }); - - test("With Array of objects", async () => { - const request = new Request( - "http://localhost?test[][key]=value1&test[][value]=value2", - ); - const result = await new RequestParser(request).parseQuery<{ - test: { key: string; value: string }[]; - }>(); - expect(result?.test).toEqual([{ key: "value1", value: "value2" }]); - }); - - test("With Array of multiple objects", async () => { - const request = new Request( - "http://localhost?test[][key]=value1&test[][value]=value2&test[][key]=value3&test[][value]=value4", - ); - const result = await new RequestParser(request).parseQuery<{ - test: { key: string[]; value: string[] }[]; - }>(); - expect(result?.test).toEqual([ - { key: ["value1", "value3"], value: ["value2", "value4"] }, - ]); - }); - - test("With both at once", async () => { - const request = new Request( - "http://localhost?param1=value1¶m2=value2&test[]=value1&test[]=value2", - ); - const result = await new RequestParser(request).parseQuery<{ - param1: string; - param2: string; - test: string[]; - }>(); - expect(result).toEqual({ - param1: "value1", - param2: "value2", - test: ["value1", "value2"], - }); - }); - }); - - it("should parse JSON body correctly", async () => { - const request = new Request("http://localhost", { - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ param1: "value1", param2: "value2" }), - }); - const result = await new RequestParser(request).toObject<{ - param1: string; - param2: string; - }>(); - expect(result).toEqual({ param1: "value1", param2: "value2" }); - }); - - it("should handle invalid JSON body", async () => { - const request = new Request("http://localhost", { - headers: { "Content-Type": "application/json" }, - body: "invalid json", - }); - const result = new RequestParser(request).toObject<{ - param1: string; - param2: string; - }>(); - expect(result).rejects.toThrow(); - }); - - describe("should parse form data correctly", () => { - test("With basic text parameters", async () => { - const formData = new FormData(); - formData.append("param1", "value1"); - formData.append("param2", "value2"); - const request = new Request("http://localhost", { - method: "POST", - body: formData, - }); - const result = await new RequestParser(request).toObject<{ - param1: string; - param2: string; - }>(); - expect(result).toEqual({ param1: "value1", param2: "value2" }); - }); - - test("With File object", async () => { - const file = new File(["content"], "filename.txt", { - type: "text/plain", - }); - const formData = new FormData(); - formData.append("file", file); - const request = new Request("http://localhost", { - method: "POST", - body: formData, - }); - const result = await new RequestParser(request).toObject<{ - file: File; - }>(); - expect(result?.file).toBeInstanceOf(File); - expect(await result?.file?.text()).toEqual("content"); - }); - - test("With Array", async () => { - const formData = new FormData(); - formData.append("test[]", "value1"); - formData.append("test[]", "value2"); - const request = new Request("http://localhost", { - method: "POST", - body: formData, - }); - const result = await new RequestParser(request).toObject<{ - test: string[]; - }>(); - expect(result?.test).toEqual(["value1", "value2"]); - }); - - test("With all three at once", async () => { - const file = new File(["content"], "filename.txt", { - type: "text/plain", - }); - const formData = new FormData(); - formData.append("param1", "value1"); - formData.append("param2", "value2"); - formData.append("file", file); - formData.append("test[]", "value1"); - formData.append("test[]", "value2"); - const request = new Request("http://localhost", { - method: "POST", - body: formData, - }); - const result = await new RequestParser(request).toObject<{ - param1: string; - param2: string; - file: File; - test: string[]; - }>(); - expect(result).toEqual({ - param1: "value1", - param2: "value2", - file: file, - test: ["value1", "value2"], - }); - }); - - test("URL Encoded", async () => { - const request = new Request("http://localhost", { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - body: "param1=value1¶m2=value2", - }); - const result = await new RequestParser(request).toObject<{ - param1: string; - param2: string; - }>(); - expect(result).toEqual({ param1: "value1", param2: "value2" }); - }); - }); -}); diff --git a/packages/server-handler/index.ts b/packages/server-handler/index.ts deleted file mode 100644 index 10fa5b6f..00000000 --- a/packages/server-handler/index.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { dualLogger } from "@loggers"; -import { errorResponse, jsonResponse, response } from "@response"; -import type { MatchedRoute } from "bun"; -import { type Config, config } from "config-manager"; -import type { Hono } from "hono"; -import type { RouterRoute } from "hono/types"; -import { LogLevel, type LogManager, type MultiLogManager } from "log-manager"; -import { RequestParser } from "request-parser"; -import type { ZodType, z } from "zod"; -import { fromZodError } from "zod-validation-error"; -import type { Application } from "~database/entities/Application"; -import { type AuthData, getFromRequest } from "~database/entities/User"; -import type { User } from "~packages/database-interface/user"; - -type MaybePromise = T | Promise; -export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS"; - -export type RouteHandler< - RouteMeta extends APIRouteMetadata, - ZodSchema extends ZodType, -> = ( - req: Request, - matchedRoute: MatchedRoute, - extraData: { - auth: { - // If the route doesn't require authentication, set the type to User | null - // Otherwise set to User - user: RouteMeta["auth"]["required"] extends true - ? User - : User | null; - token: RouteMeta["auth"]["required"] extends true - ? string - : string | null; - application: Application | null; - }; - parsedRequest: z.infer; - configManager: { - getConfig: () => Promise; - }; - }, -) => MaybePromise | MaybePromise; - -export interface APIRouteMetadata { - allowedMethods: HttpVerb[]; - ratelimits: { - max: number; - duration: number; - }; - route: string; - auth: { - required: boolean; - requiredOnMethods?: HttpVerb[]; - oauthPermissions?: string[]; - }; -} - -export interface APIRouteExports { - meta: APIRouteMetadata; - schemas?: { - query?: z.AnyZodObject; - body?: z.AnyZodObject; - }; - default: (app: Hono) => RouterRoute; -} - -export const processRoute = async ( - matchedRoute: MatchedRoute, - request: Request, - logger: LogManager | MultiLogManager, -): Promise => { - if (request.method === "OPTIONS") { - return response(); - } - - const route: APIRouteExports | null = await import( - matchedRoute.filePath - ).catch((e) => { - dualLogger.logError(LogLevel.ERROR, "Server.RouteImport", e as Error); - return null; - }); - - if (!route?.meta) { - return errorResponse("Route not found", 404); - } - - // Check if the request method is allowed - if (!route.meta.allowedMethods.includes(request.method as HttpVerb)) { - return errorResponse("Method not allowed", 405); - } - - const auth: AuthData = await getFromRequest(request); - - if ( - route.meta.auth.required || - route.meta.auth.requiredOnMethods?.includes(request.method as HttpVerb) - ) { - if (!auth.user) { - return errorResponse( - "Unauthorized: access to this method requires an authenticated user", - 401, - ); - } - } - - // Check if Content-Type header is missing if there is a body - if (request.clone().body) { - if (!request.headers.has("Content-Type")) { - return errorResponse( - `Content-Type header is missing but required on method ${request.method}`, - 400, - ); - } - } - - const parsedRequest = await new RequestParser(request.clone()) - .toObject() - .catch(async (err) => { - console.log(err); - await logger.logError( - LogLevel.ERROR, - "Server.RouteRequestParser", - err as Error, - ); - return null; - }); - - if (!parsedRequest) { - return errorResponse( - "The request could not be parsed, it may be malformed", - 400, - ); - } - - const parsingResult = route.schema?.safeParse(parsedRequest); - - if (parsingResult && !parsingResult.success) { - // Return a 422 error with the first error message - return errorResponse(fromZodError(parsingResult.error).toString(), 422); - } - - try { - const output = await route.default(request, matchedRoute, { - auth: { - token: auth?.token ?? null, - user: auth?.user ?? null, - application: auth?.application ?? null, - }, - parsedRequest: parsingResult - ? (parsingResult.data as z.infer) - : parsedRequest, - configManager: { - getConfig: async () => config as Config, - }, - }); - - // If the output is a normal JS object and not a Response, convert it to a jsonResponse - if (!(output instanceof Response)) { - return jsonResponse(output); - } - - return output; - } catch (err) { - await logger.log( - LogLevel.DEBUG, - "Server.RouteHandler", - (err as Error).toString(), - ); - await logger.logError( - LogLevel.ERROR, - "Server.RouteHandler", - err as Error, - ); - - return errorResponse( - `A server error occured: ${(err as Error).message}`, - 500, - ); - } -}; diff --git a/packages/server-handler/package.json b/packages/server-handler/package.json deleted file mode 100644 index ffb0f706..00000000 --- a/packages/server-handler/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "server-handler", - "version": "0.0.0", - "main": "index.ts", - "dependencies": { "zod": "^3.22.4", "zod-validation-error": "^3.2.0" } -} diff --git a/packages/server-handler/tests.test.ts b/packages/server-handler/tests.test.ts deleted file mode 100644 index 30ace68c..00000000 --- a/packages/server-handler/tests.test.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { afterAll, describe, expect, it, mock } from "bun:test"; -import type { MatchedRoute } from "bun"; -import { LogManager } from "log-manager"; -import { z } from "zod"; -import { getTestUsers } from "~tests/utils"; -import { type APIRouteExports, processRoute } from "."; - -describe("Route Processor", () => { - it("should return a Response", async () => { - mock.module( - "./route", - () => - ({ - default: async () => new Response(), - meta: { - allowedMethods: ["GET"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "GET", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output).toBeInstanceOf(Response); - }); - - it("should return a 404 when the route does not exist", async () => { - const output = await processRoute( - { - filePath: "./nonexistent-route", - } as MatchedRoute, - new Request("https://test.com/nonexistent-route"), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(404); - }); - - it("should return a 405 when the request method is not allowed", async () => { - mock.module( - "./route", - () => - ({ - default: async () => new Response(), - meta: { - allowedMethods: ["POST"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "GET", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(405); - }); - - it("should return a 401 when the route requires authentication but no user is authenticated", async () => { - mock.module( - "./route", - () => - ({ - default: async () => new Response(), - meta: { - allowedMethods: ["POST"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: true, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "POST", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(401); - }); - - it("should return a 400 when the Content-Type header is missing but there is a body", async () => { - mock.module( - "./route", - () => - ({ - default: async () => new Response(), - meta: { - allowedMethods: ["POST", "PUT", "PATCH"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "POST", - body: "test", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(400); - }); - - it("should return a 400 when the request could not be parsed", async () => { - mock.module( - "./route", - () => - ({ - default: async () => new Response(), - meta: { - allowedMethods: ["POST"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: "invalid-json", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(400); - }); - - it("should return a 422 when the request does not match the schema", async () => { - mock.module( - "./route", - () => - ({ - default: async () => new Response(), - meta: { - allowedMethods: ["POST"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({ - foo: z.string(), - }), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ bar: "baz" }), - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(422); - }); - - it("should convert any JS objects returned by the route to a Response", async () => { - mock.module( - "./route", - () => - ({ - default: async () => ({ status: 200 }), - meta: { - allowedMethods: ["GET"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "GET", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(200); - }); - - it("should handle route errors", async () => { - mock.module( - "./route", - () => - ({ - default: async () => { - throw new Error("Route error"); - }, - meta: { - allowedMethods: ["GET"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "GET", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(500); - }); - - it("should return the route output when everything is valid", async () => { - mock.module( - "./route", - () => - ({ - default: async () => new Response("OK"), - meta: { - allowedMethods: ["GET"], - ratelimits: { - max: 100, - duration: 60, - }, - route: "/route", - auth: { - required: false, - }, - }, - schema: z.object({}), - }) as APIRouteExports, - ); - - const output = await processRoute( - { - filePath: "./route", - } as MatchedRoute, - new Request("https://test.com/route", { - method: "GET", - }), - new LogManager(Bun.file("/dev/null")), - ); - - expect(output.status).toBe(200); - expect(await output.text()).toBe("OK"); - }); -}); diff --git a/routes.ts b/routes.ts index 7e6f5a60..828479da 100644 --- a/routes.ts +++ b/routes.ts @@ -21,9 +21,3 @@ for (const [route, path] of Object.entries(routes)) { routes = Object.fromEntries(Object.entries(routes).reverse()); export { routes }; - -export const matchRoute = (request: Request) => { - const route = routeMatcher.match(request); - - return route ?? null; -}; diff --git a/server/api/api/v1/accounts/:id/index.ts b/server/api/api/v1/accounts/:id/index.ts index 2f2682f1..24992d99 100644 --- a/server/api/api/v1/accounts/:id/index.ts +++ b/server/api/api/v1/accounts/:id/index.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, auth, handleZodError, idValidator } from "@api"; +import { applyConfig, auth, handleZodError, idValidator } from "@api"; import { zValidator } from "@hono/zod-validator"; import { errorResponse, jsonResponse } from "@response"; import type { Hono } from "hono"; 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 a3bd9102..e0fc4180 100644 --- a/server/api/api/v1/accounts/:id/remove_from_followers.ts +++ b/server/api/api/v1/accounts/:id/remove_from_followers.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, auth, handleZodError, idValidator } from "@api"; +import { applyConfig, auth, handleZodError, idValidator } from "@api"; import { zValidator } from "@hono/zod-validator"; import { errorResponse, jsonResponse } from "@response"; import { and, eq } from "drizzle-orm"; diff --git a/server/api/api/v1/accounts/index.ts b/server/api/api/v1/accounts/index.ts index c8506393..3bb77173 100644 --- a/server/api/api/v1/accounts/index.ts +++ b/server/api/api/v1/accounts/index.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, auth, handleZodError } from "@api"; +import { applyConfig, auth, handleZodError } from "@api"; import { zValidator } from "@hono/zod-validator"; import { jsonResponse, response } from "@response"; import { tempmailDomains } from "@tempmail"; diff --git a/server/api/api/v1/blocks/index.ts b/server/api/api/v1/blocks/index.ts index f21fe0f7..eb03b8c8 100644 --- a/server/api/api/v1/blocks/index.ts +++ b/server/api/api/v1/blocks/index.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, auth, handleZodError, idValidator } from "@api"; +import { applyConfig, auth, handleZodError, idValidator } from "@api"; import { zValidator } from "@hono/zod-validator"; import { errorResponse, jsonResponse } from "@response"; import { and, gt, gte, lt, sql } from "drizzle-orm"; diff --git a/server/api/api/v1/favourites/index.ts b/server/api/api/v1/favourites/index.ts index 5b95ed93..3b804b34 100644 --- a/server/api/api/v1/favourites/index.ts +++ b/server/api/api/v1/favourites/index.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, auth, handleZodError, idValidator } from "@api"; +import { applyConfig, auth, handleZodError, idValidator } from "@api"; import { zValidator } from "@hono/zod-validator"; import { errorResponse, jsonResponse } from "@response"; import { and, gt, gte, lt, sql } from "drizzle-orm"; diff --git a/server/api/api/v1/follow_requests/index.ts b/server/api/api/v1/follow_requests/index.ts index 950d44c0..707a92a3 100644 --- a/server/api/api/v1/follow_requests/index.ts +++ b/server/api/api/v1/follow_requests/index.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, auth, handleZodError, idValidator } from "@api"; +import { applyConfig, auth, handleZodError, idValidator } from "@api"; import { zValidator } from "@hono/zod-validator"; import { errorResponse, jsonResponse } from "@response"; import { and, gt, gte, lt, sql } from "drizzle-orm"; diff --git a/server/api/api/v1/notifications/index.ts b/server/api/api/v1/notifications/index.ts index 1da9c650..bb0db8e7 100644 --- a/server/api/api/v1/notifications/index.ts +++ b/server/api/api/v1/notifications/index.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, auth, handleZodError, idValidator } from "@api"; +import { applyConfig, auth, handleZodError, idValidator } from "@api"; import { zValidator } from "@hono/zod-validator"; import { errorResponse, jsonResponse } from "@response"; import { fetchTimeline } from "@timelines"; diff --git a/server/api/objects/[uuid]/index.ts b/server/api/objects/[uuid]/index.ts index 895b6aa0..9d7525b5 100644 --- a/server/api/objects/[uuid]/index.ts +++ b/server/api/objects/[uuid]/index.ts @@ -1,4 +1,4 @@ -import { apiRoute, applyConfig, handleZodError } from "@api"; +import { applyConfig, handleZodError } from "@api"; import { zValidator } from "@hono/zod-validator"; import { errorResponse, jsonResponse } from "@response"; import { and, eq, inArray, sql } from "drizzle-orm"; diff --git a/types/activitypub.ts b/types/activitypub.ts deleted file mode 100644 index ae4d8a83..00000000 --- a/types/activitypub.ts +++ /dev/null @@ -1,141 +0,0 @@ -export type APActivityPubContext = - | "https://www.w3.org/ns/activitystreams" - | { - ostatus: string; - atomUri: string; - inReplyToAtomUri: string; - conversation: string; - sensitive: string; - toot: string; - votersCount: string; - litepub: string; - directMessage: string; - }; - -export interface APActivityPubObject { - id: string; - type: string; - summary?: string; - inReplyTo?: string; - published: string; - url: string; - attributedTo: string; - to: string[]; - cc: string[]; - sensitive?: boolean; - atomUri: string; - inReplyToAtomUri?: string; - conversation: string; - content: string; - contentMap: Record; - attachment: APActivityPubAttachment[]; - tag: APTag[]; - context?: string; - quoteUri?: string; - quoteUrl?: string; - source?: { - content: string; - mediaType: string; - }; -} - -export interface APActivityPubAttachment { - type?: string; - mediaType?: string; - url?: string; - name?: string; -} - -export interface APActivityPubCollection { - id: string; - type: string; - first?: { - type: string; - next: string; - partOf: string; - items: T[]; - }; -} - -export interface APActivityPubNote extends APActivityPubObject { - type: "Note"; -} - -export interface APActivityPubActivity { - "@context": APActivityPubContext[]; - id: string; - type: string; - actor: string; - published: string; - to: string[]; - cc: string[]; - object: APActivityPubNote; -} - -export type APActorContext = - | "https://www.w3.org/ns/activitystreams" - | "https://w3id.org/security/v1" - | Record< - string, - | string - | { "@id": string; "@type": string } - | { "@container": string; "@id": string } - >; - -export interface APActorPublicKey { - id: string; - owner: string; - publicKeyPem: string; -} - -export interface APActorEndpoints { - sharedInbox: string; -} - -export interface APActorIcon { - type: string; - mediaType: string; - url: string; -} - -export interface APActor { - "@context": APActorContext[]; - id: string; - type: string; - following: string; - followers: string; - inbox: string; - outbox: string; - featured: string; - featuredTags: string; - preferredUsername: string; - name: string; - summary: string; - url: string; - manuallyApprovesFollowers: boolean; - discoverable: boolean; - indexable: boolean; - published: string; - memorial: boolean; - devices: string; - publicKey: APActorPublicKey; - tag: APTag[]; - attachment: APAttachment[]; - endpoints: APActorEndpoints; - icon: APActorIcon; -} - -export interface APTag { - type: string; - href: string; - name: string; -} - -export interface APAttachment { - type: string; - mediaType: string; - url: string; - name?: string; - blurhash?: string; - description?: string; -} diff --git a/types/api.ts b/types/api.ts index 7b695f52..48208962 100644 --- a/types/api.ts +++ b/types/api.ts @@ -1,5 +1,10 @@ -export interface APIRouteMeta { - allowedMethods: ("GET" | "POST" | "PUT" | "DELETE" | "PATCH")[]; +import type { Hono } from "hono"; +import type { RouterRoute } from "hono/types"; +import type { z } from "zod"; + +export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS"; +export interface APIRouteMetadata { + allowedMethods: HttpVerb[]; ratelimits: { max: number; duration: number; @@ -7,7 +12,16 @@ export interface APIRouteMeta { route: string; auth: { required: boolean; - requiredOnMethods?: ("GET" | "POST" | "PUT" | "DELETE" | "PATCH")[]; + requiredOnMethods?: HttpVerb[]; oauthPermissions?: string[]; }; } + +export interface APIRouteExports { + meta: APIRouteMetadata; + schemas?: { + query?: z.AnyZodObject; + body?: z.AnyZodObject; + }; + default: (app: Hono) => RouterRoute; +} diff --git a/types/lysand/Extension.ts b/types/lysand/Extension.ts deleted file mode 100644 index ebdefa56..00000000 --- a/types/lysand/Extension.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { LysandObjectType } from "./Object"; - -export interface ExtensionType extends LysandObjectType { - type: "Extension"; - extension_type: string; -} diff --git a/types/lysand/Object.ts b/types/lysand/Object.ts deleted file mode 100644 index 86103f1d..00000000 --- a/types/lysand/Object.ts +++ /dev/null @@ -1,177 +0,0 @@ -import type { Emoji } from "./extensions/org.lysand/custom_emojis"; - -export interface LysandObjectType { - type: string; - id: string; // Either a UUID or some kind of time-based UUID-compatible system - uri: string; // URI to the note - created_at: string; - extensions?: { - // Should be in the format - // "organization:extension_name": value - // Example: "org.joinmastodon:spoiler_text": "This is a spoiler!" - "org.lysand:custom_emojis"?: { - emojis: Emoji[]; - }; - "org.lysand:reactions"?: { - reactions: string; - }; - "org.lysand:polls"?: { - poll: { - options: ContentFormat[][]; - votes: number[]; - expires_at: string; - multiple_choice: boolean; - }; - }; - - [key: string]: Record | undefined; - }; -} - -export interface ActorPublicKeyData { - public_key: string; - actor: string; -} - -export interface Collection { - first: string; - last: string; - next?: string; - prev?: string; - items: T[]; -} - -export interface LysandUser extends LysandObjectType { - type: "User"; - bio: ContentFormat[]; - - inbox: string; - outbox: string; - followers: string; - following: string; - liked: string; - disliked: string; - featured: string; - - indexable: boolean; - fields?: { - key: ContentFormat[]; - value: ContentFormat[]; - }[]; - display_name?: string; - public_key?: ActorPublicKeyData; - username: string; - avatar?: ContentFormat[]; - header?: ContentFormat[]; -} - -export interface LysandPublication extends LysandObjectType { - type: "Note" | "Patch"; - author: string; - contents: ContentFormat[]; - mentions: string[]; - replies_to: string[]; - quotes: string[]; - is_sensitive: boolean; - subject: string; - attachments: ContentFormat[][]; -} - -export interface LysandAction extends LysandObjectType { - type: - | "Like" - | "Dislike" - | "Follow" - | "FollowAccept" - | "FollowReject" - | "Announce" - | "Undo" - | "Extension"; - author: string; -} - -/** - * A Note is a publication on the network, such as a post or comment - */ -export interface Note extends LysandPublication { - type: "Note"; -} - -/** - * A Patch is an edit to a Note - */ -export interface Patch extends LysandPublication { - type: "Patch"; - patched_id: string; - patched_at: string; -} - -export interface Like extends LysandAction { - type: "Like"; - object: string; -} - -export interface Dislike extends LysandAction { - type: "Dislike"; - object: string; -} - -export interface Announce extends LysandAction { - type: "Announce"; - object: string; -} - -export interface Undo extends LysandAction { - type: "Undo"; - object: string; -} - -export interface Follow extends LysandAction { - type: "Follow"; - followee: string; -} - -export interface FollowAccept extends LysandAction { - type: "FollowAccept"; - follower: string; -} - -export interface FollowReject extends LysandAction { - type: "FollowReject"; - follower: string; -} - -export interface ServerMetadata extends LysandObjectType { - type: "ServerMetadata"; - name: string; - version?: string; - description?: string; - website?: string; - moderators?: string[]; - admins?: string[]; - logo?: ContentFormat[]; - banner?: ContentFormat[]; - supported_extensions?: string[]; -} - -/** - * Content format is an array of objects that contain the content and the content type. - */ -export interface ContentFormat { - content: string; - content_type: string; - description?: string; - size?: number; - hash?: { - md5?: string; - sha1?: string; - sha256?: string; - sha512?: string; - [key: string]: string | undefined; - }; - blurhash?: string; - fps?: number; - width?: number; - height?: number; - duration?: number; -} diff --git a/types/lysand/extensions/org.lysand/custom_emojis.ts b/types/lysand/extensions/org.lysand/custom_emojis.ts deleted file mode 100644 index f2070357..00000000 --- a/types/lysand/extensions/org.lysand/custom_emojis.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ContentFormat } from "../../Object"; - -export interface Emoji { - name: string; - url: ContentFormat[]; - alt?: string; -} diff --git a/types/lysand/extensions/org.lysand/polls.ts b/types/lysand/extensions/org.lysand/polls.ts deleted file mode 100644 index ec89ba11..00000000 --- a/types/lysand/extensions/org.lysand/polls.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ExtensionType } from "../../Extension"; - -export interface OrgLysandPollsVoteType extends ExtensionType { - extension_type: "org.lysand:polls/Vote"; - author: string; - poll: string; - option: number; -} - -export interface OrgLysandPollsVoteResultType extends ExtensionType { - extension_type: "org.lysand:polls/VoteResult"; - poll: string; - votes: number[]; -} diff --git a/types/lysand/extensions/org.lysand/reactions.ts b/types/lysand/extensions/org.lysand/reactions.ts deleted file mode 100644 index 677f52ff..00000000 --- a/types/lysand/extensions/org.lysand/reactions.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ExtensionType } from "../../Extension"; - -export interface OrgLysandReactionsType extends ExtensionType { - extension_type: "org.lysand:reactions/Reaction"; - author: string; - object: string; - content: string; -} diff --git a/utils/api.ts b/utils/api.ts index 63bd38f6..ebd87632 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -13,17 +13,12 @@ import { exactly, } from "magic-regexp"; import { parse } from "qs"; -import type { - APIRouteExports, - APIRouteMetadata, - HttpVerb, - RouteHandler, -} from "server-handler"; import type { z } from "zod"; import { fromZodError } from "zod-validation-error"; import type { Application } from "~database/entities/Application"; -import { getFromHeader, getFromRequest } from "~database/entities/User"; +import { getFromHeader } from "~database/entities/User"; import type { User } from "~packages/database-interface/user"; +import type { APIRouteMetadata, HttpVerb } from "~types/api"; export const applyConfig = (routeMeta: APIRouteMetadata) => { const newMeta = routeMeta; @@ -39,15 +34,6 @@ export const applyConfig = (routeMeta: APIRouteMetadata) => { return newMeta; }; -export const apiRoute = < - Metadata extends APIRouteMetadata, - ZodSchema extends Zod.AnyZodObject, ->( - routeFunction: APIRouteExports["default"], -) => { - return routeFunction; -}; - export const idValidator = createRegExp( anyOf(digit, charIn("ABCDEF")).times(8), exactly("-"), diff --git a/utils/meilisearch.ts b/utils/meilisearch.ts index c4ff79b1..09b6e919 100644 --- a/utils/meilisearch.ts +++ b/utils/meilisearch.ts @@ -3,8 +3,6 @@ import { config } from "config-manager"; import { count } from "drizzle-orm"; import { LogLevel, type LogManager, type MultiLogManager } from "log-manager"; import { Meilisearch } from "meilisearch"; -import type { Status } from "~database/entities/Status"; -import type { UserType } from "~database/entities/User"; import { db } from "~drizzle/db"; import { Notes, Users } from "~drizzle/schema"; import type { User } from "~packages/database-interface/user"; @@ -54,18 +52,6 @@ export enum MeiliIndexType { Statuses = "statuses", } -export const addStausToMeilisearch = async (status: Status) => { - if (!config.meilisearch.enabled) return; - - await meilisearch.index(MeiliIndexType.Statuses).addDocuments([ - { - id: status.id, - content: status.content, - createdAt: status.createdAt, - }, - ]); -}; - export const addUserToMeilisearch = async (user: User) => { if (!config.meilisearch.enabled) return; diff --git a/utils/merge.ts b/utils/merge.ts deleted file mode 100644 index 87d77345..00000000 --- a/utils/merge.ts +++ /dev/null @@ -1,17 +0,0 @@ -export const deepMerge = ( - target: Record, - source: Record, -) => { - const result = { ...target, ...source }; - for (const key of Object.keys(result)) { - result[key] = - typeof target[key] === "object" && typeof source[key] === "object" - ? // @ts-expect-error deepMerge is recursive - deepMerge(target[key], source[key]) - : structuredClone(result[key]); - } - return result; -}; - -export const deepMergeArray = (array: Record[]) => - array.reduce((ci, ni) => deepMerge(ci, ni), {}); diff --git a/utils/module.ts b/utils/module.ts deleted file mode 100644 index a9aefd6a..00000000 --- a/utils/module.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { fileURLToPath } from "node:url"; - -/** - * Determines whether a module is the entry point for the running node process. - * This works for both CommonJS and ES6 environments. - * - * ### CommonJS - * ```js - * if (moduleIsEntry(module)) { - * console.log('WOO HOO!!!'); - * } - * ``` - * - * ### ES6 - * ```js - * if (moduleIsEntry(import.meta.url)) { - * console.log('WOO HOO!!!'); - * } - * ``` - */ -export const moduleIsEntry = (moduleOrImportMetaUrl: NodeModule | string) => { - if (typeof moduleOrImportMetaUrl === "string") { - return process.argv[1] === fileURLToPath(moduleOrImportMetaUrl); - } - - if (typeof require !== "undefined" && "exports" in moduleOrImportMetaUrl) { - return require.main === moduleOrImportMetaUrl; - } - - return false; -}; diff --git a/utils/oauth.ts b/utils/oauth.ts index a7dcc0c2..bf46088c 100644 --- a/utils/oauth.ts +++ b/utils/oauth.ts @@ -59,5 +59,3 @@ export const checkIfOauthIsValid = ( return false; }; - -export const oauthCodeVerifiers: Record = {}; diff --git a/utils/temp.ts b/utils/temp.ts deleted file mode 100644 index 865a1b59..00000000 --- a/utils/temp.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { exists, mkdir, readFile, writeFile } from "node:fs/promises"; -import { join } from "node:path"; - -export const writeToTempDirectory = async (filename: string, data: string) => { - const tempDir = join("/tmp/", "lysand"); - if (!(await exists(tempDir))) await mkdir(tempDir); - - const tempFile = join(tempDir, filename); - await writeFile(tempFile, data); - - return tempFile; -}; - -export const readFromTempDirectory = async (filename: string) => { - const tempDir = join("/tmp/", "lysand"); - if (!(await exists(tempDir))) await mkdir(tempDir); - - const tempFile = join(tempDir, filename); - return readFile(tempFile, "utf-8"); -};