Socket
Socket
Sign inDemoInstall

@aomex/web

Package Overview
Dependencies
Maintainers
1
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aomex/web - npm Package Compare versions

Comparing version 0.0.5 to 0.0.6

28

CHANGELOG.md
# @aomex/web
## 0.0.6
### Patch Changes
- [`d3a2757`](https://github.com/aomex/aomex/commit/d3a2757b38391ad70a206d95eac09520c64e9b85) Thanks [@geekact](https://github.com/geekact)! - fix(web): statusCode 覆盖无效
- [`07c8575`](https://github.com/aomex/aomex/commit/07c857565ede4eca7e88de4e8c5e5f244f9d16cb) Thanks [@geekact](https://github.com/geekact)! - feat(web): 删除 error-pre-respond 事件
- [`e80844a`](https://github.com/aomex/aomex/commit/e80844a6808fd0f3b9d613ec3163b06357316cae) Thanks [@geekact](https://github.com/geekact)! - feat(web): 导出 statuses 库
- [`146b6b5`](https://github.com/aomex/aomex/commit/146b6b5f09d4b9f557c1771686f3585bebf4cfc9) Thanks [@geekact](https://github.com/geekact)! - refactor(helper): 重命名 color 为 chalk
- [`56f65c8`](https://github.com/aomex/aomex/commit/56f65c8509b40679272ed58f63e12d98e1818503) Thanks [@geekact](https://github.com/geekact)! - feat(web): 设置 body 时设置 headers
- [`c6df4de`](https://github.com/aomex/aomex/commit/c6df4de61fc28f452f8a202c9a485e1a061b3eb6) Thanks [@geekact](https://github.com/geekact)! - feat(web): 动态获取 contentType
- [`79e19c1`](https://github.com/aomex/aomex/commit/79e19c1ae2a35b38580a4d2a27b6dde634345126) Thanks [@geekact](https://github.com/geekact)! - fix(web): 仅在 body setter 中可以强制指定 statusCode
- [`9adefaa`](https://github.com/aomex/aomex/commit/9adefaa8baaaafb7be610c7a98920c9830d10a3c) Thanks [@geekact](https://github.com/geekact)! - feat(web): 挂载中间件时检测到链条自动创建分割点
- [`a8bb601`](https://github.com/aomex/aomex/commit/a8bb601acaf1e1d580511ae886a4ae99bf19f699) Thanks [@geekact](https://github.com/geekact)! - feat(web): response 增加 isJSON 方法
- [`902597b`](https://github.com/aomex/aomex/commit/902597b2f98fda7e63f7419a5ef62ab2acb7c863) Thanks [@geekact](https://github.com/geekact)! - feat(web): 定制异常的响应格式使用事件触发
- Updated dependencies [[`146b6b5`](https://github.com/aomex/aomex/commit/146b6b5f09d4b9f557c1771686f3585bebf4cfc9), [`e8dee7c`](https://github.com/aomex/aomex/commit/e8dee7c3f064587cd2afb9cb95ab3341f63ccd27)]:
- @aomex/helper@0.0.3
- @aomex/core@0.0.5
## 0.0.5

@@ -4,0 +32,0 @@

126

dist/index.d.ts
import { Chain, PureChain, PureMiddlewareToken, Next, Middleware, OpenAPI, Validator, TransformedValidator, ValidateResult, ValidatorOptions } from '@aomex/core';
import { NonReadonly } from '@aomex/helper';
import { IncomingMessage, ServerResponse, Server, RequestListener } from 'node:http';
import { Server, RequestListener, ServerResponse, IncomingMessage } from 'node:http';
import EventEmitter from 'node:events';

@@ -8,6 +8,7 @@ import { HttpError } from 'http-errors';

import { IParseOptions } from 'qs';
import { Accepts } from 'accepts';
import { Stream } from 'node:stream';
import contentDisposition from 'content-disposition';
import { Accepts } from 'accepts';
import { File } from 'formidable';
export { default as statuses } from 'statuses';

@@ -27,2 +28,21 @@ declare module '@aomex/core' {

interface WebAppOption {
debug?: boolean;
globalChain?: WebChain;
queryParser?: IParseOptions;
}
declare class WebApp extends EventEmitter {
readonly options: WebAppOption;
readonly chainPoints: string[];
protected readonly middlewareList: WebMiddlewareToken[];
constructor(options?: WebAppOption);
get debug(): boolean;
listen: Server['listen'];
callback(): RequestListener<any, any>;
log(err: HttpError): void;
on(eventName: 'error', listener: (err: HttpError, ctx: WebContext) => void): this;
on(eventName: string | symbol, listener: (...args: any[]) => void): this;
mount(middleware: WebMiddlewareToken): void;
}
type UpperHeaderKeys = UpperArrayHeaderKeys | UpperStringHeaderKeys;

@@ -35,30 +55,2 @@ type UpperArrayHeaderKeys = 'Set-Cookie';

declare class WebRequest extends IncomingMessage {
app: WebApp;
res: WebResponse;
ctx: WebContext;
readonly method: string;
readonly url: string;
params: Record<string, unknown>;
protected _query?: any;
protected _body?: any;
protected _accept?: Accepts;
get path(): string;
get querystring(): string;
get query(): Record<string, unknown>;
get body(): Promise<unknown>;
get contentType(): string;
findContentType(type: string, ...types: string[]): string | null;
get accept(): Accepts;
get ip(): string;
get fresh(): boolean;
}
declare module 'node:http' {
type ExternalHeaders = {
[K in LowerExternalStringHeaderKeys]?: string;
};
interface IncomingHttpHeaders extends ExternalHeaders {
}
}
type Body = string | object | Stream | Buffer | null;

@@ -68,8 +60,9 @@ declare class WebResponse<Request extends WebRequest = WebRequest> extends ServerResponse<Request> {

ctx: WebContext;
protected _body: Body;
protected _explicitBody: boolean;
protected _explicitStatus: boolean;
private _body;
private _explicitBody;
private _explicitStatus;
private _statusCode;
private _determineHeaders;
private _determineNullBody;
constructor(req: Request);
/** @ts-expect-error */
set statusCode(code: number);
readonly setHeader: {

@@ -103,2 +96,4 @@ <T extends WebResponse>(name: UpperStringHeaderKeys, value: number | string): T;

}): void;
protected removeHeaders(...headers: Array<UpperStringHeaderKeys | UpperArrayHeaderKeys>): void;
protected removeHeaders(...headers: Array<string>): void;
redirect(url: string): void;

@@ -113,3 +108,7 @@ redirect(statusCode: 300 | 301 | 302 | 303 | 305 | 307 | 308, url: string): void;

set body(val: Body);
flush(): void;
/**
* 判断body是否为JSON格式
*/
isJSON(body: Body): body is object;
flush(): any;
onError(error?: Error | HttpError | null): void;

@@ -123,24 +122,41 @@ findContentType(type: string, ...types: string[]): string | null;

varyAppend(header: string, field: string | string[]): string;
protected setStatus(code: number): void;
/**
* 根据header设置头部信息
*/
protected determineHeaders(): void;
/**
* 重新整理body=null和状态的关系
* - status-code
* - content-type
*/
protected determineNullBody(): void;
}
interface WebAppOption {
debug?: boolean;
globalChain?: WebChain;
queryParser?: IParseOptions;
errorFormatter?: (msg: string, statusCode: number, helper: {
err: HttpError;
ctx: WebContext;
}) => Body;
declare class WebRequest extends IncomingMessage {
app: WebApp;
res: WebResponse;
ctx: WebContext;
readonly method: string;
readonly url: string;
params: Record<string, unknown>;
protected _query?: any;
protected _body?: any;
protected _accept?: Accepts;
get path(): string;
get querystring(): string;
get query(): Record<string, unknown>;
get body(): Promise<unknown>;
get contentType(): string;
findContentType(type: string, ...types: string[]): string | null;
get accept(): Accepts;
get ip(): string;
get fresh(): boolean;
}
declare class WebApp extends EventEmitter {
readonly options: WebAppOption;
readonly globalChainPoint?: string;
protected readonly middlewareList: WebMiddlewareToken[];
constructor(options?: WebAppOption);
get debug(): boolean;
listen: Server['listen'];
callback(): RequestListener<any, any>;
log(err: HttpError): void;
on(eventName: 'error', listener: (err: HttpError, ctx: WebContext) => void): this;
mount(middleware: WebMiddlewareToken): void;
declare module 'node:http' {
type ExternalHeaders = {
[K in LowerExternalStringHeaderKeys]?: string;
};
interface IncomingHttpHeaders extends ExternalHeaders {
}
}

@@ -147,0 +163,0 @@

@@ -136,3 +136,2 @@ // src/override/middleware.ts

// src/app/context.ts
import assert2 from "node:assert";
import createHttpError from "http-errors";

@@ -150,6 +149,2 @@ var WebContext = class {

if (typeof statusOrBody === "number") {
assert2(
statusOrBody >= 100 && statusOrBody <= 999,
`invalid status code: ${statusOrBody}`
);
this.response.statusCode = statusOrBody;

@@ -174,3 +169,3 @@ } else {

import { Chain as Chain2, compose as compose2 } from "@aomex/core";
import { color } from "@aomex/helper";
import { chalk } from "@aomex/helper";

@@ -266,2 +261,3 @@ // src/app/request.ts

import stream, { Stream } from "node:stream";
import assert2 from "node:assert";
import statuses from "statuses";

@@ -300,11 +296,17 @@ import escapeHtml from "escape-html";

_explicitStatus = false;
_statusCode;
_determineHeaders = false;
_determineNullBody = false;
constructor(req) {
super(req);
super.statusCode = 404;
this._statusCode = 404;
Object.defineProperty(this, "statusCode", {
get: () => {
return this._statusCode;
},
set: (code) => {
this.setStatus(code);
}
});
}
/** @ts-expect-error */
set statusCode(code) {
this._explicitStatus = true;
super.statusCode = code;
}
/**

@@ -318,2 +320,5 @@ * 批量设置头部数据

}
removeHeaders(...headers) {
headers.forEach(this.removeHeader.bind(this));
}
redirect(status, url) {

@@ -341,17 +346,7 @@ url = typeof url === "string" ? url : status.toString();

get contentLength() {
const body2 = this._body;
if (statuses.empty[this.statusCode])
return 0;
if (body2 === null && !this.findContentType("json"))
return 0;
if (body2 instanceof Stream)
return -1;
if (typeof body2 === "string")
return Buffer.byteLength(body2);
if (Buffer.isBuffer(body2))
return body2.length;
return Buffer.byteLength(JSON.stringify(body2));
const length = this.getHeader("Content-Length");
return length ? Number(length) : 0;
}
set contentLength(length) {
if (length >= 0 && !this.headersSent && !this.hasHeader("Transfer-Encoding")) {
if (!this.hasHeader("Transfer-Encoding")) {
this.setHeader("Content-Length", length);

@@ -368,9 +363,6 @@ }

if (mimeType === false) {
throw new Error(
`Fail to parse content type from literal "${typeOrFilenameOrExt}"`
);
throw new Error(`\u65E0\u6CD5\u6839\u636E\u53C2\u6570"${typeOrFilenameOrExt}"\u8BBE\u7F6EContent-Type`);
}
if (!this.headersSent) {
this.setHeader("content-type", mimeType);
}
this.setHeader("Content-Type", mimeType);
this.determineNullBody();
}

@@ -386,58 +378,42 @@ get body() {

}
this.determineHeaders();
}
/**
* 判断body是否为JSON格式
*/
isJSON(body2) {
return !(!body2 || typeof body2 === "string" || body2 instanceof Stream || Buffer.isBuffer(body2));
}
flush() {
if (!this.writable || this.headersSent)
return;
const { body: body2, req } = this;
const missContentType = !this.hasHeader("Content-Type");
const ok = (chunk2) => {
if (req.method === "HEAD") {
this.end();
this.determineHeaders();
let output = this.body;
if (statuses.empty[this.statusCode])
return this.end();
if (output === null) {
if (this._explicitBody) {
this._body = this.findContentType("json") ? String(null) : "";
} else {
this.end(chunk2);
this._body = String(this.statusMessage || this.statusCode);
}
};
if (!this._explicitStatus) {
this.statusCode = 200;
this.determineHeaders();
output = this.body;
}
if (statuses.empty[this.statusCode]) {
this.removeHeader("Content-Type");
this.removeHeader("Content-Length");
this.removeHeader("Transfer-Encoding");
return ok();
}
if (body2 === null && (missContentType || !this.findContentType("json"))) {
missContentType && (this.contentType = "text");
if (this._explicitBody) {
this.contentLength = 0;
return ok();
}
const msg = req.httpVersionMajor >= 2 ? String(this.statusCode) : this.statusMessage || String(this.statusCode);
this.contentLength = Buffer.byteLength(msg);
return ok(msg);
}
if (Buffer.isBuffer(body2)) {
missContentType && (this.contentType = "bin");
this.contentLength = body2.length;
return ok(body2);
}
if (typeof body2 === "string") {
missContentType && (this.contentType = /^\s*</.test(body2) ? "html" : "text");
this.contentLength = Buffer.byteLength(body2);
return ok(body2);
}
if (body2 instanceof Stream) {
if (req.method === "HEAD")
return;
missContentType && (this.contentType = "bin");
if (this.req.method === "HEAD")
return this.end();
if (typeof output === "string")
return this.end(output);
if (Buffer.isBuffer(output))
return this.end(output);
if (output instanceof Stream) {
stream.finished(this, () => {
destroy(body2);
destroy(output);
});
body2.once("error", this.onError).pipe(this);
return;
if (!output.listenerCount("error")) {
output.once("error", this.onError);
}
return output.pipe(this);
}
const chunk = JSON.stringify(body2);
missContentType && (this.contentType = "json");
this.contentLength = Buffer.byteLength(chunk);
return ok(chunk);
return this.end(JSON.stringify(output));
}

@@ -447,9 +423,4 @@ onError(error) {

return;
let err;
if (!isHttpError(error)) {
err = createHttpError2(error);
} else {
err = error;
}
this.getHeaderNames().forEach(this.removeHeader.bind(this));
const err = isHttpError(error) ? error : createHttpError2(error);
this.removeHeaders(...this.getHeaderNames());
err.headers && this.setHeaders(err.headers);

@@ -464,6 +435,4 @@ const code = err.status || err.statusCode;

}
this.body = err.expose ? err.message : statuses.message[this.statusCode];
this.app.emit("error", err, this.ctx);
const msg = err.expose ? err.message : statuses.message[this.statusCode];
const formatter = this.app.options.errorFormatter;
this.body = formatter ? formatter(msg, this.statusCode, { err, ctx: this.ctx }) : msg;
this.flush();

@@ -481,2 +450,68 @@ }

}
setStatus(code) {
assert2(code >= 100 && code <= 999, `\u65E0\u6548\u7684\u72B6\u6001\u7801\uFF1A${code}`);
this._statusCode = code;
this._explicitStatus = true;
if (this.req.httpVersionMajor < 2) {
this.statusMessage = String(statuses.message[code]);
}
if (statuses.empty[code]) {
this.body = null;
} else {
this.determineNullBody();
}
}
/**
* 根据header设置头部信息
*/
determineHeaders() {
if (this._determineHeaders)
return;
this._determineHeaders = true;
const { body: body2 } = this;
const missType = !this.hasHeader("Content-Type");
if (body2 === null) {
this.determineNullBody();
} else if (typeof body2 === "string") {
this.contentLength = Buffer.byteLength(body2);
if (missType) {
this.contentType = /^\s*</.test(body2) ? "html" : "text";
}
} else if (Buffer.isBuffer(body2)) {
this.contentLength = body2.length;
if (missType) {
this.contentType = "bin";
}
} else if (body2 instanceof Stream) {
if (missType) {
this.contentType = "bin";
}
} else {
this.contentType = "json";
this.contentLength = Buffer.byteLength(JSON.stringify(body2));
}
this._determineHeaders = false;
}
/**
* 重新整理body=null和状态的关系
* - status-code
* - content-type
*/
determineNullBody() {
if (this._determineNullBody || this.body !== null)
return;
this._determineNullBody = true;
if (statuses.empty[this.statusCode]) {
this.removeHeaders("Content-Type", "Content-Length", "Transfer-Encoding");
} else if (this.contentType === "application/json") {
this.contentLength = Buffer.byteLength(String(null));
} else if (this._explicitBody) {
this.contentLength = 0;
if (!this.hasHeader("Content-Type")) {
this.contentType = "text";
}
} else {
}
this._determineNullBody = false;
}
};

@@ -489,11 +524,5 @@

this.options = options;
if (options.globalChain) {
this.globalChainPoint = Chain2.createPoint(options.globalChain);
this.middlewareList = [options.globalChain];
} else {
this.middlewareList = [];
}
}
globalChainPoint;
middlewareList;
chainPoints = [];
middlewareList = [];
get debug() {

@@ -526,3 +555,3 @@ return this.options.debug || false;

console.error(
["", color.bgRed(msgs.shift()), msgs.join(EOL), ""].join(EOL)
["", chalk.bgRed(msgs.shift()), msgs.join(EOL), ""].join(EOL)
);

@@ -534,2 +563,5 @@ }

mount(middleware2) {
if (middleware2 instanceof Chain2) {
this.chainPoints.push(Chain2.createPoint(middleware2));
}
this.middlewareList.push(middleware2);

@@ -638,2 +670,3 @@ }

import { HttpError } from "http-errors";
import { default as default2 } from "statuses";
export {

@@ -655,4 +688,5 @@ FileValidator,

query,
skip
skip,
default2 as statuses
};
//# sourceMappingURL=index.js.map
{
"name": "@aomex/web",
"version": "0.0.5",
"version": "0.0.6",
"description": "",

@@ -29,6 +29,6 @@ "type": "module",

"peerDependencies": {
"@aomex/core": "^0.0.4"
"@aomex/core": "^0.0.5"
},
"dependencies": {
"@aomex/helper": "^0.0.2",
"@aomex/helper": "^0.0.3",
"@types/accepts": "^1.3.5",

@@ -39,2 +39,3 @@ "@types/content-disposition": "^0.5.5",

"@types/qs": "^6.9.7",
"@types/statuses": "^2.0.1",
"accepts": "^1.3.8",

@@ -60,3 +61,3 @@ "co-body": "^6.1.0",

"devDependencies": {
"@aomex/core": "^0.0.4",
"@aomex/core": "^0.0.5",
"@types/co-body": "^6.1.0",

@@ -71,3 +72,2 @@ "@types/content-type": "^1.1.5",

"@types/request-ip": "^0.0.37",
"@types/statuses": "^2.0.1",
"@types/type-is": "^1.6.3",

@@ -74,0 +74,0 @@ "@types/vary": "^1.1.0"

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc