This repository has no description
Something went wrong. Try again.
5.1 kB · 141 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142// SPDX-License-Identifier: AGPL-3.0-or-later
import {AdminACLs} from '@fluxer/constants/src/AdminACLs';import { LIMIT_CATEGORY_LABELS, LIMIT_KEY_METADATA, LIMIT_KEYS, type LimitKey,} from '@fluxer/constants/src/LimitConfigMetadata';import type {LimitConfigSnapshot, LimitRule} from '@fluxer/limits/src/LimitTypes';import {LimitConfigGetResponse, LimitConfigUpdateRequest} from '@fluxer/schema/src/domains/admin/AdminSchemas';import {Config} from '../../Config';import {createDefaultLimitConfig} from '../../constants/LimitConfig';import type {LimitConfigService} from '../../limits/LimitConfigService';import {requireAdminACL} from '../../middleware/AdminMiddleware';import {RateLimitMiddleware} from '../../middleware/RateLimitMiddleware';import {OpenAPI} from '../../middleware/ResponseTypeMiddleware';import {RateLimitConfigs} from '../../RateLimitConfig';import type {HonoApp} from '../../types/HonoEnv';import {Validator} from '../../Validator';
function formatConfig(config: LimitConfigSnapshot) { const defaults = createDefaultLimitConfig({selfHosted: Config.instance.selfHosted}); const defaultLimitsMap: Record<string, Record<LimitKey, number>> = {}; for (const rule of defaults.rules) { defaultLimitsMap[rule.id] = rule.limits as Record<LimitKey, number>; } return { limit_config: config, limit_config_json: JSON.stringify(config, null, 2), self_hosted: Config.instance.selfHosted, defaults: defaultLimitsMap, metadata: LIMIT_KEY_METADATA, categories: LIMIT_CATEGORY_LABELS, limit_keys: LIMIT_KEYS, };}
function trackModifiedFields(config: LimitConfigSnapshot): LimitConfigSnapshot { const defaults = createDefaultLimitConfig({selfHosted: Config.instance.selfHosted}); const defaultRulesMap = buildRulesMap(defaults.rules); const rulesWithTracking = config.rules.map((rule) => trackRuleModifiedFields(rule, defaultRulesMap)); return { ...config, rules: rulesWithTracking, };}
function buildRulesMap(rules: Array<LimitRule>): Map<string, LimitRule> { const map = new Map<string, LimitRule>(); for (const rule of rules) { map.set(rule.id, rule); } return map;}
function trackRuleModifiedFields( rule: LimitRule, defaultRulesMap: Map<string, LimitRule>,): LimitRule & { modifiedFields?: Array<LimitKey>;} { const defaultRule = defaultRulesMap.get(rule.id); const fallbackDefault = defaultRule ?? defaultRulesMap.get('default'); if (!fallbackDefault) { return { ...rule, modifiedFields: Object.keys(rule.limits) as Array<LimitKey>, }; } const modifiedFields = findModifiedLimits(rule.limits, fallbackDefault.limits); return { ...rule, modifiedFields: modifiedFields.length > 0 ? modifiedFields : undefined, };}
function findModifiedLimits( currentLimits: Partial<Record<LimitKey, number>>, defaultLimits: Partial<Record<LimitKey, number>>,): Array<LimitKey> { const modified: Array<LimitKey> = []; for (const key of LIMIT_KEYS) { const currentValue = currentLimits[key]; const defaultValue = defaultLimits[key]; if (currentValue !== undefined && currentValue !== defaultValue) { modified.push(key); } } return modified;}
export function LimitConfigAdminController(app: HonoApp) { app.post( '/admin/limit-config/get', RateLimitMiddleware(RateLimitConfigs.ADMIN_LOOKUP), requireAdminACL(AdminACLs.INSTANCE_LIMIT_CONFIG_VIEW), OpenAPI({ operationId: 'get_limit_config', summary: 'Get limit configuration', description: 'Retrieves rate limit configuration including message limits, upload limits, and request throttles. Shows defaults, metadata, and any modifications from defaults. Requires INSTANCE_LIMIT_CONFIG_VIEW permission.', responseSchema: LimitConfigGetResponse, statusCode: 200, security: 'adminApiKey', tags: 'Admin', }), async (ctx) => { const limitConfigService = ctx.get('limitConfigService') as LimitConfigService; const snapshot = limitConfigService.getConfigSnapshot(); return ctx.json(formatConfig(snapshot)); }, ); app.post( '/admin/limit-config/update', RateLimitMiddleware(RateLimitConfigs.ADMIN_USER_MODIFY), requireAdminACL(AdminACLs.INSTANCE_LIMIT_CONFIG_UPDATE), Validator('json', LimitConfigUpdateRequest), OpenAPI({ operationId: 'update_limit_config', summary: 'Update limit configuration', description: 'Updates rate limit configuration including message throughput, upload sizes, and request throttles. Changes apply immediately to all new operations. Requires INSTANCE_LIMIT_CONFIG_UPDATE permission.', responseSchema: LimitConfigGetResponse, statusCode: 200, security: 'adminApiKey', tags: 'Admin', }), async (ctx) => { const limitConfigService = ctx.get('limitConfigService') as LimitConfigService; const data = ctx.req.valid('json'); const normalized: LimitConfigSnapshot = { ...data.limit_config, traitDefinitions: data.limit_config.traitDefinitions ?? [], }; const withTracking = trackModifiedFields(normalized); await limitConfigService.updateConfig(withTracking); return ctx.json(formatConfig(limitConfigService.getConfigSnapshot())); }, );}