packages/http/SKILL.md
@hile/http 的代码生成与使用规范。适用于路由、控制器、中间件、文件系统自动路由及与 @hile/core 的集成场景。
npx skillsauth add cevio/hile hile-httpInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
本文档用于规范 AI 与开发者在 @hile/http 中的实现方式,确保控制器形式、路由加载与服务生命周期管理一致。
@hile/http 由四部分组成:
Http:封装 Koa 与路由器,负责中间件、路由注册与服务启停defineController:将方法、可选中间件与处理函数封装为标准控制器;可选配合 createControllerMetadata 与 Zod 校验 query / params / request.bodydefineResponsePlugin:注册控制器结果的后处理插件链Loader:支持手动编译路由与按文件系统自动加载,并提供冲突策略与冲突回调典型流程:定义控制器 → 加载路由 → 启动服务。
import type { Context, Middleware } from 'koa'
import type { HTTPMethod } from 'find-my-way'
import { z, type ZodObject, type ZodType } from 'zod'
type HttpProps = {
port: number
keys?: string[]
ignoreDuplicateSlashes?: boolean
ignoreTrailingSlash?: boolean
maxParamLength?: number
allowUnsafeRegex?: boolean
caseSensitive?: boolean
}
type ControllerContext<A extends ZodObject, B extends ZodObject, C extends ZodType> = Context & {
query: z.infer<A>
params: z.infer<B>
request: Context['request'] & { body: z.infer<C> }
}
type ControllerFunction<A extends ZodObject, B extends ZodObject, C extends ZodType> = (
ctx: ControllerContext<A, B, C>
) => unknown | Promise<unknown>
// 两参/三参 defineController(method, …) 内部使用占位 z.object({}),运行时跳过 Zod;handler 仍按 (ctx: Context) 书写即可
type ResponsePluginFunction = (
ctx: Context,
result: any,
next: (r: any) => Promise<void>
) => Promise<any>
interface ControllerRegisterProps {
id: number
method: HTTPMethod
middlewares: Middleware[]
data: Record<string, any>
}
type LoaderConflictStrategy = 'error' | 'warn' | 'override'
type LoaderConflictResolution = 'error' | 'keep' | 'override'
type LoaderConflictContext = {
routeKey: string
method: string
url: string
strategy: LoaderConflictStrategy
resolution: LoaderConflictResolution
}
interface LoaderCompileOptions {
defaultSuffix?: string
prefix?: string
conflict?: LoaderConflictStrategy
onConflict?: (ctx: LoaderConflictContext) => void
}
type LoaderFromOptions = {
suffix?: string
} & LoaderCompileOptions
import { Http } from '@hile/http'
const http = new Http({ port: 3000 })
listen(onListen?):可选 onListen(server) 在 createServer 之后、server.listen 完成端口绑定之前调用(可为 async),便于把同一 http.Server 交给 Next.js、WebSocket 等;返回 Promise<() => void> 关闭函数。
http.use(async (ctx, next) => {
const start = Date.now()
await next()
ctx.set('X-Response-Time', `${Date.now() - start}ms`)
})
规则:必须在 listen() 前调用。
const off = http.get('/api/users', async (ctx) => {
ctx.body = { users: [] }
})
off()
规则:所有路由注册方法都返回注销函数。另支持 patch(url, ...mw) 与通用 route(method, url, ...mw)。
无中间件:
import { defineController } from '@hile/http'
export default defineController('GET', async (ctx) => {
return { ok: true }
})
带中间件:
import { defineController } from '@hile/http'
const auth = async (ctx, next) => {
if (!ctx.headers.authorization) ctx.throw(401)
await next()
}
export default defineController('POST', [auth], async (ctx) => {
return { created: true }
})
规则:
export default(ctx),不是 (ctx, next)undefined 时自动写入 ctx.body使用 createControllerMetadata 声明 Zod schema 时,走第三重载 defineController(metadata, fn);请求进入控制器前对 ctx.query、ctx.params、ctx.request.body 分别 safeParse,失败 ctx.throw(400, message)。仅声明部分字段(如只写 body)时,未声明部分不校验。schema 的三项均为内部占位空对象时与旧版行为一致(跳过校验)。
import { z } from 'zod'
import { createControllerMetadata, defineController } from '@hile/http'
const meta = createControllerMetadata({
method: 'POST',
middlewares: [],
schema: {
query: z.object({ page: z.coerce.number().optional() }),
params: z.object({ id: z.string().uuid() }),
body: z.object({ title: z.string().min(1) }),
},
})
export default defineController(meta, async (ctx) => {
return { id: ctx.params.id, title: ctx.request.body.title, page: ctx.query.page }
})
import { defineResponsePlugin } from '@hile/http'
defineResponsePlugin(async (ctx, result, next) => {
if (ctx.path.endsWith('.json')) {
return await next({ data: result })
}
return await next(result)
})
规则:
next(transformedResult) 以传递结果next 的结果为 undefined,不会设置 ctx.bodyawait http.load('./src/controllers', {
suffix: 'controller',
defaultSuffix: '/index',
prefix: '/api',
conflict: 'warn',
onConflict: (ctx) => {
console.warn('route conflict', ctx)
},
})
文件路径映射示例:
| 文件路径 | 路由路径 |
|---|---|
| index.controller.ts | /api |
| users/index.controller.ts | /api/users |
| users/[id].controller.ts | /api/users/:id |
冲突策略说明:
error:同一 method + path 冲突时抛错(默认)warn:保留旧路由并发出警告override:新路由覆盖旧路由onConflict 会在发生冲突时回调,提供 routeKey/method/url/strategy/resolution。
from() 会校验控制器默认导出类型。若导出不合法,错误信息包含文件路径和导出摘要,便于定位。
listen() 前注册。*.controller.ts/js(或与 suffix 一致)。next(),需要 next 的逻辑放中间件。load() 为异步,必须 await。conflict 策略,避免隐式覆盖。schema 应与真实请求形状一致;校验失败为 400,消息来自 Zod。// ✗
export default defineController('GET', async (ctx, next) => {
await next()
return { ok: true }
})
// ✓
export default defineController('GET', async (ctx) => {
return { ok: true }
})
// ✗
export default defineController('GET', async (ctx) => {
ctx.body = { a: 1 }
return { b: 2 }
})
// ✓
export default defineController('GET', async () => {
return { b: 2 }
})
// ✗ 不清晰:项目多人协作时难以统一预期
await http.load('./src/controllers')
// ✓ 显式策略:可读且可审计
await http.load('./src/controllers', { conflict: 'error' })
import { defineService } from '@hile/core'
import { Http } from '@hile/http'
export const httpService = defineService('http', async (shutdown) => {
const http = new Http({ port: 3000 })
await http.load('./src/controllers', { suffix: 'controller', prefix: '/api' })
const close = await http.listen()
shutdown(close)
return http
})
| 导出 | 说明 |
|---|---|
| Http | HTTP 服务实例类(listen(onListen?)、get/post/put/delete/patch/trace/route、load) |
| defineController | 控制器定义(method+fn、method+middlewares+fn、metadata+fn) |
| createControllerMetadata | 构造带 method / middlewares / schema 的元数据,供 Zod 校验 |
| ControllerContext | 带推断类型的 Context(类型) |
| defineResponsePlugin | 响应结果插件 |
| Loader | 路由加载器 |
| compileRoutePath | 路径编译纯函数 |
| toRouterPath | 参数路径转换纯函数 |
devops
@hile/model: defineModel/loadModel 定义和消费模型;services 依赖注入;pipeline 中间件链;每次 loadModel 重新执行 main
development
Code generation and contribution rules for @hile/micro-dynamic-configs. Use when editing this package or when the user asks about dynamic config patterns or API.
development
Code generation and contribution rules for @hile/cache. Use when editing this package or when the user asks about @hile/cache API, types, patterns, or features.
development
Code generation and contribution rules for @hile/micro. Use when editing this package or when the user asks about @hile/micro API, types, patterns, or features.