egg 3.26.0 → 4.0.0-beta.0

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