mirror of
https://github.com/origranot/reduced.to.git
synced 2025-03-14 10:33:54 +00:00
Create an internal lib for configuration (#443)
* feat: use external config as library * deps: update nx deps * revert * fix: volume * fix: some syntax * fix: remove args from docker compose --------- Co-authored-by: orig <oriorigranot@gamil.com> Co-authored-by: orig <oriorigraont@gmail.com>
This commit is contained in:
35
.example.env
Normal file
35
.example.env
Normal file
@ -0,0 +1,35 @@
|
||||
# General
|
||||
BACKEND_APP_PORT=3000
|
||||
FRONTEND_APP_PORT=5000
|
||||
NODE_ENV=development
|
||||
|
||||
# RATE LIMIT
|
||||
RATE_LIMIT_TTL=60
|
||||
RATE_LIMIT_COUNT=10
|
||||
|
||||
# LOGGER
|
||||
LOGGER_CONSOLE_THRESHOLD=INFO # DEBUG, INFO, WARN, ERROR, FATAL
|
||||
|
||||
# FRONTEND
|
||||
DOMAIN=localhost
|
||||
CLIENTSIDE_API_DOMAIN=http://localhost:3000 # Use this verible, while making client side API calls
|
||||
API_DOMAIN=http://localhost:3000 # If you are running with docker compose change this to http://backend:3000
|
||||
|
||||
# DATABASE
|
||||
# If you are running with docker compose change host to postgres
|
||||
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/reduced_to_db?schema=public"
|
||||
|
||||
# REDIS
|
||||
REDIS_ENABLE=false
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=password
|
||||
REDIS_TTL=604800000 # 1 week in milliseconds
|
||||
|
||||
# AUTH
|
||||
JWT_ACCESS_SECRET=abc1234
|
||||
JWT_REFRESH_SECRET=abc1234
|
||||
|
||||
# NOVU - You don't need this when running locally (just verify your email from the database)
|
||||
NOVU_API_KEY=Get it from https://novu.co/
|
||||
|
@ -1,5 +1,8 @@
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
node_modules
|
||||
dist
|
||||
npm-debug.log
|
||||
dist
|
||||
CONTRIBUTE.MD
|
||||
README.md
|
||||
.gitignore
|
||||
LICENSE
|
||||
.DS_Store
|
||||
|
@ -1,30 +0,0 @@
|
||||
# APP - ONLY OVERRIDE IF DEFAULT SETTINGS ARE NOT ENOUGH
|
||||
APP_PORT=3000
|
||||
NODE_ENV=development
|
||||
|
||||
# RATE LIMIT
|
||||
RATE_LIMIT_TTL=60
|
||||
RATE_LIMIT_COUNT=10
|
||||
|
||||
# LOGGER
|
||||
LOGGER_CONSOLE_THRESHOLD=INFO # DEBUG, INFO, WARN, ERROR, FATAL
|
||||
|
||||
# FRONT
|
||||
FRONT_DOMAIN=http://localhost:5173
|
||||
|
||||
# DATABASE
|
||||
DATABASE_URL="postgresql://postgres:postgres@postgres:5432/reduced_to_db?schema=public"
|
||||
|
||||
# REDIS
|
||||
REDIS_ENABLE=false
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=password
|
||||
REDIS_TTL=604800000 # 1 week in milliseconds
|
||||
|
||||
# AUTH
|
||||
JWT_ACCESS_SECRET=abc1234
|
||||
JWT_REFRESH_SECRET=abc1234
|
||||
|
||||
# NOVU - You don't need this when running locally
|
||||
NOVU_API_KEY= Get it from https://novu.co/
|
@ -2,9 +2,9 @@
|
||||
# Dependencies Stage
|
||||
# --------------------------------------------
|
||||
FROM node:19.2-alpine3.15 as dependencies
|
||||
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN apk add --update python3 make g++\
|
||||
&& rm -rf /var/cache/apk/*
|
||||
@ -24,7 +24,6 @@ COPY --from=dependencies /app/node_modules ./node_modules
|
||||
# Run prisma generate & build the bundle in production mode
|
||||
RUN npx nx build backend --prod --skip-nx-cache
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# Production Stage
|
||||
# --------------------------------------------
|
||||
@ -32,12 +31,17 @@ FROM node:19.2-alpine3.15 as production
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build /app/dist/apps/backend ./backend
|
||||
COPY --from=build /app/dist/libs/prisma ./prisma
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY ./libs/ ./libs/
|
||||
COPY ./nx.json ./nx.json
|
||||
COPY --from=build /app/libs/ ./libs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
# Start the application
|
||||
CMD sh -c "npx nx migrate-deploy prisma && node backend/main.js"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3,8 +3,7 @@ import { APP_GUARD } from '@nestjs/core';
|
||||
import { ThrottlerModule } from '@nestjs/throttler';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { AppCacheModule } from './cache/cache.module';
|
||||
import { AppConfigModule } from './config/config.module';
|
||||
import { AppConfigService } from './config/config.service';
|
||||
import { AppConfigModule, AppConfigService } from '@reduced.to/config';
|
||||
import { AppLoggerModule } from './logger/logger.module';
|
||||
import { NovuModule } from './novu/novu.module';
|
||||
import { PrismaService } from '@reduced.to/prisma';
|
||||
|
@ -5,7 +5,7 @@ import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './auth.service';
|
||||
import { NovuService } from '../novu/novu.service';
|
||||
import { PrismaService } from '@reduced.to/prisma';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService, Configuration } from '@reduced.to/config';
|
||||
import { SignupDto } from './dto/signup.dto';
|
||||
import { UserContext } from './interfaces/user-context';
|
||||
import { LocalAuthGuard } from './guards/local.guard';
|
||||
@ -36,9 +36,9 @@ describe('AuthController', () => {
|
||||
};
|
||||
|
||||
const MOCK_TOKENS = { accessToken: 'access_token', refreshToken: 'refresh_token' };
|
||||
const MOCK_CONFIG = {
|
||||
front: { domain: 'example.com' },
|
||||
app: { env: 'production' },
|
||||
const MOCK_CONFIG: Partial<Configuration> = {
|
||||
front: { domain: 'example.com', apiDomain: 'http://localhost:3000', clientSideApiDomain: 'http://localhost:3000' },
|
||||
general: { env: 'production', backendPort: 3000, frontendPort: 5000 },
|
||||
jwt: {
|
||||
accessSecret: 'secret',
|
||||
refreshSecret: 'secret',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Body, Controller, Get, Post, Req, Res, UnauthorizedException, UseGuards } from '@nestjs/common';
|
||||
import { Request, Response } from 'express';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { NovuService } from '../novu/novu.service';
|
||||
import { PrismaService } from '@reduced.to/prisma';
|
||||
import { AuthService } from './auth.service';
|
||||
@ -44,7 +44,7 @@ export class AuthController {
|
||||
const user = await this.authService.signup(signupDto);
|
||||
|
||||
// Send verification email to user if in production
|
||||
if (this.appConfigService.getConfig().app.env === 'production') {
|
||||
if (this.appConfigService.getConfig().general.env === 'production') {
|
||||
await this.novuService.sendVerificationEmail(user);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { NovuModule } from '../novu/novu.module';
|
||||
import { NovuService } from '../novu/novu.service';
|
||||
import { PrismaModule } from '@reduced.to/prisma';
|
||||
|
@ -3,7 +3,7 @@ import { JwtService } from '@nestjs/jwt';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Role, User } from '@reduced.to/prisma';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { AppConfigModule } from '../config/config.module';
|
||||
import { AppConfigModule } from '@reduced.to/config';
|
||||
import { PrismaService } from '@reduced.to/prisma';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { Role } from '@reduced.to/prisma';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { PrismaService } from '@reduced.to/prisma';
|
||||
import { SignupDto } from './dto/signup.dto';
|
||||
import { UserContext } from './interfaces/user-context';
|
||||
|
@ -2,7 +2,7 @@ import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Request } from 'express';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { AppConfigService } from '../../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { AuthService } from '../auth.service';
|
||||
|
||||
@Injectable()
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { AppConfigService } from '../../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { AppConfigService } from '../../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
|
||||
@Injectable()
|
||||
export class VerifyStrategy extends PassportStrategy(Strategy, 'verify') {
|
||||
|
@ -15,13 +15,7 @@ export const setAuthCookies = (
|
||||
refreshToken: string;
|
||||
}
|
||||
) => {
|
||||
// get the host from the domain (remove port if present)
|
||||
// for example: localhost:5155 -> localhost
|
||||
// for example: reduced.to -> reduced.to
|
||||
const strippedDomain = rawDomain
|
||||
.replace(/http(s)?(:)?(\/\/)?|(\/\/)?(www\.)?/g, '') // strip prefix
|
||||
.replace(/:\d+$/g, ''); // strip port
|
||||
const domain = process.env.NODE_ENV === 'production' ? `.${strippedDomain}` : strippedDomain;
|
||||
const domain = process.env.NODE_ENV === 'production' ? `.${rawDomain}` : rawDomain;
|
||||
|
||||
res
|
||||
.cookie(AUTH_COOKIE_NAME, tokens.accessToken, {
|
||||
|
3
apps/backend/src/cache/cache.module.ts
vendored
3
apps/backend/src/cache/cache.module.ts
vendored
@ -1,8 +1,7 @@
|
||||
import { CacheModule, CacheStore } from '@nestjs/cache-manager';
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { RedisStore, redisStore } from 'cache-manager-redis-store';
|
||||
import { AppConfigModule } from '../config/config.module';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService, AppConfigModule } from '@reduced.to/config';
|
||||
import { AppCacheService } from './cache.service';
|
||||
|
||||
@Global()
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppConfigModule } from '../config/config.module';
|
||||
import { AppConfigModule } from '@reduced.to/config';
|
||||
import { AppLoggerSerivce } from './logger.service';
|
||||
|
||||
describe('LoggerService', () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Injectable, LoggerService, LogLevel } from '@nestjs/common';
|
||||
import { ConsoleTransport, Logger } from '@origranot/ts-logger';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
|
||||
@Injectable()
|
||||
export class AppLoggerSerivce implements LoggerService {
|
||||
|
@ -4,7 +4,7 @@ import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { useContainer } from 'class-validator';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import { AppModule } from './app.module';
|
||||
import { AppConfigService } from './config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
@ -22,7 +22,7 @@ async function bootstrap() {
|
||||
// Enable DI in class-validator
|
||||
useContainer(app.select(AppModule), { fallbackOnErrors: true });
|
||||
|
||||
const port = app.get(AppConfigService).getConfig().app.port;
|
||||
const port = app.get(AppConfigService).getConfig().general.backendPort;
|
||||
|
||||
await app.listen(port);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { Novu } from '@novu/node';
|
||||
|
||||
export const NOVU_INJECTION_TOKEN = 'NOVU';
|
||||
|
@ -1,14 +1,22 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Novu } from '@novu/node';
|
||||
import { UserContext } from '../auth/interfaces/user-context';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { NOVU_INJECTION_TOKEN } from './novu.module';
|
||||
import { Configuration } from '@reduced.to/config';
|
||||
|
||||
@Injectable()
|
||||
export class NovuService {
|
||||
constructor(@Inject(NOVU_INJECTION_TOKEN) private readonly novu: Novu, private readonly appConfigService: AppConfigService) {}
|
||||
private config: Configuration;
|
||||
constructor(@Inject(NOVU_INJECTION_TOKEN) private readonly novu: Novu, private readonly appConfigService: AppConfigService) {
|
||||
this.config = this.appConfigService.getConfig();
|
||||
}
|
||||
|
||||
async sendVerificationEmail(user: UserContext) {
|
||||
const domain =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? `https://${this.config.front.domain}`
|
||||
: `http://${this.config.front.domain}:${this.config.general.frontendPort}`;
|
||||
const verificationUrl = `${this.appConfigService.getConfig().front.domain}/register/verify/${user.verificationToken}`;
|
||||
|
||||
await this.novu.trigger('new-user', {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { AppConfigModule } from '../config/config.module';
|
||||
import { AppConfigModule } from '@reduced.to/config';
|
||||
import { AppCacheModule } from '../cache/cache.module';
|
||||
import { ShortenerService } from './shortener.service';
|
||||
import { ShortenerController } from './shortener.controller';
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { ShortenerService } from './shortener.service';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppCacheModule } from '../cache/cache.module';
|
||||
import { AppCacheService } from '../cache/cache.service';
|
||||
import { AppConfigModule } from '../config/config.module';
|
||||
import { AppConfigModule } from '@reduced.to/config';
|
||||
import { PrismaService } from '@reduced.to/prisma';
|
||||
import { ShortenerDto } from './dto';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { AppCacheService } from '../cache/cache.service';
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { AppConfigService } from '../config/config.service';
|
||||
import { AppConfigService } from '@reduced.to/config';
|
||||
import { PrismaService } from '@reduced.to/prisma';
|
||||
import { ShortenerDto } from './dto';
|
||||
import { UserContext } from '../auth/interfaces/user-context';
|
||||
|
@ -5,7 +5,7 @@ import { UsersController } from './users.controller';
|
||||
import { IFindAllOptions, UsersService } from './users.service';
|
||||
import { User } from '@reduced.to/prisma';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt.guard';
|
||||
import { AppConfigModule } from '../config/config.module';
|
||||
import { AppConfigModule } from '@reduced.to/config';
|
||||
import { RolesGuard } from '../auth/guards/roles.guard';
|
||||
import { IPaginationResult } from '../shared/utils';
|
||||
import { SortOrder } from '../shared/enums/sort-order.enum';
|
||||
|
@ -1,2 +0,0 @@
|
||||
DOMAIN=localhost
|
||||
API_DOMAIN=http://backend:3000 # Use this for internal (Server sided) API calls
|
@ -2,16 +2,15 @@
|
||||
# Dependencies Stage
|
||||
# --------------------------------------------
|
||||
FROM node:19.2-alpine3.15 as dependencies
|
||||
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN apk add --update python3 make g++\
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
RUN npm ci
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# Build Stage
|
||||
# --------------------------------------------
|
||||
@ -31,7 +30,6 @@ COPY --from=dependencies /app/node_modules ./node_modules
|
||||
# Run prisma generate & build the bundle in production mode
|
||||
RUN npx nx build frontend --prod --skip-nx-cache
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# Production Stage
|
||||
# --------------------------------------------
|
||||
|
@ -23,21 +23,28 @@ export const handleShortener = async (store: Store) => {
|
||||
|
||||
store.loading = true;
|
||||
|
||||
const response = await getShortenUrl(urlInput, ttl);
|
||||
try {
|
||||
const response = await getShortenUrl(urlInput, ttl);
|
||||
|
||||
store.loading = false;
|
||||
store.showResult = true;
|
||||
store.showResult = true;
|
||||
|
||||
if (!response.newUrl) {
|
||||
store.urlError = 'Invalid url...';
|
||||
return;
|
||||
if (!response.newUrl) {
|
||||
store.urlError = 'Invalid url...';
|
||||
return;
|
||||
}
|
||||
|
||||
const newUrl = response.newUrl;
|
||||
|
||||
store.inputValue = '';
|
||||
store.reducedUrl = window.location.href.split('#')[0] + newUrl;
|
||||
|
||||
copyToClipboard(store.reducedUrl);
|
||||
confettiAnimate();
|
||||
} catch (error) {
|
||||
store.urlError = 'An error occurred while shortening the URL. Please try again.';
|
||||
console.error('Error:', error);
|
||||
} finally {
|
||||
store.inputValue = '';
|
||||
store.loading = false;
|
||||
}
|
||||
|
||||
const newUrl = response.newUrl;
|
||||
|
||||
store.inputValue = '';
|
||||
store.reducedUrl = window.location.href.split('#')[0] + newUrl;
|
||||
|
||||
copyToClipboard(store.reducedUrl);
|
||||
confettiAnimate();
|
||||
};
|
||||
|
@ -27,7 +27,7 @@ const distDir = join(fileURLToPath(import.meta.url), '..', '..', 'client');
|
||||
const buildDir = join(distDir, 'build');
|
||||
|
||||
// Allow for dynamic port
|
||||
const PORT = process.env.PORT ?? 5000;
|
||||
const PORT = process.env.FRONTEND_APP_PORT ?? 5000;
|
||||
|
||||
// Create the Qwik City Node middleware
|
||||
const { router, notFound } = createQwikCity({
|
||||
|
@ -20,7 +20,7 @@ services:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- redis-server --requirepass "$${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}"
|
||||
env_file: backend.env
|
||||
env_file: .env
|
||||
ports:
|
||||
- 6379:6379
|
||||
networks:
|
||||
@ -30,7 +30,7 @@ services:
|
||||
image: ghcr.io/origranot/reduced.to/backend:master
|
||||
container_name: backend
|
||||
restart: always
|
||||
env_file: backend.env
|
||||
env_file: .env
|
||||
ports:
|
||||
- 3000:3000
|
||||
networks:
|
||||
@ -43,7 +43,7 @@ services:
|
||||
image: ghcr.io/origranot/reduced.to/frontend:master
|
||||
container_name: frontend
|
||||
restart: always
|
||||
env_file: frontend.env
|
||||
env_file: .env
|
||||
ports:
|
||||
- 5000:5000
|
||||
|
||||
|
@ -22,7 +22,7 @@ services:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- redis-server --requirepass "$${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}"
|
||||
env_file: ../../apps/backend/.env
|
||||
env_file: ../../.env
|
||||
ports:
|
||||
- '6379:6379'
|
||||
|
||||
@ -31,27 +31,20 @@ services:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: apps/frontend/Dockerfile
|
||||
args:
|
||||
- DOMAIN=${DOMAIN}
|
||||
- API_DOMAIN=${API_DOMAIN}
|
||||
- CLIENTSIDE_API_DOMAIN=${CLIENTSIDE_API_DOMAIN}
|
||||
restart: always
|
||||
ports:
|
||||
- '5000:5000'
|
||||
env_file: ../../apps/frontend/.env
|
||||
env_file: ../../.env
|
||||
|
||||
backend:
|
||||
container_name: backend
|
||||
platform: linux/amd64
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: apps/backend/Dockerfile
|
||||
restart: always
|
||||
volumes:
|
||||
- ../../apps/backend:/app/apps/backend/
|
||||
ports:
|
||||
- '3000:3000'
|
||||
env_file: ../../apps/backend/.env
|
||||
env_file: ../../.env
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
|
18
libs/config/.eslintrc.json
Normal file
18
libs/config/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
7
libs/config/README.md
Normal file
7
libs/config/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# config
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test config` to execute the unit tests via [Jest](https://jestjs.io).
|
11
libs/config/jest.config.ts
Normal file
11
libs/config/jest.config.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'config',
|
||||
preset: '../../jest.preset.js',
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageDirectory: '../../coverage/libs/config',
|
||||
};
|
40
libs/config/project.json
Normal file
40
libs/config/project.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "config",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/config/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/config",
|
||||
"tsConfig": "libs/config/tsconfig.lib.json",
|
||||
"packageJson": "libs/config/package.json",
|
||||
"main": "libs/config/src/index.ts"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["libs/config/**/*.ts"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/config/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"ci": true,
|
||||
"codeCoverage": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
3
libs/config/src/index.ts
Normal file
3
libs/config/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './lib/config.module';
|
||||
export * from './lib/config.service';
|
||||
export * from './lib/config.factory';
|
@ -4,8 +4,9 @@ import { LOG_LEVEL } from '@origranot/ts-logger';
|
||||
export const configFactory: ConfigFactory<{ config: Configuration }> = () => {
|
||||
return {
|
||||
config: {
|
||||
app: {
|
||||
port: +process.env.APP_PORT || 3000,
|
||||
general: {
|
||||
backendPort: +process.env.BACKEND_APP_PORT || 3000,
|
||||
frontendPort: +process.env.FRONTEND_APP_PORT || 5173,
|
||||
env: process.env.NODE_ENV || 'development',
|
||||
},
|
||||
logger: {
|
||||
@ -14,7 +15,9 @@ export const configFactory: ConfigFactory<{ config: Configuration }> = () => {
|
||||
},
|
||||
},
|
||||
front: {
|
||||
domain: process.env.FRONT_DOMAIN || 'http://localhost:5173',
|
||||
domain: process.env.DOMAIN || 'localhost',
|
||||
clientSideApiDomain: process.env.CLIENTSIDE_API_DOMAIN || 'http://localhost:3000',
|
||||
apiDomain: process.env.API_DOMAIN || 'http://localhost:3000',
|
||||
},
|
||||
rateLimit: {
|
||||
ttl: +process.env.RATE_LIMIT_TTL || 60,
|
||||
@ -38,8 +41,9 @@ export const configFactory: ConfigFactory<{ config: Configuration }> = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export interface AppConfig {
|
||||
port: number;
|
||||
export interface GeneralConfig {
|
||||
backendPort: number;
|
||||
frontendPort: number;
|
||||
env: string;
|
||||
}
|
||||
|
||||
@ -51,6 +55,8 @@ export interface LoggerConfig {
|
||||
|
||||
export interface FrontConfig {
|
||||
domain: string;
|
||||
clientSideApiDomain: string;
|
||||
apiDomain: string;
|
||||
}
|
||||
|
||||
export interface RateLimitConfig {
|
||||
@ -76,7 +82,7 @@ export interface NovuConfig {
|
||||
}
|
||||
|
||||
export interface Configuration {
|
||||
app: AppConfig;
|
||||
general: GeneralConfig;
|
||||
logger: LoggerConfig;
|
||||
front: FrontConfig;
|
||||
rateLimit: RateLimitConfig;
|
36
libs/config/src/lib/schema.ts
Normal file
36
libs/config/src/lib/schema.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { z } from 'zod';
|
||||
export default z.object({
|
||||
// General
|
||||
BACKEND_APP_PORT: z.string(),
|
||||
FRONTEND_APP_PORT: z.string(),
|
||||
NODE_ENV: z.string().default('development'),
|
||||
|
||||
// Rate limit config
|
||||
RATE_LIMIT_TTL: z.string(),
|
||||
RATE_LIMIT_COUNT: z.string(),
|
||||
|
||||
// Logger
|
||||
LOGGER_CONSOLE_THRESHOLD: z.string().default('INFO'),
|
||||
|
||||
// Frontend
|
||||
DOMAIN: z.string(),
|
||||
CLIENTSIDE_API_DOMAIN: z.string(),
|
||||
API_DOMAIN: z.string(),
|
||||
|
||||
// Database
|
||||
DATABASE_URL: z.string(),
|
||||
|
||||
// Redis
|
||||
REDIS_ENABLE: z.boolean().default(false),
|
||||
REDIS_HOST: z.string(),
|
||||
REDIS_PORT: z.string(),
|
||||
REDIS_PASSWORD: z.string(),
|
||||
REDIS_TTL: z.string(),
|
||||
|
||||
// Auth
|
||||
JWT_ACCESS_SECRET: z.string(),
|
||||
JWT_REFRESH_SECRET: z.string(),
|
||||
|
||||
// Novu
|
||||
NOVU_API_KEY: z.string().optional(),
|
||||
});
|
16
libs/config/tsconfig.json
Normal file
16
libs/config/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
11
libs/config/tsconfig.lib.json
Normal file
11
libs/config/tsconfig.lib.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
9
libs/config/tsconfig.spec.json
Normal file
9
libs/config/tsconfig.spec.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
|
||||
}
|
@ -13,18 +13,14 @@
|
||||
"migrate-dev": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "npx prisma migrate dev --schema=src/schema.prisma --name={args.name}",
|
||||
"cwd": "libs/prisma",
|
||||
"envFile": "apps/backend/.env",
|
||||
"command": "npx prisma migrate dev --schema=libs/prisma/src/schema.prisma --name={args.name}",
|
||||
"parallel": true
|
||||
}
|
||||
},
|
||||
"migrate-deploy": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "npx prisma migrate deploy --schema=src/schema.prisma",
|
||||
"cwd": "libs/prisma",
|
||||
"envFile": "apps/backend/.env",
|
||||
"command": "npx prisma migrate deploy --schema=libs/prisma/src/schema.prisma",
|
||||
"parallel": true
|
||||
}
|
||||
},
|
||||
|
8924
package-lock.json
generated
8924
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@ -14,15 +14,15 @@
|
||||
"@docusaurus/module-type-aliases": "^2.4.1",
|
||||
"@nestjs/schematics": "^10.0.1",
|
||||
"@nestjs/testing": "^10.0.2",
|
||||
"@nx/eslint-plugin": "16.8.0",
|
||||
"@nx/eslint-plugin": "16.8.1",
|
||||
"@nx/jest": "16.8.1",
|
||||
"@nx/js": "16.8.1",
|
||||
"@nx/linter": "16.8.0",
|
||||
"@nx/nest": "^16.8.1",
|
||||
"@nx/linter": "16.8.1",
|
||||
"@nx/nest": "16.8.1",
|
||||
"@nx/node": "16.8.1",
|
||||
"@nx/vite": "16.8.0",
|
||||
"@nx/vite": "16.8.1",
|
||||
"@nx/webpack": "16.8.1",
|
||||
"@nx/workspace": "16.8.0",
|
||||
"@nx/workspace": "16.8.1",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@tsconfig/docusaurus": "^2.0.0",
|
||||
"@types/bcryptjs": "^2.4.3",
|
||||
@ -46,8 +46,8 @@
|
||||
"jest": "^29.4.1",
|
||||
"jest-environment-node": "^29.4.1",
|
||||
"node-fetch": "~3.3.0",
|
||||
"nx": "16.8.0",
|
||||
"nx-cloud": "latest",
|
||||
"nx": "16.8.1",
|
||||
"nx-cloud": "16.4.0",
|
||||
"postcss": "^8.4.29",
|
||||
"prettier": "^2.6.2",
|
||||
"prisma": "5.2.0",
|
||||
@ -86,6 +86,7 @@
|
||||
"clsx": "^2.0.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"memphis-dev": "^1.1.4",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
@ -94,6 +95,7 @@
|
||||
"react-dom": "^17.0.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.0",
|
||||
"tslib": "^2.3.0"
|
||||
"tslib": "^2.3.0",
|
||||
"zod": "^3.22.2"
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,9 @@
|
||||
"skipDefaultLibCheck": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@reduced.to/prisma": ["libs/prisma/src/index.ts"]
|
||||
"@reduced.to/config": ["libs/config/src/index.ts"],
|
||||
"@reduced.to/prisma": ["libs/prisma/src/index.ts"],
|
||||
"@reduced.to/queue-manager": ["libs/queue-manager/src/index.ts"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "tmp"]
|
||||
|
Reference in New Issue
Block a user