@aomex/web
Advanced tools
Comparing version 1.0.2 to 1.0.3
# @aomex/web | ||
## 1.0.3 | ||
### Patch Changes | ||
- [`5f09bc3`](https://github.com/aomex/aomex/commit/5f09bc3dda73bda9e69b5968bc913982d53dd4de) Thanks [@geekact](https://github.com/geekact)! - chore(web): 升级co-body包 6.1.0 -> 6.2.0 | ||
- [`48c803e`](https://github.com/aomex/aomex/commit/48c803e35700a4718f3c993e27bc982feb29061e) Thanks [@geekact](https://github.com/geekact)! - feat(web,router): 响应格式静态类型约束 | ||
- [`eb8b1eb`](https://github.com/aomex/aomex/commit/eb8b1ebdc7072d7ee9c7ba8e1f324e802753416d) Thanks [@geekact](https://github.com/geekact)! - feat(openapi): 文档生成工具 | ||
- Updated dependencies []: | ||
- @aomex/internal-tools@1.0.3 | ||
## 1.0.2 | ||
@@ -4,0 +17,0 @@ |
@@ -48,3 +48,3 @@ import { I18nFormat, Next, Middleware, OpenAPI, MiddlewareChain, MixinMiddlewareToken, Validator, TransformedValidator, magistrate, MixinMiddlewareChain, I18n, ValidatorToken } from '@aomex/core'; | ||
url: string; | ||
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'CONNECT' | (string & {}); | ||
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; | ||
params: Record<string, unknown>; | ||
@@ -165,2 +165,4 @@ private _accept?; | ||
readonly response: WebResponse; | ||
readonly redirect: WebResponse['redirect']; | ||
readonly download: WebResponse['download']; | ||
constructor(app: WebApp, request: WebRequest, response: WebResponse); | ||
@@ -173,8 +175,5 @@ /** | ||
* ``` | ||
* 更多快捷方式: | ||
* - 链接重定向:`ctx.response.redirect(...)` | ||
* - 下载文件:`ctx.response.download(...)` | ||
*/ | ||
send(statusCode: number, body?: Body): this; | ||
send(body: Body): this; | ||
send(statusCode: number, body?: Body): void; | ||
send(body: Body): void; | ||
/** | ||
@@ -184,8 +183,6 @@ * 抛出Http请求异常 | ||
* ```typescript | ||
* ctx.throw(403) | ||
* ctx.throw('name required', 400) | ||
* ctx.throw(400, 'name required') | ||
* ctx.throw('something exploded') | ||
* ctx.throw(new Error('invalid'), 400); | ||
* ctx.throw(403); | ||
* ctx.throw(400, 'name required'); | ||
* ctx.throw(400, new Error('invalid')); | ||
* ctx.throw(500, new Error('server error'), { expose: true }); | ||
* ``` | ||
@@ -198,4 +195,4 @@ * @link https://github.com/jshttp/http-errors | ||
throw(statusCode: number, message?: string | Error, properties?: HttpErrorProperties): never; | ||
throw(message: string | Error, statusCode?: number, properties?: HttpErrorProperties): never; | ||
throw(statusCode?: number, properties?: HttpErrorProperties): never; | ||
throw(err: Error, properties?: HttpErrorProperties): never; | ||
throw(statusCode: number, properties?: HttpErrorProperties): never; | ||
} | ||
@@ -395,9 +392,18 @@ interface HttpErrorProperties { | ||
interface WebResponseOptions extends Pick<OpenAPI.MediaTypeObject, 'example'> { | ||
statusCode: number; | ||
type OKStatus = 200 | 201 | 202 | 203 | 206 | 207 | 208 | 226; | ||
type EmptyStatus = 204 | 205 | 304; | ||
type RedirectStatus = 300 | 301 | 302 | 303 | 305 | 307 | 308; | ||
type ClientErrorStatus = 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 431 | 451; | ||
type ServerErrorStatus = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511; | ||
type HttpStatus = OKStatus | EmptyStatus | RedirectStatus | ClientErrorStatus | ServerErrorStatus; | ||
type BodySubType<T extends ValidatorToken> = unknown extends Validator.Infer<T> ? Body : Extract<Validator.Infer<T>, Body>; | ||
interface WebResponseOptions<Code extends HttpStatus, Content extends ValidatorToken> extends Pick<OpenAPI.MediaTypeObject, 'example'> { | ||
statusCode: Code; | ||
/** | ||
* 响应格式,支持简写和完整写法。如果不填,则根据响应值判断 | ||
* 响应格式,支持简写和完整写法。如果不填,则根据content的结构判断 | ||
* | ||
* 包括但不限于如下类型: | ||
* - application/json | ||
* - application/* | ||
* - json | ||
* - application/json | ||
* - text | ||
@@ -407,9 +413,11 @@ * - binary | ||
* - stream | ||
* - \*\/\* | ||
*/ | ||
contentType?: string; | ||
/** | ||
* 最终的响应值类型 | ||
* 响应内容结构 | ||
*/ | ||
schema?: ValidatorToken; | ||
content?: Content; | ||
/** | ||
* 报文结构 | ||
*/ | ||
headers?: { | ||
@@ -420,5 +428,33 @@ [key: string]: Validator; | ||
} | ||
declare class WebResponseMiddleware extends WebMiddleware<object> { | ||
protected readonly options: WebResponseOptions; | ||
constructor(options: WebResponseOptions); | ||
declare class WebResponseMiddleware<Code extends HttpStatus, Content extends ValidatorToken> extends WebMiddleware<Code extends 200 ? { | ||
/** | ||
* 来自response中间件定制的send()方法。200状态码可以忽略不写 | ||
*/ | ||
send(statusCode: Code, body: BodySubType<Content>): void; | ||
send(body: BodySubType<Content>): void; | ||
} : Code extends OKStatus ? { | ||
/** | ||
* 来自response中间件定制的send()方法 | ||
*/ | ||
send(statusCode: Code, body: BodySubType<Content>): void; | ||
} : Code extends EmptyStatus ? { | ||
/** | ||
* 来自response中间件定制的send()方法。空状态码无需响应数据 | ||
*/ | ||
send(statusCode: Code): void; | ||
send(statusCode: Code, body: null): void; | ||
} : Code extends RedirectStatus ? { | ||
/** | ||
* 来自response中间件定制的redirect()方法 | ||
*/ | ||
redirect(statusCode: Code, url: string): void; | ||
} : { | ||
/** | ||
* 来自response中间件定制的throw()方法 | ||
*/ | ||
throw(statusCode: Code, message?: string | Error, properties?: HttpErrorProperties): never; | ||
throw(statusCode: Code, properties?: HttpErrorProperties): never; | ||
}> { | ||
protected readonly options: WebResponseOptions<Code, Content>; | ||
constructor(options: WebResponseOptions<Code, Content>); | ||
protected openapi(): OpenApiInjector; | ||
@@ -428,6 +464,8 @@ protected getContentType(): string; | ||
/** | ||
* 为openapi生成响应数据文档 | ||
* 响应数据声明。多个状态码时请多次调用函数。 | ||
* - 生成openapi文档 | ||
* - 静态类型约束,以保证运行时和文档一致 | ||
*/ | ||
declare const response: (options: WebResponseOptions) => WebResponseMiddleware; | ||
declare const response: <Code extends HttpStatus, Content extends ValidatorToken>(options: WebResponseOptions<Code, Content>) => WebResponseMiddleware<Code, Content>; | ||
export { type Body, FileValidator, type OpenApiInjector, WebApp, type WebAppOption, WebContext, WebMiddleware, WebMiddlewareChain, type WebMiddlewareToken, WebRequest, WebResponse, WebResponseMiddleware, type WebResponseOptions, body, params, query, response }; | ||
export { type Body, FileValidator, type HttpErrorProperties, type OpenApiInjector, WebApp, type WebAppOption, WebContext, WebMiddleware, WebMiddlewareChain, type WebMiddlewareToken, WebRequest, WebResponse, WebResponseMiddleware, type WebResponseOptions, body, params, query, response }; |
@@ -86,3 +86,5 @@ // src/i18n/locales/zh-cn.ts | ||
return this._body = coBody(this, { | ||
returnRawBody: false | ||
returnRawBody: false, | ||
// @ts-expect-error | ||
onProtoPoisoning: "remove" | ||
}).then((fields) => { | ||
@@ -427,3 +429,7 @@ return this._body = fields; | ||
request.ctx = response2.ctx = this; | ||
this.redirect = response2.redirect.bind(response2); | ||
this.download = response2.download.bind(response2); | ||
} | ||
redirect; | ||
download; | ||
send(statusOrBody, body2) { | ||
@@ -438,3 +444,2 @@ if (typeof statusOrBody === "number") { | ||
} | ||
return this; | ||
} | ||
@@ -678,10 +683,10 @@ throw(arg, ...args) { | ||
methodItem.responses ||= {}; | ||
const { statusCode, schema, headers, example, description = "" } = this.options; | ||
const { statusCode, content, headers, example, description = "" } = this.options; | ||
const resItem = methodItem.responses[statusCode] = { | ||
description | ||
}; | ||
if (schema) { | ||
if (content) { | ||
resItem.content = { | ||
[this.getContentType()]: { | ||
schema: Validator5.toDocument(toValidator(schema)).schema, | ||
schema: Validator5.toDocument(toValidator(content)).schema, | ||
example | ||
@@ -703,5 +708,5 @@ } | ||
getContentType() { | ||
let { contentType: contentType3, schema } = this.options; | ||
let { contentType: contentType3, content } = this.options; | ||
if (!contentType3) { | ||
const validator = toValidator(schema); | ||
const validator = toValidator(content); | ||
const docs = validator["toDocument"](); | ||
@@ -708,0 +713,0 @@ switch (docs.type) { |
{ | ||
"name": "@aomex/web", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "aomex web层应用", | ||
@@ -40,3 +40,3 @@ "type": "module", | ||
"accepts": "^1.3.8", | ||
"co-body": "^6.1.0", | ||
"co-body": "^6.2.0", | ||
"content-disposition": "^0.5.4", | ||
@@ -58,3 +58,3 @@ "content-type": "^1.0.5", | ||
"vary": "^1.1.2", | ||
"@aomex/internal-tools": "^1.0.2" | ||
"@aomex/internal-tools": "^1.0.3" | ||
}, | ||
@@ -72,5 +72,5 @@ "devDependencies": { | ||
"@types/vary": "^1.1.3", | ||
"@aomex/core": "^1.0.2" | ||
"@aomex/core": "^1.0.3" | ||
}, | ||
"scripts": {} | ||
} |
Sorry, the diff of this file is not supported yet
95280
1192
Updated@aomex/internal-tools@^1.0.3
Updatedco-body@^6.2.0