npm package: @sunshj/server
Description: 一个轻量级、高性能的 Web 服务器框架
Author: sunshj
Latest version: 0.1.0-beta.21

# @sunshj/server

一个轻量级、高性能的 Web 服务器框架，结合了 Express.js、Hono.js 和 h3 的优秀特性。

[![NPM Version](https://img.shields.io/npm/v/@sunshj/server)](https://www.npmjs.com/package/@sunshj/server)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/Node.js-18+-green)](https://nodejs.org/)
[![License](https://img.shields.io/npm/l/@sunshj/server)](https://github.com/sunshj/server/blob/main/LICENSE)

## ✨ 特性

- 🚀 **极致性能**: 基于 Node.js 原生 HTTP 模块，零外部依赖
- 🔷 **TypeScript 优先**: 完整的类型定义和智能提示，路径参数自动类型推断
- 🔗 **线性链式中间件**: 简洁高效的中间件系统，支持早期返回和错误处理
- 🎯 **现代 API**: 简洁直观，开发体验优秀
- 📦 **轻量级**: 仅 36.12KB (CJS),比 Express 小 5 倍
- 🔧 **灵活路由**: 动态参数、通配符、嵌套路由、类型化路由组
- ⚡ **智能响应**: 自动推断响应类型，按需解析
- 📤 **文件上传**: 原生支持 FormData 和文件上传解析
- 🌊 **流式响应**: 原生支持 ReadableStream，可轻松实现 SSE
- 🪝 **钩子系统**: 灵活的生命周期钩子(beforeRequest、beforeResponse、afterResponse、error、notFound)
- 🌐 **Web Standards**: 基于 Web 标准 API，兼容多种运行时(Node.js、Deno、Bun、Cloudflare Workers)

## 🚀 快速开始

### 安装

```bash
npm install @sunshj/server
# 或者
pnpm add @sunshj/server
# 或者
yarn add @sunshj/server
```

### 基础使用

```typescript
import { bodyParser, createApp } from '@sunshj/server'

const app = createApp()

// 注入 body parser 中间件（必须在访问请求体之前注册）
app.use(bodyParser())

// 基础路由
app.get('/', ctx => {
  return { message: 'Hello World!' }
})

// 动态路由参数
app.get('/users/:id', ctx => {
  const { id } = ctx.params
  return { user: { id, name: `User ${id}` } }
})

// 启动服务器
app.listen(3000, server => {
  console.log('🚀 Server running on http://localhost:3000')
  console.log('Server address:', server.address())
})
```

## 📚 核心概念

### Context 上下文

每个请求处理函数都会接收一个 `Context` 对象，包含请求信息和响应方法：

```typescript
app.get('/api/users/:id', ctx => {
  // 路径参数
  const { id } = ctx.params

  // 查询参数
  const { page = '1', limit = '10' } = ctx.query

  // 请求头 (Web Standard Headers)
  const userAgent = ctx.headers.get('user-agent')

  // 智能响应
  return ctx.status(200).json({
    user: { id },
    pagination: { page: Number(page), limit: Number(limit) },
    userAgent
  })
})
```

### 路由定义

支持所有标准 HTTP 方法：

```typescript
app.get('/users', getAllUsers)
app.post('/users', createUser)
app.put('/users/:id', updateUser)
app.delete('/users/:id', deleteUser)
app.patch('/users/:id', patchUser)

// 链式路由
app.route('/users/:id').get(getUser).put(updateUser).delete(deleteUser)

// 支持多种 HTTP 方法
app.get('/users', getAllUsers)
app.post('/users', createUser)
app.put('/users/:id', updateUser)
app.delete('/users/:id', deleteUser)
app.patch('/users/:id', patchUser)
app.head('/users/:id', checkUser)
app.options('/users', getUserOptions)

// 通配符路由
app.get('/static/*', serveStaticFiles)

// 匹配所有方法
app.all('/api/*', authMiddleware)
```

### 中间件系统

框架采用**线性链式中间件模型**（类似 Express），简洁高效且易于理解。

#### 中间件基础概念

中间件是一个可以访问请求上下文 (`Context`) 的函数，可以：

- 在请求到达路由处理器之前执行预处理逻辑
- 通过调用 `await ctx.next()` 将控制权传递给下一个处理器
- 通过返回 `Response` 提前终止请求处理链

**重要特性**：

- 中间件和路由处理器使用相同的 `RouteHandler` 类型
- 中间件按注册顺序依次执行（线性模型）
- **`await ctx.next()` 现在是可选的**：中间件如果不调用 `ctx.next()` 且没有返回值,会自动继续执行下一个处理器
- `await ctx.next()` 之后的代码**不会执行**（这是设计特性，非 bug）
- 如需响应后逻辑（如日志、清理），请使用 `afterResponse` hook

#### 全局中间件

应用于所有请求的中间件：

```typescript
// 日志中间件 - ctx.next() 现在是可选的
app.use(ctx => {
  console.log(`→ ${ctx.method} ${ctx.url.pathname}`)
  // ✅ 不调用 ctx.next() 也会自动继续到下一个处理器
})

// 也可以显式调用 ctx.next()
app.use(async ctx => {
  console.log(`→ ${ctx.method} ${ctx.url.pathname}`)
  await ctx.next() // 显式继续到下一个处理器
  // ⚠️ 注意：这之后的代码不会执行（线性链式模型的设计）
  // 如需响应后逻辑，请使用 afterResponse hook
})

// 计时中间件
app.use(ctx => {
  const start = Date.now()
  // 可以省略 ctx.next()，会自动继续
  // ⚠️ 注意：这里无法计算响应时间，应该使用 afterResponse hook
})

// 正确的计时方式：使用 afterResponse hook
app.on('afterResponse', (request, response, ctx, duration) => {
  console.log(`${ctx.method} ${ctx.url.pathname} - ${duration}ms`)
})
```

#### 路径中间件

只对特定路径生效的中间件：

```typescript
// API 认证中间件
app.use('/api/*', async ctx => {
  const token = ctx.headers.get('authorization')
  if (!token) {
    return ctx.error(401, 'Missing authorization header')
  }

  // 验证 token
  try {
    const user = await verifyToken(token)
    ctx.user = user // 扩展 context
    // ctx.next() 是可选的，这里会自动继续
  } catch {
    return ctx.error(401, 'Invalid token')
  }
})

// 管理员权限验证
app.use('/admin/*', ctx => {
  if (!ctx.user?.isAdmin) {
    return ctx.error(403, 'Admin access required')
  }
  // 不需要 ctx.next()，会自动继续
})
```

#### 中间件早期返回

中间件可以通过返回 `Response` 来终止请求处理链：

```typescript
// 认证中间件示例
function authMiddleware(ctx) {
  if (!ctx.headers.get('authorization')) {
    return ctx.error(401, 'Unauthorized') // 🚀 直接返回，停止执行链
  }
  // 不需要 ctx.next()，会自动继续到下一个处理器
}

// 使用多个中间件
app.post(
  '/protected',
  authMiddleware, // 第一个中间件：认证
  async ctx => {
    // 第二个中间件：验证请求体
    const data = await ctx.readBody()
    if (!data.name) {
      return ctx.error(400, 'Name is required')
    }
    // ctx.next() 是可选的
  },
  async ctx => {
    // 最终的路由处理器
    const data = await ctx.readBody()
    return { message: 'Success', data }
  }
)
```

#### 路由级中间件

多个中间件可以作为参数传入路由方法：

```typescript
// 定义中间件函数 - ctx.next() 是可选的
function logMiddleware(ctx) {
  console.log(`Processing: ${ctx.url.pathname}`)
  // 不需要 ctx.next()，会自动继续
}

function validateMiddleware(ctx) {
  const contentType = ctx.headers.get('content-type')
  if (!contentType?.includes('application/json')) {
    return ctx.error(400, 'Content-Type must be application/json')
  }
  // ctx.next() 是可选的
}

// 应用多个中间件到特定路由
app.get('/protected', authMiddleware, logMiddleware, ctx => {
  return { message: 'Protected route accessed', user: ctx.user }
})

app.post('/data', validateMiddleware, logMiddleware, async ctx => {
  const data = await ctx.readBody()
  return { received: data }
})
```

#### 中间件执行流程

```typescript
// 执行顺序示例 - ctx.next() 现在是可选的
app.use(ctx => {
  console.log('1. 全局中间件')
  // 不需要 ctx.next()，会自动继续
})

app.use('/api/*', ctx => {
  console.log('2. 路径中间件')
  // ctx.next() 是可选的
})

app.get(
  '/api/users',
  ctx => {
    console.log('3. 第一个路由中间件')
    // 可以省略 ctx.next()
  },
  ctx => {
    console.log('4. 第二个路由中间件')
    // 自动继续到下一个处理器
  },
  ctx => {
    console.log('5. 最终路由处理器')
    return { message: 'Done' }
  }
)

// 请求 GET /api/users 时的执行顺序：
// 1. 全局中间件
// 2. 路径中间件
// 3. 第一个路由中间件
// 4. 第二个路由中间件
// 5. 最终路由处理器
```

#### 中间件作用域

框架通过 `routerId` 实现中间件作用域隔离。由于 `App extends Router`，App 和 Router 实例都有唯一的 `routerId`：

```typescript
// 1. App 级全局中间件 (routerId === app.id, 无 path)
// 应用到所有路由，包括挂载的 Router 路由
app.use(ctx => {
  console.log('App middleware')
  // ctx.next() 是可选的
})

// 2. App 级路径中间件 (routerId === app.id, 有 path)
// 应用到匹配路径的所有路由
app.use('/api/*', ctx => {
  console.log('API middleware')
  // 不需要 ctx.next()
})

// 3. Router 级全局中间件 (routerId === apiRouter.id, 无 path)
// 只应用到该 Router 的路由
const apiRouter = createRouter()
apiRouter.use(ctx => {
  console.log('Router middleware - 只对 apiRouter 的路由生效')
  // 自动继续
})
apiRouter.get('/users', ctx => ({ users: [] }))

// 4. Router 级路径中间件 (routerId === apiRouter.id, 有 path)
// 只应用到该 Router 中匹配路径的路由
apiRouter.use('/admin/*', ctx => {
  console.log('Router path middleware - 只对 apiRouter 的 /admin/* 路由生效')
  // ctx.next() 可选
})
apiRouter.get('/admin/users', ctx => ({ adminUsers: [] }))

// 挂载路由器
app.use('/api', apiRouter)

// 请求 GET /api/users 的中间件执行顺序：
// 1. App 全局中间件 (routerId === app.id)
// 2. App 路径中间件 /api/* (routerId === app.id)
// 3. Router 全局中间件 (routerId === apiRouter.id)
// 4. 路由处理器 /users

// 请求 GET /api/admin/users 的中间件执行顺序：
// 1. App 全局中间件 (routerId === app.id)
// 2. App 路径中间件 /api/* (routerId === app.id)
// 3. Router 全局中间件 (routerId === apiRouter.id)
// 4. Router 路径中间件 /admin/* (routerId === apiRouter.id)
// 5. 路由处理器 /admin/users
```

#### 条件中间件

根据条件动态执行逻辑：

```typescript
// 认证检查 - ctx.next() 是可选的
function requireAuth(ctx) {
  if (!ctx.headers.get('authorization')) {
    return ctx.error(401, 'Authentication required')
  }
  // 不需要 ctx.next()，会自动继续
}

// 角色检查
function requireRole(role: string) {
  return ctx => {
    if (ctx.user?.role !== role) {
      return ctx.error(403, `Role ${role} required`)
    }
    // ctx.next() 可选
  }
}

// 使用条件中间件
app.get('/user/profile', requireAuth, ctx => {
  return { user: ctx.user }
})

app.get('/admin/settings', requireAuth, requireRole('admin'), ctx => {
  return { settings: {} }
})
```

#### 中间件最佳实践

```typescript
// ✅ 推荐：使用 afterResponse hook 处理响应后逻辑
app.on('afterResponse', (request, response, ctx, duration) => {
  // 记录日志
  logger.info({
    method: ctx.method,
    path: ctx.url.pathname,
    status: response.status,
    duration
  })
})

// ❌ 不推荐：在中间件的 ctx.next() 之后写代码（不会执行）
app.use(async ctx => {
  await ctx.next()
  console.log('这段代码不会执行') // ❌
})

// ✅ 推荐：中间件只做请求预处理，ctx.next() 是可选的
app.use(ctx => {
  ctx.startTime = Date.now()
  // 不需要 ctx.next()，会自动继续
})

// ✅ 推荐：明确的早期返回
app.use(ctx => {
  if (condition) {
    return ctx.error(400, 'Bad request') // 明确终止
  }
  // ctx.next() 是可选的，会自动继续执行
})
```

### 路由分组

使用路由器创建模块化的路由：

```typescript
import { createRouter } from '@sunshj/server'

// API 路由
const apiRouter = createRouter()
apiRouter.get('/users', getAllUsers)
apiRouter.post('/users', createUser)
apiRouter.get('/users/:id', getUser)

// 管理员路由
const adminRouter = createRouter()
adminRouter.use(adminAuthMiddleware) // 路由级中间件
adminRouter.get('/stats', getStats)
adminRouter.get('/logs', getLogs)

// 挂载路由器
app.use('/api/v1', apiRouter)
app.use('/admin', adminRouter)
```

### 智能响应

框架会自动推断响应类型，让开发更简单：

```typescript
// 自动 JSON 响应
app.get('/api/user', ctx => {
  return { id: 1, name: 'John' } // → Content-Type: application/json
})

// 自动文本响应
app.get('/health', ctx => {
  return 'OK' // → Content-Type: text/plain
})

// 自动 HTML 响应
app.get('/home', ctx => {
  return '<h1>Welcome!</h1>' // → Content-Type: text/html
})

// HTML 模板字符串语法
app.get('/profile', ctx => {
  const name = 'John'
  return ctx.html`<div><h1>Hello, ${name}!</h1></div>`
})

// 显式响应方法
app.get('/explicit', ctx => {
  return ctx.json({ success: true })
  // 或 ctx.text('Hello')
  // 或 ctx.html('<h1>Hello</h1>')
  // 或 ctx.redirect('/login')
})

// 直接返回 Response 对象（用于高级场景）
app.get('/custom', ctx => {
  return new Response('Custom response', {
    status: 200,
    headers: {
      'Content-Type': 'text/plain',
      'X-Custom-Header': 'value'
    }
  })
})

// 链式调用设置状态码
app.post('/create', ctx => {
  return ctx.status(201).json({ created: true, id: 123 })
})

// 错误响应
app.get('/error', ctx => {
  return ctx.error(404, 'Resource not found')
})
```

### 请求体处理

现代化的请求体处理，智能且高效：

```typescript
import { bodyParser, createApp } from '@sunshj/server'

const app = createApp()

// 1. 注入 body parser 中间件（必须）
app.use(
  bodyParser({
    maxSize: 10 * 1024 * 1024, // 全局最大 10MB
    limits: {
      json: 1 * 1024 * 1024, // JSON 限制 1MB
      urlencoded: 1 * 1024 * 1024, // URL-encoded 限制 1MB
      multipart: 50 * 1024 * 1024, // Multipart 限制 50MB
      text: 1 * 1024 * 1024 // Text 限制 1MB
    },
    strict: false, // JSON 解析失败时降级为文本（默认 false）
    allowEmpty: true // 允许空请求体（默认 true）
  })
)

// 2. 使用 ctx.readBody() 读取请求体（推荐）
app.post('/api/users', async ctx => {
  const userData = await ctx.readBody() // ✅ 推荐：更好的类型推断

  // 数据验证
  if (!userData.name || !userData.email) {
    return ctx.error(400, 'Name and email are required')
  }

  const user = await createUser(userData)
  return ctx.status(201).json(user)
})

// ctx.body 已废弃，但仍可用
app.post('/api/data', async ctx => {
  const data = await ctx.body // ⚠️ 已废弃，建议使用 ctx.readBody()
  return { received: data }
})

// 获取类型化查询参数
app.get('/search', ctx => {
  const query = ctx.getQuery<{ q: string; page?: string }>()
  return { query: query.q, page: Number(query.page || 1) }
})

// 文件上传示例
app.post('/upload', async ctx => {
  // 使用便捷方法获取单个文件
  const file = await ctx.file('avatar') // 获取名为 'avatar' 的文件

  if (!file) {
    return ctx.error(400, 'No file uploaded')
  }

  // 使用 Web Standards File API
  const filename = `${Date.now()}-${file.name}`
  const arrayBuffer = await file.arrayBuffer()

  // 保存文件
  await writeFile(filename, Buffer.from(arrayBuffer))

  return {
    message: 'File uploaded successfully',
    filename,
    size: file.size,
    type: file.type
  }
})

// 多文件上传
app.post('/upload/multiple', async ctx => {
  // 使用便捷方法获取多个文件
  const files = await ctx.files('photos') // 获取名为 'photos' 的所有文件

  if (!files || files.length === 0) {
    return ctx.error(400, 'No files uploaded')
  }

  const uploadedFiles = await Promise.all(
    files.map(async file => {
      const filename = `${Date.now()}-${file.name}`
      const arrayBuffer = await file.arrayBuffer()
      await writeFile(filename, Buffer.from(arrayBuffer))
      return { filename, size: file.size }
    })
  )

  return {
    message: `${files.length} files uploaded successfully`,
    files: uploadedFiles
  }
})

// 获取表单字段
app.post('/form', async ctx => {
  const name = await ctx.field('name') // 获取单个字段
  const tags = await ctx.fields('tags') // 获取字段数组
  const files = await ctx.files('documents') // 获取文件数组

  return { name, tags, fileCount: files.length }
})

// 直接访问完整的 ParsedFormData
app.post('/upload/advanced', async ctx => {
  const body = await ctx.readBody<ParsedFormData>()

  // ParsedFormData 提供辅助方法
  const singleFile = body.file('avatar') // 获取单个文件
  const multipleFiles = body.fileArray('docs') // 获取文件数组
  const fieldValue = body.field('name') // 获取单个字段值
  const fieldArray = body.fieldArray('tags') // 获取字段数组

  return {
    file: singleFile?.name,
    docs: multipleFiles.map(f => f.name),
    name: fieldValue,
    tags: fieldArray
  }
})
```

**Body Parser 特性：**

- ✅ **必须注入**: 使用 `bodyParser()` 中间件注入解析器
- ✅ **惰性解析**: 只在访问 `ctx.readBody()` 或 `ctx.body` 时解析
- ✅ **智能检测**: 根据 Content-Type 自动选择解析方式
- ✅ **大小限制**: 可针对不同类型设置不同的大小限制
- ✅ **类型安全**: 完整的 TypeScript 类型支持
- ✅ **Web Standards**: 使用原生 `request.json()`, `request.formData()` 等 API
- ✅ **便捷方法**: `ctx.file()`, `ctx.files()`, `ctx.field()`, `ctx.fields()` 简化文件和字段访问

## 🔥 高级用法

### Server-Sent Events (SSE)

框架原生支持返回 `ReadableStream`，可轻松实现 SSE 流式推送：

```typescript
app.get('/events', () => {
  const stream = new ReadableStream({
    start(controller) {
      let count = 0
      const interval = setInterval(() => {
        if (count < 10) {
          // 发送 SSE 格式的数据
          controller.enqueue(`data: ${JSON.stringify({ count, time: Date.now() })}\n\n`)
          count++
        } else {
          clearInterval(interval)
          controller.close()
        }
      }, 1000)
    },
    cancel() {
      console.log('SSE stream cancelled')
    }
  })

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      Connection: 'keep-alive'
    }
  })
})
```

客户端连接：

```javascript
const eventSource = new EventSource('/events')
eventSource.addEventListener('message', event => {
  const data = JSON.parse(event.data)
  console.log('Received:', data)
})
```

### 错误处理

```typescript
// 全局错误处理中间件
app.use(async ctx => {
  try {
    await ctx.next()
  } catch (error) {
    console.error('Request error:', error)

    if (error.code === 'VALIDATION_ERROR') {
      return ctx.error(400, error.message)
    }

    return ctx.error(500, 'Internal Server Error')
  }
})

// 自定义错误类
class ValidationError extends Error {
  constructor(message: string) {
    super(message)
    this.code = 'VALIDATION_ERROR'
  }
}

app.post('/validate', async ctx => {
  const data = await ctx.readBody()

  if (!data.email) {
    throw new ValidationError('Email is required')
  }

  return { valid: true }
})
```

### Web Standards 兼容性

框架基于 Web 标准 API 构建，提供 `fetch` 方法兼容多种运行时：

```typescript
import { createApp } from '@sunshj/server'

const app = createApp()

app.get('/hello', ctx => {
  return { message: 'Hello, World!' }
})

// 使用 Web Standard Request/Response
const request = new Request('http://localhost:3000/hello')
const response = await app.fetch(request)
const data = await response.json()
console.log(data) // { message: 'Hello, World!' }

// 兼容 Cloudflare Workers、Deno、Bun 等运行时
export default {
  fetch: app.fetch
}
```

**Web Standards 特性：**

- ✅ 使用标准 `Request` 和 `Response` 对象
- ✅ 支持 `fetch(request)` 方法调用
- ✅ 兼容 Node.js、Deno、Bun、Cloudflare Workers
- ✅ 完全符合 Web API 规范

### Hooks 生命周期

框架提供完整的请求生命周期钩子，用于日志、监控和自定义处理：

```typescript
// beforeRequest - 请求到达时（无法中断请求）
app.on('beforeRequest', (request, ctx) => {
  console.log(`→ ${ctx.method} ${ctx.url.pathname}`)
})

// beforeResponse - 响应发送前（可修改响应）
app.on('beforeResponse', (response, ctx) => {
  const headers = new Headers(response.headers)
  headers.set('X-Powered-By', '@sunshj/server')
  return new Response(response.body, {
    status: response.status,
    headers
  })
})

// afterResponse - 响应发送后（日志、性能统计、清理）
// 这是实现"响应后逻辑"的推荐方式（而不是在中间件的 ctx.next() 之后写代码）
app.on('afterResponse', (request, response, ctx, duration) => {
  // 记录完整的请求/响应日志
  console.log({
    method: ctx.method,
    path: ctx.url.pathname,
    status: response.status,
    duration: `${duration}ms`,
    userAgent: request.headers.get('user-agent')
  })

  // 发送性能指标到监控系统
  // metrics.record('http.request.duration', duration, {
  //   method: ctx.method,
  //   status: response.status
  // })
})

// notFound - 自定义 404 处理
app.on('notFound', ctx => {
  return ctx.status(404).json({
    error: 'Not Found',
    path: ctx.url.pathname,
    message: '请求的资源不存在'
  })
})

// error - 全局错误处理
app.on('error', (error, ctx) => {
  console.error('Error:', error)
  return ctx.status(500).json({
    error: 'Internal Server Error',
    message: error.message
  })
})
```

**Hooks 执行顺序：**

```
1. beforeRequest  → 请求到达
2. 中间件链执行
3. 路由处理器执行
4. notFound       → (如果没有匹配的路由)
5. beforeResponse → 修改响应
6. 发送响应到客户端
7. afterResponse  → 后台日志/清理（不阻塞响应）
8. error          → (如果有错误发生)
```

**特别说明：**

- `afterResponse` 在响应发送后执行，不会阻塞响应
- `afterResponse` 中的所有注册的处理器都会执行（不会早期返回）
- `afterResponse` 适合用于日志、监控、资源清理等场景
- **这是实现"响应后逻辑"的推荐方式**，而不是在中间件的 `await ctx.next()` 之后写代码（那些代码不会执行）
- 其他 hooks 会在第一个返回值时停止执行

### 性能监控

使用 `afterResponse` hook 实现性能监控（推荐方式）：

```typescript
// 使用 afterResponse hook 记录请求时长
app.on('afterResponse', (request, response, ctx, duration) => {
  console.log(`${ctx.method} ${ctx.url.pathname} - ${duration.toFixed(2)}ms`)
})

// 请求计数器和日志
let requestCount = 0
app.on('beforeRequest', (request, ctx) => {
  requestCount++
  console.log(`[${requestCount}] ${ctx.method} ${ctx.url.pathname}`)
})
```

### 内容协商

```typescript
app.get('/api/data', ctx => {
  const accept = ctx.headers.get('accept')
  const data = { message: 'Hello', timestamp: Date.now() }

  if (accept?.includes('application/xml')) {
    return new Response(`<data><message>${data.message}</message></data>`, {
      headers: { 'Content-Type': 'application/xml' }
    })
  }

  return ctx.json(data) // 默认 JSON
})
```

## 📖 TypeScript 支持

框架提供完整的 TypeScript 支持和类型推断：

### 导出的类和函数

```typescript
// 导入所有可用的类、函数和类型
import {
  App, // 应用程序类
  BodyParser, // 请求体解析器类
  bodyParser, // 创建 body parser 中间件
  Context, // 请求上下文类
  ContextResponse, // 响应方法类
  ContextStore, // 状态管理类
  createApp, // 创建应用实例
  createLogger, // 创建日志器实例
  createRouter, // 创建路由器实例
  createRpcClient, // 创建 RPC 客户端
  defineRouteHandler, // 定义类型化路由处理器
  Logger, // 日志器类
  logger, // 默认日志器实例
  MiddlewareManager, // 中间件管理器基类
  RouteGroup, // 路由组类
  RouteHandlerError, // 路由处理器错误
  Router, // 路由器类
  RpcError, // RPC 调用错误
  withRPC, // 为 App 添加 RPC 功能
  type Hooks, // 生命周期钩子类型
  type HTTPMethod, // HTTP 方法类型
  type LogLevel, // 日志级别类型
  type ParsedFormData, // 解析后的表单数据类型（包含辅助方法）
  type ParsedFormDataResult, // 解析后的表单数据类型（无方法）
  type Route, // 路由配置类型
  type RouteHandler // 路由处理器类型
} from '@sunshj/server'

// 从 body-parser 模块导入错误类（用于错误处理）
import { BodyParseError, BodySizeError } from '@sunshj/server/body-parser'

// 扩展 Context 类型
declare module '@sunshj/server' {
  interface Context {
    user?: { id: string; name: string }
  }
}

// 类型化的处理函数
const getUser: RouteHandler<any, { id: string }> = async ctx => {
  const { id } = ctx.params // id 自动推断为 string
  const user = await findUserById(id)

  if (!user) {
    return ctx.error(404, 'User not found')
  }

  return { user }
}

// 🔷 路由组完整类型支持
// 路径参数类型自动推断
app.route('/users/:id').get(ctx => {
  const { id } = ctx.params // ✅ id 类型为 string
  return { user: { id } }
})

app.route('/posts/:postId').get('/comments/:commentId?', ctx => {
  const { postId, commentId } = ctx.params // ✅ 完整类型推断: { postId: string, commentId?: string }
  return { postId, commentId }
})

// 类型化的中间件（使用 RouteHandler 类型）
// 注意：中间件和路由处理器使用相同的 RouteHandler 类型
const logMiddleware: RouteHandler = ctx => {
  console.log(`${ctx.method} ${ctx.url.pathname}`)
  // ctx.next() 是可选的，不调用也会自动继续到下一个处理器
}

// 泛型支持
interface CreateUserBody {
  name: string
  email: string
}

app.post('/users', async (ctx: Context<CreateUserBody>) => {
  const userData = await ctx.body // 类型为 CreateUserBody
  return { user: userData }
})
```

**类型说明**：

- `RouteHandler<Body, Params, Query>` - 统一的处理器类型，用于中间件和路由处理器
- 中间件可以调用 `await ctx.next()` 显式继续执行链，也可以省略（自动继续）
- 路由处理器必须返回值作为响应
- 返回值会自动转换为 Response 对象（通过智能响应检测）

## ⚡ 与 Express.js 对比

| 特性       | @sunshj/server        | Express.js      |
| ---------- | --------------------- | --------------- |
| 包大小     | **36.12KB (CJS)**     | 197KB           |
| 依赖数量   | **0**                 | 20+             |
| TypeScript | **原生支持**          | 需要 @types 包  |
| 响应 API   | **现代化，自动推断**  | 传统 res.json() |
| 性能       | **高性能，原生 HTTP** | 较重的抽象层    |
| 中间件模型 | 线性执行              | 线性执行        |

### 🔄 迁移示例

**Express.js:**

```javascript
const express = require('express')

const app = express()
app.use(express.json())

app.get('/users/:id', (req, res) => {
  res.json({
    user: { id: req.params.id }
  })
})

app.post('/user', (req, res) => {
  const data = req.body
  res.json({
    user: { data }
  })
})

app.listen(3000)
```

**@sunshj/server:**

```typescript
import { bodyParser, createApp } from '@sunshj/server'

const app = createApp()
app.use(bodyParser())

app.get('/users/:id', ctx => {
  return {
    user: { id: ctx.params.id }
  }
})

app.post('/user', async ctx => {
  const data = await ctx.readBody()
  return {
    user: { data }
  }
})

app.listen(3000)
```

**迁移优势:**

- ✅ 代码量减少 30%
- ✅ 原生 TypeScript 支持
- ✅ 更现代的 API 设计

## 📋 API 参考

### 核心函数

#### createApp(options?)

创建应用实例。

```typescript
import { createApp } from '@sunshj/server'

// 基础用法
const app = createApp()

// 带配置选项
const app = createApp({
  server: {
    timeout: 120000, // 请求超时时间（毫秒）
    keepAliveTimeout: 5000, // Keep-Alive 超时时间（毫秒）
    maxHeaderSize: 16384 // 最大请求头大小（字节）
  }
})
```

#### createRouter()

创建路由器实例。

```typescript
import { createRouter } from '@sunshj/server'
const router = createRouter()
```

#### defineRouteHandler()

定义类型化的路由处理函数,提供完整的类型推断支持。

```typescript
import { defineRouteHandler } from '@sunshj/server'

// 定义类型化的处理函数
const getUserHandler = defineRouteHandler<
  any, // Body type
  { id: string }, // Params type
  { include?: string } // Query type
>(async ctx => {
  const { id } = ctx.params // 自动推断为 string
  const { include } = ctx.query // 自动推断为 string | undefined

  const user = await findUserById(id)
  if (!user) {
    return ctx.error(404, 'User not found')
  }

  return { user }
})

app.get('/users/:id', getUserHandler)

// 用于创建可复用的中间件
function zodValidator(schemas: Schema) {
  return defineRouteHandler(async ctx => {
    // 验证逻辑
    await ctx.next()
  })
}
```

#### bodyParser(options?)

创建 body parser 中间件,用于解析请求体。

```typescript
import { bodyParser } from '@sunshj/server'

// 基础用法
app.use(bodyParser())

// 自定义配置
app.use(
  bodyParser({
    maxSize: 5 * 1024 * 1024, // 全局最大 5MB
    limits: {
      json: 1 * 1024 * 1024, // JSON 限制 1MB
      urlencoded: 1 * 1024 * 1024, // URL-encoded 限制 1MB
      multipart: 10 * 1024 * 1024, // Multipart 限制 10MB
      text: 1 * 1024 * 1024 // Text 限制 1MB
    },
    strict: true, // 严格模式：JSON 解析失败时抛出错误
    allowEmpty: true // 允许空请求体
  })
)
```

### App 属性和方法

创建的应用实例提供以下方法：

| 方法                          | 类型                | 描述                             |
| ----------------------------- | ------------------- | -------------------------------- |
| `app.listen(port, callback?)` | `void`              | 启动 HTTP 服务器                 |
| `app.close()`                 | `Promise<void>`     | 关闭 HTTP 服务器                 |
| `app.fetch(request)`          | `Promise<Response>` | Web Standards 兼容的请求处理方法 |
| `app.on(event, handler)`      | `this`              | 注册生命周期钩子                 |

**访问底层 HTTP 服务器示例：**

```typescript
const app = createApp()

app.get('/', ctx => ({ message: 'Hello' }))

app.listen(3000, server => {
  // 回调函数接收 server 实例作为参数
  console.log('Server:', server.address())
})
```

### Router 和 MiddlewareManager

`Router` 类继承自 `MiddlewareManager`，提供路由注册和中间件管理功能：

```typescript
// Router 提供的 HTTP 方法
router.get(path, ...handlers)
router.post(path, ...handlers)
router.put(path, ...handlers)
router.delete(path, ...handlers)
router.patch(path, ...handlers)
router.head(path, ...handlers)
router.options(path, ...handlers)
router.all(path, ...handlers) // 匹配所有 HTTP 方法

// 中间件注册
router.use(middleware) // 全局中间件
router.use(path, middleware) // 路径中间件
router.use(path, router) // 挂载子路由器

// 路由组
router.route(basePath) // 返回 RouteGroup 实例
```

### Context 属性

| 属性          | 类型                     | 描述                                      |
| ------------- | ------------------------ | ----------------------------------------- |
| `ctx.params`  | `Record<string, string>` | 路径参数                                  |
| `ctx.query`   | `Record<string, string>` | 查询参数                                  |
| `ctx.body`    | `Promise<any>`           | 请求体 (已废弃,建议使用 `ctx.readBody()`) |
| `ctx.headers` | `Headers`                | Web Standard Headers 对象                 |
| `ctx.method`  | `HTTPMethod`             | HTTP 方法                                 |
| `ctx.url`     | `URL`                    | URL 对象                                  |
| `ctx.next`    | `() => Promise<void>`    | 调用下一个中间件/处理器                   |
| `ctx.store`   | `Map<string, unknown>`   | 全局共享状态存储 (来自 ContextStore)      |

### Context 方法

#### 实例方法

| 方法                         | 描述                     | 示例                               |
| ---------------------------- | ------------------------ | ---------------------------------- |
| `ctx.json(data)`             | JSON 响应                | `ctx.json({ success: true })`      |
| `ctx.text(text)`             | 文本响应                 | `ctx.text('Hello World')`          |
| `ctx.html(html)`             | HTML 响应                | `ctx.html('<h1>Hello</h1>')`       |
| ``ctx.html`template` ``      | HTML 模板字符串响应      | ``ctx.html`<h1>${name}</h1>` ``    |
| `ctx.status(code)`           | 设置状态码               | `ctx.status(201)`                  |
| `ctx.redirect(url, status?)` | 重定向                   | `ctx.redirect('/login', 302)`      |
| `ctx.error(status, message)` | 错误响应                 | `ctx.error(404, 'Not Found')`      |
| `ctx.readBody<T>()`          | 读取类型化请求体（推荐） | `await ctx.readBody<UserData>()`   |
| `ctx.getQuery<T>()`          | 获取类型化查询参数       | `ctx.getQuery<{ page: string }>()` |
| `ctx.file(fieldName)`        | 获取单个上传文件         | `await ctx.file('avatar')`         |
| `ctx.files(fieldName)`       | 获取多个上传文件         | `await ctx.files('photos')`        |
| `ctx.field(fieldName)`       | 获取单个表单字段         | `await ctx.field('name')`          |
| `ctx.fields(fieldName)`      | 获取多个表单字段         | `await ctx.fields('tags')`         |
| `ctx.provide(key, value)`    | 提供全局共享状态         | `ctx.provide('db', dbInstance)`    |
| `ctx.inject<T>(key)`         | 注入全局共享状态         | `ctx.inject<Database>('db')`       |

#### 静态方法

| 方法                              | 描述             | 示例                                |
| --------------------------------- | ---------------- | ----------------------------------- |
| `Context.json(data, statusCode?)` | 创建 JSON 响应   | `Context.json({ ok: true }, 200)`   |
| `Context.text(text, statusCode?)` | 创建文本响应     | `Context.text('Hello', 200)`        |
| `Context.html(html, statusCode?)` | 创建 HTML 响应   | `Context.html('<h1>Hi</h1>', 200)`  |
| `Context.error(status, message?)` | 创建错误响应     | `Context.error(404, 'Not Found')`   |
| `Context.provide(key, value)`     | 提供全局共享状态 | `Context.provide('db', dbInstance)` |
| `Context.inject<T>(key)`          | 注入全局共享状态 | `Context.inject<Database>('db')`    |

### 错误处理类

框架提供了三个专门的错误类，用于处理不同类型的错误场景：

#### BodyParseError

请求体解析错误，当解析失败或验证失败时抛出。

```typescript
import { BodyParseError, BodySizeError } from '@sunshj/server/body-parser'

try {
  const data = await ctx.readBody()
} catch (error) {
  if (error instanceof BodyParseError) {
    console.error('Parse error:', error.message)
    console.error('Raw body:', error.rawBody)
    return ctx.error(400, 'Invalid request body')
  }
}
```

**属性：**

- `message: string` - 错误信息
- `rawBody: string` - 原始请求体内容

#### BodySizeError

请求体大小超限错误，当请求体或文件超过配置的大小限制时抛出。

```typescript
try {
  const data = await ctx.readBody()
} catch (error) {
  if (error instanceof BodySizeError) {
    console.error('Size limit exceeded:', error.actualSize, '>', error.limitSize)
    return ctx.error(413, `Request too large: ${error.actualSize} bytes`)
  }
}
```

**属性：**

- `message: string` - 错误信息
- `actualSize: number` - 实际大小（字节）
- `limitSize: number` - 限制大小（字节）

#### RouteHandlerError

路由处理器错误，当路由处理器没有返回值时抛出。

```typescript
import { RouteHandlerError } from '@sunshj/server'

// 框架内部使用，用户一般不需要手动抛出
// 当最后一个路由处理器没有返回响应时会自动抛出
```

**属性：**

- `message: string` - 错误信息

### 日志系统

框架提供内置的日志工具，支持日志级别和格式化输出：

```typescript
import { createLogger, logger, type LogLevel } from '@sunshj/server'

// 使用默认日志器
logger.info('Server started')
logger.error('Something went wrong')

// 创建自定义日志器
const appLogger = createLogger({
  level: 'debug', // 'debug' | 'info' | 'warn' | 'error' | 'silent'
  prefix: 'MyApp',
  timestamp: true
})

appLogger.debug('Debug message') // 只有 level >= debug 才会输出
appLogger.info('Info message')
appLogger.warn('Warning message')
appLogger.error('Error message')

// 设置日志级别
appLogger.setLevel('warn') // 只输出 warn 和 error
appLogger.setPrefix('NewPrefix')

// 创建子日志器
const childLogger = appLogger.child({ prefix: 'SubModule' })
childLogger.info('Child logger message') // [MyApp:SubModule] ...
```

**Logger 方法：**

| 方法                  | 描述                        |
| --------------------- | --------------------------- |
| `logger.debug(...)`   | 输出 debug 级别日志         |
| `logger.info(...)`    | 输出 info 级别日志          |
| `logger.warn(...)`    | 输出 warn 级别日志          |
| `logger.error(...)`   | 输出 error 级别日志         |
| `logger.log(...)`     | info 的别名                 |
| `logger.setLevel()`   | 设置日志级别                |
| `logger.setPrefix()`  | 设置日志前缀                |
| `logger.child(opts)`  | 创建子日志器，继承父级配置  |

### RPC 系统

框架提供类型安全的 RPC（远程过程调用）系统，支持服务端和客户端：

```typescript
// 服务端
import { bodyParser, createApp, withRPC } from '@sunshj/server'

const app = withRPC(createApp())

app.use(bodyParser())

// 定义 RPC 函数
const rpcFunctions = {
  add(a: number, b: number) {
    return a + b
  },
  getUser(id: string) {
    return { id, name: `User ${id}` }
  }
}

// 注册 RPC 处理器（默认路径: /__rpc）
app.registerRpcFunctions(rpcFunctions)

app.listen(3000)
```

```typescript
// 客户端
import { createRpcClient, RpcError } from '@sunshj/server/rpc'

// 创建类型安全的 RPC 客户端
const client = createRpcClient<typeof rpcFunctions>('http://localhost:3000', {
  timeout: 30000, // 请求超时（毫秒）
  headers: { Authorization: 'Bearer token' } // 自定义请求头
})

// 调用远程函数（完整类型推断）
const sum = await client.add(1, 2) // 类型: number
const user = await client.getUser('123') // 类型: { id: string, name: string }

// 错误处理
try {
  await client.unknownMethod()
} catch (error) {
  if (error instanceof RpcError) {
    console.error(error.code, error.message)
  }
}
```

**RPC 导出：**

| 导出              | 描述                                    |
| ----------------- | --------------------------------------- |
| `withRPC(app)`    | 为 App 添加 RPC 功能                    |
| `createRpcClient` | 创建类型安全的 RPC 客户端               |
| `RpcError`        | RPC 调用错误类                          |

## 🌐 生态系统

虽然框架本身轻量，但可通过中间件无限扩展：

```typescript
// CORS 中间件
function cors(options = {}) {
  return ctx => {
    if (ctx.method === 'OPTIONS') {
      return new Response(null, {
        status: 204,
        headers: {
          'Access-Control-Allow-Origin': options.origin || '*',
          'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type,Authorization'
        }
      })
    }
    // ctx.next() 是可选的，会自动继续
  }
}

// JWT 认证中间件
function jwt(secret: string) {
  return ctx => {
    const token = ctx.headers.get('authorization')?.replace('Bearer ', '')

    if (!token) {
      return ctx.error(401, 'Token required')
    }

    try {
      ctx.user = verifyJWT(token, secret)
      // 不需要 ctx.next()，会自动继续
    } catch {
      return ctx.error(401, 'Invalid token')
    }
  }
}

// 静态文件服务中间件
function serveStatic(dir: string): RouteHandler {
  return async ctx => {
    const filePath = join(dir, ctx.url.pathname)
    try {
      const stats = await stat(filePath)
      if (!stats.isFile()) return await ctx.next()

      const content = await readFile(filePath)
      const ext = filePath.split('.').pop()
      return new Response(content, {
        headers: {
          'Content-Type': getContentType(ext),
          'Content-Length': stats.size.toString()
        }
      })
    } catch {
      return await ctx.next()
    }
  }
}

// 使用中间件
app.use(cors({ origin: 'https://example.com' }))
app.use('/api/*', jwt('your-secret'))
app.use('/*', serveStatic(join(__dirname, 'public')))
```

## 📄 许可证

[MIT](LICENSE) © [sunshj](https://github.com/sunshj)