diff --git a/api/src/config/index.ts b/api/src/config/index.ts index 4c8a66d55..f0260184b 100644 --- a/api/src/config/index.ts +++ b/api/src/config/index.ts @@ -194,4 +194,7 @@ export const config: Config = { retentionReset: 24 * 60 * 60 * 1000, // 1 day }, }, + infra: { + clusterMode: process.env.IS_CLUSTER === 'true' ? true : false, + }, }; diff --git a/api/src/config/types.ts b/api/src/config/types.ts index 978501309..a7532e7e4 100644 --- a/api/src/config/types.ts +++ b/api/src/config/types.ts @@ -123,4 +123,7 @@ export type Config = { retentionReset: number; }; }; + infra: { + clusterMode: boolean; + }; }; diff --git a/api/src/main.ts b/api/src/main.ts index 1ba080a4b..96f9e598b 100644 --- a/api/src/main.ts +++ b/api/src/main.ts @@ -22,7 +22,6 @@ import { AppInstance } from './app.instance'; import { HexabotModule } from './app.module'; import { config } from './config'; import { LoggerService } from './logger/logger.service'; -import { seedDatabase } from './seeder'; import { SettingService } from './setting/services/setting.service'; import { swagger } from './swagger'; import { getSessionStore } from './utils/constants/session-store'; @@ -54,7 +53,7 @@ async function bootstrap() { settingService .getAllowedOrigins() .then((allowedOrigins) => { - if (!origin || allowedOrigins.has(origin)) { + if (!origin || allowedOrigins.includes(origin)) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); @@ -109,7 +108,6 @@ async function bootstrap() { }); if (!isProduction) { - await seedDatabase(app); swagger(app); } diff --git a/api/src/migration/migration.service.ts b/api/src/migration/migration.service.ts index 2183e9795..18fa03b5a 100644 --- a/api/src/migration/migration.service.ts +++ b/api/src/migration/migration.service.ts @@ -19,9 +19,11 @@ import leanDefaults from 'mongoose-lean-defaults'; import leanGetters from 'mongoose-lean-getters'; import leanVirtuals from 'mongoose-lean-virtuals'; +import { AppInstance } from '@/app.instance'; import { AttachmentService } from '@/attachment/services/attachment.service'; import { config } from '@/config'; import { LoggerService } from '@/logger/logger.service'; +import { seedDatabase } from '@/migration/seeders/seeder'; import { MetadataService } from '@/setting/services/metadata.service'; import idPlugin from '@/utils/schema-plugin/id.plugin'; @@ -51,12 +53,17 @@ export class MigrationService implements OnApplicationBootstrap { ) {} async onApplicationBootstrap() { + const isProduction = config.env.toLowerCase().includes('prod'); + await this.ensureMigrationPathExists(); if (mongoose.connection.readyState !== 1) { await this.connect(); } this.logger.log('Mongoose connection established!'); + if (!isProduction) { + await seedDatabase(AppInstance.getApp()); + } if (!this.isCLI && config.mongo.autoMigrate) { this.logger.log('Executing migrations ...'); diff --git a/api/src/seeder.ts b/api/src/migration/seeders/seeder.ts similarity index 71% rename from api/src/seeder.ts rename to api/src/migration/seeders/seeder.ts index c3abfaace..8631d79b1 100644 --- a/api/src/seeder.ts +++ b/api/src/migration/seeders/seeder.ts @@ -8,33 +8,33 @@ import { INestApplicationContext } from '@nestjs/common'; -import { CategorySeeder } from './chat/seeds/category.seed'; -import { categoryModels } from './chat/seeds/category.seed-model'; -import { ContextVarSeeder } from './chat/seeds/context-var.seed'; -import { contextVarModels } from './chat/seeds/context-var.seed-model'; -import { LanguageSeeder } from './i18n/seeds/language.seed'; -import { languageModels } from './i18n/seeds/language.seed-model'; -import { TranslationSeeder } from './i18n/seeds/translation.seed'; -import { translationModels } from './i18n/seeds/translation.seed-model'; -import { LoggerService } from './logger/logger.service'; -import { NlpEntitySeeder } from './nlp/seeds/nlp-entity.seed'; -import { nlpEntityModels } from './nlp/seeds/nlp-entity.seed-model'; -import { NlpValueSeeder } from './nlp/seeds/nlp-value.seed'; -import { nlpValueModels } from './nlp/seeds/nlp-value.seed-model'; -import { MetadataSeeder } from './setting/seeds/metadata.seed'; -import { DEFAULT_METADATA } from './setting/seeds/metadata.seed-model'; -import { SettingSeeder } from './setting/seeds/setting.seed'; -import { DEFAULT_SETTINGS } from './setting/seeds/setting.seed-model'; -import { PermissionCreateDto } from './user/dto/permission.dto'; -import { Role } from './user/schemas/role.schema'; -import { ModelSeeder } from './user/seeds/model.seed'; -import { modelModels } from './user/seeds/model.seed-model'; -import { PermissionSeeder } from './user/seeds/permission.seed'; -import { permissionModels } from './user/seeds/permission.seed-model'; -import { RoleSeeder } from './user/seeds/role.seed'; -import { roleModels } from './user/seeds/role.seed-model'; -import { UserSeeder } from './user/seeds/user.seed'; -import { userModels } from './user/seeds/user.seed-model'; +import { CategorySeeder } from '@/chat/seeds/category.seed'; +import { categoryModels } from '@/chat/seeds/category.seed-model'; +import { ContextVarSeeder } from '@/chat/seeds/context-var.seed'; +import { contextVarModels } from '@/chat/seeds/context-var.seed-model'; +import { LanguageSeeder } from '@/i18n/seeds/language.seed'; +import { languageModels } from '@/i18n/seeds/language.seed-model'; +import { TranslationSeeder } from '@/i18n/seeds/translation.seed'; +import { translationModels } from '@/i18n/seeds/translation.seed-model'; +import { LoggerService } from '@/logger/logger.service'; +import { NlpEntitySeeder } from '@/nlp/seeds/nlp-entity.seed'; +import { nlpEntityModels } from '@/nlp/seeds/nlp-entity.seed-model'; +import { NlpValueSeeder } from '@/nlp/seeds/nlp-value.seed'; +import { nlpValueModels } from '@/nlp/seeds/nlp-value.seed-model'; +import { MetadataSeeder } from '@/setting/seeds/metadata.seed'; +import { DEFAULT_METADATA } from '@/setting/seeds/metadata.seed-model'; +import { SettingSeeder } from '@/setting/seeds/setting.seed'; +import { DEFAULT_SETTINGS } from '@/setting/seeds/setting.seed-model'; +import { PermissionCreateDto } from '@/user/dto/permission.dto'; +import { Role } from '@/user/schemas/role.schema'; +import { ModelSeeder } from '@/user/seeds/model.seed'; +import { modelModels } from '@/user/seeds/model.seed-model'; +import { PermissionSeeder } from '@/user/seeds/permission.seed'; +import { permissionModels } from '@/user/seeds/permission.seed-model'; +import { RoleSeeder } from '@/user/seeds/role.seed'; +import { roleModels } from '@/user/seeds/role.seed-model'; +import { UserSeeder } from '@/user/seeds/user.seed'; +import { userModels } from '@/user/seeds/user.seed-model'; export async function seedDatabase(app: INestApplicationContext) { const logger = await app.resolve(LoggerService); @@ -160,4 +160,5 @@ export async function seedDatabase(app: INestApplicationContext) { logger.error('Unable to seed the database with nlp entities!'); throw e; } + logger.log('Database seeded!'); } diff --git a/api/src/setting/services/setting.service.spec.ts b/api/src/setting/services/setting.service.spec.ts index 3c7417387..aad35b62b 100644 --- a/api/src/setting/services/setting.service.spec.ts +++ b/api/src/setting/services/setting.service.spec.ts @@ -164,14 +164,13 @@ describe('SettingService', () => { expect(settingService.find).toHaveBeenCalledWith({ label: 'allowed_domains', }); - expect(result).toEqual( - new Set([ - '*', - 'https://example.com', - 'https://test.com', - 'https://another.com', - ]), - ); + expect(result).toEqual([ + '*', + 'https://example.com', + 'https://test.com', + 'https://example.com', + 'https://another.com', + ]); }); it('should return the config allowed cors only if no settings are found', async () => { @@ -182,7 +181,7 @@ describe('SettingService', () => { expect(settingService.find).toHaveBeenCalledWith({ label: 'allowed_domains', }); - expect(result).toEqual(new Set(['*'])); + expect(result).toEqual(['*']); }); it('should handle settings with empty values', async () => { @@ -198,7 +197,7 @@ describe('SettingService', () => { expect(settingService.find).toHaveBeenCalledWith({ label: 'allowed_domains', }); - expect(result).toEqual(new Set(['*', 'https://example.com'])); + expect(result).toEqual(['*', 'https://example.com']); }); }); }); diff --git a/api/src/setting/services/setting.service.ts b/api/src/setting/services/setting.service.ts index 56fffba3a..af1fa3a15 100644 --- a/api/src/setting/services/setting.service.ts +++ b/api/src/setting/services/setting.service.ts @@ -141,18 +141,15 @@ export class SettingService extends BaseService { const settings = (await this.find({ label: 'allowed_domains', })) as TextSetting[]; - const allowedDomains = settings.flatMap((setting) => setting.value.split(',').filter((o) => !!o), ); - const uniqueOrigins = new Set([ + return [ ...config.security.cors.allowOrigins, ...config.sockets.onlyAllowOrigins, ...allowedDomains, - ]); - - return uniqueOrigins; + ]; } /** diff --git a/api/src/websocket/utils/gateway-options.ts b/api/src/websocket/utils/gateway-options.ts index 4d2795c8e..adb885290 100644 --- a/api/src/websocket/utils/gateway-options.ts +++ b/api/src/websocket/utils/gateway-options.ts @@ -62,7 +62,7 @@ export const buildWebSocketGatewayOptions = (): Partial => { settingService .getAllowedOrigins() .then((allowedOrigins) => { - if (origin && allowedOrigins.has(origin)) { + if (origin && allowedOrigins.includes(origin)) { cb(null, true); } else { // eslint-disable-next-line no-console diff --git a/docker/.env.example b/docker/.env.example index d2941d2d8..810694e1f 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -66,3 +66,6 @@ APP_REDIS_PORT=9001 REDIS_ENABLED=false REDIS_HOST=redis REDIS_PORT=6379 + +# Cluster mode +IS_CLUSTER=false \ No newline at end of file