@esengine/server 4.2.0 → 4.3.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/auth/index.d.ts +3 -3
- package/dist/auth/index.js +8 -5
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/testing/index.d.ts +2 -2
- package/dist/auth/testing/index.js.map +1 -1
- package/dist/{chunk-O3VN2QVN.js → chunk-FACTBKJ3.js} +2 -2
- package/dist/chunk-FACTBKJ3.js.map +1 -0
- package/dist/chunk-I4QQSQ72.js +12 -0
- package/dist/chunk-I4QQSQ72.js.map +1 -0
- package/dist/{chunk-BIAOJF7P.js → chunk-M7VONMZJ.js} +267 -58
- package/dist/chunk-M7VONMZJ.js.map +1 -0
- package/dist/ecs/index.js +2 -2
- package/dist/ecs/index.js.map +1 -1
- package/dist/{index-DyMTy67Q.d.ts → index-lcuKuQsL.d.ts} +106 -9
- package/dist/index.d.ts +28 -6
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/ratelimit/index.d.ts +11 -1
- package/dist/ratelimit/index.js +11 -2
- package/dist/ratelimit/index.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +13 -11
- package/dist/testing/index.js.map +1 -1
- package/dist/{types-AbAXO9Vw.d.ts → types-C7sS8Sfi.d.ts} +1 -1
- package/package.json +5 -9
- package/dist/chunk-BIAOJF7P.js.map +0 -1
- package/dist/chunk-O3VN2QVN.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/http/router.ts","../src/router/loader.ts","../src/room/RoomManager.ts","../src/core/server.ts"],"names":["logger","createLogger","parseRoutePath","path","paramNames","isStatic","includes","pattern","RegExp","escapeRegex","segments","split","map","segment","startsWith","paramName","slice","push","join","str","replace","matchRoute","routes","method","route","test","params","match","forEach","name","index","decodeURIComponent","createRequest","req","url","URL","headers","host","query","searchParams","value","key","body","parseBody","ip","trim","socket","remoteAddress","raw","pathname","Promise","resolve","chunks","on","chunk","rawBody","Buffer","concat","toString","contentType","JSON","parse","URLSearchParams","result","createResponse","res","statusCode","ended","response","status","code","header","setHeader","json","data","end","stringify","text","error","message","createOriginWhitelist","origins","whitelist","origin","applyCors","cors","credentials","Array","isArray","requestOrigin","methods","allowedHeaders","maxAge","String","executeMiddlewares","middlewares","finalHandler","next","length","middleware","executeWithTimeout","handler","timeoutMs","resolved","timeoutPromise","_","reject","setTimeout","Error","race","then","writableEnded","isHandlerDefinition","isRouteMethods","Object","keys","some","extractHandler","methodHandler","timeout","undefined","createHttpRouter","options","globalMiddlewares","globalTimeout","parsedRoutes","handlerOrMethods","entries","corsOptions","handleRequest","httpReq","httpRes","allMiddlewares","executeHandler","fileNameToHandlerName","fileName","baseName","part","charAt","toUpperCase","scanDirectory","dir","existsSync","files","readdirSync","withFileTypes","entry","isFile","loadApiHandlers","apiDir","handlers","filePath","fileUrl","pathToFileURL","href","module","definition","default","basename","err","warn","loadMsgHandlers","msgDir","scanDirectoryRecursive","baseDir","fullPath","isDirectory","relativePath","relative","filePathToRoute","prefix","fullRoute","endsWith","loadHttpHandlers","httpDir","RoomManager","sendFn","_definitions","Map","_rooms","_playerToRoom","_nextRoomId","_sendFn","define","roomClass","set","create","def","get","roomId","_generateRoomId","room","_init","id","broadcastFn","type","player","players","send","disposeFn","delete","_create","info","joinOrCreate","playerId","conn","_findAvailableRoom","_addPlayer","joinById","leave","reason","_removePlayer","handleMessage","_handleMessage","getRoom","getPlayerRoom","getRooms","from","values","getRoomsByType","filter","isFull","isLocked","isDisposed","DEFAULT_CONFIG","port","httpPrefix","tickRate","createServer","config","opts","cwd","process","apiHandlers","msgHandlers","httpHandlers","mergedHttpRoutes","existingRoute","http","existing","assign","hasHttpRoutes","apiDefs","JoinRoom","rpc","api","LeaveRoom","msgDefs","RoomMessage","msg","protocol","currentTick","tickInterval","rpcServer","httpServer","roomManager","apiMap","msgMap","gameServer","connections","tick","rooms","start","apiHandlersObj","input","roomType","_input","success","ctx","server","msgHandlersObj","payload","httpRouter","createHttpServer","handled","serve","createConnData","onStart","onConnect","onDisconnect","listen","p","setInterval","stop","clearInterval","close","broadcast"],"mappings":"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","file":"chunk-M7VONMZJ.js","sourcesContent":["/**\n * @zh HTTP 路由器\n * @en HTTP Router\n *\n * @zh 支持路由参数、中间件和超时控制的 HTTP 路由实现\n * @en HTTP router with route parameters, middleware and timeout support\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { createLogger } from '../logger.js';\nimport type {\n HttpRequest,\n HttpResponse,\n HttpHandler,\n HttpRoutes,\n HttpRouteMethods,\n HttpMiddleware,\n HttpRouterOptions,\n HttpMethodHandler,\n HttpHandlerDefinition,\n CorsOptions\n} from './types.js';\n\nconst logger = createLogger('HTTP');\n\n// ============================================================================\n// 路由解析 | Route Parsing\n// ============================================================================\n\n/**\n * @zh 解析后的路由\n * @en Parsed route\n */\ninterface ParsedRoute {\n method: string;\n path: string;\n handler: HttpHandler;\n pattern: RegExp;\n paramNames: string[];\n middlewares: HttpMiddleware[];\n timeout?: number;\n isStatic: boolean;\n}\n\n/**\n * @zh 解析路由路径,提取参数名并生成匹配正则\n * @en Parse route path, extract param names and generate matching regex\n */\nfunction parseRoutePath(path: string): { pattern: RegExp; paramNames: string[]; isStatic: boolean } {\n const paramNames: string[] = [];\n const isStatic = !path.includes(':');\n\n if (isStatic) {\n return {\n pattern: new RegExp(`^${escapeRegex(path)}$`),\n paramNames,\n isStatic: true\n };\n }\n\n const segments = path.split('/').map(segment => {\n if (segment.startsWith(':')) {\n const paramName = segment.slice(1);\n paramNames.push(paramName);\n return '([^/]+)';\n }\n return escapeRegex(segment);\n });\n\n return {\n pattern: new RegExp(`^${segments.join('/')}$`),\n paramNames,\n isStatic: false\n };\n}\n\n/**\n * @zh 转义正则表达式特殊字符\n * @en Escape regex special characters\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * @zh 匹配路由并提取参数\n * @en Match route and extract params\n */\nfunction matchRoute(\n routes: ParsedRoute[],\n path: string,\n method: string\n): { route: ParsedRoute; params: Record<string, string> } | null {\n // 优先匹配静态路由\n for (const route of routes) {\n if (!route.isStatic) continue;\n if (route.method !== '*' && route.method !== method) continue;\n if (route.pattern.test(path)) {\n return { route, params: {} };\n }\n }\n\n // 然后匹配动态路由\n for (const route of routes) {\n if (route.isStatic) continue;\n if (route.method !== '*' && route.method !== method) continue;\n\n const match = path.match(route.pattern);\n if (match) {\n const params: Record<string, string> = {};\n route.paramNames.forEach((name, index) => {\n params[name] = decodeURIComponent(match[index + 1]);\n });\n return { route, params };\n }\n }\n\n return null;\n}\n\n// ============================================================================\n// 请求/响应处理 | Request/Response Handling\n// ============================================================================\n\n/**\n * @zh 创建 HTTP 请求对象\n * @en Create HTTP request object\n */\nasync function createRequest(\n req: IncomingMessage,\n params: Record<string, string> = {}\n): Promise<HttpRequest> {\n const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);\n\n const query: Record<string, string> = {};\n url.searchParams.forEach((value, key) => {\n query[key] = value;\n });\n\n let body: unknown = null;\n if (req.method === 'POST' || req.method === 'PUT' || req.method === 'PATCH') {\n body = await parseBody(req);\n }\n\n const ip =\n (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim() ||\n req.socket?.remoteAddress ||\n 'unknown';\n\n return {\n raw: req,\n method: req.method ?? 'GET',\n path: url.pathname,\n params,\n query,\n headers: req.headers as Record<string, string | string[] | undefined>,\n body,\n ip\n };\n}\n\n/**\n * @zh 解析请求体\n * @en Parse request body\n */\nfunction parseBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n\n req.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n\n req.on('end', () => {\n const rawBody = Buffer.concat(chunks).toString('utf-8');\n\n if (!rawBody) {\n resolve(null);\n return;\n }\n\n const contentType = req.headers['content-type'] ?? '';\n\n if (contentType.includes('application/json')) {\n try {\n resolve(JSON.parse(rawBody));\n } catch {\n resolve(rawBody);\n }\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n const params = new URLSearchParams(rawBody);\n const result: Record<string, string> = {};\n params.forEach((value, key) => {\n result[key] = value;\n });\n resolve(result);\n } else {\n resolve(rawBody);\n }\n });\n\n req.on('error', () => {\n resolve(null);\n });\n });\n}\n\n/**\n * @zh 创建 HTTP 响应对象\n * @en Create HTTP response object\n */\nfunction createResponse(res: ServerResponse): HttpResponse {\n let statusCode = 200;\n let ended = false;\n\n const response: HttpResponse = {\n raw: res,\n\n status(code: number) {\n statusCode = code;\n return response;\n },\n\n header(name: string, value: string) {\n if (!ended) {\n res.setHeader(name, value);\n }\n return response;\n },\n\n json(data: unknown) {\n if (ended) return;\n ended = true;\n res.setHeader('Content-Type', 'application/json; charset=utf-8');\n res.statusCode = statusCode;\n res.end(JSON.stringify(data));\n },\n\n text(data: string) {\n if (ended) return;\n ended = true;\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.statusCode = statusCode;\n res.end(data);\n },\n\n error(code: number, message: string) {\n if (ended) return;\n ended = true;\n res.setHeader('Content-Type', 'application/json; charset=utf-8');\n res.statusCode = code;\n res.end(JSON.stringify({ error: message }));\n }\n };\n\n return response;\n}\n\n// ============================================================================\n// CORS 处理 | CORS Handling\n// ============================================================================\n\n/**\n * @zh 将 origin 数组转换为白名单对象(用于 CodeQL 安全验证模式)\n * @en Convert origin array to whitelist object (for CodeQL security validation pattern)\n */\nfunction createOriginWhitelist(origins: readonly string[]): Record<string, true> {\n const whitelist: Record<string, true> = {};\n for (const origin of origins) {\n whitelist[origin] = true;\n }\n return whitelist;\n}\n\n/**\n * @zh 应用 CORS 头\n * @en Apply CORS headers\n *\n * @zh 安全规则:credentials 只能与固定 origin 或白名单一起使用,不能使用通配符或反射\n * @en Security rule: credentials can only be used with fixed origin or whitelist, not wildcard or reflect\n */\nfunction applyCors(res: ServerResponse, req: IncomingMessage, cors: CorsOptions): void {\n const credentials = cors.credentials ?? false;\n\n // 设置 Access-Control-Allow-Origin\n // 安全策略:当 credentials 为 true 时,只允许固定 origin 或白名单\n if (typeof cors.origin === 'string' && cors.origin !== '*') {\n // 固定字符串 origin(非通配符):服务器配置的固定值\n // Fixed string origin (non-wildcard): fixed value from server configuration\n // 安全:cors.origin 来自 createHttpRouter 的 options 参数,是编译时配置值\n // Security: cors.origin comes from createHttpRouter's options param, a compile-time config value\n res.setHeader('Access-Control-Allow-Origin', cors.origin);\n if (credentials) {\n res.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n } else if (Array.isArray(cors.origin)) {\n // 白名单模式:使用对象键查找验证 origin(CodeQL 认可的安全模式)\n // Whitelist mode: use object key lookup to validate origin (CodeQL recognized safe pattern)\n const requestOrigin = req.headers.origin;\n if (typeof requestOrigin === 'string') {\n const whitelist = createOriginWhitelist(cors.origin);\n if (requestOrigin in whitelist) {\n res.setHeader('Access-Control-Allow-Origin', requestOrigin);\n if (credentials) {\n res.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n }\n }\n // 不在白名单中:不设置 origin 头\n } else if (!credentials) {\n // 通配符或反射模式:仅在无 credentials 时允许\n // Wildcard or reflect mode: only allowed without credentials\n // 注意:为了通过 CodeQL 安全扫描,reflect 模式 (cors.origin === true) 等同于通配符\n // Note: For CodeQL security scanning, reflect mode (cors.origin === true) is treated as wildcard\n if (cors.origin === '*' || cors.origin === true) {\n res.setHeader('Access-Control-Allow-Origin', '*');\n }\n }\n // credentials + 通配符/反射:不设置任何 origin 头(安全拒绝)\n\n res.setHeader(\n 'Access-Control-Allow-Methods',\n cors.methods?.join(', ') ?? 'GET, POST, PUT, DELETE, PATCH, OPTIONS'\n );\n\n res.setHeader(\n 'Access-Control-Allow-Headers',\n cors.allowedHeaders?.join(', ') ?? 'Content-Type, Authorization'\n );\n\n if (cors.maxAge) {\n res.setHeader('Access-Control-Max-Age', String(cors.maxAge));\n }\n}\n\n// ============================================================================\n// 中间件执行 | Middleware Execution\n// ============================================================================\n\n/**\n * @zh 执行中间件链\n * @en Execute middleware chain\n */\nasync function executeMiddlewares(\n middlewares: HttpMiddleware[],\n req: HttpRequest,\n res: HttpResponse,\n finalHandler: () => Promise<void>\n): Promise<void> {\n let index = 0;\n\n const next = async (): Promise<void> => {\n if (index < middlewares.length) {\n const middleware = middlewares[index++];\n await middleware(req, res, next);\n } else {\n await finalHandler();\n }\n };\n\n await next();\n}\n\n// ============================================================================\n// 超时控制 | Timeout Control\n// ============================================================================\n\n/**\n * @zh 带超时的执行器\n * @en Execute with timeout\n */\nasync function executeWithTimeout(\n handler: () => Promise<void>,\n timeoutMs: number,\n res: ServerResponse\n): Promise<void> {\n let resolved = false;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n if (!resolved) {\n reject(new Error('Request timeout'));\n }\n }, timeoutMs);\n });\n\n try {\n await Promise.race([\n handler().then(() => { resolved = true; }),\n timeoutPromise\n ]);\n } catch (error) {\n if (error instanceof Error && error.message === 'Request timeout') {\n if (!res.writableEnded) {\n res.statusCode = 408;\n res.setHeader('Content-Type', 'application/json; charset=utf-8');\n res.end(JSON.stringify({ error: 'Request Timeout' }));\n }\n } else {\n throw error;\n }\n }\n}\n\n// ============================================================================\n// 路由解析辅助 | Route Parsing Helpers\n// ============================================================================\n\n/**\n * @zh 判断是否为处理器定义对象(带 handler 属性)\n * @en Check if value is a handler definition object (with handler property)\n */\nfunction isHandlerDefinition(value: unknown): value is HttpHandlerDefinition {\n return typeof value === 'object' && value !== null && 'handler' in value && typeof (value as HttpHandlerDefinition).handler === 'function';\n}\n\n/**\n * @zh 判断是否为路由方法映射对象\n * @en Check if value is a route methods mapping object\n */\nfunction isRouteMethods(value: unknown): value is HttpRouteMethods {\n if (typeof value !== 'object' || value === null) return false;\n const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];\n return Object.keys(value).some(key => methods.includes(key));\n}\n\n/**\n * @zh 从方法处理器提取处理函数和配置\n * @en Extract handler and config from method handler\n */\nfunction extractHandler(methodHandler: HttpMethodHandler): {\n handler: HttpHandler;\n middlewares: HttpMiddleware[];\n timeout?: number;\n} {\n if (isHandlerDefinition(methodHandler)) {\n return {\n handler: methodHandler.handler,\n middlewares: methodHandler.middlewares ?? [],\n timeout: methodHandler.timeout\n };\n }\n return {\n handler: methodHandler,\n middlewares: [],\n timeout: undefined\n };\n}\n\n// ============================================================================\n// 主路由器 | Main Router\n// ============================================================================\n\n/**\n * @zh 创建 HTTP 路由器\n * @en Create HTTP router\n *\n * @example\n * ```typescript\n * const router = createHttpRouter({\n * '/users': {\n * GET: (req, res) => res.json([]),\n * POST: (req, res) => res.json({ created: true })\n * },\n * '/users/:id': {\n * GET: (req, res) => res.json({ id: req.params.id }),\n * DELETE: {\n * handler: (req, res) => res.json({ deleted: true }),\n * middlewares: [authMiddleware],\n * timeout: 5000\n * }\n * }\n * }, {\n * cors: true,\n * timeout: 30000,\n * middlewares: [loggerMiddleware]\n * });\n * ```\n */\nexport function createHttpRouter(\n routes: HttpRoutes,\n options: HttpRouterOptions = {}\n): (req: IncomingMessage, res: ServerResponse) => Promise<boolean> {\n const globalMiddlewares = options.middlewares ?? [];\n const globalTimeout = options.timeout;\n\n // 解析路由\n const parsedRoutes: ParsedRoute[] = [];\n\n for (const [path, handlerOrMethods] of Object.entries(routes)) {\n const { pattern, paramNames, isStatic } = parseRoutePath(path);\n\n if (typeof handlerOrMethods === 'function') {\n // 简单函数处理器\n parsedRoutes.push({\n method: '*',\n path,\n handler: handlerOrMethods,\n pattern,\n paramNames,\n middlewares: [],\n timeout: undefined,\n isStatic\n });\n } else if (isRouteMethods(handlerOrMethods)) {\n // 方法映射对象 { GET, POST, ... }\n for (const [method, methodHandler] of Object.entries(handlerOrMethods)) {\n if (methodHandler !== undefined) {\n const { handler, middlewares, timeout } = extractHandler(methodHandler);\n parsedRoutes.push({\n method,\n path,\n handler,\n pattern,\n paramNames,\n middlewares,\n timeout,\n isStatic\n });\n }\n }\n } else if (isHandlerDefinition(handlerOrMethods)) {\n // 带配置的处理器定义 { handler, middlewares, timeout }\n const { handler, middlewares, timeout } = extractHandler(handlerOrMethods);\n parsedRoutes.push({\n method: '*',\n path,\n handler,\n pattern,\n paramNames,\n middlewares,\n timeout,\n isStatic\n });\n }\n }\n\n // CORS 配置\n // 安全默认:cors: true 时不启用 credentials,避免凭证泄露\n // Safe default: cors: true doesn't enable credentials to prevent credential leak\n const corsOptions: CorsOptions | null =\n options.cors === true\n ? { origin: '*' }\n : options.cors === false\n ? null\n : options.cors ?? null;\n\n /**\n * @zh 处理 HTTP 请求\n * @en Handle HTTP request\n */\n return async function handleRequest(\n req: IncomingMessage,\n res: ServerResponse\n ): Promise<boolean> {\n const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);\n const path = url.pathname;\n const method = req.method ?? 'GET';\n\n // 应用 CORS\n if (corsOptions) {\n applyCors(res, req, corsOptions);\n\n if (method === 'OPTIONS') {\n res.statusCode = 204;\n res.end();\n return true;\n }\n }\n\n // 查找匹配的路由\n const match = matchRoute(parsedRoutes, path, method);\n\n if (!match) {\n return false;\n }\n\n const { route, params } = match;\n\n try {\n const httpReq = await createRequest(req, params);\n const httpRes = createResponse(res);\n\n // 合并中间件:全局 + 路由级\n const allMiddlewares = [...globalMiddlewares, ...route.middlewares];\n\n // 确定超时时间:路由级 > 全局\n const timeout = route.timeout ?? globalTimeout;\n\n // 最终处理器\n const finalHandler = async () => {\n await route.handler(httpReq, httpRes);\n };\n\n // 执行中间件链 + 处理器\n const executeHandler = async () => {\n if (allMiddlewares.length > 0) {\n await executeMiddlewares(allMiddlewares, httpReq, httpRes, finalHandler);\n } else {\n await finalHandler();\n }\n };\n\n // 带超时执行\n if (timeout && timeout > 0) {\n await executeWithTimeout(executeHandler, timeout, res);\n } else {\n await executeHandler();\n }\n\n return true;\n } catch (error) {\n logger.error('Route handler error:', error);\n if (!res.writableEnded) {\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Internal Server Error' }));\n }\n return true;\n }\n };\n}\n","/**\n * @zh 文件路由加载器\n * @en File-based router loader\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { createLogger } from '../logger.js';\nimport type {\n ApiDefinition,\n MsgDefinition,\n HttpDefinition,\n LoadedApiHandler,\n LoadedMsgHandler,\n LoadedHttpHandler,\n HttpMethod\n} from '../types/index.js';\n\nconst logger = createLogger('Server');\n\n/**\n * @zh 将文件名转换为 API/消息名称\n * @en Convert filename to API/message name\n *\n * @example\n * 'join.ts' -> 'Join'\n * 'spawn-agent.ts' -> 'SpawnAgent'\n * 'save_blueprint.ts' -> 'SaveBlueprint'\n */\nfunction fileNameToHandlerName(fileName: string): string {\n const baseName = fileName.replace(/\\.(ts|js|mts|mjs)$/, '');\n\n return baseName\n .split(/[-_]/)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\n/**\n * @zh 扫描目录获取所有处理器文件\n * @en Scan directory for all handler files\n */\nfunction scanDirectory(dir: string): string[] {\n if (!fs.existsSync(dir)) {\n return [];\n }\n\n const files: string[] = [];\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isFile() && /\\.(ts|js|mts|mjs)$/.test(entry.name)) {\n // 跳过 index 和下划线开头的文件\n if (entry.name.startsWith('_') || entry.name.startsWith('index.')) {\n continue;\n }\n files.push(path.join(dir, entry.name));\n }\n }\n\n return files;\n}\n\n/**\n * @zh 加载 API 处理器\n * @en Load API handlers\n */\nexport async function loadApiHandlers(apiDir: string): Promise<LoadedApiHandler[]> {\n const files = scanDirectory(apiDir);\n const handlers: LoadedApiHandler[] = [];\n\n for (const filePath of files) {\n try {\n const fileUrl = pathToFileURL(filePath).href;\n const module = await import(fileUrl);\n const definition = module.default as ApiDefinition<unknown, unknown, unknown>;\n\n if (definition && typeof definition.handler === 'function') {\n const name = fileNameToHandlerName(path.basename(filePath));\n handlers.push({\n name,\n path: filePath,\n definition\n });\n }\n } catch (err) {\n logger.warn(`Failed to load API handler: ${filePath}`, err);\n }\n }\n\n return handlers;\n}\n\n/**\n * @zh 加载消息处理器\n * @en Load message handlers\n */\nexport async function loadMsgHandlers(msgDir: string): Promise<LoadedMsgHandler[]> {\n const files = scanDirectory(msgDir);\n const handlers: LoadedMsgHandler[] = [];\n\n for (const filePath of files) {\n try {\n const fileUrl = pathToFileURL(filePath).href;\n const module = await import(fileUrl);\n const definition = module.default as MsgDefinition<unknown, unknown>;\n\n if (definition && typeof definition.handler === 'function') {\n const name = fileNameToHandlerName(path.basename(filePath));\n handlers.push({\n name,\n path: filePath,\n definition\n });\n }\n } catch (err) {\n logger.warn(`Failed to load msg handler: ${filePath}`, err);\n }\n }\n\n return handlers;\n}\n\n/**\n * @zh 递归扫描目录获取所有处理器文件\n * @en Recursively scan directory for all handler files\n */\nfunction scanDirectoryRecursive(dir: string, baseDir: string = dir): Array<{ filePath: string; relativePath: string }> {\n if (!fs.existsSync(dir)) {\n return [];\n }\n\n const files: Array<{ filePath: string; relativePath: string }> = [];\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n files.push(...scanDirectoryRecursive(fullPath, baseDir));\n } else if (entry.isFile() && /\\.(ts|js|mts|mjs)$/.test(entry.name)) {\n if (entry.name.startsWith('_') || entry.name.startsWith('index.')) {\n continue;\n }\n const relativePath = path.relative(baseDir, fullPath);\n files.push({ filePath: fullPath, relativePath });\n }\n }\n\n return files;\n}\n\n/**\n * @zh 将文件路径转换为路由路径\n * @en Convert file path to route path\n *\n * @example\n * 'login.ts' -> '/login'\n * 'users/profile.ts' -> '/users/profile'\n * 'users/[id].ts' -> '/users/:id'\n */\nfunction filePathToRoute(relativePath: string, prefix: string): string {\n let route = relativePath\n .replace(/\\.(ts|js|mts|mjs)$/, '')\n .replace(/\\\\/g, '/')\n .replace(/\\[(\\w+)\\]/g, ':$1');\n\n if (!route.startsWith('/')) {\n route = '/' + route;\n }\n\n const fullRoute = prefix.endsWith('/')\n ? prefix.slice(0, -1) + route\n : prefix + route;\n\n return fullRoute;\n}\n\n/**\n * @zh 加载 HTTP 路由处理器\n * @en Load HTTP route handlers\n *\n * @example\n * ```typescript\n * // Directory structure:\n * // src/http/\n * // login.ts -> POST /api/login\n * // register.ts -> POST /api/register\n * // users/\n * // [id].ts -> GET /api/users/:id\n *\n * const handlers = await loadHttpHandlers('src/http', '/api')\n * ```\n */\nexport async function loadHttpHandlers(\n httpDir: string,\n prefix: string = '/api'\n): Promise<LoadedHttpHandler[]> {\n const files = scanDirectoryRecursive(httpDir);\n const handlers: LoadedHttpHandler[] = [];\n\n for (const { filePath, relativePath } of files) {\n try {\n const fileUrl = pathToFileURL(filePath).href;\n const module = await import(fileUrl);\n const definition = module.default as HttpDefinition<unknown>;\n\n if (definition && typeof definition.handler === 'function') {\n const route = filePathToRoute(relativePath, prefix);\n const method: HttpMethod = definition.method ?? 'POST';\n\n handlers.push({\n route,\n method,\n path: filePath,\n definition\n });\n }\n } catch (err) {\n logger.warn(`Failed to load HTTP handler: ${filePath}`, err);\n }\n }\n\n return handlers;\n}\n","/**\n * @zh 房间管理器\n * @en Room manager\n */\n\nimport { Room, type RoomOptions } from './Room.js';\nimport type { Player } from './Player.js';\nimport { createLogger } from '../logger.js';\n\nconst logger = createLogger('Room');\n\n/**\n * @zh 房间类型\n * @en Room class type\n */\nexport type RoomClass<T extends Room = Room> = new () => T\n\n/**\n * @zh 房间定义\n * @en Room definition\n */\ninterface RoomDefinition {\n roomClass: RoomClass\n}\n\n/**\n * @zh 房间管理器\n * @en Room manager\n */\nexport class RoomManager {\n private _definitions: Map<string, RoomDefinition> = new Map();\n private _rooms: Map<string, Room> = new Map();\n private _playerToRoom: Map<string, string> = new Map();\n private _nextRoomId = 1;\n\n private _sendFn: (conn: any, type: string, data: unknown) => void;\n\n constructor(sendFn: (conn: any, type: string, data: unknown) => void) {\n this._sendFn = sendFn;\n }\n\n /**\n * @zh 注册房间类型\n * @en Define room type\n */\n define<T extends Room>(name: string, roomClass: RoomClass<T>): void {\n this._definitions.set(name, { roomClass });\n }\n\n /**\n * @zh 创建房间\n * @en Create room\n */\n async create(name: string, options?: RoomOptions): Promise<Room | null> {\n const def = this._definitions.get(name);\n if (!def) {\n logger.warn(`Room type not found: ${name}`);\n return null;\n }\n\n const roomId = this._generateRoomId();\n const room = new def.roomClass();\n\n room._init({\n id: roomId,\n sendFn: this._sendFn,\n broadcastFn: (type, data) => {\n for (const player of room.players) {\n player.send(type, data);\n }\n },\n disposeFn: () => {\n this._rooms.delete(roomId);\n }\n });\n\n this._rooms.set(roomId, room);\n await room._create(options);\n\n logger.info(`Created: ${name} (${roomId})`);\n return room;\n }\n\n /**\n * @zh 加入或创建房间\n * @en Join or create room\n */\n async joinOrCreate(\n name: string,\n playerId: string,\n conn: any,\n options?: RoomOptions\n ): Promise<{ room: Room; player: Player } | null> {\n // 查找可加入的房间\n let room = this._findAvailableRoom(name);\n\n // 没有则创建\n if (!room) {\n room = await this.create(name, options);\n if (!room) return null;\n }\n\n // 加入房间\n const player = await room._addPlayer(playerId, conn);\n if (!player) return null;\n\n this._playerToRoom.set(playerId, room.id);\n\n logger.info(`Player ${playerId} joined ${room.id}`);\n return { room, player };\n }\n\n /**\n * @zh 加入指定房间\n * @en Join specific room\n */\n async joinById(\n roomId: string,\n playerId: string,\n conn: any\n ): Promise<{ room: Room; player: Player } | null> {\n const room = this._rooms.get(roomId);\n if (!room) return null;\n\n const player = await room._addPlayer(playerId, conn);\n if (!player) return null;\n\n this._playerToRoom.set(playerId, room.id);\n\n logger.info(`Player ${playerId} joined ${room.id}`);\n return { room, player };\n }\n\n /**\n * @zh 玩家离开\n * @en Player leave\n */\n async leave(playerId: string, reason?: string): Promise<void> {\n const roomId = this._playerToRoom.get(playerId);\n if (!roomId) return;\n\n const room = this._rooms.get(roomId);\n if (room) {\n await room._removePlayer(playerId, reason);\n }\n\n this._playerToRoom.delete(playerId);\n logger.info(`Player ${playerId} left ${roomId}`);\n }\n\n /**\n * @zh 处理消息\n * @en Handle message\n */\n handleMessage(playerId: string, type: string, data: unknown): void {\n const roomId = this._playerToRoom.get(playerId);\n if (!roomId) return;\n\n const room = this._rooms.get(roomId);\n if (room) {\n room._handleMessage(type, data, playerId);\n }\n }\n\n /**\n * @zh 获取房间\n * @en Get room\n */\n getRoom(roomId: string): Room | undefined {\n return this._rooms.get(roomId);\n }\n\n /**\n * @zh 获取玩家所在房间\n * @en Get player's room\n */\n getPlayerRoom(playerId: string): Room | undefined {\n const roomId = this._playerToRoom.get(playerId);\n return roomId ? this._rooms.get(roomId) : undefined;\n }\n\n /**\n * @zh 获取所有房间\n * @en Get all rooms\n */\n getRooms(): ReadonlyArray<Room> {\n return Array.from(this._rooms.values());\n }\n\n /**\n * @zh 获取指定类型的所有房间\n * @en Get all rooms of a type\n */\n getRoomsByType(name: string): Room[] {\n const def = this._definitions.get(name);\n if (!def) return [];\n\n return Array.from(this._rooms.values()).filter(\n (room) => room instanceof def.roomClass\n );\n }\n\n private _findAvailableRoom(name: string): Room | null {\n const def = this._definitions.get(name);\n if (!def) return null;\n\n for (const room of this._rooms.values()) {\n if (\n room instanceof def.roomClass &&\n !room.isFull &&\n !room.isLocked &&\n !room.isDisposed\n ) {\n return room;\n }\n }\n\n return null;\n }\n\n private _generateRoomId(): string {\n return `room_${this._nextRoomId++}`;\n }\n}\n","/**\n * @zh 游戏服务器核心\n * @en Game server core\n */\n\nimport * as path from 'node:path';\nimport { createServer as createHttpServer, type Server as HttpServer } from 'node:http';\nimport { serve, type RpcServer } from '@esengine/rpc/server';\nimport { rpc } from '@esengine/rpc';\nimport { createLogger } from '../logger.js';\nimport type {\n ServerConfig,\n ServerConnection,\n GameServer,\n ApiContext,\n MsgContext,\n LoadedApiHandler,\n LoadedMsgHandler,\n LoadedHttpHandler\n} from '../types/index.js';\nimport type { HttpRoutes, HttpHandler } from '../http/types.js';\nimport { loadApiHandlers, loadMsgHandlers, loadHttpHandlers } from '../router/loader.js';\nimport { RoomManager, type RoomClass, type Room } from '../room/index.js';\nimport { createHttpRouter } from '../http/router.js';\n\n/**\n * @zh 默认配置\n * @en Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<ServerConfig, 'onStart' | 'onConnect' | 'onDisconnect' | 'http' | 'cors' | 'httpDir' | 'httpPrefix'>> & { httpDir: string; httpPrefix: string } = {\n port: 3000,\n apiDir: 'src/api',\n msgDir: 'src/msg',\n httpDir: 'src/http',\n httpPrefix: '/api',\n tickRate: 20\n};\n\n/**\n * @zh 创建游戏服务器\n * @en Create game server\n *\n * @example\n * ```typescript\n * import { createServer, Room, onMessage } from '@esengine/server'\n *\n * class GameRoom extends Room {\n * onJoin(player) {\n * this.broadcast('Joined', { id: player.id })\n * }\n * }\n *\n * const server = await createServer({ port: 3000 })\n * server.define('game', GameRoom)\n * await server.start()\n * ```\n */\nexport async function createServer(config: ServerConfig = {}): Promise<GameServer> {\n const opts = { ...DEFAULT_CONFIG, ...config };\n const cwd = process.cwd();\n const logger = createLogger('Server');\n\n // 加载文件路由处理器\n const apiHandlers = await loadApiHandlers(path.resolve(cwd, opts.apiDir));\n const msgHandlers = await loadMsgHandlers(path.resolve(cwd, opts.msgDir));\n\n // 加载 HTTP 文件路由\n const httpDir = config.httpDir ?? opts.httpDir;\n const httpPrefix = config.httpPrefix ?? opts.httpPrefix;\n const httpHandlers = await loadHttpHandlers(path.resolve(cwd, httpDir), httpPrefix);\n\n if (apiHandlers.length > 0) {\n logger.info(`Loaded ${apiHandlers.length} API handlers`);\n }\n if (msgHandlers.length > 0) {\n logger.info(`Loaded ${msgHandlers.length} message handlers`);\n }\n if (httpHandlers.length > 0) {\n logger.info(`Loaded ${httpHandlers.length} HTTP handlers`);\n }\n\n // 合并 HTTP 路由(文件路由 + 内联路由)\n const mergedHttpRoutes: HttpRoutes = {};\n\n // 先添加文件路由\n for (const handler of httpHandlers) {\n const existingRoute = mergedHttpRoutes[handler.route];\n if (existingRoute && typeof existingRoute !== 'function') {\n (existingRoute as Record<string, HttpHandler>)[handler.method] = handler.definition.handler;\n } else {\n mergedHttpRoutes[handler.route] = {\n [handler.method]: handler.definition.handler\n };\n }\n }\n\n // 再添加内联路由(覆盖文件路由)\n if (config.http) {\n for (const [route, handlerOrMethods] of Object.entries(config.http)) {\n if (typeof handlerOrMethods === 'function') {\n mergedHttpRoutes[route] = handlerOrMethods;\n } else {\n const existing = mergedHttpRoutes[route];\n if (existing && typeof existing !== 'function') {\n Object.assign(existing, handlerOrMethods);\n } else {\n mergedHttpRoutes[route] = handlerOrMethods;\n }\n }\n }\n }\n\n const hasHttpRoutes = Object.keys(mergedHttpRoutes).length > 0;\n\n // 动态构建协议\n const apiDefs: Record<string, ReturnType<typeof rpc.api>> = {\n // 内置 API\n JoinRoom: rpc.api(),\n LeaveRoom: rpc.api()\n };\n const msgDefs: Record<string, ReturnType<typeof rpc.msg>> = {\n // 内置消息(房间消息透传)\n RoomMessage: rpc.msg()\n };\n\n for (const handler of apiHandlers) {\n apiDefs[handler.name] = rpc.api();\n }\n for (const handler of msgHandlers) {\n msgDefs[handler.name] = rpc.msg();\n }\n\n const protocol = rpc.define({\n api: apiDefs,\n msg: msgDefs\n });\n\n // 服务器状态\n let currentTick = 0;\n let tickInterval: ReturnType<typeof setInterval> | null = null;\n let rpcServer: RpcServer<typeof protocol, Record<string, unknown>> | null = null;\n let httpServer: HttpServer | null = null;\n\n // 房间管理器(立即初始化,以便 define() 可在 start() 前调用)\n const roomManager = new RoomManager((conn, type, data) => {\n rpcServer?.send(conn, 'RoomMessage' as any, { type, data } as any);\n });\n\n // 构建 API 处理器映射\n const apiMap: Record<string, LoadedApiHandler> = {};\n for (const handler of apiHandlers) {\n apiMap[handler.name] = handler;\n }\n\n // 构建消息处理器映射\n const msgMap: Record<string, LoadedMsgHandler> = {};\n for (const handler of msgHandlers) {\n msgMap[handler.name] = handler;\n }\n\n // 游戏服务器实例\n const gameServer: GameServer & {\n rooms: RoomManager\n } = {\n get connections() {\n return (rpcServer?.connections ?? []) as ReadonlyArray<ServerConnection>;\n },\n\n get tick() {\n return currentTick;\n },\n\n get rooms() {\n return roomManager;\n },\n\n /**\n * @zh 注册房间类型\n * @en Define room type\n */\n define(name: string, roomClass: new () => unknown): void {\n roomManager.define(name, roomClass as RoomClass);\n },\n\n async start() {\n // 构建 API handlers\n const apiHandlersObj: Record<string, (input: unknown, conn: any) => Promise<unknown>> = {};\n\n // 内置 JoinRoom API\n apiHandlersObj['JoinRoom'] = async (input: any, conn) => {\n const { roomType, roomId, options } = input as {\n roomType?: string\n roomId?: string\n options?: Record<string, unknown>\n };\n\n if (roomId) {\n const result = await roomManager.joinById(roomId, conn.id, conn);\n if (!result) {\n throw new Error('Failed to join room');\n }\n return { roomId: result.room.id, playerId: result.player.id };\n }\n\n if (roomType) {\n const result = await roomManager.joinOrCreate(roomType, conn.id, conn, options);\n if (!result) {\n throw new Error('Failed to join or create room');\n }\n return { roomId: result.room.id, playerId: result.player.id };\n }\n\n throw new Error('roomType or roomId required');\n };\n\n // 内置 LeaveRoom API\n apiHandlersObj['LeaveRoom'] = async (_input, conn) => {\n await roomManager.leave(conn.id);\n return { success: true };\n };\n\n // 文件路由 API\n for (const [name, handler] of Object.entries(apiMap)) {\n apiHandlersObj[name] = async (input, conn) => {\n const ctx: ApiContext = {\n conn: conn as ServerConnection,\n server: gameServer\n };\n return handler.definition.handler(input, ctx);\n };\n }\n\n // 构建消息 handlers\n const msgHandlersObj: Record<string, (data: unknown, conn: any) => void | Promise<void>> = {};\n\n // 内置 RoomMessage 处理\n msgHandlersObj['RoomMessage'] = async (data: any, conn) => {\n const { type, data: payload } = data as { type: string; data: unknown };\n roomManager.handleMessage(conn.id, type, payload);\n };\n\n // 文件路由消息\n for (const [name, handler] of Object.entries(msgMap)) {\n msgHandlersObj[name] = async (data, conn) => {\n const ctx: MsgContext = {\n conn: conn as ServerConnection,\n server: gameServer\n };\n await handler.definition.handler(data, ctx);\n };\n }\n\n // 如果有 HTTP 路由,创建 HTTP 服务器\n if (hasHttpRoutes) {\n const httpRouter = createHttpRouter(mergedHttpRoutes, {\n cors: config.cors ?? true\n });\n\n httpServer = createHttpServer(async (req, res) => {\n // 先尝试 HTTP 路由\n const handled = await httpRouter(req, res);\n if (!handled) {\n // 未匹配的请求返回 404\n res.statusCode = 404;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Not Found' }));\n }\n });\n\n // 使用 HTTP 服务器创建 RPC\n rpcServer = serve(protocol, {\n server: httpServer,\n createConnData: () => ({}),\n onStart: () => {\n logger.info(`Started on http://localhost:${opts.port}`);\n opts.onStart?.(opts.port);\n },\n onConnect: async (conn) => {\n await config.onConnect?.(conn as ServerConnection);\n },\n onDisconnect: async (conn) => {\n await roomManager?.leave(conn.id, 'disconnected');\n await config.onDisconnect?.(conn as ServerConnection);\n },\n api: apiHandlersObj as any,\n msg: msgHandlersObj as any\n });\n\n await rpcServer.start();\n\n // 启动 HTTP 服务器\n await new Promise<void>((resolve) => {\n httpServer!.listen(opts.port, () => resolve());\n });\n } else {\n // 仅 WebSocket 模式\n rpcServer = serve(protocol, {\n port: opts.port,\n createConnData: () => ({}),\n onStart: (p) => {\n logger.info(`Started on ws://localhost:${p}`);\n opts.onStart?.(p);\n },\n onConnect: async (conn) => {\n await config.onConnect?.(conn as ServerConnection);\n },\n onDisconnect: async (conn) => {\n await roomManager?.leave(conn.id, 'disconnected');\n await config.onDisconnect?.(conn as ServerConnection);\n },\n api: apiHandlersObj as any,\n msg: msgHandlersObj as any\n });\n\n await rpcServer.start();\n }\n\n // 启动 tick 循环\n if (opts.tickRate > 0) {\n tickInterval = setInterval(() => {\n currentTick++;\n }, 1000 / opts.tickRate);\n }\n },\n\n async stop() {\n if (tickInterval) {\n clearInterval(tickInterval);\n tickInterval = null;\n }\n if (rpcServer) {\n await rpcServer.stop();\n rpcServer = null;\n }\n if (httpServer) {\n await new Promise<void>((resolve, reject) => {\n httpServer!.close((err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n httpServer = null;\n }\n },\n\n broadcast(name, data) {\n rpcServer?.broadcast(name as any, data as any);\n },\n\n send(conn, name, data) {\n rpcServer?.send(conn as any, name as any, data as any);\n }\n };\n\n return gameServer as GameServer;\n}\n"]}
|
package/dist/ecs/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Room } from '../chunk-
|
|
2
|
-
export { Player, onMessage } from '../chunk-
|
|
1
|
+
import { Room } from '../chunk-FACTBKJ3.js';
|
|
2
|
+
export { Player, onMessage } from '../chunk-FACTBKJ3.js';
|
|
3
3
|
import { __name, __publicField } from '../chunk-T626JPC7.js';
|
|
4
4
|
import { Core, ECSEventType, NETWORK_ENTITY_METADATA, encodeDespawn, encodeSnapshot, SyncOperation, encodeSpawn, SYNC_METADATA, CHANGE_TRACKER, initChangeTracker } from '@esengine/ecs-framework';
|
|
5
5
|
export { SyncOperation, clearChanges, getSyncMetadata, hasChanges, hasSyncFields, initChangeTracker, sync } from '@esengine/ecs-framework';
|
package/dist/ecs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ecs/ECSRoom.ts"],"names":["DEFAULT_ECS_CONFIG","syncInterval","enableDeltaSync","enableAutoNetworkEntity","NETWORK_ENTITY_OWNER","ECSRoom","Room","ecsConfig","world","worldId","scene","_playerEntities","Map","_networkEntities","_lastSyncTime","Date","now","Math","random","toString","slice","Core","worldManager","createWorld","createScene","setSceneActive","start","_setupAutoNetworkEntity","eventSystem","on","ECSEventType","COMPONENT_ADDED","event","entity","component","metadata","NETWORK_ENTITY_METADATA","autoSpawn","has","id","set","prefabType","broadcastSpawn","autoDespawn","ENTITY_DESTROYED","entityId","despawnData","encodeDespawn","broadcastBinary","delete","addSystem","system","createEntity","name","createPlayerEntity","playerId","entityName","getPlayerEntity","get","destroyPlayerEntity","destroy","data","player","players","sendBinary","send","Array","from","sendFullState","entities","_getSyncEntities","length","_initComponentTrackers","encodeSnapshot","SyncOperation","FULL","encodeSpawn","broadcastDelta","changedEntities","filter","_hasChanges","DELTA","_clearChangeTrackers","onTick","_dt","onLeave","reason","onDispose","clear","removeWorld","buffer","_hasSyncComponents","push","components","SYNC_METADATA","fields","tracker","CHANGE_TRACKER","hasChanges","initChangeTracker"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @zh ECS 房间基类\n * @en ECS Room base class\n */\n\nimport {\n Core,\n Scene,\n World,\n Entity,\n EntitySystem,\n type Component,\n // Sync\n SyncOperation,\n SYNC_METADATA,\n CHANGE_TRACKER,\n type SyncMetadata,\n type ChangeTracker,\n encodeSnapshot,\n encodeSpawn,\n encodeDespawn,\n initChangeTracker,\n // Network Entity\n NETWORK_ENTITY_METADATA,\n type NetworkEntityMetadata,\n // Events\n ECSEventType,\n} from '@esengine/ecs-framework';\n\nimport { Room, type RoomOptions } from '../room/Room.js';\nimport type { Player } from '../room/Player.js';\n\n// =============================================================================\n// Types | 类型定义\n// =============================================================================\n\n/**\n * @zh ECS 房间配置\n * @en ECS room configuration\n */\nexport interface ECSRoomConfig {\n /**\n * @zh 状态同步间隔(毫秒)\n * @en State sync interval in milliseconds\n */\n syncInterval: number;\n\n /**\n * @zh 是否启用增量同步\n * @en Whether to enable delta sync\n */\n enableDeltaSync: boolean;\n\n /**\n * @zh 是否启用自动网络实体广播(基于 @NetworkEntity 装饰器)\n * @en Whether to enable automatic network entity broadcasting (based on @NetworkEntity decorator)\n * @default true\n */\n enableAutoNetworkEntity: boolean;\n}\n\nconst DEFAULT_ECS_CONFIG: ECSRoomConfig = {\n syncInterval: 50, // 20 Hz\n enableDeltaSync: true,\n enableAutoNetworkEntity: true,\n};\n\n/**\n * @zh 网络实体标识组件\n * @en Network entity identity component\n */\nconst NETWORK_ENTITY_OWNER = Symbol('NetworkEntityOwner');\n\n// =============================================================================\n// ECSRoom | ECS 房间\n// =============================================================================\n\n/**\n * @zh ECS 房间基类,带有 ECS World 支持和自动状态同步\n * @en ECS Room base class with ECS World support and automatic state synchronization\n *\n * @example\n * ```typescript\n * // 服务端启动\n * Core.create();\n * setInterval(() => Core.update(1/60), 16);\n *\n * // 定义房间\n * class GameRoom extends ECSRoom {\n * onCreate() {\n * this.addSystem(new PhysicsSystem());\n * }\n *\n * onJoin(player: Player) {\n * const entity = this.createPlayerEntity(player.id);\n * entity.addComponent(new PlayerComponent());\n * }\n * }\n * ```\n */\nexport abstract class ECSRoom<TState = any, TPlayerData = Record<string, unknown>> extends Room<TState, TPlayerData> {\n /**\n * @zh ECS World(由 Core.worldManager 管理)\n * @en ECS World (managed by Core.worldManager)\n */\n protected readonly world: World;\n\n /**\n * @zh World 在 WorldManager 中的 ID\n * @en World ID in WorldManager\n */\n protected readonly worldId: string;\n\n /**\n * @zh 房间的主场景\n * @en Room's main scene\n */\n protected readonly scene: Scene;\n\n /**\n * @zh ECS 配置\n * @en ECS configuration\n */\n protected readonly ecsConfig: ECSRoomConfig;\n\n /**\n * @zh 玩家 ID 到实体的映射\n * @en Player ID to Entity mapping\n */\n private readonly _playerEntities: Map<string, Entity> = new Map();\n\n /**\n * @zh 网络实体映射(实体 ID -> prefabType)\n * @en Network entity mapping (entity ID -> prefabType)\n */\n private readonly _networkEntities: Map<number, string> = new Map();\n\n /**\n * @zh 上次同步时间\n * @en Last sync time\n */\n private _lastSyncTime: number = 0;\n\n constructor(ecsConfig?: Partial<ECSRoomConfig>) {\n super();\n this.ecsConfig = { ...DEFAULT_ECS_CONFIG, ...ecsConfig };\n\n this.worldId = `room_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n this.world = Core.worldManager.createWorld(this.worldId);\n this.scene = this.world.createScene('game');\n this.world.setSceneActive('game', true);\n this.world.start();\n\n // 设置自动网络实体广播\n if (this.ecsConfig.enableAutoNetworkEntity) {\n this._setupAutoNetworkEntity();\n }\n }\n\n /**\n * @zh 设置自动网络实体广播\n * @en Setup automatic network entity broadcasting\n */\n private _setupAutoNetworkEntity(): void {\n // 监听组件添加事件,自动广播 spawn\n this.scene.eventSystem.on(ECSEventType.COMPONENT_ADDED, (event: any) => {\n const { entity, component } = event;\n const metadata: NetworkEntityMetadata | undefined =\n (component.constructor as any)[NETWORK_ENTITY_METADATA];\n\n if (metadata?.autoSpawn) {\n // 避免重复广播同一实体\n if (!this._networkEntities.has(entity.id)) {\n this._networkEntities.set(entity.id, metadata.prefabType);\n this.broadcastSpawn(entity, metadata.prefabType);\n }\n }\n\n // 记录需要自动 despawn 的实体\n if (metadata?.autoDespawn && !this._networkEntities.has(entity.id)) {\n this._networkEntities.set(entity.id, metadata.prefabType);\n }\n });\n\n // 监听实体销毁事件,自动广播 despawn\n this.scene.eventSystem.on(ECSEventType.ENTITY_DESTROYED, (event: any) => {\n const { entityId } = event;\n if (this._networkEntities.has(entityId)) {\n const despawnData = encodeDespawn(entityId);\n this.broadcastBinary(despawnData);\n this._networkEntities.delete(entityId);\n }\n });\n }\n\n // =========================================================================\n // Scene Management | 场景管理\n // =========================================================================\n\n /**\n * @zh 添加系统到场景\n * @en Add system to scene\n */\n protected addSystem(system: EntitySystem): void {\n this.scene.addSystem(system);\n }\n\n /**\n * @zh 创建实体\n * @en Create entity\n */\n protected createEntity(name?: string): Entity {\n return this.scene.createEntity(name ?? `entity_${Date.now()}`);\n }\n\n /**\n * @zh 为玩家创建实体\n * @en Create entity for player\n *\n * @param playerId - @zh 玩家 ID @en Player ID\n * @param name - @zh 实体名称 @en Entity name\n * @returns @zh 创建的实体 @en Created entity\n */\n protected createPlayerEntity(playerId: string, name?: string): Entity {\n const entityName = name ?? `player_${playerId}`;\n const entity = this.scene.createEntity(entityName);\n (entity as any)[NETWORK_ENTITY_OWNER] = playerId;\n this._playerEntities.set(playerId, entity);\n return entity;\n }\n\n /**\n * @zh 获取玩家的实体\n * @en Get player's entity\n */\n protected getPlayerEntity(playerId: string): Entity | undefined {\n return this._playerEntities.get(playerId);\n }\n\n /**\n * @zh 销毁玩家的实体\n * @en Destroy player's entity\n */\n protected destroyPlayerEntity(playerId: string): void {\n const entity = this._playerEntities.get(playerId);\n if (entity) {\n const despawnData = encodeDespawn(entity.id);\n this.broadcastBinary(despawnData);\n entity.destroy();\n this._playerEntities.delete(playerId);\n }\n }\n\n // =========================================================================\n // State Sync | 状态同步\n // =========================================================================\n\n /**\n * @zh 广播二进制数据\n * @en Broadcast binary data\n */\n protected broadcastBinary(data: Uint8Array): void {\n for (const player of this.players) {\n this.sendBinary(player, data);\n }\n }\n\n /**\n * @zh 发送二进制数据给指定玩家\n * @en Send binary data to specific player\n */\n protected sendBinary(player: Player<TPlayerData>, data: Uint8Array): void {\n player.send('$sync', { data: Array.from(data) });\n }\n\n /**\n * @zh 发送完整状态给玩家(用于玩家刚加入时)\n * @en Send full state to player (for when player just joined)\n */\n protected sendFullState(player: Player<TPlayerData>): void {\n const entities = this._getSyncEntities();\n if (entities.length === 0) return;\n\n for (const entity of entities) {\n this._initComponentTrackers(entity);\n }\n\n const data = encodeSnapshot(entities, SyncOperation.FULL);\n this.sendBinary(player, data);\n }\n\n /**\n * @zh 广播实体生成\n * @en Broadcast entity spawn\n */\n protected broadcastSpawn(entity: Entity, prefabType?: string): void {\n this._initComponentTrackers(entity);\n const data = encodeSpawn(entity, prefabType);\n this.broadcastBinary(data);\n }\n\n /**\n * @zh 广播增量状态更新\n * @en Broadcast delta state update\n */\n protected broadcastDelta(): void {\n const entities = this._getSyncEntities();\n const changedEntities = entities.filter(entity => this._hasChanges(entity));\n\n if (changedEntities.length === 0) return;\n\n const data = encodeSnapshot(changedEntities, SyncOperation.DELTA);\n this.broadcastBinary(data);\n this._clearChangeTrackers(changedEntities);\n }\n\n // =========================================================================\n // Lifecycle Overrides | 生命周期重载\n // =========================================================================\n\n /**\n * @zh 游戏循环,处理状态同步\n * @en Game tick, handles state sync\n */\n override onTick(_dt: number): void {\n if (this.ecsConfig.enableDeltaSync) {\n const now = Date.now();\n if (now - this._lastSyncTime >= this.ecsConfig.syncInterval) {\n this._lastSyncTime = now;\n this.broadcastDelta();\n }\n }\n }\n\n /**\n * @zh 玩家离开时自动销毁其实体\n * @en Auto destroy player entity when leaving\n */\n override async onLeave(player: Player<TPlayerData>, reason?: string): Promise<void> {\n this.destroyPlayerEntity(player.id);\n }\n\n /**\n * @zh 房间销毁时从 WorldManager 移除 World\n * @en Remove World from WorldManager when room is disposed\n */\n override onDispose(): void {\n this._playerEntities.clear();\n Core.worldManager.removeWorld(this.worldId);\n }\n\n // =========================================================================\n // Internal | 内部方法\n // =========================================================================\n\n private _getSyncEntities(): Entity[] {\n const entities: Entity[] = [];\n for (const entity of this.scene.entities.buffer) {\n if (this._hasSyncComponents(entity)) {\n entities.push(entity);\n }\n }\n return entities;\n }\n\n private _hasSyncComponents(entity: Entity): boolean {\n for (const component of entity.components) {\n const metadata: SyncMetadata | undefined = (component.constructor as any)[SYNC_METADATA];\n if (metadata && metadata.fields.length > 0) {\n return true;\n }\n }\n return false;\n }\n\n private _hasChanges(entity: Entity): boolean {\n for (const component of entity.components) {\n const tracker = (component as any)[CHANGE_TRACKER] as ChangeTracker | undefined;\n if (tracker?.hasChanges()) {\n return true;\n }\n }\n return false;\n }\n\n private _initComponentTrackers(entity: Entity): void {\n for (const component of entity.components) {\n const metadata: SyncMetadata | undefined = (component.constructor as any)[SYNC_METADATA];\n if (metadata && metadata.fields.length > 0) {\n initChangeTracker(component);\n }\n }\n }\n\n private _clearChangeTrackers(entities: Entity[]): void {\n for (const entity of entities) {\n for (const component of entity.components) {\n const tracker = (component as any)[CHANGE_TRACKER] as ChangeTracker | undefined;\n if (tracker) {\n tracker.clear();\n }\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ecs/ECSRoom.ts"],"names":["DEFAULT_ECS_CONFIG","syncInterval","enableDeltaSync","enableAutoNetworkEntity","NETWORK_ENTITY_OWNER","ECSRoom","Room","ecsConfig","world","worldId","scene","_playerEntities","Map","_networkEntities","_lastSyncTime","Date","now","Math","random","toString","slice","Core","worldManager","createWorld","createScene","setSceneActive","start","_setupAutoNetworkEntity","eventSystem","on","ECSEventType","COMPONENT_ADDED","event","entity","component","metadata","NETWORK_ENTITY_METADATA","autoSpawn","has","id","set","prefabType","broadcastSpawn","autoDespawn","ENTITY_DESTROYED","entityId","despawnData","encodeDespawn","broadcastBinary","delete","addSystem","system","createEntity","name","createPlayerEntity","playerId","entityName","getPlayerEntity","get","destroyPlayerEntity","destroy","data","player","players","sendBinary","send","Array","from","sendFullState","entities","_getSyncEntities","length","_initComponentTrackers","encodeSnapshot","SyncOperation","FULL","encodeSpawn","broadcastDelta","changedEntities","filter","_hasChanges","DELTA","_clearChangeTrackers","onTick","_dt","onLeave","reason","onDispose","clear","removeWorld","buffer","_hasSyncComponents","push","components","SYNC_METADATA","fields","tracker","CHANGE_TRACKER","hasChanges","initChangeTracker"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @zh ECS 房间基类\n * @en ECS Room base class\n */\n\nimport {\n Core,\n Scene,\n World,\n Entity,\n EntitySystem,\n type Component,\n // Sync\n SyncOperation,\n SYNC_METADATA,\n CHANGE_TRACKER,\n type SyncMetadata,\n type ChangeTracker,\n encodeSnapshot,\n encodeSpawn,\n encodeDespawn,\n initChangeTracker,\n // Network Entity\n NETWORK_ENTITY_METADATA,\n type NetworkEntityMetadata,\n // Events\n ECSEventType\n} from '@esengine/ecs-framework';\n\nimport { Room, type RoomOptions } from '../room/Room.js';\nimport type { Player } from '../room/Player.js';\n\n// =============================================================================\n// Types | 类型定义\n// =============================================================================\n\n/**\n * @zh ECS 房间配置\n * @en ECS room configuration\n */\nexport interface ECSRoomConfig {\n /**\n * @zh 状态同步间隔(毫秒)\n * @en State sync interval in milliseconds\n */\n syncInterval: number;\n\n /**\n * @zh 是否启用增量同步\n * @en Whether to enable delta sync\n */\n enableDeltaSync: boolean;\n\n /**\n * @zh 是否启用自动网络实体广播(基于 @NetworkEntity 装饰器)\n * @en Whether to enable automatic network entity broadcasting (based on @NetworkEntity decorator)\n * @default true\n */\n enableAutoNetworkEntity: boolean;\n}\n\nconst DEFAULT_ECS_CONFIG: ECSRoomConfig = {\n syncInterval: 50, // 20 Hz\n enableDeltaSync: true,\n enableAutoNetworkEntity: true\n};\n\n/**\n * @zh 网络实体标识组件\n * @en Network entity identity component\n */\nconst NETWORK_ENTITY_OWNER = Symbol('NetworkEntityOwner');\n\n// =============================================================================\n// ECSRoom | ECS 房间\n// =============================================================================\n\n/**\n * @zh ECS 房间基类,带有 ECS World 支持和自动状态同步\n * @en ECS Room base class with ECS World support and automatic state synchronization\n *\n * @example\n * ```typescript\n * // 服务端启动\n * Core.create();\n * setInterval(() => Core.update(1/60), 16);\n *\n * // 定义房间\n * class GameRoom extends ECSRoom {\n * onCreate() {\n * this.addSystem(new PhysicsSystem());\n * }\n *\n * onJoin(player: Player) {\n * const entity = this.createPlayerEntity(player.id);\n * entity.addComponent(new PlayerComponent());\n * }\n * }\n * ```\n */\nexport abstract class ECSRoom<TState = any, TPlayerData = Record<string, unknown>> extends Room<TState, TPlayerData> {\n /**\n * @zh ECS World(由 Core.worldManager 管理)\n * @en ECS World (managed by Core.worldManager)\n */\n protected readonly world: World;\n\n /**\n * @zh World 在 WorldManager 中的 ID\n * @en World ID in WorldManager\n */\n protected readonly worldId: string;\n\n /**\n * @zh 房间的主场景\n * @en Room's main scene\n */\n protected readonly scene: Scene;\n\n /**\n * @zh ECS 配置\n * @en ECS configuration\n */\n protected readonly ecsConfig: ECSRoomConfig;\n\n /**\n * @zh 玩家 ID 到实体的映射\n * @en Player ID to Entity mapping\n */\n private readonly _playerEntities: Map<string, Entity> = new Map();\n\n /**\n * @zh 网络实体映射(实体 ID -> prefabType)\n * @en Network entity mapping (entity ID -> prefabType)\n */\n private readonly _networkEntities: Map<number, string> = new Map();\n\n /**\n * @zh 上次同步时间\n * @en Last sync time\n */\n private _lastSyncTime: number = 0;\n\n constructor(ecsConfig?: Partial<ECSRoomConfig>) {\n super();\n this.ecsConfig = { ...DEFAULT_ECS_CONFIG, ...ecsConfig };\n\n this.worldId = `room_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n this.world = Core.worldManager.createWorld(this.worldId);\n this.scene = this.world.createScene('game');\n this.world.setSceneActive('game', true);\n this.world.start();\n\n // 设置自动网络实体广播\n if (this.ecsConfig.enableAutoNetworkEntity) {\n this._setupAutoNetworkEntity();\n }\n }\n\n /**\n * @zh 设置自动网络实体广播\n * @en Setup automatic network entity broadcasting\n */\n private _setupAutoNetworkEntity(): void {\n // 监听组件添加事件,自动广播 spawn\n this.scene.eventSystem.on(ECSEventType.COMPONENT_ADDED, (event: any) => {\n const { entity, component } = event;\n const metadata: NetworkEntityMetadata | undefined =\n (component.constructor as any)[NETWORK_ENTITY_METADATA];\n\n if (metadata?.autoSpawn) {\n // 避免重复广播同一实体\n if (!this._networkEntities.has(entity.id)) {\n this._networkEntities.set(entity.id, metadata.prefabType);\n this.broadcastSpawn(entity, metadata.prefabType);\n }\n }\n\n // 记录需要自动 despawn 的实体\n if (metadata?.autoDespawn && !this._networkEntities.has(entity.id)) {\n this._networkEntities.set(entity.id, metadata.prefabType);\n }\n });\n\n // 监听实体销毁事件,自动广播 despawn\n this.scene.eventSystem.on(ECSEventType.ENTITY_DESTROYED, (event: any) => {\n const { entityId } = event;\n if (this._networkEntities.has(entityId)) {\n const despawnData = encodeDespawn(entityId);\n this.broadcastBinary(despawnData);\n this._networkEntities.delete(entityId);\n }\n });\n }\n\n // =========================================================================\n // Scene Management | 场景管理\n // =========================================================================\n\n /**\n * @zh 添加系统到场景\n * @en Add system to scene\n */\n protected addSystem(system: EntitySystem): void {\n this.scene.addSystem(system);\n }\n\n /**\n * @zh 创建实体\n * @en Create entity\n */\n protected createEntity(name?: string): Entity {\n return this.scene.createEntity(name ?? `entity_${Date.now()}`);\n }\n\n /**\n * @zh 为玩家创建实体\n * @en Create entity for player\n *\n * @param playerId - @zh 玩家 ID @en Player ID\n * @param name - @zh 实体名称 @en Entity name\n * @returns @zh 创建的实体 @en Created entity\n */\n protected createPlayerEntity(playerId: string, name?: string): Entity {\n const entityName = name ?? `player_${playerId}`;\n const entity = this.scene.createEntity(entityName);\n (entity as any)[NETWORK_ENTITY_OWNER] = playerId;\n this._playerEntities.set(playerId, entity);\n return entity;\n }\n\n /**\n * @zh 获取玩家的实体\n * @en Get player's entity\n */\n protected getPlayerEntity(playerId: string): Entity | undefined {\n return this._playerEntities.get(playerId);\n }\n\n /**\n * @zh 销毁玩家的实体\n * @en Destroy player's entity\n */\n protected destroyPlayerEntity(playerId: string): void {\n const entity = this._playerEntities.get(playerId);\n if (entity) {\n const despawnData = encodeDespawn(entity.id);\n this.broadcastBinary(despawnData);\n entity.destroy();\n this._playerEntities.delete(playerId);\n }\n }\n\n // =========================================================================\n // State Sync | 状态同步\n // =========================================================================\n\n /**\n * @zh 广播二进制数据\n * @en Broadcast binary data\n */\n protected broadcastBinary(data: Uint8Array): void {\n for (const player of this.players) {\n this.sendBinary(player, data);\n }\n }\n\n /**\n * @zh 发送二进制数据给指定玩家\n * @en Send binary data to specific player\n */\n protected sendBinary(player: Player<TPlayerData>, data: Uint8Array): void {\n player.send('$sync', { data: Array.from(data) });\n }\n\n /**\n * @zh 发送完整状态给玩家(用于玩家刚加入时)\n * @en Send full state to player (for when player just joined)\n */\n protected sendFullState(player: Player<TPlayerData>): void {\n const entities = this._getSyncEntities();\n if (entities.length === 0) return;\n\n for (const entity of entities) {\n this._initComponentTrackers(entity);\n }\n\n const data = encodeSnapshot(entities, SyncOperation.FULL);\n this.sendBinary(player, data);\n }\n\n /**\n * @zh 广播实体生成\n * @en Broadcast entity spawn\n */\n protected broadcastSpawn(entity: Entity, prefabType?: string): void {\n this._initComponentTrackers(entity);\n const data = encodeSpawn(entity, prefabType);\n this.broadcastBinary(data);\n }\n\n /**\n * @zh 广播增量状态更新\n * @en Broadcast delta state update\n */\n protected broadcastDelta(): void {\n const entities = this._getSyncEntities();\n const changedEntities = entities.filter((entity) => this._hasChanges(entity));\n\n if (changedEntities.length === 0) return;\n\n const data = encodeSnapshot(changedEntities, SyncOperation.DELTA);\n this.broadcastBinary(data);\n this._clearChangeTrackers(changedEntities);\n }\n\n // =========================================================================\n // Lifecycle Overrides | 生命周期重载\n // =========================================================================\n\n /**\n * @zh 游戏循环,处理状态同步\n * @en Game tick, handles state sync\n */\n override onTick(_dt: number): void {\n if (this.ecsConfig.enableDeltaSync) {\n const now = Date.now();\n if (now - this._lastSyncTime >= this.ecsConfig.syncInterval) {\n this._lastSyncTime = now;\n this.broadcastDelta();\n }\n }\n }\n\n /**\n * @zh 玩家离开时自动销毁其实体\n * @en Auto destroy player entity when leaving\n */\n override async onLeave(player: Player<TPlayerData>, reason?: string): Promise<void> {\n this.destroyPlayerEntity(player.id);\n }\n\n /**\n * @zh 房间销毁时从 WorldManager 移除 World\n * @en Remove World from WorldManager when room is disposed\n */\n override onDispose(): void {\n this._playerEntities.clear();\n Core.worldManager.removeWorld(this.worldId);\n }\n\n // =========================================================================\n // Internal | 内部方法\n // =========================================================================\n\n private _getSyncEntities(): Entity[] {\n const entities: Entity[] = [];\n for (const entity of this.scene.entities.buffer) {\n if (this._hasSyncComponents(entity)) {\n entities.push(entity);\n }\n }\n return entities;\n }\n\n private _hasSyncComponents(entity: Entity): boolean {\n for (const component of entity.components) {\n const metadata: SyncMetadata | undefined = (component.constructor as any)[SYNC_METADATA];\n if (metadata && metadata.fields.length > 0) {\n return true;\n }\n }\n return false;\n }\n\n private _hasChanges(entity: Entity): boolean {\n for (const component of entity.components) {\n const tracker = (component as any)[CHANGE_TRACKER] as ChangeTracker | undefined;\n if (tracker?.hasChanges()) {\n return true;\n }\n }\n return false;\n }\n\n private _initComponentTrackers(entity: Entity): void {\n for (const component of entity.components) {\n const metadata: SyncMetadata | undefined = (component.constructor as any)[SYNC_METADATA];\n if (metadata && metadata.fields.length > 0) {\n initChangeTracker(component);\n }\n }\n }\n\n private _clearChangeTrackers(entities: Entity[]): void {\n for (const entity of entities) {\n for (const component of entity.components) {\n const tracker = (component as any)[CHANGE_TRACKER] as ChangeTracker | undefined;\n if (tracker) {\n tracker.clear();\n }\n }\n }\n }\n}\n"]}
|
|
@@ -26,6 +26,11 @@ interface HttpRequest {
|
|
|
26
26
|
* @en Request path
|
|
27
27
|
*/
|
|
28
28
|
path: string;
|
|
29
|
+
/**
|
|
30
|
+
* @zh 路由参数(从 URL 路径提取,如 /users/:id)
|
|
31
|
+
* @en Route parameters (extracted from URL path, e.g., /users/:id)
|
|
32
|
+
*/
|
|
33
|
+
params: Record<string, string>;
|
|
29
34
|
/**
|
|
30
35
|
* @zh 查询参数
|
|
31
36
|
* @en Query parameters
|
|
@@ -88,18 +93,89 @@ interface HttpResponse {
|
|
|
88
93
|
* @en HTTP route handler
|
|
89
94
|
*/
|
|
90
95
|
type HttpHandler = (req: HttpRequest, res: HttpResponse) => void | Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* @zh HTTP 中间件函数
|
|
98
|
+
* @en HTTP middleware function
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const authMiddleware: HttpMiddleware = async (req, res, next) => {
|
|
103
|
+
* if (!req.headers.authorization) {
|
|
104
|
+
* res.error(401, 'Unauthorized');
|
|
105
|
+
* return;
|
|
106
|
+
* }
|
|
107
|
+
* await next();
|
|
108
|
+
* };
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
type HttpMiddleware = (req: HttpRequest, res: HttpResponse, next: () => Promise<void>) => void | Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* @zh 带中间件和超时的路由处理器定义
|
|
114
|
+
* @en Route handler definition with middleware and timeout support
|
|
115
|
+
*/
|
|
116
|
+
interface HttpHandlerDefinition {
|
|
117
|
+
/**
|
|
118
|
+
* @zh 处理函数
|
|
119
|
+
* @en Handler function
|
|
120
|
+
*/
|
|
121
|
+
handler: HttpHandler;
|
|
122
|
+
/**
|
|
123
|
+
* @zh 路由级中间件
|
|
124
|
+
* @en Route-level middlewares
|
|
125
|
+
*/
|
|
126
|
+
middlewares?: HttpMiddleware[];
|
|
127
|
+
/**
|
|
128
|
+
* @zh 路由级超时时间(毫秒),覆盖全局设置
|
|
129
|
+
* @en Route-level timeout in milliseconds, overrides global setting
|
|
130
|
+
*/
|
|
131
|
+
timeout?: number;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* @zh HTTP 路由方法配置(支持简单处理器或完整定义)
|
|
135
|
+
* @en HTTP route method configuration (supports simple handler or full definition)
|
|
136
|
+
*/
|
|
137
|
+
type HttpMethodHandler = HttpHandler | HttpHandlerDefinition;
|
|
138
|
+
/**
|
|
139
|
+
* @zh HTTP 路由方法映射
|
|
140
|
+
* @en HTTP route methods mapping
|
|
141
|
+
*/
|
|
142
|
+
interface HttpRouteMethods {
|
|
143
|
+
GET?: HttpMethodHandler;
|
|
144
|
+
POST?: HttpMethodHandler;
|
|
145
|
+
PUT?: HttpMethodHandler;
|
|
146
|
+
DELETE?: HttpMethodHandler;
|
|
147
|
+
PATCH?: HttpMethodHandler;
|
|
148
|
+
OPTIONS?: HttpMethodHandler;
|
|
149
|
+
}
|
|
91
150
|
/**
|
|
92
151
|
* @zh HTTP 路由配置
|
|
93
152
|
* @en HTTP routes configuration
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const routes: HttpRoutes = {
|
|
157
|
+
* // 简单处理器
|
|
158
|
+
* '/health': (req, res) => res.json({ ok: true }),
|
|
159
|
+
*
|
|
160
|
+
* // 按方法分开
|
|
161
|
+
* '/users': {
|
|
162
|
+
* GET: (req, res) => res.json([]),
|
|
163
|
+
* POST: (req, res) => res.json({ created: true })
|
|
164
|
+
* },
|
|
165
|
+
*
|
|
166
|
+
* // 路由参数
|
|
167
|
+
* '/users/:id': {
|
|
168
|
+
* GET: (req, res) => res.json({ id: req.params.id }),
|
|
169
|
+
* DELETE: {
|
|
170
|
+
* handler: (req, res) => res.json({ deleted: true }),
|
|
171
|
+
* middlewares: [authMiddleware],
|
|
172
|
+
* timeout: 5000
|
|
173
|
+
* }
|
|
174
|
+
* }
|
|
175
|
+
* };
|
|
176
|
+
* ```
|
|
94
177
|
*/
|
|
95
|
-
type HttpRoutes = Record<string,
|
|
96
|
-
GET?: HttpHandler;
|
|
97
|
-
POST?: HttpHandler;
|
|
98
|
-
PUT?: HttpHandler;
|
|
99
|
-
DELETE?: HttpHandler;
|
|
100
|
-
PATCH?: HttpHandler;
|
|
101
|
-
OPTIONS?: HttpHandler;
|
|
102
|
-
}>;
|
|
178
|
+
type HttpRoutes = Record<string, HttpMethodHandler | HttpRouteMethods>;
|
|
103
179
|
/**
|
|
104
180
|
* @zh CORS 配置
|
|
105
181
|
* @en CORS configuration
|
|
@@ -131,6 +207,27 @@ interface CorsOptions {
|
|
|
131
207
|
*/
|
|
132
208
|
maxAge?: number;
|
|
133
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* @zh HTTP 路由器选项
|
|
212
|
+
* @en HTTP router options
|
|
213
|
+
*/
|
|
214
|
+
interface HttpRouterOptions {
|
|
215
|
+
/**
|
|
216
|
+
* @zh CORS 配置
|
|
217
|
+
* @en CORS configuration
|
|
218
|
+
*/
|
|
219
|
+
cors?: CorsOptions | boolean;
|
|
220
|
+
/**
|
|
221
|
+
* @zh 全局请求超时时间(毫秒)
|
|
222
|
+
* @en Global request timeout in milliseconds
|
|
223
|
+
*/
|
|
224
|
+
timeout?: number;
|
|
225
|
+
/**
|
|
226
|
+
* @zh 全局中间件
|
|
227
|
+
* @en Global middlewares
|
|
228
|
+
*/
|
|
229
|
+
middlewares?: HttpMiddleware[];
|
|
230
|
+
}
|
|
134
231
|
|
|
135
232
|
/**
|
|
136
233
|
* @zh ESEngine Server 类型定义
|
|
@@ -370,4 +467,4 @@ interface HttpDefinition<TBody = unknown> {
|
|
|
370
467
|
}, res: HttpResponse) => void | Promise<void>;
|
|
371
468
|
}
|
|
372
469
|
|
|
373
|
-
export type { ApiDefinition as A, CorsOptions as C, GameServer as G, HttpDefinition as H, MsgDefinition as M, ServerConfig as S, HttpRoutes as a,
|
|
470
|
+
export type { ApiDefinition as A, CorsOptions as C, GameServer as G, HttpDefinition as H, MsgDefinition as M, ServerConfig as S, HttpRoutes as a, HttpRouterOptions as b, ServerConnection as c, ApiContext as d, MsgContext as e, HttpMethod as f, HttpRequest as g, HttpResponse as h, HttpHandler as i };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as ServerConfig, G as GameServer, A as ApiDefinition, M as MsgDefinition, H as HttpDefinition, a as HttpRoutes,
|
|
2
|
-
export {
|
|
1
|
+
import { S as ServerConfig, G as GameServer, A as ApiDefinition, M as MsgDefinition, H as HttpDefinition, a as HttpRoutes, b as HttpRouterOptions } from './index-lcuKuQsL.js';
|
|
2
|
+
export { d as ApiContext, C as CorsOptions, i as HttpHandler, f as HttpMethod, g as HttpRequest, h as HttpResponse, e as MsgContext, c as ServerConnection } from './index-lcuKuQsL.js';
|
|
3
3
|
export { I as IPlayer, P as Player, R as Room, a as RoomOptions } from './Room-BnKpl5Sj.js';
|
|
4
4
|
export { o as onMessage } from './decorators-DY8nZ8Nh.js';
|
|
5
5
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
@@ -101,14 +101,36 @@ declare function defineHttp<TBody = unknown>(definition: HttpDefinition<TBody>):
|
|
|
101
101
|
* @zh HTTP 路由器
|
|
102
102
|
* @en HTTP Router
|
|
103
103
|
*
|
|
104
|
-
* @zh
|
|
105
|
-
* @en
|
|
104
|
+
* @zh 支持路由参数、中间件和超时控制的 HTTP 路由实现
|
|
105
|
+
* @en HTTP router with route parameters, middleware and timeout support
|
|
106
106
|
*/
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* @zh 创建 HTTP 路由器
|
|
110
110
|
* @en Create HTTP router
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const router = createHttpRouter({
|
|
115
|
+
* '/users': {
|
|
116
|
+
* GET: (req, res) => res.json([]),
|
|
117
|
+
* POST: (req, res) => res.json({ created: true })
|
|
118
|
+
* },
|
|
119
|
+
* '/users/:id': {
|
|
120
|
+
* GET: (req, res) => res.json({ id: req.params.id }),
|
|
121
|
+
* DELETE: {
|
|
122
|
+
* handler: (req, res) => res.json({ deleted: true }),
|
|
123
|
+
* middlewares: [authMiddleware],
|
|
124
|
+
* timeout: 5000
|
|
125
|
+
* }
|
|
126
|
+
* }
|
|
127
|
+
* }, {
|
|
128
|
+
* cors: true,
|
|
129
|
+
* timeout: 30000,
|
|
130
|
+
* middlewares: [loggerMiddleware]
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
111
133
|
*/
|
|
112
|
-
declare function createHttpRouter(routes: HttpRoutes,
|
|
134
|
+
declare function createHttpRouter(routes: HttpRoutes, options?: HttpRouterOptions): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
|
113
135
|
|
|
114
|
-
export { ApiDefinition,
|
|
136
|
+
export { ApiDefinition, GameServer, HttpDefinition, HttpRoutes, MsgDefinition, ServerConfig, createHttpRouter, createServer, defineApi, defineHttp, defineMsg };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { createHttpRouter, createServer } from './chunk-
|
|
2
|
-
|
|
1
|
+
export { createHttpRouter, createServer } from './chunk-M7VONMZJ.js';
|
|
2
|
+
import './chunk-I4QQSQ72.js';
|
|
3
|
+
export { Player, Room, onMessage } from './chunk-FACTBKJ3.js';
|
|
3
4
|
import { __name } from './chunk-T626JPC7.js';
|
|
4
5
|
export { ErrorCode, RpcError } from '@esengine/rpc';
|
|
5
6
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/helpers/define.ts"],"names":["defineApi","definition","defineMsg","defineHttp"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/helpers/define.ts"],"names":["defineApi","definition","defineMsg","defineHttp"],"mappings":";;;;;;;AAwBO,SAASA,UACZC,UAAAA,EAA4C;AAE5C,EAAA,OAAOA,UAAAA;AACX;AAJgBD,MAAAA,CAAAA,SAAAA,EAAAA,WAAAA,CAAAA;AAsBT,SAASE,UACZD,UAAAA,EAAsC;AAEtC,EAAA,OAAOA,UAAAA;AACX;AAJgBC,MAAAA,CAAAA,SAAAA,EAAAA,WAAAA,CAAAA;AA8BT,SAASC,WACZF,UAAAA,EAAiC;AAEjC,EAAA,OAAOA,UAAAA;AACX;AAJgBE,MAAAA,CAAAA,UAAAA,EAAAA,YAAAA,CAAAA","file":"index.js","sourcesContent":["/**\n * @zh API、消息和 HTTP 定义助手\n * @en API, message, and HTTP definition helpers\n */\n\nimport type { ApiDefinition, MsgDefinition, HttpDefinition } from '../types/index.js';\n\n/**\n * @zh 定义 API 处理器\n * @en Define API handler\n *\n * @example\n * ```typescript\n * // src/api/join.ts\n * import { defineApi } from '@esengine/server'\n *\n * export default defineApi<ReqJoin, ResJoin>({\n * handler(req, ctx) {\n * ctx.conn.data.playerId = generateId()\n * return { playerId: ctx.conn.data.playerId }\n * }\n * })\n * ```\n */\nexport function defineApi<TReq, TRes, TData = Record<string, unknown>>(\n definition: ApiDefinition<TReq, TRes, TData>\n): ApiDefinition<TReq, TRes, TData> {\n return definition;\n}\n\n/**\n * @zh 定义消息处理器\n * @en Define message handler\n *\n * @example\n * ```typescript\n * // src/msg/input.ts\n * import { defineMsg } from '@esengine/server'\n *\n * export default defineMsg<MsgInput>({\n * handler(msg, ctx) {\n * console.log('Input from', ctx.conn.id, msg)\n * }\n * })\n * ```\n */\nexport function defineMsg<TMsg, TData = Record<string, unknown>>(\n definition: MsgDefinition<TMsg, TData>\n): MsgDefinition<TMsg, TData> {\n return definition;\n}\n\n/**\n * @zh 定义 HTTP 路由处理器\n * @en Define HTTP route handler\n *\n * @example\n * ```typescript\n * // src/http/login.ts\n * import { defineHttp } from '@esengine/server'\n *\n * interface LoginBody {\n * username: string\n * password: string\n * }\n *\n * export default defineHttp<LoginBody>({\n * method: 'POST',\n * handler(req, res) {\n * const { username, password } = req.body\n * // ... validate credentials\n * res.json({ token: '...', userId: '...' })\n * }\n * })\n * ```\n */\nexport function defineHttp<TBody = unknown>(\n definition: HttpDefinition<TBody>\n): HttpDefinition<TBody> {\n return definition;\n}\n"]}
|
|
@@ -637,6 +637,16 @@ type RateLimitRoomClass = new (...args: any[]) => Room & IRateLimitRoom;
|
|
|
637
637
|
* @en Get rate limit context for player
|
|
638
638
|
*/
|
|
639
639
|
declare function getPlayerRateLimitContext(player: Player): IRateLimitContext | null;
|
|
640
|
+
/**
|
|
641
|
+
* @zh 抽象构造器类型
|
|
642
|
+
* @en Abstract constructor type
|
|
643
|
+
*/
|
|
644
|
+
type AbstractConstructor<T = object> = abstract new (...args: any[]) => T;
|
|
645
|
+
/**
|
|
646
|
+
* @zh 可混入的 Room 构造器类型(支持抽象和具体类)
|
|
647
|
+
* @en Mixable Room constructor type (supports both abstract and concrete classes)
|
|
648
|
+
*/
|
|
649
|
+
type RoomConstructor = AbstractConstructor<Room>;
|
|
640
650
|
/**
|
|
641
651
|
* @zh 包装房间类添加速率限制功能
|
|
642
652
|
* @en Wrap room class with rate limit functionality
|
|
@@ -677,7 +687,7 @@ declare function getPlayerRateLimitContext(player: Player): IRateLimitContext |
|
|
|
677
687
|
* }
|
|
678
688
|
* ```
|
|
679
689
|
*/
|
|
680
|
-
declare function withRateLimit<TBase extends
|
|
690
|
+
declare function withRateLimit<TBase extends RoomConstructor>(Base: TBase, config?: RateLimitConfig): TBase & AbstractConstructor<IRateLimitRoom>;
|
|
681
691
|
|
|
682
692
|
/**
|
|
683
693
|
* @zh 速率限制装饰器
|
package/dist/ratelimit/index.js
CHANGED
|
@@ -624,10 +624,19 @@ function setPlayerRateLimitContext(player, context) {
|
|
|
624
624
|
});
|
|
625
625
|
}
|
|
626
626
|
__name(setPlayerRateLimitContext, "setPlayerRateLimitContext");
|
|
627
|
+
function toExtendable(Base) {
|
|
628
|
+
return Base;
|
|
629
|
+
}
|
|
630
|
+
__name(toExtendable, "toExtendable");
|
|
631
|
+
function toMixinResult(MixinClass) {
|
|
632
|
+
return MixinClass;
|
|
633
|
+
}
|
|
634
|
+
__name(toMixinResult, "toMixinResult");
|
|
627
635
|
function withRateLimit(Base, config = {}) {
|
|
628
636
|
var _a;
|
|
629
637
|
const { messagesPerSecond = 10, burstSize = 20, strategy = "token-bucket", onLimited, disconnectOnLimit = false, maxConsecutiveLimits = 0, getKey = /* @__PURE__ */ __name((player) => player.id, "getKey"), cleanupInterval = 6e4 } = config;
|
|
630
|
-
|
|
638
|
+
const BaseRoom = toExtendable(Base);
|
|
639
|
+
let RateLimitRoom = (_a = class extends BaseRoom {
|
|
631
640
|
constructor(...args) {
|
|
632
641
|
super(...args);
|
|
633
642
|
__publicField(this, "_rateLimitStrategy");
|
|
@@ -809,7 +818,7 @@ function withRateLimit(Base, config = {}) {
|
|
|
809
818
|
}
|
|
810
819
|
}
|
|
811
820
|
}, __name(_a, "RateLimitRoom"), _a);
|
|
812
|
-
return RateLimitRoom;
|
|
821
|
+
return toMixinResult(RateLimitRoom);
|
|
813
822
|
}
|
|
814
823
|
__name(withRateLimit, "withRateLimit");
|
|
815
824
|
|