diff --git a/.gitignore b/.gitignore index 03642d8..a58b7b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .devenv .devenv.flake.nix -.idea \ No newline at end of file +.idea +node_modules \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml index 30bab2a..d8e9561 100644 --- a/.idea/discord.xml +++ b/.idea/discord.xml @@ -1,7 +1,7 @@ - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index afbe93f..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,5 @@ - \ No newline at end of file diff --git a/apps/backend/package.json b/apps/backend/package.json index da69ca7..ced3a46 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -16,6 +16,7 @@ "@nestjs/core": "^10.0.0", "@nestjs/platform-express": "^10.0.0", "@nestjs/typeorm": "^10.0.1", + "glob": "^10.4.2", "mongodb": "^6.7.0", "pg": "^8.11.3", "typeorm": "^0.3.17" diff --git a/apps/backend/src/app.controller.ts b/apps/backend/src/app.controller.ts deleted file mode 100644 index ae7af0a..0000000 --- a/apps/backend/src/app.controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Controller, Get } from '@nestjs/common'; -import { AppService } from './app.service'; - -@Controller() -export class AppController { - constructor(private readonly appService: AppService) {} - - @Get() - createUser() { - return this.appService.createUser(); - } -} diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 7c9a4e6..2fab81f 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -1,8 +1,7 @@ -import { Module } from '@nestjs/common'; +import { Module, type Type } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; import { User } from './entities/user.entity'; +import { PluginModule } from "./common/plugins/plugin.module"; const userForFeature = TypeOrmModule.forFeature([User]); @@ -10,18 +9,20 @@ const userForFeature = TypeOrmModule.forFeature([User]); imports: [ TypeOrmModule.forRoot({ type: "mongodb", - host: "localhost", + host: "127.0.0.1", port: 27017, username: "homespace", password: "homespace", - database: "homespace", + database: "test", + authSource: "admin", synchronize: true, logging: false, entities: [User], }), userForFeature, + PluginModule.register() ], - controllers: [AppController], - providers: [AppService], + controllers: [], + providers: [], }) export class AppModule {} diff --git a/apps/backend/src/app.service.ts b/apps/backend/src/app.service.ts deleted file mode 100644 index 58a6ac5..0000000 --- a/apps/backend/src/app.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import type { Repository } from 'typeorm'; -import { User } from './entities/user.entity'; - -@Injectable() -export class AppService { - constructor( - @InjectRepository(User) - private readonly userRepository: Repository, - ) {} - - async createUser() { - const user = this.userRepository.create({ - firstName: 'Johannes', - lastName: 'Reckers', - age: 18, - }); - - const entity = await this.userRepository.save(user); - return entity; - } -} diff --git a/apps/backend/src/common/plugins/plugin.interface.ts b/apps/backend/src/common/plugins/plugin.interface.ts index ffe1d28..3c8e041 100644 --- a/apps/backend/src/common/plugins/plugin.interface.ts +++ b/apps/backend/src/common/plugins/plugin.interface.ts @@ -1,3 +1,5 @@ +import {INestApplication} from "@nestjs/common"; + export interface Plugin { - register(): void + register(app: INestApplication): void } \ No newline at end of file diff --git a/apps/backend/src/common/plugins/plugin.loader.ts b/apps/backend/src/common/plugins/plugin.loader.ts new file mode 100644 index 0000000..f4ac565 --- /dev/null +++ b/apps/backend/src/common/plugins/plugin.loader.ts @@ -0,0 +1,20 @@ +import { glob } from 'glob'; +import { join } from 'path'; + +export async function loadPlugins(): Promise { + return new Promise(async (resolve, reject) => { + const files = await glob('homespace-shared/plugins/**/*.plugin.{ts,js}'); + + console.log(files) + + const plugins = []; + for (const file of files) { + const filePath = join(process.cwd(), file); + const pluginModule = await import(filePath); + const pluginClass = Object.values(pluginModule)[0]; + plugins.push(pluginClass); + } + + resolve(plugins); + }); +} diff --git a/apps/backend/src/common/plugins/plugin.module.ts b/apps/backend/src/common/plugins/plugin.module.ts new file mode 100644 index 0000000..97c7c09 --- /dev/null +++ b/apps/backend/src/common/plugins/plugin.module.ts @@ -0,0 +1,25 @@ +import { Module, DynamicModule, Global, type Type } from '@nestjs/common'; +import { PluginService } from './plugin.service'; +import { type Plugin } from './plugin.interface'; +import { loadPlugins } from './plugin.loader'; + +@Global() +@Module({}) +export class PluginModule { + static async register(): Promise { + const plugins = await loadPlugins(); + + return { + module: PluginModule, + providers: [ + PluginService, + ...plugins, + { + provide: 'PLUGIN_PROVIDERS', + useValue: plugins, + }, + ], + exports: [PluginService], + }; + } +} \ No newline at end of file diff --git a/apps/backend/src/common/plugins/plugin.service.ts b/apps/backend/src/common/plugins/plugin.service.ts index 77be46c..ea9c1df 100644 --- a/apps/backend/src/common/plugins/plugin.service.ts +++ b/apps/backend/src/common/plugins/plugin.service.ts @@ -1,15 +1,18 @@ -import { Injectable, OnModuleInit } from "@nestjs/common"; +import {Injectable, OnModuleInit, Inject, type Type, INestApplication} from '@nestjs/common'; import { type Plugin } from './plugin.interface'; @Injectable() -export class PluginService implements OnModuleInit { - private plugins: Plugin[] = []; +export class PluginService { + private plugins: Type[] = []; - public registerPlugin(plugin: Plugin) { - this.plugins.push(plugin); + constructor(@Inject('PLUGIN_PROVIDERS') private readonly pluginProviders: Type[]) { + this.plugins = pluginProviders; } - onModuleInit() { - this.plugins.forEach((plugin) => plugin.register()); + initializePlugins(app: INestApplication) { + this.plugins.forEach(plugin => { + const pluginInstance = new plugin(); + pluginInstance.register(app); + }); } } \ No newline at end of file diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 3fb330f..8eb642d 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -1,12 +1,12 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; -import { PluginService } from './common/plugins/plugin.service'; +import { PluginService } from "./common/plugins/plugin.service"; async function bootstrap() { const app = await NestFactory.create(AppModule); const pluginService = app.get(PluginService); - pluginService.onModuleInit(); // Initialize plugins + pluginService.initializePlugins(app); await app.listen(4300); } diff --git a/apps/shared/package.json b/apps/shared/package.json new file mode 100644 index 0000000..5083a4e --- /dev/null +++ b/apps/shared/package.json @@ -0,0 +1,7 @@ +{ + "name": "homespace-shared", + "version": "0.0.1", + "workspaces": [ + "plugins/*" + ] +} \ No newline at end of file diff --git a/custom/plugins/blmedia-example/apps/frontend/src/main.js b/apps/shared/plugins/example-plugin/apps/frontend/src/main.js similarity index 100% rename from custom/plugins/blmedia-example/apps/frontend/src/main.js rename to apps/shared/plugins/example-plugin/apps/frontend/src/main.js diff --git a/apps/shared/plugins/example-plugin/example-plugin.plugin.ts b/apps/shared/plugins/example-plugin/example-plugin.plugin.ts new file mode 100644 index 0000000..dbcfac3 --- /dev/null +++ b/apps/shared/plugins/example-plugin/example-plugin.plugin.ts @@ -0,0 +1,8 @@ +// Todo: create example plugin +import { type Plugin } from "homespace-backend/src/common/plugins/plugin.interface"; + +export class ExamplePlugin implements Plugin { + register() { + console.log("plugin registered: ExamplePlugin"); + } +} \ No newline at end of file diff --git a/custom/plugins/blmedia-example/package.json b/apps/shared/plugins/example-plugin/package.json similarity index 67% rename from custom/plugins/blmedia-example/package.json rename to apps/shared/plugins/example-plugin/package.json index 7add712..6a6f3d9 100644 --- a/custom/plugins/blmedia-example/package.json +++ b/apps/shared/plugins/example-plugin/package.json @@ -1,5 +1,5 @@ { - "name": "blmedia-example", + "name": "example-plugin", "version": "0.0.1", "workspaces": [ "apps/*" diff --git a/bun.lockb b/bun.lockb index b2dbe57..d941ab8 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/custom/plugins/blmedia-example/blmedia-example.plugin.ts b/custom/plugins/blmedia-example/blmedia-example.plugin.ts deleted file mode 100644 index fab40f0..0000000 --- a/custom/plugins/blmedia-example/blmedia-example.plugin.ts +++ /dev/null @@ -1 +0,0 @@ -// Todo: create example plugin \ No newline at end of file