From 25fcd99acfa146107f12cfaf00a617dcf7ab0510 Mon Sep 17 00:00:00 2001 From: creations Date: Sun, 13 Apr 2025 09:14:23 -0400 Subject: [PATCH] move to biomejs, this is before unsafe lint run --- .forgejo/workflows/biomejs.yml | 24 +++ .vscode/extensions.json | 7 +- biome.json | 35 ++++ config/environment.ts | 7 +- config/sql/avatars.ts | 2 +- config/sql/files.ts | 2 +- config/sql/folders.ts | 2 +- config/sql/invites.ts | 2 +- config/sql/settings.ts | 10 +- config/sql/users.ts | 5 +- eslint.config.js | 142 ----------------- package.json | 38 ++--- public/css/auth.css | 220 +++++++++++++------------- public/css/dashboard/index.css | 38 ++--- public/css/global.css | 22 ++- public/js/auth.js | 15 +- src/helpers/auth.ts | 2 +- src/helpers/char.ts | 20 +-- src/helpers/ejs.ts | 2 +- src/helpers/logger.ts | 22 +-- src/helpers/redis.ts | 13 +- src/helpers/sessions.ts | 19 +-- src/helpers/workers/thumbnails.ts | 27 +--- src/index.ts | 13 +- src/routes/api/auth/login.ts | 10 +- src/routes/api/auth/register.ts | 16 +- src/routes/api/files/delete[query].ts | 20 +-- src/routes/api/files/upload.ts | 34 ++-- src/routes/api/invite/create.ts | 4 +- src/routes/api/settings/set.ts | 3 +- src/routes/api/user/avatar/delete.ts | 6 +- src/routes/api/user/avatar/set.ts | 11 +- src/routes/api/user/files.ts | 15 +- src/routes/api/user/info[query].ts | 2 +- src/routes/auth/register.ts | 3 +- src/routes/dashboard/index.ts | 1 + src/routes/raw/[query].ts | 10 +- src/routes/user/avatar/[user].ts | 7 +- src/server.ts | 32 +--- src/views/partials/sidebar.ejs | 4 +- src/websocket.ts | 8 +- stylelint.config.js | 9 -- tsconfig.json | 34 +--- 43 files changed, 353 insertions(+), 565 deletions(-) create mode 100644 .forgejo/workflows/biomejs.yml create mode 100644 biome.json delete mode 100644 eslint.config.js delete mode 100644 stylelint.config.js diff --git a/.forgejo/workflows/biomejs.yml b/.forgejo/workflows/biomejs.yml new file mode 100644 index 0000000..15c990c --- /dev/null +++ b/.forgejo/workflows/biomejs.yml @@ -0,0 +1,24 @@ +name: Code quality checks + +on: + push: + pull_request: + +jobs: + biome: + runs-on: docker + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Bun + run: | + curl -fsSL https://bun.sh/install | bash + export BUN_INSTALL="$HOME/.bun" + echo "$BUN_INSTALL/bin" >> $GITHUB_PATH + + - name: Install Dependencies + run: bun install + + - name: Run Biome with verbose output + run: bunx biome ci . --verbose diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0fe1acd..34232ea 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,9 +1,8 @@ { - "recommendations": [ + "recommendations": [ "mikestead.dotenv", "EditorConfig.EditorConfig", "leonzalion.vscode-ejs", - "dbaeumer.vscode-eslint", - "stylelint.vscode-stylelint" - ] + "biomejs.biome" + ] } diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..921a7a5 --- /dev/null +++ b/biome.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": true, + "ignore": [] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab", + "lineEnding": "lf" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double", + "indentStyle": "tab", + "lineEnding": "lf", + "jsxQuoteStyle": "double", + "semicolons": "always" + } + } +} diff --git a/config/environment.ts b/config/environment.ts index 9370a4b..50cfe9e 100644 --- a/config/environment.ts +++ b/config/environment.ts @@ -1,11 +1,10 @@ import { resolve } from "path"; export const environment: Environment = { - port: parseInt(process.env.PORT || "8080", 10), + port: Number.parseInt(process.env.PORT || "8080", 10), host: process.env.HOST || "0.0.0.0", development: - process.env.NODE_ENV === "development" || - process.argv.includes("--dev"), + process.env.NODE_ENV === "development" || process.argv.includes("--dev"), }; export const redisConfig: { @@ -15,7 +14,7 @@ export const redisConfig: { password?: string | undefined; } = { host: process.env.REDIS_HOST || "localhost", - port: parseInt(process.env.REDIS_PORT || "6379", 10), + port: Number.parseInt(process.env.REDIS_PORT || "6379", 10), username: process.env.REDIS_USERNAME || undefined, password: process.env.REDIS_PASSWORD || undefined, }; diff --git a/config/sql/avatars.ts b/config/sql/avatars.ts index 7047e24..78d33d2 100644 --- a/config/sql/avatars.ts +++ b/config/sql/avatars.ts @@ -4,7 +4,7 @@ import { type ReservedSQL, sql } from "bun"; export const order: number = 6; export async function createTable(reservation?: ReservedSQL): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); diff --git a/config/sql/files.ts b/config/sql/files.ts index da08db5..5eafcfd 100644 --- a/config/sql/files.ts +++ b/config/sql/files.ts @@ -4,7 +4,7 @@ import { type ReservedSQL, sql } from "bun"; export const order: number = 5; export async function createTable(reservation?: ReservedSQL): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); diff --git a/config/sql/folders.ts b/config/sql/folders.ts index 1946c4a..d2358d8 100644 --- a/config/sql/folders.ts +++ b/config/sql/folders.ts @@ -4,7 +4,7 @@ import { type ReservedSQL, sql } from "bun"; export const order: number = 4; export async function createTable(reservation?: ReservedSQL): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); diff --git a/config/sql/invites.ts b/config/sql/invites.ts index e098d32..7f27e11 100644 --- a/config/sql/invites.ts +++ b/config/sql/invites.ts @@ -4,7 +4,7 @@ import { type ReservedSQL, sql } from "bun"; export const order: number = 3; export async function createTable(reservation?: ReservedSQL): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); diff --git a/config/sql/settings.ts b/config/sql/settings.ts index 0def8e8..8a2d339 100644 --- a/config/sql/settings.ts +++ b/config/sql/settings.ts @@ -20,7 +20,7 @@ const defaultSettings: Setting[] = [ ]; export async function createTable(reservation?: ReservedSQL): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); @@ -99,7 +99,7 @@ export async function getSetting( key: string, reservation?: ReservedSQL, ): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); @@ -130,7 +130,7 @@ export async function setSetting( value: string, reservation?: ReservedSQL, ): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); @@ -157,7 +157,7 @@ export async function deleteSetting( key: string, reservation?: ReservedSQL, ): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); @@ -179,7 +179,7 @@ export async function deleteSetting( export async function getAllSettings( reservation?: ReservedSQL, ): Promise<{ key: string; value: string }[]> { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); diff --git a/config/sql/users.ts b/config/sql/users.ts index c6eab77..c6da657 100644 --- a/config/sql/users.ts +++ b/config/sql/users.ts @@ -4,7 +4,7 @@ import { type ReservedSQL, sql } from "bun"; export const order: number = 1; export async function createTable(reservation?: ReservedSQL): Promise { - let selfReservation: boolean = false; + let selfReservation = false; if (!reservation) { reservation = await sql.reserve(); @@ -114,7 +114,8 @@ export function isValidPassword(password: string): { if (!passwordRestrictions.regex.test(password)) { return { valid: false, - error: "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character", + error: + "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character", }; } diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 7442449..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,142 +0,0 @@ -import pluginJs from "@eslint/js"; -import tseslintPlugin from "@typescript-eslint/eslint-plugin"; -import tsParser from "@typescript-eslint/parser"; -import prettier from "eslint-plugin-prettier"; -import promisePlugin from "eslint-plugin-promise"; -import simpleImportSort from "eslint-plugin-simple-import-sort"; -import unicorn from "eslint-plugin-unicorn"; -import unusedImports from "eslint-plugin-unused-imports"; -import globals from "globals"; -import stylelintPlugin from "stylelint"; - -/** @type {import('eslint').Linter.FlatConfig[]} */ -export default [ - { - files: ["**/*.{js,mjs,cjs}"], - languageOptions: { - globals: globals.node, - }, - ...pluginJs.configs.recommended, - plugins: { - "simple-import-sort": simpleImportSort, - "unused-imports": unusedImports, - promise: promisePlugin, - prettier: prettier, - unicorn: unicorn, - }, - rules: { - "eol-last": ["error", "always"], - "no-multiple-empty-lines": ["error", { max: 1, maxEOF: 1 }], - "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], - "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": [ - "warn", - { - vars: "all", - varsIgnorePattern: "^_", - args: "after-used", - argsIgnorePattern: "^_", - }, - ], - "promise/always-return": "error", - "promise/no-return-wrap": "error", - "promise/param-names": "error", - "promise/catch-or-return": "error", - "promise/no-nesting": "warn", - "promise/no-promise-in-callback": "warn", - "promise/no-callback-in-promise": "warn", - "prettier/prettier": [ - "error", - { - useTabs: true, - tabWidth: 4, - }, - ], - indent: ["error", "tab", { SwitchCase: 1 }], - "unicorn/filename-case": [ - "error", - { - case: "camelCase", - }, - ], - }, - }, - { - files: ["**/*.{ts,tsx}"], - languageOptions: { - parser: tsParser, - globals: globals.node, - }, - plugins: { - "@typescript-eslint": tseslintPlugin, - "simple-import-sort": simpleImportSort, - "unused-imports": unusedImports, - promise: promisePlugin, - prettier: prettier, - unicorn: unicorn, - }, - rules: { - ...tseslintPlugin.configs.recommended.rules, - quotes: ["error", "double"], - "eol-last": ["error", "always"], - "no-multiple-empty-lines": ["error", { max: 1, maxEOF: 1 }], - "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], - "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": [ - "warn", - { - vars: "all", - varsIgnorePattern: "^_", - args: "after-used", - argsIgnorePattern: "^_", - }, - ], - "promise/always-return": "error", - "promise/no-return-wrap": "error", - "promise/param-names": "error", - "promise/catch-or-return": "error", - "promise/no-nesting": "warn", - "promise/no-promise-in-callback": "warn", - "promise/no-callback-in-promise": "warn", - "prettier/prettier": [ - "error", - { - useTabs: true, - tabWidth: 4, - }, - ], - indent: ["error", "tab", { SwitchCase: 1 }], - "unicorn/filename-case": [ - "error", - { - case: "camelCase", - }, - ], - "@typescript-eslint/explicit-function-return-type": ["error"], - "@typescript-eslint/explicit-module-boundary-types": ["error"], - "@typescript-eslint/typedef": [ - "error", - { - arrowParameter: true, - variableDeclaration: true, - propertyDeclaration: true, - memberVariableDeclaration: true, - parameter: true, - }, - ], - }, - }, - { - files: ["**/*.{css,scss,sass,less}"], - plugins: { - stylelint: stylelintPlugin, - }, - rules: { - "stylelint/rule-name": "error", - }, - }, -]; diff --git a/package.json b/package.json index 0fc03b5..813bf9e 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,36 @@ { - "name": "bun_frontend_template", + "name": "atums.world", + "private": true, "module": "src/index.ts", "type": "module", "scripts": { "start": "bun run src/index.ts", - "dev": "bun run --watch src/index.ts --dev", - "lint": "eslint", - "lint:fix": "bun lint --fix", + "dev": "bun run --hot src/index.ts --dev", + "lint": "bunx biome check", + "lint:fix": "bunx biome check --fix", "cleanup": "rm -rf logs node_modules bun.lockdb", "clearTable": "bun run src/helpers/commands/clearTable.ts" }, "devDependencies": { - "@eslint/js": "^9.22.0", - "@types/bun": "^1.2.5", + "@biomejs/biome": "^1.9.4", + "@types/bun": "^1.2.9", "@types/ejs": "^3.1.5", "@types/fluent-ffmpeg": "^2.1.27", "@types/image-thumbnail": "^1.0.4", - "@types/luxon": "^3.4.2", - "@typescript-eslint/eslint-plugin": "^8.26.1", - "@typescript-eslint/parser": "^8.26.1", - "eslint": "^9.22.0", - "eslint-plugin-prettier": "^5.2.3", - "eslint-plugin-promise": "^7.2.1", - "eslint-plugin-simple-import-sort": "^12.1.1", - "eslint-plugin-stylelint": "^0.1.1", - "eslint-plugin-unicorn": "^56.0.1", - "eslint-plugin-unused-imports": "^4.1.4", - "globals": "^15.15.0", - "prettier": "^3.5.3", - "stylelint": "^16.16.0", - "stylelint-config-standard": "^37.0.0" + "@types/luxon": "^3.6.2", + "globals": "16.0.0", + "prettier": "^3.5.3" }, "peerDependencies": { - "typescript": "^5.7.3" + "typescript": "^5.8.2" }, "dependencies": { "ejs": "^3.1.10", - "exiftool-vendored": "^29.2.0", - "fast-jwt": "^5.0.5", + "exiftool-vendored": "^29.3.0", + "fast-jwt": "6.0.1", "fluent-ffmpeg": "^2.1.3", "image-thumbnail": "^1.0.17", - "luxon": "^3.5.0", + "luxon": "^3.6.1", "redis": "^4.7.0" } } diff --git a/public/css/auth.css b/public/css/auth.css index 05743b2..dfeb8c6 100644 --- a/public/css/auth.css +++ b/public/css/auth.css @@ -1,194 +1,198 @@ .container { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - height: 100vh; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + height: 100vh; } .content { - border: 1px solid var(--border); - background-color: var(--background-secondary); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 2rem; - width: clamp(200px, 50%, 300px); + border: 1px solid var(--border); + background-color: var(--background-secondary); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem; + width: clamp(200px, 50%, 300px); } .content form { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; } .auth-container { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - min-height: 100vh; - background: linear-gradient(135deg, rgba(31 30 30 / 90%) 0%, rgba(45 45 45 / 90%) 100%); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + min-height: 100vh; + background: linear-gradient( + 135deg, + rgba(31 30 30 / 90%) 0%, + rgba(45 45 45 / 90%) 100% + ); } .auth-logo { - text-align: center; - margin-bottom: 2rem; + text-align: center; + margin-bottom: 2rem; } .auth-logo h1 { - font-size: 2.5rem; - margin-bottom: 0.5rem; - color: var(--accent); + font-size: 2.5rem; + margin-bottom: 0.5rem; + color: var(--accent); } .auth-logo p { - color: var(--text-secondary); - margin-top: 0.5rem; + color: var(--text-secondary); + margin-top: 0.5rem; } .auth-card { - background-color: var(--background-secondary); - border-radius: 8px; - box-shadow: var(--card-shadow); - width: 100%; - max-width: 400px; - overflow: hidden; - animation: fade-in 0.5s ease; + background-color: var(--background-secondary); + border-radius: 8px; + box-shadow: var(--card-shadow); + width: 100%; + max-width: 400px; + overflow: hidden; + animation: fade-in 0.5s ease; } .auth-header { - padding: 1.5rem; - text-align: center; - border-bottom: 1px solid var(--border); - background-color: rgba(0 0 0 / 10%); + padding: 1.5rem; + text-align: center; + border-bottom: 1px solid var(--border); + background-color: rgba(0 0 0 / 10%); } .auth-header h2 { - margin: 0; - font-size: 1.5rem; - color: var(--text); + margin: 0; + font-size: 1.5rem; + color: var(--text); } .auth-form { - padding: 1.5rem; + padding: 1.5rem; } .auth-form form { - display: flex; - flex-direction: column; - width: 100%; + display: flex; + flex-direction: column; + width: 100%; } .auth-toggle { - text-align: center; - margin-top: 1.5rem; - font-size: 0.9rem; - color: var(--text-secondary); + text-align: center; + margin-top: 1.5rem; + font-size: 0.9rem; + color: var(--text-secondary); } .form-footer { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 0.9rem; - margin-top: 1rem; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.9rem; + margin-top: 1rem; } .form-footer a { - color: var(--accent); - text-decoration: none; + color: var(--accent); + text-decoration: none; } .form-footer a:hover { - text-decoration: underline; + text-decoration: underline; } .form-footer label { - display: flex; - align-items: center; - gap: 0.5rem; - cursor: pointer; - white-space: nowrap; + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + white-space: nowrap; } .auth-form button { - margin-top: 0.5rem; - width: 100%; + margin-top: 0.5rem; + width: 100%; } .password-group { - position: relative; - width: 100%; + position: relative; + width: 100%; } .password-wrapper { - position: relative; - width: 100%; + position: relative; + width: 100%; } .password-wrapper input { - width: 100%; - padding-right: 2rem; + width: 100%; + padding-right: 2rem; } .toggle-password { - position: absolute; - right: 12px; - top: 50%; - transform: translateY(-50%); - cursor: pointer; - width: 20px; - height: 20px; - fill: var(--text-secondary); - transition: fill 0.2s ease; + position: absolute; + right: 12px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + width: 20px; + height: 20px; + fill: var(--text-secondary); + transition: fill 0.2s ease; } .toggle-password:hover { - fill: var(--text); + fill: var(--text); } .error-message { - color: var(--error); - background-color: rgb(237 66 69 / 10%); - padding: 0.75rem; - margin-bottom: 1.5rem; - border-radius: 4px; - display: none; - font-size: 0.9rem; + color: var(--error); + background-color: rgb(237 66 69 / 10%); + padding: 0.75rem; + margin-bottom: 1.5rem; + border-radius: 4px; + display: none; + font-size: 0.9rem; text-align: center; } @keyframes fade-in { - from { - opacity: 0; - transform: translateY(-20px); - } + from { + opacity: 0; + transform: translateY(-20px); + } - to { - opacity: 1; - transform: translateY(0); - } + to { + opacity: 1; + transform: translateY(0); + } } .auth-link { - color: var(--accent); - text-decoration: none; - font-weight: bold; + color: var(--accent); + text-decoration: none; + font-weight: bold; } .auth-link:hover { - text-decoration: underline; + text-decoration: underline; } @media (width <= 480px) { - .auth-card { - max-width: 100%; - } + .auth-card { + max-width: 100%; + } - .auth-logo h1 { - font-size: 2rem; - } + .auth-logo h1 { + font-size: 2rem; + } } diff --git a/public/css/dashboard/index.css b/public/css/dashboard/index.css index 3a829ff..c2feb7f 100644 --- a/public/css/dashboard/index.css +++ b/public/css/dashboard/index.css @@ -5,19 +5,6 @@ body { /* sidebar */ -/* */ - .sidebar { background-color: var(--background-secondary); width: 220px; @@ -26,6 +13,8 @@ body { flex-direction: column; align-items: center; justify-content: space-between; + border-right: 1px solid var(--border); + box-sizing: border-box; } .sidebar .actions { @@ -33,34 +22,47 @@ body { flex-direction: column; align-items: center; width: 100%; + box-sizing: border-box; } .sidebar .actions .action { display: flex; + justify-content: flex-start; + gap: .5rem; align-items: center; padding: 1rem; - height: 20px; + height: 3rem; width: 100%; - border-radius: 4px; transition: background-color 0.2s ease; + text-decoration: none; + color: var(--text); + box-sizing: border-box; } .sidebar .actions .action svg { - width: 25px; - height: 25px; + width: 15px; + height: 15px; } .sidebar .actions .action:hover { background-color: var(--background); } +.sidebar .actions .action.active { + background-color: var(--background); +} + +.sidebar .actions .action.active:hover { + background-color: var(--background-secondary); +} + .sidebar .user-area { display: flex; flex-direction: column; align-items: center; width: 100%; border-top: 1px solid var(--border); - background-color: rgba(0 0 0 / 10%); + background-color: rgba(0 0 0 / 10%); } .sidebar .user-area img { diff --git a/public/css/global.css b/public/css/global.css index 0c841f5..b51f16a 100644 --- a/public/css/global.css +++ b/public/css/global.css @@ -31,7 +31,8 @@ @font-face { font-family: Fira Code; - src: url("/public/assets/fonts/Fira_code/FiraCode-Regular.ttf") format("truetype"); + src: url("/public/assets/fonts/Fira_code/FiraCode-Regular.ttf") + format("truetype"); font-weight: normal; font-style: normal; } @@ -52,14 +53,18 @@ body { padding: 0 1rem; } -input, button, textarea, select { +input, +button, +textarea, +select { font-family: inherit; font-size: 1rem; border-radius: 4px; transition: all 0.2s ease; } -button, .button { +button, +.button { cursor: pointer; padding: 0.75rem 1.5rem; border: none; @@ -70,11 +75,14 @@ button, .button { transition: background-color 0.2s ease; } -button:hover, .button:hover { +button:hover, +.button:hover { background-color: var(--accent-hover); } -input, textarea, select { +input, +textarea, +select { padding: 0.75rem; border: 1px solid var(--border); background-color: var(--input-background); @@ -83,7 +91,9 @@ input, textarea, select { box-sizing: border-box; } -input:focus, textarea:focus, select:focus { +input:focus, +textarea:focus, +select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px rgb(88 101 242 / 30%); diff --git a/public/js/auth.js b/public/js/auth.js index 0f70264..6b9c884 100644 --- a/public/js/auth.js +++ b/public/js/auth.js @@ -18,8 +18,7 @@ if (loginForm) { if (!email || !password) { if (errorMessage) { errorMessage.style.display = "block"; - errorMessage.textContent = - "Please enter both email and password."; + errorMessage.textContent = "Please enter both email and password."; } return; } @@ -46,16 +45,14 @@ if (loginForm) { if (errorMessage) { errorMessage.style.display = "block"; errorMessage.textContent = - data.error || - "Invalid email or password. Please try again."; + data.error || "Invalid email or password. Please try again."; } } } catch (error) { console.error("Login error:", error); if (errorMessage) { errorMessage.style.display = "block"; - errorMessage.textContent = - "An error occurred. Please try again."; + errorMessage.textContent = "An error occurred. Please try again."; } } }); @@ -103,8 +100,7 @@ if (loginForm) { .join(""); } else { errorMessage.textContent = - data.error || - "An error occurred. Please try again."; + data.error || "An error occurred. Please try again."; } } } @@ -112,8 +108,7 @@ if (loginForm) { console.error("Register error:", error); if (errorMessage) { errorMessage.style.display = "block"; - errorMessage.textContent = - "An error occurred. Please try again."; + errorMessage.textContent = "An error occurred. Please try again."; } } }); diff --git a/src/helpers/auth.ts b/src/helpers/auth.ts index 1a3d91f..8426b25 100644 --- a/src/helpers/auth.ts +++ b/src/helpers/auth.ts @@ -6,7 +6,7 @@ export async function authByToken( request: ExtendedRequest, reservation?: ReservedSQL, ): Promise { - let selfReservation: boolean = false; + let selfReservation = false; const authorizationHeader: string | null = request.headers.get("Authorization"); diff --git a/src/helpers/char.ts b/src/helpers/char.ts index 084386b..45837a4 100644 --- a/src/helpers/char.ts +++ b/src/helpers/char.ts @@ -48,7 +48,7 @@ export function parseDuration(input: string): DurationObject { }; for (const match of matches) { - const value: number = parseInt(match[1], 10); + const value: number = Number.parseInt(match[1], 10); const unit: string = match[2]; switch (unit) { @@ -90,12 +90,10 @@ export function generateRandomString(length?: number): string { const characters: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let result: string = ""; + let result = ""; - for (let i: number = 0; i < length; i++) { - result += characters.charAt( - Math.floor(Math.random() * characters.length), - ); + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)); } return result; @@ -172,9 +170,7 @@ export function nameWithoutExtension(fileName: string): string { if (lastDotIndex <= 0) return fileName; const ext: string = fileName.slice(lastDotIndex + 1).toLowerCase(); - return knownExtensions.has(ext) - ? fileName.slice(0, lastDotIndex) - : fileName; + return knownExtensions.has(ext) ? fileName.slice(0, lastDotIndex) : fileName; } export function supportsExif(mimeType: string, extension: string): boolean { @@ -211,13 +207,11 @@ export function parseArgs(): Record { const args: string[] = process.argv.slice(2); const parsedArgs: Record = {}; - for (let i: number = 0; i < args.length; i++) { + for (let i = 0; i < args.length; i++) { if (args[i].startsWith("--")) { const key: string = args[i].slice(2); const value: string | boolean = - args[i + 1] && !args[i + 1].startsWith("--") - ? args[i + 1] - : true; + args[i + 1] && !args[i + 1].startsWith("--") ? args[i + 1] : true; parsedArgs[key] = value; if (value !== true) i++; } diff --git a/src/helpers/ejs.ts b/src/helpers/ejs.ts index 6b03dd0..7ff667c 100644 --- a/src/helpers/ejs.ts +++ b/src/helpers/ejs.ts @@ -1,5 +1,5 @@ -import { renderFile } from "ejs"; import { resolve } from "path"; +import { renderFile } from "ejs"; export async function renderEjsTemplate( viewName: string | string[], diff --git a/src/helpers/logger.ts b/src/helpers/logger.ts index 16e1076..7ebcf40 100644 --- a/src/helpers/logger.ts +++ b/src/helpers/logger.ts @@ -1,15 +1,15 @@ -import { environment } from "@config/environment"; -import { timestampToReadable } from "@helpers/char"; import type { Stats } from "fs"; import { + type WriteStream, createWriteStream, existsSync, mkdirSync, statSync, - WriteStream, } from "fs"; import { EOL } from "os"; import { basename, join } from "path"; +import { environment } from "@config/environment"; +import { timestampToReadable } from "@helpers/char"; class Logger { private static instance: Logger; @@ -37,7 +37,7 @@ class Logger { mkdirSync(logDir, { recursive: true }); } - let addSeparator: boolean = false; + let addSeparator = false; if (existsSync(logFile)) { const fileStats: Stats = statSync(logFile); @@ -66,9 +66,9 @@ class Logger { private extractFileName(stack: string): string { const stackLines: string[] = stack.split("\n"); - let callerFile: string = ""; + let callerFile = ""; - for (let i: number = 2; i < stackLines.length; i++) { + for (let i = 2; i < stackLines.length; i++) { const line: string = stackLines[i].trim(); if (line && !line.includes("Logger.") && line.includes("(")) { callerFile = line.split("(")[1]?.split(")")[0] || ""; @@ -91,7 +91,7 @@ class Logger { return { filename, timestamp: readableTimestamp }; } - public info(message: string | string[], breakLine: boolean = false): void { + public info(message: string | string[], breakLine = false): void { const stack: string = new Error().stack || ""; const { filename, timestamp } = this.getCallerInfo(stack); @@ -110,7 +110,7 @@ class Logger { this.writeConsoleMessageColored(logMessageParts, breakLine); } - public warn(message: string | string[], breakLine: boolean = false): void { + public warn(message: string | string[], breakLine = false): void { const stack: string = new Error().stack || ""; const { filename, timestamp } = this.getCallerInfo(stack); @@ -131,7 +131,7 @@ class Logger { public error( message: string | Error | ErrorEvent | (string | Error)[], - breakLine: boolean = false, + breakLine = false, ): void { const stack: string = new Error().stack || ""; const { filename, timestamp } = this.getCallerInfo(stack); @@ -161,7 +161,7 @@ class Logger { bracketMessage2: string, message: string | string[], color: string, - breakLine: boolean = false, + breakLine = false, ): void { const stack: string = new Error().stack || ""; const { timestamp } = this.getCallerInfo(stack); @@ -189,7 +189,7 @@ class Logger { private writeConsoleMessageColored( logMessageParts: ILogMessageParts, - breakLine: boolean = false, + breakLine = false, ): void { const logMessage: string = Object.keys(logMessageParts) .map((key: string) => { diff --git a/src/helpers/redis.ts b/src/helpers/redis.ts index 5cd1e54..3251320 100644 --- a/src/helpers/redis.ts +++ b/src/helpers/redis.ts @@ -1,6 +1,6 @@ import { redisConfig } from "@config/environment"; import { logger } from "@helpers/logger"; -import { createClient, type RedisClientType } from "redis"; +import { type RedisClientType, createClient } from "redis"; class RedisJson { private static instance: RedisJson | null = null; @@ -21,11 +21,7 @@ class RedisJson { }); RedisJson.instance.client.on("error", (err: Error) => { - logger.error([ - "Error connecting to Redis:", - err, - redisConfig.host, - ]); + logger.error(["Error connecting to Redis:", err, redisConfig.host]); process.exit(1); }); @@ -167,10 +163,7 @@ class RedisJson { try { await this.client.expire(key, seconds); } catch (error) { - logger.error([ - `Error expiring key in Redis: ${key}`, - error as Error, - ]); + logger.error([`Error expiring key in Redis: ${key}`, error as Error]); throw error; } } diff --git a/src/helpers/sessions.ts b/src/helpers/sessions.ts index 05b5376..20fa5c7 100644 --- a/src/helpers/sessions.ts +++ b/src/helpers/sessions.ts @@ -45,8 +45,7 @@ class SessionManager { const cookie: string | null = request.headers.get("Cookie"); if (!cookie) return null; - const token: string | null = - cookie.match(/session=([^;]+)/)?.[1] || null; + const token: string | null = cookie.match(/session=([^;]+)/)?.[1] || null; if (!token) return null; const userSessions: string[] = await redis @@ -72,15 +71,13 @@ class SessionManager { const cookie: string | null = request.headers.get("Cookie"); if (!cookie) throw new Error("No session found in request"); - const token: string | null = - cookie.match(/session=([^;]+)/)?.[1] || null; + const token: string | null = cookie.match(/session=([^;]+)/)?.[1] || null; if (!token) throw new Error("Session token not found"); const userSessions: string[] = await redis .getInstance() .keys("session:*:" + token); - if (!userSessions.length) - throw new Error("Session not found or expired"); + if (!userSessions.length) throw new Error("Session not found or expired"); const sessionKey: string = userSessions[0]; @@ -100,8 +97,7 @@ class SessionManager { const userSessions: string[] = await redis .getInstance() .keys("session:*:" + token); - if (!userSessions.length) - throw new Error("Session not found or expired"); + if (!userSessions.length) throw new Error("Session not found or expired"); const sessionData: unknown = await redis .getInstance() @@ -121,8 +117,7 @@ class SessionManager { const cookie: string | null = request.headers.get("Cookie"); if (!cookie) return; - const token: string | null = - cookie.match(/session=([^;]+)/)?.[1] || null; + const token: string | null = cookie.match(/session=([^;]+)/)?.[1] || null; if (!token) return; const userSessions: string[] = await redis @@ -152,7 +147,7 @@ class SessionManager { domain, } = options || {}; - let cookie: string = `session=${encodeURIComponent(token)}; Path=${path}; Max-Age=${maxAge}`; + let cookie = `session=${encodeURIComponent(token)}; Path=${path}; Max-Age=${maxAge}`; if (httpOnly) cookie += "; HttpOnly"; @@ -173,7 +168,7 @@ class SessionManager { } const [, value, unit] = match; - const num: number = parseInt(value, 10); + const num: number = Number.parseInt(value, 10); switch (unit) { case "s": diff --git a/src/helpers/workers/thumbnails.ts b/src/helpers/workers/thumbnails.ts index 45c9073..da2c845 100644 --- a/src/helpers/workers/thumbnails.ts +++ b/src/helpers/workers/thumbnails.ts @@ -1,9 +1,9 @@ +import { join, resolve } from "path"; import { dataType } from "@config/environment.ts"; import { logger } from "@helpers/logger.ts"; import { type BunFile, s3, sql } from "bun"; import ffmpeg from "fluent-ffmpeg"; import imageThumbnail from "image-thumbnail"; -import { join, resolve } from "path"; declare var self: Worker; @@ -22,10 +22,7 @@ async function generateVideoThumbnail( .format("mjpeg") .output(thumbnailPath) .on("error", (error: Error) => { - logger.error([ - "failed to generate thumbnail", - error as Error, - ]); + logger.error(["failed to generate thumbnail", error as Error]); reject(error); }) @@ -71,10 +68,7 @@ async function generateImageThumbnail( }, }; - const thumbnailBuffer: Buffer = await imageThumbnail( - filePath, - options, - ); + const thumbnailBuffer: Buffer = await imageThumbnail(filePath, options); await Bun.write(thumbnailPath, thumbnailBuffer.buffer); resolve(await Bun.file(thumbnailPath).arrayBuffer()); @@ -104,20 +98,14 @@ async function createThumbnails(files: FileEntry[]): Promise { try { fileArrayBuffer = await Bun.file(filePath).arrayBuffer(); } catch { - logger.error([ - "Could not generate thumbnail for file:", - fileName, - ]); + logger.error(["Could not generate thumbnail for file:", fileName]); continue; } } else { try { fileArrayBuffer = await s3.file(fileName).arrayBuffer(); } catch { - logger.error([ - "Could not generate thumbnail for file:", - fileName, - ]); + logger.error(["Could not generate thumbnail for file:", fileName]); continue; } } @@ -149,10 +137,7 @@ async function createThumbnails(files: FileEntry[]): Promise { : await generateImageThumbnail(tempFilePath, tempThumbnailPath); if (!thumbnailArrayBuffer) { - logger.error([ - "Could not generate thumbnail for file:", - fileName, - ]); + logger.error(["Could not generate thumbnail for file:", fileName]); continue; } diff --git a/src/index.ts b/src/index.ts index 5af5367..495815c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ +import { existsSync, mkdirSync } from "fs"; +import { resolve } from "path"; import { dataType } from "@config/environment"; import { logger } from "@helpers/logger"; import { type ReservedSQL, s3, sql } from "bun"; -import { existsSync, mkdirSync } from "fs"; import { readdir } from "fs/promises"; -import { resolve } from "path"; import { serverHandler } from "@/server"; @@ -17,9 +17,7 @@ async function initializeDatabase(): Promise { files .filter((file: string): boolean => file.endsWith(".ts")) .map(async (file: string): Promise => { - const module: Module["module"] = await import( - resolve(sqlDir, file) - ); + const module: Module["module"] = await import(resolve(sqlDir, file)); return { file, module }; }), ); @@ -69,10 +67,7 @@ async function main(): Promise { } } - logger.info([ - "Using local datasource directory", - `${dataType.path}`, - ]); + logger.info(["Using local datasource directory", `${dataType.path}`]); } else { try { await s3.write("test", "test"); diff --git a/src/routes/api/auth/login.ts b/src/routes/api/auth/login.ts index 6e1fa3f..90d7f32 100644 --- a/src/routes/api/auth/login.ts +++ b/src/routes/api/auth/login.ts @@ -3,7 +3,7 @@ import { isValidPassword, isValidUsername, } from "@config/sql/users"; -import { password as bunPassword, type ReservedSQL, sql } from "bun"; +import { type ReservedSQL, password as bunPassword, sql } from "bun"; import { logger } from "@/helpers/logger"; import { sessionManager } from "@/helpers/sessions"; @@ -61,13 +61,9 @@ async function handler( const errors: string[] = []; const validations: UserValidation[] = [ - username - ? { check: isValidUsername(username), field: "Username" } - : null, + username ? { check: isValidUsername(username), field: "Username" } : null, email ? { check: isValidEmail(email), field: "Email" } : null, - password - ? { check: isValidPassword(password), field: "Password" } - : null, + password ? { check: isValidPassword(password), field: "Password" } : null, ].filter(Boolean) as UserValidation[]; validations.forEach(({ check }: UserValidation): void => { diff --git a/src/routes/api/auth/register.ts b/src/routes/api/auth/register.ts index 185131d..065858c 100644 --- a/src/routes/api/auth/register.ts +++ b/src/routes/api/auth/register.ts @@ -5,7 +5,7 @@ import { isValidPassword, isValidUsername, } from "@config/sql/users"; -import { password as bunPassword, type ReservedSQL, sql } from "bun"; +import { type ReservedSQL, password as bunPassword, sql } from "bun"; import { isValidTimezone } from "@/helpers/char"; import { logger } from "@/helpers/logger"; @@ -57,9 +57,9 @@ async function handler( const normalizedUsername: string = username.normalize("NFC"); const reservation: ReservedSQL = await sql.reserve(); - let firstUser: boolean = false; + let firstUser = false; let inviteData: Invite | null = null; - let roles: string[] = []; + const roles: string[] = []; try { const registrationEnabled: boolean = @@ -69,11 +69,10 @@ async function handler( firstUser = Number( - (await reservation`SELECT COUNT(*) AS count FROM users;`)[0] - ?.count, + (await reservation`SELECT COUNT(*) AS count FROM users;`)[0]?.count, ) === 0; - let inviteValid: boolean = true; + let inviteValid = true; if (!firstUser && invite) { const inviteValidation: { valid: boolean; error?: string } = isValidInvite(invite); @@ -184,10 +183,7 @@ async function handler( if (inviteData?.role) roles.push(inviteData.role); } } catch (error) { - logger.error([ - "Error inserting user into the database:", - error as Error, - ]); + logger.error(["Error inserting user into the database:", error as Error]); return Response.json( { success: false, diff --git a/src/routes/api/files/delete[query].ts b/src/routes/api/files/delete[query].ts index cd2ccb8..8a9dac6 100644 --- a/src/routes/api/files/delete[query].ts +++ b/src/routes/api/files/delete[query].ts @@ -1,6 +1,6 @@ -import { dataType } from "@config/environment"; -import { s3, sql, type SQLQuery } from "bun"; import { resolve } from "path"; +import { dataType } from "@config/environment"; +import { type SQLQuery, s3, sql } from "bun"; import { isUUID } from "@/helpers/char"; import { logger } from "@/helpers/logger"; @@ -134,26 +134,14 @@ async function handler( try { if (file && !(typeof file === "string" && file.length === 0)) { - await processFile( - request, - file, - isAdmin, - failedFiles, - successfulFiles, - ); + await processFile(request, file, isAdmin, failedFiles, successfulFiles); } else if (files) { files = Array.isArray(files) ? files : files.split(/[, ]+/).filter(Boolean); for (const file of files) { - await processFile( - request, - file, - isAdmin, - failedFiles, - successfulFiles, - ); + await processFile(request, file, isAdmin, failedFiles, successfulFiles); } } } catch (error) { diff --git a/src/routes/api/files/upload.ts b/src/routes/api/files/upload.ts index ef12d63..faf4468 100644 --- a/src/routes/api/files/upload.ts +++ b/src/routes/api/files/upload.ts @@ -1,15 +1,15 @@ +import { resolve } from "path"; import { dataType } from "@config/environment"; import { getSetting } from "@config/sql/settings"; import { + type SQLQuery, password as bunPassword, randomUUIDv7, s3, sql, - type SQLQuery, } from "bun"; import { exiftool } from "exiftool-vendored"; import { DateTime } from "luxon"; -import { resolve } from "path"; import { generateRandomString, @@ -97,9 +97,7 @@ async function removeExifData( LocationName: null, }; - await exiftool.write(tempInputPath, tagsToRemove, [ - "-overwrite_original", - ]); + await exiftool.write(tempInputPath, tagsToRemove, ["-overwrite_original"]); return await Bun.file(tempInputPath).arrayBuffer(); } catch (error) { @@ -161,9 +159,9 @@ async function processFile( }; const extension: string | null = getExtension(file.name); - let rawName: string | null = nameWithoutExtension(file.name); + const rawName: string | null = nameWithoutExtension(file.name); const maxViews: number | null = - parseInt(user_provided_max_views, 10) || null; + Number.parseInt(user_provided_max_views, 10) || null; if (!rawName) { failedFiles.push({ @@ -190,7 +188,7 @@ async function processFile( ? user_provided_tags : (user_provided_tags?.split(/[, ]+/).filter(Boolean) ?? []); - let uploadEntry: FileUpload = { + const uploadEntry: FileUpload = { id: randomUUID as UUID, owner: session.id as UUID, name: rawName, @@ -201,9 +199,7 @@ async function processFile( password: hashedPassword, favorite: user_wants_favorite === "true" || user_wants_favorite === "1", tags: tags, - expires_at: delete_short_string - ? getNewTimeUTC(delete_short_string) - : null, + expires_at: delete_short_string ? getNewTimeUTC(delete_short_string) : null, }; if (name_format === "date") { @@ -366,9 +362,7 @@ async function handler(request: ExtendedRequest): Promise { requestBody.append( "file", new Blob([body], { type: request.actualContentType }), - request.actualContentType === "text/plain" - ? "file.txt" - : "file.json", + request.actualContentType === "text/plain" ? "file.txt" : "file.json", ); } else { return Response.json( @@ -442,20 +436,16 @@ async function handler(request: ExtendedRequest): Promise { } const filesThatSupportThumbnails: FileUpload[] = successfulFiles.filter( - (file: FileUpload): boolean => - supportsThumbnail(file.mime_type as string), + (file: FileUpload): boolean => supportsThumbnail(file.mime_type as string), ); if ( (await getSetting("enable_thumbnails")) === "true" && filesThatSupportThumbnails.length > 0 ) { try { - const worker: Worker = new Worker( - "./src/helpers/workers/thumbnails.ts", - { - type: "module", - }, - ); + const worker: Worker = new Worker("./src/helpers/workers/thumbnails.ts", { + type: "module", + }); worker.postMessage({ files: filesThatSupportThumbnails, }); diff --git a/src/routes/api/invite/create.ts b/src/routes/api/invite/create.ts index 30f214d..ee2dfd1 100644 --- a/src/routes/api/invite/create.ts +++ b/src/routes/api/invite/create.ts @@ -67,9 +67,7 @@ async function handler( ); } - const expirationDate: string | null = expires - ? getNewTimeUTC(expires) - : null; + const expirationDate: string | null = expires ? getNewTimeUTC(expires) : null; const maxUses: number = Number(max_uses) || 1; const inviteRole: string = role || "user"; diff --git a/src/routes/api/settings/set.ts b/src/routes/api/settings/set.ts index 61f1279..b84df90 100644 --- a/src/routes/api/settings/set.ts +++ b/src/routes/api/settings/set.ts @@ -53,7 +53,8 @@ async function handler( { success: false, code: 400, - error: "Expected key to be a string and value to be a string, boolean, or number", + error: + "Expected key to be a string and value to be a string, boolean, or number", }, { status: 400 }, ); diff --git a/src/routes/api/user/avatar/delete.ts b/src/routes/api/user/avatar/delete.ts index 29e0e35..2c20c9a 100644 --- a/src/routes/api/user/avatar/delete.ts +++ b/src/routes/api/user/avatar/delete.ts @@ -1,6 +1,6 @@ +import { resolve } from "path"; import { dataType } from "@config/environment"; import { s3, sql } from "bun"; -import { resolve } from "path"; import { logger } from "@/helpers/logger"; import { sessionManager } from "@/helpers/sessions"; @@ -21,9 +21,7 @@ async function deleteAvatar( try { if (dataType.type === "local" && dataType.path) { - await Bun.file( - resolve(dataType.path, "avatars", fileName), - ).unlink(); + await Bun.file(resolve(dataType.path, "avatars", fileName)).unlink(); } else { await s3.delete(`/avatars/${fileName}`); } diff --git a/src/routes/api/user/avatar/set.ts b/src/routes/api/user/avatar/set.ts index 8dc5a7e..dd1e463 100644 --- a/src/routes/api/user/avatar/set.ts +++ b/src/routes/api/user/avatar/set.ts @@ -1,8 +1,8 @@ +import { resolve } from "path"; import { dataType } from "@config/environment"; import { isValidTypeOrExtension } from "@config/sql/avatars"; import { getSetting } from "@config/sql/settings"; import { s3, sql } from "bun"; -import { resolve } from "path"; import { getBaseUrl, getExtension } from "@/helpers/char"; import { logger } from "@/helpers/logger"; @@ -50,10 +50,7 @@ async function processFile( await s3.delete(`/avatars/${existingFileName}`); } } catch (error) { - logger.error([ - "Error deleting existing avatar file:", - error as Error, - ]); + logger.error(["Error deleting existing avatar file:", error as Error]); } } @@ -138,9 +135,7 @@ async function handler( } const file: File | null = - (formData.get("file") as File) || - (formData.get("avatar") as File) || - null; + (formData.get("file") as File) || (formData.get("avatar") as File) || null; if (!file.type || file.type === "") { return Response.json( diff --git a/src/routes/api/user/files.ts b/src/routes/api/user/files.ts index 1ea5548..ef5ae83 100644 --- a/src/routes/api/user/files.ts +++ b/src/routes/api/user/files.ts @@ -1,4 +1,4 @@ -import { type ReservedSQL, sql, type SQLQuery } from "bun"; +import { type ReservedSQL, type SQLQuery, sql } from "bun"; import { isUUID } from "@/helpers/char"; import { logger } from "@/helpers/logger"; @@ -107,24 +107,21 @@ async function handler(request: ExtendedRequest): Promise { ); } - const safeCount: number = Math.min(parseInt(count) || 25, 100); - const safePage: number = Math.max(parseInt(page) || 0, 0); + const safeCount: number = Math.min(Number.parseInt(count) || 25, 100); + const safePage: number = Math.max(Number.parseInt(page) || 0, 0); const offset: number = safePage * safeCount; const sortColumn: string = sort_by || "created_at"; const order: "ASC" | "DESC" = validSortOrder(sort_order) as "ASC" | "DESC"; const safeSearchValue: string = escapeLike(search_value || ""); let files: FileEntry[]; - let totalPages: number = 0; - let totalFiles: number = 0; + let totalPages = 0; + let totalFiles = 0; const reservation: ReservedSQL = await sql.reserve(); try { // ! i really dont understand why bun wont accept reservation(order)` - function orderBy( - field_name: string, - orderBy: "ASC" | "DESC", - ): SQLQuery { + function orderBy(field_name: string, orderBy: "ASC" | "DESC"): SQLQuery { return reservation`ORDER BY ${reservation(field_name)} ${orderBy === "ASC" ? reservation`ASC` : reservation`DESC`}`; } diff --git a/src/routes/api/user/info[query].ts b/src/routes/api/user/info[query].ts index 78158d1..af35ca7 100644 --- a/src/routes/api/user/info[query].ts +++ b/src/routes/api/user/info[query].ts @@ -28,7 +28,7 @@ async function handler(request: ExtendedRequest): Promise { } let user: GetUser | null = null; - let isSelf: boolean = false; + let isSelf = false; const isId: boolean = isUUID(query); const normalized: string = isId ? query : query.normalize("NFC"); const isAdmin: boolean = request.session diff --git a/src/routes/auth/register.ts b/src/routes/auth/register.ts index 36f7325..d5be754 100644 --- a/src/routes/auth/register.ts +++ b/src/routes/auth/register.ts @@ -18,8 +18,7 @@ async function handler(request: ExtendedRequest): Promise { const [firstUser] = await sql`SELECT COUNT(*) FROM users`; const instanceName: string = - (await getSetting("instance_name", reservation)) || - "Unnamed Instance"; + (await getSetting("instance_name", reservation)) || "Unnamed Instance"; const requiresInvite: boolean = (await getSetting("enable_invitations", reservation)) === "true" && firstUser.count !== "0"; diff --git a/src/routes/dashboard/index.ts b/src/routes/dashboard/index.ts index c1f2614..30e2ddf 100644 --- a/src/routes/dashboard/index.ts +++ b/src/routes/dashboard/index.ts @@ -13,6 +13,7 @@ async function handler(request: ExtendedRequest): Promise { const ejsTemplateData: EjsTemplateData = { title: "Hello, World!", + active: "dashboard", }; return await renderEjsTemplate("dashboard/index.ejs", ejsTemplateData); diff --git a/src/routes/raw/[query].ts b/src/routes/raw/[query].ts index be23740..de4dec6 100644 --- a/src/routes/raw/[query].ts +++ b/src/routes/raw/[query].ts @@ -1,6 +1,6 @@ +import { resolve } from "path"; import { dataType } from "@config/environment"; import { type BunFile, type ReservedSQL, sql } from "bun"; -import { resolve } from "path"; import { isUUID, nameWithoutExtension } from "@/helpers/char"; import { logger } from "@/helpers/logger"; @@ -139,9 +139,7 @@ async function handler(request: ExtendedRequest): Promise { } else { path = resolve( dataType.path, - `${fileData.id}${ - fileData.extension ? `.${fileData.extension}` : "" - }`, + `${fileData.id}${fileData.extension ? `.${fileData.extension}` : ""}`, ); } } else { @@ -157,9 +155,7 @@ async function handler(request: ExtendedRequest): Promise { return new Response(bunStream, { headers: { - "Content-Type": shouldShowThumbnail - ? "image/jpeg" - : fileData.mime_type, + "Content-Type": shouldShowThumbnail ? "image/jpeg" : fileData.mime_type, "Content-Disposition": downloadFile === "true" || downloadFile === "1" ? `attachment; filename="${fileData.original_name || fileData.name}"` diff --git a/src/routes/user/avatar/[user].ts b/src/routes/user/avatar/[user].ts index 9c8be7b..919b0fc 100644 --- a/src/routes/user/avatar/[user].ts +++ b/src/routes/user/avatar/[user].ts @@ -1,7 +1,7 @@ +import { resolve } from "path"; import { dataType } from "@config/environment"; import { isValidUsername } from "@config/sql/users"; import { type BunFile, type ReservedSQL, sql } from "bun"; -import { resolve } from "path"; import { getBaseUrl, isUUID, nameWithoutExtension } from "@/helpers/char"; import { logger } from "@/helpers/logger"; @@ -71,11 +71,12 @@ async function handler(request: ExtendedRequest): Promise { if (json === "true" || json === "1") { return Response.json( { - success: true, code: 200, + success: true, + code: 200, avatar: { ...avatar, url: `${getBaseUrl(request)}/user/avatar/${user.id}`, - } + }, }, { status: 200 }, ); diff --git a/src/server.ts b/src/server.ts index fc40125..7f3350a 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,3 +1,4 @@ +import { resolve } from "path"; import { environment } from "@config/environment"; import { logger } from "@helpers/logger"; import { @@ -6,7 +7,6 @@ import { type MatchedRoute, type Serve, } from "bun"; -import { resolve } from "path"; import { webSocketHandler } from "@/websocket"; @@ -77,8 +77,7 @@ class ServerHandler { if (await file.exists()) { const fileContent: ArrayBuffer = await file.arrayBuffer(); - const contentType: string = - file.type || "application/octet-stream"; + const contentType: string = file.type || "application/octet-stream"; return new Response(fileContent, { headers: { "Content-Type": contentType }, @@ -88,10 +87,7 @@ class ServerHandler { return new Response("Not Found", { status: 404 }); } } catch (error) { - logger.error([ - `Error serving static file: ${pathname}`, - error as Error, - ]); + logger.error([`Error serving static file: ${pathname}`, error as Error]); return new Response("Internal Server Error", { status: 500 }); } } @@ -116,8 +112,7 @@ class ServerHandler { try { const routeModule: RouteModule = await import(filePath); - const contentType: string | null = - request.headers.get("Content-Type"); + const contentType: string | null = request.headers.get("Content-Type"); const actualContentType: string | null = contentType ? contentType.split(";")[0].trim() : null; @@ -144,9 +139,7 @@ class ServerHandler { if ( (Array.isArray(routeModule.routeDef.method) && - !routeModule.routeDef.method.includes( - request.method, - )) || + !routeModule.routeDef.method.includes(request.method)) || (!Array.isArray(routeModule.routeDef.method) && routeModule.routeDef.method !== request.method) ) { @@ -171,9 +164,7 @@ class ServerHandler { if (Array.isArray(expectedContentType)) { matchesAccepts = expectedContentType.includes("*/*") || - expectedContentType.includes( - actualContentType || "", - ); + expectedContentType.includes(actualContentType || ""); } else { matchesAccepts = expectedContentType === "*/*" || @@ -202,11 +193,7 @@ class ServerHandler { (await authByToken(request)) || (await sessionManager.getSession(request)); - response = await routeModule.handler( - request, - requestBody, - server, - ); + response = await routeModule.handler(request, requestBody, server); if (routeModule.routeDef.returns !== "*/*") { response.headers.set( @@ -217,10 +204,7 @@ class ServerHandler { } } } catch (error: unknown) { - logger.error([ - `Error handling route ${request.url}:`, - error as Error, - ]); + logger.error([`Error handling route ${request.url}:`, error as Error]); response = Response.json( { diff --git a/src/views/partials/sidebar.ejs b/src/views/partials/sidebar.ejs index 5a5a64d..0c8a2fa 100644 --- a/src/views/partials/sidebar.ejs +++ b/src/views/partials/sidebar.ejs @@ -1,7 +1,7 @@