From 5c05d6505559364118f191f95c50b327b1e7f081 Mon Sep 17 00:00:00 2001 From: Marcelo Lazaroni Date: Tue, 14 Oct 2025 13:43:06 +0100 Subject: [PATCH] Remove di directory --- src/{di/container.ts => app/integrations.ts} | 61 +++----------------- src/app/services.ts | 6 -- src/{common => app}/services/email.ts | 26 ++------- src/{common => app}/services/file-storage.ts | 35 +++-------- src/app/services/index.ts | 41 +++++++++++++ src/di/index.ts | 2 - src/di/scopedContainer.ts | 24 -------- src/index.ts | 6 +- 8 files changed, 63 insertions(+), 138 deletions(-) rename src/{di/container.ts => app/integrations.ts} (54%) delete mode 100644 src/app/services.ts rename src/{common => app}/services/email.ts (78%) rename src/{common => app}/services/file-storage.ts (87%) create mode 100644 src/app/services/index.ts delete mode 100644 src/di/index.ts delete mode 100644 src/di/scopedContainer.ts diff --git a/src/di/container.ts b/src/app/integrations.ts similarity index 54% rename from src/di/container.ts rename to src/app/integrations.ts index 9bd6bec..fd76a97 100644 --- a/src/di/container.ts +++ b/src/app/integrations.ts @@ -1,6 +1,5 @@ -import { container } from 'tsyringe'; -import { EmailService } from '@/common/services/email'; -import { FileStorageService } from '@/common/services/file-storage'; +export { type Dependencies, configureDependencies }; + import env from '@/app/environment'; import { Postgres, defaultPoolSettings } from '@/lib/postgres'; import { Mongo } from '@/lib/mongo'; @@ -12,53 +11,9 @@ import { ServerApiVersion } from 'mongodb'; import * as eventStore from '@/app/eventStore'; import { PostgresEventStore, WithEventStore } from '@/app/eventStore'; import { schemas } from '@/app/events'; -import { Services } from '@/app/services'; +import { Services, initializeServices } from '@/app/services'; import { Repositories, initializeRepositories } from '@/app/projections'; -function registerEnvironmentVariables() { - const postgresConnectionString = - `postgresql://${env.EVENT_STORE_USER}:${env.EVENT_STORE_PASSWORD}@` + - `${env.EVENT_STORE_HOST}:${env.EVENT_STORE_PORT}/` + - `${env.EVENT_STORE_DATABASE_NAME}`; - container.register('postgresConnectionString', { - useValue: postgresConnectionString, - }); - container.register('eventStoreTable', { - useValue: env.EVENT_STORE_CREATE_TABLE_WITH_NAME, - }); - container.register('eventStoreDatabaseName', { - useValue: env.EVENT_STORE_DATABASE_NAME, - }); - container.register('eventStoreCreateReplicationUserWithUsername', { - useValue: env.EVENT_STORE_CREATE_REPLICATION_USER_WITH_USERNAME, - }); - container.register('eventStoreCreateReplicationUserWithPassword', { - useValue: env.EVENT_STORE_CREATE_REPLICATION_USER_WITH_PASSWORD, - }); - container.register('eventStoreCreateReplicationPublication', { - useValue: env.EVENT_STORE_CREATE_REPLICATION_PUBLICATION, - }); - - const mongoConnectionString = - `mongodb://${env.MONGODB_PROJECTION_DATABASE_USERNAME}:${env.MONGODB_PROJECTION_DATABASE_PASSWORD}@` + - `${env.MONGODB_PROJECTION_HOST}:${env.MONGODB_PROJECTION_PORT}/` + - `${env.MONGODB_PROJECTION_DATABASE_NAME}` + - '?serverSelectionTimeoutMS=10000&connectTimeoutMS=10000&authSource=admin'; - const mongoDatabaseName = env.MONGODB_PROJECTION_DATABASE_NAME; - container.register('mongoConnectionString', { - useValue: mongoConnectionString, - }); - container.register('mongoDatabaseName', { useValue: mongoDatabaseName }); -} - -function registerSingletons() { - // common/services - container.registerSingleton(EmailService); - container.registerSingleton(FileStorageService); -} - -function registerScopedServices() {} - type Dependencies = { withEventStore: WithEventStore; withProjectionStore: WithProjectionStore; @@ -66,11 +21,7 @@ type Dependencies = { repositories: Repositories; }; -export async function configureDependencies(): Promise { - registerEnvironmentVariables(); - registerSingletons(); - registerScopedServices(); - +async function configureDependencies(): Promise { const postgres = new Postgres({ user: env.EVENT_STORE_USER, password: env.EVENT_STORE_PASSWORD, @@ -127,10 +78,12 @@ export async function configureDependencies(): Promise { initializeRepositories(new MongoProjectionStore(t)), ); + const services = initializeServices(); + return { withEventStore, withProjectionStore, - services: {}, + services, repositories, }; } diff --git a/src/app/services.ts b/src/app/services.ts deleted file mode 100644 index 64fcff1..0000000 --- a/src/app/services.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - All application services -*/ -export { type Services }; - -type Services = {}; diff --git a/src/common/services/email.ts b/src/app/services/email.ts similarity index 78% rename from src/common/services/email.ts rename to src/app/services/email.ts index 3752ea8..655999e 100644 --- a/src/common/services/email.ts +++ b/src/app/services/email.ts @@ -1,8 +1,9 @@ +export { EmailService, type EmailServiceConfig }; + import nodemailer from 'nodemailer'; import { log } from '@/common/util/Logger'; -import env from '@/app/environment'; -export interface EmailOptions { +interface EmailOptions { to: string | string[]; subject: string; text?: string; @@ -10,7 +11,7 @@ export interface EmailOptions { from?: string; } -export interface EmailServiceConfig { +interface EmailServiceConfig { host: string; port: number; secure: boolean; @@ -21,12 +22,10 @@ export interface EmailServiceConfig { defaultFrom?: string; } -export class EmailService { +class EmailService { private transporter: nodemailer.Transporter; - private config: EmailServiceConfig; - constructor(config?: EmailServiceConfig) { - this.config = config || this.getRequiredConfig(); + constructor(private config: EmailServiceConfig) { this.transporter = nodemailer.createTransport({ host: this.config.host, port: this.config.port, @@ -41,19 +40,6 @@ export class EmailService { }); } - private getRequiredConfig(): EmailServiceConfig { - return { - host: env.SMTP_HOST, - port: env.SMTP_PORT, - secure: true, - auth: { - user: env.SMTP_USERNAME, - pass: env.SMTP_PASSWORD, - }, - defaultFrom: env.SMTP_FROM_EMAIL, - }; - } - async sendEmail(options: EmailOptions): Promise { try { const mailOptions = { diff --git a/src/common/services/file-storage.ts b/src/app/services/file-storage.ts similarity index 87% rename from src/common/services/file-storage.ts rename to src/app/services/file-storage.ts index 2f018a9..6bd4264 100644 --- a/src/common/services/file-storage.ts +++ b/src/app/services/file-storage.ts @@ -1,9 +1,10 @@ +export { FileStorageService, type FileStorageServiceConfig }; + import * as Minio from 'minio'; import { Readable } from 'stream'; import { log } from '@/common/util/Logger'; -import env from '@/app/environment'; -export interface FileStorageOptions { +interface FileStorageOptions { bucketName: string; objectName: string; stream: string | Buffer | Readable; @@ -11,7 +12,7 @@ export interface FileStorageOptions { metaData?: Minio.ItemBucketMetadata; } -export interface FileStorageServiceConfig { +interface FileStorageServiceConfig { endPoint: string; port: number; useSSL: boolean; @@ -20,23 +21,21 @@ export interface FileStorageServiceConfig { region?: string; } -export interface FileStorageResult { +interface FileStorageResult { etag?: string; objectName: string; bucketName: string; } -export interface FileDownloadResult { +interface FileDownloadResult { stream: Readable; stat: Minio.BucketItemStat; } -export class FileStorageService { +class FileStorageService { private client: Minio.Client; - private config: FileStorageServiceConfig; - constructor(config?: FileStorageServiceConfig) { - this.config = config || this.getRequiredConfig(); + constructor(private config: FileStorageServiceConfig) { this.client = new Minio.Client({ endPoint: this.config.endPoint, port: this.config.port, @@ -53,24 +52,6 @@ export class FileStorageService { }); } - private getRequiredConfig(): FileStorageServiceConfig { - const endpointUrl = env.S3_ENDPOINT_URL; - const url = new URL(endpointUrl); - - return { - endPoint: url.hostname, - port: url.port - ? parseInt(url.port) - : url.protocol === 'https:' - ? 443 - : 80, - useSSL: url.protocol === 'https:', - accessKey: env.S3_ACCESS_KEY, - secretKey: env.S3_SECRET_KEY, - region: env.S3_REGION, - }; - } - async createBucket(bucketName: string, region?: string): Promise { try { const exists = await this.client.bucketExists(bucketName); diff --git a/src/app/services/index.ts b/src/app/services/index.ts new file mode 100644 index 0000000..717555c --- /dev/null +++ b/src/app/services/index.ts @@ -0,0 +1,41 @@ +/* + All application services +*/ +export { type Services, initializeServices }; + +import { EmailService } from '@/app/services/email'; +import { FileStorageService } from '@/app/services/file-storage'; +import env from '@/app/environment'; + +type Services = { + fileStorage: FileStorageService; + email: EmailService; +}; + +function initializeServices(): Services { + const url = new URL(env.S3_ENDPOINT_URL); + return { + fileStorage: new FileStorageService({ + endPoint: url.hostname, + port: url.port + ? parseInt(url.port) + : url.protocol === 'https:' + ? 443 + : 80, + useSSL: url.protocol === 'https:', + accessKey: env.S3_ACCESS_KEY, + secretKey: env.S3_SECRET_KEY, + region: env.S3_REGION, + }), + email: new EmailService({ + host: env.SMTP_HOST, + port: env.SMTP_PORT, + secure: true, + auth: { + user: env.SMTP_USERNAME, + pass: env.SMTP_PASSWORD, + }, + defaultFrom: env.SMTP_FROM_EMAIL, + }), + }; +} diff --git a/src/di/index.ts b/src/di/index.ts deleted file mode 100644 index 2c1014f..0000000 --- a/src/di/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './container'; -export * from './scopedContainer'; diff --git a/src/di/scopedContainer.ts b/src/di/scopedContainer.ts deleted file mode 100644 index 1532c0b..0000000 --- a/src/di/scopedContainer.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Request, Response, NextFunction } from 'express'; -import { container, DependencyContainer } from 'tsyringe'; - -declare global { - namespace Express { - interface Request { - container: DependencyContainer; - } - } -} - -export function scopedContainer( - req: Request, - res: Response, - next: NextFunction, -) { - req.container = container.createChildContainer(); - - res.on('finish', () => { - req.container.dispose(); - }); - - next(); -} diff --git a/src/index.ts b/src/index.ts index 3a702c2..f896591 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,7 @@ import 'tsconfig-paths/register'; // enable absolute paths import 'reflect-metadata'; import express from 'express'; -import { configureDependencies } from '@/di/container'; -import { scopedContainer } from '@/di/scopedContainer'; +import { configureDependencies } from '@/app/integrations'; import { log } from '@/common/util/Logger'; import { handleCommand, CommandController } from '@/app/handleCommand'; import { Event } from '@/lib/eventSourcing/event'; @@ -27,9 +26,6 @@ async function main() { const app = express(); app.use(express.json()); - // Add scoped container middleware - app.use(scopedContainer); - const command = (endpoint: string, controller: CommandController) => app.post( endpoint,