@eggjs/core 6.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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +296 -0
  3. package/dist/commonjs/base_context_class.d.ts +16 -0
  4. package/dist/commonjs/base_context_class.js +41 -0
  5. package/dist/commonjs/egg.d.ts +204 -0
  6. package/dist/commonjs/egg.js +346 -0
  7. package/dist/commonjs/index.d.ts +5 -0
  8. package/dist/commonjs/index.js +26 -0
  9. package/dist/commonjs/lifecycle.d.ts +75 -0
  10. package/dist/commonjs/lifecycle.js +306 -0
  11. package/dist/commonjs/loader/context_loader.d.ts +24 -0
  12. package/dist/commonjs/loader/context_loader.js +109 -0
  13. package/dist/commonjs/loader/egg_loader.d.ts +405 -0
  14. package/dist/commonjs/loader/egg_loader.js +1497 -0
  15. package/dist/commonjs/loader/file_loader.d.ts +96 -0
  16. package/dist/commonjs/loader/file_loader.js +248 -0
  17. package/dist/commonjs/package.json +3 -0
  18. package/dist/commonjs/types.d.ts +1 -0
  19. package/dist/commonjs/types.js +403 -0
  20. package/dist/commonjs/utils/index.d.ts +14 -0
  21. package/dist/commonjs/utils/index.js +146 -0
  22. package/dist/commonjs/utils/sequencify.d.ts +13 -0
  23. package/dist/commonjs/utils/sequencify.js +59 -0
  24. package/dist/commonjs/utils/timing.d.ts +22 -0
  25. package/dist/commonjs/utils/timing.js +100 -0
  26. package/dist/esm/base_context_class.d.ts +16 -0
  27. package/dist/esm/base_context_class.js +37 -0
  28. package/dist/esm/egg.d.ts +204 -0
  29. package/dist/esm/egg.js +339 -0
  30. package/dist/esm/index.d.ts +5 -0
  31. package/dist/esm/index.js +6 -0
  32. package/dist/esm/lifecycle.d.ts +75 -0
  33. package/dist/esm/lifecycle.js +276 -0
  34. package/dist/esm/loader/context_loader.d.ts +24 -0
  35. package/dist/esm/loader/context_loader.js +102 -0
  36. package/dist/esm/loader/egg_loader.d.ts +405 -0
  37. package/dist/esm/loader/egg_loader.js +1490 -0
  38. package/dist/esm/loader/file_loader.d.ts +96 -0
  39. package/dist/esm/loader/file_loader.js +241 -0
  40. package/dist/esm/package.json +3 -0
  41. package/dist/esm/types.d.ts +1 -0
  42. package/dist/esm/types.js +402 -0
  43. package/dist/esm/utils/index.d.ts +14 -0
  44. package/dist/esm/utils/index.js +141 -0
  45. package/dist/esm/utils/sequencify.d.ts +13 -0
  46. package/dist/esm/utils/sequencify.js +56 -0
  47. package/dist/esm/utils/timing.d.ts +22 -0
  48. package/dist/esm/utils/timing.js +93 -0
  49. package/package.json +103 -0
  50. package/src/base_context_class.ts +39 -0
  51. package/src/egg.ts +430 -0
  52. package/src/index.ts +6 -0
  53. package/src/lifecycle.ts +363 -0
  54. package/src/loader/context_loader.ts +121 -0
  55. package/src/loader/egg_loader.ts +1703 -0
  56. package/src/loader/file_loader.ts +295 -0
  57. package/src/types.ts +447 -0
  58. package/src/utils/index.ts +154 -0
  59. package/src/utils/sequencify.ts +70 -0
  60. package/src/utils/timing.ts +114 -0
@@ -0,0 +1,93 @@
1
+ import { EOL } from 'node:os';
2
+ import { debuglog } from 'node:util';
3
+ import assert from 'node:assert';
4
+ const debug = debuglog('@eggjs/core:utils:timing');
5
+ export class Timing {
6
+ #enable;
7
+ #startTime;
8
+ #map;
9
+ #list;
10
+ constructor() {
11
+ this.#enable = true;
12
+ this.#startTime = null;
13
+ this.#map = new Map();
14
+ this.#list = [];
15
+ this.init();
16
+ }
17
+ init() {
18
+ // process start time
19
+ this.start('Process Start', Date.now() - Math.floor(process.uptime() * 1000));
20
+ this.end('Process Start');
21
+ if ('scriptStartTime' in process && typeof process.scriptStartTime === 'number') {
22
+ // js script start execute time
23
+ this.start('Script Start', process.scriptStartTime);
24
+ this.end('Script Start');
25
+ }
26
+ }
27
+ start(name, start) {
28
+ if (!name || !this.#enable)
29
+ return;
30
+ if (this.#map.has(name)) {
31
+ this.end(name);
32
+ }
33
+ start = start || Date.now();
34
+ if (this.#startTime === null) {
35
+ this.#startTime = start;
36
+ }
37
+ const item = {
38
+ name,
39
+ start,
40
+ pid: process.pid,
41
+ index: this.#list.length,
42
+ };
43
+ this.#map.set(name, item);
44
+ this.#list.push(item);
45
+ debug('start %j', item);
46
+ return item;
47
+ }
48
+ end(name) {
49
+ if (!name || !this.#enable)
50
+ return;
51
+ assert(this.#map.has(name), `should run timing.start('${name}') first`);
52
+ const item = this.#map.get(name);
53
+ item.end = Date.now();
54
+ item.duration = item.end - item.start;
55
+ debug('end %j', item);
56
+ return item;
57
+ }
58
+ enable() {
59
+ this.#enable = true;
60
+ }
61
+ disable() {
62
+ this.#enable = false;
63
+ }
64
+ clear() {
65
+ this.#map.clear();
66
+ this.#list = [];
67
+ }
68
+ toJSON() {
69
+ return this.#list;
70
+ }
71
+ itemToString(timelineEnd, item, times) {
72
+ const isEnd = typeof item.duration === 'number';
73
+ const duration = isEnd ? item.duration : timelineEnd - item.start;
74
+ const offset = item.start - this.#startTime;
75
+ const status = `${duration}ms${isEnd ? '' : ' NOT_END'}`;
76
+ const timespan = Math.floor(Number((offset * times).toFixed(6)));
77
+ let timeline = Math.floor(Number((duration * times).toFixed(6)));
78
+ timeline = timeline > 0 ? timeline : 1; // make sure there is at least one unit
79
+ const message = `#${item.index} ${item.name}`;
80
+ return ' '.repeat(timespan) + '▇'.repeat(timeline) + ` [${status}] - ${message}`;
81
+ }
82
+ toString(prefix = 'egg start timeline:', width = 50) {
83
+ const timelineEnd = Date.now();
84
+ const timelineDuration = timelineEnd - this.#startTime;
85
+ let times = 1;
86
+ if (timelineDuration > width) {
87
+ times = width / timelineDuration;
88
+ }
89
+ // follow https://github.com/node-modules/time-profile/blob/master/lib/profiler.js#L88
90
+ return prefix + EOL + this.#list.map(item => this.itemToString(timelineEnd, item, times)).join(EOL);
91
+ }
92
+ }
93
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL3RpbWluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQzlCLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckMsT0FBTyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBRWpDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBV25ELE1BQU0sT0FBTyxNQUFNO0lBQ2pCLE9BQU8sQ0FBVTtJQUNqQixVQUFVLENBQWdCO0lBQzFCLElBQUksQ0FBMEI7SUFDOUIsS0FBSyxDQUFlO0lBQ3BCO1FBQ0UsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFDcEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7UUFDdkIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNkLENBQUM7SUFFRCxJQUFJO1FBQ0YscUJBQXFCO1FBQ3JCLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQzlFLElBQUksQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFMUIsSUFBSSxpQkFBaUIsSUFBSSxPQUFPLElBQUksT0FBTyxPQUFPLENBQUMsZUFBZSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ2hGLCtCQUErQjtZQUMvQixJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUM7WUFD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
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@eggjs/core",
3
+ "version": "6.0.0-beta.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "engines": {
8
+ "node": ">= 18.19.0"
9
+ },
10
+ "tnpm": {
11
+ "mode": "npm"
12
+ },
13
+ "description": "A core plugin framework based on koa",
14
+ "scripts": {
15
+ "lint": "eslint src test --ext ts",
16
+ "test": "npm run lint -- --fix && npm run test-local",
17
+ "test-local": "egg-bin test",
18
+ "ci": "npm run lint && egg-bin cov && npm run prepublishOnly",
19
+ "contributor": "git-contributor",
20
+ "prepublishOnly": "tshy && tshy-after"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/eggjs/egg-core.git"
25
+ },
26
+ "keywords": [
27
+ "egg",
28
+ "loader"
29
+ ],
30
+ "author": "gxcsoccer <gxcsoccer@126.com>",
31
+ "license": "MIT",
32
+ "bugs": {
33
+ "url": "https://github.com/eggjs/egg/issues"
34
+ },
35
+ "homepage": "https://github.com/eggjs/egg-core#readme",
36
+ "dependencies": {
37
+ "@eggjs/koa": "^2.18.2",
38
+ "@eggjs/router": "^3.0.5",
39
+ "egg-logger": "^3.5.0",
40
+ "egg-path-matching": "^2.0.0",
41
+ "extend2": "^4.0.0",
42
+ "get-ready": "^3.1.0",
43
+ "globby": "^11.0.2",
44
+ "is-type-of": "^2.1.0",
45
+ "node-homedir": "^2.0.0",
46
+ "performance-ms": "^1.1.0",
47
+ "ready-callback": "^4.0.0",
48
+ "tsconfig-paths": "^4.1.1",
49
+ "utility": "^2.1.0"
50
+ },
51
+ "devDependencies": {
52
+ "@eggjs/tsconfig": "1",
53
+ "@types/js-yaml": "^4.0.9",
54
+ "@types/mocha": "10",
55
+ "@types/node": "20",
56
+ "@types/supertest": "^6.0.2",
57
+ "await-event": "2",
58
+ "coffee": "5",
59
+ "egg-bin": "6",
60
+ "egg-utils": "2",
61
+ "eslint": "8",
62
+ "eslint-config-egg": "13",
63
+ "gals": "^1.0.2",
64
+ "git-contributor": "2",
65
+ "js-yaml": "^3.13.1",
66
+ "mm": "3",
67
+ "spy": "^1.0.0",
68
+ "supertest": "^4.0.2",
69
+ "ts-node": "10",
70
+ "tshy": "^1.15.1",
71
+ "tshy-after": "^1.0.0",
72
+ "typescript": "^5.4.5",
73
+ "urllib": "3"
74
+ },
75
+ "files": [
76
+ "dist",
77
+ "src"
78
+ ],
79
+ "type": "module",
80
+ "tshy": {
81
+ "exports": {
82
+ "./package.json": "./package.json",
83
+ ".": "./src/index.ts"
84
+ }
85
+ },
86
+ "exports": {
87
+ "./package.json": "./package.json",
88
+ ".": {
89
+ "import": {
90
+ "source": "./src/index.ts",
91
+ "types": "./dist/esm/index.d.ts",
92
+ "default": "./dist/esm/index.js"
93
+ },
94
+ "require": {
95
+ "source": "./src/index.ts",
96
+ "types": "./dist/commonjs/index.d.ts",
97
+ "default": "./dist/commonjs/index.js"
98
+ }
99
+ }
100
+ },
101
+ "main": "./dist/commonjs/index.js",
102
+ "types": "./dist/commonjs/index.d.ts"
103
+ }
@@ -0,0 +1,39 @@
1
+ import type { EggCore, EggCoreContext } from './egg.js';
2
+
3
+ /**
4
+ * BaseContextClass is a base class that can be extended,
5
+ * it's instantiated in context level,
6
+ * {@link Helper}, {@link Service} is extending it.
7
+ */
8
+ export class BaseContextClass {
9
+ ctx: EggCoreContext;
10
+ app: EggCore;
11
+ config: Record<string, any>;
12
+ service: BaseContextClass;
13
+
14
+ /**
15
+ * @since 1.0.0
16
+ */
17
+ constructor(ctx: EggCoreContext) {
18
+ /**
19
+ * @member {Context} BaseContextClass#ctx
20
+ * @since 1.0.0
21
+ */
22
+ this.ctx = ctx;
23
+ /**
24
+ * @member {Application} BaseContextClass#app
25
+ * @since 1.0.0
26
+ */
27
+ this.app = ctx.app;
28
+ /**
29
+ * @member {Config} BaseContextClass#config
30
+ * @since 1.0.0
31
+ */
32
+ this.config = ctx.app.config;
33
+ /**
34
+ * @member {Service} BaseContextClass#service
35
+ * @since 1.0.0
36
+ */
37
+ this.service = ctx.service;
38
+ }
39
+ }
package/src/egg.ts ADDED
@@ -0,0 +1,430 @@
1
+ /* eslint-disable prefer-spread */
2
+ import assert from 'node:assert';
3
+ import { debuglog } from 'node:util';
4
+ import is from 'is-type-of';
5
+ import KoaApplication from '@eggjs/koa';
6
+ import type { ContextDelegation, Next } from '@eggjs/koa';
7
+ import { EggConsoleLogger } from 'egg-logger';
8
+ import { RegisterOptions, ResourcesController, EggRouter as Router } from '@eggjs/router';
9
+ import type { ReadyFunctionArg } from 'get-ready';
10
+ import { BaseContextClass } from './base_context_class.js';
11
+ import { Timing } from './utils/timing.js';
12
+ import type { Fun } from './utils/index.js';
13
+ import { Lifecycle } from './lifecycle.js';
14
+ import { EggLoader } from './loader/egg_loader.js';
15
+ import utils from './utils/index.js';
16
+
17
+ const debug = debuglog('@eggjs/core:egg');
18
+
19
+ const EGG_LOADER = Symbol.for('egg#loader');
20
+
21
+ export interface EggCoreOptions {
22
+ baseDir: string;
23
+ type: 'application' | 'agent';
24
+ plugins?: any;
25
+ serverScope?: string;
26
+ env?: string;
27
+ }
28
+
29
+ export type EggCoreInitOptions = Partial<EggCoreOptions>;
30
+
31
+ type Middleware = (ctx: EggCoreContext, next: Next) => Promise<void> | void;
32
+ export type MiddlewareFunc = Middleware & {
33
+ _name?: string;
34
+ };
35
+
36
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
37
+ // @ts-ignore
38
+ export interface EggCoreContext extends ContextDelegation {
39
+ app: EggCore;
40
+ }
41
+
42
+ export class EggCore extends KoaApplication {
43
+ options: EggCoreOptions;
44
+ timing: Timing;
45
+ console: EggConsoleLogger;
46
+ BaseContextClass: typeof BaseContextClass;
47
+ Controller: typeof BaseContextClass;
48
+ Service: typeof BaseContextClass;
49
+ Helper?: typeof BaseContextClass;
50
+ lifecycle: Lifecycle;
51
+ loader: EggLoader;
52
+ #closePromise?: Promise<void>;
53
+ #router?: Router;
54
+
55
+ /** auto inject on loadService() */
56
+ readonly serviceClasses: Record<string, any> = {};
57
+ /** auto inject on loadController() */
58
+ readonly controller: Record<string, any> = {};
59
+ /** auto inject on loadMiddleware() */
60
+ readonly middlewares: Record<string, (opt: any, app: EggCore) => MiddlewareFunc> = {};
61
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
62
+ // @ts-ignore
63
+ declare middleware: MiddlewareFunc[];
64
+
65
+ /**
66
+ * @class
67
+ * @param {Object} options - options
68
+ * @param {String} [options.baseDir=process.cwd()] - the directory of application
69
+ * @param {String} [options.type=application|agent] - whether it's running in app worker or agent worker
70
+ * @param {Object} [options.plugins] - custom plugins
71
+ * @since 1.0.0
72
+ */
73
+ constructor(options: EggCoreInitOptions = {}) {
74
+ options.baseDir = options.baseDir ?? process.cwd();
75
+ options.type = options.type ?? 'application';
76
+ assert(typeof options.baseDir === 'string', 'options.baseDir required, and must be a string');
77
+ // assert(fs.existsSync(options.baseDir), `Directory ${options.baseDir} not exists`);
78
+ // assert(fs.statSync(options.baseDir).isDirectory(), `Directory ${options.baseDir} is not a directory`);
79
+ assert(options.type === 'application' || options.type === 'agent', 'options.type should be application or agent');
80
+ super();
81
+
82
+ this.timing = new Timing();
83
+ /**
84
+ * @member {Object} EggCore#options
85
+ * @private
86
+ * @since 1.0.0
87
+ */
88
+ this.options = options as EggCoreOptions;
89
+
90
+ /**
91
+ * logging for EggCore, avoid using console directly
92
+ * @member {Logger} EggCore#console
93
+ * @private
94
+ * @since 1.0.0
95
+ */
96
+ this.console = new EggConsoleLogger();
97
+
98
+ /**
99
+ * @member {BaseContextClass} EggCore#BaseContextClass
100
+ * @since 1.0.0
101
+ */
102
+ this.BaseContextClass = BaseContextClass;
103
+
104
+ /**
105
+ * Base controller to be extended by controller in `app.controller`
106
+ * @class Controller
107
+ * @augments BaseContextClass
108
+ * @example
109
+ * class UserController extends app.Controller {}
110
+ */
111
+ const Controller = this.BaseContextClass;
112
+
113
+ /**
114
+ * Retrieve base controller
115
+ * @member {Controller} EggCore#Controller
116
+ * @since 1.0.0
117
+ */
118
+ this.Controller = Controller;
119
+
120
+ /**
121
+ * Base service to be extended by services in `app.service`
122
+ * @class Service
123
+ * @augments BaseContextClass
124
+ * @example
125
+ * class UserService extends app.Service {}
126
+ */
127
+ const Service = this.BaseContextClass;
128
+
129
+ /**
130
+ * Retrieve base service
131
+ * @member {Service} EggCore#Service
132
+ * @since 1.0.0
133
+ */
134
+ this.Service = Service;
135
+
136
+ this.lifecycle = new Lifecycle({
137
+ baseDir: options.baseDir,
138
+ app: this,
139
+ logger: this.console,
140
+ });
141
+ this.lifecycle.on('error', err => this.emit('error', err));
142
+ this.lifecycle.on('ready_timeout', id => this.emit('ready_timeout', id));
143
+ this.lifecycle.on('ready_stat', data => this.emit('ready_stat', data));
144
+
145
+ /**
146
+ * The loader instance, the default class is {@link EggLoader}.
147
+ * If you want define
148
+ * @member {EggLoader} EggCore#loader
149
+ * @since 1.0.0
150
+ */
151
+ const Loader = this[EGG_LOADER];
152
+ assert(Loader, 'Symbol.for(\'egg#loader\') is required');
153
+ this.loader = new Loader({
154
+ baseDir: options.baseDir,
155
+ app: this,
156
+ plugins: options.plugins,
157
+ logger: this.console,
158
+ serverScope: options.serverScope,
159
+ env: options.env ?? '',
160
+ EggCoreClass: EggCore,
161
+ });
162
+ }
163
+
164
+ /**
165
+ * override koa's app.use, support generator function
166
+ * @since 1.0.0
167
+ */
168
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
169
+ // @ts-ignore
170
+ use(fn: MiddlewareFunc) {
171
+ assert(is.function(fn), 'app.use() requires a function');
172
+ debug('[use] add middleware: %o', fn._name || fn.name || '-');
173
+ this.middleware.push(fn);
174
+ return this;
175
+ }
176
+
177
+ /**
178
+ * Whether `application` or `agent`
179
+ * @member {String}
180
+ * @since 1.0.0
181
+ */
182
+ get type() {
183
+ return this.options.type;
184
+ }
185
+
186
+ /**
187
+ * The current directory of application
188
+ * @member {String}
189
+ * @see {@link AppInfo#baseDir}
190
+ * @since 1.0.0
191
+ */
192
+ get baseDir() {
193
+ return this.options.baseDir;
194
+ }
195
+
196
+ /**
197
+ * Alias to {@link https://npmjs.com/package/depd}
198
+ * @member {Function}
199
+ * @since 1.0.0
200
+ */
201
+ get deprecate() {
202
+ return utils.deprecated;
203
+ }
204
+
205
+ /**
206
+ * The name of application
207
+ * @member {String}
208
+ * @see {@link AppInfo#name}
209
+ * @since 1.0.0
210
+ */
211
+ get name() {
212
+ return this.loader ? this.loader.pkg.name : '';
213
+ }
214
+
215
+ /**
216
+ * Retrieve enabled plugins
217
+ * @member {Object}
218
+ * @since 1.0.0
219
+ */
220
+ get plugins() {
221
+ return this.loader ? this.loader.plugins : {};
222
+ }
223
+
224
+ /**
225
+ * The configuration of application
226
+ * @member {Config}
227
+ * @since 1.0.0
228
+ */
229
+ get config() {
230
+ return this.loader ? this.loader.config : {};
231
+ }
232
+
233
+ /**
234
+ * Execute scope after loaded and before app start.
235
+ *
236
+ * Notice:
237
+ * This method is now NOT recommanded and reguarded as a deprecated one,
238
+ * For plugin development, we should use `didLoad` instead.
239
+ * For application development, we should use `willReady` instead.
240
+ *
241
+ * @see https://eggjs.org/en/advanced/loader.html#beforestart
242
+ *
243
+ * @param {Function|AsyncFunction} scope function will execute before app start
244
+ * @param {string} [name] scope name, default is empty string
245
+ */
246
+ beforeStart(scope: Fun, name?: string) {
247
+ this.deprecate('Please use "Life Cycles" instead, see https://www.eggjs.org/advanced/loader#life-cycles');
248
+ this.lifecycle.registerBeforeStart(scope, name ?? '');
249
+ }
250
+
251
+ /**
252
+ * register an callback function that will be invoked when application is ready.
253
+ * @see https://github.com/node-modules/get-ready
254
+ * @since 1.0.0
255
+ * @example
256
+ * const app = new Application(...);
257
+ * app.ready(err => {
258
+ * if (err) throw err;
259
+ * console.log('done');
260
+ * });
261
+ */
262
+ ready(flagOrFunction?: ReadyFunctionArg) {
263
+ return this.lifecycle.ready(flagOrFunction);
264
+ }
265
+
266
+ /**
267
+ * If a client starts asynchronously, you can register `readyCallback`,
268
+ * then the application will wait for the callback to ready
269
+ *
270
+ * It will log when the callback is not invoked after 10s
271
+ *
272
+ * Recommend to use {@link EggCore#beforeStart}
273
+ * @since 1.0.0
274
+ *
275
+ * @param {String} name - readyCallback task name
276
+ * @param {object} opts -
277
+ * - {Number} [timeout=10000] - emit `ready_timeout` when it doesn't finish but reach the timeout
278
+ * - {Boolean} [isWeakDep=false] - whether it's a weak dependency
279
+ * @return {Function} - a callback
280
+ * @example
281
+ * const done = app.readyCallback('mysql');
282
+ * mysql.ready(done);
283
+ */
284
+ readyCallback(name: string, opts: object) {
285
+ this.deprecate('Please use "Life Cycles" instead, see https://www.eggjs.org/advanced/loader#life-cycles');
286
+ return this.lifecycle.legacyReadyCallback(name, opts);
287
+ }
288
+
289
+ /**
290
+ * Register a function that will be called when app close.
291
+ *
292
+ * Notice:
293
+ * This method is now NOT recommanded directly used,
294
+ * Developers SHOULDN'T use app.beforeClose directly now,
295
+ * but in the form of class to implement beforeClose instead.
296
+ *
297
+ * @see https://eggjs.org/en/advanced/loader.html#beforeclose
298
+ *
299
+ * @param {Function} fn - the function that can be generator function or async function.
300
+ */
301
+ beforeClose(fn: Fun) {
302
+ this.deprecate('Please use "Life Cycles" instead, see https://www.eggjs.org/advanced/loader#life-cycles');
303
+ this.lifecycle.registerBeforeClose(fn);
304
+ }
305
+
306
+ /**
307
+ * Close all, it will close
308
+ * - callbacks registered by beforeClose
309
+ * - emit `close` event
310
+ * - remove add listeners
311
+ *
312
+ * If error is thrown when it's closing, the promise will reject.
313
+ * It will also reject after following call.
314
+ * @return {Promise} promise
315
+ * @since 1.0.0
316
+ */
317
+ async close(): Promise<void> {
318
+ if (this.#closePromise) return this.#closePromise;
319
+ this.#closePromise = this.lifecycle.close();
320
+ return this.#closePromise;
321
+ }
322
+
323
+ /**
324
+ * get router
325
+ * @member {Router} EggCore#router
326
+ * @since 1.0.0
327
+ */
328
+ get router() {
329
+ if (this.#router) {
330
+ return this.#router;
331
+ }
332
+ const router = this.#router = new Router({ sensitive: true }, this);
333
+ return router;
334
+ }
335
+
336
+ /**
337
+ * Alias to {@link Router#url}
338
+ * @param {String} name - Router name
339
+ * @param {Object} params - more parameters
340
+ * @return {String} url
341
+ */
342
+ url(name: string, params?: any): string {
343
+ return this.router.url(name, params);
344
+ }
345
+
346
+ // delegate all router method to application
347
+ // 'head', 'options', 'get', 'put', 'patch', 'post', 'delete'
348
+ // 'all', 'resources', 'register', 'redirect'
349
+ head(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
350
+ head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
351
+ head(...args: any): EggCore {
352
+ this.router.head.apply(this.router, args);
353
+ return this;
354
+ }
355
+ // options(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
356
+ // options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
357
+ // options(...args: any): EggCore {
358
+ // this.router.options.apply(this.router, args);
359
+ // return this;
360
+ // }
361
+ get(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
362
+ get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
363
+ get(...args: any): EggCore {
364
+ this.router.get.apply(this.router, args);
365
+ return this;
366
+ }
367
+ put(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
368
+ put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
369
+ put(...args: any): EggCore {
370
+ this.router.put.apply(this.router, args);
371
+ return this;
372
+ }
373
+ patch(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
374
+ patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
375
+ patch(...args: any): EggCore {
376
+ this.router.patch.apply(this.router, args);
377
+ return this;
378
+ }
379
+ post(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
380
+ post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
381
+ post(...args: any): EggCore {
382
+ this.router.post.apply(this.router, args);
383
+ return this;
384
+ }
385
+ delete(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
386
+ delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
387
+ delete(...args: any): EggCore {
388
+ this.router.delete.apply(this.router, args);
389
+ return this;
390
+ }
391
+ del(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
392
+ del(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
393
+ del(...args: any): EggCore {
394
+ this.router.del.apply(this.router, args);
395
+ return this;
396
+ }
397
+
398
+ all(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
399
+ all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): EggCore;
400
+ all(...args: any): EggCore {
401
+ this.router.all.apply(this.router, args);
402
+ return this;
403
+ }
404
+
405
+ resources(prefix: string, controller: string | ResourcesController): EggCore;
406
+ resources(prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): EggCore;
407
+ resources(name: string, prefix: string, controller: string | ResourcesController): EggCore;
408
+ resources(name: string, prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): EggCore;
409
+ resources(...args: any): EggCore {
410
+ this.router.resources.apply(this.router, args);
411
+ return this;
412
+ }
413
+
414
+ redirect(source: string, destination: string, status: number = 301) {
415
+ this.router.redirect(source, destination, status);
416
+ return this;
417
+ }
418
+
419
+ register(path: string | RegExp | (string | RegExp)[],
420
+ methods: string[],
421
+ middleware: MiddlewareFunc | MiddlewareFunc[],
422
+ opts?: RegisterOptions) {
423
+ this.router.register(path, methods, middleware, opts);
424
+ return this;
425
+ }
426
+
427
+ get [EGG_LOADER]() {
428
+ return EggLoader;
429
+ }
430
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import utils from './utils/index.js';
2
+
3
+ export * from './egg.js';
4
+ export * from './loader/egg_loader.js';
5
+ export * from './base_context_class.js';
6
+ export { utils };