@eggjs/koa 3.0.0 → 3.1.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -1,11 +1,14 @@
1
- export type CustomError = Error & {
2
- headers?: Record<string, string>;
3
- status?: number;
4
- statusCode?: number;
5
- code?: string;
6
- expose?: boolean;
7
- headerSent?: boolean;
1
+ //#region src/types.d.ts
2
+ type CustomError = Error & {
3
+ headers?: Record<string, string>;
4
+ status?: number;
5
+ statusCode?: number;
6
+ code?: string;
7
+ expose?: boolean;
8
+ headerSent?: boolean;
8
9
  };
9
- export interface AnyProto {
10
- [key: string | symbol]: any;
10
+ interface AnyProto {
11
+ [key: string | symbol]: any;
11
12
  }
13
+ //#endregion
14
+ export { AnyProto, CustomError };
package/package.json CHANGED
@@ -1,37 +1,30 @@
1
1
  {
2
2
  "name": "@eggjs/koa",
3
- "version": "3.0.0",
3
+ "version": "3.1.0-beta.10",
4
4
  "engines": {
5
- "node": ">= 22.17.1"
5
+ "node": ">= 20.19.0"
6
6
  },
7
7
  "publishConfig": {
8
- "access": "public",
9
- "tag": "alpha"
8
+ "access": "public"
10
9
  },
11
- "description": "Koa web app framework for https://eggjs.org",
12
- "scripts": {
13
- "pretest": "npm run lint -- --fix",
14
- "test": "node --test --test-force-exit --test-update-snapshots --experimental-strip-types",
15
- "preci": "npm run lint",
16
- "ci": "c8 -r html -r lcov -r text npm test",
17
- "postci": "npm run prepublishOnly",
18
- "lint": "oxlint",
19
- "prepublishOnly": "npm run clean && npm run build",
20
- "build": "tsc --build",
21
- "clean": "tsc --build --clean",
22
- "prepare": "husky"
23
- },
24
- "lint-staged": {
25
- "*": "prettier --write --ignore-unknown --cache",
26
- "*.{ts,js,json,md,yml}": [
27
- "prettier --ignore-unknown --write",
28
- "oxlint --fix"
29
- ]
10
+ "type": "module",
11
+ "exports": {
12
+ ".": "./dist/index.js",
13
+ "./package.json": "./package.json"
30
14
  },
15
+ "types": "./dist/index.d.ts",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "main": "./dist/index.js",
20
+ "module": "./dist/index.js",
21
+ "description": "Koa web app framework for https://eggjs.org",
31
22
  "repository": {
32
23
  "type": "git",
33
- "url": "git@github.com:eggjs/koa.git"
24
+ "url": "git://github.com/eggjs/egg.git",
25
+ "directory": "packages/koa"
34
26
  },
27
+ "homepage": "https://github.com/eggjs/egg/tree/next/packages/koa",
35
28
  "keywords": [
36
29
  "web",
37
30
  "app",
@@ -50,21 +43,20 @@
50
43
  "content-type": "^1.0.5",
51
44
  "cookies": "^0.9.1",
52
45
  "destroy": "^1.0.4",
53
- "encodeurl": "^1.0.2",
46
+ "encodeurl": "^2.0.0",
54
47
  "escape-html": "^1.0.3",
55
48
  "fresh": "~0.5.2",
56
- "gals": "^1.0.1",
49
+ "gals": "1",
57
50
  "http-errors": "^2.0.0",
58
- "is-type-of": "^2.1.0",
51
+ "is-type-of": "^2.2.0",
59
52
  "koa-compose": "^4.1.0",
60
53
  "on-finished": "^2.4.1",
61
54
  "parseurl": "^1.3.3",
62
55
  "statuses": "^2.0.1",
63
- "type-is": "^1.6.18",
56
+ "type-is": "^2.0.0",
64
57
  "vary": "^1.1.2"
65
58
  },
66
59
  "devDependencies": {
67
- "@eggjs/tsconfig": "^3.0.0",
68
60
  "@types/accepts": "^1.3.7",
69
61
  "@types/content-type": "^1.1.8",
70
62
  "@types/cookies": "^0.9.0",
@@ -74,27 +66,21 @@
74
66
  "@types/fresh": "^0.5.2",
75
67
  "@types/http-errors": "^2.0.4",
76
68
  "@types/koa-compose": "^3.2.8",
77
- "@types/node": "24",
69
+ "@types/node": "24.5.2",
78
70
  "@types/on-finished": "^2.3.4",
79
71
  "@types/parseurl": "^1.3.3",
80
72
  "@types/statuses": "^2.0.5",
81
- "@types/supertest": "^6.0.2",
82
73
  "@types/type-is": "^1.6.6",
83
74
  "@types/vary": "^1.1.3",
84
- "c8": "^10.1.3",
85
- "husky": "9",
86
- "lint-staged": "15",
87
- "mm": "^4.0.1",
88
- "oxlint": "^1.9.0",
89
- "prettier": "3",
90
- "supertest": "^3.1.0",
91
- "typescript": "^5.8.3"
75
+ "mm": "^4.0.2",
76
+ "tsdown": "^0.15.4",
77
+ "typescript": "5.9.2",
78
+ "@eggjs/supertest": "8.3.0-beta.10"
92
79
  },
93
- "type": "module",
94
- "exports": "./dist/index.js",
95
- "types": "./dist/index.d.ts",
96
- "files": [
97
- "dist",
98
- "src"
99
- ]
100
- }
80
+ "scripts": {
81
+ "build": "tsdown",
82
+ "typecheck": "tsc --noEmit",
83
+ "lint": "oxlint --type-aware",
84
+ "test": "vitest run"
85
+ }
86
+ }
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
@@ -1,322 +0,0 @@
1
- import util, { debuglog } from 'node:util';
2
- import Emitter from 'node:events';
3
- import Stream from 'node:stream';
4
- import type { AsyncLocalStorage } from 'node:async_hooks';
5
- import http, { type IncomingMessage, type ServerResponse } from 'node:http';
6
-
7
- import { getAsyncLocalStorage } from 'gals';
8
- import { isGeneratorFunction } from 'is-type-of';
9
- import onFinished from 'on-finished';
10
- import statuses from 'statuses';
11
- import compose from 'koa-compose';
12
-
13
- import { HttpError } from 'http-errors';
14
- import { Context } from './context.ts';
15
- import { Request } from './request.ts';
16
- import { Response } from './response.ts';
17
- import type { CustomError, AnyProto } from './types.ts';
18
-
19
- const debug = debuglog('@eggjs/koa/application');
20
-
21
- // oxlint-disable-next-line typescript/no-explicit-any
22
- export type ProtoImplClass<T = object> = new (...args: any[]) => T;
23
- export type Next = () => Promise<void>;
24
- type _MiddlewareFunc<T> = (ctx: T, next: Next) => Promise<void> | void;
25
- export type MiddlewareFunc<T extends Context = Context> = _MiddlewareFunc<T> & {
26
- _name?: string;
27
- };
28
-
29
- /**
30
- * Expose `Application` class.
31
- * Inherits from `Emitter.prototype`.
32
- */
33
- export class Application extends Emitter {
34
- [key: symbol]: unknown;
35
- /**
36
- * Make HttpError available to consumers of the library so that consumers don't
37
- * have a direct dependency upon `http-errors`
38
- */
39
- static HttpError = HttpError;
40
-
41
- protected _proxy: boolean;
42
- protected _env: string;
43
- subdomainOffset: number;
44
- proxyIpHeader: string;
45
- maxIpsCount: number;
46
- protected _keys?: string[];
47
- middleware: MiddlewareFunc<Context>[];
48
- ctxStorage: AsyncLocalStorage<Context>;
49
- silent: boolean;
50
- ContextClass: ProtoImplClass<Context>;
51
- context: AnyProto;
52
- RequestClass: ProtoImplClass<Request>;
53
- request: AnyProto;
54
- ResponseClass: ProtoImplClass<Response>;
55
- response: AnyProto;
56
-
57
- /**
58
- * Initialize a new `Application`.
59
- *
60
- * @param {object} [options] Application options
61
- * @param {string} [options.env] Environment, default is `development`
62
- * @param {string[]} [options.keys] Signed cookie keys
63
- * @param {boolean} [options.proxy] Trust proxy headers
64
- * @param {number} [options.subdomainOffset] Subdomain offset
65
- * @param {string} [options.proxyIpHeader] Proxy IP header, defaults to X-Forwarded-For
66
- * @param {number} [options.maxIpsCount] Max IPs read from proxy IP header, default to 0 (means infinity)
67
- */
68
-
69
- constructor(options?: {
70
- proxy?: boolean;
71
- subdomainOffset?: number;
72
- proxyIpHeader?: string;
73
- maxIpsCount?: number;
74
- env?: string;
75
- keys?: string[];
76
- }) {
77
- super();
78
- options = options || {};
79
- this._proxy = options.proxy || false;
80
- this.subdomainOffset = options.subdomainOffset || 2;
81
- this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
82
- this.maxIpsCount = options.maxIpsCount || 0;
83
- this._env = options.env || process.env.NODE_ENV || 'development';
84
- if (options.keys) {
85
- this._keys = options.keys;
86
- }
87
- this.middleware = [];
88
- this.ctxStorage = getAsyncLocalStorage();
89
- this.silent = false;
90
- this.ContextClass =
91
- class ApplicationContext extends Context {} as ProtoImplClass<Context>;
92
- this.context = this.ContextClass.prototype;
93
- this.RequestClass =
94
- class ApplicationRequest extends Request {} as ProtoImplClass<Request>;
95
- this.request = this.RequestClass.prototype;
96
- this.ResponseClass =
97
- class ApplicationResponse extends Response {} as ProtoImplClass<Response>;
98
- this.response = this.ResponseClass.prototype;
99
- }
100
-
101
- get keys() {
102
- return this._keys;
103
- }
104
-
105
- set keys(value: string[] | undefined) {
106
- this._keys = value;
107
- }
108
-
109
- get env() {
110
- return this._env;
111
- }
112
- set env(value: string) {
113
- this._env = value;
114
- }
115
-
116
- get proxy() {
117
- return this._proxy;
118
- }
119
- set proxy(value: boolean) {
120
- this._proxy = value;
121
- }
122
-
123
- /**
124
- * Shorthand for:
125
- *
126
- * http.createServer(app.callback()).listen(...)
127
- */
128
- // oxlint-disable-next-line typescript/no-explicit-any
129
- listen(...args: any[]) {
130
- debug('listen with args: %o', args);
131
- const server = http.createServer(this.callback());
132
- return server.listen(...args);
133
- }
134
-
135
- /**
136
- * Return JSON representation.
137
- * We only bother showing settings.
138
- */
139
- toJSON() {
140
- return {
141
- subdomainOffset: this.subdomainOffset,
142
- proxy: this.proxy,
143
- env: this.env,
144
- };
145
- }
146
-
147
- /**
148
- * Inspect implementation.
149
- */
150
- inspect() {
151
- return this.toJSON();
152
- }
153
-
154
- [util.inspect.custom]() {
155
- return this.inspect();
156
- }
157
-
158
- /**
159
- * Use the given middleware `fn`.
160
- */
161
- use<T extends Context = Context>(fn: MiddlewareFunc<T>) {
162
- if (typeof fn !== 'function')
163
- throw new TypeError('middleware must be a function!');
164
- const name = fn._name || fn.name || '-';
165
- if (isGeneratorFunction(fn)) {
166
- throw new TypeError(
167
- `Support for generators was removed, middleware: ${name}. ` +
168
- 'See the documentation for examples of how to convert old middleware ' +
169
- 'https://github.com/koajs/koa/blob/master/docs/migration.md'
170
- );
171
- }
172
- debug('use %o #%d', name, this.middleware.length);
173
- this.middleware.push(fn as MiddlewareFunc<Context>);
174
- return this;
175
- }
176
-
177
- /**
178
- * Return a request handler callback
179
- * for node's native http server.
180
- */
181
- callback() {
182
- const fn = compose(this.middleware);
183
-
184
- if (!this.listenerCount('error')) {
185
- this.on('error', this.onerror.bind(this));
186
- }
187
-
188
- const handleRequest = (req: IncomingMessage, res: ServerResponse) => {
189
- const ctx = this.createContext(req, res);
190
- return this.ctxStorage.run(ctx, async () => {
191
- return await this.handleRequest(ctx, fn);
192
- });
193
- };
194
-
195
- return handleRequest;
196
- }
197
-
198
- /**
199
- * return current context from async local storage
200
- */
201
- get currentContext() {
202
- return this.ctxStorage.getStore();
203
- }
204
-
205
- /**
206
- * Handle request in callback.
207
- * @private
208
- */
209
- protected async handleRequest(
210
- ctx: Context,
211
- fnMiddleware: (ctx: Context) => Promise<void>
212
- ) {
213
- this.emit('request', ctx);
214
- const res = ctx.res;
215
- res.statusCode = 404;
216
- const onerror = (err: CustomError) => ctx.onerror(err);
217
- // oxlint-disable-next-line promise/prefer-await-to-callbacks
218
- onFinished(res, (err: CustomError | null) => {
219
- if (err) {
220
- onerror(err);
221
- }
222
- this.emit('response', ctx);
223
- });
224
- try {
225
- await fnMiddleware(ctx);
226
- return this._respond(ctx);
227
- } catch (err) {
228
- return onerror(err as CustomError);
229
- }
230
- }
231
-
232
- /**
233
- * Initialize a new context.
234
- * @private
235
- */
236
- createContext(req: IncomingMessage, res: ServerResponse) {
237
- const context = new this.ContextClass(this, req, res);
238
- return context;
239
- }
240
-
241
- /**
242
- * Default error handler.
243
- * @private
244
- */
245
- protected onerror(err: CustomError) {
246
- // When dealing with cross-globals a normal `instanceof` check doesn't work properly.
247
- // See https://github.com/koajs/koa/issues/1466
248
- // We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
249
- const isNativeError =
250
- err instanceof Error ||
251
- Object.prototype.toString.call(err) === '[object Error]';
252
- if (!isNativeError)
253
- throw new TypeError(util.format('non-error thrown: %j', err));
254
-
255
- if (err.status === 404 || err.expose) return;
256
- if (this.silent) return;
257
-
258
- const msg = err.stack || err.toString();
259
- // oxlint-disable-next-line no-console
260
- console.error(`\n${msg.replaceAll(/^/gm, ' ')}\n`);
261
- }
262
-
263
- /**
264
- * Response helper.
265
- */
266
- protected _respond(ctx: Context) {
267
- // allow bypassing koa
268
- if (ctx.respond === false) return;
269
-
270
- if (!ctx.writable) return;
271
-
272
- const res = ctx.res;
273
- let body = ctx.body;
274
- const code = ctx.status;
275
-
276
- // ignore body
277
- if (statuses.empty[code]) {
278
- // strip headers
279
- ctx.body = null;
280
- return res.end();
281
- }
282
-
283
- if (ctx.method === 'HEAD') {
284
- if (!res.headersSent && !ctx.response.has('Content-Length')) {
285
- const { length } = ctx.response;
286
- if (Number.isInteger(length)) ctx.length = length;
287
- }
288
- return res.end();
289
- }
290
-
291
- // status body
292
- if (body === null || body === undefined) {
293
- if (ctx.response._explicitNullBody) {
294
- ctx.response.remove('Content-Type');
295
- ctx.response.remove('Transfer-Encoding');
296
- return res.end();
297
- }
298
- if (ctx.req.httpVersionMajor >= 2) {
299
- body = String(code);
300
- } else {
301
- body = ctx.message || String(code);
302
- }
303
- if (!res.headersSent) {
304
- ctx.type = 'text';
305
- ctx.length = Buffer.byteLength(body);
306
- }
307
- return res.end(body);
308
- }
309
-
310
- // responses
311
- if (Buffer.isBuffer(body)) return res.end(body);
312
- if (typeof body === 'string') return res.end(body);
313
- if (body instanceof Stream) return body.pipe(res);
314
-
315
- // body: json
316
- body = JSON.stringify(body);
317
- if (!res.headersSent) {
318
- ctx.length = Buffer.byteLength(body);
319
- }
320
- res.end(body);
321
- }
322
- }