From dba81832c1bc75927722e70a4de93a57a2960dc0 Mon Sep 17 00:00:00 2001 From: Henry Winkel Date: Sat, 16 May 2026 20:11:02 +0200 Subject: [PATCH] feat(settings): add SettingsService with cache and emitter\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- app/lib/__tests__/settings.server.test.ts | 12 +++++++ app/lib/settings.server.ts | 43 +++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 app/lib/__tests__/settings.server.test.ts create mode 100644 app/lib/settings.server.ts diff --git a/app/lib/__tests__/settings.server.test.ts b/app/lib/__tests__/settings.server.test.ts new file mode 100644 index 0000000..eb070e4 --- /dev/null +++ b/app/lib/__tests__/settings.server.test.ts @@ -0,0 +1,12 @@ +// app/lib/__tests__/settings.server.test.ts +import { settingsService } from '../settings.server'; + +describe('SettingsService', () => { + test('set and get', async () => { + const key = `test_key_${Date.now()}`; + const val = { enabled: true }; + await settingsService.set(key, val, 'test'); + const got = await settingsService.get(key); + expect(got).toEqual(val); + }); +}); diff --git a/app/lib/settings.server.ts b/app/lib/settings.server.ts new file mode 100644 index 0000000..c4bad27 --- /dev/null +++ b/app/lib/settings.server.ts @@ -0,0 +1,43 @@ +// app/lib/settings.server.ts +import { PrismaClient } from '@prisma/client'; +import EventEmitter from 'events'; + +const prisma = new PrismaClient(); + +type JSONValue = any; + +class SettingsService extends EventEmitter { + private cache: Map = new Map(); + private initialized = false; + + async init() { + if (this.initialized) return; + const rows = await prisma.appSetting.findMany(); + rows.forEach(r => this.cache.set(r.key, r.value)); + this.initialized = true; + } + + async get(key: string) { + if (!this.initialized) await this.init(); + return this.cache.has(key) ? this.cache.get(key) : null; + } + + async set(key: string, value: JSONValue, updatedBy?: string) { + if (!this.initialized) await this.init(); + await prisma.appSetting.upsert({ + where: { key }, + update: { value, updatedBy }, + create: { key, value, updatedBy }, + }); + this.cache.set(key, value); + this.emit('update', { key, value }); + return { key, value }; + } + + subscribe(fn: (payload: { key: string; value: any }) => void) { + this.on('update', fn); + return () => this.off('update', fn); + } +} + +export const settingsService = new SettingsService();