npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

broly-software-core

v1.2.3

Published

Library infra by Broly software

Readme

🗺️ Índice

Broly Infra

NestJS is a utility and package library designed to simplify and standardize the development of microservices with a hexagonal or n-tier architecture, using NestJS and TypeScript. Package management is handled with pnpm, ensuring rapid installation and efficient use of disk space.

📄 Requirements

  • Node.js >= 22.14.0
  • pnpm >= 10.x

🚀 Installation

# Install dependencies
pnpm install

# Development
pnpm run start:dev

# Production
pnpm run start:prod

# Build
pnpm run build

🌎 Publication

# Increase a version path (1.0.0) -> (1.0.1)
$ pnpm version patch

# Increase a minor version (1.0.0) -> (1.1.0)
$ pnpm version minor

# Increase a major version (1.0.0) -> (2.0.0)
$ pnpm version major

# Increase a specific version (1.0.0) -> (3.1.1)
$ pnpm version <version>

# Publish the package
$ pnpm publish

📖 Project Structure

The repository is organized into two main directories:

  • libs/: Contains reusable modules and packages for various functionalities.
  • src/: Includes the source code for how to use these libraries and how to test them.
[libs]/
├── [adapter]/           # [Adapters for external transport services, such as NATS, Kafka, SMTP, for microservices.]
├── [cdecorator]/        # [Provides custom decorators for NestJS.]
├── [common-cache]/      # [Functions for cache management, such as REDIS or local.]
├── [common-database]/   # [This module facilitates interaction with the database]
├── [common-encrypted]/  # [Utilities for data encryption and decryption.]
├── [common-http]/       # [Centralizes utilities for handling HTTP requests and responses]
├── [common-keyvault]/   # [Loads and injects secrets from a remote key vault provider (e.g. Infisical) into process.env at bootstrap time.]
├── [common-logger]/     # [Provides a unified logging system, crucial for application monitoring and debugging.]
├── [common-response]/   # [Standardized response structures for APIs, Events, such as success and error.]
├── [common-search]/     # [Advanced search logic, with respect to databases.]
├── [server-started]/    # [Centralizes and standardizes the NestJS application bootstrap (HTTP and NATS microservice).]
└── index.ts             # [Main entry point]

Usage/Examples

adapter

Adapters for external transport services, such as NATS, Kafka, SMTP, for microservices.

Use:

The way to inject the module:

natsTransport.module.ts

import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { AdapterModule, Adapter } from 'caserita-infra/packages/adapter';
import { NATS_MS_SERVICE_INJECT } from '@app/utils/constants.util'

@Module({
  imports: [
    AdapterModule,
    ClientsModule.registerAsync([
      {
        name: NATS_MS_SERVICE_INJECT,
        useFactory: (adapter: Adapter) => {
          const natsConfig = adapter.config();
          return natsConfig;
        },
        inject: [Adapter],
      },
    ]),
  ],
  exports: [ClientsModule],
})
export class NatsTransportModule {}

How to use the module on the client:

caseritaTaxidentityvalidationMsEvent.client.ts

import { Inject, Injectable } from "@nestjs/common";
import { ConfigService } from '@nestjs/config';
import { ClientProxy } from '@nestjs/microservices';
import { firstValueFrom } from 'rxjs';
import { NATS_MS_SERVICE_INJECT } from '@app/utils/constants.util';
import { CaseritaTaxidentityvalidationMsService } from "@domain/caseritaTaxidentityvalidationMs.service";
import { CaseritaTaxidentityvalidationMsFindCompanyByRucRequest } from "@domain/interfaces/caseritaTaxidentityvalidationMsFindCompanyByRucRequest.interface";
import { CaseritaTaxidentityvalidationMsFindCompanyByRucResponse } from "@domain/interfaces/caseritaTaxidentityvalidationMsFindCompanyByRucResponse.interface";

@Injectable()
export class CaseritaTaxidentityvalidationMsEventClient implements CaseritaTaxidentityvalidationMsService {
  private caseritaTaxIdentityValidationMsFindCompayByRuc: string;
  private caseritaTaxIdentityValidationMsFindLegalRepresentativeByRuc: string;
  private caseritaTaxIdentityValidationMsFindPersonByDni: string;

  constructor(
    private readonly configService: ConfigService,
    @Inject(NATS_MS_SERVICE_INJECT) private readonly client: ClientProxy
  ) {
    this.caseritaTaxIdentityValidationMsFindCompayByRuc = this.configService.get<string>('CASERITA_TAXIDENTITYVALIDATION_MS_FIND_COMPANY_BY_RUC');
    this.caseritaTaxIdentityValidationMsFindLegalRepresentativeByRuc = this.configService.get<string>('CASERITA_TAXIDENTITYVALIDATION_MS_FIND_LEGAL_REPRESENTATIVE_BY_RUC');
    this.caseritaTaxIdentityValidationMsFindPersonByDni = this.configService.get<string>('CASERITA_TAXIDENTITYVALIDATION_MS_FIND_PERSON_BY_DNI');
  }

  findCompanyByRuc(input: CaseritaTaxidentityvalidationMsFindCompanyByRucRequest): Promise<CaseritaTaxidentityvalidationMsFindCompanyByRucResponse> {
    const { ruc } = input;
    return firstValueFrom(this.client.send({ cmd: this.caseritaTaxIdentityValidationMsFindCompayByRuc }, { ruc }));
  }
}

Environments:

This package uses the following variables:

.env  .env.development.local

NATS_SERVERS="nats://localhost:4222"

cdecorator

Provides custom decorators for NestJS.

Use:

How to use the module on the controller:

store.controller.ts

import { Controller,  Post } from '@nestjs/common';
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import { ValidateBody } from 'caserita-infra/packages/cdecorator';
import { CreateCommandImpl } from '@app/commands/impl/create-command.impl';
import { CreateInputValidator } from '@infra/validators/create.input.validator';
import { CreateStoreRequest } from '@domain/interfaces/createStoreRequest.interface';

@Controller('stores')
export class StoreController {
  constructor(
    private readonly commandBus: CommandBus,
    private readonly queryBus: QueryBus,
  ) {}

  @Post('/create')
  create(@ValidateBody(CreateInputValidator) input: CreateStoreRequest) {
    return this.commandBus.execute(new CreateCommandImpl(input));
  }
}

common-cache

Functions for cache management, such as REDIS or local.

Use:

The way to inject the module:

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonCacheModule } from '@caserita/common-cache';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true, cache: true }),
    CommonCacheModule,
  ],
  controllers: [AppController, AppHandler],
  providers: [AppService, AppRepository],
})
export class AppModule {}

How to use the module on the service:

app.service.ts

import { ConfigService } from '@nestjs/config';
import { Injectable } from '@nestjs/common';
import { RedisCacheService } from '@caserita/common-cache';
import { AppRepository } from './app.repository';

@Injectable()
export class AppService {
  private baseUrl: string;
  constructor(
    private readonly configService: ConfigService,
    private readonly cacheService: RedisCacheService,
    private readonly appRepository: AppRepository,
  ) {
    this.baseUrl = this.configService.get<string>('BASE_URL_DATTEBAYO');
  }

  async getRedisCloud() {
    return this.cacheService.get('HOLA:1236');
  }

  async setRedisCloud() {
    await this.cacheService.set('HOLA:1239', { A: '1234', B: 'xyz' }, 300); //ttl 300 equivale a 5 minutos
  }
}

Environments:

This package uses the following variables:

.env  .env.development.local

REDIS_CLOUD_HOST=example.redis-cloud.com
REDIS_CLOUD_PORT=18472
REDIS_CLOUD_PASSWORD=vHqWgOtqqZXoA18km0Y76XiI4iNnr8DZ
REDIS_CLOUD_TTL= 300
REDIS_NUMBER_DB=

common-database

This module facilitates interaction with the database

Use:

The way to inject the module:

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import {
  CommonDatabaseModule,
  DatabaseConnectionType,
  DatabaseEnumType,
} from '@caserita/common-database';
// import { CommonCacheModule } from '@caserita/common-cache';
import { CommonEncryptedModule, EncryptedProviderType, ValueTransformer, HashTransformer } from '@caserita/common-encrypted';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { EntityModule } from './entity/entity.module';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';
import { AppEntity } from './entity/app.entity';
import { AppPostgresEntity } from './entity/appPostgres.entity';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true, cache: true }),
    CommonDatabaseModule.register([
      {
        name: DatabaseConnectionType.MONGODB_CONNECTION,
        type: DatabaseEnumType.MONGODB,
        entities: [AppEntity],
      },
      {
        name: DatabaseConnectionType.POSTGRES_CONNECTION,
        type: DatabaseEnumType.POSTGES,
        entities: [AppPostgresEntity],

        // If you need to encrypt data in SQL
        imports: [CommonEncryptedModule.register(EncryptedProviderType.DATABASE)],
        inject: [ValueTransformer, HashTransformer],
        columnsTransformers: ['fieldencrypt', 'fieldencrypt_index', 'fieldencrypttwo'],
      },
    ]),
    EntityModule,
  ],
  controllers: [AppController, AppHandler],
  providers: [AppService, AppRepository],
})
export class AppModule {}

How to use the module on the entity:

entity.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DatabaseConnectionType } from '@caserita/common-database';
import { AppEntity } from './app.entity';
import { AppPostgresEntity } from './appPostgres.entity';

// The "forFeature" already creates the providers (the repositories)
const mongoRepositoryModule = TypeOrmModule.forFeature([AppEntity], DatabaseConnectionType.MONGODB_CONNECTION);
const postgresRepositoryModule = TypeOrmModule.forFeature([AppPostgresEntity], DatabaseConnectionType.POSTGRES_CONNECTION);

@Module({
  imports: [mongoRepositoryModule, postgresRepositoryModule],
  // This is where the change lies: you must export the entity classes that act as
  // tokens for the repositories. This causes TypeOrmModule to expose the repositories
  // created in the "imports" process.
  exports: [mongoRepositoryModule, postgresRepositoryModule],
})
export class EntityModule {}

Environments:

This package uses the following variables:

.env  .env.development.local

# MONGO DATABASE
DB_USER_MONGO=example
DB_KEY_MONGO=7247uriu2482rw247
DB_HOST_MONGO=example.mongodb.net
DB_CONTAINER_NAME_MONGO=cstainfradbdev
DB_SYNCHRONIZE_MONGO=true

# POSTGRES DATABASE
DB_HOST_POSTGRES=example.supabase.com
DB_PORT_POSTGRES=6543
DB_USERNAME_POSTGRES=postgres.qsyvlxmwyodpyevujbgx
DB_PASSWORD_POSTGRES=7247uriu2482rw247
DB_CONTAINER_NAME_POSTGRES=cstainfradbdev
DB_SYNCHRONIZE_POSTGRES=true

# ENCRYPTION DATBASE SQL
ENCRYPT_DATABASE_SECRET_KEY=xDkjHdp132nRLBjUOcvHGAJzb7dGmt

common-encrypted

Utilities for data encryption and decryption.

Use:

The way to inject the module:

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonEncryptedModule, EncryptedProviderType } from '@caserita/common-encrypted';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true, cache: true }),
    CommonEncryptedModule.register(EncryptedProviderType.APP),
  ],
  controllers: [AppController, AppHandler],
  providers: [AppService, AppRepository],
})
export class AppModule {}

How to use the module on the service:

app.service.ts

import { ConfigService } from '@nestjs/config';
import { Injectable } from '@nestjs/common';
import { CipherEngine } from '@caserita/common-encrypted';
import { AppRepository } from './app.repository';

@Injectable()
export class AppService {
  private baseUrl: string;
  constructor(
    private readonly configService: ConfigService,
    private readonly cipherEngine: CipherEngine,
    private readonly appRepository: AppRepository,
  ) {
    this.baseUrl = this.configService.get<string>('BASE_URL_DATTEBAYO');
  }

  async encryption(entry: string) {
    return this.cipherEngine.encrypt(entry);
  }

  async decryptyion(entry: string) {
    return this.cipherEngine.decrypt(entry);
  }
}

Environments:

This package uses the following variables:

.env  .env.development.local

ENCRYPT_SECRET_KEY=WwMIK54FypnmSR1JPSCdcwxcwCl2cA
ENCRYPT_DATABASE_SECRET_KEY=xDkjHdp132nRLBjUOcvHGAJzb7dGmt

common-http

Centralizes utilities for handling HTTP requests and responses

Use:

The way to inject the module:

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonHttpModule } from '@caserita/common-http';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true, cache: true }),
    CommonHttpModule,
  ],
  controllers: [AppController, AppHandler],
  providers: [AppService, AppRepository],
})
export class AppModule {}

How to use the module on the client:

app.service.ts

import { ConfigService } from '@nestjs/config';
import { HttpException, Injectable } from '@nestjs/common';
import { catchError, firstValueFrom } from 'rxjs';
import { AxiosError } from 'axios';
import { HttpClient } from '@caserita/common-http';

@Injectable()
export class AppService {
  private baseUrl: string;
  constructor(
    private readonly httpClient: HttpClient,
    private readonly configService: ConfigService,
  ) {
    this.baseUrl = this.configService.get<string>('BASE_URL_DATTEBAYO');
  }

  async proxy() {
    return firstValueFrom(
      this.httpClient.get(`${this.baseUrl}/characters/1344`).pipe(
        catchError((error: AxiosError) => {
          throw new HttpException(
            {
              errorCode: error.code,
              message: error.response.data,
              stack: error.stack,
            },
            error.status,
          );
        }),
      ),
    );
  }
}

common-logger

Provides a unified logging system, crucial for application monitoring and debugging.

Use:

The way to inject the module:

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonLoggerModule } from '@caserita/common-logger';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true, cache: true }),
    CommonLoggerModule,
  ],
  controllers: [AppController, AppHandler],
  providers: [AppService, AppRepository],
})
export class AppModule {}

How to use the module on the use-case:

create-command.handler.ts

import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { Logger } from '@nestjs/common';
import { CreateCommandImpl } from '@app/commands/impl/create-command.impl';
import { ExpedientService } from '@domain/expedient.service';
import { CaseritaBusinessAccountMsService } from '@domain/caseritaBusinessAccountMs.service';
import { Expedient } from '@domain/entities/expedient.entity';
import { ExpedientTracing } from '@domain/entities/expedientTracing.entity';
import { DatosEmpresa } from '@domain/entities/datosEmpresa';
import { DatosRepresentanteLegal } from '@domain/entities/datosRepresentanteLegal';
import { Archivo } from '@domain/entities/archivo.entity';
import { EstadoExpediente } from '@domain/emun/estadoExpediente.enum';
import { TipoDocumento } from '@domain/emun/tipoDocumento.enum';

@CommandHandler(CreateCommandImpl)
export class CreateCommandHandler implements ICommandHandler<CreateCommandImpl> {
  private readonly logger = new Logger('CreateCommandHandler');

  constructor(
    private readonly service: ExpedientService,
    private readonly caseritaBusinessAccountMs: CaseritaBusinessAccountMsService,
  ) {}

  async execute({ command }: CreateCommandImpl): Promise<void> {
    const expedient = new Expedient();
    const expedientTracing = new ExpedientTracing();
    const datosEmpresa = new DatosEmpresa();
    const datosRepresentanteLegal = new DatosRepresentanteLegal();
    const archivo = new Archivo();
    const archivos: Archivo[] = [];

    expedient.estado = EstadoExpediente.CREADO;
    expedient.codigoExpediente = this.generateCodeExpediente(
      command.datosEmpresa.numeroDocumento,
      command.datosRepresentanteLegal.numeroDocumento,
    );

    datosEmpresa.tipoDocumento = TipoDocumento.RUC;
    datosEmpresa.numeroDocumento = command.datosEmpresa.numeroDocumento;

    datosRepresentanteLegal.tipoDocumento = TipoDocumento.DNI;
    datosRepresentanteLegal.numeroDocumento = command.datosRepresentanteLegal.numeroDocumento;
    datosRepresentanteLegal.fechaNacimiento = command.datosRepresentanteLegal.fechaNacimiento;
    datosRepresentanteLegal.correoElectronico = command.datosRepresentanteLegal.correoElectronico;
    datosRepresentanteLegal.direccion = command.datosRepresentanteLegal.direccion;
    datosRepresentanteLegal.telefono = command.datosRepresentanteLegal.telefono;

    for (const a of command.archivos) {
      archivo.nombreArchivo = a.nombreArchivo;
      archivo.url = a.url;
      archivo.tipoArchivo = a.tipoArchivo;
      archivo.fechaSubida = a.fechaSubida;

      archivos.push(archivo);
    }

    expedient.datosEmpresa = datosEmpresa;
    expedient.datosRepresentanteLegal = datosRepresentanteLegal;
    expedient.archivos = archivos;

    const result = await this.service.create(expedient);
    this.logger.log('[CreateCommandImpl - CREATE EXPEDIENTE]: Se creo el expediente con éxito');

    // Envio mensaje service bus para proceso asincrono de creacion de cuenta negocio
    this.logger.log('[CreateCommandImpl - SEND CREATE ASYNC BUSINESS ACCOUNT]');
    this.caseritaBusinessAccountMs.create({ idExpediente: expedient.idExpediente, idEmpresa: expedient.codigoExpediente });

    expedientTracing.codigoExpediente = result.codigoExpediente;
    expedientTracing.estado = EstadoExpediente.CREADO;
    expedientTracing.ruc = datosEmpresa.numeroDocumento;
    expedientTracing.dni = datosRepresentanteLegal.numeroDocumento;
    expedientTracing.fechaCreacion = result.fechaCreacion.toISOString();

    await this.service.createTracing(expedientTracing);
    this.logger.log(
      '[CreateCommandImpl - CREATE EXPEDIENTE TRACING]: Se creo el trazado del expediente con éxito',
    );
  }

  private generateCodeExpediente(rucNumber: string, dniNumber: string) {
    return `${TipoDocumento.RUC}${rucNumber}${TipoDocumento.DNI}${dniNumber}`;
  }
}

Environments:

This package uses the following variables:

.env  .env.development.local

LOGGER_LEVEL=info
LOGGER_ENABLED=true    # false
LOGGER_CLOUD=logtail   # local -> TOKEN_LOGTAIL_LOGGER is empty
TOKEN_LOGTAIL_LOGGER=82jk4y28y283yru2734728

common-response

Standardized response structures for APIs, Events, such as success and error. It exposes a global exception filter (AppErrorResponseFilter) and a success interceptor (SuccessResponseInterceptor) that wrap every controller response (and unhandled error) in a consistent envelope.

Use:

The way to inject the module and wire the global filter/interceptor:

main.ts

import { NestFactory } from '@nestjs/core';
import {
  CommonResponseModule,
  AppErrorResponseFilter,
  SuccessResponseInterceptor,
} from '@caserita/common-response';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(app.get(AppErrorResponseFilter));
  app.useGlobalInterceptors(app.get(SuccessResponseInterceptor));

  await app.listen(3000);
}
bootstrap();
app.module.ts

import { Module } from '@nestjs/common';
import { CommonResponseModule } from '@caserita/common-response';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [CommonResponseModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

ℹ️ Note: bootstrap() from @caserita/server-started already wires AppErrorResponseFilter and SuccessResponseInterceptor for you — see the server-started section below.

common-search

Advanced search logic, with respect to databases. Provides shared query-building utilities (filtering, pagination, sorting) reused across repositories/adapters.

Use:

The way to inject the module:

app.module.ts

import { Module } from '@nestjs/common';
import { CommonSearchModule } from '@caserita/common-search';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';

@Module({
  imports: [CommonSearchModule],
  controllers: [AppController],
  providers: [AppService, AppRepository],
})
export class AppModule {}

common-keyvault

Loads secrets from a remote key vault provider (currently Infisical, with Azure/AWS reserved for future support) and injects them into process.env at application startup, keeping local .env files as the source of truth for development.

Use:

The way to inject the module (registers the provider so it can be used via DI, e.g. KeyvaultEngine):

app.module.ts

import { Module } from '@nestjs/common';
import { CommonKeyvaultModule, KeyvaultProviderType } from '@caserita/common-keyvault';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    CommonKeyvaultModule.register(KeyvaultProviderType.INFISICAL),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

How to bootstrap secrets before the Nest application starts (loads secrets straight into process.env, so ConfigService can read them right after):

main.ts

import { KeyvaultBootstrap, KeyvaultProviderType } from '@caserita/common-keyvault';

async function bootstrap() {
  const NODE_ENV = process.env.NODE_ENV || 'development';

  await KeyvaultBootstrap.load(KeyvaultProviderType.INFISICAL, {
    isLocal: NODE_ENV === 'development',    // skip remote fetch in local/dev
    overrideLocal: NODE_ENV !== 'development', // remote secrets win over local .env in prod/CI
  });

  // ...continue with NestFactory.create(AppModule)
}
bootstrap();

ℹ️ Note: bootstrap() from @caserita/server-started already calls KeyvaultBootstrap.load(...) for you — see the server-started section below.

Environments:

This package uses the following variables:

.env  .env.development.local

KEYVAULT_INFISICAL_CLIENT_ID=******
KEYVAULT_INFISICAL_CLIENT_SECRET=******
KEYVAULT_INFISICAL_PROJECT_ID=******
KEYVAULT_INFISICAL_ENVIRONMENT=dev
KEYVAULT_INFISICAL_SITE_URL=https://us.infisical.com

server-started

Centralizes and standardizes the application bootstrap: reads APP_RUNNING_ENV to start either an HTTP server or a NATS microservice, wires the global filters/interceptors/pipes, loads secrets via common-keyvault, and prints a startup banner (via figlet) plus version/author info from your project's package.json.

Use:

Because this module lives in a library, it doesn't know the file structure of the project that installs it. For that reason, bootstrap() doesn't resolve anything on its own (AppModule, package.json, etc.) — everything is injected explicitly by the consumer project:

main.ts

import { KeyvaultBootstrap, KeyvaultProviderType } from '@caserita/common-keyvault';
import { AppLoggerService, Logger, LoggerInterceptor } from '@caserita/common-logger';
import { AppErrorResponseFilter, SuccessResponseInterceptor } from '@caserita/common-response';
import { bootstrap } from '@caserita/server-started';
import { AppModule } from './app.module';
import * as fs from 'fs';
import * as path from 'path';

const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));

bootstrap({
  AppModule,
  GlobalPrefix: 'v1', // or null to disable the global prefix
  KeyvaultBootstrap,
  KeyvaultProviderType,
  AppErrorResponseFilter,
  LoggerInterceptor,
  SuccessResponseInterceptor,
  AppLoggerService,
  Logger,
  pkg,
});

Depending on APP_RUNNING_ENV, bootstrap() will:

  • HTTP: create a regular Nest HTTP application (NestFactory.create), apply GlobalPrefix, enable CORS, register the global error filter and interceptors, and listen on PORT.
  • NATS: create a Nest microservice over NATS (NestFactory.createMicroservice) using NATS_SERVERS, and register the logger interceptor.

In both cases it also applies a global ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }), resolves the app logger, and — in development — prints the running environment, NODE_ENV, and the version/author fields taken from the pkg you passed in.

Environments:

This package uses the following variables:

.env  .env.development.local

APPLICATION_NAME=INFRA
APP_RUNNING_ENV=HTTP # NATS
PORT=8080
NATS_SERVERS="nats://localhost:4222"

📝 Environment Variables

To run this project, you will need to add the following environment variables to your .env.development.local file

.env.development.local

# APP
APPLICATION_NAME=INFRA
APP_RUNNING_ENV=HTTP # NATS
NODE_ENV=development # production
PORT=8080

# NATS
NATS_SERVERS="nats://localhost:4222"

# LOGGER
LOGGER_LEVEL=info
LOGGER_ENABLED=true
LOGGER_CLOUD=logtail
TOKEN_LOGTAIL_LOGGER=******

# DATABASE
DB_USER_MONGO=******
DB_KEY_MONGO=******
DB_HOST_MONGO=******
DB_CONTAINER_NAME_MONGO=******

# POSTGRES DATABASE
DB_HOST_POSTGRES=******
DB_PORT_POSTGRES=******
DB_USERNAME_POSTGRES=******
DB_PASSWORD_POSTGRES=******
DB_CONTAINER_NAME_POSTGRES=******
DB_SYNCHRONIZE_POSTGRES=******

# ENCRYPTION
ENCRYPT_SECRET_KEY=******
ENCRYPT_DATABASE_SECRET_KEY=******

# CACHE REDIS
REDIS_CLOUD_HOST=******
REDIS_CLOUD_PORT=******
REDIS_CLOUD_PASSWORD=******
REDIS_CLOUD_TTL= 300
REDIS_NUMBER_DB=

# KEYVAULT
KEYVAULT_INFISICAL_CLIENT_ID=******
KEYVAULT_INFISICAL_CLIENT_SECRET=******
KEYVAULT_INFISICAL_PROJECT_ID=******
KEYVAULT_INFISICAL_ENVIRONMENT=dev
KEYVAULT_INFISICAL_SITE_URL=https://us.infisical.com

# PROXIES
BASE_URL_DATTEBAYO=https://dattebayo-api.onrender.com

🛠️ Scripts Disponibles

Here are some related projects

# Desarrollo
pnpm run start:dev      # Ejecuta en modo desarrollo con watch
pnpm run start          # Ejecuta en modo normal
pnpm run start:prod     # Ejecuta en modo producción

# Build
pnpm run build          # Compila el proyecto

# Testing
pnpm run test           # Ejecuta tests unitarios
pnpm run test:watch     # Ejecuta tests en modo watch
pnpm run test:e2e       # Ejecuta tests end-to-end
pnpm run test:cov       # Ejecuta tests con coverage

# Linting y Formato
pnpm run lint           # Ejecuta ESLint
pnpm run format         # Formatea código con Prettier

🚀 Deployment

To deploy this project with docker:


FROM node:18-alpine

WORKDIR /app

# Instalar pnpm
RUN npm install -g pnpm

# Copiar archivos de dependencias
COPY package.json pnpm-lock.yaml ./

# Instalar dependencias
RUN pnpm install --frozen-lockfile

# Copiar código fuente
COPY . .

# Build
RUN pnpm run build

# Exponer puerto
EXPOSE 3000

# Comando de inicio
CMD ["pnpm", "run", "start:prod"]

docker-compose:


version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:password@db:5432/caserita
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: caserita
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

😁 Authors