@esengine/server 4.0.0 → 4.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/http/router.ts","../src/router/loader.ts","../src/room/RoomManager.ts","../src/core/server.ts"],"names":["createRequest","req","url","URL","headers","host","query","searchParams","forEach","value","key","body","method","parseBody","ip","split","trim","socket","remoteAddress","raw","path","pathname","Promise","resolve","chunks","on","chunk","push","rawBody","Buffer","concat","toString","contentType","includes","JSON","parse","params","URLSearchParams","result","createResponse","res","statusCode","response","status","code","header","name","setHeader","json","data","end","stringify","text","error","message","applyCors","cors","origin","Array","isArray","methods","join","allowedHeaders","credentials","maxAge","String","createHttpRouter","routes","parsedRoutes","handlerOrMethods","Object","entries","handler","undefined","corsOptions","handleRequest","route","find","r","httpReq","httpRes","console","fileNameToHandlerName","fileName","baseName","replace","map","part","charAt","toUpperCase","slice","scanDirectory","dir","existsSync","files","readdirSync","withFileTypes","entry","isFile","test","startsWith","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","options","def","get","roomId","_generateRoomId","room","_init","id","broadcastFn","type","player","players","send","disposeFn","delete","_create","log","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","length","mergedHttpRoutes","existingRoute","http","existing","assign","hasHttpRoutes","keys","apiDefs","JoinRoom","rpc","api","LeaveRoom","msgDefs","RoomMessage","msg","protocol","currentTick","tickInterval","rpcServer","httpServer","roomManager","apiMap","msgMap","gameServer","connections","tick","rooms","start","apiHandlersObj","input","roomType","Error","_input","success","ctx","server","msgHandlersObj","payload","httpRouter","createHttpServer","handled","serve","createConnData","onStart","onConnect","onDisconnect","listen","p","setInterval","stop","clearInterval","reject","close","broadcast"],"mappings":"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","file":"chunk-BIAOJF7P.js","sourcesContent":["/**\n * @zh HTTP 路由器\n * @en HTTP Router\n *\n * @zh 简洁的 HTTP 路由实现,支持与 WebSocket 共用端口\n * @en Simple HTTP router implementation, supports sharing port with WebSocket\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type {\n HttpRequest,\n HttpResponse,\n HttpHandler,\n HttpRoutes,\n CorsOptions,\n} from './types.js';\n\n/**\n * @zh 创建 HTTP 请求对象\n * @en Create HTTP request object\n */\nasync function createRequest(req: IncomingMessage): Promise<HttpRequest> {\n const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);\n\n // 解析查询参数\n const query: Record<string, string> = {};\n url.searchParams.forEach((value, key) => {\n query[key] = value;\n });\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 // 获取客户端 IP\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 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\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 res.setHeader(name, value);\n return response;\n },\n\n json(data: unknown) {\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 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 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 * @zh 应用 CORS 头\n * @en Apply CORS headers\n */\nfunction applyCors(res: ServerResponse, req: IncomingMessage, cors: CorsOptions): void {\n const origin = req.headers.origin;\n\n // 处理 origin\n if (cors.origin === true || cors.origin === '*') {\n res.setHeader('Access-Control-Allow-Origin', origin ?? '*');\n } else if (typeof cors.origin === 'string') {\n res.setHeader('Access-Control-Allow-Origin', cors.origin);\n } else if (Array.isArray(cors.origin) && origin && cors.origin.includes(origin)) {\n res.setHeader('Access-Control-Allow-Origin', origin);\n }\n\n // 允许的方法\n if (cors.methods) {\n res.setHeader('Access-Control-Allow-Methods', cors.methods.join(', '));\n } else {\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');\n }\n\n // 允许的头\n if (cors.allowedHeaders) {\n res.setHeader('Access-Control-Allow-Headers', cors.allowedHeaders.join(', '));\n } else {\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');\n }\n\n // 凭证\n if (cors.credentials) {\n res.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n\n // 缓存\n if (cors.maxAge) {\n res.setHeader('Access-Control-Max-Age', String(cors.maxAge));\n }\n}\n\n/**\n * @zh 创建 HTTP 路由器\n * @en Create HTTP router\n */\nexport function createHttpRouter(routes: HttpRoutes, cors?: CorsOptions | boolean) {\n // 解析路由\n const parsedRoutes: Array<{\n method: string;\n path: string;\n handler: HttpHandler;\n }> = [];\n\n for (const [path, handlerOrMethods] of Object.entries(routes)) {\n if (typeof handlerOrMethods === 'function') {\n // 简单形式:路径 -> 处理器(接受所有方法)\n parsedRoutes.push({ method: '*', path, handler: handlerOrMethods });\n } else {\n // 对象形式:路径 -> { GET, POST, ... }\n for (const [method, handler] of Object.entries(handlerOrMethods)) {\n if (handler !== undefined) {\n parsedRoutes.push({ method, path, handler });\n }\n }\n }\n }\n\n // 默认 CORS 配置\n const corsOptions: CorsOptions | null =\n cors === true\n ? { origin: true, credentials: true }\n : cors === false\n ? null\n : 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 // 处理预检请求\n if (method === 'OPTIONS') {\n res.statusCode = 204;\n res.end();\n return true;\n }\n }\n\n // 查找匹配的路由\n const route = parsedRoutes.find(\n (r) => r.path === path && (r.method === '*' || r.method === method)\n );\n\n if (!route) {\n return false; // 未找到路由,让其他处理器处理\n }\n\n try {\n const httpReq = await createRequest(req);\n const httpRes = createResponse(res);\n await route.handler(httpReq, httpRes);\n return true;\n } catch (error) {\n console.error('[HTTP] Route handler error:', error);\n res.statusCode = 500;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Internal Server Error' }));\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 type {\n ApiDefinition,\n MsgDefinition,\n HttpDefinition,\n LoadedApiHandler,\n LoadedMsgHandler,\n LoadedHttpHandler,\n HttpMethod,\n} from '../types/index.js'\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 console.warn(`[Server] 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 console.warn(`[Server] 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(/\\[([^\\]]+)\\]/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 console.warn(`[Server] 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'\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 console.warn(`[RoomManager] 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 console.log(`[Room] 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 console.log(`[Room] 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 console.log(`[Room] 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 console.log(`[Room] 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 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\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 console.log(`[Server] Loaded ${apiHandlers.length} API handlers`)\n }\n if (msgHandlers.length > 0) {\n console.log(`[Server] Loaded ${msgHandlers.length} message handlers`)\n }\n if (httpHandlers.length > 0) {\n console.log(`[Server] 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, config.cors ?? true)\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 console.log(`[Server] 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 console.log(`[Server] 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"]}
@@ -0,0 +1,373 @@
1
+ import { Connection } from '@esengine/rpc';
2
+ import { IncomingMessage, ServerResponse } from 'node:http';
3
+
4
+ /**
5
+ * @zh HTTP 路由类型定义
6
+ * @en HTTP router type definitions
7
+ */
8
+
9
+ /**
10
+ * @zh HTTP 请求上下文
11
+ * @en HTTP request context
12
+ */
13
+ interface HttpRequest {
14
+ /**
15
+ * @zh 原始请求对象
16
+ * @en Raw request object
17
+ */
18
+ raw: IncomingMessage;
19
+ /**
20
+ * @zh 请求方法
21
+ * @en Request method
22
+ */
23
+ method: string;
24
+ /**
25
+ * @zh 请求路径
26
+ * @en Request path
27
+ */
28
+ path: string;
29
+ /**
30
+ * @zh 查询参数
31
+ * @en Query parameters
32
+ */
33
+ query: Record<string, string>;
34
+ /**
35
+ * @zh 请求头
36
+ * @en Request headers
37
+ */
38
+ headers: Record<string, string | string[] | undefined>;
39
+ /**
40
+ * @zh 解析后的 JSON 请求体
41
+ * @en Parsed JSON body
42
+ */
43
+ body: unknown;
44
+ /**
45
+ * @zh 客户端 IP
46
+ * @en Client IP
47
+ */
48
+ ip: string;
49
+ }
50
+ /**
51
+ * @zh HTTP 响应工具
52
+ * @en HTTP response utilities
53
+ */
54
+ interface HttpResponse {
55
+ /**
56
+ * @zh 原始响应对象
57
+ * @en Raw response object
58
+ */
59
+ raw: ServerResponse;
60
+ /**
61
+ * @zh 设置状态码
62
+ * @en Set status code
63
+ */
64
+ status(code: number): HttpResponse;
65
+ /**
66
+ * @zh 设置响应头
67
+ * @en Set response header
68
+ */
69
+ header(name: string, value: string): HttpResponse;
70
+ /**
71
+ * @zh 发送 JSON 响应
72
+ * @en Send JSON response
73
+ */
74
+ json(data: unknown): void;
75
+ /**
76
+ * @zh 发送文本响应
77
+ * @en Send text response
78
+ */
79
+ text(data: string): void;
80
+ /**
81
+ * @zh 发送错误响应
82
+ * @en Send error response
83
+ */
84
+ error(code: number, message: string): void;
85
+ }
86
+ /**
87
+ * @zh HTTP 路由处理器
88
+ * @en HTTP route handler
89
+ */
90
+ type HttpHandler = (req: HttpRequest, res: HttpResponse) => void | Promise<void>;
91
+ /**
92
+ * @zh HTTP 路由配置
93
+ * @en HTTP routes configuration
94
+ */
95
+ type HttpRoutes = Record<string, HttpHandler | {
96
+ GET?: HttpHandler;
97
+ POST?: HttpHandler;
98
+ PUT?: HttpHandler;
99
+ DELETE?: HttpHandler;
100
+ PATCH?: HttpHandler;
101
+ OPTIONS?: HttpHandler;
102
+ }>;
103
+ /**
104
+ * @zh CORS 配置
105
+ * @en CORS configuration
106
+ */
107
+ interface CorsOptions {
108
+ /**
109
+ * @zh 允许的来源
110
+ * @en Allowed origins
111
+ */
112
+ origin?: string | string[] | boolean;
113
+ /**
114
+ * @zh 允许的方法
115
+ * @en Allowed methods
116
+ */
117
+ methods?: string[];
118
+ /**
119
+ * @zh 允许的请求头
120
+ * @en Allowed headers
121
+ */
122
+ allowedHeaders?: string[];
123
+ /**
124
+ * @zh 是否允许携带凭证
125
+ * @en Allow credentials
126
+ */
127
+ credentials?: boolean;
128
+ /**
129
+ * @zh 预检请求缓存时间(秒)
130
+ * @en Preflight cache max age
131
+ */
132
+ maxAge?: number;
133
+ }
134
+
135
+ /**
136
+ * @zh ESEngine Server 类型定义
137
+ * @en ESEngine Server type definitions
138
+ */
139
+
140
+ /**
141
+ * @zh 服务器配置
142
+ * @en Server configuration
143
+ */
144
+ interface ServerConfig {
145
+ /**
146
+ * @zh 监听端口
147
+ * @en Listen port
148
+ * @default 3000
149
+ */
150
+ port?: number;
151
+ /**
152
+ * @zh API 目录路径
153
+ * @en API directory path
154
+ * @default 'src/api'
155
+ */
156
+ apiDir?: string;
157
+ /**
158
+ * @zh 消息处理器目录路径
159
+ * @en Message handlers directory path
160
+ * @default 'src/msg'
161
+ */
162
+ msgDir?: string;
163
+ /**
164
+ * @zh HTTP 路由目录路径
165
+ * @en HTTP routes directory path
166
+ * @default 'src/http'
167
+ *
168
+ * @zh 文件命名规则:
169
+ * - `login.ts` → POST /api/login
170
+ * - `users/[id].ts` → /api/users/:id
171
+ * - `health.ts` (method: 'GET') → GET /api/health
172
+ * @en File naming convention:
173
+ * - `login.ts` → POST /api/login
174
+ * - `users/[id].ts` → /api/users/:id
175
+ * - `health.ts` (method: 'GET') → GET /api/health
176
+ */
177
+ httpDir?: string;
178
+ /**
179
+ * @zh HTTP 路由前缀
180
+ * @en HTTP routes prefix
181
+ * @default '/api'
182
+ */
183
+ httpPrefix?: string;
184
+ /**
185
+ * @zh 游戏 Tick 速率 (每秒)
186
+ * @en Game tick rate (per second)
187
+ * @default 20
188
+ */
189
+ tickRate?: number;
190
+ /**
191
+ * @zh HTTP 路由配置(内联定义,与 httpDir 文件路由合并)
192
+ * @en HTTP routes configuration (inline definition, merged with httpDir file routes)
193
+ */
194
+ http?: HttpRoutes;
195
+ /**
196
+ * @zh CORS 配置
197
+ * @en CORS configuration
198
+ * @default true
199
+ */
200
+ cors?: CorsOptions | boolean;
201
+ /**
202
+ * @zh 服务器启动回调
203
+ * @en Server start callback
204
+ */
205
+ onStart?: (port: number) => void;
206
+ /**
207
+ * @zh 连接建立回调
208
+ * @en Connection established callback
209
+ */
210
+ onConnect?: (conn: ServerConnection) => void | Promise<void>;
211
+ /**
212
+ * @zh 连接断开回调
213
+ * @en Connection closed callback
214
+ */
215
+ onDisconnect?: (conn: ServerConnection) => void | Promise<void>;
216
+ }
217
+ /**
218
+ * @zh 服务器连接(扩展 RPC Connection)
219
+ * @en Server connection (extends RPC Connection)
220
+ */
221
+ interface ServerConnection<TData = Record<string, unknown>> extends Connection<TData> {
222
+ /**
223
+ * @zh 连接唯一标识(继承自 Connection)
224
+ * @en Connection unique identifier (inherited from Connection)
225
+ */
226
+ readonly id: string;
227
+ /**
228
+ * @zh 用户自定义数据
229
+ * @en User-defined data
230
+ */
231
+ data: TData;
232
+ }
233
+ /**
234
+ * @zh API 处理器上下文
235
+ * @en API handler context
236
+ */
237
+ interface ApiContext<TData = Record<string, unknown>> {
238
+ /**
239
+ * @zh 当前连接
240
+ * @en Current connection
241
+ */
242
+ conn: ServerConnection<TData>;
243
+ /**
244
+ * @zh 服务器实例
245
+ * @en Server instance
246
+ */
247
+ server: GameServer;
248
+ }
249
+ /**
250
+ * @zh API 定义选项
251
+ * @en API definition options
252
+ */
253
+ interface ApiDefinition<TReq = unknown, TRes = unknown, TData = Record<string, unknown>> {
254
+ /**
255
+ * @zh API 处理函数
256
+ * @en API handler function
257
+ */
258
+ handler: (req: TReq, ctx: ApiContext<TData>) => TRes | Promise<TRes>;
259
+ /**
260
+ * @zh 请求验证函数(可选)
261
+ * @en Request validation function (optional)
262
+ */
263
+ validate?: (req: unknown) => req is TReq;
264
+ }
265
+ /**
266
+ * @zh 消息处理器上下文
267
+ * @en Message handler context
268
+ */
269
+ interface MsgContext<TData = Record<string, unknown>> {
270
+ /**
271
+ * @zh 当前连接
272
+ * @en Current connection
273
+ */
274
+ conn: ServerConnection<TData>;
275
+ /**
276
+ * @zh 服务器实例
277
+ * @en Server instance
278
+ */
279
+ server: GameServer;
280
+ }
281
+ /**
282
+ * @zh 消息定义选项
283
+ * @en Message definition options
284
+ */
285
+ interface MsgDefinition<TMsg = unknown, TData = Record<string, unknown>> {
286
+ /**
287
+ * @zh 消息处理函数
288
+ * @en Message handler function
289
+ */
290
+ handler: (msg: TMsg, ctx: MsgContext<TData>) => void | Promise<void>;
291
+ }
292
+ /**
293
+ * @zh 游戏服务器接口
294
+ * @en Game server interface
295
+ */
296
+ interface GameServer {
297
+ /**
298
+ * @zh 启动服务器
299
+ * @en Start server
300
+ */
301
+ start(): Promise<void>;
302
+ /**
303
+ * @zh 停止服务器
304
+ * @en Stop server
305
+ */
306
+ stop(): Promise<void>;
307
+ /**
308
+ * @zh 广播消息
309
+ * @en Broadcast message
310
+ */
311
+ broadcast<T>(name: string, data: T): void;
312
+ /**
313
+ * @zh 发送消息给指定连接
314
+ * @en Send message to specific connection
315
+ */
316
+ send<T>(conn: ServerConnection, name: string, data: T): void;
317
+ /**
318
+ * @zh 获取所有连接
319
+ * @en Get all connections
320
+ */
321
+ readonly connections: ReadonlyArray<ServerConnection>;
322
+ /**
323
+ * @zh 当前 Tick
324
+ * @en Current tick
325
+ */
326
+ readonly tick: number;
327
+ /**
328
+ * @zh 注册房间类型
329
+ * @en Define room type
330
+ */
331
+ define(name: string, roomClass: new () => unknown): void;
332
+ }
333
+ /**
334
+ * @zh HTTP 请求方法
335
+ * @en HTTP request method
336
+ */
337
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
338
+ /**
339
+ * @zh HTTP 定义选项
340
+ * @en HTTP definition options
341
+ *
342
+ * @example
343
+ * ```typescript
344
+ * // src/http/login.ts
345
+ * import { defineHttp } from '@esengine/server'
346
+ *
347
+ * export default defineHttp({
348
+ * method: 'POST',
349
+ * handler: async (req, res) => {
350
+ * const { username, password } = req.body
351
+ * // ... authentication logic
352
+ * res.json({ token: '...', userId: '...' })
353
+ * }
354
+ * })
355
+ * ```
356
+ */
357
+ interface HttpDefinition<TBody = unknown> {
358
+ /**
359
+ * @zh 请求方法
360
+ * @en Request method
361
+ * @default 'POST'
362
+ */
363
+ method?: HttpMethod;
364
+ /**
365
+ * @zh 处理函数
366
+ * @en Handler function
367
+ */
368
+ handler: (req: HttpRequest & {
369
+ body: TBody;
370
+ }, res: HttpResponse) => void | Promise<void>;
371
+ }
372
+
373
+ export type { ApiDefinition as A, CorsOptions as C, GameServer as G, HttpDefinition as H, MsgDefinition as M, ServerConfig as S, HttpRoutes as a, ServerConnection as b, ApiContext as c, MsgContext as d, HttpMethod as e, HttpRequest as f, HttpResponse as g, HttpHandler as h };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { S as ServerConfig, G as GameServer, A as ApiDefinition, M as MsgDefinition } from './index-DgaJIm6-.js';
2
- export { b as ApiContext, c as MsgContext, a as ServerConnection } from './index-DgaJIm6-.js';
1
+ import { S as ServerConfig, G as GameServer, A as ApiDefinition, M as MsgDefinition, H as HttpDefinition, a as HttpRoutes, C as CorsOptions } from './index-DyMTy67Q.js';
2
+ export { c as ApiContext, h as HttpHandler, e as HttpMethod, f as HttpRequest, g as HttpResponse, d as MsgContext, b as ServerConnection } from './index-DyMTy67Q.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
+ import { IncomingMessage, ServerResponse } from 'node:http';
5
6
  export { ErrorCode, RpcError } from '@esengine/rpc';
6
7
 
7
8
  /**
@@ -31,8 +32,8 @@ export { ErrorCode, RpcError } from '@esengine/rpc';
31
32
  declare function createServer(config?: ServerConfig): Promise<GameServer>;
32
33
 
33
34
  /**
34
- * @zh API 和消息定义助手
35
- * @en API and message definition helpers
35
+ * @zh API、消息和 HTTP 定义助手
36
+ * @en API, message, and HTTP definition helpers
36
37
  */
37
38
 
38
39
  /**
@@ -70,5 +71,44 @@ declare function defineApi<TReq, TRes, TData = Record<string, unknown>>(definiti
70
71
  * ```
71
72
  */
72
73
  declare function defineMsg<TMsg, TData = Record<string, unknown>>(definition: MsgDefinition<TMsg, TData>): MsgDefinition<TMsg, TData>;
74
+ /**
75
+ * @zh 定义 HTTP 路由处理器
76
+ * @en Define HTTP route handler
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * // src/http/login.ts
81
+ * import { defineHttp } from '@esengine/server'
82
+ *
83
+ * interface LoginBody {
84
+ * username: string
85
+ * password: string
86
+ * }
87
+ *
88
+ * export default defineHttp<LoginBody>({
89
+ * method: 'POST',
90
+ * handler(req, res) {
91
+ * const { username, password } = req.body
92
+ * // ... validate credentials
93
+ * res.json({ token: '...', userId: '...' })
94
+ * }
95
+ * })
96
+ * ```
97
+ */
98
+ declare function defineHttp<TBody = unknown>(definition: HttpDefinition<TBody>): HttpDefinition<TBody>;
99
+
100
+ /**
101
+ * @zh HTTP 路由器
102
+ * @en HTTP Router
103
+ *
104
+ * @zh 简洁的 HTTP 路由实现,支持与 WebSocket 共用端口
105
+ * @en Simple HTTP router implementation, supports sharing port with WebSocket
106
+ */
107
+
108
+ /**
109
+ * @zh 创建 HTTP 路由器
110
+ * @en Create HTTP router
111
+ */
112
+ declare function createHttpRouter(routes: HttpRoutes, cors?: CorsOptions | boolean): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
73
113
 
74
- export { ApiDefinition, GameServer, MsgDefinition, ServerConfig, createServer, defineApi, defineMsg };
114
+ export { ApiDefinition, CorsOptions, GameServer, HttpDefinition, HttpRoutes, MsgDefinition, ServerConfig, createHttpRouter, createServer, defineApi, defineHttp, defineMsg };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { createServer } from './chunk-QWEIP5QH.js';
1
+ export { createHttpRouter, createServer } from './chunk-BIAOJF7P.js';
2
2
  export { Player, Room, onMessage } from './chunk-O3VN2QVN.js';
3
3
  import { __name } from './chunk-T626JPC7.js';
4
4
  export { ErrorCode, RpcError } from '@esengine/rpc';
@@ -12,7 +12,11 @@ function defineMsg(definition) {
12
12
  return definition;
13
13
  }
14
14
  __name(defineMsg, "defineMsg");
15
+ function defineHttp(definition) {
16
+ return definition;
17
+ }
18
+ __name(defineHttp, "defineHttp");
15
19
 
16
- export { defineApi, defineMsg };
20
+ export { defineApi, defineHttp, defineMsg };
17
21
  //# sourceMappingURL=index.js.map
18
22
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/helpers/define.ts"],"names":["defineApi","definition","defineMsg"],"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","file":"index.js","sourcesContent":["/**\n * @zh API 和消息定义助手\n * @en API and message definition helpers\n */\n\nimport type { ApiDefinition, MsgDefinition } 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"]}
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"]}
@@ -1,7 +1,8 @@
1
1
  import { Codec } from '@esengine/rpc/codec';
2
- import { G as GameServer } from '../index-DgaJIm6-.js';
2
+ import { G as GameServer } from '../index-DyMTy67Q.js';
3
3
  import { R as Room, P as Player } from '../Room-BnKpl5Sj.js';
4
4
  import '@esengine/rpc';
5
+ import 'node:http';
5
6
 
6
7
  /**
7
8
  * @zh 测试客户端
@@ -1,4 +1,4 @@
1
- import { createServer } from '../chunk-QWEIP5QH.js';
1
+ import { createServer } from '../chunk-BIAOJF7P.js';
2
2
  import { onMessage, Room } from '../chunk-O3VN2QVN.js';
3
3
  import { __name, __publicField } from '../chunk-T626JPC7.js';
4
4
  import WebSocket from 'ws';
@@ -1,4 +1,4 @@
1
- import { a as ServerConnection, b as ApiContext, c as MsgContext, G as GameServer } from './index-DgaJIm6-.js';
1
+ import { b as ServerConnection, c as ApiContext, d as MsgContext, G as GameServer } from './index-DyMTy67Q.js';
2
2
 
3
3
  /**
4
4
  * @zh 认证系统类型定义