imean-service-engine
Version:
基于Hono的轻量级微服务引擎框架
2,263 lines (2,207 loc) • 85 kB
text/typescript
import { Hono, MiddlewareHandler, Context } from 'hono';
export { Context, MiddlewareHandler } from 'hono';
import * as hono_utils_html from 'hono/utils/html';
import * as hono_jsx_jsx_dev_runtime from 'hono/jsx/jsx-dev-runtime';
import { ContentfulStatusCode } from 'hono/utils/http-status';
import { z } from 'zod';
export { z } from 'zod';
/**
* 微服务引擎实现类
* @internal 此类型仅供内部使用,用户应通过 Factory.create() 创建引擎实例
*/
declare class Microservice<ModuleOptions = Record<string, any>> {
private modules;
protected plugins: Plugin<Record<string, any>>[];
protected pluginRegistry: Map<string, Plugin<Record<string, any>>>;
private moduleInstances;
readonly options: Readonly<MicroserviceOptions>;
private started;
private readonly moduleMetadataKey;
private actualPort;
private hono;
private server;
constructor(options: MicroserviceOptions, moduleMetadataKey: symbol);
/**
* 获取 Hono 实例(供插件使用)
*/
getHono(): Hono;
/**
* 内部注册插件方法(供构造函数和子类使用)
* @protected
*/
protected registerPlugin<T>(plugin: Plugin<T>): void;
/**
* 加载并注册所有模块(通过唯一的 key 查找)
* 在引擎启动时调用,使用双向访问机制查找所有被装饰的类
*
* 注意:
* - 每个引擎实例使用唯一的 moduleMetadataKey,实现隔离
* - 模块类是静态的,可以被多个引擎实例共享
* - 每个引擎实例会创建独立的模块实例,互不影响
*/
private loadModules;
/**
* 加载Handler元数据(平铺结构)
* 每个装饰器都是独立的HandlerMetadata条目
* 为每个方法创建包装链管理器,提供简单的 wrap API
*/
private loadHandlerMetadata;
/**
* 应用所有包装链到原型
* 在所有插件执行完 onHandlerLoad 后调用
*/
private applyWrapperChains;
/**
* 寻找一个随机的可用端口
*/
private getRandomPort;
/**
* 启动引擎
* @param requestedPort 启动端口(可选,默认0,表示随机端口)
* @returns 实际使用的端口号
*/
start(requestedPort?: number): Promise<number>;
/**
* 确定实际使用的端口
*/
private determinePort;
/**
* 初始化模块和插件
*/
private initializeModulesAndPlugins;
/**
* 处理 Handler 元数据和插件包装
*/
private processHandlers;
/**
* 执行插件启动钩子
*/
private executePluginStartHooks;
/**
* 注册版本路由(/prefix/version)
* 用于健康检查和探针
*/
private registerVersionRoute;
/**
* 启动 HTTP 服务器
*/
private startHttpServer;
/**
* 按优先级排序插件
*/
private sortPluginsByPriority;
/**
* 获取插件优先级
*/
private getPluginPriority;
/**
* 分离包装插件和路由插件
*/
private separateWrapperAndRoutePlugins;
/**
* 执行插件钩子(通用方法)
*/
private executePluginHook;
/**
* 停止引擎
*/
stop(): Promise<void>;
/**
* 获取模块实例(单例)
* @param moduleClass 模块类
* @returns 模块实例
*/
get<T extends Class>(moduleClass: T): InstanceType<T>;
/**
* 获取已注册的模块列表
*/
getModules(): ModuleMetadata<Record<string, any>>[];
/**
* 获取实际使用的端口
*/
getPort(): number | null;
/**
* 确保引擎已初始化(模块和处理器已加载)
* 如果引擎未启动,则执行必要的初始化步骤
*/
private ensureInitialized;
/**
* 获取模块处理器方法(不启动 HTTP 服务器)
* 适用于测试场景,可以完整执行中间件和处理逻辑
*
* 返回一个已绑定模块和方法名的调用函数,调用时只需要传递方法参数
* 类型推导:自动推导方法参数类型和返回值类型(无需显式指定泛型参数)
*
* @param moduleClass 模块类
* @param methodName 方法名(handler 名称)
* @returns 调用函数,只需要传递方法参数
*
* @example
* ```typescript
* @Module("users")
* class UserService {
* @Action({ params: [z.string(), z.number()] })
* add(a: string, b: number): { result: number } {
* return { result: Number(a) + b };
* }
*
* @Action({ params: [z.string()] })
* getUser(id: string): Promise<{ id: string; name: string }> {
* return Promise.resolve({ id, name: "Alice" });
* }
* }
*
* // 获取 handler 并调用(类型自动推导,无需显式指定泛型)
* const addHandler = engine.handler(UserService, "add");
* const result1 = await addHandler("10", 20);
* // result1 的类型是 { result: number }
*
* // 也可以链式调用
* const result2 = await engine.handler(UserService, "getUser")("123");
* // result2 的类型是 { id: string; name: string }(自动解包 Promise)
* ```
*/
handler<T extends Class, M extends keyof InstanceType<T> & string>(moduleClass: T, methodName: M): (...args: InstanceType<T>[M] extends (...args: infer P) => any ? P : never) => Promise<InstanceType<T>[M] extends (...args: any[]) => infer R ? R extends Promise<infer U> ? U : R : never>;
/**
* 使用 Hono 的 request 方法调用路由处理器(不启动 HTTP 服务器)
* 适用于测试场景,可以完整执行中间件和处理逻辑
*
* @param input Request 对象、URL 字符串或相对路径
* @param init RequestInit 选项(当 input 是字符串时使用)
* @returns Response 对象
*
* @example
* ```typescript
* // 使用相对路径
* const response = await engine.request("/api/users/123");
*
* // 使用完整 URL
* const response = await engine.request("http://localhost/api/users/123");
*
* // 使用 Request 对象
* const request = new Request("http://localhost/api/users/123", {
* method: "POST",
* headers: { "Content-Type": "application/json" },
* body: JSON.stringify({ name: "Alice" }),
* });
* const response = await engine.request(request);
* ```
*/
request(input: RequestInit | URL | string, init?: RequestInit): Promise<Response>;
}
/**
* 核心类型定义
*/
type Class = new (...args: any[]) => any;
/**
* 插件Module配置Schema(运行时+类型双维度)
*/
interface PluginModuleOptionsSchema<T = Record<string, any>> {
_type: T;
validate?: (options: T) => boolean | string;
}
/**
* 插件优先级
* 数值越小,优先级越高(越先执行)
* 引擎会自动按优先级排序,用户无需关心注册顺序
*/
declare enum PluginPriority {
/**
* 系统级优先级:系统核心功能插件(优雅停机等)
* 最高优先级,应该最先执行
*/
SYSTEM = 50,
/**
* 最高优先级:安全相关插件(限流、认证等)
* 应该最先执行,快速拒绝无效请求
*/
SECURITY = 100,
/**
* 高优先级:日志、监控等插件
* 记录所有请求,包括被安全插件拒绝的
*/
LOGGING = 200,
/**
* 中优先级:业务逻辑插件(数据转换等)
* 在安全和日志之后执行
*/
BUSINESS = 300,
/**
* 低优先级:性能优化插件(缓存等)
* 在业务逻辑之后执行,避免重复计算
*/
PERFORMANCE = 400,
/**
* 最低优先级:路由插件
* 必须最后执行,注册HTTP路由
*/
ROUTE = 1000
}
/**
* 核心插件接口
*/
interface Plugin<TModuleOptions = Record<string, any>> {
name: string;
/**
* 插件优先级(可选)
* 如果不指定,默认为 PluginPriority.BUSINESS
* 引擎会自动按优先级排序,用户无需关心注册顺序
*
* 优先级规则:
* - 数值越小,优先级越高(越先执行)
* - 相同优先级按注册顺序执行
*/
priority?: PluginPriority | number;
getModuleOptionsSchema?: () => PluginModuleOptionsSchema<TModuleOptions>;
onInit?: (engine: Microservice) => void;
onModuleLoad?: (modules: ModuleMetadata[]) => void;
onHandlerLoad?: (handlers: HandlerMetadata[]) => void;
onBeforeStart?: (engine: Microservice) => void;
onAfterStart?: (engine: Microservice) => void | Promise<void>;
onDestroy?: () => void | Promise<void>;
}
/**
* 引擎创建选项
*/
interface MicroserviceOptions {
name: string;
version: string;
hostname?: string;
prefix?: string;
}
/**
* Module装饰器类型(由引擎实例创建,自动推导类型)
* 使用最新的 Stage 3 装饰器标准
*/
type ModuleDecorator<TOptions = Record<string, any>> = (name: string, options?: TOptions) => (target: Class, context: ClassDecoratorContext) => void;
/**
* 模块元数据
*/
interface ModuleMetadata<TOptions = Record<string, any>> {
name: string;
clazz: Class;
options: TOptions;
}
/**
* Handler包装函数类型
* 插件只需要提供这个函数,引擎自动管理包装链
*
* @param next 调用下一个包装层或原始方法
* @param instance 模块实例
* @param args 方法参数
* @returns 方法执行结果
*/
type HandlerWrapper = (next: () => Promise<any> | any, instance: any, ...args: any[]) => Promise<any> | any;
/**
* Handler元数据(单组元数据)
* 提供简单的 wrap API,引擎自动管理包装链和执行顺序
*/
interface HandlerMetadata {
type: string;
options: Record<string, any>;
method: Function;
methodName: string;
module: Class;
/**
* 包装当前方法(引擎自动管理包装链)
*
* 插件只需要调用这个方法,引擎会自动:
* - 按插件优先级构建包装链
* - 确保 RoutePlugin 最后执行
* - 自动应用包装到原型
*
* @param wrapper 包装函数
* - next: 调用下一个包装层或原始方法
* - instance: 模块实例
* - args: 方法参数
*
* @example
* ```typescript
* handler.wrap(async (next, instance, ...args) => {
* // 前置逻辑
* const result = await next();
* // 后置逻辑
* return result;
* });
* ```
*/
wrap(wrapper: HandlerWrapper): void;
}
/**
* Stage 3 装饰器上下文类型
*/
type ClassDecoratorContext = {
kind: "class";
name: string | undefined;
addInitializer(initializer: () => void): void;
};
type ClassMethodDecoratorContext$1 = {
kind: "method";
name: string | symbol;
static: boolean;
private: boolean;
addInitializer(initializer: () => void): void;
};
/**
* 通用Handler装饰器(支持多应用)
* 使用最新的 Stage 3 装饰器标准
*
* @param config Handler配置
* @returns 方法装饰器
*/
declare function Handler<T = Record<string, any>>(config: {
type: string;
options?: T;
}): (target: Function, context: ClassMethodDecoratorContext) => void;
/**
* 核心异常类型定义
*/
declare class PluginNameRequiredError extends Error {
constructor(pluginName?: string);
}
declare class ModuleConfigValidationError extends Error {
constructor(moduleName: string, pluginName: string, message: string);
}
declare class DuplicateModuleError extends Error {
constructor(moduleName: string);
}
interface PreStartChecker {
name: string;
check: () => Promise<void> | void;
skip?: boolean;
}
declare function startCheck(checkers: PreStartChecker[], pass?: () => void | Promise<void>): Promise<void>;
declare const BaseLayout: (props?: {
children?: any;
title?: string;
heads?: any;
}) => hono_utils_html.HtmlEscapedString | Promise<hono_utils_html.HtmlEscapedString>;
declare const HtmxLayout: (props?: {
children?: any;
title: string;
favicon?: any;
}) => hono_utils_html.HtmlEscapedString | Promise<hono_utils_html.HtmlEscapedString>;
/**
* 服务状态信息接口
* 基于 MicroserviceOptions,并添加运行时信息
*/
interface ServiceStatusInfo {
name: string;
version: string;
prefix?: string;
hostname?: string;
port?: number;
env?: string;
status?: string;
}
declare const ServiceInfoCards: ({ serviceInfo, }: {
serviceInfo: ServiceStatusInfo;
}) => hono_jsx_jsx_dev_runtime.JSX.Element;
declare const ServiceStatusPage: ({ serviceInfo, }: {
serviceInfo: ServiceStatusInfo;
}) => hono_jsx_jsx_dev_runtime.JSX.Element;
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
/**
* Route装饰器配置选项
*/
interface RouteOptions {
/**
* HTTP方法(可选,默认为 GET)
* 如果未指定,则默认为 GET 方法
*/
method?: HTTPMethod | HTTPMethod[];
/**
* 路由路径(支持单个路径或多个路径)
* 如果提供数组,将为每个路径注册相同的处理器
*/
path: string | string[];
/**
* 路由专属中间件
*/
middlewares?: MiddlewareHandler[];
/**
* 路由描述(用于文档和日志)
*/
description?: string;
/**
* 请求参数校验规则
*/
validate?: {
query?: Record<string, any>;
body?: Record<string, any>;
params?: Record<string, any>;
};
/**
* 响应配置
*/
response?: {
status?: ContentfulStatusCode;
type?: "json" | "text" | "html";
};
}
/**
* RoutePlugin的Module配置
* 注意:配置直接平铺在 Module options 中,不使用 route 命名空间
* 插件作者需要确保字段名不与其他插件冲突
*/
interface RouteModuleOptions {
routePrefix?: string;
routeMiddlewares?: MiddlewareHandler[];
}
/**
* 错误转换函数
* 当路由处理器抛出异常时,可以自定义错误响应格式
* @param ctx Hono Context 对象
* @param error 捕获到的错误对象
* @param handler Handler 元数据,包含路由信息、方法名等
* @returns Response 对象或可序列化的值(会被自动转换为 Response)
*/
type ErrorTransformer = (ctx: Context, error: unknown, handler: HandlerMetadata) => Response | Promise<Response>;
/**
* RoutePlugin 配置选项
*/
interface RoutePluginOptions {
/**
* 全局路径前缀(应用于所有路由)
* 路径拼接顺序:全局前缀 + 模块前缀 + 路由路径
* 例如:prefix="/api", routePrefix="/v1", path="/users" => "/api/v1/users"
*/
prefix?: string;
/**
* 全局中间件(应用于所有路由)
* 执行顺序:全局中间件 -> 模块级中间件 -> 路由级中间件
* 常用于鉴权、日志等全局功能
*/
globalMiddlewares?: MiddlewareHandler[];
/**
* 错误转换函数(可选)
* 当路由处理器抛出异常时,可以自定义错误响应格式
* 如果不提供,将使用默认的错误响应格式
*/
errorTransformer?: ErrorTransformer;
}
/**
* Route装饰器(Handler的语法糖封装)
* 固定type="route",简化HTTP路由标注
* 使用最新的 Stage 3 装饰器标准
*
* @example
* ```typescript
* @Route({ method: "GET", path: "/users" })
* async getUsers(ctx: Context) {
* return ctx.json({ users: [] });
* }
*
* // 支持多个路径
* @Route({ path: ["/", "/home", "/dashboard"] })
* async homePage(ctx: Context) {
* return <HomePage />;
* }
* ```
*/
declare function Route(options: RouteOptions): (target: Function, context: ClassMethodDecoratorContext) => void;
/**
* Page装饰器(Route的别名,用于向后兼容)
* 专门用于页面路由,默认使用 GET 方法
*
* @example
* ```typescript
* @Page({ path: ["/", "/home"] })
* async adminPage(ctx: Context) {
* return HtmxLayout({ title: "Admin", children: <AdminLayout /> });
* }
* ```
*/
declare function Page(options: RouteOptions): (target: Function, context: ClassMethodDecoratorContext) => void;
/**
* RoutePlugin - 核心路由插件
* 负责解析type="route"的Handler元数据,注册HTTP路由到Hono实例
*
* @example
* ```typescript
* // 使用全局前缀和中间件
* const authMiddleware = async (ctx, next) => {
* // 验证 token
* await next();
* };
*
* const routePlugin = new RoutePlugin({
* prefix: "/api", // 全局路径前缀,所有路由都会加上这个前缀
* globalMiddlewares: [authMiddleware],
* });
* ```
*/
declare class RoutePlugin implements Plugin<RouteModuleOptions> {
readonly name = "route-plugin";
readonly priority = PluginPriority.ROUTE;
private engine;
private globalPrefix;
private globalMiddlewares;
private errorTransformer?;
/**
* 构造函数
* @param options 插件配置选项
*/
constructor(options?: RoutePluginOptions);
/**
* 声明Module配置Schema(用于类型推导+运行时校验)
*/
getModuleOptionsSchema(): PluginModuleOptionsSchema<RouteModuleOptions>;
/**
* 引擎初始化钩子:获取Hono实例
*/
onInit(engine: Microservice): void;
/**
* Handler加载钩子:解析type="route"的Handler元数据,注册HTTP路由
*/
onHandlerLoad(handlers: HandlerMetadata[]): void;
}
/**
* Action装饰器配置选项
*/
interface ActionOptions {
/**
* 动作描述
*/
description?: string;
/**
* 参数校验 Schema(使用 zod)
* 数组顺序对应方法参数的顺序
*/
params: z.ZodTypeAny[];
/**
* 返回值校验 Schema(使用 zod)
*/
returns?: z.ZodTypeAny;
/**
* 是否流式返回(默认 false)
*/
stream?: boolean;
/**
* 是否幂等(默认 false)
*/
idempotence?: boolean;
/**
* 路由专属中间件
*/
middlewares?: MiddlewareHandler[];
}
/**
* ActionPlugin的Module配置
*/
interface ActionModuleOptions {
/**
* 模块级路由中间件
*/
actionMiddlewares?: MiddlewareHandler[];
}
/**
* ActionPlugin - 动作处理插件
* 提供基于下标的参数传递、zod 校验和自动参数注入
*/
declare class ActionPlugin implements Plugin<ActionModuleOptions> {
readonly name = "action-plugin";
readonly priority = PluginPriority.ROUTE;
private engine;
/**
* 声明Module配置Schema(用于类型推导+运行时校验)
*/
getModuleOptionsSchema(): PluginModuleOptionsSchema<ActionModuleOptions>;
/**
* 引擎初始化钩子:获取Hono实例
*/
onInit(engine: Microservice): void;
/**
* Handler加载钩子:解析type="action"的Handler元数据,注册HTTP路由
*/
onHandlerLoad(handlers: HandlerMetadata[]): void;
}
/**
* Action装饰器(Handler的语法糖封装)
* 固定type="action",用于标注动作处理方法
*/
declare function Action(options: ActionOptions): (target: Function, context: ClassMethodDecoratorContext) => void;
/**
* Cache装饰器配置选项
*/
interface CacheOptions {
/**
* 缓存失效时间(毫秒)
* 默认:60000 (1分钟)
*/
ttl?: number;
/**
* 缓存键生成函数
* 函数签名应该和处理器方法一样,接收相同的参数
* 可以返回任意值,返回值会被 ejson 序列化后进行 hash 生成缓存键
* 如果不提供,将使用入参(args)进行相同的计算
*
* @example
* ```typescript
* @Cache({
* key: (id: string, name: string) => ({ id, name }), // 返回对象
* ttl: 5000
* })
* async getUser(id: string, name: string) {
* return { id, name };
* }
* ```
*/
key?: (...args: any[]) => any;
/**
* 是否启用缓存
* 默认:true
*/
enabled?: boolean;
}
/**
* CachePlugin的Module配置
* 注意:配置直接平铺在 Module options 中
*/
interface CacheModuleOptions {
/**
* 默认缓存失效时间(毫秒)
* 默认:60000 (1分钟)
*/
cacheDefaultTtl?: number;
/**
* 是否启用全局缓存
* 默认:true
*/
cacheEnabled?: boolean;
/**
* 缓存清理间隔(毫秒)
* 默认:60000 (1分钟)
*/
cacheCleanupInterval?: number;
}
/**
* 缓存项数据结构
*/
interface CacheItem<T = any> {
value: T;
expiresAt: number;
createdAt: number;
}
/**
* Cache Adapter 接口
* 定义缓存存储的抽象接口,支持不同的存储后端
*/
/**
* 缓存适配器接口
*/
interface CacheAdapter {
/**
* 获取缓存项
* @param key 缓存键
* @returns 缓存项,如果不存在或已过期则返回 null
*/
get<T = any>(key: string): Promise<CacheItem<T> | null>;
/**
* 设置缓存项
* @param key 缓存键
* @param item 缓存项
*/
set<T = any>(key: string, item: CacheItem<T>): Promise<void>;
/**
* 删除缓存项
* @param key 缓存键
* @returns 是否删除成功
*/
delete(key: string): Promise<boolean>;
/**
* 清空所有缓存
*/
clear(): Promise<void>;
/**
* 获取所有缓存键(用于统计)
* @returns 缓存键数组(不包含过期项)
*/
keys(): Promise<string[]>;
/**
* 清理所有过期项(高效批量清理)
* @returns 清理的过期项数量
*/
cleanupExpired?(): Promise<number>;
/**
* 获取缓存统计信息
*/
getStats(): Promise<{
size: number;
entries: Array<{
key: string;
expiresAt: number;
createdAt: number;
}>;
}>;
}
/**
* 内存缓存适配器
* 使用 Map 存储,适合单进程应用
*
* 注意:过期项会在以下情况被自动清理:
* 1. get() 时检查并删除过期项
* 2. keys() 和 getStats() 会过滤过期项
* 3. 建议通过 CachePlugin 的定期清理机制主动清理过期项
*/
declare class MemoryCacheAdapter implements CacheAdapter {
private cache;
get<T = any>(key: string): Promise<CacheItem<T> | null>;
set<T = any>(key: string, item: CacheItem<T>): Promise<void>;
delete(key: string): Promise<boolean>;
clear(): Promise<void>;
keys(): Promise<string[]>;
/**
* 清理所有过期项(高效批量清理)
* 这个方法比通过 keys() + get() + delete() 更高效
*/
cleanupExpired(): Promise<number>;
getStats(): Promise<{
size: number;
entries: Array<{
key: string;
expiresAt: number;
createdAt: number;
}>;
}>;
}
/**
* Redis 缓存适配器配置
*/
interface RedisCacheAdapterOptions {
/**
* Redis 客户端实例(需要实现基本的 get/set/del/keys 方法)
* 可以是 ioredis、node-redis 等
*/
client: {
get(key: string): Promise<string | null>;
set(key: string, value: string, expiryMode?: string, time?: number): Promise<string | null>;
del(key: string): Promise<number>;
keys(pattern: string): Promise<string[]>;
};
/**
* 键前缀,用于区分不同应用的缓存
* 默认:'cache:'
*/
keyPrefix?: string;
}
/**
* Redis 缓存适配器
* 使用 Redis 作为存储后端,适合分布式应用
*
* 注意:Redis 本身支持 TTL(Time To Live),过期键会自动删除,
* 因此不需要手动清理过期项。当使用 SET key value EX seconds 时,
* Redis 会在过期后自动删除键。
*/
declare class RedisCacheAdapter implements CacheAdapter {
private client;
private keyPrefix;
constructor(options: RedisCacheAdapterOptions);
private getKey;
get<T = any>(key: string): Promise<CacheItem<T> | null>;
set<T = any>(key: string, item: CacheItem<T>): Promise<void>;
delete(key: string): Promise<boolean>;
clear(): Promise<void>;
keys(): Promise<string[]>;
/**
* 清理所有过期项
*
* 注意:Redis 本身支持自动过期(通过 SET key value EX seconds),
* 过期键会被 Redis 自动删除。但在某些情况下(如测试环境、某些 Redis 客户端),
* 可能需要手动清理。此方法会检查并清理:
* 1. 已过期但尚未被 Redis 删除的键(双重保险)
* 2. JSON 解析失败的数据
*/
cleanupExpired(): Promise<number>;
getStats(): Promise<{
size: number;
entries: Array<{
key: string;
expiresAt: number;
createdAt: number;
}>;
}>;
}
/**
* CachePlugin - 缓存插件
* 负责为标记了 @Cache 装饰器的方法提供缓存功能
*
* @example
* ```ts
* // 使用内存缓存(默认)
* const cachePlugin = new CachePlugin();
*
* // 使用自定义适配器
* const cachePlugin = new CachePlugin(new MemoryCacheAdapter());
*
* // 使用 Redis 适配器
* import { RedisCacheAdapter } from "./adapter";
* const cachePlugin = new CachePlugin(new RedisCacheAdapter({ client: redisClient }));
* ```
*/
declare class CachePlugin implements Plugin<CacheModuleOptions> {
readonly name = "cache-plugin";
readonly priority = PluginPriority.PERFORMANCE;
private adapter;
private cleanupTimer;
private engine;
private defaultTtl;
private cacheEnabled;
private cleanupInterval;
/**
* 构造函数
* @param adapter 缓存适配器,如果不提供则使用默认的内存缓存适配器
*/
constructor(adapter?: CacheAdapter);
/**
* 声明Module配置Schema
*/
getModuleOptionsSchema(): PluginModuleOptionsSchema<CacheModuleOptions>;
/**
* 引擎初始化前钩子
*/
onInit(engine: Microservice): void;
/**
* Handler加载后钩子
* 拦截带有 type="cache" 的 Handler,包装原始方法实现缓存逻辑
*/
onHandlerLoad(handlers: HandlerMetadata[]): void;
/**
* 引擎启动前钩子
*/
onBeforeStart(engine: Microservice): void;
/**
* 引擎停止时钩子
*/
onDestroy(): Promise<void>;
/**
* 生成缓存键
* @param moduleName 模块名
* @param methodName 方法名
* @param keyFunction 可选的 key 函数
* @param args 方法参数
* @returns 缓存键(格式:模块名:方法名:hash)
*/
private generateCacheKey;
/**
* 清理过期缓存
*/
private cleanup;
/**
* 获取缓存统计信息
*/
getStats(): Promise<{
size: number;
entries: Array<{
key: string;
expiresAt: number;
createdAt: number;
}>;
}>;
/**
* 清空所有缓存
*/
clear(): Promise<void>;
/**
* 删除指定的缓存项
*/
delete(key: string): Promise<boolean>;
}
/**
* Cache装饰器
* 用于标记需要缓存的方法
*
* @example
* ```typescript
* @Cache({ ttl: 5000 })
* async getUser(id: number) {
* return { id, name: "John" };
* }
* ```
*/
declare function Cache(options?: CacheOptions): (target: Function, context: ClassMethodDecoratorContext) => void;
/**
* 优雅停机插件配置选项
*/
interface GracefulShutdownPluginOptions {
/**
* 停机超时时间(毫秒)
* 默认:10分钟(600000ms)
*/
shutdownTimeout?: number;
/**
* 是否启用优雅停机
* 默认:true
*/
enabled?: boolean;
}
/**
* 优雅停机插件
*
* 功能:
* 1. 追踪所有处理器的执行状态(包括 Action、Route、Schedule 等)
* 2. 监听系统停机信号(SIGINT、SIGTERM 等)
* 3. 收到信号后,等待所有正在执行的处理器完成
* 4. 如果超时或所有处理完成,执行优雅停机
*
* @example
* ```typescript
* // 使用默认配置(10分钟超时)
* const gracefulShutdownPlugin = new GracefulShutdownPlugin();
*
* // 自定义超时时间(5分钟)
* const gracefulShutdownPlugin = new GracefulShutdownPlugin({
* shutdownTimeout: 5 * 60 * 1000, // 5分钟
* });
* ```
*/
declare class GracefulShutdownPlugin implements Plugin {
readonly name = "graceful-shutdown-plugin";
readonly priority = PluginPriority.SYSTEM;
private engine;
private options;
private activeHandlers;
private isShuttingDown;
private shutdownTimer;
private signalListeners;
constructor(options?: GracefulShutdownPluginOptions);
/**
* 引擎初始化钩子
*/
onInit(engine: Microservice): void;
/**
* Handler加载钩子:拦截所有处理器,追踪执行状态
*/
onHandlerLoad(handlers: HandlerMetadata[]): void;
/**
* 引擎启动后钩子:注册系统信号监听器
*/
onAfterStart(engine: Microservice): Promise<void>;
/**
* 注册系统信号监听器
*/
private registerSignalHandlers;
/**
* 增加活跃处理器计数
*/
private incrementActiveHandlers;
/**
* 减少活跃处理器计数
*/
private decrementActiveHandlers;
/**
* 启动优雅停机流程
*/
private initiateShutdown;
/**
* 完成停机流程
*/
private completeShutdown;
/**
* 清理信号监听器
*/
private cleanupSignalHandlers;
/**
* 引擎销毁钩子:清理资源
*/
onDestroy(): Promise<void>;
/**
* 获取当前活跃处理器数量(用于测试和监控)
*/
getActiveHandlersCount(): number;
/**
* 检查是否正在停机(用于测试和监控)
*/
isShuttingDownNow(): boolean;
}
/**
* 调度模式
*/
declare enum ScheduleMode {
/**
* 固定频率模式:无论任务执行时间多长,都会按照固定间隔执行
* 例如:每 5 秒执行一次,即使上次任务执行了 10 秒
*/
FIXED_RATE = "FIXED_RATE",
/**
* 固定延迟模式:任务执行完成后,等待固定间隔再执行下一次
* 例如:任务执行了 10 秒,间隔 5 秒,则下次执行在 15 秒后
*/
FIXED_DELAY = "FIXED_DELAY"
}
/**
* 调度选项
*/
interface ScheduleOptions {
/**
* 执行间隔(毫秒)
*/
interval: number;
/**
* 调度模式(默认 FIXED_RATE)
*/
mode?: ScheduleMode;
}
/**
* 调度元数据
*/
interface ScheduleMetadata {
/**
* 方法名称
*/
name: string;
/**
* 执行间隔(毫秒)
*/
interval: number;
/**
* 调度模式
*/
mode: ScheduleMode;
}
/**
* SchedulePlugin 配置选项
*/
interface SchedulePluginOptions {
/**
* Etcd3 客户端实例
* 如果未提供且 useMockEtcd 为 false,插件将不会启动调度任务
*/
etcdClient?: Etcd3;
/**
* 是否使用 Mock Etcd(用于测试和本地开发)
* 当设置为 true 时,将使用内置的 MockEtcd3,始终选举自己作为 leader
* 这样可以在没有真实 etcd 的情况下运行调度任务
*
* @default false
*/
useMockEtcd?: boolean;
}
/**
* Etcd3 类型定义(避免直接依赖 etcd3 包)
*/
interface Etcd3 {
election(key: string, ttl: number): Election;
}
interface Election {
observe(): Promise<Observer>;
campaign(candidate: string): Campaign;
}
interface Observer {
on(event: "change", callback: (leader: string) => void): void;
}
interface Campaign {
on(event: "error", callback: (error: any) => void): void;
on(event: "elected", callback: () => void): void;
resign(): Promise<void>;
}
/**
* Schedule装饰器
* 用于标记需要定时调度的方法
*
* @example
* ```typescript
* @Schedule({ interval: 5000, mode: ScheduleMode.FIXED_RATE })
* async syncData() {
* // 定时执行的任务
* }
* ```
*/
declare function Schedule(options: ScheduleOptions): (target: Function, context: ClassMethodDecoratorContext) => void;
/**
* SchedulePlugin - 调度任务插件
* 使用 etcd 选举机制实现分布式定时任务,确保多个实例中只有一个执行任务
*/
declare class SchedulePlugin implements Plugin {
readonly name = "schedule-plugin";
readonly priority = PluginPriority.BUSINESS;
private engine;
private scheduler;
private etcdClient;
private scheduleHandlers;
private useMockEtcd;
constructor(options?: SchedulePluginOptions);
/**
* 引擎初始化钩子
*/
onInit(engine: Microservice): void;
/**
* Handler加载钩子:收集所有调度任务
*/
onHandlerLoad(handlers: HandlerMetadata[]): void;
/**
* 引擎启动后钩子:启动所有调度任务
*/
onAfterStart(engine: Microservice): Promise<void>;
/**
* 引擎销毁钩子:停止所有调度任务
*/
onDestroy(): Promise<void>;
}
/**
* 调度器类
* 负责管理基于 etcd 选举的分布式定时任务
*/
declare class Scheduler {
private etcdClient;
private campaigns;
private timers;
private isLeader;
constructor(etcdClient: Etcd3);
/**
* 启动调度任务
*/
startSchedule(serviceId: string, moduleName: string, methodName: string, electionKey: string, metadata: ScheduleMetadata, method: Function): Promise<void>;
/**
* 启动定时器
*/
private startTimer;
/**
* 停止定时器
*/
private stopTimer;
/**
* 停止所有调度任务
*/
stop(): Promise<void>;
}
/**
* Mock Etcd3 客户端
* 用于测试和本地开发,模拟 etcd 的选举机制
* 始终选举第一个参与选举的候选者作为 leader
*/
declare class MockEtcd3 implements Etcd3 {
private elections;
election(key: string, ttl: number): Election;
getElection(key: string): MockElection | undefined;
clearElections(): void;
}
/**
* Mock Election
*/
declare class MockElection implements Election {
private key;
private observers;
private campaigns;
private currentLeader;
constructor(key: string);
observe(): Promise<Observer>;
campaign(candidate: string): Campaign;
setLeader(leader: string): void;
getCurrentLeader(): string | null;
}
/**
* ClientCodePlugin 配置选项
*/
interface ClientCodePluginOptions {
/**
* 客户端代码保存路径(可选)
* 如果设置,将在生成代码后自动保存到该路径
* 通常用于开发阶段自动生成客户端代码用于调试或测试
*
* @example
* ```ts
* new ClientCodePlugin({ clientSavePath: "./generated/client.ts" })
* ```
*/
clientSavePath?: string;
}
/**
* ClientCodePlugin - 客户端代码生成插件
* 收集所有 Action handlers,生成类型化的客户端代码,
* 并提供 /client.ts 路由供远程下载
*/
declare class ClientCodePlugin implements Plugin {
readonly name = "client-code-plugin";
readonly priority = PluginPriority.ROUTE;
private engine;
private actionHandlers;
private generatedCode;
private readonly clientSavePath?;
constructor(options?: ClientCodePluginOptions);
/**
* 引擎初始化钩子
*/
onInit(engine: Microservice): void;
/**
* Handler加载钩子:收集所有 Action handlers
*/
onHandlerLoad(handlers: HandlerMetadata[]): void;
/**
* 引擎启动后钩子:注册客户端代码下载路由
*/
onAfterStart(engine: Microservice): Promise<void>;
/**
* 生成客户端代码
*/
private generateCode;
/**
* 保存代码到文件
*/
private saveCodeToFile;
}
/**
* Action 信息(用于生成客户端代码)
*/
interface ActionInfo {
/**
* 动作描述
*/
description?: string;
/**
* 参数校验 Schema(使用 zod)
*/
params: z.ZodTypeAny[];
/**
* 返回值校验 Schema(使用 zod)
*/
returns?: z.ZodTypeAny;
/**
* 是否流式返回(默认 false)
*/
stream?: boolean;
/**
* 是否幂等(默认 false)
*/
idempotence?: boolean;
/**
* 参数名称数组(从方法定义中提取)
*/
paramNames?: string[];
}
/**
* 模块信息(用于生成客户端代码)
*/
interface ModuleInfo {
/**
* 模块名称
*/
name: string;
/**
* 模块的所有 actions
*/
actions: Record<string, ActionInfo>;
}
/**
* 获取 Zod 类型的 TypeScript 类型字符串
*/
declare function getZodTypeString(schema: z.ZodType<any>, defaultOptional?: boolean): string;
/**
* 生成客户端代码
* @param modules 模块信息
* @returns 生成的客户端代码
*/
declare function generateClientCode(modules: Record<string, ModuleInfo>): Promise<string>;
/**
* 将 HandlerMetadata 数组转换为 ModuleInfo 格式
* @param handlers Action handlers
* @returns 模块信息映射
*/
declare function convertHandlersToModuleInfo(handlers: HandlerMetadata[]): Record<string, ModuleInfo>;
/**
* 从引擎获取模块信息并转换为 ModuleInfo 格式
* @param handlers Action handlers
* @param getModuleMetadata 获取模块元数据的函数
* @returns 模块信息映射
*/
declare function convertHandlersToModuleInfoWithMetadata(handlers: HandlerMetadata[], getModuleMetadata: (moduleClass: any) => {
name: string;
} | undefined): Record<string, ModuleInfo>;
/**
* HtmxAdminPlugin 类型定义
*/
/**
* 导航项配置
*/
interface NavItemConfig {
/** 导航标签 */
label: string;
/** 导航图标 */
icon?: string;
/** 自定义路径 */
href: string;
/** 嵌套子路由 */
children?: NavItemConfig[];
}
/**
* 用户信息接口
*/
interface UserInfo {
name?: string;
avatar?: string;
email?: string;
[key: string]: any;
}
/**
* 模块类型信息
*/
interface ModuleTypeInfo {
/** 模块标题 */
title: string;
/** 模块描述 */
description: string;
/** 模块基础路径 */
basePath: string;
/** 是否有 list 类型的模块 */
hasList: boolean;
/** 是否有 detail 类型的模块 */
hasDetail: boolean;
/** 是否有 form 类型的模块 */
hasForm: boolean;
/** 是否有 custom 类型的模块 */
hasCustom: boolean;
}
/**
* 面包屑项
*/
interface BreadcrumbItem {
label: string;
href?: string;
}
/**
* 站点配置选项
*/
interface HtmxAdminPluginOptions {
/** 站点标题 */
title?: string;
/** 站点 Logo URL(可选) */
logo?: string;
/** 管理后台路径前缀(默认 /admin) */
prefix?: string;
/** 首页路径(访问插件默认路径时重定向到此路径,如果未配置则使用第一个模块的路径) */
homePath?: string;
/** 导航配置(集中式声明导航结构,支持嵌套) */
navigation?: NavItemConfig[];
/** 获取用户信息的函数(用于显示用户信息) */
getUserInfo?: (ctx: Context) => UserInfo | null | Promise<UserInfo | null>;
}
/**
* 模块类型
*/
type ModuleType = "list" | "detail" | "form" | "custom";
/**
* 模块配置选项
* 通用配置放在这里,不同类型页面的差异配置通过类来实现
*/
interface HtmxAdminModuleOptions {
type: ModuleType;
title?: string;
description?: string;
}
/**
* 列表数据源接口(仅用于 list 类型)
*/
interface ListDatasource<T = any> {
/** 获取列表数据 */
getList(params: ListParams): Promise<ListResult<T>>;
/** 删除数据(可选,如果不提供则列表页不显示删除操作) */
deleteItem?(id: string | number): Promise<boolean>;
}
/**
* 详情数据源接口(仅用于 detail 类型)
*/
interface DetailDatasource<T = any> {
/** 获取单条数据 */
getItem(id: string | number): Promise<T | null>;
/** 删除数据(可选) */
deleteItem?(id: string | number): Promise<boolean>;
}
/**
* 表单数据源接口(仅用于 form 类型)
*/
interface FormDatasource<T = any> {
/** 获取单条数据(编辑时使用) */
getItem?(id: string | number): Promise<T | null>;
/** 更新数据 */
updateItem?(id: string | number, data: Partial<T>): Promise<T | null>;
/** 创建数据 */
createItem?(data: Partial<T>): Promise<T>;
}
/**
* 列表查询参数
*/
interface ListParams {
/** 页码(从1开始) */
page?: number;
/** 每页数量 */
pageSize?: number;
/** 排序字段 */
sortBy?: string;
/** 排序方向 */
sortOrder?: "asc" | "desc";
/** 筛选条件 */
filters?: Record<string, any>;
}
/**
* 列表查询结果
*/
interface ListResult<T> {
/** 数据列表 */
items: T[];
/** 总数量 */
total: number;
/** 当前页码 */
page: number;
/** 每页数量 */
pageSize: number;
/** 总页数 */
totalPages: number;
}
/**
* Action Helper - 简化操作按钮定义
*/
/**
* Action Helper 类
* 提供便捷的方法来定义操作按钮,隐藏路径规则的具体实现
*/
declare class PathHelper {
private basePath;
constructor(basePath: string);
/**
* 详情页动作
* 生成路径: {basePath}/detail/{id}
* @param label 按钮标签
* @param dialog 是否在对话框中打开
*/
detail(id: string | number, dialog?: boolean): string;
/**
* 编辑页动作
* 生成路径: {basePath}/edit/{id}
* @param dialog 是否在对话框中打开
*/
edit(id: string | number, dialog?: boolean): string;
/**
* 删除动作
* 生成路径: {basePath}/detail/{id},方法: DELETE
*/
delete(id: string | number): string;
/**
* 新建页动作
* 生成路径: {basePath}/new
* @param label 按钮标签
* @param dialog 是否在对话框中打开
*/
create(dialog?: boolean): string;
/**
* 列表页动作
* 生成路径: {basePath}/list
*/
list(): string;
base(): string;
}
/**
* HtmxAdmin 上下文对象
* 封装请求处理过程中的状态和操作
*/
/**
* 通知类型
*/
type NotificationType = "error" | "warning" | "info" | "success";
/**
* 通知项
*/
interface Notification {
type: NotificationType;
title: string;
message: string;
}
/**
* HtmxAdmin 上下文
* 封装请求处理过程中的所有状态和操作
*/
declare class HtmxAdminContext {
/** 模块元数据 */
readonly moduleMetadata: ModuleTypeInfo;
/** 插件选项 */
readonly pluginOptions: Required<HtmxAdminPluginOptions>;
/** Hono Context */
readonly ctx: Context;
/** 之前的模块名 */
readonly previousModuleName?: string;
/** 是否是片段请求(HTMX 请求) */
readonly isFragment: boolean;
/** 是否是对话框请求 */
readonly isDialog: boolean;
/** 响应目标容器 */
readonly target: string;
/** 交换方式 */
readonly swap: string;
/** 用户信息 */
readonly userInfo: UserInfo | null;
/** 通知队列 */
readonly notifications: Notification[];
/** 页面标题(用于 HX-Title 和页面展示) */
title: string;
/** 页面描述(用于SEO和页面展示) */
description: string;
/** 面包屑项 */
breadcrumbs: BreadcrumbItem[];
/** 主要内容 */
content: any;
/** 需要重定向的 URL */
redirectUrl?: string;
/** 是否需要刷新页面(用于 HX-Refresh) */
refresh: boolean;
constructor(ctx: Context, userInfo: UserInfo | null, moduleMetadata: ModuleTypeInfo, pluginOptions: Required<HtmxAdminPluginOptions>);
/**
* 发送通知
* 通知将在响应时通过 OOB 更新到错误容器
*/
sendNotification(type: NotificationType, title: string, message: string): void;
/**
* 发送错误通知(便捷方法)
*/
sendError(title: string, message: string): void;
/**
* 发送警告通知(便捷方法)
*/
sendWarning(title: string, message: string): void;
/**
* 发送信息通知(便捷方法)
*/
sendInfo(title: string, message: string): void;
/**
* 发送成功通知(便捷方法)
*/
sendSuccess(title: string, message: string): void;
/**
* 设置需要推送的 URL
* 用于 HX-Push-Url 响应头
*/
redirect(url: string): void;
/**
* 设置需要刷新页面
* 用于 HX-Refresh 响应头
*/
setRefresh(refresh?: boolean): void;
/**
* 检查是否有列表页面
* 封装 moduleMetadata 访问,避免直接访问内部属性
*/
hasList(): boolean;
/**
* 检查是否有详情页面
* 封装 moduleMetadata 访问,避免直接访问内部属性
*/
hasDetail(): boolean;
/**
* 检查是否有表单页面
* 封装 moduleMetadata 访问,避免直接访问内部属性
*/
hasForm(): boolean;
/**
* 检查是否有自定义页面
* 封装 moduleMetadata 访问,避免直接访问内部属性
*/
hasCustom(): boolean;
}
/**
* Page 模块基类
* 所有页面模块的基类,提供通用的属性和方法
*/
/**
* Page 页面模块基类
* 所有页面模块都继承此类,包括 ListPageModule、DetailPageModule、FormPageModule
*
* 对于 custom 类型的模块,必须实现 render 方法
* 对于其他类型的模块,可以重写 render 方法来自定义渲染,否则使用默认渲染逻辑
*/
declare abstract class PageModule {
/** HtmxAdmin 上下文对象 */
context: HtmxAdminContext;
/** Action Helper 实例 */
paths: PathHelper;
/**
* 初始化模块实例(私有方法,仅由 RouteHandler 调用)
* 用于设置模块的基础属性
*/
__init(context: HtmxAdminContext): void;
/**
* 获取页面标题
* 子类可以重写此方法来返回页面标题
* 默认实现:使用模块名
*/
getTitle(): string;
/**
* 获取页面描述
* 子类可以重写此方法来返回页面描述(用于SEO和页面展示)
* 默认实现:返回空字符串
*/
getDescription(): string;
/**
* 获取面包屑
* 子类可以重写此方法来自定义面包屑
* 默认实现:首页 => 自定义页面
*/
getBreadcrumbs(): BreadcrumbItem[];
/**
* 处理请求的统一入口(由 RouteHandler 调用)
* 默认实现:直接调用 render 方法
* 子类可以重写此方法来处理请求级别的逻辑(如根据 HTTP method 分发)
*
* @param adminContext HtmxAdmin 上下文对象(必需),包含请求状态和 helper 方法
* @returns 页面内容
*/
__handle(): Promise<any>;
/**
* 渲染页面内容
*
* 所有页面模块都必须提供 render 方法
* - Custom 类型:必须实现此方法
* - List/Detail/Form 类型:基类提供默认实现,可以重写来自定义渲染
*
* @param adminContext HtmxAdmin 上下文对象(必需),包含请求状态和 helper 方法
* 可以通过 adminContext.ctx 访问 Hono Context
*/
abstract render(): any | Promise<any>;
}
/**
* Detail 模块基类
* 用于详情展示,继承自 PageModule
*/
/**
* Detail 页面模块基类
* 继承自 PageModule,提供详情页面的默认行为
*
* 可以重写 render 方法来自定义渲染,否则使用默认的详情渲染逻辑
*/
declare abstract class DetailPageModule<T = any> extends PageModule {
/** ID 字段名(默认 "id") */
protected readonly idField: string;
/**
* 获取数据源(抽象方法,必须实现)
* 子类必须实现此方法来提供数据源
*/
abstract getDatasource(): DetailDatasource<T>;
/**
* 获取字段标签(可选)
* 子类可以重写此方法来自定义字段的中文标签
*/
getFieldLabel?(field: string): string;
/**
* 渲染字段值(可选)
* 子类可以重写此方法来自定义字段的渲染方式
*/
renderField?(field: string, value: any, item: T): any;
/**
* 获取字段分组(可选)
* 子类可以重写此方法来定义字段分组
* 返回 null 或 undefined 表示不分组,平铺显示
*/
getFieldGroups?(item: T): Array<{
title: string;
fields: string[];
}> | null;
/**
* 获取可见字段列表(可选)
* 子类可以重写此方法来控制字段的显示顺序和可见性
* 返回 null 或 undefined 表示显示所有字段
*/
getVisibleFields?(item: T): string[] | null;
/**
* 获取详情页操作按钮(可选)
* 子类可以重写此方法来添加详情页的操作按钮
* 如果不定义,则根据模块元数据智能生成默认操作按钮
*/
getDetailActions?(item: T): Array<{
label: string;
href: string | ((item: T) => string);
method?: string;
class?: string;
}>;
/**
* 渲染详情页面(默认实现)
* 子类可以重写此方法来自定义渲染
*/
render(): Promise<any>;
}
/**
* Form 模块基类
* 用于表单(新建/编辑),继承自 PageModule
*/
/**
* Form 页面模块基类
* 继承自 PageModule,提供表单页面的默认行为
*
* 可以重写 render 方法来自定义渲染,否则使用默认的表单渲染逻辑
*/
declare abstract class FormPageModule<T = any> extends PageModule {
/** ID 字段名(默认 "id") */
protected idField: string;
/** Zod Schema(可选,如果提供则自动生成表单字段和校验) */
protected schema?: z.ZodObject<any>;
constructor(schema?: z.ZodObject<any>);
/**
* 获取数据源(抽象方法,必须实现)
* 子类必须实现此方法来提供数据源
*/
abstract getDatasource(): FormDatasource<T>;
/**
* 获取单条数据(编辑时使用)
*/
getItem(id: string | number): Promise<T | null>;
/**
* 获取字段标签(可选)
* 子类可以重写此方法来自定义字段的中文标签
*/
getFieldLabel?(field: string): string;
/**
* 获取表单字段定义
*
* 如果提供了 schema,则自动从 schema 生成字段定义
* 否则子类必须实现此方法来定义表单的字段
*/
getFormFields(item: T | null): Array<{
name: string;
label: string;
type?: "text" | "email" | "number" | "textarea" | "select" | "date" | "datetime-local";
required?: boolean;
placeholder?: string;
options?: Array<{
value: string | number;
label: string;
}>;
}>;
/**
* 获取字段标签映射(可选)
* 用于覆盖从 schema description 提取的标签
*/
getFieldLabels?(): Record<string, string>;
/**
* 获取字段占位符映射(可选)
*/
getFieldPlaceholders?(): Record<string, string>;
/**
* 获取字段选项映射(可选)
* 用于覆盖从 schema enum 提取的选项
*/
getFieldOptions?(): Record<string, Array<{
value: string | number;
label: string;
}>>;
/**
* 获取字段类型映射(可选)
* 用于覆盖自动推断的类型
*/
getFieldTypes?(): Record<string, "text" | "email" | "number" | "textarea" | "select" | "date" | "datetime-local">;
/**
* 获取要排除的字段列表(可选)
*/
getExcludeFields?(): string[];
/**
* 验证表单数据
*
* 如果提供了 schema,则自动使用 schema 进行校验
* 否则子类可以重写此方法来验证表单数据
*/
validateFormData(data: Record<string, any>, item: T | null): string | null;
/**
* 处理请求的统一入口(重写基类方法)
* 根据 HTTP method 处理不同请求:
* - GET: 渲染表单页面(调用 render)
* - POST: 创建数据
* - PUT: 更新数据
* - DELETE: 删除数据
* 子类可以重写此方法来自定义请求处理逻辑
*/
__handle(): Promise<any>;
/**
* 渲染表单页面(默认实现)
* 子类可以重写此方法来自定义渲染
* @param formData 表单数据(用于回填验证失败时的值)
*/
render(formData?: Record<string, any>): Promise<any>;
/**
* 处理创建请求(POST)
*/
private handleCreate;
/**
* 处理更新请求(PUT)
*/
private handleUpdate;
/**
* 处理删除请求(DELETE)
* 注意:FormDatasource 不包含 deleteItem,删除操作通常由 List 或 Detail 模块处理
* 这里提供默认实现,子类可以重写
*/
private handleDelete;
/**
* 渲染表单页面(辅助方法)
* 用于在验证失败时重新渲染表单页面
* @param adminContext 上下文对象
* @param item 原始数据项(编辑时)
* @param isEdit 是否是编辑模式
* @param formData 表单数据(用于回填验证失败时的值)
*/
private renderFormPage;
}
/**
* List 模块基类
* 用于列表展示,继承自 PageModule
*/
/**
* List 页面模块基类
* 继承自 PageModule,提供列表页面的默认行为
*
* 可以重写 render 方法来自定义渲染,否则使用默认的列表渲染逻辑
*/
declare abstract class ListPageModule<T extends {
id: string | number;
} = {
id: string | number;
}> extends PageModule {
/** ID 字段名(默认 "id") */
protected readonly idField: string;
/**
* 获取数据源(抽象方法,必须实现)
* 子类必须实现此方法来提供数据源
*/
abstract getDatasource(): ListDatasource<T>;
/**
* 获取列表数据
*/
getList(params: ListParams): Promise<ListResult<T>>;
/**
* 删除数据(可选,如果数据源支持删除)
*/
deleteItem(id: string | number): Promise<boolean>;
/**
* 获取字段标签(可选)
* 子类可以重写此方法来自定义字段的中文标签
*/
getFieldLabel?(field: string): string;
/**
* 自定义列渲染(可选)
* 子类可以重写此方法来自定义列的渲染逻辑
*/
renderColumn?(field: string, value: any, item: T): any;
/**
* 获取统计信息(可选)
* 子类可以重写此方法来返回 KPI 统计卡片数据
* 返回的数组将渲染为 StatCard 组件
*/
getStats?(params: ListParams): Promise<Array<{
title: string;
value: string | number;
change?: number;
changeLabel?: string;
iconColor?: "blue" | "green" | "yellow" | "purple" | "red" | "indigo";
icon?: any;
}>> | Array<{
title: string;
value: string | number;
change?: number;
changeLabel?: string;
iconColor?: "blue" | "green" | "yellow" | "purple" | "red" | "indigo";
icon?: any;
}>;
/**
* 获取筛选器配置(可选)
* 子类可以重写此方法来返回筛选器字段配置
* 返回的配置将渲染为 FilterCard 组件
*/
getFilters?(params: ListParams): Array<{
name: string;
label: string;
options: Array<{
value: string | number;
label: string;
disabled?: boolean;
}>;
value?: string | number;
defaultValue?: string | number;
}>;
/**
* 获取表格标题(可选)
* 子类可以重写此方法来返回表格标题
* 如果不定义,默认使用模块名
*/
getTableTitle?(): string;
/**
* 获取表格操作按钮(可选)
* 子类可以重写此方法来返回表格操作按钮配置(如导出、清空、刷新等)
* 如果不定义,默认会生成一个刷新按钮
*/
getTableActions?(params: ListParams, basePath: string): Array<{
label: string;
href?: string;
hxGet?: string;
hxPost?: string;
hxDelete?: string;
variant?: "primary" | "secondary" | "danger" | "ghost";
hxConfirm?: string;
}>;
/**
* 自定义操作按钮(可选)
* 子类可以重写此方法来添加自定义操作按钮
* 如果不定义,则根据模块元数据智能生成默认操作按钮
*/
getActions?(item: T): Array<{
label: string;
href: string | ((item: T) => string);
method?: string;
class?: string;
}>;
/**
* 渲染列表页面(默认实现)
* 子类可以重写此方法来自定义渲染
*/
render(): Promise<any>;
}
/**
* 数据源接口和基础实现
*/
/**
* 内存数据源(完整实现,可用于 list、detail、form 类型)
*/
declare class MemoryListDatasource<T extends {
id: string | number;
}> implements ListDatasource<T>, DetailDatasource<T>, FormDatasource<T> {
private data;
constructor(data?: T[]);
getList(params?: ListParams): Promise<ListResult<T>>;
getItem(id: string | number): Promise<T | null>;
deleteItem(id: string | number): Promise<boolean>;
updateItem(id: string | number, data: Partial<T>): Promise<T | null>;
createItem(data: Partial<T>): Promise<T>;
}
/**
* HtmxAdminPlugin - 管理后台插件
* 使用 HTMX + Tailwind + Hyperscript + JSX 快速构建管理后台
*/
/**
* HtmxAdminPlugin
*/
declare class HtmxAdminPlugin implements Plugin<HtmxAdminModuleOptions> {
readonly name = "htmx-admin-plugin";
readonly priority = PluginPriority.ROUTE;
private engine;
private hono;
private options;
private moduleTypeMap;
constructor(options?: HtmxAdminPluginOptions);
/**
* 声明Module配置Schema
*/
getModuleOptionsSchema(): PluginModuleOptionsSchema<HtmxAdminModuleOptions>;
/**
* 引擎初始化钩子
*/
onInit(engine: Microservice): void;
/**
* 检查并注册模块
*/
private checkAndRegisterModules;
/**
* 注册路由
*/
private registerRoutes;
/**
* 模块加载钩子:检查模块类型约束并注册路由
*/
onModuleLoad(modules: ModuleMetadata[]): void;
}
/**
* 渲染工具函数
*/
/**
* 安全渲染值(支持 JSX 和字符串 HTML)
* 如果返回的是字符串 HTML,将其转换为 JSX 元素
*/
declare function safeRender(value: any): any;
/**
* 表单组件(用于编辑和新建)
*/
/**
* 字段定义
*/
interface FormField$1 {
/** 字段名 */
name: string;
/** 字段标签 */
label: string;
/** 字段类型 */
type?: "text" | "email" | "number" | "textarea" | "select" | "date" | "datetime-local";
/** 是否必填 */
required?: boolean;
/** 占位符 */
placeholder?: string;
/** 选项(用于 select 类型) */
options?: Array<{
value: string | number;
label: string;
}>;
/** 自定义渲染函数 */
render?: (value: any, item: any) => any;
}
/**
* 表单组件 Props
*/
interface FormProps<T = any> {
/** 数据项(编辑时传入,新建时为 null) */
item: T | null;
/** 字段定义列表 */
fields: FormField$1[];
/** 提交 URL */
submitUrl: string;
/** 提交方法(默认 PUT) */
method?: "PUT" | "POST";
/** 提交后重定向 URL */
redirectUrl?: string;
/** 页面标题(默认 "编辑" 或 "新建") */
title?: string;
/** 取消按钮 URL */
cancelUrl?: string;
/** 是否在对话框中显示 */
isDialog?: boolean;
/** 表单数据(用于回填验证失败时的值) */
formData?: Record<string, any>;
}
/**
* 表单组件
*/
declare const Form: <T extends Record<string, any>>(props: FormProps<T>) => hono_jsx_jsx_dev_runtime.JSX.Element;
/**
* Zod Schema 表单工具
* 从 Zod Schema 自动生成表单字段定义和校验逻辑
*/
/**
* 从 Zod Object Schema 生成表单字段定义
*/
declare function generateFormFieldsFromSchema<T extends z.ZodObject<any>>(schema: T, options?: {
/** 字段标签映射(覆盖从 description 提取的标签) */
fieldLabels?: Record<string, string>;
/** 字段占位符映射 */
fieldPlaceholders?: Record<string, string>;
/** 字段选项映射(覆盖从 enum 提取的选项) */
fieldOptions?: Record<string, Array<{
value: string | number;
label: string;
}>>;
/** 字段类型映射(覆盖自动推断的类型) */
fieldTypes?: Record<string, FormField$1["type"]>;
/** 要排除的字段 */
excludeFields?: string[];
}): FormField$1[];
/**
* 使用 Zod Schema 验证表单数据
*/
declare function validateFormDataWithSchema<T extends z.ZodObject<any>>(schema: T, data: Record<string, any>): {
success: true;
data: z.infer<T>;
} | {
success: false;
error: string;
};
/**
* 操作按钮组件
*/
interface ActionButtonProps {
/** 按钮文本 */
label: string;
/** 链接地址 */
href: string | ((item: any) => string);
/** HTTP 方法 */
method?: string;
/** 自定义类名 */
className?: string;
/** 数据项(用于生成动态链接) */
item?: any;
}
/**
* 操作按钮组件
*/
declare const ActionButton: (props: ActionButtonProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
/**
* 最近活动卡片组件
*/
interface ActivityItem {
/** 活动描述 */
description: string;
/** 时间(如"2分钟前") */
time: string;
/** 活动类型颜色(blue, green, purple, gray等) */
color?: "blue" | "green" | "purple" | "gray" | "yellow" | "red";
}
interface ActivityCardProps {
/** 标题 */
title: string;
/** 活动列表 */
activities: ActivityItem[];
/** 自定义类名 */
className?: string;
}
/**
* 最近活动卡片组件
* 用于展示最近的活动记录列表
*/
declare const ActivityCard: (props: ActivityCardProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
/**
* 徽章组件(用于标签显示)
*/
interface BadgeProps {
/** 标签文本 */
children: any;
/** 颜色主题 */
variant?: "blue" | "green" | "yellow" | "red" | "gray" | "purple" | "indigo";
/** 自定义类名 */
className?: string;
}
/**
* 徽章组件
* 用于显示状态标签,如日志级别、状态等
*/
declare const Badge: (props: BadgeProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
/**
* 按钮组件
*/
interface ButtonProps {
/** 按钮文本 */
children: any;
/** 按钮类型 */
variant?: "primary" | "secondary" | "danger" | "ghost";
/** 按钮大小 */
size?: "sm" | "md" | "lg";
/** 是否禁用 */
disabled?: boolean;
/** 自定义类名 */
className?: string;
/** HTMX 属性 */
hxGet?: string;
hxPost?: string;
hxPut?: string;
hxDelete?: string;
hxTarget?: string;
hxSwap?: string;
hxPushUrl?: string | boolean;
hxIndicator?: string;
hxConfirm?: string;
hxHeaders?: string;
/** 其他属性 */
[key: string]: any;
}
/**
* 按钮组件
*/
declare const Button: (props: ButtonProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
/**
* 卡片组件
*/
interface CardProps {
/** 卡片内容 */
children: any;
/** 卡片标题 */
title?: string;
/** 自定义类名 */
className?: string;
/** 是否显示阴影 */
shadow?: boolean;
/** 是否显示边框 */
bordered?: boolean;
/** 是否去掉内边距 */
noPadding?: boolean;
}
/**
* 卡片组件
*/
declare