fix(plugins): per-tenant plugin store flag and harden broken schema APIs

Store enablement is now a tenant settings row instead of a global runtime switch, and expiring/requests endpoints degrade to empty lists when store tables are missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-07 19:51:11 +03:30
co-authored by Cursor
parent 1f776cf6e2
commit b3112cf032
9 changed files with 301 additions and 136 deletions
@@ -22,17 +22,4 @@ export class RuntimeSettingsController {
this.settings.setAdminSmsEnabled(dto.enabled);
return this.settings.getPublic();
}
@Get('plugin-store')
@RequirePermissions('settings:write')
getPluginStore() {
return this.settings.getPublic();
}
@Patch('plugin-store')
@RequirePermissions('settings:write')
setPluginStore(@Body() dto: UpdateAdminSmsDto) {
this.settings.setPluginStoreEnabled(dto.enabled);
return this.settings.getPublic();
}
}
+6 -19
View File
@@ -5,13 +5,10 @@ import { join } from 'path';
type RuntimeSettings = {
/** When false, SuperAdmin stops SMS alerts to managers */
adminSmsEnabled: boolean;
/** When false, khanegi admin plugin store menu is hidden */
pluginStoreEnabled: boolean;
};
const DEFAULTS: RuntimeSettings = {
adminSmsEnabled: true,
pluginStoreEnabled: false,
};
@Injectable()
@@ -31,22 +28,13 @@ export class RuntimeSettingsService {
return next;
}
getPluginStoreEnabled(): boolean {
return this.read().pluginStoreEnabled === true;
}
setPluginStoreEnabled(enabled: boolean) {
const next = { ...this.read(), pluginStoreEnabled: Boolean(enabled) };
this.write(next);
this.logger.log(`Plugin store ${next.pluginStoreEnabled ? 'enabled' : 'disabled'}`);
return next;
}
getPublic() {
return {
adminSmsEnabled: this.getAdminSmsEnabled(),
pluginStoreEnabled: this.getPluginStoreEnabled(),
};
try {
return { adminSmsEnabled: this.getAdminSmsEnabled() };
} catch (error: any) {
this.logger.warn(`getPublic failed: ${error?.message || error}`);
return { adminSmsEnabled: true };
}
}
private read(): RuntimeSettings {
@@ -59,7 +47,6 @@ export class RuntimeSettingsService {
const raw = JSON.parse(readFileSync(this.filePath, 'utf8')) as Partial<RuntimeSettings>;
this.cache = {
adminSmsEnabled: raw.adminSmsEnabled !== false,
pluginStoreEnabled: raw.pluginStoreEnabled === true,
};
return this.cache;
} catch (error: any) {