@lytjs/http-server 6.8.0 → 6.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +219 -0
- package/dist/index.d.ts +219 -0
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -351,8 +351,9 @@ var Server = class {
|
|
|
351
351
|
let index = this.middlewares.length;
|
|
352
352
|
const next = async () => {
|
|
353
353
|
index--;
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
const middleware = this.middlewares[index];
|
|
355
|
+
if (index >= 0 && middleware) {
|
|
356
|
+
await middleware(ctx, next);
|
|
356
357
|
} else {
|
|
357
358
|
await handler();
|
|
358
359
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer","parseQueryStringWithArrays"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler } from './types';\nimport type { HttpMethod } from '@lytjs/shared-types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler } from './types';\nimport type {\n HttpMethod,\n HttpContext as Context,\n HttpRequest as Request,\n HttpResponse as Response,\n} from '@lytjs/shared-types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: ((ctx: Context, next: () => Promise<void>) => Promise<void>)[] = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n if (index >= 0 && this.middlewares[index]) {\n await this.middlewares[index](ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v);\n }\n } else {\n res.setHeader(key, value);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer","parseQueryStringWithArrays"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler, HttpMethod } from './types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler, Context, Request, Response, HttpMethod } from './types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: Array<(ctx: Context, next: () => Promise<void>) => Promise<void>> = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n const middleware = this.middlewares[index];\n if (index >= 0 && middleware) {\n await middleware(ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v as string | number | string[]);\n }\n } else {\n res.setHeader(key, value as string | number | string[]);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { HttpMethod as HttpMethod$1 } from '@lytjs/shared-types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HTTP 服务器类型定义
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
type HttpMethod = HttpMethod$1;
|
|
8
|
+
interface Context {
|
|
9
|
+
request: Request;
|
|
10
|
+
response: Response;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
interface Request {
|
|
14
|
+
method: HttpMethod;
|
|
15
|
+
url: string;
|
|
16
|
+
path: string;
|
|
17
|
+
headers: Record<string, string | string[] | undefined>;
|
|
18
|
+
query: Record<string, string | string[]>;
|
|
19
|
+
params: Record<string, string>;
|
|
20
|
+
ip?: string;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
interface Response {
|
|
24
|
+
status: number;
|
|
25
|
+
headers: Record<string, string | string[] | undefined>;
|
|
26
|
+
body?: unknown;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
type Route = unknown;
|
|
30
|
+
/**
|
|
31
|
+
* 请求处理器函数
|
|
32
|
+
*/
|
|
33
|
+
type Handler = (ctx: Context) => Promise<void> | void;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* HTTP 服务器类
|
|
37
|
+
*/
|
|
38
|
+
declare class Server {
|
|
39
|
+
/** 路由实例 */
|
|
40
|
+
private router;
|
|
41
|
+
/** 中间件列表 */
|
|
42
|
+
private middlewares;
|
|
43
|
+
/** Node.js 服务器实例 */
|
|
44
|
+
private server?;
|
|
45
|
+
/**
|
|
46
|
+
* 构造函数
|
|
47
|
+
*/
|
|
48
|
+
constructor();
|
|
49
|
+
/**
|
|
50
|
+
* 添加中间件
|
|
51
|
+
*
|
|
52
|
+
* @param middleware - 中间件函数
|
|
53
|
+
* @returns 服务器实例
|
|
54
|
+
*/
|
|
55
|
+
use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this;
|
|
56
|
+
/**
|
|
57
|
+
* 添加路由
|
|
58
|
+
*
|
|
59
|
+
* @param method - HTTP 方法
|
|
60
|
+
* @param path - 路径
|
|
61
|
+
* @param handler - 处理器
|
|
62
|
+
* @returns 服务器实例
|
|
63
|
+
*/
|
|
64
|
+
on(method: HttpMethod, path: string, handler: Handler): this;
|
|
65
|
+
/**
|
|
66
|
+
* 添加 GET 路由
|
|
67
|
+
*
|
|
68
|
+
* @param path - 路径
|
|
69
|
+
* @param handler - 处理器
|
|
70
|
+
* @returns 服务器实例
|
|
71
|
+
*/
|
|
72
|
+
get(path: string, handler: Handler): this;
|
|
73
|
+
/**
|
|
74
|
+
* 添加 POST 路由
|
|
75
|
+
*
|
|
76
|
+
* @param path - 路径
|
|
77
|
+
* @param handler - 处理器
|
|
78
|
+
* @returns 服务器实例
|
|
79
|
+
*/
|
|
80
|
+
post(path: string, handler: Handler): this;
|
|
81
|
+
/**
|
|
82
|
+
* 添加 PUT 路由
|
|
83
|
+
*
|
|
84
|
+
* @param path - 路径
|
|
85
|
+
* @param handler - 处理器
|
|
86
|
+
* @returns 服务器实例
|
|
87
|
+
*/
|
|
88
|
+
put(path: string, handler: Handler): this;
|
|
89
|
+
/**
|
|
90
|
+
* 添加 PATCH 路由
|
|
91
|
+
*
|
|
92
|
+
* @param path - 路径
|
|
93
|
+
* @param handler - 处理器
|
|
94
|
+
* @returns 服务器实例
|
|
95
|
+
*/
|
|
96
|
+
patch(path: string, handler: Handler): this;
|
|
97
|
+
/**
|
|
98
|
+
* 添加 DELETE 路由
|
|
99
|
+
*
|
|
100
|
+
* @param path - 路径
|
|
101
|
+
* @param handler - 处理器
|
|
102
|
+
* @returns 服务器实例
|
|
103
|
+
*/
|
|
104
|
+
delete(path: string, handler: Handler): this;
|
|
105
|
+
/**
|
|
106
|
+
* 启动服务器监听
|
|
107
|
+
*
|
|
108
|
+
* @param port - 端口
|
|
109
|
+
* @param hostname - 主机名
|
|
110
|
+
* @returns Promise
|
|
111
|
+
*/
|
|
112
|
+
listen(port: number, hostname?: string): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* 关闭服务器
|
|
115
|
+
*
|
|
116
|
+
* @returns Promise
|
|
117
|
+
*/
|
|
118
|
+
close(): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* 处理请求
|
|
121
|
+
*
|
|
122
|
+
* @param req - Node.js 请求对象
|
|
123
|
+
* @param res - Node.js 响应对象
|
|
124
|
+
*/
|
|
125
|
+
private handleRequest;
|
|
126
|
+
/**
|
|
127
|
+
* 发送响应
|
|
128
|
+
*
|
|
129
|
+
* @param res - Node.js 响应对象
|
|
130
|
+
* @param response - 响应对象
|
|
131
|
+
*/
|
|
132
|
+
private sendResponse;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 创建 HTTP 服务器
|
|
136
|
+
*
|
|
137
|
+
* @returns 服务器实例
|
|
138
|
+
*/
|
|
139
|
+
declare function createServer(): Server;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* HTTP 路由实现
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 路由类
|
|
147
|
+
*/
|
|
148
|
+
declare class Router {
|
|
149
|
+
/** 路由列表 */
|
|
150
|
+
private routes;
|
|
151
|
+
/**
|
|
152
|
+
* 添加路由
|
|
153
|
+
*
|
|
154
|
+
* @param method - HTTP 方法
|
|
155
|
+
* @param path - 路径
|
|
156
|
+
* @param handler - 处理器
|
|
157
|
+
* @returns 路由实例
|
|
158
|
+
*/
|
|
159
|
+
on(method: HttpMethod, path: string, handler: Handler): this;
|
|
160
|
+
/**
|
|
161
|
+
* 添加 GET 路由
|
|
162
|
+
*
|
|
163
|
+
* @param path - 路径
|
|
164
|
+
* @param handler - 处理器
|
|
165
|
+
* @returns 路由实例
|
|
166
|
+
*/
|
|
167
|
+
get(path: string, handler: Handler): this;
|
|
168
|
+
/**
|
|
169
|
+
* 添加 POST 路由
|
|
170
|
+
*
|
|
171
|
+
* @param path - 路径
|
|
172
|
+
* @param handler - 处理器
|
|
173
|
+
* @returns 路由实例
|
|
174
|
+
*/
|
|
175
|
+
post(path: string, handler: Handler): this;
|
|
176
|
+
/**
|
|
177
|
+
* 添加 PUT 路由
|
|
178
|
+
*
|
|
179
|
+
* @param path - 路径
|
|
180
|
+
* @param handler - 处理器
|
|
181
|
+
* @returns 路由实例
|
|
182
|
+
*/
|
|
183
|
+
put(path: string, handler: Handler): this;
|
|
184
|
+
/**
|
|
185
|
+
* 添加 PATCH 路由
|
|
186
|
+
*
|
|
187
|
+
* @param path - 路径
|
|
188
|
+
* @param handler - 处理器
|
|
189
|
+
* @returns 路由实例
|
|
190
|
+
*/
|
|
191
|
+
patch(path: string, handler: Handler): this;
|
|
192
|
+
/**
|
|
193
|
+
* 添加 DELETE 路由
|
|
194
|
+
*
|
|
195
|
+
* @param path - 路径
|
|
196
|
+
* @param handler - 处理器
|
|
197
|
+
* @returns 路由实例
|
|
198
|
+
*/
|
|
199
|
+
delete(path: string, handler: Handler): this;
|
|
200
|
+
/**
|
|
201
|
+
* 匹配路由
|
|
202
|
+
*
|
|
203
|
+
* @param method - HTTP 方法
|
|
204
|
+
* @param path - 路径
|
|
205
|
+
* @returns 匹配结果或 null
|
|
206
|
+
*/
|
|
207
|
+
match(method: HttpMethod, path: string): {
|
|
208
|
+
handler: Handler;
|
|
209
|
+
params: Record<string, string | string[]>;
|
|
210
|
+
} | null;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* 创建路由
|
|
214
|
+
*
|
|
215
|
+
* @returns 路由实例
|
|
216
|
+
*/
|
|
217
|
+
declare function createRouter(): Router;
|
|
218
|
+
|
|
219
|
+
export { type Context, type Handler, type HttpMethod, type Request, type Response, type Route, Router, Server, createRouter, createServer };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { HttpMethod as HttpMethod$1 } from '@lytjs/shared-types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HTTP 服务器类型定义
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
type HttpMethod = HttpMethod$1;
|
|
8
|
+
interface Context {
|
|
9
|
+
request: Request;
|
|
10
|
+
response: Response;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
interface Request {
|
|
14
|
+
method: HttpMethod;
|
|
15
|
+
url: string;
|
|
16
|
+
path: string;
|
|
17
|
+
headers: Record<string, string | string[] | undefined>;
|
|
18
|
+
query: Record<string, string | string[]>;
|
|
19
|
+
params: Record<string, string>;
|
|
20
|
+
ip?: string;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
interface Response {
|
|
24
|
+
status: number;
|
|
25
|
+
headers: Record<string, string | string[] | undefined>;
|
|
26
|
+
body?: unknown;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
type Route = unknown;
|
|
30
|
+
/**
|
|
31
|
+
* 请求处理器函数
|
|
32
|
+
*/
|
|
33
|
+
type Handler = (ctx: Context) => Promise<void> | void;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* HTTP 服务器类
|
|
37
|
+
*/
|
|
38
|
+
declare class Server {
|
|
39
|
+
/** 路由实例 */
|
|
40
|
+
private router;
|
|
41
|
+
/** 中间件列表 */
|
|
42
|
+
private middlewares;
|
|
43
|
+
/** Node.js 服务器实例 */
|
|
44
|
+
private server?;
|
|
45
|
+
/**
|
|
46
|
+
* 构造函数
|
|
47
|
+
*/
|
|
48
|
+
constructor();
|
|
49
|
+
/**
|
|
50
|
+
* 添加中间件
|
|
51
|
+
*
|
|
52
|
+
* @param middleware - 中间件函数
|
|
53
|
+
* @returns 服务器实例
|
|
54
|
+
*/
|
|
55
|
+
use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this;
|
|
56
|
+
/**
|
|
57
|
+
* 添加路由
|
|
58
|
+
*
|
|
59
|
+
* @param method - HTTP 方法
|
|
60
|
+
* @param path - 路径
|
|
61
|
+
* @param handler - 处理器
|
|
62
|
+
* @returns 服务器实例
|
|
63
|
+
*/
|
|
64
|
+
on(method: HttpMethod, path: string, handler: Handler): this;
|
|
65
|
+
/**
|
|
66
|
+
* 添加 GET 路由
|
|
67
|
+
*
|
|
68
|
+
* @param path - 路径
|
|
69
|
+
* @param handler - 处理器
|
|
70
|
+
* @returns 服务器实例
|
|
71
|
+
*/
|
|
72
|
+
get(path: string, handler: Handler): this;
|
|
73
|
+
/**
|
|
74
|
+
* 添加 POST 路由
|
|
75
|
+
*
|
|
76
|
+
* @param path - 路径
|
|
77
|
+
* @param handler - 处理器
|
|
78
|
+
* @returns 服务器实例
|
|
79
|
+
*/
|
|
80
|
+
post(path: string, handler: Handler): this;
|
|
81
|
+
/**
|
|
82
|
+
* 添加 PUT 路由
|
|
83
|
+
*
|
|
84
|
+
* @param path - 路径
|
|
85
|
+
* @param handler - 处理器
|
|
86
|
+
* @returns 服务器实例
|
|
87
|
+
*/
|
|
88
|
+
put(path: string, handler: Handler): this;
|
|
89
|
+
/**
|
|
90
|
+
* 添加 PATCH 路由
|
|
91
|
+
*
|
|
92
|
+
* @param path - 路径
|
|
93
|
+
* @param handler - 处理器
|
|
94
|
+
* @returns 服务器实例
|
|
95
|
+
*/
|
|
96
|
+
patch(path: string, handler: Handler): this;
|
|
97
|
+
/**
|
|
98
|
+
* 添加 DELETE 路由
|
|
99
|
+
*
|
|
100
|
+
* @param path - 路径
|
|
101
|
+
* @param handler - 处理器
|
|
102
|
+
* @returns 服务器实例
|
|
103
|
+
*/
|
|
104
|
+
delete(path: string, handler: Handler): this;
|
|
105
|
+
/**
|
|
106
|
+
* 启动服务器监听
|
|
107
|
+
*
|
|
108
|
+
* @param port - 端口
|
|
109
|
+
* @param hostname - 主机名
|
|
110
|
+
* @returns Promise
|
|
111
|
+
*/
|
|
112
|
+
listen(port: number, hostname?: string): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* 关闭服务器
|
|
115
|
+
*
|
|
116
|
+
* @returns Promise
|
|
117
|
+
*/
|
|
118
|
+
close(): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* 处理请求
|
|
121
|
+
*
|
|
122
|
+
* @param req - Node.js 请求对象
|
|
123
|
+
* @param res - Node.js 响应对象
|
|
124
|
+
*/
|
|
125
|
+
private handleRequest;
|
|
126
|
+
/**
|
|
127
|
+
* 发送响应
|
|
128
|
+
*
|
|
129
|
+
* @param res - Node.js 响应对象
|
|
130
|
+
* @param response - 响应对象
|
|
131
|
+
*/
|
|
132
|
+
private sendResponse;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 创建 HTTP 服务器
|
|
136
|
+
*
|
|
137
|
+
* @returns 服务器实例
|
|
138
|
+
*/
|
|
139
|
+
declare function createServer(): Server;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* HTTP 路由实现
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 路由类
|
|
147
|
+
*/
|
|
148
|
+
declare class Router {
|
|
149
|
+
/** 路由列表 */
|
|
150
|
+
private routes;
|
|
151
|
+
/**
|
|
152
|
+
* 添加路由
|
|
153
|
+
*
|
|
154
|
+
* @param method - HTTP 方法
|
|
155
|
+
* @param path - 路径
|
|
156
|
+
* @param handler - 处理器
|
|
157
|
+
* @returns 路由实例
|
|
158
|
+
*/
|
|
159
|
+
on(method: HttpMethod, path: string, handler: Handler): this;
|
|
160
|
+
/**
|
|
161
|
+
* 添加 GET 路由
|
|
162
|
+
*
|
|
163
|
+
* @param path - 路径
|
|
164
|
+
* @param handler - 处理器
|
|
165
|
+
* @returns 路由实例
|
|
166
|
+
*/
|
|
167
|
+
get(path: string, handler: Handler): this;
|
|
168
|
+
/**
|
|
169
|
+
* 添加 POST 路由
|
|
170
|
+
*
|
|
171
|
+
* @param path - 路径
|
|
172
|
+
* @param handler - 处理器
|
|
173
|
+
* @returns 路由实例
|
|
174
|
+
*/
|
|
175
|
+
post(path: string, handler: Handler): this;
|
|
176
|
+
/**
|
|
177
|
+
* 添加 PUT 路由
|
|
178
|
+
*
|
|
179
|
+
* @param path - 路径
|
|
180
|
+
* @param handler - 处理器
|
|
181
|
+
* @returns 路由实例
|
|
182
|
+
*/
|
|
183
|
+
put(path: string, handler: Handler): this;
|
|
184
|
+
/**
|
|
185
|
+
* 添加 PATCH 路由
|
|
186
|
+
*
|
|
187
|
+
* @param path - 路径
|
|
188
|
+
* @param handler - 处理器
|
|
189
|
+
* @returns 路由实例
|
|
190
|
+
*/
|
|
191
|
+
patch(path: string, handler: Handler): this;
|
|
192
|
+
/**
|
|
193
|
+
* 添加 DELETE 路由
|
|
194
|
+
*
|
|
195
|
+
* @param path - 路径
|
|
196
|
+
* @param handler - 处理器
|
|
197
|
+
* @returns 路由实例
|
|
198
|
+
*/
|
|
199
|
+
delete(path: string, handler: Handler): this;
|
|
200
|
+
/**
|
|
201
|
+
* 匹配路由
|
|
202
|
+
*
|
|
203
|
+
* @param method - HTTP 方法
|
|
204
|
+
* @param path - 路径
|
|
205
|
+
* @returns 匹配结果或 null
|
|
206
|
+
*/
|
|
207
|
+
match(method: HttpMethod, path: string): {
|
|
208
|
+
handler: Handler;
|
|
209
|
+
params: Record<string, string | string[]>;
|
|
210
|
+
} | null;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* 创建路由
|
|
214
|
+
*
|
|
215
|
+
* @returns 路由实例
|
|
216
|
+
*/
|
|
217
|
+
declare function createRouter(): Router;
|
|
218
|
+
|
|
219
|
+
export { type Context, type Handler, type HttpMethod, type Request, type Response, type Route, Router, Server, createRouter, createServer };
|
package/dist/index.mjs
CHANGED
|
@@ -349,8 +349,9 @@ var Server = class {
|
|
|
349
349
|
let index = this.middlewares.length;
|
|
350
350
|
const next = async () => {
|
|
351
351
|
index--;
|
|
352
|
-
|
|
353
|
-
|
|
352
|
+
const middleware = this.middlewares[index];
|
|
353
|
+
if (index >= 0 && middleware) {
|
|
354
|
+
await middleware(ctx, next);
|
|
354
355
|
} else {
|
|
355
356
|
await handler();
|
|
356
357
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler } from './types';\nimport type { HttpMethod } from '@lytjs/shared-types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler } from './types';\nimport type {\n HttpMethod,\n HttpContext as Context,\n HttpRequest as Request,\n HttpResponse as Response,\n} from '@lytjs/shared-types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: ((ctx: Context, next: () => Promise<void>) => Promise<void>)[] = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n if (index >= 0 && this.middlewares[index]) {\n await this.middlewares[index](ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v);\n }\n } else {\n res.setHeader(key, value);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/router.ts","../src/server.ts"],"names":["createNodeServer"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * HTTP 路由实现\n */\nimport type { Handler, HttpMethod } from './types';\n\n// ===== Token Types =====\n\ninterface TokenStatic {\n type: 'static';\n value: string;\n}\n\ninterface TokenParam {\n type: 'param';\n name: string;\n repeatable: boolean;\n optional: boolean;\n}\n\ninterface TokenWildcard {\n type: 'wildcard';\n value: string;\n}\n\ntype PathToken = TokenStatic | TokenParam | TokenWildcard;\n\n// ===== Path Tokenizer =====\n\nconst PARAM_RE = /^:(\\w+)(\\??)?(\\.\\.\\.)?$/;\nconst WILDCARD_RE = /^\\*$/;\n\n/**\n * Tokenize a path segment string into tokens\n */\nfunction tokenizePath(path: string): PathToken[] {\n const segments = path.split('/');\n const tokens: PathToken[] = [];\n\n for (const segment of segments) {\n if (!segment) continue;\n\n const paramMatch = segment.match(PARAM_RE);\n if (paramMatch) {\n const [, name, optional, repeatable] = paramMatch;\n if (name) {\n tokens.push({\n type: 'param',\n name,\n repeatable: repeatable === '...',\n optional: optional === '?',\n });\n }\n continue;\n }\n\n if (WILDCARD_RE.test(segment)) {\n tokens.push({ type: 'wildcard', value: '*' });\n continue;\n }\n\n tokens.push({ type: 'static', value: segment });\n }\n\n return tokens;\n}\n\n// ===== Path Scoring =====\n\n/**\n * Score a route record for ranking (higher = more specific)\n */\nfunction scoreRoute(tokens: PathToken[]): number {\n let score = 0;\n for (const token of tokens) {\n switch (token.type) {\n case 'static':\n score += 3;\n break;\n case 'param':\n score += token.optional ? 1 : 2;\n break;\n case 'wildcard':\n score += 0;\n break;\n }\n }\n return score;\n}\n\n// ===== Path Matching =====\n\ninterface PathMatchResult {\n matched: boolean;\n params: Record<string, string | string[]>;\n path: string;\n score: number;\n}\n\n/**\n * Match a pathname against a tokenized route\n */\nfunction matchPath(\n pathname: string,\n tokens: PathToken[],\n strict: boolean = false,\n): PathMatchResult {\n const pathSegments = pathname.split('/').filter(Boolean);\n const params: Record<string, string | string[]> = {};\n let matched = true;\n let i = 0;\n\n for (const token of tokens) {\n if (i >= pathSegments.length) {\n if (token.type === 'param' && token.optional) continue;\n if (token.type === 'wildcard') continue;\n matched = false;\n break;\n }\n\n const segment = pathSegments[i];\n\n switch (token.type) {\n case 'static':\n if (segment !== token.value) {\n matched = false;\n }\n i++;\n break;\n\n case 'param':\n if (token.repeatable) {\n params[token.name] = pathSegments.slice(i);\n i = pathSegments.length;\n } else if (segment !== undefined) {\n params[token.name] = segment;\n i++;\n }\n break;\n\n case 'wildcard':\n params[token.value] = pathSegments.slice(i).join('/');\n i = pathSegments.length;\n break;\n }\n\n if (!matched) break;\n }\n\n // Check if all path segments were consumed\n if (matched && i < pathSegments.length) {\n matched = false;\n }\n\n // In non-strict mode, trailing slash is ok\n if (!strict && matched && pathSegments.length === 0 && tokens.length === 0) {\n matched = true;\n }\n\n return {\n matched,\n params,\n path: '/' + pathSegments.slice(0, i).join('/'),\n score: scoreRoute(tokens),\n };\n}\n\n/**\n * 路由类\n */\nexport class Router {\n /** 路由列表 */\n private routes: Array<{\n method: HttpMethod;\n path: string;\n tokens: ReturnType<typeof tokenizePath>;\n handler: Handler;\n }> = [];\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n const tokens = tokenizePath(path);\n this.routes.push({ method, path, tokens, handler });\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 路由实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 匹配路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @returns 匹配结果或 null\n */\n match(\n method: HttpMethod,\n path: string,\n ): { handler: Handler; params: Record<string, string | string[]> } | null {\n const candidates = this.routes.filter((r) => r.method === method);\n\n let bestMatch: { handler: Handler; params: Record<string, string | string[]> } | null = null;\n let bestScore = -1;\n\n for (const route of candidates) {\n const result = matchPath(path, route.tokens);\n if (result.matched && result.score > bestScore) {\n bestScore = result.score;\n bestMatch = { handler: route.handler, params: result.params };\n }\n }\n\n return bestMatch;\n }\n}\n\n/**\n * 创建路由\n *\n * @returns 路由实例\n */\nexport function createRouter(): Router {\n return new Router();\n}\n","/**\n * HTTP 服务器实现\n */\nimport type { Server as NodeServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { createServer as createNodeServer } from 'node:http';\nimport type { Handler, Context, Request, Response, HttpMethod } from './types';\nimport { Router } from './router';\nimport { parseQueryStringWithArrays } from '@lytjs/common-query';\n\n/**\n * HTTP 服务器类\n */\nexport class Server {\n /** 路由实例 */\n private router: Router;\n /** 中间件列表 */\n private middlewares: Array<(ctx: Context, next: () => Promise<void>) => Promise<void>> = [];\n /** Node.js 服务器实例 */\n private server?: NodeServer;\n\n /**\n * 构造函数\n */\n constructor() {\n this.router = new Router();\n }\n\n /**\n * 添加中间件\n *\n * @param middleware - 中间件函数\n * @returns 服务器实例\n */\n use(middleware: (ctx: Context, next: () => Promise<void>) => Promise<void>): this {\n this.middlewares.push(middleware);\n return this;\n }\n\n /**\n * 添加路由\n *\n * @param method - HTTP 方法\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n on(method: HttpMethod, path: string, handler: Handler): this {\n this.router.on(method, path, handler);\n return this;\n }\n\n /**\n * 添加 GET 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n get(path: string, handler: Handler): this {\n return this.on('GET', path, handler);\n }\n\n /**\n * 添加 POST 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n post(path: string, handler: Handler): this {\n return this.on('POST', path, handler);\n }\n\n /**\n * 添加 PUT 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n put(path: string, handler: Handler): this {\n return this.on('PUT', path, handler);\n }\n\n /**\n * 添加 PATCH 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n patch(path: string, handler: Handler): this {\n return this.on('PATCH', path, handler);\n }\n\n /**\n * 添加 DELETE 路由\n *\n * @param path - 路径\n * @param handler - 处理器\n * @returns 服务器实例\n */\n delete(path: string, handler: Handler): this {\n return this.on('DELETE', path, handler);\n }\n\n /**\n * 启动服务器监听\n *\n * @param port - 端口\n * @param hostname - 主机名\n * @returns Promise\n */\n listen(port: number, hostname?: string): Promise<void> {\n return new Promise((resolve) => {\n this.server = createNodeServer(this.handleRequest.bind(this));\n this.server.listen(port, hostname, () => {\n resolve();\n });\n });\n }\n\n /**\n * 关闭服务器\n *\n * @returns Promise\n */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.server.close((err) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n\n /**\n * 处理请求\n *\n * @param req - Node.js 请求对象\n * @param res - Node.js 响应对象\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url || '/';\n const path = url.split('?')[0] || '/';\n const method = (req.method || 'GET') as HttpMethod;\n\n const request: Request = {\n method,\n url,\n path,\n headers: req.headers,\n query: parseQueryStringWithArrays(url),\n params: {},\n ip: req.socket.remoteAddress,\n };\n\n const response: Response = {\n status: 200,\n headers: {},\n };\n\n const ctx: Context = {\n request,\n response,\n };\n\n const match = this.router.match(method, path);\n\n if (match) {\n // 转换类型,确保兼容性\n ctx.request.params = {};\n for (const [key, value] of Object.entries(match.params)) {\n if (Array.isArray(value)) {\n // 如果是数组,只取第一个元素\n ctx.request.params[key] = value[0] || '';\n } else {\n ctx.request.params[key] = value;\n }\n }\n\n const handler = async () => {\n await match.handler(ctx);\n };\n\n let index = this.middlewares.length;\n const next = async () => {\n index--;\n const middleware = this.middlewares[index];\n if (index >= 0 && middleware) {\n await middleware(ctx, next);\n } else {\n await handler();\n }\n };\n\n await next();\n } else {\n if (ctx.response) {\n ctx.response.status = 404;\n ctx.response.body = { error: '未找到' };\n }\n }\n\n if (ctx.response) {\n this.sendResponse(res, ctx.response);\n }\n }\n\n /**\n * 发送响应\n *\n * @param res - Node.js 响应对象\n * @param response - 响应对象\n */\n private sendResponse(res: ServerResponse, response: Response): void {\n res.statusCode = response.status;\n\n for (const [key, value] of Object.entries(response.headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n res.setHeader(key, v as string | number | string[]);\n }\n } else {\n res.setHeader(key, value as string | number | string[]);\n }\n }\n\n if (response.body !== undefined) {\n const body =\n typeof response.body === 'string' ? response.body : JSON.stringify(response.body);\n\n if (!response.headers['content-type']) {\n res.setHeader(\n 'content-type',\n typeof response.body === 'string' ? 'text/plain' : 'application/json',\n );\n }\n\n res.end(body);\n } else {\n res.end();\n }\n }\n}\n\n/**\n * 创建 HTTP 服务器\n *\n * @returns 服务器实例\n */\nexport function createServer(): Server {\n return new Server();\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lytjs/http-server",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"description": "LytJS HTTP 服务器",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"clean": "rm -rf dist node_modules .turbo"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@lytjs/common-is": "^6.
|
|
35
|
-
"@lytjs/common-query": "^6.
|
|
36
|
-
"@lytjs/middleware": "^6.
|
|
37
|
-
"@lytjs/shared-types": "^6.
|
|
34
|
+
"@lytjs/common-is": "^6.9.0",
|
|
35
|
+
"@lytjs/common-query": "^6.9.0",
|
|
36
|
+
"@lytjs/middleware": "^6.9.0",
|
|
37
|
+
"@lytjs/shared-types": "^6.9.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"tsup": "^8.3.6",
|