619 lines
17 KiB
TypeScript
619 lines
17 KiB
TypeScript
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 };
|