egg 4.0.0-beta.0 → 4.0.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/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/dist/commonjs/app/extend/context.d.ts +154 -0
- package/dist/commonjs/app/extend/context.js +261 -0
- package/dist/commonjs/app/extend/context.types.d.ts +16 -0
- package/dist/commonjs/app/extend/context.types.js +3 -0
- package/dist/commonjs/app/extend/helper.d.ts +37 -0
- package/dist/commonjs/app/extend/helper.js +49 -0
- package/dist/commonjs/app/extend/request.d.ts +128 -0
- package/dist/commonjs/app/extend/request.js +270 -0
- package/dist/commonjs/app/extend/response.d.ts +25 -0
- package/dist/commonjs/app/extend/response.js +37 -0
- package/dist/commonjs/app/middleware/meta.d.ts +2 -3
- package/dist/commonjs/app/middleware/meta.js +1 -1
- package/dist/commonjs/app/middleware/notfound.d.ts +2 -3
- package/dist/commonjs/app/middleware/notfound.js +1 -1
- package/dist/commonjs/app/middleware/site_file.d.ts +5 -3
- package/dist/commonjs/app/middleware/site_file.js +21 -3
- package/dist/commonjs/config/config.default.js +5 -4
- package/dist/commonjs/config/plugin.js +3 -3
- package/dist/commonjs/index.d.ts +3 -1
- package/dist/commonjs/index.js +8 -6
- package/dist/commonjs/lib/application.d.ts +5 -12
- package/dist/commonjs/lib/application.js +9 -20
- package/dist/commonjs/lib/core/base_context_class.d.ts +2 -2
- package/dist/commonjs/lib/core/base_hook_class.d.ts +1 -1
- package/dist/commonjs/lib/core/context_httpclient.d.ts +3 -3
- package/dist/commonjs/lib/core/context_httpclient.js +1 -1
- package/dist/commonjs/lib/core/httpclient.d.ts +2 -3
- package/dist/commonjs/lib/core/httpclient.js +3 -6
- package/dist/commonjs/lib/core/messenger/IMessenger.d.ts +3 -3
- package/dist/commonjs/lib/core/messenger/index.js +2 -2
- package/dist/commonjs/lib/core/messenger/ipc.d.ts +6 -4
- package/dist/commonjs/lib/core/messenger/ipc.js +31 -20
- package/dist/commonjs/lib/core/messenger/local.d.ts +3 -3
- package/dist/commonjs/lib/core/messenger/local.js +14 -11
- package/dist/commonjs/lib/egg.d.ts +25 -16
- package/dist/commonjs/lib/egg.js +44 -22
- package/dist/commonjs/lib/egg.types.d.ts +6 -0
- package/dist/commonjs/lib/egg.types.js +3 -0
- package/dist/commonjs/lib/type.d.ts +3 -5
- package/dist/commonjs/lib/utils.d.ts +2 -0
- package/dist/commonjs/lib/utils.js +21 -0
- package/dist/esm/app/extend/context.d.ts +154 -0
- package/dist/esm/app/extend/context.js +255 -0
- package/dist/esm/app/extend/context.types.d.ts +16 -0
- package/dist/esm/app/extend/context.types.js +2 -0
- package/dist/esm/app/extend/helper.d.ts +37 -0
- package/dist/esm/app/extend/helper.js +43 -0
- package/dist/esm/app/extend/request.d.ts +128 -0
- package/dist/esm/app/extend/request.js +264 -0
- package/dist/esm/app/extend/response.d.ts +25 -0
- package/dist/esm/app/extend/response.js +34 -0
- package/dist/esm/app/middleware/meta.d.ts +2 -3
- package/dist/esm/app/middleware/meta.js +1 -1
- package/dist/esm/app/middleware/notfound.d.ts +2 -3
- package/dist/esm/app/middleware/notfound.js +1 -1
- package/dist/esm/app/middleware/site_file.d.ts +5 -3
- package/dist/esm/app/middleware/site_file.js +21 -3
- package/dist/esm/config/config.default.js +5 -4
- package/dist/esm/config/plugin.js +3 -3
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +5 -4
- package/dist/esm/lib/application.d.ts +5 -12
- package/dist/esm/lib/application.js +9 -20
- package/dist/esm/lib/core/base_context_class.d.ts +2 -2
- package/dist/esm/lib/core/base_hook_class.d.ts +1 -1
- package/dist/esm/lib/core/context_httpclient.d.ts +3 -3
- package/dist/esm/lib/core/context_httpclient.js +1 -1
- package/dist/esm/lib/core/httpclient.d.ts +2 -3
- package/dist/esm/lib/core/httpclient.js +2 -2
- package/dist/esm/lib/core/messenger/IMessenger.d.ts +3 -3
- package/dist/esm/lib/core/messenger/index.js +2 -2
- package/dist/esm/lib/core/messenger/ipc.d.ts +6 -4
- package/dist/esm/lib/core/messenger/ipc.js +29 -18
- package/dist/esm/lib/core/messenger/local.d.ts +3 -3
- package/dist/esm/lib/core/messenger/local.js +14 -11
- package/dist/esm/lib/egg.d.ts +25 -16
- package/dist/esm/lib/egg.js +24 -15
- package/dist/esm/lib/egg.types.d.ts +6 -0
- package/dist/esm/lib/egg.types.js +2 -0
- package/dist/esm/lib/type.d.ts +3 -5
- package/dist/esm/lib/utils.d.ts +2 -0
- package/dist/esm/lib/utils.js +14 -0
- package/dist/package.json +1 -1
- package/package.json +32 -28
- package/src/app/extend/context.ts +303 -0
- package/src/app/extend/context.types.ts +24 -0
- package/src/app/extend/{helper.js → helper.ts} +14 -13
- package/src/app/extend/{request.js → request.ts} +81 -79
- package/src/app/extend/response.ts +36 -0
- package/src/app/middleware/meta.ts +2 -3
- package/src/app/middleware/notfound.ts +2 -3
- package/src/app/middleware/site_file.ts +26 -7
- package/src/config/config.default.ts +4 -3
- package/src/config/plugin.ts +2 -2
- package/src/index.ts +5 -3
- package/src/lib/application.ts +14 -21
- package/src/lib/core/base_context_class.ts +2 -2
- package/src/lib/core/base_hook_class.ts +1 -1
- package/src/lib/core/context_httpclient.ts +3 -3
- package/src/lib/core/httpclient.ts +4 -5
- package/src/lib/core/messenger/IMessenger.ts +3 -3
- package/src/lib/core/messenger/index.ts +1 -1
- package/src/lib/core/messenger/ipc.ts +31 -20
- package/src/lib/core/messenger/local.ts +13 -11
- package/src/lib/egg.ts +60 -28
- package/src/lib/egg.types.ts +6 -0
- package/src/lib/type.ts +6 -6
- package/src/lib/utils.ts +16 -0
- package/src/app/extend/context.js +0 -285
- package/src/app/extend/response.js +0 -101
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Router,
|
|
3
|
+
} from '@eggjs/core';
|
|
4
|
+
import type {
|
|
5
|
+
HttpClientRequestURL, HttpClientRequestOptions, HttpClient,
|
|
6
|
+
} from '../../lib/core/httpclient.js';
|
|
7
|
+
import type {
|
|
8
|
+
ContextHttpClient,
|
|
9
|
+
} from '../../lib/core/context_httpclient.js';
|
|
10
|
+
import type Helper from './helper.js';
|
|
11
|
+
import type { EggLogger } from 'egg-logger';
|
|
12
|
+
|
|
13
|
+
declare module '@eggjs/core' {
|
|
14
|
+
// add Context overrides types
|
|
15
|
+
interface Context {
|
|
16
|
+
curl(url: HttpClientRequestURL, options?: HttpClientRequestOptions): ReturnType<HttpClient['request']>;
|
|
17
|
+
get router(): Router;
|
|
18
|
+
set router(val: Router);
|
|
19
|
+
get helper(): Helper;
|
|
20
|
+
get httpclient(): ContextHttpClient;
|
|
21
|
+
get httpClient(): ContextHttpClient;
|
|
22
|
+
getLogger(name: string): EggLogger;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const url = require('url');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
module.exports = {
|
|
1
|
+
import url from 'node:url';
|
|
2
|
+
import { BaseContextClass } from '../../lib/core/base_context_class.js';
|
|
7
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The Helper class which can be used as utility function.
|
|
6
|
+
* We support developers to extend Helper through ${baseDir}/app/extend/helper.js ,
|
|
7
|
+
* then you can use all method on `ctx.helper` that is a instance of Helper.
|
|
8
|
+
*/
|
|
9
|
+
export default class Helper extends BaseContextClass {
|
|
8
10
|
/**
|
|
9
11
|
* Generate URL path(without host) for route. Takes the route name and a map of named params.
|
|
10
12
|
* @function Helper#pathFor
|
|
@@ -19,9 +21,9 @@ module.exports = {
|
|
|
19
21
|
* ```
|
|
20
22
|
* @return {String} url path(without host)
|
|
21
23
|
*/
|
|
22
|
-
pathFor(name, params) {
|
|
24
|
+
pathFor(name: string, params: Record<string, any>): string {
|
|
23
25
|
return this.app.router.url(name, params);
|
|
24
|
-
}
|
|
26
|
+
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Generate full URL(with host) for route. Takes the route name and a map of named params.
|
|
@@ -36,8 +38,7 @@ module.exports = {
|
|
|
36
38
|
* ```
|
|
37
39
|
* @return {String} full url(with host)
|
|
38
40
|
*/
|
|
39
|
-
urlFor(name, params) {
|
|
40
|
-
return this.ctx.protocol + '://' + this.ctx.host + url.resolve('/', this.
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
};
|
|
41
|
+
urlFor(name: string, params: Record<string, any>): string {
|
|
42
|
+
return this.ctx.protocol + '://' + this.ctx.host + url.resolve('/', this.pathFor(name, params));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import querystring from 'node:querystring';
|
|
2
|
+
import { Request as EggCoreRequest } from '@eggjs/core';
|
|
3
|
+
import type { Application } from '../../lib/application.js';
|
|
4
|
+
import type { ContextDelegation } from './context.js';
|
|
5
|
+
import Response from './response.js';
|
|
2
6
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const PROTOCOL = Symbol('PROTOCOL');
|
|
9
|
-
const HOST = Symbol('HOST');
|
|
10
|
-
const ACCEPTS = Symbol('ACCEPTS');
|
|
11
|
-
const IPS = Symbol('IPS');
|
|
7
|
+
const QUERY_CACHE = Symbol('request query cache');
|
|
8
|
+
const QUERIES_CACHE = Symbol('request queries cache');
|
|
9
|
+
const PROTOCOL = Symbol('request protocol');
|
|
10
|
+
const HOST = Symbol('request host');
|
|
11
|
+
const IPS = Symbol('request ips');
|
|
12
12
|
const RE_ARRAY_KEY = /[^\[\]]+\[\]$/;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
export default class Request extends EggCoreRequest {
|
|
15
|
+
declare app: Application;
|
|
16
|
+
declare ctx: ContextDelegation;
|
|
17
|
+
declare response: Response;
|
|
18
|
+
|
|
15
19
|
/**
|
|
16
20
|
* Parse the "Host" header field host
|
|
17
21
|
* and support X-Forwarded-Host when a
|
|
@@ -29,17 +33,19 @@ module.exports = {
|
|
|
29
33
|
* => 'demo.eggjs.org'
|
|
30
34
|
* ```
|
|
31
35
|
*/
|
|
32
|
-
get host() {
|
|
33
|
-
|
|
36
|
+
get host(): string {
|
|
37
|
+
let host = this[HOST] as string | undefined;
|
|
38
|
+
if (host) {
|
|
39
|
+
return host;
|
|
40
|
+
}
|
|
34
41
|
|
|
35
|
-
let host;
|
|
36
42
|
if (this.app.config.proxy) {
|
|
37
43
|
host = getFromHeaders(this, this.app.config.hostHeaders);
|
|
38
44
|
}
|
|
39
45
|
host = host || this.get('host') || '';
|
|
40
|
-
this[HOST] = host.split(
|
|
41
|
-
return
|
|
42
|
-
}
|
|
46
|
+
this[HOST] = host = host.split(',')[0].trim();
|
|
47
|
+
return host;
|
|
48
|
+
}
|
|
43
49
|
|
|
44
50
|
/**
|
|
45
51
|
* @member {String} Request#protocol
|
|
@@ -49,25 +55,28 @@ module.exports = {
|
|
|
49
55
|
* => 'https'
|
|
50
56
|
* ```
|
|
51
57
|
*/
|
|
52
|
-
get protocol() {
|
|
53
|
-
|
|
58
|
+
get protocol(): string {
|
|
59
|
+
let protocol = this[PROTOCOL] as string;
|
|
60
|
+
if (protocol) {
|
|
61
|
+
return protocol;
|
|
62
|
+
}
|
|
54
63
|
// detect encrypted socket
|
|
55
|
-
if (this.socket
|
|
56
|
-
this[PROTOCOL] = 'https';
|
|
57
|
-
return
|
|
64
|
+
if (this.socket?.encrypted) {
|
|
65
|
+
this[PROTOCOL] = protocol = 'https';
|
|
66
|
+
return protocol;
|
|
58
67
|
}
|
|
59
68
|
// get from headers specified in `app.config.protocolHeaders`
|
|
60
69
|
if (this.app.config.proxy) {
|
|
61
70
|
const proto = getFromHeaders(this, this.app.config.protocolHeaders);
|
|
62
71
|
if (proto) {
|
|
63
|
-
this[PROTOCOL] = proto.split(/\s*,\s*/)[0];
|
|
64
|
-
return
|
|
72
|
+
this[PROTOCOL] = protocol = proto.split(/\s*,\s*/)[0];
|
|
73
|
+
return protocol;
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
|
-
// use protocol specified in `app.
|
|
68
|
-
this[PROTOCOL] = this.app.config.protocol || 'http';
|
|
69
|
-
return
|
|
70
|
-
}
|
|
76
|
+
// use protocol specified in `app.config.protocol`
|
|
77
|
+
this[PROTOCOL] = protocol = this.app.config.protocol || 'http';
|
|
78
|
+
return protocol;
|
|
79
|
+
}
|
|
71
80
|
|
|
72
81
|
/**
|
|
73
82
|
* Get all pass through ip addresses from the request.
|
|
@@ -80,29 +89,34 @@ module.exports = {
|
|
|
80
89
|
* => ['100.23.1.2', '201.10.10.2']
|
|
81
90
|
* ```
|
|
82
91
|
*/
|
|
83
|
-
get ips() {
|
|
84
|
-
|
|
92
|
+
get ips(): string[] {
|
|
93
|
+
let ips = this[IPS] as string[] | undefined;
|
|
94
|
+
if (ips) {
|
|
95
|
+
return ips;
|
|
96
|
+
}
|
|
85
97
|
|
|
86
98
|
// return empty array when proxy=false
|
|
87
99
|
if (!this.app.config.proxy) {
|
|
88
|
-
this[IPS] = [];
|
|
89
|
-
return
|
|
100
|
+
this[IPS] = ips = [];
|
|
101
|
+
return ips;
|
|
90
102
|
}
|
|
91
103
|
|
|
92
|
-
const val = getFromHeaders(this, this.app.config.ipHeaders)
|
|
93
|
-
this[IPS] = val ? val.split(/\s*,\s*/) : [];
|
|
104
|
+
const val = getFromHeaders(this, this.app.config.ipHeaders);
|
|
105
|
+
this[IPS] = ips = val ? val.split(/\s*,\s*/) : [];
|
|
94
106
|
|
|
95
107
|
let maxIpsCount = this.app.config.maxIpsCount;
|
|
96
108
|
// Compatible with maxProxyCount logic (previous logic is wrong, only for compatibility with legacy logic)
|
|
97
|
-
if (!maxIpsCount && this.app.config.maxProxyCount)
|
|
109
|
+
if (!maxIpsCount && this.app.config.maxProxyCount) {
|
|
110
|
+
maxIpsCount = this.app.config.maxProxyCount + 1;
|
|
111
|
+
}
|
|
98
112
|
|
|
99
113
|
if (maxIpsCount > 0) {
|
|
100
114
|
// if maxIpsCount present, only keep `maxIpsCount` ips
|
|
101
115
|
// [ illegalIp, clientRealIp, proxyIp1, proxyIp2 ...]
|
|
102
|
-
this[IPS] =
|
|
116
|
+
this[IPS] = ips = ips.slice(-maxIpsCount);
|
|
103
117
|
}
|
|
104
|
-
return
|
|
105
|
-
}
|
|
118
|
+
return ips;
|
|
119
|
+
}
|
|
106
120
|
|
|
107
121
|
/**
|
|
108
122
|
* Get the request remote IPv4 address
|
|
@@ -115,16 +129,16 @@ module.exports = {
|
|
|
115
129
|
* => '111.10.2.1'
|
|
116
130
|
* ```
|
|
117
131
|
*/
|
|
118
|
-
get ip() {
|
|
132
|
+
get ip(): string {
|
|
119
133
|
if (this._ip) {
|
|
120
134
|
return this._ip;
|
|
121
135
|
}
|
|
122
|
-
const ip = this.ips[0]
|
|
136
|
+
const ip = this.ips[0] ?? this.socket.remoteAddress;
|
|
123
137
|
// will be '::ffff:x.x.x.x', should convert to standard IPv4 format
|
|
124
138
|
// https://zh.wikipedia.org/wiki/IPv6
|
|
125
|
-
this._ip = ip && ip.
|
|
139
|
+
this._ip = ip && ip.startsWith('::ffff:') ? ip.substring(7) : ip;
|
|
126
140
|
return this._ip;
|
|
127
|
-
}
|
|
141
|
+
}
|
|
128
142
|
|
|
129
143
|
/**
|
|
130
144
|
* Set the request remote IPv4 address
|
|
@@ -137,9 +151,9 @@ module.exports = {
|
|
|
137
151
|
* => '111.10.2.1'
|
|
138
152
|
* ```
|
|
139
153
|
*/
|
|
140
|
-
set ip(ip) {
|
|
154
|
+
set ip(ip: string) {
|
|
141
155
|
this._ip = ip;
|
|
142
|
-
}
|
|
156
|
+
}
|
|
143
157
|
|
|
144
158
|
/**
|
|
145
159
|
* detect if response should be json
|
|
@@ -150,25 +164,25 @@ module.exports = {
|
|
|
150
164
|
* @member {Boolean} Request#acceptJSON
|
|
151
165
|
* @since 1.0.0
|
|
152
166
|
*/
|
|
153
|
-
get acceptJSON() {
|
|
167
|
+
get acceptJSON(): boolean {
|
|
154
168
|
if (this.path.endsWith('.json')) return true;
|
|
155
169
|
if (this.response.type && this.response.type.indexOf('json') >= 0) return true;
|
|
156
170
|
if (this.accepts('html', 'text', 'json') === 'json') return true;
|
|
157
171
|
return false;
|
|
158
|
-
}
|
|
172
|
+
}
|
|
159
173
|
|
|
160
174
|
// How to read query safely
|
|
161
175
|
// https://github.com/koajs/qs/issues/5
|
|
162
|
-
_customQuery(cacheName, filter) {
|
|
176
|
+
_customQuery(cacheName: symbol, filter: (value: string | string[]) => string | string[]) {
|
|
163
177
|
const str = this.querystring || '';
|
|
164
|
-
let c = this[cacheName]
|
|
178
|
+
let c = this[cacheName] as Record<string, Record<string, string | string[]>>;
|
|
165
179
|
if (!c) {
|
|
166
180
|
c = this[cacheName] = {};
|
|
167
181
|
}
|
|
168
182
|
let cacheQuery = c[str];
|
|
169
183
|
if (!cacheQuery) {
|
|
170
184
|
cacheQuery = c[str] = {};
|
|
171
|
-
const isQueries = cacheName ===
|
|
185
|
+
const isQueries = cacheName === QUERIES_CACHE;
|
|
172
186
|
// `querystring.parse` CANNOT parse something like `a[foo]=1&a[bar]=2`
|
|
173
187
|
const query = str ? querystring.parse(str) : {};
|
|
174
188
|
for (const key in query) {
|
|
@@ -176,20 +190,19 @@ module.exports = {
|
|
|
176
190
|
// key is '', like `a=b&`
|
|
177
191
|
continue;
|
|
178
192
|
}
|
|
179
|
-
const value = filter(query[key]);
|
|
193
|
+
const value = filter(query[key]!);
|
|
180
194
|
cacheQuery[key] = value;
|
|
181
195
|
if (isQueries && RE_ARRAY_KEY.test(key)) {
|
|
182
196
|
// `this.queries['key'] => this.queries['key[]']` is compatibly supported
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
cacheQuery[subkey] = value;
|
|
197
|
+
const subKey = key.substring(0, key.length - 2);
|
|
198
|
+
if (!cacheQuery[subKey]) {
|
|
199
|
+
cacheQuery[subKey] = value;
|
|
187
200
|
}
|
|
188
201
|
}
|
|
189
202
|
}
|
|
190
203
|
}
|
|
191
204
|
return cacheQuery;
|
|
192
|
-
}
|
|
205
|
+
}
|
|
193
206
|
|
|
194
207
|
/**
|
|
195
208
|
* get params pass by querystring, all values are of string type.
|
|
@@ -212,8 +225,8 @@ module.exports = {
|
|
|
212
225
|
* ```
|
|
213
226
|
*/
|
|
214
227
|
get query() {
|
|
215
|
-
return this._customQuery(
|
|
216
|
-
}
|
|
228
|
+
return this._customQuery(QUERY_CACHE, firstValue) as Record<string, string>;
|
|
229
|
+
}
|
|
217
230
|
|
|
218
231
|
/**
|
|
219
232
|
* get params pass by querystring, all value are Array type. {@link Request#query}
|
|
@@ -232,50 +245,39 @@ module.exports = {
|
|
|
232
245
|
* ```
|
|
233
246
|
*/
|
|
234
247
|
get queries() {
|
|
235
|
-
return this._customQuery(
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
get accept() {
|
|
239
|
-
let accept = this[ACCEPTS];
|
|
240
|
-
if (accept) {
|
|
241
|
-
return accept;
|
|
242
|
-
}
|
|
243
|
-
accept = this[ACCEPTS] = accepts(this.req);
|
|
244
|
-
return accept;
|
|
245
|
-
},
|
|
248
|
+
return this._customQuery(QUERIES_CACHE, arrayValue) as Record<string, string[]>;
|
|
249
|
+
}
|
|
246
250
|
|
|
247
251
|
/**
|
|
248
252
|
* Set query-string as an object.
|
|
249
253
|
*
|
|
250
254
|
* @function Request#query
|
|
251
255
|
* @param {Object} obj set querystring and query object for request.
|
|
252
|
-
* @return {void}
|
|
253
256
|
*/
|
|
254
|
-
set query(obj) {
|
|
257
|
+
set query(obj: Record<string, string>) {
|
|
255
258
|
this.querystring = querystring.stringify(obj);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
+
}
|
|
260
|
+
}
|
|
259
261
|
|
|
260
|
-
function firstValue(value) {
|
|
262
|
+
function firstValue(value: string | string[]) {
|
|
261
263
|
if (Array.isArray(value)) {
|
|
262
264
|
value = value[0];
|
|
263
265
|
}
|
|
264
266
|
return value;
|
|
265
267
|
}
|
|
266
268
|
|
|
267
|
-
function arrayValue(value) {
|
|
269
|
+
function arrayValue(value: string | string[]) {
|
|
268
270
|
if (!Array.isArray(value)) {
|
|
269
271
|
value = [ value ];
|
|
270
272
|
}
|
|
271
273
|
return value;
|
|
272
274
|
}
|
|
273
275
|
|
|
274
|
-
function getFromHeaders(
|
|
276
|
+
function getFromHeaders(request: Request, names: string) {
|
|
275
277
|
if (!names) return '';
|
|
276
|
-
|
|
277
|
-
for (const name of
|
|
278
|
-
const value =
|
|
278
|
+
const fields = names.split(/\s*,\s*/);
|
|
279
|
+
for (const name of fields) {
|
|
280
|
+
const value = request.get<string>(name);
|
|
279
281
|
if (value) return value;
|
|
280
282
|
}
|
|
281
283
|
return '';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Response as KoaResponse } from '@eggjs/core';
|
|
2
|
+
|
|
3
|
+
const REAL_STATUS = Symbol('response realStatus');
|
|
4
|
+
|
|
5
|
+
export default class Response extends KoaResponse {
|
|
6
|
+
/**
|
|
7
|
+
* Get or set a real status code.
|
|
8
|
+
*
|
|
9
|
+
* e.g.: Using 302 status redirect to the global error page
|
|
10
|
+
* instead of show current 500 status page.
|
|
11
|
+
* And access log should save 500 not 302,
|
|
12
|
+
* then the `realStatus` can help us find out the real status code.
|
|
13
|
+
* @member {Number} Response#realStatus
|
|
14
|
+
* @return {Number} The status code to be set.
|
|
15
|
+
*/
|
|
16
|
+
get realStatus(): number {
|
|
17
|
+
if (this[REAL_STATUS]) {
|
|
18
|
+
return this[REAL_STATUS] as number;
|
|
19
|
+
}
|
|
20
|
+
return this.status;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Set a real status code.
|
|
25
|
+
*
|
|
26
|
+
* e.g.: Using 302 status redirect to the global error page
|
|
27
|
+
* instead of show current 500 status page.
|
|
28
|
+
* And access log should save 500 not 302,
|
|
29
|
+
* then the `realStatus` can help us find out the real status code.
|
|
30
|
+
* @member {Number} Response#realStatus
|
|
31
|
+
* @param {Number} status The status code to be set.
|
|
32
|
+
*/
|
|
33
|
+
set realStatus(status: number) {
|
|
34
|
+
this[REAL_STATUS] = status;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { performance } from 'node:perf_hooks';
|
|
6
|
-
import type {
|
|
7
|
-
import type { Next } from '../../lib/type.js';
|
|
6
|
+
import type { ContextDelegation, Next } from '../../lib/egg.js';
|
|
8
7
|
|
|
9
8
|
export interface MetaMiddlewareOptions {
|
|
10
9
|
enable: boolean;
|
|
@@ -12,7 +11,7 @@ export interface MetaMiddlewareOptions {
|
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
export default (options: MetaMiddlewareOptions) => {
|
|
15
|
-
return async function meta(ctx:
|
|
14
|
+
return async function meta(ctx: ContextDelegation, next: Next) {
|
|
16
15
|
if (options.logging) {
|
|
17
16
|
ctx.coreLogger.info('[meta] request started, host: %s, user-agent: %s',
|
|
18
17
|
ctx.host, ctx.header['user-agent']);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Next } from '../../lib/type.js';
|
|
1
|
+
import type { Next, ContextDelegation } from '../../lib/egg.js';
|
|
3
2
|
|
|
4
3
|
export interface NotFoundMiddlewareOptions {
|
|
5
4
|
enable: boolean;
|
|
@@ -7,7 +6,7 @@ export interface NotFoundMiddlewareOptions {
|
|
|
7
6
|
}
|
|
8
7
|
|
|
9
8
|
export default (options: NotFoundMiddlewareOptions) => {
|
|
10
|
-
return async function notfound(ctx:
|
|
9
|
+
return async function notfound(ctx: ContextDelegation, next: Next) {
|
|
11
10
|
await next();
|
|
12
11
|
|
|
13
12
|
if (ctx.status !== 404 || ctx.body) {
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import type { Next, ContextDelegation } from '../../lib/egg.js';
|
|
4
5
|
|
|
5
|
-
export type SiteFileContentFun = (ctx:
|
|
6
|
+
export type SiteFileContentFun = (ctx: ContextDelegation) => Promise<Buffer | string>;
|
|
6
7
|
|
|
7
8
|
export interface SiteFileMiddlewareOptions {
|
|
8
9
|
enable: boolean;
|
|
9
10
|
cacheControl: string;
|
|
10
|
-
[key: string]: string | Buffer | boolean | SiteFileContentFun;
|
|
11
|
+
[key: string]: string | Buffer | boolean | SiteFileContentFun | URL;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const BUFFER_CACHE = Symbol('siteFile URL buffer cache');
|
|
15
|
+
|
|
16
|
+
export default (options: SiteFileMiddlewareOptions) => {
|
|
17
|
+
return async function siteFile(ctx: ContextDelegation, next: Next) {
|
|
15
18
|
if (ctx.method !== 'HEAD' && ctx.method !== 'GET') {
|
|
16
19
|
return next();
|
|
17
20
|
}
|
|
18
|
-
/* istanbul ignore if */
|
|
19
21
|
if (ctx.path[0] !== '/') {
|
|
20
22
|
return next();
|
|
21
23
|
}
|
|
@@ -35,6 +37,23 @@ module.exports = (options: SiteFileMiddlewareOptions) => {
|
|
|
35
37
|
return ctx.redirect(content);
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
// URL
|
|
41
|
+
if (content instanceof URL) {
|
|
42
|
+
if (content.protocol !== 'file:') {
|
|
43
|
+
return ctx.redirect(content.href);
|
|
44
|
+
}
|
|
45
|
+
// protocol = file:
|
|
46
|
+
let buffer = Reflect.get(content, BUFFER_CACHE) as Buffer;
|
|
47
|
+
if (!buffer) {
|
|
48
|
+
buffer = await readFile(fileURLToPath(content));
|
|
49
|
+
Reflect.set(content, BUFFER_CACHE, buffer);
|
|
50
|
+
}
|
|
51
|
+
ctx.set('cache-control', options.cacheControl);
|
|
52
|
+
ctx.body = content;
|
|
53
|
+
ctx.type = path.extname(ctx.path);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
38
57
|
// '/robots.txt': Buffer <xx..
|
|
39
58
|
// content is buffer
|
|
40
59
|
if (Buffer.isBuffer(content)) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
3
|
import type { EggAppInfo } from '@eggjs/core';
|
|
4
4
|
import type { EggAppConfig } from '../lib/type.js';
|
|
5
|
+
import { getSourceFile } from '../lib/utils.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* The configuration of egg application, can be access by `app.config`
|
|
@@ -189,7 +190,7 @@ export default (appInfo: EggAppInfo) => {
|
|
|
189
190
|
/**
|
|
190
191
|
* The option of `siteFile` middleware
|
|
191
192
|
*
|
|
192
|
-
* You can map some files using this options, it will response
|
|
193
|
+
* You can map some files using this options, it will response immediately when matching.
|
|
193
194
|
*
|
|
194
195
|
* @member {Object} Config#siteFile - key is path, and value is url or buffer.
|
|
195
196
|
* @property {String} cacheControl - files cache , default is public, max-age=2592000
|
|
@@ -201,7 +202,7 @@ export default (appInfo: EggAppInfo) => {
|
|
|
201
202
|
*/
|
|
202
203
|
config.siteFile = {
|
|
203
204
|
enable: true,
|
|
204
|
-
'/favicon.ico':
|
|
205
|
+
'/favicon.ico': pathToFileURL(getSourceFile('config/favicon.png')),
|
|
205
206
|
// default cache in 30 days
|
|
206
207
|
cacheControl: 'public, max-age=2592000',
|
|
207
208
|
};
|
package/src/config/plugin.ts
CHANGED
|
@@ -41,7 +41,7 @@ export default {
|
|
|
41
41
|
*/
|
|
42
42
|
watcher: {
|
|
43
43
|
enable: true,
|
|
44
|
-
package: '
|
|
44
|
+
package: '@eggjs/watcher',
|
|
45
45
|
},
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -96,7 +96,7 @@ export default {
|
|
|
96
96
|
*/
|
|
97
97
|
schedule: {
|
|
98
98
|
enable: true,
|
|
99
|
-
package: '
|
|
99
|
+
package: '@eggjs/schedule',
|
|
100
100
|
},
|
|
101
101
|
|
|
102
102
|
/**
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { BaseContextClass } from './lib/core/base_context_class.js';
|
|
6
6
|
import { startEgg } from './lib/start.js';
|
|
7
|
+
import Helper from './app/extend/helper.js';
|
|
8
|
+
|
|
9
|
+
// export extends
|
|
10
|
+
export { Helper };
|
|
7
11
|
|
|
8
12
|
// export types
|
|
9
13
|
export * from './lib/egg.js';
|
|
@@ -14,9 +18,7 @@ export * from './lib/start.js';
|
|
|
14
18
|
* Start egg application with cluster mode
|
|
15
19
|
* @since 1.0.0
|
|
16
20
|
*/
|
|
17
|
-
|
|
18
|
-
// @ts-ignore
|
|
19
|
-
export { startCluster } from 'egg-cluster';
|
|
21
|
+
export * from '@eggjs/cluster';
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* Start egg application with single process mode
|
package/src/lib/application.ts
CHANGED
|
@@ -2,14 +2,16 @@ import path from 'node:path';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import http from 'node:http';
|
|
4
4
|
import { Socket } from 'node:net';
|
|
5
|
-
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
import graceful from 'graceful';
|
|
5
|
+
import { graceful } from 'graceful';
|
|
8
6
|
import { assign } from 'utility';
|
|
9
7
|
import { utils as eggUtils } from '@eggjs/core';
|
|
10
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
EggApplicationCore,
|
|
10
|
+
type EggApplicationCoreOptions,
|
|
11
|
+
type ContextDelegation,
|
|
12
|
+
} from './egg.js';
|
|
11
13
|
import { AppWorkerLoader } from './loader/index.js';
|
|
12
|
-
import
|
|
14
|
+
import Helper from '../app/extend/helper.js';
|
|
13
15
|
|
|
14
16
|
const EGG_LOADER = Symbol.for('egg#loader');
|
|
15
17
|
|
|
@@ -34,13 +36,6 @@ function escapeHeaderValue(value: string) {
|
|
|
34
36
|
return /[\r\n]/.test(value) ? value.replace(/[\r\n]+[ \t]*/g, '') : value;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
/**
|
|
38
|
-
* The Helper class which can be used as utility function.
|
|
39
|
-
* We support developers to extend Helper through ${baseDir}/app/extend/helper.js ,
|
|
40
|
-
* then you can use all method on `ctx.helper` that is a instance of Helper.
|
|
41
|
-
*/
|
|
42
|
-
class HelperClass extends BaseContextClass {}
|
|
43
|
-
|
|
44
39
|
/**
|
|
45
40
|
* Singleton instance in App Worker, extend {@link EggApplicationCore}
|
|
46
41
|
* @augments EggApplicationCore
|
|
@@ -53,7 +48,7 @@ export class Application extends EggApplicationCore {
|
|
|
53
48
|
* reference to {@link Helper}
|
|
54
49
|
* @member {Helper} Application#Helper
|
|
55
50
|
*/
|
|
56
|
-
Helper =
|
|
51
|
+
Helper = Helper;
|
|
57
52
|
|
|
58
53
|
/**
|
|
59
54
|
* @class
|
|
@@ -77,8 +72,7 @@ export class Application extends EggApplicationCore {
|
|
|
77
72
|
}
|
|
78
73
|
|
|
79
74
|
#responseRaw(socket: Socket, raw?: any) {
|
|
80
|
-
|
|
81
|
-
if (!socket.writable) return;
|
|
75
|
+
if (!socket?.writable) return;
|
|
82
76
|
if (!raw) {
|
|
83
77
|
return socket.end(DEFAULT_BAD_REQUEST_RESPONSE);
|
|
84
78
|
}
|
|
@@ -152,7 +146,6 @@ export class Application extends EggApplicationCore {
|
|
|
152
146
|
// set ignore code
|
|
153
147
|
const serverGracefulIgnoreCode = this.config.serverGracefulIgnoreCode || [];
|
|
154
148
|
|
|
155
|
-
/* istanbul ignore next */
|
|
156
149
|
graceful({
|
|
157
150
|
server: [ server ],
|
|
158
151
|
error: (err: Error, throwErrorCount: number) => {
|
|
@@ -228,13 +221,13 @@ export class Application extends EggApplicationCore {
|
|
|
228
221
|
* @see Context#runInBackground
|
|
229
222
|
* @param {Function} scope - the first args is an anonymous ctx
|
|
230
223
|
*/
|
|
231
|
-
runInBackground(scope: (ctx:
|
|
232
|
-
const ctx = this.createAnonymousContext();
|
|
224
|
+
runInBackground(scope: (ctx: ContextDelegation) => Promise<void>, req?: unknown) {
|
|
225
|
+
const ctx = this.createAnonymousContext(req);
|
|
233
226
|
if (!scope.name) {
|
|
234
227
|
Reflect.set(scope, '_name', eggUtils.getCalleeFromStack(true));
|
|
235
228
|
}
|
|
236
229
|
this.ctxStorage.run(ctx, () => {
|
|
237
|
-
ctx.runInBackground(scope);
|
|
230
|
+
return ctx.runInBackground(scope);
|
|
238
231
|
});
|
|
239
232
|
}
|
|
240
233
|
|
|
@@ -244,13 +237,13 @@ export class Application extends EggApplicationCore {
|
|
|
244
237
|
* @param {Function} scope - the first args is an anonymous ctx, scope should be async function
|
|
245
238
|
* @param {Request} [req] - if you want to mock request like querystring, you can pass an object to this function.
|
|
246
239
|
*/
|
|
247
|
-
async runInAnonymousContextScope(scope: (ctx:
|
|
240
|
+
async runInAnonymousContextScope(scope: (ctx: ContextDelegation) => Promise<void>, req?: unknown) {
|
|
248
241
|
const ctx = this.createAnonymousContext(req);
|
|
249
242
|
if (!scope.name) {
|
|
250
243
|
Reflect.set(scope, '_name', eggUtils.getCalleeFromStack(true));
|
|
251
244
|
}
|
|
252
245
|
return await this.ctxStorage.run(ctx, async () => {
|
|
253
|
-
return await scope(ctx
|
|
246
|
+
return await scope(ctx);
|
|
254
247
|
});
|
|
255
248
|
}
|
|
256
249
|
|