2025-04-17 22:31:04 +08:00

619 lines
17 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Schema } from 'http://esm.xiongxiao.me/zod@3.24.3/index.d.ts';
export { Schema } from 'http://esm.xiongxiao.me/zod@3.24.3/index.d.ts';
import http, { IncomingMessage, ServerResponse } from 'node:http';
import https from 'node:https';
import http2 from 'node:http2';
import * as cookie from 'http://esm.xiongxiao.me/cookie@1.0.2/dist/index.d.ts';
import { WebSocketServer, WebSocket } from 'http://esm.xiongxiao.me/@types/ws@~8.18.1/index.d.mts';
type BaseRule = {
value?: any;
required?: boolean;
message?: string;
};
type RuleString = {
type: 'string';
minLength?: number;
maxLength?: number;
regex?: string;
} & BaseRule;
type RuleNumber = {
type: 'number';
min?: number;
max?: number;
} & BaseRule;
type RuleBoolean = {
type: 'boolean';
} & BaseRule;
type RuleArray = {
type: 'array';
items: Rule;
minItems?: number;
maxItems?: number;
} & BaseRule;
type RuleObject = {
type: 'object';
properties: {
[key: string]: Rule;
};
} & BaseRule;
type RuleAny = {
type: 'any';
} & BaseRule;
type Rule = RuleString | RuleNumber | RuleBoolean | RuleArray | RuleObject | RuleAny;
declare const createSchema: (rule: Rule) => Schema;
type RouterContextT = {
code?: number;
[key: string]: any;
};
type RouteContext<T = {
code?: number;
}, S = any> = {
query?: {
[key: string]: any;
};
/** return body */
body?: number | string | Object;
/** return code */
code?: number;
/** return msg */
message?: string;
state?: S;
currentPath?: string;
currentKey?: string;
currentRoute?: Route;
progress?: [[string, string]][];
nextQuery?: {
[key: string]: any;
};
end?: boolean;
queryRouter?: QueryRouter;
error?: any;
/** 请求 route的返回结果包函ctx */
call?: (message: {
path: string;
key?: string;
payload?: any;
[key: string]: any;
} | {
id: string;
apyload?: any;
[key: string]: any;
}, ctx?: RouteContext & {
[key: string]: any;
}) => Promise<any>;
/** 请求 route的返回结果不包函ctx */
queryRoute?: (message: {
path: string;
key?: string;
payload?: any;
}, ctx?: RouteContext & {
[key: string]: any;
}) => Promise<any>;
index?: number;
throw?: (code?: number | string, message?: string, tips?: string) => void;
/** 是否需要序列化 */
needSerialize?: boolean;
} & T;
type Run<T = any> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
type RouteOpts = {
path?: string;
key?: string;
id?: string;
run?: Run;
nextRoute?: NextRoute;
description?: string;
metadata?: {
[key: string]: any;
};
middleware?: Route[] | string[];
type?: 'route' | 'middleware';
/**
* validator: {
* packageName: {
* type: 'string',
* required: true,
* },
* }
*/
validator?: {
[key: string]: Rule;
};
schema?: {
[key: string]: Schema<any>;
};
isVerify?: boolean;
verify?: (ctx?: RouteContext, dev?: boolean) => boolean;
verifyKey?: (key: string, ctx?: RouteContext, dev?: boolean) => boolean;
/**
* $#$ will be used to split path and key
*/
idUsePath?: boolean;
isDebug?: boolean;
};
type DefineRouteOpts = Omit<RouteOpts, 'idUsePath' | 'verify' | 'verifyKey' | 'nextRoute'>;
declare const pickValue: readonly ["path", "key", "id", "description", "type", "validator", "middleware"];
type RouteInfo = Pick<Route, (typeof pickValue)[number]>;
declare class Route<U = {
[key: string]: any;
}> {
/**
* 一级路径
*/
path?: string;
/**
* 二级路径
*/
key?: string;
id?: string;
share?: boolean;
run?: Run;
nextRoute?: NextRoute;
description?: string;
metadata?: {
[key: string]: any;
};
middleware?: (Route | string)[];
type?: string;
private _validator?;
schema?: {
[key: string]: Schema<any>;
};
data?: any;
/**
* 是否需要验证
*/
isVerify?: boolean;
/**
* 是否开启debug开启后会打印错误信息
*/
isDebug?: boolean;
constructor(path: string, key?: string, opts?: RouteOpts);
private createSchema;
/**
* set validator and create schema
* @param validator
*/
set validator(validator: {
[key: string]: Rule;
});
get validator(): {
[key: string]: Rule;
};
/**
* has code, body, message in ctx, return ctx if has error
* @param ctx
* @param dev
* @returns
*/
verify(ctx: RouteContext, dev?: boolean): void;
/**
* Need to manully call return ctx fn and configure body, code, message
* @param key
* @param ctx
* @param dev
* @returns
*/
verifyKey(key: string, ctx: RouteContext, dev?: boolean): {
message: string;
path: string;
key: string;
error: any;
} | {
message: string;
path: string;
key: string;
error?: undefined;
};
setValidator(validator: {
[key: string]: Rule;
}): this;
define<T extends {
[key: string]: any;
} = RouterContextT>(opts: DefineRouteOpts): this;
define<T extends {
[key: string]: any;
} = RouterContextT>(fn: Run<T & U>): this;
define<T extends {
[key: string]: any;
} = RouterContextT>(key: string, fn: Run<T & U>): this;
define<T extends {
[key: string]: any;
} = RouterContextT>(path: string, key: string, fn: Run<T & U>): this;
addTo(router: QueryRouter | {
add: (route: Route) => void;
[key: string]: any;
}): void;
setData(data: any): this;
throw(code?: number | string, message?: string, tips?: string): void;
}
declare class QueryRouter {
routes: Route[];
maxNextRoute: number;
context?: RouteContext;
constructor();
add(route: Route): void;
/**
* remove route by path and key
* @param route
*/
remove(route: Route | {
path: string;
key?: string;
}): void;
/**
* remove route by id
* @param uniqueId
*/
removeById(unique: string): void;
/**
* 执行route
* @param path
* @param key
* @param ctx
* @returns
*/
runRoute(path: string, key: string, ctx?: RouteContext): any;
/**
* 第一次执行
* @param message
* @param ctx
* @returns
*/
parse(message: {
path: string;
key?: string;
payload?: any;
}, ctx?: RouteContext & {
[key: string]: any;
}): Promise<any>;
/**
* 返回的数据包含所有的context的请求返回的内容可做其他处理
* @param message
* @param ctx
* @returns
*/
call(message: {
id?: string;
path?: string;
key?: string;
payload?: any;
}, ctx?: RouteContext & {
[key: string]: any;
}): Promise<any>;
/**
* 请求 result 的数据
* @param message
* @param ctx
* @returns
*/
queryRoute(message: {
path: string;
key?: string;
payload?: any;
}, ctx?: RouteContext & {
[key: string]: any;
}): Promise<{
code: any;
data: any;
message: any;
}>;
setContext(ctx: RouteContext): Promise<void>;
getList(): RouteInfo[];
getHandle<T = any>(router: QueryRouter, wrapperFn?: HandleFn<T>, ctx?: RouteContext): (msg: {
path: string;
key?: string;
[key: string]: any;
}, handleContext?: RouteContext) => Promise<{
[key: string]: any;
code: string;
data?: any;
message?: string;
} | {
code: any;
data: any;
message: any;
} | {
code: number;
message: any;
data?: undefined;
}>;
exportRoutes(): Route<{
[key: string]: any;
}>[];
importRoutes(routes: Route[]): void;
importRouter(router: QueryRouter): void;
throw(code?: number | string, message?: string, tips?: string): void;
hasRoute(path: string, key?: string): Route<{
[key: string]: any;
}>;
}
type QueryRouterServerOpts = {
handleFn?: HandleFn;
context?: RouteContext;
};
interface HandleFn<T = any> {
(msg: {
path: string;
[key: string]: any;
}, ctx?: any): {
code: string;
data?: any;
message?: string;
[key: string]: any;
};
(res: RouteContext<T>): any;
}
/**
* QueryRouterServer
* @description 移除server相关的功能只保留router相关的功能和http.createServer不相关独立
*/
declare class QueryRouterServer extends QueryRouter {
handle: any;
constructor(opts?: QueryRouterServerOpts);
setHandle(wrapperFn?: HandleFn, ctx?: RouteContext): void;
use(path: string, fn: (ctx: any) => any, opts?: RouteOpts): void;
addRoute(route: Route): void;
Route: typeof Route;
route(opts: RouteOpts): Route<Required<RouteContext>>;
route(path: string, key?: string): Route<Required<RouteContext>>;
route(path: string, opts?: RouteOpts): Route<Required<RouteContext>>;
route(path: string, key?: string, opts?: RouteOpts): Route<Required<RouteContext>>;
/**
* 等于queryRoute但是调用了handle
* @param param0
* @returns
*/
run({ path, key, payload }: {
path: string;
key?: string;
payload?: any;
}): Promise<any>;
}
declare class Connect {
path: string;
key?: string;
_fn?: (ctx?: RouteContext) => Promise<RouteContext>;
description?: string;
connects: {
path: string;
key?: string;
}[];
share: boolean;
constructor(path: string);
use(path: string): void;
useList(paths: string[]): void;
useConnect(connect: Connect): void;
useConnectList(connects: Connect[]): void;
getPathList(): string[];
set fn(fn: (ctx?: RouteContext) => Promise<RouteContext>);
get fn(): (ctx?: RouteContext) => Promise<RouteContext>;
}
declare class QueryConnect {
connects: Connect[];
constructor();
add(connect: Connect): void;
remove(connect: Connect): void;
getList(): {
path: string;
key: string;
}[];
}
type Listener = (...args: any[]) => void;
type CookieFn = (name: string, value: string, options?: cookie.SerializeOptions, end?: boolean) => void;
type HandleCtx = {
req: IncomingMessage & {
cookies: Record<string, string>;
};
res: ServerResponse & {
/**
* cookie 函数, end 参数用于设置是否立即设置到响应头设置了后面的cookie再设置会覆盖前面的
*/
cookie: CookieFn;
};
};
type Cors = {
/**
* @default '*''
*/
origin?: string | undefined;
};
type ServerOpts = {
/**path default `/api/router` */
path?: string;
/**handle Fn */
handle?: (msg?: {
path: string;
key?: string;
[key: string]: any;
}, ctx?: {
req: http.IncomingMessage;
res: http.ServerResponse;
}) => any;
cors?: Cors;
httpType?: 'http' | 'https' | 'http2';
httpsKey?: string;
httpsCert?: string;
};
declare class Server {
path: string;
private _server;
handle: ServerOpts['handle'];
private _callback;
private cors;
private hasOn;
private httpType;
private options;
constructor(opts?: ServerOpts);
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
listen(port: number, hostname?: string, listeningListener?: () => void): void;
listen(port: number, backlog?: number, listeningListener?: () => void): void;
listen(port: number, listeningListener?: () => void): void;
listen(path: string, backlog?: number, listeningListener?: () => void): void;
listen(path: string, listeningListener?: () => void): void;
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
listen(handle: any, listeningListener?: () => void): void;
createServer(): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | https.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | http2.Http2SecureServer<typeof http.IncomingMessage, typeof http.ServerResponse, typeof http2.Http2ServerRequest, typeof http2.Http2ServerResponse>;
setHandle(handle?: any): void;
/**
* get callback
* @returns
*/
createCallback(): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
get handleServer(): any;
set handleServer(fn: any);
/**
* 兜底监听,当除开 `/api/router` 之外的请求框架只监听一个api所以有其他的请求都执行其他的监听
* @description 主要是为了兼容其他的监听
* @param listener
*/
on(listener: Listener | Listener[]): void;
get callback(): any;
get server(): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | https.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | http2.Http2SecureServer<typeof http.IncomingMessage, typeof http.ServerResponse, typeof http2.Http2ServerRequest, typeof http2.Http2ServerResponse>;
}
/**
* get params and body
* 优先原则
* 1. 请求参数中的 payload 的token 优先
* 2. 请求头中的 authorization 优先
* 3. 请求头中的 cookie 优先
* @param req
* @param res
* @returns
*/
declare const handleServer: (req: IncomingMessage, res: ServerResponse) => Promise<{
cookies: Record<string, string>;
token: string;
}>;
/** 自定义错误 */
declare class CustomError extends Error {
code?: number;
data?: any;
message: string;
tips?: string;
constructor(code?: number | string, message?: string, tips?: string);
static fromCode(code?: number): CustomError;
static fromErrorData(code?: number, data?: any): CustomError;
static parseError(e: CustomError): {
code: number;
data: any;
message: string;
tips: string;
};
parse(e?: CustomError): {
code: number;
data: any;
message: string;
tips: string;
};
}
type WsServerBaseOpts = {
wss?: WebSocketServer;
path?: string;
};
type ListenerFn = (message: {
data: Record<string, any>;
ws: WebSocket;
end: (data: any) => any;
}) => Promise<any>;
declare class WsServerBase {
wss: WebSocketServer;
path: string;
listeners: {
type: string;
listener: ListenerFn;
}[];
listening: boolean;
constructor(opts: WsServerBaseOpts);
setPath(path: string): void;
listen(): void;
addListener(type: string, listener: ListenerFn): void;
removeListener(type: string): void;
}
declare class WsServer extends WsServerBase {
server: Server;
constructor(server: Server, opts?: any);
initListener(): void;
listen(): void;
}
type RouterHandle = (msg: {
path: string;
[key: string]: any;
}) => {
code: string;
data?: any;
message?: string;
[key: string]: any;
};
type AppOptions<T = {}> = {
router?: QueryRouter;
server?: Server;
/** handle msg 关联 */
routerHandle?: RouterHandle;
routerContext?: RouteContext<T>;
serverOptions?: ServerOpts;
io?: boolean;
ioOpts?: {
routerHandle?: RouterHandle;
routerContext?: RouteContext<T>;
path?: string;
};
};
type AppReqRes = HandleCtx;
/**
* 封装了 Router 和 Server 的 App 模块处理http的请求和响应内置了 Cookie 和 Token 和 res 的处理
*/
declare class App<T = {}, U = AppReqRes> {
router: QueryRouter;
server: Server;
io: WsServer;
constructor(opts?: AppOptions<T>);
listen(port: number, hostname?: string, backlog?: number, listeningListener?: () => void): void;
listen(port: number, hostname?: string, listeningListener?: () => void): void;
listen(port: number, backlog?: number, listeningListener?: () => void): void;
listen(port: number, listeningListener?: () => void): void;
listen(path: string, backlog?: number, listeningListener?: () => void): void;
listen(path: string, listeningListener?: () => void): void;
listen(handle: any, backlog?: number, listeningListener?: () => void): void;
listen(handle: any, listeningListener?: () => void): void;
use(path: string, fn: (ctx: any) => any, opts?: RouteOpts): void;
addRoute(route: Route): void;
add: (route: Route) => void;
Route: typeof Route;
route(opts: RouteOpts): Route<U>;
route(path: string, key?: string): Route<U>;
route(path: string, opts?: RouteOpts): Route<U>;
route(path: string, key?: string, opts?: RouteOpts): Route<U>;
call(message: {
path: string;
key?: string;
payload?: any;
}, ctx?: RouteContext & {
[key: string]: any;
}): Promise<any>;
queryRoute(path: string, key?: string, payload?: any, ctx?: RouteContext & {
[key: string]: any;
}): Promise<{
code: any;
data: any;
message: any;
}>;
exportRoutes(): Route<{
[key: string]: any;
}>[];
importRoutes(routes: any[]): void;
importApp(app: App): void;
throw(code?: number | string, message?: string, tips?: string): void;
}
export { App, Connect, CustomError, QueryConnect, QueryRouter, QueryRouterServer, Route, Server, createSchema, handleServer };
export type { RouteContext, RouteOpts, Rule, Run };