@aomex/web
Advanced tools
Comparing version 0.0.7 to 0.0.8
# @aomex/web | ||
## 0.0.8 | ||
### Patch Changes | ||
- [`dcf2f4b`](https://github.com/aomex/aomex/commit/dcf2f4b6a13228d4731e4969e6abff9bef8ef0e2) Thanks [@geekact](https://github.com/geekact)! - fix(web): hasHeader and removeHeader cannot tip keyword Set-Cookie | ||
- [`d788ce7`](https://github.com/aomex/aomex/commit/d788ce731af885eae3819683813b2a9502742cea) Thanks [@geekact](https://github.com/geekact)! - refactor(web): rename option queryParser to query | ||
- [`c6fe6cb`](https://github.com/aomex/aomex/commit/c6fe6cb2f21acf74bc06db1509deff4aa35c48b3) Thanks [@geekact](https://github.com/geekact)! - feat(web): export response middleware | ||
- [`a2727fb`](https://github.com/aomex/aomex/commit/a2727fb7619341dc3b23736e5dc11cee7d65e0bc) Thanks [@geekact](https://github.com/geekact)! - feat(web): add cookie support | ||
- [`4253004`](https://github.com/aomex/aomex/commit/42530043854956a42d16be090b89fbac70e2fa17) Thanks [@geekact](https://github.com/geekact)! - fix(web): response returning invalid content-type for openapi | ||
- [`fc7008e`](https://github.com/aomex/aomex/commit/fc7008e889a55e6a0a268bb77cab5be0f0bd9d30) Thanks [@geekact](https://github.com/geekact)! - refactor(web,web-router): move method enum from web-router to web | ||
- [`d80df1a`](https://github.com/aomex/aomex/commit/d80df1a07eb92214a9c3c7fa15c629ea1ee88c43) Thanks [@geekact](https://github.com/geekact)! - feat(web): request add protocol and secure getter | ||
- Updated dependencies []: | ||
- @aomex/core@0.0.7 | ||
## 0.0.7 | ||
@@ -4,0 +25,0 @@ |
@@ -8,2 +8,3 @@ import { Chain, PureChain, PureMiddlewareToken, Next, Middleware, OpenAPI, Validator, TransformedValidator, ValidateResult, ValidatorOptions } from '@aomex/core'; | ||
import { IParseOptions } from 'qs'; | ||
import { CookieParseOptions, CookieSerializeOptions } from 'cookie'; | ||
import { Accepts } from 'accepts'; | ||
@@ -31,3 +32,22 @@ import { Stream } from 'node:stream'; | ||
debug?: boolean; | ||
queryParser?: IParseOptions; | ||
/** | ||
* Set default options for `qs` when parsing querystring from request | ||
* @see WebRequest.query | ||
*/ | ||
query?: IParseOptions; | ||
/** | ||
* Set default/common options for cookie | ||
*/ | ||
cookie?: { | ||
/** | ||
* Default option for request.cookie | ||
* @see WebRequest.cookie | ||
*/ | ||
get?: CookieParseOptions; | ||
/** | ||
* Default option for response.cookie | ||
* @see WebResponse.cookie | ||
*/ | ||
set?: CookieSerializeOptions; | ||
}; | ||
} | ||
@@ -56,2 +76,6 @@ declare class WebApp extends EventEmitter { | ||
type Body = string | object | Stream | Buffer | null; | ||
interface CookieCache { | ||
set(name: string, value: string, options?: CookieSerializeOptions): void; | ||
remove(name: string, options?: Omit<CookieSerializeOptions, 'maxAge' | 'expires'>): void; | ||
} | ||
declare class WebResponse<Request extends WebRequest = WebRequest> extends ServerResponse<Request> { | ||
@@ -66,2 +90,3 @@ app: WebApp; | ||
private _determineNullBody; | ||
private _cookie; | ||
constructor(req: Request); | ||
@@ -80,2 +105,3 @@ readonly setHeader: { | ||
(name: UpperStringHeaderKeys): boolean; | ||
(name: UpperArrayHeaderKeys): boolean; | ||
(name: string): boolean; | ||
@@ -85,2 +111,3 @@ }; | ||
(name: UpperStringHeaderKeys): void; | ||
(name: UpperArrayHeaderKeys): void; | ||
(name: string): void; | ||
@@ -116,2 +143,3 @@ }; | ||
varyAppend(header: string, field: string | string[]): string; | ||
get cookie(): CookieCache; | ||
protected setStatus(code: number): void; | ||
@@ -132,2 +160,5 @@ protected determineHeaders(): void; | ||
protected _accept?: Accepts; | ||
protected _cookie?: { | ||
readonly [key: string]: string | undefined; | ||
}; | ||
get path(): string; | ||
@@ -141,3 +172,11 @@ get querystring(): string; | ||
get ip(): string; | ||
get protocol(): string; | ||
get secure(): boolean; | ||
get fresh(): boolean; | ||
/** | ||
* A short hand for request header `Cookie` | ||
*/ | ||
get cookie(): { | ||
readonly [key: string]: string | undefined; | ||
}; | ||
} | ||
@@ -194,2 +233,14 @@ declare module 'node:http' { | ||
declare const getMimeType: (filenameOrExt: string) => string | false; | ||
declare enum METHOD { | ||
GET = "GET", | ||
POST = "POST", | ||
PUT = "PUT", | ||
PATCH = "PATCH", | ||
DELETE = "DELETE", | ||
OPTIONS = "OPTIONS", | ||
HEAD = "HEAD" | ||
} | ||
declare module '@aomex/core' { | ||
@@ -203,2 +254,3 @@ interface MiddlewarePlatform { | ||
pathItem?: OpenAPI.PathItemObject; | ||
methodName?: METHOD; | ||
methodItem?: OpenAPI.OperationObject; | ||
@@ -250,4 +302,2 @@ } | ||
declare const getMimeType: (filenameOrExt: string) => string | false; | ||
declare class WebBodyMiddleware<Props extends { | ||
@@ -343,2 +393,44 @@ [key: string]: Validator; | ||
export { Body, FileValidator, FileValidatorOptions, FormidableFile, WebApp, WebAppOption, WebBodyMiddleware, WebChain, WebContext, WebMiddleware, WebMiddlewareSkipOptions, WebMiddlewareToDocument, WebMiddlewareToken, WebParamMiddleware, WebQueryMiddleware, WebRequest, WebResponse, body, getMimeType, params, query, skip }; | ||
interface WebResponseOptions extends Pick<OpenAPI.MediaTypeObject, 'example'> { | ||
/** | ||
* Examples: | ||
* - 200 | ||
* - 201 | ||
* - 2xx | ||
* - 3xx | ||
* - default (handle unknown response) | ||
*/ | ||
statusCode: number | string; | ||
/** | ||
* - json | ||
* - application/json | ||
* - text | ||
* - binary | ||
* - html | ||
* - stream | ||
* - \*\/\* (any type) | ||
*/ | ||
contentType?: string; | ||
/** | ||
* Final data schema | ||
*/ | ||
schema: Validator | { | ||
[key: string]: Validator; | ||
}; | ||
headers?: { | ||
[key: string]: Validator; | ||
}; | ||
description?: string; | ||
} | ||
/** | ||
* web响应中间件,帮助openapi生成最合适的文档 | ||
*/ | ||
declare const response: (options: WebResponseOptions) => WebResponseMiddleware; | ||
declare class WebResponseMiddleware extends WebMiddleware<object> { | ||
protected readonly options: WebResponseOptions; | ||
constructor(options: WebResponseOptions); | ||
toDocument({ methodItem }: WebMiddlewareToDocument): void; | ||
protected fixContentType(contentType: string): string; | ||
} | ||
export { Body, FileValidator, FileValidatorOptions, FormidableFile, METHOD, WebApp, WebAppOption, WebBodyMiddleware, WebChain, WebContext, WebMiddleware, WebMiddlewareSkipOptions, WebMiddlewareToDocument, WebMiddlewareToken, WebParamMiddleware, WebQueryMiddleware, WebRequest, WebResponse, WebResponseMiddleware, WebResponseOptions, body, getMimeType, params, query, response, skip }; |
// src/override/middleware.ts | ||
import assert from "node:assert"; | ||
import { Middleware as Middleware2 } from "@aomex/core"; | ||
@@ -55,3 +54,3 @@ | ||
toDocument(options) { | ||
assert(options); | ||
options; | ||
} | ||
@@ -131,9 +130,9 @@ }; | ||
var WebContext = class { | ||
constructor(app, request, response) { | ||
constructor(app, request, response2) { | ||
this.app = app; | ||
this.request = request; | ||
this.response = response; | ||
request.app = response.app = app; | ||
request.res = response; | ||
request.ctx = response.ctx = this; | ||
this.response = response2; | ||
request.app = response2.app = app; | ||
request.res = response2; | ||
request.ctx = response2.ctx = this; | ||
} | ||
@@ -167,2 +166,3 @@ send(statusOrBody, body2) { | ||
import qs from "qs"; | ||
import cookie from "cookie"; | ||
import coBody from "co-body"; | ||
@@ -183,2 +183,3 @@ import formidable from "formidable"; | ||
_accept; | ||
_cookie; | ||
get path() { | ||
@@ -193,3 +194,3 @@ return parseurl(this).pathname; | ||
comma: true, | ||
...this.app.options.queryParser | ||
...this.app.options.query | ||
}); | ||
@@ -239,2 +240,11 @@ } | ||
} | ||
get protocol() { | ||
if (this.socket.encrypted) | ||
return "https"; | ||
const proto = this.headers["x-forwarded-proto"]; | ||
return proto && proto.split(/\s*,\s*/, 1)[0] || "http"; | ||
} | ||
get secure() { | ||
return this.protocol === "https"; | ||
} | ||
get fresh() { | ||
@@ -251,2 +261,11 @@ const method = this.method; | ||
} | ||
/** | ||
* A short hand for request header `Cookie` | ||
*/ | ||
get cookie() { | ||
return this._cookie ||= cookie.parse( | ||
this.headers["cookie"] || "", | ||
this.app.options.cookie?.get | ||
); | ||
} | ||
}; | ||
@@ -257,3 +276,3 @@ | ||
import stream, { Stream } from "node:stream"; | ||
import assert2 from "node:assert"; | ||
import assert from "node:assert"; | ||
import statuses from "statuses"; | ||
@@ -283,5 +302,18 @@ import escapeHtml from "escape-html"; | ||
// src/util/method.ts | ||
var METHOD = /* @__PURE__ */ ((METHOD2) => { | ||
METHOD2["GET"] = "GET"; | ||
METHOD2["POST"] = "POST"; | ||
METHOD2["PUT"] = "PUT"; | ||
METHOD2["PATCH"] = "PATCH"; | ||
METHOD2["DELETE"] = "DELETE"; | ||
METHOD2["OPTIONS"] = "OPTIONS"; | ||
METHOD2["HEAD"] = "HEAD"; | ||
return METHOD2; | ||
})(METHOD || {}); | ||
// src/app/response.ts | ||
import typeIs2 from "type-is"; | ||
import vary from "vary"; | ||
import cookie2 from "cookie"; | ||
var WebResponse = class extends ServerResponse { | ||
@@ -296,2 +328,3 @@ app; | ||
_determineNullBody = false; | ||
_cookie = null; | ||
constructor(req) { | ||
@@ -435,4 +468,36 @@ super(req); | ||
} | ||
get cookie() { | ||
if (this._cookie) | ||
return this._cookie; | ||
const defaultSerializeOptions = { | ||
path: "/", | ||
sameSite: false, | ||
secure: this.req.secure, | ||
httpOnly: true, | ||
...this.app.options.cookie?.set | ||
}; | ||
this._cookie = { | ||
set: (name, value, options) => { | ||
const setCookie = this.getHeader("Set-Cookie") || []; | ||
setCookie.push( | ||
cookie2.serialize(name, value, { | ||
...defaultSerializeOptions, | ||
...options | ||
}) | ||
); | ||
this.setHeader("Set-Cookie", setCookie); | ||
}, | ||
remove: (name, options) => { | ||
this.cookie.set(name, "", { | ||
...defaultSerializeOptions, | ||
...options, | ||
maxAge: void 0, | ||
expires: /* @__PURE__ */ new Date(0) | ||
}); | ||
} | ||
}; | ||
return this._cookie; | ||
} | ||
setStatus(code) { | ||
assert2(code >= 100 && code <= 999, `\u65E0\u6548\u7684\u72B6\u6001\u7801\uFF1A${code}`); | ||
assert(code >= 100 && code <= 999, `\u65E0\u6548\u7684\u72B6\u6001\u7801\uFF1A${code}`); | ||
this._statusCode = code; | ||
@@ -646,2 +711,46 @@ this._explicitStatus = true; | ||
// src/middleware/response.ts | ||
import { rule as rule2, Validator as Validator5 } from "@aomex/core"; | ||
var response = (options) => new WebResponseMiddleware(options); | ||
var WebResponseMiddleware = class extends WebMiddleware { | ||
constructor(options) { | ||
super((_, next) => next()); | ||
this.options = options; | ||
} | ||
toDocument({ methodItem }) { | ||
if (!methodItem) | ||
return; | ||
methodItem.responses ||= {}; | ||
const { | ||
statusCode, | ||
contentType: contentType2 = "*/*", | ||
schema, | ||
headers = {}, | ||
example, | ||
description = "" | ||
} = this.options; | ||
methodItem.responses[statusCode] = { | ||
description, | ||
content: { | ||
[this.fixContentType(contentType2)]: { | ||
schema: Validator5.toDocument( | ||
schema instanceof Validator5 ? schema : rule2.object(schema) | ||
).schema, | ||
example | ||
} | ||
}, | ||
headers: Object.fromEntries( | ||
Object.entries(headers).map(([key, header]) => [ | ||
key, | ||
Validator5.toDocument(header) | ||
]) | ||
) | ||
}; | ||
} | ||
fixContentType(contentType2) { | ||
const type = contentType2.includes("*") ? contentType2 : getMimeType(contentType2) || "*/*"; | ||
return type.split(";", 1)[0]; | ||
} | ||
}; | ||
// src/index.ts | ||
@@ -653,2 +762,3 @@ import { HttpError } from "http-errors"; | ||
HttpError, | ||
METHOD, | ||
WebApp, | ||
@@ -663,2 +773,3 @@ WebBodyMiddleware, | ||
WebResponse, | ||
WebResponseMiddleware, | ||
body, | ||
@@ -668,2 +779,3 @@ getMimeType, | ||
query, | ||
response, | ||
skip, | ||
@@ -670,0 +782,0 @@ default2 as statuses |
{ | ||
"name": "@aomex/web", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "", | ||
@@ -29,3 +29,3 @@ "type": "module", | ||
"peerDependencies": { | ||
"@aomex/core": "^0.0.6" | ||
"@aomex/core": "^0.0.7" | ||
}, | ||
@@ -36,2 +36,3 @@ "dependencies": { | ||
"@types/content-disposition": "^0.5.5", | ||
"@types/cookie": "^0.5.1", | ||
"@types/formidable": "^2.0.5", | ||
@@ -45,2 +46,3 @@ "@types/http-errors": "^2.0.1", | ||
"content-type": "^1.0.5", | ||
"cookie": "^0.5.0", | ||
"destroy": "^1.2.0", | ||
@@ -62,3 +64,3 @@ "encodeurl": "^1.0.2", | ||
"devDependencies": { | ||
"@aomex/core": "^0.0.6", | ||
"@aomex/core": "^0.0.7", | ||
"@types/co-body": "^6.1.0", | ||
@@ -65,0 +67,0 @@ "@types/content-type": "^1.1.5", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
91967
1163
28
+ Added@types/cookie@^0.5.1
+ Addedcookie@^0.5.0
+ Added@aomex/cache@0.0.4(transitive)
+ Added@aomex/core@0.0.7(transitive)
+ Added@aomex/validator@0.0.6(transitive)
+ Added@types/cookie@0.5.4(transitive)
+ Addedcookie@0.5.0(transitive)
- Removed@aomex/cache@0.0.3(transitive)
- Removed@aomex/core@0.0.6(transitive)
- Removed@aomex/validator@0.0.5(transitive)