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

node-universe

v1.6.6

Published

基于 Nodejs 环境的一款微服务框架,原理来自于宇宙中的恒星,行星,卫星等系统。

Downloads

139

Readme

Node-Universe

基于 Node.js 环境的微服务框架

npm version License: ISC Node.js Version

🌟 简介

灵感来自宇宙中的恒星与行星,一个星系中可以有一个或多个恒星,恒星作为服务主体,为行星之间提供服务。Node-Universe 是一个现代化的微服务框架,提供了完整的微服务开发解决方案。

✨ 特性

  • 🚀 高性能: 基于事件驱动的异步架构
  • 🔧 模块化: 插件化设计,按需加载
  • 🌐 分布式: 支持多种传输协议和服务发现
  • 📊 监控: 内置性能指标和链路追踪
  • 🛡️ 可靠性: 熔断器、重试机制、负载均衡
  • 🎯 AOP支持: 强大的钩子系统,支持面向切面编程
  • 📝 TypeScript: 完整的类型定义支持

📦 安装

npm install node-universe
# 或
yarn add node-universe

🚀 快速开始

创建基本服务

import { Star } from 'node-universe';

// 创建用户服务
const userService = {
  name: 'user',
  
  actions: {
    // 创建用户
    create: {
      params: {
        name: 'string',
        email: 'email'
      },
      handler(ctx) {
        const user = {
          id: Date.now(),
          ...ctx.params,
          createdAt: new Date()
        };
        this.logger.info('用户创建成功', user);
        return user;
      }
    },
    
    // 获取用户列表
    list: {
      cache: true, // 启用缓存
      handler(ctx) {
        return [
          { id: 1, name: 'Alice', email: '[email protected]' },
          { id: 2, name: 'Bob', email: '[email protected]' }
        ];
      }
    }
  },
  
  // 钩子函数 - AOP支持
  hooks: {
    before: {
      '*': 'validateAuth', // 所有动作前验证权限
      'create': 'validateParams' // 创建前额外验证
    },
    after: {
      '*': 'logOperation', // 所有动作后记录日志
      'create': 'sendWelcomeEmail' // 创建后发送欢迎邮件
    },
    error: {
      '*': 'handleError' // 统一错误处理
    }
  },
  
  methods: {
    validateAuth(ctx) {
      // 权限验证逻辑
      if (!ctx.meta.user) {
        throw new Error('未授权访问');
      }
    },
    
    validateParams(ctx) {
      // 参数验证逻辑
      if (!ctx.params.name || ctx.params.name.length < 2) {
        throw new Error('用户名至少2个字符');
      }
    },
    
    logOperation(ctx, res) {
      this.logger.info(`操作完成: ${ctx.action.name}`, {
        params: ctx.params,
        result: res
      });
    },
    
    sendWelcomeEmail(ctx, res) {
      // 发送欢迎邮件逻辑
      this.logger.info(`发送欢迎邮件给: ${res.email}`);
    },
    
    handleError(ctx, err) {
      this.logger.error('操作失败', {
        action: ctx.action.name,
        error: err.message,
        params: ctx.params
      });
    }
  },
  
  // 生命周期钩子
  created() {
    this.logger.info('用户服务已创建');
  },
  
  started() {
    this.logger.info('用户服务已启动');
  }
};

// 创建并启动框架
const star = new Star({
  namespace: 'my-app',
  nodeID: 'node-1'
});

// 注册服务
star.createService(userService);

// 启动服务
star.start().then(() => {
  console.log('🚀 微服务启动成功!');
  
  // 调用服务
  star.call('user.create', {
    name: 'John Doe',
    email: '[email protected]'
  }, {
    meta: { user: { id: 1 } } // 模拟用户认证信息
  }).then(result => {
    console.log('创建用户结果:', result);
  });
});

分布式服务示例

// 服务A - 用户服务
const userStar = new Star({
  namespace: 'ecommerce',
  nodeID: 'user-service',
  transporter: {
    type: 'KAFKA',
    host: 'localhost:9092'
  }
});

// 服务B - 订单服务
const orderStar = new Star({
  namespace: 'ecommerce',
  nodeID: 'order-service',
  transporter: {
    type: 'KAFKA',
    host: 'localhost:9092'
  }
});

// 订单服务调用用户服务
const orderService = {
  name: 'order',
  actions: {
    create: {
      async handler(ctx) {
        // 验证用户是否存在
        const user = await ctx.call('user.get', { id: ctx.params.userId });
        
        // 创建订单
        const order = {
          id: Date.now(),
          userId: user.id,
          items: ctx.params.items,
          total: ctx.params.total,
          createdAt: new Date()
        };
        
        // 发送订单创建事件
        ctx.emit('order.created', order);
        
        return order;
      }
    }
  }
};

orderStar.createService(orderService);

⚙️ 配置选项

完整配置示例

const options = {
  namespace: 'my-app', // 命名空间,用于服务隔离
  nodeID: 'node-1', // 节点ID,默认自动生成
  metadata: { // 节点元数据
    region: 'us-west-1',
    version: '1.0.0'
  },
  
  // 性能指标
  metrics: {
    enabled: true,
    reporter: {
      type: 'Console', // Console | Prometheus | Datadog
      options: {
        interval: 5000 // 报告间隔(ms)
      }
    }
  },
  
  // 日志配置
  logger: {
    type: 'console', // console | file | log4js | pino
    level: 'info', // trace | debug | info | warn | error | fatal
    options: {
      colors: true,
      moduleColors: false,
      formatter: 'full', // full | short | simple | json
      objectPrinter: null,
      autoPadding: false
    }
  },
  
  // 传输层配置
  transporter: {
    type: 'TCP', // TCP | NATS | MQTT | Redis | AMQP | KAFKA
    options: {
      host: 'localhost',
      port: 4222
    }
  },
  
  // 服务注册与发现
  registry: {
    strategy: 'RoundRobin', // RoundRobin | Random | CpuUsage | Latency
    preferLocal: true,
    discoverer: {
      type: 'Local', // Local | Etcd | Consul
      options: {
        heartbeatInterval: 15,
        heartbeatTimeout: 30,
        disableHeartbeatChecks: false,
        disableOfflineNodeRemoving: false,
        cleanOfflineNodesTimeout: 600
      }
    }
  },
  
  // 缓存配置
  cacher: {
    type: 'Memory', // Memory | Redis
    options: {
      ttl: 30, // 默认TTL(秒)
      maxKeys: 1000 // 最大缓存键数
    }
  },
  
  // 序列化器
  serializer: {
    type: 'JSON' // JSON | Avro | MsgPack | Notepack | ProtoBuf | Thrift
  },
  
  // 验证器
  validator: {
    type: 'Fastest' // Fastest | Joi
  },
  
  // 链路追踪
  tracing: {
    enabled: true,
    exporter: {
      type: 'Console', // Console | Jaeger | Zipkin | Datadog
      options: {
        endpoint: 'http://localhost:14268/api/traces'
      }
    }
  },
  
  // 熔断器
  circuitBreaker: {
    enabled: true,
    threshold: 0.5,
    minRequestCount: 20,
    windowTime: 60,
    halfOpenTime: 10
  },
  
  // 重试策略
  retryPolicy: {
    enabled: true,
    retries: 5,
    delay: 100,
    maxDelay: 1000,
    factor: 2
  },
  
  // 请求超时
  requestTimeout: 5000,
  
  // 最大调用级别(防止循环调用)
  maxCallLevel: 100,
  
  // 心跳间隔
  heartbeatInterval: 10,
  heartbeatTimeout: 30,
  
  // 跟踪参数变化
  tracking: {
    enabled: false,
    shutdownTimeout: 5000
  },
  
  // 关闭超时
  shutdownTimeout: 5000,
  
  // 中间件
  middlewares: [
    // 自定义中间件
  ]
};

const star = new Star(options);

📚 核心概念

服务 (Service)

服务是 Node-Universe 的基本构建块,每个服务包含一组相关的动作 (Actions)。

const mathService = {
  name: 'math',
  version: '1.0.0',
  
  settings: {
    // 服务级别的设置
    precision: 2
  },
  
  actions: {
    add: {
      params: {
        a: 'number',
        b: 'number'
      },
      handler(ctx) {
        return ctx.params.a + ctx.params.b;
      }
    },
    
    divide: {
      params: {
        a: 'number',
        b: { type: 'number', min: 0.001 } // 避免除零
      },
      cache: {
        keys: ['a', 'b'],
        ttl: 60
      },
      handler(ctx) {
        const result = ctx.params.a / ctx.params.b;
        return Number(result.toFixed(this.settings.precision));
      }
    }
  },
  
  methods: {
    // 内部方法,不对外暴露
    formatNumber(num) {
      return Number(num.toFixed(this.settings.precision));
    }
  },
  
  events: {
    // 事件监听器
    'user.created'(payload, sender, eventName) {
      this.logger.info('收到用户创建事件', payload);
    }
  }
};

动作 (Actions)

动作是服务对外提供的接口,类似于 REST API 的端点。

const userService = {
  name: 'user',
  actions: {
    // 基本动作
    get: {
      params: {
        id: 'number'
      },
      handler(ctx) {
        return this.users.find(u => u.id === ctx.params.id);
      }
    },
    
    // 带缓存的动作
    list: {
      cache: true, // 使用默认缓存设置
      handler(ctx) {
        return this.users;
      }
    },
    
    // 自定义缓存配置
    search: {
      params: {
        query: 'string'
      },
      cache: {
        keys: ['query'], // 缓存键
        ttl: 300 // 5分钟过期
      },
      handler(ctx) {
        return this.users.filter(u => 
          u.name.includes(ctx.params.query)
        );
      }
    },
    
    // 流式响应
    export: {
      handler(ctx) {
        const stream = new Readable({
          objectMode: true,
          read() {}
        });
        
        // 异步发送数据
        this.users.forEach(user => {
          stream.push(user);
        });
        stream.push(null); // 结束流
        
        return stream;
      }
    }
  }
};

上下文 (Context)

上下文对象包含了动作执行所需的所有信息。

const service = {
  name: 'example',
  actions: {
    demo: {
      handler(ctx) {
        // 请求参数
        console.log('参数:', ctx.params);
        
        // 元数据 (用户信息、请求ID等)
        console.log('元数据:', ctx.meta);
        
        // 调用其他服务
        const user = await ctx.call('user.get', { id: 1 });
        
        // 发送事件
        ctx.emit('demo.executed', { userId: 1 });
        
        // 广播事件到所有节点
        ctx.broadcast('global.event', { data: 'test' });
        
        return { success: true };
      }
    }
  }
};

🎯 钩子系统 (Hooks) - AOP 支持

钩子系统提供了强大的面向切面编程能力,允许在动作执行的不同阶段插入自定义逻辑。

钩子类型

const service = {
  name: 'user',
  
  hooks: {
    // 前置钩子 - 在动作执行前运行
    before: {
      '*': ['authenticate', 'rateLimit'], // 所有动作
      'create': 'validateInput', // 特定动作
      'update': ['validateInput', 'checkPermission']
    },
    
    // 后置钩子 - 在动作成功执行后运行
    after: {
      '*': 'logAccess',
      'create': ['sendNotification', 'updateCache'],
      'delete': 'clearCache'
    },
    
    // 错误钩子 - 在动作执行出错时运行
    error: {
      '*': 'logError',
      'payment.*': 'handlePaymentError' // 支持通配符
    }
  },
  
  methods: {
    // 认证钩子
    authenticate(ctx) {
      if (!ctx.meta.user) {
        throw new Error('未授权访问');
      }
    },
    
    // 限流钩子
    rateLimit(ctx) {
      const key = `rate_limit:${ctx.meta.user.id}`;
      // 实现限流逻辑
    },
    
    // 输入验证钩子
    validateInput(ctx) {
      // 自定义验证逻辑
      if (ctx.action.name === 'create' && !ctx.params.email) {
        throw new Error('邮箱不能为空');
      }
    },
    
    // 权限检查钩子
    checkPermission(ctx) {
      const action = ctx.action.name;
      const userRole = ctx.meta.user.role;
      
      if (action === 'delete' && userRole !== 'admin') {
        throw new Error('权限不足');
      }
    },
    
    // 访问日志钩子
    logAccess(ctx, res) {
      this.logger.info('动作执行完成', {
        action: ctx.action.name,
        user: ctx.meta.user?.id,
        duration: ctx.duration,
        success: true
      });
    },
    
    // 错误处理钩子
    logError(ctx, err) {
      this.logger.error('动作执行失败', {
        action: ctx.action.name,
        error: err.message,
        stack: err.stack,
        params: ctx.params
      });
    }
  }
};

动作级别钩子

const service = {
  name: 'order',
  actions: {
    create: {
      // 动作级别的钩子
      hooks: {
        before: 'validateOrder',
        after: ['sendConfirmation', 'updateInventory'],
        error: 'rollbackOrder'
      },
      
      handler(ctx) {
        // 创建订单逻辑
        return { id: Date.now(), ...ctx.params };
      }
    }
  },
  
  methods: {
    validateOrder(ctx) {
      // 订单验证逻辑
    },
    
    sendConfirmation(ctx, result) {
      // 发送确认邮件
    },
    
    updateInventory(ctx, result) {
      // 更新库存
    },
    
    rollbackOrder(ctx, err) {
      // 回滚订单
    }
  }
};

🔄 事件系统

事件系统支持服务间的异步通信和解耦。

发送事件

const userService = {
  name: 'user',
  actions: {
    create: {
      async handler(ctx) {
        const user = await this.createUser(ctx.params);
        
        // 发送本地事件
        ctx.emit('user.created', user);
        
        // 广播到所有节点
        ctx.broadcast('user.registered', {
          userId: user.id,
          timestamp: Date.now()
        });
        
        return user;
      }
    }
  }
};

监听事件

const emailService = {
  name: 'email',
  
  events: {
    // 监听用户创建事件
    'user.created': {
      group: 'email', // 事件组,用于负载均衡
      handler(payload, sender, eventName, ctx) {
        return this.sendWelcomeEmail(payload.email);
      }
    },
    
    // 监听多个事件
    'user.*': {
      handler(payload, sender, eventName, ctx) {
        this.logger.info(`收到用户事件: ${eventName}`, payload);
      }
    },
    
    // 异步事件处理
    'order.created': {
      async handler(payload) {
        await this.processOrder(payload);
      }
    }
  },
  
  methods: {
    sendWelcomeEmail(email) {
      this.logger.info(`发送欢迎邮件到: ${email}`);
      // 实际发送邮件逻辑
    },
    
    async processOrder(order) {
      // 处理订单逻辑
    }
  }
};

🔌 中间件系统

中间件提供了扩展框架功能的机制。

内置中间件

const star = new Star({
  middlewares: [
    // 请求ID中间件
    {
      name: 'RequestID',
      localAction(handler, action) {
        return function(ctx) {
          ctx.requestID = ctx.requestID || generateUUID();
          return handler(ctx);
        };
      }
    },
    
    // 性能监控中间件
    {
      name: 'Metrics',
      localAction(handler, action) {
        return async function(ctx) {
          const start = Date.now();
          try {
            const result = await handler(ctx);
            this.metrics.increment(`action.${action.name}.success`);
            this.metrics.timing(`action.${action.name}.duration`, Date.now() - start);
            return result;
          } catch (err) {
            this.metrics.increment(`action.${action.name}.error`);
            throw err;
          }
        };
      }
    },
    
    // 缓存中间件
    {
      name: 'Cache',
      localAction(handler, action) {
        if (!action.cache) return handler;
        
        return async function(ctx) {
          const cacheKey = this.getCacheKey(action.name, ctx.params);
          
          // 尝试从缓存获取
          let result = await this.cacher.get(cacheKey);
          if (result) {
            return result;
          }
          
          // 执行动作并缓存结果
          result = await handler(ctx);
          await this.cacher.set(cacheKey, result, action.cache.ttl);
          
          return result;
        };
      }
    }
  ]
});

自定义中间件

// 自定义认证中间件
const AuthMiddleware = {
  name: 'Auth',
  
  // 本地动作中间件
  localAction(handler, action) {
    // 跳过不需要认证的动作
    if (action.auth === false) {
      return handler;
    }
    
    return async function(ctx) {
      const token = ctx.meta.authorization;
      if (!token) {
        throw new Error('缺少认证令牌');
      }
      
      try {
        const user = await this.verifyToken(token);
        ctx.meta.user = user;
        return handler(ctx);
      } catch (err) {
        throw new Error('认证失败');
      }
    };
  },
  
  // 远程调用中间件
  remoteAction(handler, action) {
    return function(ctx) {
      // 传递认证信息到远程服务
      if (ctx.meta.user) {
        ctx.meta.authorization = ctx.meta.authorization;
      }
      return handler(ctx);
    };
  },
  
  // 事件中间件
  localEvent(handler, event) {
    return function(payload, sender, eventName, ctx) {
      this.logger.debug(`处理事件: ${eventName}`, { sender, payload });
      return handler(payload, sender, eventName, ctx);
    };
  }
};

// 使用中间件
const star = new Star({
  middlewares: [AuthMiddleware]
});

🚦 错误处理

错误类型

import { 
  ValidationError, 
  ServiceNotFoundError, 
  RequestTimeoutError,
  MaxCallLevelError,
  ServiceNotAvailableError
} from 'node-universe';

const service = {
  name: 'user',
  actions: {
    create: {
      params: {
        name: 'string',
        email: 'email'
      },
      handler(ctx) {
        // 业务逻辑错误
        if (this.userExists(ctx.params.email)) {
          throw new ValidationError('用户已存在', 'USER_EXISTS', {
            email: ctx.params.email
          });
        }
        
        try {
          return this.createUser(ctx.params);
        } catch (err) {
          // 包装系统错误
          throw new Error(`创建用户失败: ${err.message}`);
        }
      }
    }
  },
  
  // 全局错误处理
  errorHandler(err, ctx) {
    if (err instanceof ValidationError) {
      this.logger.warn('验证错误', {
        action: ctx.action.name,
        error: err.message,
        data: err.data
      });
    } else {
      this.logger.error('未知错误', {
        action: ctx.action.name,
        error: err.message,
        stack: err.stack
      });
    }
    
    // 重新抛出错误
    throw err;
  }
};

熔断器

const star = new Star({
  circuitBreaker: {
    enabled: true,
    threshold: 0.5, // 50% 错误率触发熔断
    minRequestCount: 20, // 最小请求数
    windowTime: 60, // 时间窗口(秒)
    halfOpenTime: 10 // 半开状态持续时间(秒)
  }
});

// 服务级别熔断器配置
const service = {
  name: 'external-api',
  settings: {
    circuitBreaker: {
      threshold: 0.3, // 覆盖全局配置
      windowTime: 30
    }
  },
  
  actions: {
    call: {
      // 动作级别熔断器
      circuitBreaker: {
        enabled: true,
        threshold: 0.2
      },
      handler(ctx) {
        // 调用外部API
        return this.callExternalAPI(ctx.params);
      }
    }
  }
};

📊 监控和指标

内置指标

const star = new Star({
  metrics: {
    enabled: true,
    reporter: {
      type: 'Prometheus',
      options: {
        port: 3030,
        path: '/metrics'
      }
    }
  }
});

// 自定义指标
const service = {
  name: 'user',
  
  created() {
    // 注册自定义指标
    this.metrics.register({
      name: 'user_registrations_total',
      type: 'counter',
      help: '用户注册总数'
    });
    
    this.metrics.register({
      name: 'user_login_duration',
      type: 'histogram',
      help: '用户登录耗时',
      buckets: [0.1, 0.5, 1, 2, 5]
    });
  },
  
  actions: {
    register: {
      handler(ctx) {
        const user = this.createUser(ctx.params);
        
        // 增加计数器
        this.metrics.increment('user_registrations_total', {
          method: 'email'
        });
        
        return user;
      }
    },
    
    login: {
      handler(ctx) {
        const timer = this.metrics.timer('user_login_duration');
        
        try {
          const result = this.authenticateUser(ctx.params);
          timer.end({ status: 'success' });
          return result;
        } catch (err) {
          timer.end({ status: 'error' });
          throw err;
        }
      }
    }
  }
};

🔍 链路追踪

const star = new Star({
  tracing: {
    enabled: true,
    exporter: {
      type: 'Jaeger',
      options: {
        endpoint: 'http://localhost:14268/api/traces',
        serviceName: 'my-service'
      }
    },
    sampling: {
      rate: 1.0 // 100% 采样率
    }
  }
});

// 在服务中使用追踪
const service = {
  name: 'order',
  actions: {
    create: {
      async handler(ctx) {
        // 创建子span
        const span = ctx.startSpan('validate-order');
        try {
          await this.validateOrder(ctx.params);
          span.setTag('validation', 'success');
        } catch (err) {
          span.setTag('error', true);
          span.log({ error: err.message });
          throw err;
        } finally {
          span.finish();
        }
        
        // 调用其他服务会自动传播追踪上下文
        const user = await ctx.call('user.get', { id: ctx.params.userId });
        
        return this.createOrder(ctx.params, user);
      }
    }
  }
};

🏗️ 最佳实践

1. 服务设计原则

// ✅ 好的服务设计
const userService = {
  name: 'user',
  version: '1.0.0',
  
  // 明确的设置
  settings: {
    defaultFields: ['id', 'name', 'email'],
    maxPageSize: 100
  },
  
  actions: {
    // 单一职责
    get: {
      params: {
        id: 'number',
        fields: { type: 'array', optional: true }
      },
      handler(ctx) {
        const fields = ctx.params.fields || this.settings.defaultFields;
        return this.getUserById(ctx.params.id, fields);
      }
    },
    
    // 输入验证
    create: {
      params: {
        name: { type: 'string', min: 2, max: 50 },
        email: 'email',
        age: { type: 'number', min: 0, max: 150, optional: true }
      },
      handler(ctx) {
        return this.createUser(ctx.params);
      }
    }
  },
  
  methods: {
    // 可复用的方法
    getUserById(id, fields) {
      const user = this.users.find(u => u.id === id);
      if (!user) {
        throw new Error('用户不存在');
      }
      return this.selectFields(user, fields);
    },
    
    selectFields(obj, fields) {
      const result = {};
      fields.forEach(field => {
        if (obj.hasOwnProperty(field)) {
          result[field] = obj[field];
        }
      });
      return result;
    }
  }
};

2. 错误处理最佳实践

const service = {
  name: 'payment',
  
  actions: {
    process: {
      params: {
        amount: 'number',
        currency: 'string',
        cardToken: 'string'
      },
      
      async handler(ctx) {
        try {
          // 验证支付信息
          await this.validatePayment(ctx.params);
          
          // 处理支付
          const result = await this.processPayment(ctx.params);
          
          // 记录成功
          this.logger.info('支付成功', {
            amount: ctx.params.amount,
            transactionId: result.id
          });
          
          return result;
          
        } catch (err) {
          // 分类错误处理
          if (err.code === 'INSUFFICIENT_FUNDS') {
            throw new ValidationError('余额不足', err.code, {
              available: err.available,
              required: ctx.params.amount
            });
          } else if (err.code === 'CARD_DECLINED') {
            throw new ValidationError('银行卡被拒绝', err.code);
          } else {
            // 记录未知错误
            this.logger.error('支付处理失败', {
              error: err.message,
              params: ctx.params
            });
            throw new Error('支付处理失败,请稍后重试');
          }
        }
      }
    }
  }
};

3. 性能优化

const service = {
  name: 'product',
  
  actions: {
    // 使用缓存
    list: {
      cache: {
        keys: ['category', 'page', 'limit'],
        ttl: 300 // 5分钟缓存
      },
      params: {
        category: { type: 'string', optional: true },
        page: { type: 'number', default: 1, min: 1 },
        limit: { type: 'number', default: 20, min: 1, max: 100 }
      },
      handler(ctx) {
        return this.getProducts(ctx.params);
      }
    },
    
    // 批量操作
    getBatch: {
      params: {
        ids: { type: 'array', items: 'number', max: 100 }
      },
      handler(ctx) {
        // 一次查询多个产品,而不是循环调用单个查询
        return this.getProductsByIds(ctx.params.ids);
      }
    }
  },
  
  methods: {
    async getProducts({ category, page, limit }) {
      // 使用数据库分页而不是内存分页
      const offset = (page - 1) * limit;
      return this.db.products.find({
        category,
        limit,
        offset
      });
    }
  }
};

🧪 测试

单元测试

import { ServiceBroker } from 'node-universe';
import UserService from '../services/user.service';

describe('用户服务测试', () => {
  let broker;
  
  beforeAll(async () => {
    broker = new ServiceBroker({ logger: false });
    broker.createService(UserService);
    await broker.start();
  });
  
  afterAll(async () => {
    await broker.stop();
  });
  
  test('应该创建用户', async () => {
    const user = await broker.call('user.create', {
      name: 'Test User',
      email: '[email protected]'
    });
    
    expect(user).toHaveProperty('id');
    expect(user.name).toBe('Test User');
    expect(user.email).toBe('[email protected]');
  });
  
  test('应该验证邮箱格式', async () => {
    await expect(
      broker.call('user.create', {
        name: 'Test User',
        email: 'invalid-email'
      })
    ).rejects.toThrow('邮箱格式不正确');
  });
});

集成测试

import { ServiceBroker } from 'node-universe';
import UserService from '../services/user.service';
import EmailService from '../services/email.service';

describe('用户注册流程测试', () => {
  let broker;
  
  beforeAll(async () => {
    broker = new ServiceBroker({
      logger: false,
      transporter: 'fake' // 使用假传输器进行测试
    });
    
    broker.createService(UserService);
    broker.createService(EmailService);
    
    await broker.start();
  });
  
  test('用户注册应该发送欢迎邮件', async () => {
    const emailSpy = jest.spyOn(broker.getLocalService('email'), 'sendWelcomeEmail');
    
    await broker.call('user.register', {
      name: 'New User',
      email: '[email protected]'
    });
    
    // 等待事件处理
    await broker.Promise.delay(100);
    
    expect(emailSpy).toHaveBeenCalledWith('[email protected]');
  });
});

📖 API 参考

Star 类

class Star {
  constructor(options?: StarOptions);
  
  // 创建服务
  createService(schema: ServiceSchema): Service;
  
  // 启动框架
  start(): Promise<void>;
  
  // 停止框架
  stop(): Promise<void>;
  
  // 调用服务动作
  call<T = any>(actionName: string, params?: any, opts?: CallOptions): Promise<T>;
  
  // 发送事件
  emit(eventName: string, payload?: any, groups?: string[]): void;
  
  // 广播事件
  broadcast(eventName: string, payload?: any, groups?: string[]): void;
  
  // 等待服务
  waitForServices(serviceNames: string[], timeout?: number): Promise<void>;
}

服务模式

interface ServiceSchema {
  name: string;
  version?: string;
  settings?: any;
  metadata?: any;
  
  actions?: { [key: string]: ActionSchema };
  methods?: { [key: string]: Function };
  events?: { [key: string]: EventSchema };
  
  hooks?: ServiceHooks;
  
  created?(): void;
  started?(): Promise<void>;
  stopped?(): Promise<void>;
}

interface ActionSchema {
  params?: any;
  handler: ActionHandler;
  cache?: boolean | CacheOptions;
  hooks?: ActionHooks;
}

🤝 贡献

我们欢迎所有形式的贡献!请查看 贡献指南 了解详情。

开发环境设置

# 克隆仓库
git clone https://github.com/your-org/node-universe.git
cd node-universe

# 安装依赖
npm install

# 运行测试
npm test

# 构建项目
npm run build

# 运行示例
npm run example

📄 许可证

本项目采用 ISC 许可证

🔗 相关链接

❓ 常见问题

Q: 如何在生产环境中部署?

A: 推荐使用 Docker 容器化部署,配置适当的环境变量和健康检查。

FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

Q: 如何处理服务间的认证?

A: 使用 JWT 令牌在服务间传递认证信息,配合中间件进行统一处理。

Q: 如何实现服务的版本控制?

A: 在服务名称中包含版本号,如 user.v1.create,或使用服务的 version 属性。


Node-Universe - 让微服务开发变得简单而强大! 🚀