npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@svton/dynamic-config

v0.3.0

Published

Dynamic configuration management system with multi-layer caching

Readme

@svton/dynamic-config

动态配置管理系统,支持多层缓存、热更新、NestJS 集成和 React 组件。

特性

  • 🚀 动态配置 - 运行时修改配置,无需重启服务
  • 💾 多层缓存 - Redis 优先,内存兜底的分层缓存策略
  • 🔧 类型安全 - 完整的 TypeScript 类型支持
  • 📦 模块化 - 核心逻辑与框架集成分离
  • 🎨 React 组件 - 开箱即用的配置管理 UI 组件
  • 🔌 可扩展 - 支持自定义 Repository 和缓存策略

安装

pnpm add @svton/dynamic-config

子模块

| 模块 | 说明 | 导入路径 | |------|------|----------| | core | 核心逻辑(框架无关) | @svton/dynamic-config/core | | nestjs | NestJS 集成 | @svton/dynamic-config/nestjs | | prisma | Prisma 适配器 | @svton/dynamic-config/prisma | | react | React 组件和 Hooks | @svton/dynamic-config/react |

快速开始

1. 添加 Prisma Schema

src/prisma/schema.prisma.template 中的模型添加到你的 schema.prisma 文件。

2. NestJS 集成

// app.module.ts
import { Module } from '@nestjs/common';
import { DynamicConfigModule } from '@svton/dynamic-config/nestjs';
import { PrismaConfigRepository, PrismaDictionaryRepository } from '@svton/dynamic-config/prisma';
import { TieredCache, RedisCache, MemoryCache } from '@svton/dynamic-config/core';

@Module({
  imports: [
    DynamicConfigModule.forRootAsync({
      imports: [PrismaModule, RedisModule],
      useFactory: (prisma, redis) => ({
        configRepository: new PrismaConfigRepository(prisma),
        dictionaryRepository: new PrismaDictionaryRepository(prisma),
        cache: new TieredCache(
          new RedisCache(redis, { prefix: 'config:' }),
          new MemoryCache({ prefix: 'config:' }),
        ),
      }),
      inject: [PrismaService, RedisService],
    }),
  ],
})
export class AppModule {}

3. 使用配置服务

import { Injectable } from '@nestjs/common';
import { DynamicConfigService } from '@svton/dynamic-config/nestjs';

@Injectable()
export class UploadService {
  constructor(private configService: DynamicConfigService) {}

  async upload(file: File) {
    const storageType = await this.configService.getString('storage.type', 'local');
    const maxSize = await this.configService.getNumber('upload.maxSize', 10485760);

    // ...
  }
}

4. 自定义 Controller(添加权限控制)

import { Controller, UseGuards, Delete, Param } from '@nestjs/common';
import { BaseConfigController, DynamicConfigService } from '@svton/dynamic-config/nestjs';
import { JwtAuthGuard } from './auth/guards/jwt-auth.guard';
import { RolesGuard } from './auth/guards/roles.guard';
import { Roles } from './auth/decorators/roles.decorator';
import { Public } from './auth/decorators/public.decorator';

@Controller('config')
@UseGuards(JwtAuthGuard, RolesGuard)
export class ConfigController extends BaseConfigController {
  constructor(configService: DynamicConfigService) {
    super(configService);
  }

  @Public()
  @Get('public')
  async getPublicConfigs() {
    return super.getPublicConfigs();
  }

  @Roles('admin')
  @Delete(':key')
  async delete(@Param('key') key: string) {
    return super.delete(key);
  }
}

5. React 组件

import {
  DynamicConfigProvider,
  useConfigCategory,
  useConfigMutation,
  ConfigForm,
  initConfigFormValues,
} from '@svton/dynamic-config/react';

// 1. 实现 API 客户端
const configApi = {
  getPublicConfigs: () => fetch('/api/config/public').then(r => r.json()),
  getByCategory: (category) => fetch(`/api/config/category/${category}`).then(r => r.json()),
  batchUpdate: (configs) => fetch('/api/config/batch', {
    method: 'PUT',
    body: JSON.stringify({ configs }),
  }),
  // ... 其他方法
};

// 2. 包装 Provider
function App() {
  return (
    <DynamicConfigProvider configApi={configApi} dictionaryApi={dictionaryApi}>
      <ConfigPage />
    </DynamicConfigProvider>
  );
}

// 3. 使用 Hooks 和组件
function ConfigPage() {
  const { configs, loading, refetch } = useConfigCategory('storage');
  const { batchUpdate, loading: saving } = useConfigMutation();
  const [values, setValues] = useState({});

  useEffect(() => {
    if (configs.length > 0) {
      setValues(initConfigFormValues(configs));
    }
  }, [configs]);

  const handleSave = async () => {
    const updates = Object.entries(values).map(([key, value]) => ({ key, value }));
    await batchUpdate(updates);
    refetch();
  };

  return (
    <ConfigForm
      configs={configs}
      values={values}
      onChange={(key, value) => setValues(prev => ({ ...prev, [key]: value }))}
      onSave={handleSave}
      saving={saving}
      components={uiComponents} // 传入 shadcn/ui 组件
    />
  );
}

API 文档

Core

ConfigManager

const manager = new ConfigManager({
  repository: configRepository,
  cache: cacheStrategy,
  preload: true,
  logger: customLogger,
});

// 获取配置
await manager.get<string>('storage.type', 'local');
await manager.getString('storage.type', 'local');
await manager.getNumber('upload.maxSize', 10485760);
await manager.getBoolean('features.enableComment', true);
await manager.getJson<string[]>('upload.allowedTypes', []);

// 设置配置
await manager.set('storage.type', 'cos');

// 批量更新
await manager.batchUpdate([
  { key: 'storage.type', value: 'cos' },
  { key: 'upload.maxSize', value: 20971520 },
]);

// 获取分类配置
await manager.getByCategory('storage');

// 获取公开配置
await manager.getPublicConfigs();

// 获取系统配置(嵌套结构)
await manager.getSystemConfig();

// 重新加载
await manager.reload();

缓存策略

import { MemoryCache, RedisCache, TieredCache } from '@svton/dynamic-config/core';

// 内存缓存
const memoryCache = new MemoryCache({ prefix: 'config:', defaultTtl: 3600 });

// Redis 缓存
const redisCache = new RedisCache(redisClient, { prefix: 'config:', defaultTtl: 3600 });

// 分层缓存(Redis 优先,内存兜底)
const tieredCache = new TieredCache(redisCache, memoryCache);

NestJS

DynamicConfigModule

// 同步配置
DynamicConfigModule.forRoot({
  configRepository: new PrismaConfigRepository(prisma),
  dictionaryRepository: new PrismaDictionaryRepository(prisma),
  cache: new MemoryCache(),
  registerController: true,  // 是否注册默认 Controller
  isGlobal: false,           // 是否全局模块
  preload: true,             // 是否预加载配置
});

// 异步配置
DynamicConfigModule.forRootAsync({
  imports: [PrismaModule],
  useFactory: (prisma) => ({
    configRepository: new PrismaConfigRepository(prisma),
    // ...
  }),
  inject: [PrismaService],
});

React

Hooks

// 获取单个配置
const { value, loading, error, update } = useConfig('storage.type', 'local');

// 获取分类配置
const { configs, loading, error, refetch } = useConfigCategory('storage');

// 获取公开配置
const { configs, loading, error } = usePublicConfigs();

// 获取系统配置
const { config, loading, error } = useSystemConfig();

// 配置修改
const { set, batchUpdate, remove, reload, loading } = useConfigMutation();

// 字典相关
const { items, loading, error } = useDictionaries();
const { items, loading, error } = useDictionaryByCode('storage_type');
const { tree, loading, error } = useDictionaryTree('category');
const { create, update, remove, loading } = useDictionaryMutation();

数据库 Schema

Config 表

| 字段 | 类型 | 说明 | |------|------|------| | id | int | 主键 | | key | varchar(100) | 配置键(唯一) | | value | text | 配置值(JSON 字符串) | | type | varchar(20) | 值类型 | | category | varchar(50) | 分类 | | label | varchar(100) | 显示名称 | | description | varchar(500) | 说明 | | isPublic | boolean | 是否公开 | | isRequired | boolean | 是否必填 | | defaultValue | text | 默认值 | | options | text | 可选项(enum 类型) | | sort | int | 排序 |

Dictionary 表

| 字段 | 类型 | 说明 | |------|------|------| | id | int | 主键 | | code | varchar(50) | 字典编码 | | parentId | int | 父级 ID | | label | varchar(100) | 显示名称 | | value | varchar(200) | 字典值 | | type | varchar(20) | 类型(enum/tree/list) | | sort | int | 排序 | | isEnabled | boolean | 是否启用 | | description | varchar(500) | 说明 | | extra | text | 扩展字段 |

License

MIT