fix: 🚨 Enable more Biome 2.0 rules
Some checks failed
CodeQL Scan / Analyze (javascript-typescript) (push) Failing after 4s
Build Docker Images / lint (push) Failing after 10s
Build Docker Images / check (push) Failing after 10s
Build Docker Images / tests (push) Failing after 6s
Deploy Docs to GitHub Pages / build (push) Failing after 0s
Build Docker Images / build (server, Dockerfile, ${{ github.repository_owner }}/server) (push) Has been skipped
Build Docker Images / build (worker, Worker.Dockerfile, ${{ github.repository_owner }}/worker) (push) Has been skipped
Deploy Docs to GitHub Pages / Deploy (push) Has been skipped
Mirror to Codeberg / Mirror (push) Failing after 0s
Nix Build / check (push) Failing after 0s

This commit is contained in:
Jesse Wierzbinski 2025-04-10 19:56:42 +02:00
parent 963173cdae
commit 1679585c4c
No known key found for this signature in database
21 changed files with 116 additions and 53 deletions

3
app.ts
View file

@ -27,6 +27,7 @@ import { routes } from "./routes.ts";
import type { ApiRouteExports, HonoEnv } from "./types/api.ts";
// Extends Zod with OpenAPI schema generation
import "zod-openapi/extend";
import { cwd } from "node:process";
export const appFactory = async (): Promise<Hono<HonoEnv>> => {
await configureLoggers();
@ -121,7 +122,7 @@ export const appFactory = async (): Promise<Hono<HonoEnv>> => {
const loader = new PluginLoader();
const plugins = await loader.loadPlugins(
join(process.cwd(), "plugins"),
join(cwd(), "plugins"),
config.plugins?.autoload ?? true,
config.plugins?.overrides.enabled,
config.plugins?.overrides.disabled,

View file

@ -45,6 +45,23 @@
},
"useLiteralEnumMembers": "error",
"noCommaOperator": "error",
"noNegationElse": "error",
"noYodaExpression": "error",
"useBlockStatements": "error",
"useCollapsedElseIf": "error",
"useConsistentArrayType": {
"level": "error",
"options": {
"syntax": "shorthand"
}
},
"useConsistentBuiltinInstantiation": "error",
"useExplicitLengthCheck": "error",
"useForOf": "error",
"useNodeAssertStrict": "error",
"useShorthandAssign": "error",
"useThrowNewError": "error",
"useThrowOnlyError": "error",
"useNodejsImportProtocol": "error",
"useAsConstAssertion": "error",
"useNumericLiterals": "error",
@ -67,16 +84,39 @@
"useShorthandFunctionType": "error"
},
"correctness": {
"useImportExtensions": "error"
"useImportExtensions": "error",
"noConstantMathMinMaxClamp": "error",
"noUndeclaredDependencies": "error",
"noUnusedFunctionParameters": "error",
"noUnusedImports": "error",
"noUnusedPrivateClassMembers": "error",
"useArrayLiterals": "error"
},
"nursery": {
"noBitwiseOperators": "error",
"noConstantBinaryExpression": "error",
"noFloatingPromises": "error",
"noGlobalDirnameFilename": "error",
"noOctalEscape": "error",
"noProcessEnv": "error",
"noDuplicateElseIf": "warn",
"noProcessGlobal": "warn",
"noTsIgnore": "warn",
"useAtIndex": "warn",
"useCollapsedIf": "warn",
"useConsistentObjectDefinition": {
"level": "warn",
"options": {
"syntax": "shorthand"
}
},
"useConsistentMemberAccessibility": {
"level": "warn",
"options": {
"accessibility": "explicit"
}
},
"useParseIntRadix": "warn",
"noCommonJs": "warn",
"noDynamicNamespaceImportAccess": "warn",
"noExportedImports": "warn",
@ -91,11 +131,21 @@
"useTrimStartEnd": "warn"
},
"complexity": {
"noExcessiveCognitiveComplexity": "off"
"noForEach": "error",
"noUselessStringConcat": "error",
"useDateNow": "error",
"useSimplifiedLogicExpression": "error",
"useWhile": "error"
},
"suspicious": {
"noMisplacedAssertion": "off",
"noConsole": "off"
"noDuplicateTestHooks": "error",
"noEmptyBlockStatements": "error",
"noEvolvingTypes": "error",
"noExportsInTest": "error",
"noVar": "error",
"useAwait": "error",
"useErrorMessage": "error",
"useNumberToFixedDigitsArgument": "error"
}
}
},

View file

@ -93,12 +93,16 @@
"version": "0.2.0-alpha.1",
"dependencies": {
"@badgateway/oauth2-client": "^2.4.2",
"iso-639-1": "^3.1.5",
"zod": "^3.24.2",
},
},
"packages/plugin-kit": {
"name": "@versia/kit",
"version": "0.0.0",
"dependencies": {
"drizzle-orm": "^0.41.0",
"hono": "^4.7.6",
"mitt": "^3.0.1",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.3",
@ -108,6 +112,11 @@
"packages/sdk": {
"name": "@versia/sdk",
"version": "0.0.1",
"dependencies": {
"magic-regexp": "^0.9.0",
"mime-types": "^3.0.1",
"zod": "^3.24.2",
},
},
},
"trustedDependencies": [

View file

@ -141,11 +141,11 @@ export class Timeline<Type extends Note | User | Notification> {
if (notes.length >= (limit ?? 20)) {
const objectAfter = await Note.fromSql(
gt(Notes.id, notes[notes.length - 1].data.id),
gt(Notes.id, notes.at(-1)?.data.id ?? ""),
);
if (objectAfter) {
linkHeader.push(
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${notes[notes.length - 1].data.id}>; rel="next"`,
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${notes.at(-1)?.data.id}>; rel="next"`,
);
}
}
@ -169,11 +169,11 @@ export class Timeline<Type extends Note | User | Notification> {
if (users.length >= (limit ?? 20)) {
const objectAfter = await User.fromSql(
gt(Users.id, users[users.length - 1].id),
gt(Users.id, users.at(-1)?.id ?? ""),
);
if (objectAfter) {
linkHeader.push(
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${users[users.length - 1].id}>; rel="next"`,
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${users.at(-1)?.id}>; rel="next"`,
);
}
}
@ -199,14 +199,11 @@ export class Timeline<Type extends Note | User | Notification> {
if (notifications.length >= (limit ?? 20)) {
const objectAfter = await Notification.fromSql(
gt(
Notifications.id,
notifications[notifications.length - 1].data.id,
),
gt(Notifications.id, notifications.at(-1)?.data.id ?? ""),
);
if (objectAfter) {
linkHeader.push(
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${notifications[notifications.length - 1].data.id}>; rel="next"`,
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${notifications.at(-1)?.data.id}>; rel="next"`,
);
}
}

View file

@ -499,7 +499,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
await note.author.notify("favourite", this, note);
} else if (this.local && note.author.remote) {
// Federate the like
this.federateToFollowers(newLike.toVersia());
await this.federateToFollowers(newLike.toVersia());
}
return newLike;
@ -528,7 +528,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
await likeToDelete.clearRelatedNotifications();
} else if (this.local && note.author.remote) {
// User is local, federate the delete
this.federateToFollowers(likeToDelete.unlikeToVersia(this));
await this.federateToFollowers(likeToDelete.unlikeToVersia(this));
}
}

View file

@ -52,7 +52,7 @@ const isConvertible = (
*/
const extractFilenameFromPath = (path: string): string => {
const pathParts = path.split(/(?<!\\)\//);
return pathParts[pathParts.length - 1];
return pathParts.at(-1) as string;
};
/**

View file

@ -1,4 +1,5 @@
// @ts-expect-error - Root import is required or the Clec type definitions won't work
// biome-ignore lint/correctness/noUnusedImports: Root import is required or the Clec type definitions won't work
import { defineCommand, type Root } from "clerc";
import ora from "ora";
import {

View file

@ -1,5 +1,6 @@
import chalk from "chalk";
// @ts-expect-error - Root import is required or the Clec type definitions won't work
// biome-ignore lint/correctness/noUnusedImports: Root import is required or the Clec type definitions won't work
import { defineCommand, type Root } from "clerc";
import { eq } from "drizzle-orm";
import { Instance } from "~/classes/database/instance.ts";

View file

@ -1,5 +1,6 @@
import chalk from "chalk";
// @ts-expect-error - Root import is required or the Clec type definitions won't work
// biome-ignore lint/correctness/noUnusedImports: Root import is required or the Clec type definitions won't work
import { defineCommand, type Root } from "clerc";
import { and, eq, isNull } from "drizzle-orm";
import { renderUnicodeCompact } from "uqr";

View file

@ -1,6 +1,7 @@
import confirm from "@inquirer/confirm";
import chalk from "chalk";
// @ts-expect-error - Root import is required or the Clec type definitions won't work
// biome-ignore lint/correctness/noUnusedImports: Root import is required or the Clec type definitions won't work
import { defineCommand, type Root } from "clerc";
import { retrieveUser } from "../utils.ts";

View file

@ -1,5 +1,6 @@
import chalk from "chalk";
// @ts-expect-error - Root import is required or the Clec type definitions won't work
// biome-ignore lint/correctness/noUnusedImports: Root import is required or the Clec type definitions won't work
import { defineCommand, type Root } from "clerc";
import ora from "ora";
import { User } from "~/classes/database/user.ts";

View file

@ -1,6 +1,7 @@
import { randomUUIDv7 } from "bun";
import chalk from "chalk";
// @ts-expect-error - Root import is required or the Clec type definitions won't work
// biome-ignore lint/correctness/noUnusedImports: Root import is required or the Clec type definitions won't work
import { defineCommand, type Root } from "clerc";
import { randomString } from "@/math.ts";
import { Token } from "~/classes/database/token.ts";

View file

@ -1,4 +1,5 @@
import cluster from "node:cluster";
import process from "node:process";
import { Youch } from "youch";
import { sentry } from "@/sentry";
import { createServer } from "@/server";

View file

@ -1,3 +1,4 @@
import process from "node:process";
import { getLogger } from "@logtape/logtape";
import chalk from "chalk";
import { sentry } from "@/sentry";

View file

@ -5,14 +5,15 @@ export const boundaryCheck = createMiddleware(async (context, next) => {
// Checks that FormData boundary is present
const contentType = context.req.header("content-type");
if (contentType?.includes("multipart/form-data")) {
if (!contentType.includes("boundary")) {
throw new ApiError(
400,
"Missing FormData boundary",
"You are sending a request with a multipart/form-data content type but without a boundary. Please include a boundary in the Content-Type header. For more information, visit https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data",
);
}
if (
contentType?.includes("multipart/form-data") &&
!contentType.includes("boundary")
) {
throw new ApiError(
400,
"Missing FormData boundary",
"You are sending a request with a multipart/form-data content type but without a boundary. Please include a boundary in the Content-Type header. For more information, visit https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data",
);
}
await next();

View file

@ -63,6 +63,8 @@
],
"packageManager": "bun@1.2.5",
"dependencies": {
"@badgateway/oauth2-client": "^2.4.2"
"@badgateway/oauth2-client": "^2.4.2",
"iso-639-1": "^3.1.5",
"zod": "^3.24.2"
}
}

View file

@ -151,11 +151,9 @@ export class BaseClient {
if (this.accessToken) {
headers.set("Authorization", `Bearer ${this.accessToken}`);
}
if (body) {
if (!(body instanceof FormData)) {
headers.set("Content-Type", "application/json; charset=utf-8");
} // else: let FormData set the content type, as it knows best (boundary, etc.)
}
if (body && !(body instanceof FormData)) {
headers.set("Content-Type", "application/json; charset=utf-8");
} // else: let FormData set the content type, as it knows best (boundary, etc.)
for (const [key, value] of Object.entries(extra?.headers || {})) {
headers.set(key, value);

View file

@ -1229,10 +1229,8 @@ export class Client extends BaseClient {
): Promise<Output<z.infer<typeof Account>[]>> {
const params = new URLSearchParams();
if (options) {
if (options.limit) {
params.set("limit", options.limit.toString());
}
if (options?.limit) {
params.set("limit", options.limit.toString());
}
return this.get<z.infer<typeof Account>[]>(
@ -1449,10 +1447,8 @@ export class Client extends BaseClient {
): Promise<Output<z.infer<typeof Tag>[]>> {
const params = new URLSearchParams();
if (options) {
if (options.limit) {
params.set("limit", options.limit.toString());
}
if (options?.limit) {
params.set("limit", options.limit.toString());
}
return this.get<z.infer<typeof Tag>[]>(`/api/v1/trends?${params}`);
@ -1839,10 +1835,8 @@ export class Client extends BaseClient {
params.append("id[]", id);
}
if (options) {
if (options.with_suspended) {
params.set("with_suspended", "true");
}
if (options?.with_suspended) {
params.set("with_suspended", "true");
}
return this.get<z.infer<typeof Relationship>[]>(
@ -2121,10 +2115,8 @@ export class Client extends BaseClient {
): Promise<Output<z.infer<typeof Account>[]>> {
const params = new URLSearchParams();
if (options) {
if (options.limit) {
params.set("limit", options.limit.toString());
}
if (options?.limit) {
params.set("limit", options.limit.toString());
}
return this.get<z.infer<typeof Account>[]>(

View file

@ -32,6 +32,8 @@
},
"private": true,
"dependencies": {
"drizzle-orm": "^0.41.0",
"hono": "^4.7.6",
"mitt": "^3.0.1",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.3",

View file

@ -71,5 +71,10 @@
"typescript",
"sdk"
],
"packageManager": "bun@1.2.5"
"packageManager": "bun@1.2.5",
"dependencies": {
"magic-regexp": "^0.9.0",
"mime-types": "^3.0.1",
"zod": "^3.24.2"
}
}

View file

@ -1,17 +1,15 @@
import { join } from "node:path";
import { cwd } from "node:process";
import { FileSystemRouter } from "bun";
// Returns the route filesystem path when given a URL
export const routeMatcher = new FileSystemRouter({
style: "nextjs",
dir: `${process.cwd()}/api`,
dir: `${cwd()}/api`,
fileExtensions: [".ts", ".js"],
});
export const routes = Object.fromEntries(
Object.entries(routeMatcher.routes)
.filter(([route]) => !route.endsWith(".test"))
.map(([route, path]) => [
route,
path.replace(join(process.cwd()), "."),
]),
.map(([route, path]) => [route, path.replace(join(cwd()), ".")]),
) as Record<string, string>;