{"_id":"@darkhorseone/primeforge-common","_rev":"2-ee375fc56c379dfc1be9e59adf7c0b57","name":"@darkhorseone/primeforge-common","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@darkhorseone/primeforge-common","version":"1.0.0","keywords":["nestjs","shared","common","utilities"],"author":{"name":"DarkhorseOne Limited"},"license":"MIT","_id":"@darkhorseone/primeforge-common@1.0.0","maintainers":[{"name":"nick-ma","email":"honeyday.mj@gmail.com"}],"dist":{"shasum":"913b2b1390b6ae5b8a3ccd4aa766bbffcffd1e3c","tarball":"https://registry.npmjs.org/@darkhorseone/primeforge-common/-/primeforge-common-1.0.0.tgz","fileCount":108,"integrity":"sha512-4c3VlaNhOzwLfnon5JmeQsHW2b4vCBPf0DdsKyGLC/9Q+u9QBZCFxTn4AxrKFLoMf+ggrdNvFVfgaZVXSWBtFg==","signatures":[{"sig":"MEYCIQDsyFoMHzeNrwSFwxQ19GeZnfnm+fBmLad0k3dUuBQuhwIhAK4tvElO61YLYG6o0Rj2NGFwWq1Gt3YufJQC/+/KJEzZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":199064},"jest":{"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"testEnvironment":"node","coverageDirectory":"../coverage","collectCoverageFrom":["**/*.(t|j)s"],"moduleFileExtensions":["js","json","ts"]},"main":"dist/index.js","type":"commonjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","require":"./dist/index.js"}},"gitHead":"89cd2e6fedcaa8b14ae42f8b3fc05fa89e5cf294","scripts":{"lint":"eslint 'src/**/*.ts'","test":"jest","build":"tsc","lint:fix":"eslint 'src/**/*.ts' --fix","test:cov":"jest --coverage","test:watch":"jest --watch","build:watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"nick-ma","email":"honeyday.mj@gmail.com"},"_npmVersion":"11.3.0","description":"Shared services and utilities for NestJS applications in PrimeForge","directories":{},"_nodeVersion":"20.18.0","dependencies":{"jose":"^5.2.0","pino":"^10.0.0","argon2":"^0.40.1","@nestjs/jwt":"^11.0.1","@sendgrid/mail":"^8.1.0","@fastify/static":"^8.2.0","@nestjs/swagger":"^11.2.0","class-validator":"^0.14.2","@nestjs/terminus":"^11.0.0","class-transformer":"^0.5.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^9.18.0","ts-jest":"^29.2.5","typescript":"^5.8.3","@types/jest":"^29.5.14","@types/node":"^22.15.34","typescript-eslint":"^8.20.0"},"peerDependencies":{"rxjs":"^7.0.0","@nestjs/core":"^11.0.0","@nestjs/common":"^11.0.0","@nestjs/config":"^4.0.0","reflect-metadata":"^0.2.0"},"_npmOperationalInternal":{"tmp":"tmp/primeforge-common_1.0.0_1760712682073_0.9145981503009113","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@darkhorseone/primeforge-common","version":"1.0.1","description":"Shared services and utilities for NestJS applications in PrimeForge","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","require":"./dist/index.js","import":"./dist/index.js","default":"./dist/index.js"}},"typesVersions":{"*":{"*":["dist/index.d.ts"]}},"scripts":{"build":"tsc","build:watch":"tsc --watch","test":"jest","test:watch":"jest --watch","test:cov":"jest --coverage","lint":"eslint 'src/**/*.ts'","lint:fix":"eslint 'src/**/*.ts' --fix","prepublishOnly":"npm run build"},"keywords":["nestjs","shared","common","utilities"],"author":{"name":"DarkhorseOne Limited"},"license":"MIT","type":"commonjs","publishConfig":{"access":"public"},"dependencies":{"@fastify/static":"^8.2.0","@nestjs/terminus":"^11.0.0","@nestjs/swagger":"^11.2.0","@nestjs/jwt":"^11.0.1","@sendgrid/mail":"^8.1.0","pino":"^10.0.0","jose":"^5.2.0","argon2":"^0.40.1","class-validator":"^0.14.2","class-transformer":"^0.5.1"},"devDependencies":{"@types/node":"^22.15.34","typescript":"^5.8.3","@types/jest":"^29.5.14","jest":"^29.7.0","ts-jest":"^29.2.5","eslint":"^9.18.0","typescript-eslint":"^8.20.0"},"peerDependencies":{"@nestjs/common":"^11.0.0","@nestjs/config":"^4.0.0","@nestjs/core":"^11.0.0","reflect-metadata":"^0.2.0","rxjs":"^7.0.0"},"jest":{"moduleFileExtensions":["js","json","ts"],"rootDir":"src","testRegex":".*\\.spec\\.ts$","transform":{"^.+\\.(t|j)s$":"ts-jest"},"collectCoverageFrom":["**/*.(t|j)s"],"coverageDirectory":"../coverage","testEnvironment":"node"},"_id":"@darkhorseone/primeforge-common@1.0.1","gitHead":"89cd2e6fedcaa8b14ae42f8b3fc05fa89e5cf294","_nodeVersion":"20.18.0","_npmVersion":"11.3.0","dist":{"integrity":"sha512-MyYh07Gd1X0qDw2FU0PcKncp6PjdvuIOicQEvnEllNoHfOwDIVGTGb8XnsaKOigQfWKyzyflEpdTFF3s12Dx0A==","shasum":"f0a42319e5b25b8277b9ac1925c8a1ed66754234","tarball":"https://registry.npmjs.org/@darkhorseone/primeforge-common/-/primeforge-common-1.0.1.tgz","fileCount":108,"unpackedSize":199225,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDJiCpUqR1lBP38Ewv4UbxUmsNLiugh+VkwthT49I+H7QIgc2MJzI+P23AaB6CyQXyUBAjv69hgIDIsjlBfjKfLmzI="}]},"_npmUser":{"name":"nick-ma","email":"honeyday.mj@gmail.com"},"directories":{},"maintainers":[{"name":"nick-ma","email":"honeyday.mj@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/primeforge-common_1.0.1_1760724483856_0.31625798074607103"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-17T14:51:21.926Z","modified":"2025-10-17T18:08:04.330Z","1.0.0":"2025-10-17T14:51:22.260Z","1.0.1":"2025-10-17T18:08:04.062Z"},"author":{"name":"DarkhorseOne Limited"},"license":"MIT","keywords":["nestjs","shared","common","utilities"],"description":"Shared services and utilities for NestJS applications in PrimeForge","maintainers":[{"name":"nick-ma","email":"honeyday.mj@gmail.com"}],"readme":"# @darkhorseone/primeforge-common\n\n**Shared services and utilities for NestJS applications in PrimeForge**\n\nA comprehensive collection of reusable NestJS modules, services, and utilities designed to accelerate development and maintain consistency across microservices.\n\n## 📦 Installation\n\nPublish the compiled package to your private registry (for example GitHub Packages or a self-hosted Verdaccio) and consume it like any other dependency. The `prepublishOnly` script builds `dist/` automatically before the publish step.\n\n```bash\n# Configure your .npmrc once per environment\nnpm config set //npm.pkg.github.com/:_authToken=<YOUR_TOKEN>\nnpm config set @darkhorseone:registry=https://npm.pkg.github.com\n\n# Publish from this repository\nnpm publish --registry=https://npm.pkg.github.com\n```\n\nOnce the package is available in the registry:\n\n```bash\nnpm install @darkhorseone/primeforge-common\n```\n\n> Adjust the scope/registry values to match your setup. For local development without publishing, `npm install @darkhorseone/primeforge-common@file:../primeforge-common` remains supported.\n\n## 🚀 Quick Start\n\n```typescript\nimport { Module } from \"@nestjs/common\";\nimport { ConfigModule, LoggerModule, HealthModule } from \"@darkhorseone/primeforge-common\";\n\n@Module({\n  imports: [ConfigModule, LoggerModule.forRoot(), HealthModule.forRoot()],\n})\nexport class AppModule {}\n```\n\n## 📋 Table of Contents\n\n- [Modules](#-modules)\n  - [ConfigModule](#configmodule)\n  - [LoggerModule](#loggermodule)\n  - [HealthModule](#healthmodule)\n  - [EmailModule](#emailmodule)\n  - [AuthModule](#authmodule)\n- [Common Utilities](#-common-utilities)\n  - [Decorators](#decorators)\n  - [DTOs](#dtos)\n  - [Filters](#filters)\n  - [Utilities](#utilities)\n- [Examples](#-examples)\n- [Configuration](#-configuration)\n- [Migration Guide](#-migration-guide)\n- [API Reference](#-api-reference)\n\n## 🧩 Modules\n\n### ConfigModule\n\nCentralized configuration management with environment validation and type safety.\n\n**Features:**\n\n- Environment variable validation\n- Type-safe configuration access\n- Support for multiple environments\n- Auto-loading of .env files\n\n**Usage:**\n\n```typescript\nimport { ConfigModule, ConfigService } from \"@darkhorseone/primeforge-common\";\n\n@Module({\n  imports: [ConfigModule],\n})\nexport class AppModule {}\n\n// In your service\n@Injectable()\nexport class MyService {\n  constructor(private configService: ConfigService) {}\n\n  getAppConfig() {\n    return this.configService.app; // Type-safe access\n  }\n}\n```\n\n**Available Configurations:**\n\n- `app` - Application settings (port, host, environment)\n- `database` - Database connection settings\n- `redis` - Redis configuration\n- `jwt` - JWT token configuration\n- `email` - Email service settings\n- `logger` - Logging configuration\n- `security` - Security settings\n- `monitoring` - Health check and metrics settings\n\n### LoggerModule\n\nStructured logging service with multiple output formats and log levels.\n\n**Features:**\n\n- JSON and pretty-print formats\n- Multiple log levels (debug, info, warn, error)\n- Context-aware logging\n- File and console output\n- Request correlation IDs\n\n**Usage:**\n\n```typescript\nimport { LoggerModule, LoggerService } from \"@darkhorseone/primeforge-common\";\n\n@Module({\n  imports: [\n    LoggerModule.forRoot({\n      level: \"info\",\n      format: \"json\",\n      outputToFile: true,\n    }),\n  ],\n})\nexport class AppModule {}\n\n// In your service\n@Injectable()\nexport class MyService {\n  constructor(private logger: LoggerService) {}\n\n  doSomething() {\n    this.logger.info(\"Operation started\", { userId: \"123\" });\n    this.logger.warn(\"Warning message\");\n    this.logger.error(\"Error occurred\", { error: \"details\" });\n  }\n}\n```\n\n### HealthModule\n\nComprehensive health checking and monitoring for your applications.\n\n**Features:**\n\n- Basic and detailed health checks\n- Readiness and liveness probes\n- Prometheus-style metrics\n- Database connectivity checks\n- System resource monitoring\n\n**Usage:**\n\n```typescript\nimport { HealthModule } from \"@darkhorseone/primeforge-common\";\n\n@Module({\n  imports: [\n    HealthModule.forRoot({\n      enableDetailedHealth: true,\n      database: {\n        enabled: true,\n        timeout: 3000,\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n**Available Endpoints:**\n\n- `GET /health` - Basic health check\n- `GET /health/detailed` - Detailed system information\n- `GET /health/ready` - Readiness probe\n- `GET /health/live` - Liveness probe\n- `GET /metrics` - Prometheus metrics\n\n### EmailModule\n\nCore email sending service focused on delivery through SendGrid.\n\n> **Note**: EmailModule now provides only core email delivery functionality. For business logic like welcome emails and templates, implement dedicated services in your application modules.\n\n**Features:**\n\n- SendGrid integration\n- Direct email sending\n- Batch email support\n- Scheduled email delivery\n- Attachment support\n- Email status tracking\n\n**Usage:**\n\n```typescript\nimport { EmailModule, EmailService } from \"@darkhorseone/primeforge-common\";\n\n@Module({\n  imports: [\n    EmailModule.forRootAsync({\n      useFactory: (configService: ConfigService) => configService.email,\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class AppModule {}\n\n// In your service\n@Injectable()\nexport class MyService {\n  constructor(private emailService: EmailService) {}\n\n  async sendNotification(user: User) {\n    await this.emailService.sendEmail({\n      to: { email: user.email, name: user.name },\n      subject: \"Notification\",\n      htmlContent: \"<h1>Hello!</h1><p>This is a notification.</p>\",\n      textContent: \"Hello! This is a notification.\",\n    });\n  }\n}\n```\n\n**For Template Management:**\n\nCreate an EmailTemplateService in your application to handle business logic:\n\n```typescript\n// See EMAIL_MIGRATION_GUIDE.md for complete examples\n@Injectable()\nexport class EmailTemplateService {\n  constructor(\n    private prisma: PrismaService,\n    private emailService: EmailService\n  ) {}\n\n  async sendWelcomeEmail(email: string, name: string) {\n    const template = await this.getTemplate(\"welcome\");\n    const content = this.processTemplate(template.html_body, { name });\n\n    return this.emailService.sendEmail({\n      to: { email },\n      subject: template.subject,\n      htmlContent: content,\n    });\n  }\n}\n```\n\n### AuthModule\n\nJWT-based authentication and authorization utilities.\n\n**Features:**\n\n- JWT token verification\n- Authentication guards\n- Role-based access control\n- Permission checking\n- Token management\n\n**Usage:**\n\n```typescript\nimport { AuthModule, JwtAuthGuard } from \"@darkhorseone/primeforge-common\";\n\n@Module({\n  imports: [\n    AuthModule.forRootAsync({\n      useFactory: (configService: ConfigService) => configService.jwt,\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class AppModule {}\n\n// In your controller\n@Controller(\"users\")\n@UseGuards(JwtAuthGuard)\nexport class UsersController {\n  @Get(\"profile\")\n  @Roles(\"user\", \"admin\")\n  getProfile(@CurrentUser() user: any) {\n    return user;\n  }\n}\n```\n\n## 🛠 Common Utilities\n\n### Decorators\n\n**@Public()** - Mark routes as public (no authentication required)\n\n```typescript\n@Get('public-endpoint')\n@Public()\ngetPublicData() {\n  return { message: 'This is public' };\n}\n```\n\n**@Roles(...)** - Require specific roles\n\n```typescript\n@Get('admin-only')\n@Roles('admin')\ngetAdminData() {\n  return { message: 'Admin only' };\n}\n```\n\n**@RequirePermissions(...)** - Require specific permissions\n\n```typescript\n@Get('protected')\n@RequirePermissions('read:users')\ngetProtectedData() {\n  return { message: 'Protected data' };\n}\n```\n\n**@CurrentUser()** - Inject current user from JWT\n\n```typescript\n@Get('profile')\ngetProfile(@CurrentUser() user: JwtPayload) {\n  return user;\n}\n```\n\n### DTOs\n\n**PaginationDto** - Standard pagination parameters\n\n```typescript\nexport class GetUsersDto extends PaginationDto {\n  @IsOptional()\n  @IsString()\n  search?: string;\n}\n```\n\n### Filters\n\n**HttpExceptionFilter** - Global exception handling\n\n```typescript\napp.useGlobalFilters(new HttpExceptionFilter(logger));\n```\n\n### Utilities\n\n**HashUtil** - Password hashing and token generation\n\n```typescript\nimport { HashUtil } from \"@darkhorseone/primeforge-common\";\n\n// Hash password\nconst hashedPassword = await HashUtil.hashPassword(\"plaintext\");\n\n// Verify password\nconst isValid = await HashUtil.verifyPassword(hash, \"plaintext\");\n\n// Generate token\nconst token = HashUtil.generateToken(32);\n\n// Generate OTP\nconst otp = HashUtil.generateOTP(6);\n```\n\n**ValidationUtil** - Common validation functions\n\n```typescript\nimport { ValidationUtil } from \"@darkhorseone/primeforge-common\";\n\n// Validate email\nconst isValidEmail = ValidationUtil.isValidEmail(\"user@example.com\");\n\n// Validate password strength\nconst { isValid, errors, score } =\n  ValidationUtil.validatePasswordStrength(\"MyPassword123!\");\n\n// Validate UUID\nconst isValidUUID = ValidationUtil.isValidUUID(\n  \"123e4567-e89b-12d3-a456-426614174000\"\n);\n```\n\n## 💡 Examples\n\n### Complete Application Setup\n\n```typescript\nimport { Module } from \"@nestjs/common\";\nimport {\n  ConfigModule,\n  ConfigService,\n  LoggerModule,\n  HealthModule,\n  EmailModule,\n  AuthModule,\n  HttpExceptionFilter,\n} from \"@darkhorseone/primeforge-common\";\n\n@Module({\n  imports: [\n    // Global configuration\n    ConfigModule,\n\n    // Structured logging\n    LoggerModule.forRootAsync({\n      useFactory: (configService: ConfigService) => configService.logger,\n      inject: [ConfigService],\n    }),\n\n    // Health monitoring\n    HealthModule.forRoot({\n      enableDetailedHealth: true,\n      database: { enabled: true, timeout: 3000 },\n    }),\n\n    // Email service\n    EmailModule.forRootAsync({\n      useFactory: (configService: ConfigService) => configService.email,\n      inject: [ConfigService],\n    }),\n\n    // JWT Authentication\n    AuthModule.forRootAsync({\n      useFactory: (configService: ConfigService) => configService.jwt,\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### Secure Controller with Authentication\n\n```typescript\nimport { Controller, Get, Post, Body, UseGuards } from \"@nestjs/common\";\nimport {\n  JwtAuthGuard,\n  Roles,\n  RequirePermissions,\n  CurrentUser,\n  Public,\n  PaginationDto,\n  JwtPayload,\n} from \"@darkhorseone/primeforge-common\";\n\n@Controller(\"api/users\")\n@UseGuards(JwtAuthGuard)\nexport class UsersController {\n  @Get(\"public\")\n  @Public()\n  getPublicInfo() {\n    return { message: \"This endpoint is public\" };\n  }\n\n  @Get(\"profile\")\n  getProfile(@CurrentUser() user: JwtPayload) {\n    return { user };\n  }\n\n  @Get(\"admin\")\n  @Roles(\"admin\")\n  getAdminData() {\n    return { message: \"Admin only data\" };\n  }\n\n  @Get(\"users\")\n  @RequirePermissions(\"read:users\")\n  getUsers(@Query() pagination: PaginationDto) {\n    return { users: [], meta: pagination };\n  }\n}\n```\n\n## ⚙️ Configuration\n\n### Environment Variables\n\n```bash\n# Application\nAPP_NAME=MyApp\nPORT=3000\nHOST=0.0.0.0\nNODE_ENV=development\nGLOBAL_PREFIX=api\n\n# Database\nDATABASE_URL=postgresql://user:pass@localhost:5432/db\n\n# JWT\nJWT_SECRET=your-secret-key\nJWT_EXPIRES_IN=15m\nJWT_REFRESH_SECRET=your-refresh-secret\nJWT_REFRESH_EXPIRES_IN=7d\n\n# Email (SendGrid)\nSENDGRID_API_KEY=your-sendgrid-api-key\nSENDGRID_DEFAULT_FROM=noreply@example.com\n\n# Redis (optional)\nREDIS_HOST=localhost\nREDIS_PORT=6379\nREDIS_PASSWORD=\n\n# Security\nCORS_ORIGINS=http://localhost:3000,http://localhost:3001\n```\n\n### TypeScript Configuration\n\nEnsure your `tsconfig.json` includes:\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true\n  }\n}\n```\n\n## 📚 Migration Guide\n\nIf you're upgrading from a previous version that included template management features in EmailService, please refer to our comprehensive migration guide:\n\n**[📖 Email Service Migration Guide](./docs/EMAIL_MIGRATION_GUIDE.md)**\n\nThe guide covers:\n\n- ✅ Step-by-step migration instructions\n- ✅ Interface changes and new features\n- ✅ Code examples for common patterns\n- ✅ Testing updates\n- ✅ Troubleshooting tips\n\n## 🔗 API Reference\n\n### Types and Interfaces\n\nAll modules export comprehensive TypeScript types:\n\n```typescript\nimport type {\n  AppConfig,\n  DatabaseConfig,\n  JwtConfig,\n  EmailConfig,\n  LoggerConfig,\n  HealthConfig,\n  JwtPayload,\n  EmailMessage,\n  PaginatedResult,\n} from \"@darkhorseone/primeforge-common\";\n```\n\n### Constants\n\n```typescript\nimport {\n  AUTH_IS_PUBLIC_KEY,\n  AUTH_ROLES_KEY,\n  AUTH_PERMISSIONS_KEY,\n} from \"@darkhorseone/primeforge-common\";\n```\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## 📝 License\n\nThis project is licensed under the UNLICENSED License - see the package.json file for details.\n\n## 🔍 Troubleshooting\n\n### Common Issues\n\n**Module not found errors:**\n\n```bash\nnpm install reflect-metadata\n```\n\n**Decorator errors:**\nEnable experimental decorators in your `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true\n  }\n}\n```\n\n**Environment variables not loading:**\nEnsure you have the correct `.env` file structure and that ConfigModule is imported first.\n\n---\n\nFor more detailed examples and advanced usage, please refer to the individual module documentation in the `/docs` directory.\n","readmeFilename":"README.md"}