feat: enhance pre-push validation and update ESLint configurations

- Updated the Husky pre-push hook to validate all applications (web, docs, and server) before pushing changes, improving code quality checks.
- Modified ESLint configurations for the docs app to include additional ignored directories, ensuring cleaner linting results.
- Refactored the HomePage component in the docs app to improve structure and readability, while reintroducing the Highlight component for better content presentation.
- Added a .prettierignore file in the server app to exclude specific directories from formatting, enhancing development workflow.
- Updated various import statements across multiple files for consistency and clarity.
This commit is contained in:
Daniel Luiz Alves
2025-07-02 14:53:23 -03:00
parent 4fb7007db2
commit 75d6049b87
51 changed files with 2766 additions and 3272 deletions

View File

@@ -1,2 +1,12 @@
echo "🔍 Running pre-push validation for web app..."
cd apps/web && pnpm validate
echo "🔍 Running pre-push validation for all apps..."
echo "📱 Validating web app..."
cd apps/web && pnpm validate
echo "📚 Validating docs app..."
cd ../docs && pnpm validate
echo "🖥️ Validating server app..."
cd ../server && pnpm validate
echo "✅ All validations passed!"

View File

@@ -62,6 +62,6 @@ export default [
},
// Ignore ESLint errors in @/ui directory
{
ignores: ["src/components/ui/**/*"],
ignores: ["src/components/ui/**/*", "src/components/magicui/**/*"],
},
];

View File

@@ -59,23 +59,6 @@ const images = [
const docsLink = "/docs/3.1-beta";
export default function HomePage() {
return (
<>
<main className="relative z-[2] w-full px-4 py-6 sm:px-6 lg:px-8">
<div className="relative mx-auto max-w-screen-xl bg-background">
<Hero />
<LogoShowcase />
<Feedback />
<Features />
<GetStarted />
</div>
</main>
<FullWidthFooter />
</>
);
}
function Hero() {
return (
<section className="relative z-[2] flex flex-col border-x border-t px-6 pt-12 pb-10 md:px-12 md:pt-16 max-md:text-center">
@@ -136,6 +119,18 @@ function Feedback() {
);
}
function Highlight({ icon: Icon, heading, children }: { icon: LucideIcon; heading: ReactNode; children: ReactNode }) {
return (
<div className="border-l border-t px-6 py-12">
<div className="mb-4 flex items-center gap-2 text-fd-muted-foreground">
<Icon className="size-6" />
<h2 className="text-sm font-medium">{heading}</h2>
</div>
<span className="font-medium">{children}</span>
</div>
);
}
function Features() {
return (
<>
@@ -218,18 +213,6 @@ function Features() {
);
}
function Highlight({ icon: Icon, heading, children }: { icon: LucideIcon; heading: ReactNode; children: ReactNode }) {
return (
<div className="border-l border-t px-6 py-12">
<div className="mb-4 flex items-center gap-2 text-fd-muted-foreground">
<Icon className="size-6" />
<h2 className="text-sm font-medium">{heading}</h2>
</div>
<span className="font-medium">{children}</span>
</div>
);
}
function GetStarted() {
return (
<section className="flex w-full flex-1">
@@ -321,3 +304,20 @@ function FullWidthFooter() {
</footer>
);
}
export default function HomePage() {
return (
<>
<main className="relative z-[2] w-full px-4 py-6 sm:px-6 lg:px-8">
<div className="relative mx-auto max-w-screen-xl bg-background">
<Hero />
<LogoShowcase />
<Feedback />
<Features />
<GetStarted />
</div>
</main>
<FullWidthFooter />
</>
);
}

View File

@@ -0,0 +1,6 @@
/node_modules
/dist
/build
/uploads
/temp-chunks
/prisma/migrations

View File

@@ -1,5 +1,7 @@
{
"plugins": ["@trivago/prettier-plugin-sort-imports"],
"importOrder": ["<THIRD_PARTY_MODULES>", "", "^@/(.*)$", "^[./]"],
"importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"],
"plugins": ["@ianvs/prettier-plugin-sort-imports", "prettier-plugin-sort-json"],
"printWidth": 120,
"singleQuote": false,
"tabWidth": 2,

View File

@@ -1,24 +1,45 @@
import pluginJs from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";
import importPlugin from "eslint-plugin-import";
import globals from "globals";
import tseslint from "typescript-eslint";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { FlatCompat } from "@eslint/eslintrc";
import js from "@eslint/js";
import typescriptEslintEslintPlugin from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
import prettier from "eslint-plugin-prettier";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
/** @type {import('eslint').Linter.Config[]} */
export default [
{ files: ["**/*.{js,mjs,cjs,ts}"] },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
importPlugin.flatConfigs.recommended,
eslintConfigPrettier,
...tseslint.configs.recommended,
...compat.extends("prettier"),
{
plugins: {
prettier,
},
rules: {
"import/no-unresolved": "off",
"import/no-named-as-default": "off",
"@typescript-eslint/no-unused-vars": "warn",
"prettier/prettier": "error",
camelcase: "off",
},
},
{
files: ["**/*.+(ts|tsx)"],
plugins: {
"@typescript-eslint": typescriptEslintEslintPlugin,
},
languageOptions: {
parser: tsParser,
},
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"no-use-before-define": [0],
"@typescript-eslint/no-use-before-define": [1],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-var-requires": "off",
},
},
];

View File

@@ -19,10 +19,12 @@
"dev": "tsx watch src/server.ts",
"build": "tsc -p tsconfig.json",
"start": "node dist/server.js",
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
"lint": "eslint \"src/**/*.+(ts|tsx)\"",
"lint:fix": "eslint \"src/**/*.+(ts|tsx)\" --fix",
"format": "prettier . --write",
"format:check": "prettier . --check",
"type-check": "npx tsc --noEmit",
"validate": "pnpm format && pnpm lint:fix && pnpm type-check",
"db:seed": "ts-node prisma/seed.js"
},
"prisma": {
@@ -53,20 +55,22 @@
"zod": "^3.24.1"
},
"devDependencies": {
"@eslint/js": "^9.19.0",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@eslint/eslintrc": "3.3.1",
"@eslint/js": "9.30.0",
"@ianvs/prettier-plugin-sort-imports": "4.4.2",
"@types/bcryptjs": "^2.4.6",
"@types/node": "^22.13.4",
"@types/nodemailer": "^6.4.17",
"eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-import": "^2.31.0",
"globals": "^15.14.0",
"prettier": "3.4.2",
"@typescript-eslint/eslint-plugin": "8.35.1",
"@typescript-eslint/parser": "8.35.1",
"eslint": "9.30.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-prettier": "5.5.1",
"prettier": "3.6.2",
"prettier-plugin-sort-json": "4.1.1",
"prisma": "^6.3.1",
"ts-node": "^10.9.2",
"tsx": "^4.19.2",
"typescript": "^5.7.3",
"typescript-eslint": "^8.23.0"
"typescript": "^5.7.3"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* eslint-disable no-undef */
const { PrismaClient } = require('@prisma/client');
const crypto = require('crypto');
const { PrismaClient } = require("@prisma/client");
const crypto = require("crypto");
const prisma = new PrismaClient();
@@ -147,7 +147,7 @@ const defaultConfigs = [
value: "http://localhost:3333",
type: "string",
group: "general",
}
},
];
const defaultAuthProviders = [
@@ -167,8 +167,8 @@ const defaultAuthProviders = [
description: "Sign in with your Google account",
docs: "https://developers.google.com/identity/protocols/oauth2",
supportsDiscovery: true,
authMethod: "body"
})
authMethod: "body",
}),
},
{
name: "discord",
@@ -186,8 +186,8 @@ const defaultAuthProviders = [
description: "Sign in with your Discord account",
docs: "https://discord.com/developers/docs/topics/oauth2",
supportsDiscovery: false,
authMethod: "body"
})
authMethod: "body",
}),
},
{
name: "github",
@@ -204,8 +204,8 @@ const defaultAuthProviders = [
metadata: JSON.stringify({
description: "Sign in with your GitHub account",
docs: "https://docs.github.com/en/developers/apps/building-oauth-apps",
specialHandling: "email_fetch_required"
})
specialHandling: "email_fetch_required",
}),
},
{
name: "auth0",
@@ -222,8 +222,8 @@ const defaultAuthProviders = [
metadata: JSON.stringify({
description: "Sign in with Auth0 - Replace 'your-tenant' with your Auth0 domain",
docs: "https://auth0.com/docs/get-started/authentication-and-authorization-flow",
supportsDiscovery: true
})
supportsDiscovery: true,
}),
},
{
name: "kinde",
@@ -240,8 +240,8 @@ const defaultAuthProviders = [
metadata: JSON.stringify({
description: "Sign in with Kinde - Replace 'your-tenant' with your Kinde domain",
docs: "https://kinde.com/docs/developer-tools/about/",
supportsDiscovery: true
})
supportsDiscovery: true,
}),
},
{
name: "zitadel",
@@ -259,8 +259,8 @@ const defaultAuthProviders = [
description: "Sign in with Zitadel - Replace with your Zitadel instance URL",
docs: "https://zitadel.com/docs/guides/integrate/login/oidc",
supportsDiscovery: true,
authMethod: "basic"
})
authMethod: "basic",
}),
},
{
name: "authentik",
@@ -277,8 +277,8 @@ const defaultAuthProviders = [
metadata: JSON.stringify({
description: "Sign in with Authentik - Replace with your Authentik instance URL",
docs: "https://goauthentik.io/docs/providers/oauth2",
supportsDiscovery: true
})
supportsDiscovery: true,
}),
},
{
name: "frontegg",
@@ -295,8 +295,8 @@ const defaultAuthProviders = [
metadata: JSON.stringify({
description: "Sign in with Frontegg - Replace 'your-tenant' with your Frontegg tenant",
docs: "https://docs.frontegg.com",
supportsDiscovery: true
})
supportsDiscovery: true,
}),
},
];
@@ -370,4 +370,4 @@ main()
})
.finally(async () => {
await prisma.$disconnect();
});
});

View File

@@ -1,13 +1,14 @@
import { registerSwagger } from "./config/swagger.config";
import { envTimeoutOverrides } from "./config/timeout.config";
import { prisma } from "./shared/prisma";
import crypto from "node:crypto";
import fastifyCookie from "@fastify/cookie";
import { fastifyCors } from "@fastify/cors";
import fastifyJwt from "@fastify/jwt";
import { fastifySwaggerUi } from "@fastify/swagger-ui";
import { fastify } from "fastify";
import { validatorCompiler, serializerCompiler, ZodTypeProvider } from "fastify-type-provider-zod";
import crypto from "node:crypto";
import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "fastify-type-provider-zod";
import { registerSwagger } from "./config/swagger.config";
import { envTimeoutOverrides } from "./config/timeout.config";
import { prisma } from "./shared/prisma";
export async function buildApp() {
const jwtConfig = await prisma.appConfig.findUnique({

View File

@@ -1,6 +1,7 @@
import { S3Client } from "@aws-sdk/client-s3";
import { env } from "../env";
import { StorageConfig } from "../types/storage";
import { S3Client } from "@aws-sdk/client-s3";
export const storageConfig: StorageConfig = {
endpoint: env.S3_ENDPOINT || "",

View File

@@ -1,9 +1,10 @@
import fs from "fs";
import path from "path";
import { FastifyReply, FastifyRequest } from "fastify";
import { EmailService } from "../email/service";
import { LogoService } from "./logo.service";
import { AppService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
import fs from "fs";
import path from "path";
const isDocker = (() => {
try {

View File

@@ -1,6 +1,7 @@
import { prisma } from "../../shared/prisma";
import sharp from "sharp";
import { prisma } from "../../shared/prisma";
export class LogoService {
async uploadLogo(buffer: Buffer): Promise<string> {
try {

View File

@@ -1,9 +1,10 @@
import { prisma } from "../../shared/prisma";
import { AppController } from "./controller";
import { ConfigResponseSchema, BulkUpdateConfigSchema } from "./dto";
import { FastifyInstance } from "fastify";
import { z } from "zod";
import { prisma } from "../../shared/prisma";
import { AppController } from "./controller";
import { BulkUpdateConfigSchema, ConfigResponseSchema } from "./dto";
export async function appRoutes(app: FastifyInstance) {
const appController = new AppController();

View File

@@ -1,3 +1,5 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { UpdateAuthProviderSchema } from "./dto";
import { AuthProvidersService } from "./service";
import {
@@ -9,7 +11,6 @@ import {
UpdateProviderRequest,
UpdateProvidersOrderRequest,
} from "./types";
import { FastifyRequest, FastifyReply } from "fastify";
const COOKIE_MAX_AGE = 7 * 24 * 60 * 60 * 1000;

View File

@@ -1,8 +1,9 @@
import { FastifyInstance } from "fastify";
import { z } from "zod";
import { prisma } from "../../shared/prisma";
import { AuthProvidersController } from "./controller";
import { CreateAuthProviderSchema, UpdateProvidersOrderSchema } from "./dto";
import { FastifyInstance } from "fastify";
import { z } from "zod";
export async function authProvidersRoutes(fastify: FastifyInstance) {
const authProvidersController = new AuthProvidersController();

View File

@@ -1,21 +1,22 @@
import crypto from "crypto";
import { prisma } from "../../shared/prisma";
import {
providersConfig,
detectProviderType,
getProviderScopes,
shouldSupportDiscovery,
getFallbackEndpoints,
DISCOVERY_PATHS,
getFallbackEndpoints,
getProviderScopes,
providersConfig,
shouldSupportDiscovery,
} from "./providers.config";
import {
ProviderConfig,
ProviderUserInfo,
TokenResponse,
ProviderEndpoints,
RequestContextService,
PendingState,
ProviderConfig,
ProviderEndpoints,
ProviderUserInfo,
RequestContextService,
TokenResponse,
} from "./types";
import crypto from "crypto";
// Constants
const DEFAULT_BASE_URL = "http://localhost:3000";

View File

@@ -1,8 +1,9 @@
import { env } from "../../env";
import { LoginSchema, RequestPasswordResetSchema, createResetPasswordSchema } from "./dto";
import { AuthService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
import { env } from "../../env";
import { createResetPasswordSchema, LoginSchema, RequestPasswordResetSchema } from "./dto";
import { AuthService } from "./service";
export class AuthController {
private authService = new AuthService();

View File

@@ -1,6 +1,7 @@
import { ConfigService } from "../config/service";
import { z } from "zod";
import { ConfigService } from "../config/service";
const configService = new ConfigService();
export const createPasswordSchema = async () => {

View File

@@ -1,9 +1,10 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { ConfigService } from "../config/service";
import { validatePasswordMiddleware } from "../user/middleware";
import { AuthController } from "./controller";
import { RequestPasswordResetSchema, createResetPasswordSchema } from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
import { createResetPasswordSchema, RequestPasswordResetSchema } from "./dto";
const configService = new ConfigService();

View File

@@ -1,11 +1,12 @@
import crypto from "node:crypto";
import bcrypt from "bcryptjs";
import { prisma } from "../../shared/prisma";
import { ConfigService } from "../config/service";
import { EmailService } from "../email/service";
import { UserResponseSchema } from "../user/dto";
import { PrismaUserRepository } from "../user/repository";
import { LoginInput } from "./dto";
import bcrypt from "bcryptjs";
import crypto from "node:crypto";
export class AuthService {
private userRepository = new PrismaUserRepository();

View File

@@ -1,6 +1,7 @@
import { ConfigService } from "../config/service";
import nodemailer from "nodemailer";
import { ConfigService } from "../config/service";
interface SmtpConfig {
smtpEnabled: string;
smtpHost: string;

View File

@@ -1,8 +1,9 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { prisma } from "../../shared/prisma";
import { ConfigService } from "../config/service";
import { RegisterFileSchema, RegisterFileInput, UpdateFileSchema, CheckFileInput, CheckFileSchema } from "./dto";
import { CheckFileInput, CheckFileSchema, RegisterFileInput, RegisterFileSchema, UpdateFileSchema } from "./dto";
import { FileService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
export class FileController {
private fileService = new FileService();

View File

@@ -1,7 +1,8 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { FileController } from "./controller";
import { CheckFileSchema, RegisterFileSchema, UpdateFileSchema } from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function fileRoutes(app: FastifyInstance) {
const fileController = new FileController();

View File

@@ -1,9 +1,10 @@
import { FilesystemStorageProvider } from "../../providers/filesystem-storage.provider";
import { FileService } from "../file/service";
import { FastifyRequest, FastifyReply } from "fastify";
import * as fs from "fs";
import * as path from "path";
import { pipeline } from "stream/promises";
import { FastifyReply, FastifyRequest } from "fastify";
import { FilesystemStorageProvider } from "../../providers/filesystem-storage.provider";
import { FileService } from "../file/service";
export class FilesystemController {
private fileService = new FileService();

View File

@@ -1,7 +1,8 @@
import { FilesystemController } from "./controller";
import { FastifyInstance, FastifyRequest } from "fastify";
import { z } from "zod";
import { FilesystemController } from "./controller";
export async function filesystemRoutes(app: FastifyInstance) {
const filesystemController = new FilesystemController();

View File

@@ -1,7 +1,8 @@
import { HealthController } from "./controller";
import { FastifyInstance } from "fastify";
import { z } from "zod";
import { HealthController } from "./controller";
export async function healthRoutes(app: FastifyInstance) {
const healthController = new HealthController();

View File

@@ -1,13 +1,14 @@
import { FastifyReply, FastifyRequest } from "fastify";
import {
CreateReverseShareSchema,
UpdateReverseShareSchema,
UpdateReverseSharePasswordSchema,
UploadToReverseShareSchema,
ReverseSharePasswordSchema,
GetPresignedUrlSchema,
ReverseSharePasswordSchema,
UpdateReverseSharePasswordSchema,
UpdateReverseShareSchema,
UploadToReverseShareSchema,
} from "./dto";
import { ReverseShareService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
export class ReverseShareController {
private reverseShareService = new ReverseShareService();

View File

@@ -1,6 +1,7 @@
import bcrypt from "bcryptjs";
import { prisma } from "../../shared/prisma";
import { CreateReverseShareInput, UpdateReverseShareInput } from "./dto";
import bcrypt from "bcryptjs";
export class ReverseShareRepository {
async create(data: CreateReverseShareInput, creatorId: string) {

View File

@@ -1,18 +1,19 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { ReverseShareController } from "./controller";
import {
CreateReverseShareSchema,
UpdateReverseShareSchema,
UpdateReverseSharePasswordSchema,
ReverseShareResponseSchema,
ReverseSharePublicSchema,
ReverseSharePasswordSchema,
ReverseShareFileSchema,
UploadToReverseShareSchema,
GetPresignedUrlSchema,
ReverseShareFileSchema,
ReverseSharePasswordSchema,
ReverseSharePublicSchema,
ReverseShareResponseSchema,
UpdateReverseShareFileSchema,
UpdateReverseSharePasswordSchema,
UpdateReverseShareSchema,
UploadToReverseShareSchema,
} from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function reverseShareRoutes(app: FastifyInstance) {
const reverseShareController = new ReverseShareController();

View File

@@ -1,12 +1,13 @@
import { PrismaClient } from "@prisma/client";
import { FileService } from "../file/service";
import {
CreateReverseShareInput,
ReverseShareResponseSchema,
UpdateReverseShareInput,
UploadToReverseShareInput,
ReverseShareResponseSchema,
} from "./dto";
import { ReverseShareRepository } from "./repository";
import { PrismaClient } from "@prisma/client";
interface ReverseShareData {
id: string;

View File

@@ -1,12 +1,13 @@
import { FastifyReply, FastifyRequest } from "fastify";
import {
CreateShareSchema,
UpdateShareSchema,
UpdateSharePasswordSchema,
UpdateShareFilesSchema,
UpdateSharePasswordSchema,
UpdateShareRecipientsSchema,
UpdateShareSchema,
} from "./dto";
import { ShareService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
export class ShareController {
private shareService = new ShareService();

View File

@@ -1,6 +1,7 @@
import type { Share, ShareSecurity } from "@prisma/client";
import { prisma } from "../../shared/prisma";
import type { CreateShareInput } from "./dto";
import type { Share, ShareSecurity } from "@prisma/client";
export interface IShareRepository {
createShare(data: CreateShareInput & { securityId: string; creatorId: string }): Promise<Share>;

View File

@@ -1,15 +1,16 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { ShareController } from "./controller";
import {
CreateShareSchema,
ShareResponseSchema,
UpdateShareSchema,
UpdateSharePasswordSchema,
UpdateShareFilesSchema,
UpdateShareRecipientsSchema,
ShareAliasResponseSchema,
ShareResponseSchema,
UpdateShareFilesSchema,
UpdateSharePasswordSchema,
UpdateShareRecipientsSchema,
UpdateShareSchema,
} from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function shareRoutes(app: FastifyInstance) {
const shareController = new ShareController();

View File

@@ -1,8 +1,9 @@
import bcrypt from "bcryptjs";
import { prisma } from "../../shared/prisma";
import { EmailService } from "../email/service";
import { CreateShareInput, UpdateShareInput, ShareResponseSchema } from "./dto";
import { PrismaShareRepository, IShareRepository } from "./repository";
import bcrypt from "bcryptjs";
import { CreateShareInput, ShareResponseSchema, UpdateShareInput } from "./dto";
import { IShareRepository, PrismaShareRepository } from "./repository";
export class ShareService {
constructor(private readonly shareRepository: IShareRepository = new PrismaShareRepository()) {}

View File

@@ -1,5 +1,6 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { StorageService } from "./service";
import { FastifyRequest, FastifyReply } from "fastify";
export class StorageController {
private storageService = new StorageService();

View File

@@ -1,7 +1,8 @@
import { StorageController } from "./controller";
import { FastifyInstance } from "fastify";
import { z } from "zod";
import { StorageController } from "./controller";
export async function storageRoutes(app: FastifyInstance) {
const storageController = new StorageController();

View File

@@ -1,9 +1,10 @@
import { IS_RUNNING_IN_CONTAINER } from "../../utils/container-detection";
import { ConfigService } from "../config/service";
import { PrismaClient } from "@prisma/client";
import { exec } from "child_process";
import fs from "node:fs";
import { promisify } from "util";
import { PrismaClient } from "@prisma/client";
import { IS_RUNNING_IN_CONTAINER } from "../../utils/container-detection";
import { ConfigService } from "../config/service";
const execAsync = promisify(exec);
const prisma = new PrismaClient();

View File

@@ -1,9 +1,8 @@
import sharp from "sharp";
import { prisma } from "../../shared/prisma";
export class AvatarService {
async uploadAvatar(buffer: Buffer): Promise<string> {
try {
const metadata = await sharp(buffer).metadata();
@@ -12,20 +11,20 @@ export class AvatarService {
}
const webpBuffer = await sharp(buffer)
.resize(100, 100, {
.resize(100, 100, {
fit: "cover",
background: { r: 255, g: 255, b: 255, alpha: 0 }
background: { r: 255, g: 255, b: 255, alpha: 0 },
})
.webp({
.webp({
quality: 60,
effort: 6,
nearLossless: true,
alphaQuality: 100,
lossless: true
lossless: true,
})
.toBuffer();
return `data:image/webp;base64,${webpBuffer.toString('base64')}`;
return `data:image/webp;base64,${webpBuffer.toString("base64")}`;
} catch (error) {
console.error("Error processing avatar:", error);
throw error;

View File

@@ -1,8 +1,9 @@
import { AvatarService } from "./avatar.service";
import { UpdateUserSchema, createRegisterUserSchema } from "./dto";
import { UserService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
import { AvatarService } from "./avatar.service";
import { createRegisterUserSchema, UpdateUserSchema } from "./dto";
import { UserService } from "./service";
export class UserController {
private userService = new UserService();
private avatarService = new AvatarService();
@@ -101,7 +102,7 @@ export class UserController {
return reply.status(400).send({ error: "No file uploaded" });
}
if (!file.mimetype.startsWith('image/')) {
if (!file.mimetype.startsWith("image/")) {
return reply.status(400).send({ error: "Only images are allowed" });
}

View File

@@ -1,6 +1,7 @@
import { ConfigService } from "../config/service";
import { z } from "zod";
import { ConfigService } from "../config/service";
const configService = new ConfigService();
export const BaseRegisterUserSchema = z.object({

View File

@@ -1,5 +1,6 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { ConfigService } from "../config/service";
import { FastifyRequest, FastifyReply } from "fastify";
const configService = new ConfigService();

View File

@@ -1,6 +1,7 @@
import type { User } from "@prisma/client";
import { prisma } from "../../shared/prisma";
import type { RegisterUserInput, UpdateUserInput } from "./dto";
import type { User } from "@prisma/client";
export interface IUserRepository {
createUser(data: RegisterUserInput & { password: string }): Promise<User>;

View File

@@ -1,10 +1,11 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { prisma } from "../../shared/prisma";
import { createPasswordSchema } from "../auth/dto";
import { UserController } from "./controller";
import { UpdateUserSchema, UserResponseSchema } from "./dto";
import { validatePasswordMiddleware } from "./middleware";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function userRoutes(app: FastifyInstance) {
const userController = new UserController();

View File

@@ -1,8 +1,9 @@
import { RegisterUserInput, UserResponseSchema } from "./dto";
import { PrismaUserRepository, IUserRepository } from "./repository";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";
import { RegisterUserInput, UserResponseSchema } from "./dto";
import { IUserRepository, PrismaUserRepository } from "./repository";
type UserWithPassword = {
id: string;
email?: string;

View File

@@ -1,6 +1,3 @@
import { env } from "../env";
import { StorageProvider } from "../types/storage";
import { IS_RUNNING_IN_CONTAINER } from "../utils/container-detection";
import * as crypto from "crypto";
import * as fsSync from "fs";
import * as fs from "fs/promises";
@@ -8,6 +5,10 @@ import * as path from "path";
import { Transform } from "stream";
import { pipeline } from "stream/promises";
import { env } from "../env";
import { StorageProvider } from "../types/storage";
import { IS_RUNNING_IN_CONTAINER } from "../utils/container-detection";
export class FilesystemStorageProvider implements StorageProvider {
private static instance: FilesystemStorageProvider;
private uploadsDir: string;

View File

@@ -1,8 +1,9 @@
import { s3Client, bucketName } from "../config/storage.config";
import { StorageProvider } from "../types/storage";
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { bucketName, s3Client } from "../config/storage.config";
import { StorageProvider } from "../types/storage";
export class S3StorageProvider implements StorageProvider {
constructor() {
if (!s3Client) {

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env node
import * as readline from "readline";
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";
import * as readline from "readline";
const prisma = new PrismaClient();

View File

@@ -1,3 +1,9 @@
import * as fs from "fs/promises";
import crypto from "node:crypto";
import path from "path";
import fastifyMultipart from "@fastify/multipart";
import fastifyStatic from "@fastify/static";
import { buildApp } from "./app";
import { env } from "./env";
import { appRoutes } from "./modules/app/routes";
@@ -11,11 +17,6 @@ import { shareRoutes } from "./modules/share/routes";
import { storageRoutes } from "./modules/storage/routes";
import { userRoutes } from "./modules/user/routes";
import { IS_RUNNING_IN_CONTAINER } from "./utils/container-detection";
import fastifyMultipart from "@fastify/multipart";
import fastifyStatic from "@fastify/static";
import * as fs from "fs/promises";
import crypto from "node:crypto";
import path from "path";
if (typeof globalThis.crypto === "undefined") {
globalThis.crypto = crypto.webcrypto as any;

View File

@@ -1,4 +1,3 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { FastifyRequest } from "fastify";
declare module "fastify" {

View File

@@ -1,11 +1,8 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Node 22",
"_version": "22.0.0",
"compilerOptions": {
"lib": [
"es2023"
],
"lib": ["es2023"],
"module": "node16",
"target": "es2022",
"strict": true,
@@ -16,12 +13,9 @@
"rootDir": "./src",
"baseUrl": "./src",
"paths": {
"@/*": [
"src/*"
]
"@/*": ["src/*"]
}
},
"include": [
"src/**/*"
]
}
"display": "Node 22",
"include": ["src/**/*"]
}