egg 3.29.0 → 4.0.0-beta.2

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.
Files changed (202) hide show
  1. package/README.md +2 -1
  2. package/README.zh-CN.md +7 -5
  3. package/dist/commonjs/agent.d.ts +4 -0
  4. package/dist/commonjs/agent.js +10 -0
  5. package/dist/commonjs/app/extend/context.d.ts +2 -0
  6. package/dist/commonjs/app/extend/context.js +263 -0
  7. package/dist/commonjs/app/middleware/body_parser.d.ts +2 -0
  8. package/dist/commonjs/app/middleware/body_parser.js +8 -0
  9. package/dist/commonjs/app/middleware/meta.d.ts +11 -0
  10. package/dist/commonjs/app/middleware/meta.js +22 -0
  11. package/dist/commonjs/app/middleware/notfound.d.ts +8 -0
  12. package/dist/commonjs/app/middleware/notfound.js +31 -0
  13. package/dist/commonjs/app/middleware/override_method.d.ts +2 -0
  14. package/dist/commonjs/app/middleware/override_method.js +8 -0
  15. package/dist/commonjs/app/middleware/site_file.d.ts +7 -0
  16. package/dist/commonjs/app/middleware/site_file.js +59 -0
  17. package/dist/commonjs/config/config.default.d.ts +9 -0
  18. package/dist/commonjs/config/config.default.js +378 -0
  19. package/dist/commonjs/config/config.local.d.ts +8 -0
  20. package/dist/commonjs/config/config.local.js +12 -0
  21. package/dist/commonjs/config/config.unittest.d.ts +7 -0
  22. package/dist/commonjs/config/config.unittest.js +11 -0
  23. package/dist/commonjs/config/plugin.d.ts +122 -0
  24. package/dist/commonjs/config/plugin.js +125 -0
  25. package/dist/commonjs/index.d.ts +61 -0
  26. package/dist/commonjs/index.js +89 -0
  27. package/dist/commonjs/lib/agent.d.ts +19 -0
  28. package/dist/commonjs/lib/agent.js +58 -0
  29. package/dist/commonjs/lib/application.d.ts +66 -0
  30. package/dist/commonjs/lib/application.js +281 -0
  31. package/dist/commonjs/lib/core/base_context_class.d.ts +14 -0
  32. package/dist/commonjs/lib/core/base_context_class.js +22 -0
  33. package/dist/commonjs/lib/core/base_context_logger.d.ts +36 -0
  34. package/dist/commonjs/lib/core/base_context_logger.js +64 -0
  35. package/dist/commonjs/lib/core/base_hook_class.d.ts +11 -0
  36. package/dist/commonjs/lib/core/base_hook_class.js +30 -0
  37. package/dist/commonjs/lib/core/context_httpclient.d.ts +16 -0
  38. package/dist/commonjs/lib/core/context_httpclient.js +30 -0
  39. package/dist/commonjs/lib/core/httpclient.d.ts +14 -0
  40. package/dist/commonjs/lib/core/httpclient.js +40 -0
  41. package/dist/commonjs/lib/core/logger.d.ts +3 -0
  42. package/dist/commonjs/lib/core/logger.js +40 -0
  43. package/dist/commonjs/lib/core/messenger/IMessenger.d.ts +50 -0
  44. package/dist/commonjs/lib/core/messenger/IMessenger.js +3 -0
  45. package/dist/commonjs/lib/core/messenger/index.d.ts +7 -0
  46. package/dist/commonjs/lib/core/messenger/index.js +14 -0
  47. package/dist/commonjs/lib/core/messenger/ipc.d.ts +57 -0
  48. package/dist/commonjs/lib/core/messenger/ipc.js +126 -0
  49. package/dist/commonjs/lib/core/messenger/local.d.ts +61 -0
  50. package/dist/commonjs/lib/core/messenger/local.js +134 -0
  51. package/dist/commonjs/lib/core/singleton.d.ts +23 -0
  52. package/dist/commonjs/lib/core/singleton.js +120 -0
  53. package/dist/commonjs/lib/core/utils.d.ts +2 -0
  54. package/dist/commonjs/lib/core/utils.js +77 -0
  55. package/dist/commonjs/lib/egg.d.ts +271 -0
  56. package/dist/commonjs/lib/egg.js +613 -0
  57. package/dist/commonjs/lib/loader/AgentWorkerLoader.d.ts +12 -0
  58. package/dist/commonjs/lib/loader/AgentWorkerLoader.js +24 -0
  59. package/dist/commonjs/lib/loader/AppWorkerLoader.d.ts +17 -0
  60. package/dist/commonjs/lib/loader/AppWorkerLoader.js +43 -0
  61. package/dist/commonjs/lib/loader/EggApplicationLoader.d.ts +4 -0
  62. package/dist/commonjs/lib/loader/EggApplicationLoader.js +8 -0
  63. package/dist/commonjs/lib/loader/index.d.ts +3 -0
  64. package/dist/commonjs/lib/loader/index.js +22 -0
  65. package/dist/commonjs/lib/start.d.ts +15 -0
  66. package/dist/commonjs/lib/start.js +49 -0
  67. package/dist/commonjs/lib/type.d.ts +296 -0
  68. package/dist/commonjs/lib/type.js +3 -0
  69. package/dist/commonjs/package.json +3 -0
  70. package/dist/esm/agent.d.ts +4 -0
  71. package/dist/esm/agent.js +7 -0
  72. package/dist/esm/app/extend/context.d.ts +2 -0
  73. package/dist/esm/app/extend/context.js +258 -0
  74. package/dist/esm/app/middleware/body_parser.d.ts +2 -0
  75. package/dist/esm/app/middleware/body_parser.js +3 -0
  76. package/dist/esm/app/middleware/meta.d.ts +11 -0
  77. package/dist/esm/app/middleware/meta.js +20 -0
  78. package/dist/esm/app/middleware/notfound.d.ts +8 -0
  79. package/dist/esm/app/middleware/notfound.js +29 -0
  80. package/dist/esm/app/middleware/override_method.d.ts +2 -0
  81. package/dist/esm/app/middleware/override_method.js +3 -0
  82. package/dist/esm/app/middleware/site_file.d.ts +7 -0
  83. package/dist/esm/app/middleware/site_file.js +54 -0
  84. package/dist/esm/config/config.default.d.ts +9 -0
  85. package/dist/esm/config/config.default.js +373 -0
  86. package/dist/esm/config/config.local.d.ts +8 -0
  87. package/dist/esm/config/config.local.js +10 -0
  88. package/dist/esm/config/config.unittest.d.ts +7 -0
  89. package/dist/esm/config/config.unittest.js +9 -0
  90. package/dist/esm/config/favicon.png +0 -0
  91. package/dist/esm/config/plugin.d.ts +122 -0
  92. package/dist/esm/config/plugin.js +123 -0
  93. package/dist/esm/index.d.ts +61 -0
  94. package/dist/esm/index.js +65 -0
  95. package/dist/esm/lib/agent.d.ts +19 -0
  96. package/dist/esm/lib/agent.js +54 -0
  97. package/dist/esm/lib/application.d.ts +66 -0
  98. package/dist/esm/lib/application.js +274 -0
  99. package/dist/esm/lib/core/base_context_class.d.ts +14 -0
  100. package/dist/esm/lib/core/base_context_class.js +18 -0
  101. package/dist/esm/lib/core/base_context_logger.d.ts +36 -0
  102. package/dist/esm/lib/core/base_context_logger.js +60 -0
  103. package/dist/esm/lib/core/base_hook_class.d.ts +11 -0
  104. package/dist/esm/lib/core/base_hook_class.js +23 -0
  105. package/dist/esm/lib/core/context_httpclient.d.ts +16 -0
  106. package/dist/esm/lib/core/context_httpclient.js +26 -0
  107. package/dist/esm/lib/core/httpclient.d.ts +14 -0
  108. package/dist/esm/lib/core/httpclient.js +33 -0
  109. package/dist/esm/lib/core/logger.d.ts +3 -0
  110. package/dist/esm/lib/core/logger.js +37 -0
  111. package/dist/esm/lib/core/messenger/IMessenger.d.ts +50 -0
  112. package/dist/esm/lib/core/messenger/IMessenger.js +2 -0
  113. package/dist/esm/lib/core/messenger/index.d.ts +7 -0
  114. package/dist/esm/lib/core/messenger/index.js +11 -0
  115. package/dist/esm/lib/core/messenger/ipc.d.ts +57 -0
  116. package/dist/esm/lib/core/messenger/ipc.js +119 -0
  117. package/dist/esm/lib/core/messenger/local.d.ts +61 -0
  118. package/dist/esm/lib/core/messenger/local.js +127 -0
  119. package/dist/esm/lib/core/singleton.d.ts +23 -0
  120. package/dist/esm/lib/core/singleton.js +113 -0
  121. package/dist/esm/lib/core/utils.d.ts +2 -0
  122. package/dist/esm/lib/core/utils.js +70 -0
  123. package/dist/esm/lib/egg.d.ts +271 -0
  124. package/dist/esm/lib/egg.js +573 -0
  125. package/dist/esm/lib/loader/AgentWorkerLoader.d.ts +12 -0
  126. package/dist/esm/lib/loader/AgentWorkerLoader.js +20 -0
  127. package/dist/esm/lib/loader/AppWorkerLoader.d.ts +17 -0
  128. package/dist/esm/lib/loader/AppWorkerLoader.js +39 -0
  129. package/dist/esm/lib/loader/EggApplicationLoader.d.ts +4 -0
  130. package/dist/esm/lib/loader/EggApplicationLoader.js +4 -0
  131. package/dist/esm/lib/loader/index.d.ts +3 -0
  132. package/dist/esm/lib/loader/index.js +4 -0
  133. package/dist/esm/lib/start.d.ts +15 -0
  134. package/dist/esm/lib/start.js +43 -0
  135. package/dist/esm/lib/type.d.ts +296 -0
  136. package/dist/esm/lib/type.js +2 -0
  137. package/dist/esm/package.json +3 -0
  138. package/dist/package.json +4 -0
  139. package/package.json +87 -72
  140. package/src/agent.ts +7 -0
  141. package/{app/extend/context.js → src/app/extend/context.ts} +19 -23
  142. package/src/app/middleware/body_parser.ts +3 -0
  143. package/{app/middleware/meta.js → src/app/middleware/meta.ts} +12 -4
  144. package/{app/middleware/notfound.js → src/app/middleware/notfound.ts} +9 -3
  145. package/src/app/middleware/override_method.ts +3 -0
  146. package/src/app/middleware/site_file.ts +70 -0
  147. package/{config/config.default.js → src/config/config.default.ts} +24 -45
  148. package/src/config/config.local.ts +11 -0
  149. package/src/config/config.unittest.ts +10 -0
  150. package/src/config/favicon.png +0 -0
  151. package/{config/plugin.js → src/config/plugin.ts} +1 -3
  152. package/src/index.ts +78 -0
  153. package/src/lib/agent.ts +66 -0
  154. package/{lib/application.js → src/lib/application.ts} +79 -120
  155. package/src/lib/core/base_context_class.ts +21 -0
  156. package/src/lib/core/base_context_logger.ts +67 -0
  157. package/src/lib/core/base_hook_class.ts +30 -0
  158. package/src/lib/core/context_httpclient.ts +33 -0
  159. package/src/lib/core/httpclient.ts +52 -0
  160. package/src/lib/core/logger.ts +42 -0
  161. package/src/lib/core/messenger/IMessenger.ts +58 -0
  162. package/src/lib/core/messenger/index.ts +15 -0
  163. package/{lib/core/messenger/ipc.js → src/lib/core/messenger/ipc.ts} +24 -29
  164. package/{lib/core/messenger/local.js → src/lib/core/messenger/local.ts} +27 -21
  165. package/{lib/core/singleton.js → src/lib/core/singleton.ts} +56 -33
  166. package/src/lib/core/utils.ts +77 -0
  167. package/{lib/egg.js → src/lib/egg.ts} +262 -219
  168. package/src/lib/loader/AgentWorkerLoader.ts +21 -0
  169. package/src/lib/loader/AppWorkerLoader.ts +42 -0
  170. package/src/lib/loader/EggApplicationLoader.ts +5 -0
  171. package/src/lib/loader/index.ts +3 -0
  172. package/src/lib/start.ts +56 -0
  173. package/src/lib/type.ts +336 -0
  174. package/CHANGELOG.md +0 -2395
  175. package/History.md +0 -52
  176. package/agent.js +0 -11
  177. package/app/middleware/body_parser.js +0 -3
  178. package/app/middleware/override_method.js +0 -3
  179. package/app/middleware/site_file.js +0 -31
  180. package/config/config.local.js +0 -7
  181. package/config/config.unittest.js +0 -8
  182. package/index.d.ts +0 -1288
  183. package/index.js +0 -68
  184. package/lib/agent.js +0 -95
  185. package/lib/core/base_context_class.js +0 -20
  186. package/lib/core/base_context_logger.js +0 -64
  187. package/lib/core/base_hook_class.js +0 -31
  188. package/lib/core/context_httpclient.js +0 -26
  189. package/lib/core/dnscache_httpclient.js +0 -93
  190. package/lib/core/httpclient.js +0 -119
  191. package/lib/core/httpclient_next.js +0 -80
  192. package/lib/core/logger.js +0 -35
  193. package/lib/core/messenger/index.js +0 -14
  194. package/lib/core/utils.js +0 -73
  195. package/lib/loader/agent_worker_loader.js +0 -27
  196. package/lib/loader/app_worker_loader.js +0 -48
  197. package/lib/loader/index.js +0 -5
  198. package/lib/start.js +0 -39
  199. /package/{config → dist/commonjs/config}/favicon.png +0 -0
  200. /package/{app → src/app}/extend/helper.js +0 -0
  201. /package/{app → src/app}/extend/request.js +0 -0
  202. /package/{app → src/app}/extend/response.js +0 -0
@@ -1,37 +1,120 @@
1
- const { performance } = require('perf_hooks');
2
- const path = require('path');
3
- const fs = require('fs');
4
- const ms = require('ms');
5
- const http = require('http');
6
- const EggCore = require('egg-core').EggCore;
7
- const cluster = require('cluster-client');
8
- const extend = require('extend2');
9
- const ContextLogger = require('egg-logger').EggContextLogger;
10
- const ContextCookies = require('egg-cookies');
11
- const CircularJSON = require('circular-json-for-egg');
12
- const ContextHttpClient = require('./core/context_httpclient');
13
- const Messenger = require('./core/messenger');
14
- const DNSCacheHttpClient = require('./core/dnscache_httpclient');
15
- const HttpClient = require('./core/httpclient');
16
- const HttpClientNext = require('./core/httpclient_next');
17
- const createLoggers = require('./core/logger');
18
- const Singleton = require('./core/singleton');
19
- const utils = require('./core/utils');
20
- const BaseContextClass = require('./core/base_context_class');
21
- const BaseHookClass = require('./core/base_hook_class');
22
-
23
- const HTTPCLIENT = Symbol('EggApplication#httpclient');
24
- const LOGGERS = Symbol('EggApplication#loggers');
1
+ import { performance } from 'node:perf_hooks';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import http, { type IncomingMessage, type ServerResponse } from 'node:http';
5
+ import inspector from 'node:inspector';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { EggCore, type EggCoreContext, type EggCoreOptions } from '@eggjs/core';
8
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
9
+ // @ts-ignore
10
+ import createClusterClient, { close as closeClusterClient } from 'cluster-client';
11
+ import { extend } from 'extend2';
12
+ import { EggContextLogger as ContextLogger, EggLoggers, EggLogger } from 'egg-logger';
13
+ import { Cookies as ContextCookies } from '@eggjs/cookies';
14
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
15
+ // @ts-ignore
16
+ import CircularJSON from 'circular-json-for-egg';
17
+ import type { Agent } from './agent.js';
18
+ import type { Application } from './application.js';
19
+ import type { EggAppConfig } from './type.js';
20
+ import { create as createMessenger, IMessenger } from './core/messenger/index.js';
21
+ import { ContextHttpClient } from './core/context_httpclient.js';
22
+ import {
23
+ HttpClient, type HttpClientRequestOptions, type HttpClientRequestURL, type HttpClientResponse,
24
+ } from './core/httpclient.js';
25
+ import { createLoggers } from './core/logger.js';
26
+ import {
27
+ Singleton, type SingletonCreateMethod, type SingletonOptions,
28
+ } from './core/singleton.js';
29
+ import { convertObject } from './core/utils.js';
30
+ import { BaseContextClass } from './core/base_context_class.js';
31
+ import { BaseHookClass } from './core/base_hook_class.js';
32
+ import type { EggApplicationLoader } from './loader/index.js';
33
+
25
34
  const EGG_PATH = Symbol.for('egg#eggPath');
26
- const CLUSTER_CLIENTS = Symbol.for('egg#clusterClients');
35
+
36
+ export interface EggApplicationCoreOptions extends Omit<EggCoreOptions, 'baseDir'> {
37
+ mode?: 'cluster' | 'single';
38
+ clusterPort?: number;
39
+ baseDir?: string;
40
+ }
41
+
42
+ export interface EggContext extends EggCoreContext {
43
+ app: EggApplicationCore;
44
+ /**
45
+ * Request start time
46
+ * @member {Number} Context#starttime
47
+ */
48
+ starttime: number;
49
+ /**
50
+ * Request start timer using `performance.now()`
51
+ * @member {Number} Context#performanceStarttime
52
+ */
53
+ performanceStarttime: number;
54
+ }
27
55
 
28
56
  /**
29
57
  * Based on koa's Application
30
58
  * @see https://github.com/eggjs/egg-core
31
- * @see http://koajs.com/#application
59
+ * @see https://github.com/eggjs/koa/blob/master/src/application.ts
32
60
  * @augments EggCore
33
61
  */
34
- class EggApplication extends EggCore {
62
+ export class EggApplicationCore extends EggCore {
63
+ // export context base classes, let framework can impl sub class and over context extend easily.
64
+ ContextCookies = ContextCookies;
65
+ ContextLogger = ContextLogger;
66
+ ContextHttpClient = ContextHttpClient;
67
+ HttpClient = HttpClient;
68
+ /**
69
+ * Retrieve base context class
70
+ * @member {BaseContextClass} BaseContextClass
71
+ * @since 1.0.0
72
+ */
73
+ BaseContextClass = BaseContextClass;
74
+
75
+ /**
76
+ * Retrieve base controller
77
+ * @member {Controller} Controller
78
+ * @since 1.0.0
79
+ */
80
+ Controller = BaseContextClass;
81
+
82
+ /**
83
+ * Retrieve base service
84
+ * @member {Service} Service
85
+ * @since 1.0.0
86
+ */
87
+ Service = BaseContextClass;
88
+
89
+ /**
90
+ * Retrieve base subscription
91
+ * @member {Subscription} Subscription
92
+ * @since 2.12.0
93
+ */
94
+ Subscription = BaseContextClass;
95
+
96
+ /**
97
+ * Retrieve base context class
98
+ * @member {BaseHookClass} BaseHookClass
99
+ */
100
+ BaseHookClass = BaseHookClass;
101
+
102
+ /**
103
+ * Retrieve base boot
104
+ * @member {Boot}
105
+ */
106
+ Boot = BaseHookClass;
107
+
108
+ declare options: Required<EggApplicationCoreOptions>;
109
+
110
+ #httpClient?: HttpClient;
111
+ #loggers?: EggLoggers;
112
+ #clusterClients: any[] = [];
113
+
114
+ readonly messenger: IMessenger;
115
+ agent?: Agent;
116
+ application?: Application;
117
+ declare loader: EggApplicationLoader;
35
118
 
36
119
  /**
37
120
  * @class
@@ -41,91 +124,73 @@ class EggApplication extends EggCore {
41
124
  * - {Object} [plugins] - custom plugin config, use it in unittest
42
125
  * - {String} [mode] - process mode, can be cluster / single, default is `cluster`
43
126
  */
44
- constructor(options = {}) {
45
- options.mode = options.mode || 'cluster';
127
+ constructor(options?: EggApplicationCoreOptions) {
128
+ options = {
129
+ mode: 'cluster',
130
+ type: 'application',
131
+ baseDir: process.cwd(),
132
+ ...options,
133
+ };
46
134
  super(options);
47
-
48
- // export context base classes, let framework can impl sub class and over context extend easily.
49
- this.ContextCookies = ContextCookies;
50
- this.ContextLogger = ContextLogger;
51
- this.ContextHttpClient = ContextHttpClient;
52
- this.HttpClient = HttpClient;
53
- this.HttpClientNext = HttpClientNext;
54
-
55
- this.loader.loadConfig();
56
-
57
135
  /**
58
136
  * messenger instance
59
137
  * @member {Messenger}
60
138
  * @since 1.0.0
61
139
  */
62
- this.messenger = Messenger.create(this);
140
+ this.messenger = createMessenger(this);
63
141
 
64
142
  // trigger `serverDidReady` hook when all the app workers
65
143
  // and agent worker are ready
66
144
  this.messenger.once('egg-ready', () => {
67
145
  this.lifecycle.triggerServerDidReady();
68
146
  });
147
+ this.lifecycle.registerBeforeStart(async () => {
148
+ await this.load();
149
+ }, 'load files');
150
+ }
69
151
 
152
+ /**
153
+ * @deprecated please use `options` property instead
154
+ */
155
+ get _options() {
156
+ return this.options;
157
+ }
158
+
159
+ protected async loadConfig() {
160
+ await this.loader.loadConfig();
161
+ }
162
+
163
+ protected async load() {
164
+ await this.loadConfig();
70
165
  // dump config after ready, ensure all the modifications during start will be recorded
71
166
  // make sure dumpConfig is the last ready callback
72
167
  this.ready(() => process.nextTick(() => {
73
168
  const dumpStartTime = Date.now();
74
169
  this.dumpConfig();
75
170
  this.dumpTiming();
76
- this.coreLogger.info('[egg:core] dump config after ready, %s', ms(Date.now() - dumpStartTime));
171
+ this.coreLogger.info('[egg] dump config after ready, %sms', Date.now() - dumpStartTime);
77
172
  }));
78
- this._setupTimeoutTimer();
173
+ this.#setupTimeoutTimer();
79
174
 
80
- this.console.info('[egg:core] App root: %s', this.baseDir);
81
- this.console.info('[egg:core] All *.log files save on %j', this.config.logger.dir);
82
- this.console.info('[egg:core] Loaded enabled plugin %j', this.loader.orderPlugins);
175
+ this.console.info('[egg] App root: %s', this.baseDir);
176
+ this.console.info('[egg] All *.log files save on %j', this.config.logger.dir);
177
+ this.console.info('[egg] Loaded enabled plugin %j', this.loader.orderPlugins);
83
178
 
84
179
  // Listen the error that promise had not catch, then log it in common-error
85
180
  this._unhandledRejectionHandler = this._unhandledRejectionHandler.bind(this);
86
181
  process.on('unhandledRejection', this._unhandledRejectionHandler);
87
182
 
88
- this[CLUSTER_CLIENTS] = [];
89
-
90
- /**
91
- * Wrap the Client with Leader/Follower Pattern
92
- *
93
- * @description almost the same as Agent.cluster API, the only different is that this method create Follower.
94
- *
95
- * @see https://github.com/node-modules/cluster-client
96
- * @param {Function} clientClass - client class function
97
- * @param {Object} [options]
98
- * - {Boolean} [autoGenerate] - whether generate delegate rule automatically, default is true
99
- * - {Function} [formatKey] - a method to tranform the subscription info into a string,default is JSON.stringify
100
- * - {Object} [transcode|JSON.stringify/parse]
101
- * - {Function} encode - custom serialize method
102
- * - {Function} decode - custom deserialize method
103
- * - {Boolean} [isBroadcast] - whether broadcast subscrption result to all followers or just one, default is true
104
- * - {Number} [responseTimeout] - response timeout, default is 3 seconds
105
- * - {Number} [maxWaitTime|30000] - leader startup max time, default is 30 seconds
106
- * @return {ClientWrapper} wrapper
107
- */
108
- this.cluster = (clientClass, options) => {
109
- options = Object.assign({}, this.config.clusterClient, options, {
110
- singleMode: this.options.mode === 'single',
111
- // cluster need a port that can't conflict on the environment
112
- port: this.options.clusterPort,
113
- // agent worker is leader, app workers are follower
114
- isLeader: this.type === 'agent',
115
- logger: this.coreLogger,
116
- // debug mode does not check heartbeat
117
- isCheckHeartbeat: this.config.env === 'prod' ? true : require('inspector').url() === undefined,
118
- });
119
- const client = cluster(clientClass, options);
120
- this._patchClusterClient(client);
121
- return client;
122
- };
123
-
124
183
  // register close function
125
- this.beforeClose(async () => {
184
+ this.lifecycle.registerBeforeClose(async () => {
185
+ // close all cluster clients
186
+ for (const clusterClient of this.#clusterClients) {
187
+ await closeClusterClient(clusterClient);
188
+ }
189
+ this.#clusterClients = [];
190
+
126
191
  // single process mode will close agent before app close
127
192
  if (this.type === 'application' && this.options.mode === 'single') {
128
- await this.agent.close();
193
+ await this.agent!.close();
129
194
  }
130
195
 
131
196
  for (const logger of this.loggers.values()) {
@@ -135,45 +200,43 @@ class EggApplication extends EggCore {
135
200
  process.removeListener('unhandledRejection', this._unhandledRejectionHandler);
136
201
  });
137
202
 
138
- /**
139
- * Retreive base context class
140
- * @member {BaseContextClass} BaseContextClass
141
- * @since 1.0.0
142
- */
143
- this.BaseContextClass = BaseContextClass;
144
-
145
- /**
146
- * Retreive base controller
147
- * @member {Controller} Controller
148
- * @since 1.0.0
149
- */
150
- this.Controller = BaseContextClass;
151
-
152
- /**
153
- * Retreive base service
154
- * @member {Service} Service
155
- * @since 1.0.0
156
- */
157
- this.Service = BaseContextClass;
158
-
159
- /**
160
- * Retreive base subscription
161
- * @member {Subscription} Subscription
162
- * @since 2.12.0
163
- */
164
- this.Subscription = BaseContextClass;
165
-
166
- /**
167
- * Retreive base context class
168
- * @member {BaseHookClass} BaseHookClass
169
- */
170
- this.BaseHookClass = BaseHookClass;
203
+ await this.loader.load();
204
+ }
171
205
 
172
- /**
173
- * Retreive base boot
174
- * @member {Boot}
175
- */
176
- this.Boot = BaseHookClass;
206
+ /**
207
+ * Wrap the Client with Leader/Follower Pattern
208
+ *
209
+ * @description almost the same as Agent.cluster API, the only different is that this method create Follower.
210
+ *
211
+ * @see https://github.com/node-modules/cluster-client
212
+ * @param {Function} clientClass - client class function
213
+ * @param {Object} [options]
214
+ * - {Boolean} [autoGenerate] - whether generate delegate rule automatically, default is true
215
+ * - {Function} [formatKey] - a method to transform the subscription info into a string,default is JSON.stringify
216
+ * - {Object} [transcode|JSON.stringify/parse]
217
+ * - {Function} encode - custom serialize method
218
+ * - {Function} decode - custom deserialize method
219
+ * - {Boolean} [isBroadcast] - whether broadcast subscription result to all followers or just one, default is true
220
+ * - {Number} [responseTimeout] - response timeout, default is 3 seconds
221
+ * - {Number} [maxWaitTime|30000] - leader startup max time, default is 30 seconds
222
+ * @return {ClientWrapper} wrapper
223
+ */
224
+ cluster(clientClass: unknown, options: object) {
225
+ const clientClassOptions = {
226
+ ...this.config.clusterClient,
227
+ ...options,
228
+ singleMode: this.options.mode === 'single',
229
+ // cluster need a port that can't conflict on the environment
230
+ port: this.options.clusterPort,
231
+ // agent worker is leader, app workers are follower
232
+ isLeader: this.type === 'agent',
233
+ logger: this.coreLogger,
234
+ // debug mode does not check heartbeat
235
+ isCheckHeartbeat: this.config.env === 'prod' ? true : inspector.url() === undefined,
236
+ };
237
+ const client = createClusterClient(clientClass, clientClassOptions);
238
+ this.#patchClusterClient(client);
239
+ return client;
177
240
  }
178
241
 
179
242
  /**
@@ -185,7 +248,7 @@ class EggApplication extends EggCore {
185
248
  * console.log(app);
186
249
  * =>
187
250
  * {
188
- * name: 'mockapp',
251
+ * name: 'mock-app',
189
252
  * env: 'test',
190
253
  * subdomainOffset: 2,
191
254
  * config: '<egg config>',
@@ -197,23 +260,21 @@ class EggApplication extends EggCore {
197
260
  * }
198
261
  * ```
199
262
  */
200
- inspect() {
263
+ inspect(): any {
201
264
  const res = {
202
265
  env: this.config.env,
203
266
  };
204
267
 
205
- function delegate(res, app, keys) {
268
+ function delegate(res: any, app: any, keys: string[]) {
206
269
  for (const key of keys) {
207
- /* istanbul ignore else */
208
270
  if (app[key]) {
209
271
  res[key] = app[key];
210
272
  }
211
273
  }
212
274
  }
213
275
 
214
- function abbr(res, app, keys) {
276
+ function abbr(res: any, app: any, keys: string[]) {
215
277
  for (const key of keys) {
216
- /* istanbul ignore else */
217
278
  if (app[key]) {
218
279
  res[key] = `<egg ${key}>`;
219
280
  }
@@ -250,13 +311,13 @@ class EggApplication extends EggCore {
250
311
  * See https://github.com/node-modules/urllib#api-doc for more details.
251
312
  *
252
313
  * @param {String} url request url address.
253
- * @param {Object} opts
314
+ * @param {Object} options
254
315
  * - method {String} - Request method, defaults to GET. Could be GET, POST, DELETE or PUT. Alias 'type'.
255
316
  * - data {Object} - Data to be sent. Will be stringify automatically.
256
317
  * - dataType {String} - String - Type of response data. Could be `text` or `json`.
257
- * If it's `text`, the callbacked data would be a String.
318
+ * If it's `text`, the callback data would be a String.
258
319
  * If it's `json`, the data of callback would be a parsed JSON Object.
259
- * Default callbacked data would be a Buffer.
320
+ * Default callback data would be a Buffer.
260
321
  * - headers {Object} - Request headers.
261
322
  * - timeout {Number} - Request timeout in milliseconds. Defaults to exports.TIMEOUT.
262
323
  * Include remote server connecting timeout and response timeout.
@@ -266,10 +327,10 @@ class EggApplication extends EggCore {
266
327
  * - gzip {Boolean} - let you get the res object when request connected, default false. alias customResponse
267
328
  * - nestedQuerystring {Boolean} - urllib default use querystring to stringify form data which don't
268
329
  * support nested object, will use qs instead of querystring to support nested object by set this option to true.
269
- * - more options see https://www.npmjs.com/package/urllib
330
+ * - more options see https://github.com/node-modules/urllib
270
331
  * @return {Object}
271
332
  * - status {Number} - HTTP response status
272
- * - headers {Object} - HTTP response seaders
333
+ * - headers {Object} - HTTP response headers
273
334
  * - res {Object} - HTTP response meta
274
335
  * - data {Object} - HTTP response body
275
336
  *
@@ -282,24 +343,8 @@ class EggApplication extends EggCore {
282
343
  * console.log(result.status, result.headers, result.data);
283
344
  * ```
284
345
  */
285
- async curl(url, opts) {
286
- return await this.httpclient.request(url, opts);
287
- }
288
-
289
- /**
290
- * Create a new HttpClient instance with custom options
291
- * @param {Object} [options] HttpClient init options
292
- */
293
- createHttpClient(options) {
294
- let httpClient;
295
- if (this.config.httpclient.useHttpClientNext || this.config.httpclient.allowH2) {
296
- httpClient = new this.HttpClientNext(this, options);
297
- } else if (this.config.httpclient.enableDNSCache) {
298
- httpClient = new DNSCacheHttpClient(this, options);
299
- } else {
300
- httpClient = new this.HttpClient(this, options);
301
- }
302
- return httpClient;
346
+ async curl<T = any>(url: HttpClientRequestURL, options?: HttpClientRequestOptions): Promise<HttpClientResponse<T>> {
347
+ return await this.httpClient.request<T>(url, options);
303
348
  }
304
349
 
305
350
  /**
@@ -307,31 +352,32 @@ class EggApplication extends EggCore {
307
352
  * @see https://github.com/node-modules/urllib
308
353
  * @member {HttpClient}
309
354
  */
310
- get httpclient() {
311
- if (!this[HTTPCLIENT]) {
312
- this[HTTPCLIENT] = this.createHttpClient();
355
+ get httpClient() {
356
+ if (!this.#httpClient) {
357
+ this.#httpClient = new this.HttpClient(this);
313
358
  }
314
- return this[HTTPCLIENT];
359
+ return this.#httpClient;
315
360
  }
316
361
 
317
362
  /**
318
- * @alias httpclient
363
+ * @deprecated please use httpClient instead
364
+ * @alias httpClient
319
365
  * @member {HttpClient}
320
366
  */
321
- get httpClient() {
322
- return this.httpclient;
367
+ get httpclient() {
368
+ return this.httpClient;
323
369
  }
324
370
 
325
371
  /**
326
- * All loggers contain logger, coreLogger and customLogger
372
+ * All loggers contain logger, coreLogger and customLogger
327
373
  * @member {Object}
328
374
  * @since 1.0.0
329
375
  */
330
376
  get loggers() {
331
- if (!this[LOGGERS]) {
332
- this[LOGGERS] = createLoggers(this);
377
+ if (!this.#loggers) {
378
+ this.#loggers = createLoggers(this);
333
379
  }
334
- return this[LOGGERS];
380
+ return this.#loggers;
335
381
  }
336
382
 
337
383
  /**
@@ -340,7 +386,7 @@ class EggApplication extends EggCore {
340
386
  * @param {String} name - logger name
341
387
  * @return {Logger} logger
342
388
  */
343
- getLogger(name) {
389
+ getLogger(name: string): EggLogger {
344
390
  return this.loggers[name] || null;
345
391
  }
346
392
 
@@ -362,7 +408,7 @@ class EggApplication extends EggCore {
362
408
  return this.getLogger('coreLogger');
363
409
  }
364
410
 
365
- _unhandledRejectionHandler(err) {
411
+ _unhandledRejectionHandler(err: any) {
366
412
  if (!(err instanceof Error)) {
367
413
  const newError = new Error(String(err));
368
414
  // err maybe an object, try to copy the name, message and stack to the new error instance
@@ -384,21 +430,23 @@ class EggApplication extends EggCore {
384
430
  /**
385
431
  * dump out the config and meta object
386
432
  * @private
387
- * @return {Object} the result
388
433
  */
389
434
  dumpConfigToObject() {
390
- let ignoreList;
435
+ let ignoreList: (string | RegExp)[];
391
436
  try {
392
437
  // support array and set
393
438
  ignoreList = Array.from(this.config.dump.ignore);
394
439
  } catch (_) {
395
440
  ignoreList = [];
396
441
  }
397
-
398
- const json = extend(true, {}, { config: this.config, plugins: this.loader.allPlugins, appInfo: this.loader.appInfo });
399
- utils.convertObject(json, ignoreList);
442
+ const config = extend(true, {}, {
443
+ config: this.config,
444
+ plugins: this.loader.allPlugins,
445
+ appInfo: this.loader.appInfo,
446
+ });
447
+ convertObject(config, ignoreList);
400
448
  return {
401
- config: json,
449
+ config,
402
450
  meta: this.loader.configMeta,
403
451
  };
404
452
  }
@@ -410,10 +458,11 @@ class EggApplication extends EggCore {
410
458
  dumpConfig() {
411
459
  const rundir = this.config.rundir;
412
460
  try {
413
- /* istanbul ignore if */
414
- if (!fs.existsSync(rundir)) fs.mkdirSync(rundir);
461
+ if (!fs.existsSync(rundir)) {
462
+ fs.mkdirSync(rundir);
463
+ }
415
464
 
416
- // get dumpped object
465
+ // get dumped object
417
466
  const { config, meta } = this.dumpConfigToObject();
418
467
 
419
468
  // dump config
@@ -423,8 +472,8 @@ class EggApplication extends EggCore {
423
472
  // dump config meta
424
473
  const dumpMetaFile = path.join(rundir, `${this.type}_config_meta.json`);
425
474
  fs.writeFileSync(dumpMetaFile, CircularJSON.stringify(meta, null, 2));
426
- } catch (err) {
427
- this.coreLogger.warn(`dumpConfig error: ${err.message}`);
475
+ } catch (err: any) {
476
+ this.coreLogger.warn(`[egg] dumpConfig error: ${err.message}`);
428
477
  }
429
478
  }
430
479
 
@@ -437,24 +486,29 @@ class EggApplication extends EggCore {
437
486
  this.coreLogger.info(this.timing.toString());
438
487
  // only disable, not clear bootstrap timing data.
439
488
  this.timing.disable();
440
- // show duration >= ${slowBootActionMinDuration}ms action to warnning log
489
+ // show duration >= ${slowBootActionMinDuration}ms action to warning log
441
490
  for (const item of items) {
442
491
  // ignore #0 name: Process Start
443
- if (item.index > 0 && item.duration >= this.config.dump.timing.slowBootActionMinDuration) {
444
- this.coreLogger.warn('[egg:core][slow-boot-action] #%d %dms, name: %s',
492
+ if (item.index > 0 && item.duration && item.duration >= this.config.dump.timing.slowBootActionMinDuration) {
493
+ this.coreLogger.warn('[egg][dumpTiming][slow-boot-action] #%d %dms, name: %s',
445
494
  item.index, item.duration, item.name);
446
495
  }
447
496
  }
448
- } catch (err) {
449
- this.coreLogger.warn(`dumpTiming error: ${err.message}`);
497
+ } catch (err: any) {
498
+ this.coreLogger.warn(`[egg] dumpTiming error: ${err.message}`);
450
499
  }
451
500
  }
452
501
 
453
502
  get [EGG_PATH]() {
454
- return path.join(__dirname, '..');
503
+ if (typeof __dirname !== 'undefined') {
504
+ return path.dirname(__dirname);
505
+ }
506
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
507
+ // @ts-ignore
508
+ return path.dirname(path.dirname(fileURLToPath(import.meta.url)));
455
509
  }
456
510
 
457
- _setupTimeoutTimer() {
511
+ #setupTimeoutTimer() {
458
512
  const startTimeoutTimer = setTimeout(() => {
459
513
  this.coreLogger.error(this.timing.toString());
460
514
  this.coreLogger.error(`${this.type} still doesn't ready after ${this.config.workerStartTimeout} ms.`);
@@ -464,7 +518,8 @@ class EggApplication extends EggCore {
464
518
  if (item.end) continue;
465
519
  this.coreLogger.error(`unfinished timing item: ${CircularJSON.stringify(item)}`);
466
520
  }
467
- this.coreLogger.error(`check run/${this.type}_timing_${process.pid}.json for more details.`);
521
+ this.coreLogger.error('[egg][setupTimeoutTimer] check run/%s_timing_%s.json for more details.',
522
+ this.type, process.pid);
468
523
  this.emit('startTimeout');
469
524
  this.dumpConfig();
470
525
  this.dumpTiming();
@@ -472,6 +527,10 @@ class EggApplication extends EggCore {
472
527
  this.ready(() => clearTimeout(startTimeoutTimer));
473
528
  }
474
529
 
530
+ get config() {
531
+ return super.config as EggAppConfig;
532
+ }
533
+
475
534
  /**
476
535
  * app.env delegate app.config.env
477
536
  * @deprecated
@@ -488,7 +547,7 @@ class EggApplication extends EggCore {
488
547
  * @deprecated
489
548
  */
490
549
  get proxy() {
491
- this.deprecate('please use app.config.proxy instead');
550
+ // this.deprecate('please use app.config.proxy instead');
492
551
  return this.config.proxy;
493
552
  }
494
553
  /* eslint no-empty-function: off */
@@ -499,11 +558,12 @@ class EggApplication extends EggCore {
499
558
  * @param {String} name - unique name for singleton
500
559
  * @param {Function|AsyncFunction} create - method will be invoked when singleton instance create
501
560
  */
502
- addSingleton(name, create) {
503
- const options = {};
504
- options.name = name;
505
- options.create = create;
506
- options.app = this;
561
+ addSingleton(name: string, create: SingletonCreateMethod) {
562
+ const options: SingletonOptions = {
563
+ name,
564
+ create,
565
+ app: this,
566
+ };
507
567
  const singleton = new Singleton(options);
508
568
  const initPromise = singleton.init();
509
569
  if (initPromise) {
@@ -513,12 +573,11 @@ class EggApplication extends EggCore {
513
573
  }
514
574
  }
515
575
 
516
- _patchClusterClient(client) {
517
- const create = client.create;
518
- client.create = (...args) => {
519
- const realClient = create.apply(client, args);
520
- this[CLUSTER_CLIENTS].push(realClient);
521
- this.beforeClose(() => cluster.close(realClient));
576
+ #patchClusterClient(client: any) {
577
+ const rawCreate = client.create;
578
+ client.create = (...args: any) => {
579
+ const realClient = rawCreate.apply(client, args);
580
+ this.#clusterClients.push(realClient);
522
581
  return realClient;
523
582
  };
524
583
  }
@@ -530,8 +589,8 @@ class EggApplication extends EggCore {
530
589
  * @param {Request} [req] - if you want to mock request like querystring, you can pass an object to this function.
531
590
  * @return {Context} context
532
591
  */
533
- createAnonymousContext(req) {
534
- const request = {
592
+ createAnonymousContext(req?: any): EggCoreContext {
593
+ const request: any = {
535
594
  headers: {
536
595
  host: '127.0.0.1',
537
596
  'x-forwarded-for': '127.0.0.1',
@@ -570,36 +629,20 @@ class EggApplication extends EggCore {
570
629
  * @param {Res} res - node native Response object
571
630
  * @return {Context} context object
572
631
  */
573
- createContext(req, res) {
574
- const app = this;
575
- const context = Object.create(app.context);
576
- const request = context.request = Object.create(app.request);
577
- const response = context.response = Object.create(app.response);
578
- context.app = request.app = response.app = app;
632
+ createContext(req: IncomingMessage, res: ServerResponse): EggContext {
633
+ const context = Object.create(this.context) as EggContext;
634
+ const request = context.request = Object.create(this.request);
635
+ const response = context.response = Object.create(this.response);
636
+ context.app = request.app = response.app = this;
579
637
  context.req = request.req = response.req = req;
580
638
  context.res = request.res = response.res = res;
581
639
  request.ctx = response.ctx = context;
582
640
  request.response = response;
583
641
  response.request = request;
584
642
  context.onerror = context.onerror.bind(context);
585
- context.originalUrl = request.originalUrl = req.url;
586
-
587
- /**
588
- * Request start time
589
- * @member {Number} Context#starttime
590
- */
643
+ context.originalUrl = request.originalUrl = req.url as string;
591
644
  context.starttime = Date.now();
592
-
593
- if (this.config.logger.enablePerformanceTimer) {
594
- /**
595
- * Request start timer using `performance.now()`
596
- * @member {Number} Context#performanceStarttime
597
- */
598
- context.performanceStarttime = performance.now();
599
- }
645
+ context.performanceStarttime = performance.now();
600
646
  return context;
601
647
  }
602
-
603
648
  }
604
-
605
- module.exports = EggApplication;