@vritti/api-sdk 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,7 @@ NestJS SDK for multi-tenant applications with automatic database routing, JWT au
13
13
  - 🎯 **Request-Scoped Context**: Tenant information available throughout the request lifecycle
14
14
  - 🛡️ **Decorators**: `@Public()`, `@Onboarding()`, and `@Tenant()` for flexible access control
15
15
  - ⚡ **Zero Configuration**: Auto-registers guards and interceptors
16
+ - 📝 **Unified Logging**: Environment-aware logging with PII masking, correlation IDs, and multi-tenant context
16
17
 
17
18
  ## Installation
18
19
 
@@ -370,6 +371,272 @@ super(database, (p) => p.inventoryItem);
370
371
  }
371
372
  ```
372
373
 
374
+ ## Unified Logging
375
+
376
+ The SDK provides a comprehensive logging system with built-in support for correlation IDs, HTTP logging, and multi-tenant context tracking. Choose between NestJS default logger or Winston with environment-based presets.
377
+
378
+ ### Features
379
+
380
+ - 🎯 **Dual Provider Support**: Switch between NestJS default Logger and Winston
381
+ - 🌍 **Environment Presets**: Pre-configured settings for development, staging, production, and test
382
+ - 🔗 **Correlation IDs**: Track requests across services with automatic ID generation and propagation
383
+ - 🏢 **Multi-Tenant Context**: Automatically includes tenant and user IDs in logs
384
+ - 📁 **File Logging**: Automatic file rotation with configurable retention
385
+ - 🚀 **HTTP Request/Response Logging**: Automatic logging of all HTTP traffic
386
+ - ⚡ **Zero Configuration**: Works out of the box with sensible defaults
387
+
388
+ ### Quick Start
389
+
390
+ Import the `LoggerModule` in your application:
391
+
392
+ ```typescript
393
+ import { Module } from '@nestjs/common';
394
+ import { ConfigModule, ConfigService } from '@nestjs/config';
395
+ import { LoggerModule } from '@vritti/api-sdk';
396
+
397
+ @Module({
398
+ imports: [
399
+ ConfigModule.forRoot({ isGlobal: true }),
400
+
401
+ // Option 1: Simple configuration with environment preset
402
+ LoggerModule.forRoot({
403
+ environment: 'development', // Required: development, staging, production, test
404
+ appName: 'my-service',
405
+ }),
406
+
407
+ // Option 2: Dynamic configuration with ConfigService
408
+ LoggerModule.forRootAsync({
409
+ imports: [ConfigModule],
410
+ useFactory: (config: ConfigService) => ({
411
+ environment: config.get('NODE_ENV', 'development'),
412
+ appName: config.get('APP_NAME'),
413
+ provider: config.get('LOG_PROVIDER'), // 'default' or 'winston'
414
+ level: config.get('LOG_LEVEL'), // Optional override
415
+ format: config.get('LOG_FORMAT'), // Optional override
416
+ enableFileLogger: config.get('LOG_TO_FILE') === 'true',
417
+ enableHttpLogger: true,
418
+ httpLogger: {
419
+ enableRequestLog: true,
420
+ enableResponseLog: true,
421
+ slowRequestThreshold: 3000,
422
+ },
423
+ }),
424
+ inject: [ConfigService],
425
+ }),
426
+ ],
427
+ })
428
+ export class AppModule {}
429
+ ```
430
+
431
+ Inject and use the `LoggerService`:
432
+
433
+ ```typescript
434
+ import { Injectable } from '@nestjs/common';
435
+ import { LoggerService } from '@vritti/api-sdk';
436
+
437
+ @Injectable()
438
+ export class UsersService {
439
+ constructor(private readonly logger: LoggerService) {}
440
+
441
+ async createUser(data: CreateUserDto) {
442
+ this.logger.log('Creating new user', 'UsersService');
443
+
444
+ try {
445
+ const user = await this.userRepository.create(data);
446
+ this.logger.log('User created successfully', { userId: user.id });
447
+ return user;
448
+ } catch (error) {
449
+ this.logger.error('Failed to create user', error.stack, 'UsersService');
450
+ throw error;
451
+ }
452
+ }
453
+ }
454
+ ```
455
+
456
+ ### Environment Presets
457
+
458
+ The logger module provides pre-configured settings based on environment:
459
+
460
+ | Environment | Provider | Level | Format | File Logging | HTTP Logging |
461
+ |------------|----------|-------|--------|--------------|--------------|
462
+ | development | winston | debug | text | No | Yes (verbose) |
463
+ | staging | winston | log | json | Yes | Yes |
464
+ | production | winston | warn | json | Yes | Limited |
465
+ | test | winston | error | json | No | No |
466
+
467
+ ### Provider Selection
468
+
469
+ Choose between NestJS default Logger or Winston:
470
+
471
+ ```typescript
472
+ // Use NestJS default Logger
473
+ LoggerModule.forRoot({
474
+ environment: 'development',
475
+ provider: 'default', // Simple, built-in NestJS logger
476
+ })
477
+
478
+ // Use Winston (default)
479
+ LoggerModule.forRoot({
480
+ environment: 'production',
481
+ provider: 'winston', // Advanced features, file logging, etc.
482
+ })
483
+ ```
484
+
485
+ **Environment Variable:**
486
+ ```bash
487
+ # In .env file
488
+ LOG_PROVIDER=default # or 'winston'
489
+ ```
490
+
491
+ **Important:** When using `LOG_PROVIDER=default`, update your `main.ts` to avoid circular references:
492
+
493
+ ```typescript
494
+ async function bootstrap() {
495
+ const logProvider = process.env.LOG_PROVIDER || 'winston';
496
+ const useBuiltInLogger = logProvider === 'default';
497
+
498
+ const app = await NestFactory.create<NestFastifyApplication>(
499
+ AppModule,
500
+ new FastifyAdapter(),
501
+ useBuiltInLogger ? {} : {
502
+ logger: new LoggerService({
503
+ environment: process.env.NODE_ENV
504
+ })
505
+ },
506
+ );
507
+
508
+ // Only replace logger when using Winston
509
+ if (!useBuiltInLogger) {
510
+ const appLogger = app.get(LoggerService);
511
+ app.useLogger(appLogger);
512
+ }
513
+
514
+ // ... rest of bootstrap
515
+ }
516
+ ```
517
+
518
+ ### HTTP Request Logging
519
+
520
+ HTTP logging is automatically enabled when `enableHttpLogger: true`. The interceptor is registered globally:
521
+
522
+ ```typescript
523
+ LoggerModule.forRoot({
524
+ environment: 'development',
525
+ enableHttpLogger: true,
526
+ httpLogger: {
527
+ enableRequestLog: true, // Log incoming requests
528
+ enableResponseLog: true, // Log outgoing responses
529
+ slowRequestThreshold: 3000, // Warn on requests > 3 seconds
530
+ },
531
+ })
532
+ ```
533
+
534
+ **Request Log Example:**
535
+ ```
536
+ 2025-01-23T10:30:45.123Z INFO [abc123] [HTTP] → POST /api/users
537
+ ```
538
+
539
+ **Response Log Example:**
540
+ ```
541
+ 2025-01-23T10:30:45.456Z INFO [abc123] [HTTP] ← 201 POST /api/users (333ms)
542
+ ```
543
+
544
+ **Slow Request Warning:**
545
+ ```
546
+ 2025-01-23T10:30:50.789Z WARN [abc123] [HTTP] ← 200 GET /api/reports (4521ms) [SLOW]
547
+ ```
548
+
549
+ ### Correlation ID Middleware
550
+
551
+ Correlation IDs are automatically included in all logs when the middleware is registered:
552
+
553
+ ```typescript
554
+ // In main.ts (Fastify)
555
+ const correlationMiddleware = app.get(CorrelationIdMiddleware);
556
+ const fastifyInstance = app.getHttpAdapter().getInstance();
557
+ fastifyInstance.addHook('onRequest', async (request, reply) => {
558
+ await correlationMiddleware.onRequest(request as any, reply as any);
559
+ });
560
+ ```
561
+
562
+ The correlation ID appears in all logs:
563
+ ```
564
+ 2025-01-23T10:30:45.123Z INFO [abc123] [UsersService] Creating new user
565
+ ```
566
+
567
+ ### Custom Configuration
568
+
569
+ Override preset defaults for specific needs:
570
+
571
+ ```typescript
572
+ LoggerModule.forRoot({
573
+ environment: 'production', // Start with production preset
574
+ level: 'debug', // Override: use debug level
575
+ enableFileLogger: true, // Enable file logging
576
+ filePath: './logs', // Custom log directory
577
+ maxFiles: '30d', // Keep logs for 30 days
578
+ httpLogger: {
579
+ enableRequestLog: true, // Override: enable request logs in production
580
+ enableResponseLog: true,
581
+ slowRequestThreshold: 5000, // 5 seconds
582
+ },
583
+ })
584
+ ```
585
+
586
+ ### Logging with Metadata
587
+
588
+ Add custom metadata to enrich your logs (Winston only):
589
+
590
+ ```typescript
591
+ this.logger.logWithMetadata(
592
+ 'log',
593
+ 'Payment processed',
594
+ {
595
+ orderId: order.id,
596
+ amount: order.total,
597
+ paymentMethod: 'credit_card',
598
+ },
599
+ 'PaymentService'
600
+ );
601
+ ```
602
+
603
+ ### Child Loggers
604
+
605
+ Create context-specific loggers:
606
+
607
+ ```typescript
608
+ @Injectable()
609
+ export class OrderService {
610
+ private readonly logger: LoggerService;
611
+
612
+ constructor(loggerService: LoggerService) {
613
+ this.logger = loggerService.child('OrderService');
614
+ }
615
+
616
+ processOrder(orderId: string) {
617
+ this.logger.log('Processing order', { orderId });
618
+ // All logs from this logger will include context: "OrderService"
619
+ }
620
+ }
621
+ ```
622
+
623
+ ### Configuration Reference
624
+
625
+ | Option | Type | Default | Description |
626
+ |--------|------|---------|-------------|
627
+ | `environment` | `string` | Required | Environment preset: `development`, `staging`, `production`, `test` |
628
+ | `provider` | `'default' \| 'winston'` | `'winston'` | Logger implementation to use |
629
+ | `appName` | `string` | - | Application name (included in all logs) |
630
+ | `level` | `string` | Preset | Log level: `error`, `warn`, `log`, `debug`, `verbose` |
631
+ | `format` | `'text' \| 'json'` | Preset | Log output format |
632
+ | `enableFileLogger` | `boolean` | Preset | Enable file-based logging |
633
+ | `filePath` | `string` | `'./logs'` | Directory for log files |
634
+ | `maxFiles` | `string` | `'14d'` | Log retention period |
635
+ | `enableHttpLogger` | `boolean` | Preset | Enable HTTP request/response logging |
636
+ | `httpLogger.enableRequestLog` | `boolean` | Preset | Log incoming HTTP requests |
637
+ | `httpLogger.enableResponseLog` | `boolean` | Preset | Log outgoing HTTP responses |
638
+ | `httpLogger.slowRequestThreshold` | `number` | Preset | Threshold (ms) to warn on slow requests |
639
+
373
640
  ## API Reference
374
641
 
375
642
  ### Modules
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+
17
+ // src/drizzle-orm.ts
18
+ var drizzle_orm_exports = {};
19
+ module.exports = __toCommonJS(drizzle_orm_exports);
20
+ __reExport(drizzle_orm_exports, require("drizzle-orm"), module.exports);
21
+ // Annotate the CommonJS export names for ESM import in node:
22
+ 0 && (module.exports = {
23
+ ...require("drizzle-orm")
24
+ });
25
+ //# sourceMappingURL=drizzle-orm.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/drizzle-orm.ts"],"sourcesContent":["// Re-export all of drizzle-orm\nexport * from 'drizzle-orm';\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;;AACA,gCAAc,wBADd;","names":[]}
@@ -0,0 +1,2 @@
1
+ export * from 'drizzle-orm';
2
+ import 'drizzle-orm/pg-core';
@@ -0,0 +1,2 @@
1
+ export * from 'drizzle-orm';
2
+ import 'drizzle-orm/pg-core';
@@ -0,0 +1,3 @@
1
+ // src/drizzle-orm.ts
2
+ export * from "drizzle-orm";
3
+ //# sourceMappingURL=drizzle-orm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/drizzle-orm.ts"],"sourcesContent":["// Re-export all of drizzle-orm\nexport * from 'drizzle-orm';\n"],"mappings":";AACA,cAAc;","names":[]}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+
17
+ // src/drizzle-pg-core.ts
18
+ var drizzle_pg_core_exports = {};
19
+ module.exports = __toCommonJS(drizzle_pg_core_exports);
20
+ __reExport(drizzle_pg_core_exports, require("drizzle-orm/pg-core"), module.exports);
21
+ // Annotate the CommonJS export names for ESM import in node:
22
+ 0 && (module.exports = {
23
+ ...require("drizzle-orm/pg-core")
24
+ });
25
+ //# sourceMappingURL=drizzle-pg-core.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/drizzle-pg-core.ts"],"sourcesContent":["// Re-export all of drizzle-orm/pg-core\nexport * from 'drizzle-orm/pg-core';\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;;AACA,oCAAc,gCADd;","names":[]}
@@ -0,0 +1 @@
1
+ export * from 'drizzle-orm/pg-core';
@@ -0,0 +1 @@
1
+ export * from 'drizzle-orm/pg-core';
@@ -0,0 +1,3 @@
1
+ // src/drizzle-pg-core.ts
2
+ export * from "drizzle-orm/pg-core";
3
+ //# sourceMappingURL=drizzle-pg-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/drizzle-pg-core.ts"],"sourcesContent":["// Re-export all of drizzle-orm/pg-core\nexport * from 'drizzle-orm/pg-core';\n"],"mappings":";AACA,cAAc;","names":[]}