# @tonysamperi/ts-mapi-core-nest

A comprehensive set of shared utilities and modules for NestJS projects, providing authentication, caching, logging, database connectivity, and API validation features.

## 📦 Installation

```bash
npm install @tonysamperi/ts-mapi-core-nest
```

or

```bash
yarn add @tonysamperi/ts-mapi-core-nest
```

## 🚀 Quick Start

Import the modules you need in your NestJS application:

```typescript
import {
  SmpConfigModule,
  SmpFirestoreModule,
  SmpZodOpenApiModule,
  SmpSmtpModule,
  SmpOpenFeatureModule,
  SmpCronModule
} from '@tonysamperi/ts-mapi-core-nest';

@Module({
  imports: [
    SmpConfigModule.forRoot(),
    SmpFirestoreModule.forRoot(),
    SmpZodOpenApiModule.forRoot(),
    SmpSmtpModule,
    SmpOpenFeatureModule.forRoot(),
    SmpCronModule
  ],
})
export class AppModule {}
```

## ✨ Features

### 🔐 Authentication & Authorization
- **Guards**: JWT, Basic Auth, OIDC, Microsoft Auth
- **Services**: Abstract user services, OIDC authentication
- **Decorators**: Public routes, OIDC roles/groups/user, Basic Auth restricted/forbidden/users

### 🗄️ Database & Storage
- **Firestore**: Abstract services, caching, token management
- **Knex**: Database connections with SSH tunneling support
- **Modules**: Configurable database providers

### 🌐 API & Validation
- **Zod Integration**: Schema validation with OpenAPI/Swagger generation
- **DTOs**: Abstract Zod DTOs with automatic API documentation
- **Pipes**: Validation pipes for requests

### 📊 Caching & Performance
- **Interceptors**: Cache interceptors with Firestore strategy
- **Decorators**: Cacheable endpoints, skip serialization

### 📧 Email & SMTP
- **SMTP Integration**: Amazon SES support with configurable settings
- **Services**: Email sending capabilities
- **Global Module**: `SmpSmtpService` available throughout the application

### 🕒 Cron Jobs
- **Discovery**: Automatic discovery of cron jobs via decorators
- **Management**: Schedule and monitor background tasks

### 🚀 Config&Feature Management
- **OpenFeature Integration**: Feature flags and experimentation
- **Services**: Feature flag evaluation and management

### 📝 Logging & Monitoring
- **Winston Logger**: Custom transports, Datadog integration
- **Interceptors**: REST logging, global error logging
- **Decorators**: REST logging, global error logging
- **Services**: Configurable logger services

### 🛠️ Utilities
- **Config**: Environment-based configuration
- **HTTP**: Custom exceptions, error mapping
- **Decorators**: Skip REST logging, class serialization
- **Providers**: Cache strategies, proxy middleware

## 📚 API Reference

### Modules
- `SmpConfigModule` - Environment configuration management
- `SmpCronModule` - Cron job discovery and management
- `SmpFirestoreModule` - Firestore integration with caching
- `SmpOpenFeatureModule` - Feature flags and experimentation
- `SmpSmtpModule` - SMTP email sending (requires `SmpConfigModule`), depends on `nodemailer`
- `SmpZodOpenApiModule` - Zod validation with OpenAPI documentation

### Guards
- `SmpJwtAuthGuard` - JWT authentication
- `SmpBasicAuthGuard` - Basic authentication
- `SmpOidcAuthGuard` - OpenID Connect authentication
- `SmpRequiredHeadersGuard` - Required headers validation

### Services
- `SmpJwtUserService` - JWT user management
- `SmpBasicAuthUserService` - Basic auth user management
- `SmpMicrosoftAuthService` - Microsoft authentication
- `SmpDatadogWinstonLoggerService` - Datadog logging
- `SmpOpenFeatureService` - Feature flag management
- `SmpSmtpService` - Email sending via SMTP
- `SmpWinstonLoggerService` - Winston logging service
- `SmpCronSchedulerDiscoveryService` - Cron job discovery service

### Decorators
- `@SmpBasicAuthRestrictedTo()` / `@SmpBasicAuthForbiddenTo()` / `@SmpBasicAuthUsers()` / `@SmpBasicAuthUsersForbid()` - Basic Auth control
- `@SmpCacheable()` - Enable caching for endpoints
- `@SmpCronJob()` - Define a cron job
- `@SmpGlobalErrorLogger()` - Enable global error logging for an endpoint
- `@SmpOidcRoles()` / `@SmpOidcGroups()` / `@SmpOidcUser()` - OIDC info extraction
- `@SmpPublic()` - Mark routes as public
- `@SmpSkipRestLogging()` - Skip REST logging
- `@SmpSkipClassSerializer()` - Skip class serialization

### Interceptors
- `SmpCacheInterceptor` - Caching interceptor
- `SmpClassSerializerInterceptor` - Class serialization
- `SmpGlobalErrorLoggerInterceptor` - Global error logging
- `SmpRestLoggerInterceptor` - REST request logging

### Exceptions
- `SmpHttpBadRequestException` (400)
- `SmpHttpUnauthorizedException` (401)
- `SmpHttpForbiddenException` (403)
- `SmpHttpNotFoundException` (404)
- `SmpHttpMethodNotAllowedException` (405)
- `SmpHttpConflictException` (409)
- `SmpHttpTooManyRequestsException` (429)
- `SmpHttpServerException` (500)

### Utilities
- `SmpAbstractFirebaseRemoteConfigService` - Base Firebase Remote Config service to retrieve server config
- `SmpAbstractFirestoreService` - Base Firestore service
- `SmpAbstractFirestoreTokenService` - Service to store tokens in Firestore
- `smpBuildPaginationNextLink` - Pagination link building
- `smpDefaultEnvConfig` - Default environment configuration
- `smpEnvironmentVariablesSchema` - Environment validation schema

## 📖 Documentation

- [Zod OpenAPI Integration Guide](./docs/zod-openapi-swagger.md) - Detailed guide for using Zod with Swagger/OpenAPI
- [Zod OpenFeature Integration Guide](./docs/open-feature.md) - Detailed guide for using OpenFeature
- [Basic Auth Guide](./docs/basic-auth.md) - Detailed guide for using Basic Authentication

## 📄 License

ISC

## 👤 Author

Tony Samperi

---

## 🛠️ Development

### Install deps

We use Yarn **Berry**, so
* `corepack enable` (if you haven't already)
* `npm i -g yarn` (if you haven't already)
* `yarn install`

### Try locally
* `npm run build`

### Dependencies management
This tool is quite smart and will treat as external all dependencies listed in the peerDependencies of the package.json.
To work with dependencies here, you'll always install your deps as **devDependencies**.
This will allow you to decide if your dependency can be bundled or should be an external dependency.

Based on how vital is that dependency, you might decide to make the dependency optional.
To do so you'll have to get inspired by the project structure: you'll see that some dependencies are managed in a way that are imported dynamically, therefore not requiring the specific dependency (e.g. rxjs) unless specifically imported.
Things to consider: structure of the exports (if you export at the wrong level, files requiring certain deps might always be loaded, leading to a *MISSING MODULE* error), structure of the `index.cts`.

Remember to test this locally with a **beta** version (see below).

### Release a beta version ⚠️
To release a beta version, just push a beta tag, e.g. `3.0.0-beta.0`

### Release a production version ⚠️
To release a production version you just need to push a tag

### Exports need to end with .js, because of the NodeNext resolution
Automated checks through eslint and tests 
