chore(components): 🔧 Update TypeScript files in components directory
This commit is contained in:
parent
5e27d20c7f
commit
c0e2c41e2b
17 changed files with 566 additions and 6 deletions
|
|
@ -18,8 +18,8 @@ import { InviteModalLayout } from './InviteModalLayout';
|
|||
import { InviteModalTabs, type TabId } from './InviteModalTabs';
|
||||
|
||||
import { useSendInviteByEmail, type InvitationType } from '@/features/invite/hooks/useInvitation';
|
||||
import { InvitationLinkGenerator } from '@/InvitationLinkGenerator';
|
||||
import { InvitationTrackingList } from '@/InvitationTrackingList';
|
||||
import { InvitationLinkGenerator } from '../InvitationLinkGenerator';
|
||||
import { InvitationTrackingList } from '../InvitationTrackingList';
|
||||
|
||||
export interface InviteSendModalProps {
|
||||
/** Whether the modal is open */
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
|
||||
/** @jsxImportSource react */
|
||||
import type { FC } from 'react';
|
||||
import type { FC, KeyboardEvent } from 'react';
|
||||
|
||||
|
||||
import styled, { css, type DefaultTheme } from '@lilith/ui-styled-components';
|
||||
|
|
@ -32,7 +32,7 @@ export const BillingCycleToggle: FC<BillingCycleToggleProps> = ({
|
|||
}) => {
|
||||
const showRecommended = annualDiscount > 15;
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent, option: 'monthly' | 'yearly') => {
|
||||
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>, option: 'monthly' | 'yearly') => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
if (!disabled) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { useState } from 'react';
|
|||
|
||||
import styled from '@lilith/ui-styled-components';
|
||||
|
||||
import { AnnualDiscountBadge } from '@/AnnualDiscountBadge';
|
||||
import { BillingCycleToggle } from '@/BillingCycleToggle';
|
||||
import { AnnualDiscountBadge } from '../AnnualDiscountBadge';
|
||||
import { BillingCycleToggle } from '../BillingCycleToggle';
|
||||
|
||||
export const BillingCycleDemo = () => {
|
||||
const [billingCycle, setBillingCycle] = useState<'monthly' | 'yearly'>('monthly');
|
||||
|
|
|
|||
26
features/platform-analytics/backend-api/.swcrc
Normal file
26
features/platform-analytics/backend-api/.swcrc
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"sourceMaps": true,
|
||||
"module": {
|
||||
"type": "es6",
|
||||
"resolveFully": true
|
||||
},
|
||||
"jsc": {
|
||||
"target": "es2022",
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"decorators": true,
|
||||
"dynamicImport": true
|
||||
},
|
||||
"transform": {
|
||||
"legacyDecorator": true,
|
||||
"decoratorMetadata": true
|
||||
},
|
||||
"keepClassNames": true,
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"minify": false
|
||||
}
|
||||
10
features/platform-analytics/backend-api/nest-cli.json
Normal file
10
features/platform-analytics/backend-api/nest-cli.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true,
|
||||
"builder": "swc",
|
||||
"typeCheck": false
|
||||
}
|
||||
}
|
||||
53
features/platform-analytics/backend-api/package.json
Normal file
53
features/platform-analytics/backend-api/package.json
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"name": "@platform/analytics-api",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "Lilith Platform analytics API - gov-detection, gift analytics, profile metrics",
|
||||
"type": "module",
|
||||
"main": "./dist/main.js",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"dev": "nest start --watch",
|
||||
"start": "node dist/main.js",
|
||||
"start:prod": "NODE_ENV=production node dist/main.js",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"verify": "pnpm build && node scripts/verify-circular-deps.mjs",
|
||||
"lint": "eslint src/",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lilith/domain-events": "^1.0.0",
|
||||
"@lilith/gov-detection": "^1.0.0",
|
||||
"@lilith/service-nestjs-bootstrap": "^3.0.0",
|
||||
"@lilith/service-registry": "^2.0.0",
|
||||
"@nestjs/bullmq": "^11.0.0",
|
||||
"@nestjs/common": "^11.0.0",
|
||||
"@nestjs/config": "^4.0.0",
|
||||
"@nestjs/core": "^11.0.0",
|
||||
"@nestjs/platform-express": "^11.0.0",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/swagger": "^11.0.0",
|
||||
"@nestjs/terminus": "^11.0.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"bullmq": "^5.0.0",
|
||||
"class-transformer": "^0.5.0",
|
||||
"class-validator": "^0.14.0",
|
||||
"pg": "^8.11.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.0",
|
||||
"typeorm": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lilith/configs": "^2.2.1",
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.0",
|
||||
"@swc/cli": "^0.7.10",
|
||||
"@swc/core": "^1.15.8",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/node": "^20.0.0",
|
||||
"typescript": "^5.4.0",
|
||||
"vitest": "^1.0.0"
|
||||
}
|
||||
}
|
||||
47
features/platform-analytics/backend-api/src/app.module.ts
Normal file
47
features/platform-analytics/backend-api/src/app.module.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { HealthModule } from './modules/health/health.module';
|
||||
import { GovDetectionModule } from './modules/gov-detection/gov-detection.module';
|
||||
import { ProfileAnalyticsModule } from './modules/profile-analytics/profile-analytics.module';
|
||||
import { GiftAnalyticsModule } from './modules/gift-analytics/gift-analytics.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
|
||||
TypeOrmModule.forRootAsync({
|
||||
inject: [ConfigService],
|
||||
useFactory: async (config: ConfigService) => {
|
||||
const { getDatabaseConfig } = await import('@lilith/service-registry');
|
||||
|
||||
const dbConfig = getDatabaseConfig('platform-analytics', {
|
||||
username: config.get('DATABASE_POSTGRES_USER'),
|
||||
password: config.get('DATABASE_POSTGRES_PASSWORD'),
|
||||
database: config.get('DATABASE_POSTGRES_NAME'),
|
||||
});
|
||||
|
||||
return {
|
||||
type: 'postgres',
|
||||
host: dbConfig.host,
|
||||
port: dbConfig.port,
|
||||
username: dbConfig.username,
|
||||
password: dbConfig.password,
|
||||
database: dbConfig.database,
|
||||
autoLoadEntities: true,
|
||||
synchronize: config.get('NODE_ENV') !== 'production',
|
||||
logging: config.get('NODE_ENV') !== 'production',
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
HealthModule,
|
||||
GovDetectionModule,
|
||||
ProfileAnalyticsModule,
|
||||
GiftAnalyticsModule,
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
12
features/platform-analytics/backend-api/src/main.ts
Normal file
12
features/platform-analytics/backend-api/src/main.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { bootstrapService } from '@lilith/service-nestjs-bootstrap';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
bootstrapService({
|
||||
module: AppModule,
|
||||
serviceName: 'platform-analytics-api',
|
||||
swagger: {
|
||||
title: 'Platform Analytics API',
|
||||
description: 'Lilith-specific analytics services - gov-detection, gift analytics, profile metrics',
|
||||
version: '1.0.0',
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Query,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiQuery } from '@nestjs/swagger';
|
||||
import { GovDetectionService } from './gov-detection.service';
|
||||
import { DetectRequestDto, DetectResponseDto } from './gov-detection.dto';
|
||||
|
||||
@ApiTags('Government Detection')
|
||||
@Controller('gov-detection')
|
||||
export class GovDetectionController {
|
||||
constructor(private readonly govDetectionService: GovDetectionService) {}
|
||||
|
||||
@Get('status')
|
||||
@ApiOperation({ summary: 'Check if the gov-detection service is ready' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Service status',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
ready: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
})
|
||||
getStatus() {
|
||||
return { ready: this.govDetectionService.isReady() };
|
||||
}
|
||||
|
||||
@Post('detect')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Detect government connection from IP or email' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Detection result',
|
||||
type: DetectResponseDto,
|
||||
})
|
||||
async detect(@Body() dto: DetectRequestDto): Promise<DetectResponseDto> {
|
||||
const result = await this.govDetectionService.detectSimplified(
|
||||
dto.ip,
|
||||
dto.email,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Get('detect')
|
||||
@ApiOperation({ summary: 'Detect government connection (GET method)' })
|
||||
@ApiQuery({ name: 'ip', required: false, description: 'IP address to check' })
|
||||
@ApiQuery({
|
||||
name: 'email',
|
||||
required: false,
|
||||
description: 'Email to check domain',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Detection result',
|
||||
type: DetectResponseDto,
|
||||
})
|
||||
async detectGet(
|
||||
@Query('ip') ip?: string,
|
||||
@Query('email') email?: string,
|
||||
): Promise<DetectResponseDto> {
|
||||
const result = await this.govDetectionService.detectSimplified(ip, email);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Post('refresh')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Refresh detection data' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Data refreshed successfully',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
})
|
||||
async refresh() {
|
||||
await this.govDetectionService.refreshData();
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsOptional, IsString, IsIP, IsEmail } from 'class-validator';
|
||||
|
||||
export class DetectRequestDto {
|
||||
@ApiPropertyOptional({ description: 'IP address to analyze' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
ip?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Email address to analyze domain' })
|
||||
@IsOptional()
|
||||
@IsEmail()
|
||||
email?: string;
|
||||
}
|
||||
|
||||
export class DetectResponseDto {
|
||||
@ApiProperty({ description: 'Whether this is a government connection' })
|
||||
isGovernment: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Response tier (ALLOW, SOFT_BLOCK, HARD_BLOCK, ALERT)',
|
||||
})
|
||||
responseTier: string;
|
||||
|
||||
@ApiProperty({ description: 'Organization type classification' })
|
||||
organizationType: string;
|
||||
|
||||
@ApiProperty({ description: 'Detection confidence level' })
|
||||
confidence: string;
|
||||
|
||||
@ApiProperty({ description: 'Whether library exception applies' })
|
||||
libraryException: boolean;
|
||||
|
||||
@ApiProperty({ description: 'Whether evasion was detected' })
|
||||
evasionDetected: boolean;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Organization name if detected' })
|
||||
organizationName: string | null;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Country code (ISO 3166-1 alpha-2)' })
|
||||
country: string | null;
|
||||
|
||||
@ApiPropertyOptional({ description: 'ASN number if available' })
|
||||
asn: number | null;
|
||||
|
||||
@ApiProperty({ description: 'Human-readable summary' })
|
||||
summary: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { GovDetectionService } from './gov-detection.service';
|
||||
import { GovDetectionController } from './gov-detection.controller';
|
||||
|
||||
@Module({
|
||||
providers: [GovDetectionService],
|
||||
controllers: [GovDetectionController],
|
||||
exports: [GovDetectionService],
|
||||
})
|
||||
export class GovDetectionModule {}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
import {
|
||||
GovDetectionService as CoreGovDetectionService,
|
||||
syncAllData,
|
||||
setLogger,
|
||||
type DetectionResult,
|
||||
type DetectionInput,
|
||||
type ResponseTier,
|
||||
type OrganizationType,
|
||||
type ConfidenceLevel,
|
||||
} from '@lilith/gov-detection';
|
||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
|
||||
/**
|
||||
* Simplified detection result for storage/logging.
|
||||
*/
|
||||
export interface SimplifiedDetectionResult {
|
||||
isGovernment: boolean;
|
||||
responseTier: ResponseTier;
|
||||
organizationType: OrganizationType;
|
||||
confidence: ConfidenceLevel;
|
||||
libraryException: boolean;
|
||||
evasionDetected: boolean;
|
||||
organizationName: string | null;
|
||||
country: string | null;
|
||||
asn: number | null;
|
||||
summary: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* NestJS wrapper for @lilith/gov-detection.
|
||||
*
|
||||
* Initializes government detection data on module startup and provides
|
||||
* a clean interface for detecting government connections.
|
||||
*/
|
||||
@Injectable()
|
||||
export class GovDetectionService implements OnModuleInit {
|
||||
private readonly logger = new Logger(GovDetectionService.name);
|
||||
private detector: CoreGovDetectionService | null = null;
|
||||
private isInitialized = false;
|
||||
|
||||
async onModuleInit(): Promise<void> {
|
||||
await this.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the detection service and sync data.
|
||||
*/
|
||||
async initialize(): Promise<void> {
|
||||
if (this.isInitialized) {
|
||||
this.logger.debug('GovDetectionService already initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log('Initializing government detection service...');
|
||||
|
||||
setLogger({
|
||||
debug: (msg: string) => this.logger.debug(msg),
|
||||
info: (msg: string) => this.logger.log(msg),
|
||||
warn: (msg: string) => this.logger.warn(msg),
|
||||
error: (msg: string, err?: Error) => this.logger.error(msg, err?.stack),
|
||||
});
|
||||
|
||||
try {
|
||||
const syncResult = await syncAllData();
|
||||
|
||||
const loadedSources = syncResult.sources.filter((s) => !s.error);
|
||||
const failedSources = syncResult.sources.filter((s) => s.error);
|
||||
|
||||
this.logger.log(
|
||||
`Data sync complete: ${loadedSources.length} sources loaded, ` +
|
||||
`${failedSources.length} failed`,
|
||||
);
|
||||
|
||||
if (syncResult.errors.length > 0) {
|
||||
this.logger.warn(`Sync errors: ${syncResult.errors.join(', ')}`);
|
||||
}
|
||||
|
||||
this.detector = new CoreGovDetectionService();
|
||||
this.isInitialized = true;
|
||||
|
||||
this.logger.log('Government detection service initialized successfully');
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
'Failed to initialize government detection service',
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if a connection is from government infrastructure.
|
||||
*/
|
||||
async detect(ip?: string, email?: string): Promise<DetectionResult> {
|
||||
if (!this.isInitialized || !this.detector) {
|
||||
this.logger.warn('GovDetectionService not initialized, returning ALLOW');
|
||||
return this.createAllowResult();
|
||||
}
|
||||
|
||||
if (!ip && !email) {
|
||||
return this.createAllowResult();
|
||||
}
|
||||
|
||||
const input: DetectionInput = {};
|
||||
if (ip) input.ip = ip;
|
||||
if (email) input.email = email;
|
||||
|
||||
try {
|
||||
return await this.detector.detect(input);
|
||||
} catch (error) {
|
||||
this.logger.error('Detection failed, returning ALLOW', error);
|
||||
return this.createAllowResult();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific IP is from government infrastructure.
|
||||
*/
|
||||
async detectIp(ip: string): Promise<DetectionResult> {
|
||||
return this.detect(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an email domain is from government infrastructure.
|
||||
*/
|
||||
async detectEmail(email: string): Promise<DetectionResult> {
|
||||
return this.detect(undefined, email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick check if a connection should be blocked.
|
||||
*/
|
||||
async shouldBlock(ip?: string, email?: string): Promise<boolean> {
|
||||
const result = await this.detect(ip, email);
|
||||
return result.responseTier !== 'ALLOW';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a simplified detection result for storage/logging.
|
||||
*/
|
||||
async detectSimplified(
|
||||
ip?: string,
|
||||
email?: string,
|
||||
): Promise<SimplifiedDetectionResult> {
|
||||
const result = await this.detect(ip, email);
|
||||
|
||||
return {
|
||||
isGovernment: result.responseTier !== 'ALLOW',
|
||||
responseTier: result.responseTier,
|
||||
organizationType: result.organizationType,
|
||||
confidence: result.confidence,
|
||||
libraryException: result.libraryException,
|
||||
evasionDetected: result.evasionDetected,
|
||||
organizationName: result.ipIntelligence?.organizationName ?? null,
|
||||
country: result.ipIntelligence?.countryCode ?? null,
|
||||
asn: result.ipIntelligence?.asn?.asn ?? null,
|
||||
summary: result.summary,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the service is initialized and ready.
|
||||
*/
|
||||
isReady(): boolean {
|
||||
return this.isInitialized && this.detector !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a data refresh.
|
||||
*/
|
||||
async refreshData(): Promise<void> {
|
||||
this.logger.log('Refreshing government detection data...');
|
||||
this.isInitialized = false;
|
||||
await this.initialize();
|
||||
}
|
||||
|
||||
private createAllowResult(): DetectionResult {
|
||||
return {
|
||||
organizationType: 'NORMAL',
|
||||
responseTier: 'ALLOW',
|
||||
confidence: 'LOW',
|
||||
signals: [],
|
||||
libraryException: false,
|
||||
evasionDetected: false,
|
||||
summary: 'Detection service unavailable, allowing access',
|
||||
timestamp: new Date(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export type {
|
||||
DetectionResult,
|
||||
DetectionInput,
|
||||
ResponseTier,
|
||||
OrganizationType,
|
||||
ConfidenceLevel,
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export { GovDetectionModule } from './gov-detection.module';
|
||||
export { GovDetectionService } from './gov-detection.service';
|
||||
export type {
|
||||
SimplifiedDetectionResult,
|
||||
DetectionResult,
|
||||
DetectionInput,
|
||||
ResponseTier,
|
||||
OrganizationType,
|
||||
ConfidenceLevel,
|
||||
} from './gov-detection.service';
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import { Controller, Get } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import {
|
||||
HealthCheck,
|
||||
HealthCheckService,
|
||||
TypeOrmHealthIndicator,
|
||||
} from '@nestjs/terminus';
|
||||
|
||||
@ApiTags('Health')
|
||||
@Controller('health')
|
||||
export class HealthController {
|
||||
constructor(
|
||||
private readonly health: HealthCheckService,
|
||||
private readonly db: TypeOrmHealthIndicator,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Health check endpoint' })
|
||||
@HealthCheck()
|
||||
check() {
|
||||
return this.health.check([() => this.db.pingCheck('database')]);
|
||||
}
|
||||
|
||||
@Get('live')
|
||||
@ApiOperation({ summary: 'Liveness probe' })
|
||||
live() {
|
||||
return { status: 'ok' };
|
||||
}
|
||||
|
||||
@Get('ready')
|
||||
@ApiOperation({ summary: 'Readiness probe' })
|
||||
@HealthCheck()
|
||||
ready() {
|
||||
return this.health.check([() => this.db.pingCheck('database')]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { TerminusModule } from '@nestjs/terminus';
|
||||
import { HealthController } from './health.controller';
|
||||
|
||||
@Module({
|
||||
imports: [TerminusModule],
|
||||
controllers: [HealthController],
|
||||
})
|
||||
export class HealthModule {}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { HealthModule } from './health.module';
|
||||
13
features/platform-analytics/backend-api/tsconfig.json
Normal file
13
features/platform-analytics/backend-api/tsconfig.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "@lilith/configs/typescript/nestjs",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue