chore: update version to 0.0.43 and enhance request/response types for Bun server
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.42",
|
"version": "0.0.43",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/router.js",
|
"main": "./dist/router.js",
|
||||||
|
|||||||
@@ -18,3 +18,6 @@ export type { Rule, Schema, } from './validator/index.ts';
|
|||||||
export { App } from './app.ts';
|
export { App } from './app.ts';
|
||||||
|
|
||||||
export * from './router-define.ts';
|
export * from './router-define.ts';
|
||||||
|
|
||||||
|
|
||||||
|
export { RouterReq, RouterRes } from './server/server-type.ts';
|
||||||
@@ -4,19 +4,8 @@
|
|||||||
* @tags bun, server, websocket, http
|
* @tags bun, server, websocket, http
|
||||||
* @createdAt 2025-12-20
|
* @createdAt 2025-12-20
|
||||||
*/
|
*/
|
||||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
import { ServerType, type ServerOpts, type Cors, RouterRes, RouterReq } from './server-type.ts';
|
||||||
import { ServerType, type ServerOpts, type Cors, Listener } from './server-type.ts';
|
|
||||||
import { handleServer } from './handle-server.ts';
|
|
||||||
import { ServerBase } from './server-base.ts';
|
import { ServerBase } from './server-base.ts';
|
||||||
import { parseIfJson } from '../utils/parse.ts';
|
|
||||||
|
|
||||||
const resultError = (error: string, code = 500) => {
|
|
||||||
const r = {
|
|
||||||
code: code,
|
|
||||||
message: error,
|
|
||||||
};
|
|
||||||
return JSON.stringify(r);
|
|
||||||
};
|
|
||||||
|
|
||||||
export class BunServer extends ServerBase implements ServerType {
|
export class BunServer extends ServerBase implements ServerType {
|
||||||
declare _server: any;
|
declare _server: any;
|
||||||
@@ -54,15 +43,16 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestCallback = this.createCallback();
|
const requestCallback = this.createCallback() as unknown as (req: RouterReq, res: RouterRes) => void;
|
||||||
const wsPath = this.path;
|
const wsPath = this.path;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this._server = Bun.serve({
|
this._server = Bun.serve({
|
||||||
port,
|
port,
|
||||||
hostname,
|
hostname,
|
||||||
idleTimeout: 0, // 4 minutes idle timeout (max 255 seconds)
|
idleTimeout: 0, // 4 minutes idle timeout (max 255 seconds)
|
||||||
fetch: async (request: Request, server: any) => {
|
fetch: async (request: Bun.BunRequest, server: any) => {
|
||||||
const host = request.headers.get('host') || 'localhost';
|
const host = request.headers.get('host') || 'localhost';
|
||||||
|
const clientInfo = server.requestIP(request); // 返回 { address: string, port: number } 或 null
|
||||||
const url = new URL(request.url, `http://${host}`);
|
const url = new URL(request.url, `http://${host}`);
|
||||||
// 处理 WebSocket 升级请求
|
// 处理 WebSocket 升级请求
|
||||||
if (request.headers.get('upgrade') === 'websocket') {
|
if (request.headers.get('upgrade') === 'websocket') {
|
||||||
@@ -82,17 +72,23 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
|
|
||||||
// 将 Bun 的 Request 转换为 Node.js 风格的 req/res
|
// 将 Bun 的 Request 转换为 Node.js 风格的 req/res
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const req: any = {
|
const req: RouterReq = {
|
||||||
url: url.pathname + url.search,
|
url: url.pathname + url.search,
|
||||||
method: request.method,
|
method: request.method,
|
||||||
headers: Object.fromEntries(request.headers.entries()),
|
headers: Object.fromEntries(request.headers.entries()),
|
||||||
|
socket: {
|
||||||
|
// @ts-ignore
|
||||||
|
remoteAddress: request?.remoteAddress || request?.ip || clientInfo?.address || '',
|
||||||
|
remotePort: clientInfo?.port || 0,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const res: any = {
|
const res: RouterRes = {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
headersSent: false,
|
headersSent: false,
|
||||||
writableEnded: false,
|
writableEnded: false,
|
||||||
_headers: {} as Record<string, string | string[]>,
|
_headers: {} as Record<string, string | string[]>,
|
||||||
|
_bodyChunks: [] as any[],
|
||||||
writeHead(statusCode: number, headers: Record<string, string | string[]>) {
|
writeHead(statusCode: number, headers: Record<string, string | string[]>) {
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
for (const key in headers) {
|
for (const key in headers) {
|
||||||
@@ -130,10 +126,84 @@ export class BunServer extends ServerBase implements ServerType {
|
|||||||
}
|
}
|
||||||
this.setHeader('Set-Cookie', cookieString);
|
this.setHeader('Set-Cookie', cookieString);
|
||||||
},
|
},
|
||||||
|
write(chunk: any, encoding?: string | Function, callback?: Function) {
|
||||||
|
if (typeof encoding === 'function') {
|
||||||
|
callback = encoding;
|
||||||
|
encoding = 'utf8';
|
||||||
|
}
|
||||||
|
if (!this._bodyChunks) {
|
||||||
|
this._bodyChunks = [];
|
||||||
|
}
|
||||||
|
this._bodyChunks.push(chunk);
|
||||||
|
if (callback) callback();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
pipe(stream: any) {
|
||||||
|
this.writableEnded = true;
|
||||||
|
|
||||||
|
// 如果是 ReadableStream,直接使用
|
||||||
|
if (stream instanceof ReadableStream) {
|
||||||
|
resolve(
|
||||||
|
new Response(stream, {
|
||||||
|
status: this.statusCode,
|
||||||
|
headers: this._headers as any,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是 Node.js 流,转换为 ReadableStream
|
||||||
|
const readableStream = new ReadableStream({
|
||||||
|
start(controller) {
|
||||||
|
stream.on('data', (chunk: any) => {
|
||||||
|
controller.enqueue(chunk);
|
||||||
|
});
|
||||||
|
stream.on('end', () => {
|
||||||
|
controller.close();
|
||||||
|
});
|
||||||
|
stream.on('error', (err: any) => {
|
||||||
|
controller.error(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cancel() {
|
||||||
|
if (stream.destroy) {
|
||||||
|
stream.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(
|
||||||
|
new Response(readableStream, {
|
||||||
|
status: this.statusCode,
|
||||||
|
headers: this._headers as any,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
end(data?: string) {
|
end(data?: string) {
|
||||||
this.writableEnded = true;
|
this.writableEnded = true;
|
||||||
|
|
||||||
|
// 合并所有写入的数据块
|
||||||
|
let responseData: string | Buffer = data;
|
||||||
|
if (this._bodyChunks && this._bodyChunks.length > 0) {
|
||||||
|
if (data) this._bodyChunks.push(data);
|
||||||
|
// 处理 Buffer 和字符串混合的情况
|
||||||
|
const hasBuffer = this._bodyChunks.some(chunk => chunk instanceof Buffer || chunk instanceof Uint8Array);
|
||||||
|
if (hasBuffer) {
|
||||||
|
// 如果有 Buffer,转换所有内容为 Buffer 后合并
|
||||||
|
const buffers = this._bodyChunks.map(chunk => {
|
||||||
|
if (chunk instanceof Buffer) return chunk;
|
||||||
|
if (chunk instanceof Uint8Array) return Buffer.from(chunk);
|
||||||
|
return Buffer.from(String(chunk));
|
||||||
|
});
|
||||||
|
responseData = Buffer.concat(buffers);
|
||||||
|
} else {
|
||||||
|
// 纯字符串,直接拼接
|
||||||
|
responseData = this._bodyChunks.map(chunk => String(chunk)).join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resolve(
|
resolve(
|
||||||
new Response(data, {
|
new Response(responseData as any, {
|
||||||
status: this.statusCode,
|
status: this.statusCode,
|
||||||
headers: this._headers as any,
|
headers: this._headers as any,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type Listener = {
|
|||||||
fun: (...args: any[]) => Promise<void> | void;
|
fun: (...args: any[]) => Promise<void> | void;
|
||||||
}
|
}
|
||||||
export type ListenerFun = (...args: any[]) => Promise<void> | void;
|
export type ListenerFun = (...args: any[]) => Promise<void> | void;
|
||||||
export type OnListener = Listener | Listener[] | ListenerFun | ListenerFun[];
|
export type OnListener = Listener | ListenerFun | (Listener | ListenerFun)[];
|
||||||
export type Cors = {
|
export type Cors = {
|
||||||
/**
|
/**
|
||||||
* @default '*''
|
* @default '*''
|
||||||
@@ -52,19 +52,27 @@ type WS = {
|
|||||||
close: () => void;
|
close: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommonReq = {
|
export type RouterReq<T = {}> = {
|
||||||
url: string;
|
url: string;
|
||||||
method: string;
|
method: string;
|
||||||
headers: Record<string, string>;
|
headers: Record<string, string>;
|
||||||
[key: string]: any;
|
socket?: {
|
||||||
}
|
remoteAddress?: string;
|
||||||
|
remotePort?: number;
|
||||||
|
};
|
||||||
|
cookies?: Record<string, string>;
|
||||||
|
} & T;
|
||||||
|
|
||||||
export type CommonRes = {
|
export type RouterRes<T = {}> = {
|
||||||
statusCode: number;
|
statusCode: number;
|
||||||
|
headersSent: boolean;
|
||||||
|
_headers: Record<string, string | string[]>;
|
||||||
|
_bodyChunks: any[];
|
||||||
writableEnded: boolean;
|
writableEnded: boolean;
|
||||||
writeHead: (statusCode: number, headers?: Record<string, string>) => void;
|
writeHead: (statusCode: number, headers?: Record<string, string>) => void;
|
||||||
setHeader: (name: string, value: string | string[]) => void;
|
setHeader: (name: string, value: string | string[]) => void;
|
||||||
cookie: (name: string, value: string, options?: any) => void;
|
cookie: (name: string, value: string, options?: any) => void;
|
||||||
|
write: (chunk: any) => void;
|
||||||
|
pipe: (stream: any) => void;
|
||||||
end: (data?: any) => void;
|
end: (data?: any) => void;
|
||||||
[key: string]: any;
|
} & T;
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user