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..." echo "🔍 Running pre-push validation for all apps..."
cd apps/web && pnpm validate
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 // 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"; 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() { function Hero() {
return ( 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"> <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() { function Features() {
return ( 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() { function GetStarted() {
return ( return (
<section className="flex w-full flex-1"> <section className="flex w-full flex-1">
@@ -321,3 +304,20 @@ function FullWidthFooter() {
</footer> </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, "printWidth": 120,
"singleQuote": false, "singleQuote": false,
"tabWidth": 2, "tabWidth": 2,

View File

@@ -1,24 +1,45 @@
import pluginJs from "@eslint/js"; import path from "node:path";
import eslintConfigPrettier from "eslint-config-prettier"; import { fileURLToPath } from "node:url";
import importPlugin from "eslint-plugin-import"; import { FlatCompat } from "@eslint/eslintrc";
import globals from "globals"; import js from "@eslint/js";
import tseslint from "typescript-eslint"; 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 [ export default [
{ files: ["**/*.{js,mjs,cjs,ts}"] }, ...compat.extends("prettier"),
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
importPlugin.flatConfigs.recommended,
eslintConfigPrettier,
...tseslint.configs.recommended,
{ {
plugins: {
prettier,
},
rules: { rules: {
"import/no-unresolved": "off", "prettier/prettier": "error",
"import/no-named-as-default": "off", camelcase: "off",
"@typescript-eslint/no-unused-vars": "warn", },
},
{
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-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", "dev": "tsx watch src/server.ts",
"build": "tsc -p tsconfig.json", "build": "tsc -p tsconfig.json",
"start": "node dist/server.js", "start": "node dist/server.js",
"lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", "lint": "eslint \"src/**/*.+(ts|tsx)\"",
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix", "lint:fix": "eslint \"src/**/*.+(ts|tsx)\" --fix",
"format": "prettier . --write", "format": "prettier . --write",
"format:check": "prettier . --check", "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" "db:seed": "ts-node prisma/seed.js"
}, },
"prisma": { "prisma": {
@@ -53,20 +55,22 @@
"zod": "^3.24.1" "zod": "^3.24.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.19.0", "@eslint/eslintrc": "3.3.1",
"@trivago/prettier-plugin-sort-imports": "^5.2.2", "@eslint/js": "9.30.0",
"@ianvs/prettier-plugin-sort-imports": "4.4.2",
"@types/bcryptjs": "^2.4.6", "@types/bcryptjs": "^2.4.6",
"@types/node": "^22.13.4", "@types/node": "^22.13.4",
"@types/nodemailer": "^6.4.17", "@types/nodemailer": "^6.4.17",
"eslint": "^9.19.0", "@typescript-eslint/eslint-plugin": "8.35.1",
"eslint-config-prettier": "^10.0.1", "@typescript-eslint/parser": "8.35.1",
"eslint-plugin-import": "^2.31.0", "eslint": "9.30.0",
"globals": "^15.14.0", "eslint-config-prettier": "9.1.0",
"prettier": "3.4.2", "eslint-plugin-prettier": "5.5.1",
"prettier": "3.6.2",
"prettier-plugin-sort-json": "4.1.1",
"prisma": "^6.3.1", "prisma": "^6.3.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsx": "^4.19.2", "tsx": "^4.19.2",
"typescript": "^5.7.3", "typescript": "^5.7.3"
"typescript-eslint": "^8.23.0"
} }
} }

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import { S3Client } from "@aws-sdk/client-s3";
import { env } from "../env"; import { env } from "../env";
import { StorageConfig } from "../types/storage"; import { StorageConfig } from "../types/storage";
import { S3Client } from "@aws-sdk/client-s3";
export const storageConfig: StorageConfig = { export const storageConfig: StorageConfig = {
endpoint: env.S3_ENDPOINT || "", 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 { EmailService } from "../email/service";
import { LogoService } from "./logo.service"; import { LogoService } from "./logo.service";
import { AppService } from "./service"; import { AppService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
import fs from "fs";
import path from "path";
const isDocker = (() => { const isDocker = (() => {
try { try {

View File

@@ -1,6 +1,7 @@
import { prisma } from "../../shared/prisma";
import sharp from "sharp"; import sharp from "sharp";
import { prisma } from "../../shared/prisma";
export class LogoService { export class LogoService {
async uploadLogo(buffer: Buffer): Promise<string> { async uploadLogo(buffer: Buffer): Promise<string> {
try { 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 { FastifyInstance } from "fastify";
import { z } from "zod"; import { z } from "zod";
import { prisma } from "../../shared/prisma";
import { AppController } from "./controller";
import { BulkUpdateConfigSchema, ConfigResponseSchema } from "./dto";
export async function appRoutes(app: FastifyInstance) { export async function appRoutes(app: FastifyInstance) {
const appController = new AppController(); const appController = new AppController();

View File

@@ -1,3 +1,5 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { UpdateAuthProviderSchema } from "./dto"; import { UpdateAuthProviderSchema } from "./dto";
import { AuthProvidersService } from "./service"; import { AuthProvidersService } from "./service";
import { import {
@@ -9,7 +11,6 @@ import {
UpdateProviderRequest, UpdateProviderRequest,
UpdateProvidersOrderRequest, UpdateProvidersOrderRequest,
} from "./types"; } from "./types";
import { FastifyRequest, FastifyReply } from "fastify";
const COOKIE_MAX_AGE = 7 * 24 * 60 * 60 * 1000; 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 { prisma } from "../../shared/prisma";
import { AuthProvidersController } from "./controller"; import { AuthProvidersController } from "./controller";
import { CreateAuthProviderSchema, UpdateProvidersOrderSchema } from "./dto"; import { CreateAuthProviderSchema, UpdateProvidersOrderSchema } from "./dto";
import { FastifyInstance } from "fastify";
import { z } from "zod";
export async function authProvidersRoutes(fastify: FastifyInstance) { export async function authProvidersRoutes(fastify: FastifyInstance) {
const authProvidersController = new AuthProvidersController(); const authProvidersController = new AuthProvidersController();

View File

@@ -1,21 +1,22 @@
import crypto from "crypto";
import { prisma } from "../../shared/prisma"; import { prisma } from "../../shared/prisma";
import { import {
providersConfig,
detectProviderType, detectProviderType,
getProviderScopes,
shouldSupportDiscovery,
getFallbackEndpoints,
DISCOVERY_PATHS, DISCOVERY_PATHS,
getFallbackEndpoints,
getProviderScopes,
providersConfig,
shouldSupportDiscovery,
} from "./providers.config"; } from "./providers.config";
import { import {
ProviderConfig,
ProviderUserInfo,
TokenResponse,
ProviderEndpoints,
RequestContextService,
PendingState, PendingState,
ProviderConfig,
ProviderEndpoints,
ProviderUserInfo,
RequestContextService,
TokenResponse,
} from "./types"; } from "./types";
import crypto from "crypto";
// Constants // Constants
const DEFAULT_BASE_URL = "http://localhost:3000"; 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 { FastifyReply, FastifyRequest } from "fastify";
import { env } from "../../env";
import { createResetPasswordSchema, LoginSchema, RequestPasswordResetSchema } from "./dto";
import { AuthService } from "./service";
export class AuthController { export class AuthController {
private authService = new AuthService(); private authService = new AuthService();

View File

@@ -1,6 +1,7 @@
import { ConfigService } from "../config/service";
import { z } from "zod"; import { z } from "zod";
import { ConfigService } from "../config/service";
const configService = new ConfigService(); const configService = new ConfigService();
export const createPasswordSchema = async () => { 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 { ConfigService } from "../config/service";
import { validatePasswordMiddleware } from "../user/middleware"; import { validatePasswordMiddleware } from "../user/middleware";
import { AuthController } from "./controller"; import { AuthController } from "./controller";
import { RequestPasswordResetSchema, createResetPasswordSchema } from "./dto"; import { createResetPasswordSchema, RequestPasswordResetSchema } from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
const configService = new ConfigService(); 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 { prisma } from "../../shared/prisma";
import { ConfigService } from "../config/service"; import { ConfigService } from "../config/service";
import { EmailService } from "../email/service"; import { EmailService } from "../email/service";
import { UserResponseSchema } from "../user/dto"; import { UserResponseSchema } from "../user/dto";
import { PrismaUserRepository } from "../user/repository"; import { PrismaUserRepository } from "../user/repository";
import { LoginInput } from "./dto"; import { LoginInput } from "./dto";
import bcrypt from "bcryptjs";
import crypto from "node:crypto";
export class AuthService { export class AuthService {
private userRepository = new PrismaUserRepository(); private userRepository = new PrismaUserRepository();

View File

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

View File

@@ -1,8 +1,9 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { prisma } from "../../shared/prisma"; import { prisma } from "../../shared/prisma";
import { ConfigService } from "../config/service"; 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 { FileService } from "./service";
import { FastifyReply, FastifyRequest } from "fastify";
export class FileController { export class FileController {
private fileService = new FileService(); 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 { FileController } from "./controller";
import { CheckFileSchema, RegisterFileSchema, UpdateFileSchema } from "./dto"; import { CheckFileSchema, RegisterFileSchema, UpdateFileSchema } from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function fileRoutes(app: FastifyInstance) { export async function fileRoutes(app: FastifyInstance) {
const fileController = new FileController(); 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 fs from "fs";
import * as path from "path"; import * as path from "path";
import { pipeline } from "stream/promises"; 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 { export class FilesystemController {
private fileService = new FileService(); private fileService = new FileService();

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import bcrypt from "bcryptjs";
import { prisma } from "../../shared/prisma"; import { prisma } from "../../shared/prisma";
import { CreateReverseShareInput, UpdateReverseShareInput } from "./dto"; import { CreateReverseShareInput, UpdateReverseShareInput } from "./dto";
import bcrypt from "bcryptjs";
export class ReverseShareRepository { export class ReverseShareRepository {
async create(data: CreateReverseShareInput, creatorId: string) { 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 { ReverseShareController } from "./controller";
import { import {
CreateReverseShareSchema, CreateReverseShareSchema,
UpdateReverseShareSchema,
UpdateReverseSharePasswordSchema,
ReverseShareResponseSchema,
ReverseSharePublicSchema,
ReverseSharePasswordSchema,
ReverseShareFileSchema,
UploadToReverseShareSchema,
GetPresignedUrlSchema, GetPresignedUrlSchema,
ReverseShareFileSchema,
ReverseSharePasswordSchema,
ReverseSharePublicSchema,
ReverseShareResponseSchema,
UpdateReverseShareFileSchema, UpdateReverseShareFileSchema,
UpdateReverseSharePasswordSchema,
UpdateReverseShareSchema,
UploadToReverseShareSchema,
} from "./dto"; } from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function reverseShareRoutes(app: FastifyInstance) { export async function reverseShareRoutes(app: FastifyInstance) {
const reverseShareController = new ReverseShareController(); const reverseShareController = new ReverseShareController();

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import type { Share, ShareSecurity } from "@prisma/client";
import { prisma } from "../../shared/prisma"; import { prisma } from "../../shared/prisma";
import type { CreateShareInput } from "./dto"; import type { CreateShareInput } from "./dto";
import type { Share, ShareSecurity } from "@prisma/client";
export interface IShareRepository { export interface IShareRepository {
createShare(data: CreateShareInput & { securityId: string; creatorId: string }): Promise<Share>; 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 { ShareController } from "./controller";
import { import {
CreateShareSchema, CreateShareSchema,
ShareResponseSchema,
UpdateShareSchema,
UpdateSharePasswordSchema,
UpdateShareFilesSchema,
UpdateShareRecipientsSchema,
ShareAliasResponseSchema, ShareAliasResponseSchema,
ShareResponseSchema,
UpdateShareFilesSchema,
UpdateSharePasswordSchema,
UpdateShareRecipientsSchema,
UpdateShareSchema,
} from "./dto"; } from "./dto";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function shareRoutes(app: FastifyInstance) { export async function shareRoutes(app: FastifyInstance) {
const shareController = new ShareController(); const shareController = new ShareController();

View File

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

View File

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

View File

@@ -1,7 +1,8 @@
import { StorageController } from "./controller";
import { FastifyInstance } from "fastify"; import { FastifyInstance } from "fastify";
import { z } from "zod"; import { z } from "zod";
import { StorageController } from "./controller";
export async function storageRoutes(app: FastifyInstance) { export async function storageRoutes(app: FastifyInstance) {
const storageController = new StorageController(); 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 { exec } from "child_process";
import fs from "node:fs"; import fs from "node:fs";
import { promisify } from "util"; 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 execAsync = promisify(exec);
const prisma = new PrismaClient(); const prisma = new PrismaClient();

View File

@@ -1,9 +1,8 @@
import sharp from "sharp"; import sharp from "sharp";
import { prisma } from "../../shared/prisma"; import { prisma } from "../../shared/prisma";
export class AvatarService { export class AvatarService {
async uploadAvatar(buffer: Buffer): Promise<string> { async uploadAvatar(buffer: Buffer): Promise<string> {
try { try {
const metadata = await sharp(buffer).metadata(); const metadata = await sharp(buffer).metadata();
@@ -12,20 +11,20 @@ export class AvatarService {
} }
const webpBuffer = await sharp(buffer) const webpBuffer = await sharp(buffer)
.resize(100, 100, { .resize(100, 100, {
fit: "cover", fit: "cover",
background: { r: 255, g: 255, b: 255, alpha: 0 } background: { r: 255, g: 255, b: 255, alpha: 0 },
}) })
.webp({ .webp({
quality: 60, quality: 60,
effort: 6, effort: 6,
nearLossless: true, nearLossless: true,
alphaQuality: 100, alphaQuality: 100,
lossless: true lossless: true,
}) })
.toBuffer(); .toBuffer();
return `data:image/webp;base64,${webpBuffer.toString('base64')}`; return `data:image/webp;base64,${webpBuffer.toString("base64")}`;
} catch (error) { } catch (error) {
console.error("Error processing avatar:", error); console.error("Error processing avatar:", error);
throw 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 { FastifyReply, FastifyRequest } from "fastify";
import { AvatarService } from "./avatar.service";
import { createRegisterUserSchema, UpdateUserSchema } from "./dto";
import { UserService } from "./service";
export class UserController { export class UserController {
private userService = new UserService(); private userService = new UserService();
private avatarService = new AvatarService(); private avatarService = new AvatarService();
@@ -101,7 +102,7 @@ export class UserController {
return reply.status(400).send({ error: "No file uploaded" }); 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" }); 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 { z } from "zod";
import { ConfigService } from "../config/service";
const configService = new ConfigService(); const configService = new ConfigService();
export const BaseRegisterUserSchema = z.object({ export const BaseRegisterUserSchema = z.object({

View File

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

View File

@@ -1,6 +1,7 @@
import type { User } from "@prisma/client";
import { prisma } from "../../shared/prisma"; import { prisma } from "../../shared/prisma";
import type { RegisterUserInput, UpdateUserInput } from "./dto"; import type { RegisterUserInput, UpdateUserInput } from "./dto";
import type { User } from "@prisma/client";
export interface IUserRepository { export interface IUserRepository {
createUser(data: RegisterUserInput & { password: string }): Promise<User>; 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 { prisma } from "../../shared/prisma";
import { createPasswordSchema } from "../auth/dto"; import { createPasswordSchema } from "../auth/dto";
import { UserController } from "./controller"; import { UserController } from "./controller";
import { UpdateUserSchema, UserResponseSchema } from "./dto"; import { UpdateUserSchema, UserResponseSchema } from "./dto";
import { validatePasswordMiddleware } from "./middleware"; import { validatePasswordMiddleware } from "./middleware";
import { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
import { z } from "zod";
export async function userRoutes(app: FastifyInstance) { export async function userRoutes(app: FastifyInstance) {
const userController = new UserController(); 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 { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import { RegisterUserInput, UserResponseSchema } from "./dto";
import { IUserRepository, PrismaUserRepository } from "./repository";
type UserWithPassword = { type UserWithPassword = {
id: string; id: string;
email?: 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 crypto from "crypto";
import * as fsSync from "fs"; import * as fsSync from "fs";
import * as fs from "fs/promises"; import * as fs from "fs/promises";
@@ -8,6 +5,10 @@ import * as path from "path";
import { Transform } from "stream"; import { Transform } from "stream";
import { pipeline } from "stream/promises"; 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 { export class FilesystemStorageProvider implements StorageProvider {
private static instance: FilesystemStorageProvider; private static instance: FilesystemStorageProvider;
private uploadsDir: string; 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 { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; 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 { export class S3StorageProvider implements StorageProvider {
constructor() { constructor() {
if (!s3Client) { if (!s3Client) {

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
import * as readline from "readline";
import { PrismaClient } from "@prisma/client"; import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import * as readline from "readline";
const prisma = new PrismaClient(); 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 { buildApp } from "./app";
import { env } from "./env"; import { env } from "./env";
import { appRoutes } from "./modules/app/routes"; import { appRoutes } from "./modules/app/routes";
@@ -11,11 +17,6 @@ import { shareRoutes } from "./modules/share/routes";
import { storageRoutes } from "./modules/storage/routes"; import { storageRoutes } from "./modules/storage/routes";
import { userRoutes } from "./modules/user/routes"; import { userRoutes } from "./modules/user/routes";
import { IS_RUNNING_IN_CONTAINER } from "./utils/container-detection"; 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") { if (typeof globalThis.crypto === "undefined") {
globalThis.crypto = crypto.webcrypto as any; 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"; import type { FastifyRequest } from "fastify";
declare module "fastify" { declare module "fastify" {

View File

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