@eggjs/core 7.0.0-beta.20 → 7.0.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2425 +1,12 @@
1
- import BuiltinModule from "node:module";
2
- import { debuglog, format, inspect } from "node:util";
3
- import path from "node:path";
4
- import fs from "node:fs";
5
- import { stat } from "node:fs/promises";
6
- import { importModule, importResolve, isESM, isSupportTypeScript } from "@eggjs/utils";
7
- import assert from "node:assert";
8
- import { Application, Application as KoaApplication, Context as Context$1, Context as KoaContext, Request as KoaRequest, Request as Request$1, Response as KoaResponse, Response as Response$1 } from "@eggjs/koa";
9
- import { EggConsoleLogger } from "egg-logger";
10
- import { EggRouter as Router } from "@eggjs/router";
11
- import { EOL } from "node:os";
12
- import { EventEmitter } from "node:events";
13
- import { isAsyncFunction, isClass, isGeneratorFunction, isObject, isPrimitive, isPromise } from "is-type-of";
14
- import { Ready } from "get-ready";
15
- import { Ready as Ready$1 } from "ready-callback";
16
- import { homedir } from "node-homedir";
17
- import { exists, getParamNames, readJSON, readJSONSync } from "utility";
18
- import { extend } from "@eggjs/extend2";
19
- import { register } from "tsconfig-paths";
20
- import { pathMatching } from "egg-path-matching";
21
- import { diff, now } from "performance-ms";
22
- import globby from "globby";
23
-
24
- //#region src/utils/index.ts
25
- const debug$6 = debuglog("egg/core/utils");
26
- const extensions = (typeof module !== "undefined" && module.constructor.length > 1 ? module.constructor : BuiltinModule)._extensions;
27
- const extensionNames = Object.keys(extensions).concat([".cjs", ".mjs"]);
28
- debug$6("Module extensions: %j", extensionNames);
29
- function getCalleeFromStack(withLine, stackIndex) {
30
- stackIndex = stackIndex === void 0 ? 2 : stackIndex;
31
- const limit = Error.stackTraceLimit;
32
- const prep = Error.prepareStackTrace;
33
- Error.prepareStackTrace = prepareObjectStackTrace;
34
- Error.stackTraceLimit = 5;
35
- const obj = {};
36
- Error.captureStackTrace(obj);
37
- let callSite = obj.stack[stackIndex];
38
- let fileName = "";
39
- if (callSite) {
40
- fileName = callSite.getFileName();
41
- /* istanbul ignore if */
42
- if (fileName && fileName.endsWith("egg-mock/lib/app.js")) {
43
- callSite = obj.stack[stackIndex + 1];
44
- fileName = callSite.getFileName();
45
- }
46
- }
47
- Error.prepareStackTrace = prep;
48
- Error.stackTraceLimit = limit;
49
- if (!callSite || !fileName) return "<anonymous>";
50
- if (!withLine) return fileName;
51
- return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`;
52
- }
53
- var utils_default = {
54
- deprecated(message) {
55
- if (debug$6.enabled) console.trace("[@eggjs/core/deprecated] %s", message);
56
- else {
57
- console.log("[@eggjs/core/deprecated] %s", message);
58
- console.log("[@eggjs/core/deprecated] set NODE_DEBUG=@eggjs/core/utils can show call stack");
59
- }
60
- },
61
- extensions,
62
- extensionNames,
63
- async existsPath(filepath) {
64
- try {
65
- await stat(filepath);
66
- return true;
67
- } catch {
68
- return false;
69
- }
70
- },
71
- async loadFile(filepath) {
72
- debug$6("[loadFile:start] filepath: %s", filepath);
73
- try {
74
- const extname = path.extname(filepath);
75
- if (extname && !extensionNames.includes(extname) && extname !== ".ts") return fs.readFileSync(filepath);
76
- return await importModule(filepath, { importDefaultOnly: true });
77
- } catch (e) {
78
- if (!(e instanceof Error)) {
79
- console.trace(e);
80
- throw e;
81
- }
82
- const err = /* @__PURE__ */ new Error(`[egg/core] load file: ${filepath}, error: ${e.message}`);
83
- err.cause = e;
84
- debug$6("[loadFile] handle %s error: %s", filepath, e);
85
- throw err;
86
- }
87
- },
88
- resolvePath(filepath, options) {
89
- return importResolve(filepath, options);
90
- },
91
- methods: [
92
- "head",
93
- "options",
94
- "get",
95
- "put",
96
- "patch",
97
- "post",
98
- "delete"
99
- ],
100
- async callFn(fn, args, ctx) {
101
- args = args || [];
102
- if (typeof fn !== "function") return;
103
- return ctx ? fn.call(ctx, ...args) : fn(...args);
104
- },
105
- getCalleeFromStack,
106
- getResolvedFilename(filepath, baseDir) {
107
- return filepath.replace(baseDir + path.sep, "").replace(/[/\\]/g, "/");
108
- }
109
- };
110
- /**
111
- * Capture call site stack from v8.
112
- * https://github.com/v8/v8/wiki/Stack-Trace-API
113
- */
114
- function prepareObjectStackTrace(_obj, stack) {
115
- return stack;
116
- }
117
-
118
- //#endregion
119
- //#region src/base_context_class.ts
120
- /**
121
- * BaseContextClass is a base class that can be extended,
122
- * it's instantiated in context level,
123
- * {@link Helper}, {@link Service} is extending it.
124
- */
125
- var BaseContextClass = class {
126
- ctx;
127
- app;
128
- config;
129
- service;
130
- /**
131
- * @since 1.0.0
132
- */
133
- constructor(ctx) {
134
- /**
135
- * @member {Context} BaseContextClass#ctx
136
- * @since 1.0.0
137
- */
138
- this.ctx = ctx;
139
- /**
140
- * @member {Application} BaseContextClass#app
141
- * @since 1.0.0
142
- */
143
- this.app = ctx.app;
144
- /**
145
- * @member {Config} BaseContextClass#config
146
- * @since 1.0.0
147
- */
148
- this.config = ctx.app.config;
149
- /**
150
- * @member {Service} BaseContextClass#service
151
- * @since 1.0.0
152
- */
153
- this.service = ctx.service;
154
- }
155
- };
156
-
157
- //#endregion
158
- //#region src/utils/timing.ts
159
- const debug$5 = debuglog("egg/core/utils/timing");
160
- var Timing = class {
161
- #enable;
162
- #startTime;
163
- #map;
164
- #list;
165
- constructor() {
166
- this.#enable = true;
167
- this.#map = /* @__PURE__ */ new Map();
168
- this.#list = [];
169
- this.init();
170
- }
171
- init() {
172
- this.start("Process Start", Date.now() - Math.floor(process.uptime() * 1e3));
173
- this.end("Process Start");
174
- if ("scriptStartTime" in process && typeof process.scriptStartTime === "number") {
175
- this.start("Script Start", process.scriptStartTime);
176
- this.end("Script Start");
177
- }
178
- }
179
- start(name, start) {
180
- if (!name || !this.#enable) return;
181
- if (this.#map.has(name)) this.end(name);
182
- start = start || Date.now();
183
- if (!this.#startTime) this.#startTime = start;
184
- const item = {
185
- name,
186
- start,
187
- pid: process.pid,
188
- index: this.#list.length
189
- };
190
- this.#map.set(name, item);
191
- this.#list.push(item);
192
- debug$5("start %j", item);
193
- return item;
194
- }
195
- end(name) {
196
- if (!name || !this.#enable) return;
197
- const item = this.#map.get(name);
198
- assert(item, `should run timing.start('${name}') first`);
199
- item.end = Date.now();
200
- item.duration = item.end - item.start;
201
- debug$5("end %j", item);
202
- return item;
203
- }
204
- enable() {
205
- this.#enable = true;
206
- }
207
- disable() {
208
- this.#enable = false;
209
- }
210
- clear() {
211
- this.#map.clear();
212
- this.#list = [];
213
- }
214
- toJSON() {
215
- return this.#list;
216
- }
217
- itemToString(timelineEnd, item, times) {
218
- const isEnd = typeof item.duration === "number";
219
- const duration = isEnd ? item.duration : timelineEnd - item.start;
220
- const offset = item.start - this.#startTime;
221
- const status = `${duration}ms${isEnd ? "" : " NOT_END"}`;
222
- const timespan = Math.floor(Number((offset * times).toFixed(6)));
223
- let timeline = Math.floor(Number((duration * times).toFixed(6)));
224
- timeline = timeline > 0 ? timeline : 1;
225
- const message = `#${item.index} ${item.name}`;
226
- return " ".repeat(timespan) + "▇".repeat(timeline) + ` [${status}] - ${message}`;
227
- }
228
- toString(prefix = "egg start timeline:", width = 50) {
229
- const timelineEnd = Date.now();
230
- const timelineDuration = timelineEnd - this.#startTime;
231
- let times = 1;
232
- if (timelineDuration > width) times = width / timelineDuration;
233
- return prefix + EOL + this.#list.map((item) => this.itemToString(timelineEnd, item, times)).join(EOL);
234
- }
235
- };
236
-
237
- //#endregion
238
- //#region src/lifecycle.ts
239
- const debug$4 = debuglog("egg/core/lifecycle");
240
- var Lifecycle = class extends EventEmitter {
241
- #init;
242
- #readyObject;
243
- #bootHooks;
244
- #boots;
245
- #isClosed;
246
- #closeFunctionSet;
247
- loadReady;
248
- bootReady;
249
- options;
250
- readyTimeout;
251
- constructor(options) {
252
- super();
253
- options.logger = options.logger ?? new EggConsoleLogger();
254
- this.options = options;
255
- this.#readyObject = new Ready();
256
- this.#bootHooks = [];
257
- this.#boots = [];
258
- this.#closeFunctionSet = /* @__PURE__ */ new Set();
259
- this.#isClosed = false;
260
- this.#init = false;
261
- this.timing.start(`${this.options.app.type} Start`);
262
- const eggReadyTimeoutEnv = Number.parseInt(process.env.EGG_READY_TIMEOUT_ENV || "10000");
263
- assert(Number.isInteger(eggReadyTimeoutEnv), `process.env.EGG_READY_TIMEOUT_ENV ${process.env.EGG_READY_TIMEOUT_ENV} should be able to parseInt.`);
264
- this.readyTimeout = eggReadyTimeoutEnv;
265
- this.#initReady();
266
- this.on("ready_stat", (data) => {
267
- this.logger.info("[egg/core/lifecycle:ready_stat] end ready task %s, remain %j", data.id, data.remain);
268
- }).on("ready_timeout", (id) => {
269
- this.logger.warn("[egg/core/lifecycle:ready_timeout] %s seconds later %s was still unable to finish.", this.readyTimeout / 1e3, id);
270
- });
271
- this.ready((err) => {
272
- this.triggerDidReady(err);
273
- debug$4("app ready");
274
- this.timing.end(`${this.options.app.type} Start`);
275
- });
276
- }
277
- ready(flagOrFunction) {
278
- if (flagOrFunction === void 0) return this.#readyObject.ready();
279
- return this.#readyObject.ready(flagOrFunction);
280
- }
281
- get app() {
282
- return this.options.app;
283
- }
284
- get logger() {
285
- return this.options.logger;
286
- }
287
- get timing() {
288
- return this.app.timing;
289
- }
290
- legacyReadyCallback(name, opt) {
291
- const timingKeyPrefix = "readyCallback";
292
- const timing = this.timing;
293
- const cb = this.loadReady.readyCallback(name, opt);
294
- const timingKey = `${timingKeyPrefix} in ` + utils_default.getResolvedFilename(name, this.app.baseDir);
295
- this.timing.start(timingKey);
296
- debug$4("register legacyReadyCallback");
297
- return function legacyReadyCallback(...args) {
298
- timing.end(timingKey);
299
- debug$4("end legacyReadyCallback");
300
- cb(...args);
301
- };
302
- }
303
- addBootHook(bootHootOrBootClass) {
304
- assert(this.#init === false, "do not add hook when lifecycle has been initialized");
305
- this.#bootHooks.push(bootHootOrBootClass);
306
- }
307
- addFunctionAsBootHook(hook, fullPath) {
308
- assert(this.#init === false, "do not add hook when lifecycle has been initialized");
309
- class Boot {
310
- static fullPath;
311
- app;
312
- constructor(app) {
313
- this.app = app;
314
- }
315
- configDidLoad() {
316
- hook(this.app);
317
- }
318
- }
319
- Boot.fullPath = fullPath;
320
- this.#bootHooks.push(Boot);
321
- }
322
- /**
323
- * init boots and trigger config did config
324
- */
325
- init() {
326
- debug$4("%s init lifecycle", this.app.type);
327
- assert(this.#init === false, "lifecycle have been init");
328
- this.#init = true;
329
- this.#boots = this.#bootHooks.map((BootHootOrBootClass) => {
330
- let instance = BootHootOrBootClass;
331
- if (isClass(BootHootOrBootClass)) {
332
- instance = new BootHootOrBootClass(this.app);
333
- if (!instance.fullPath && "fullPath" in BootHootOrBootClass) instance.fullPath = BootHootOrBootClass.fullPath;
334
- }
335
- debug$4("[init] add boot instance: %o", instance.fullPath);
336
- return instance;
337
- });
338
- }
339
- registerBeforeStart(scope, name) {
340
- debug$4("%s add registerBeforeStart, name: %o", this.options.app.type, name);
341
- this.#registerReadyCallback({
342
- scope,
343
- ready: this.loadReady,
344
- timingKeyPrefix: "Before Start",
345
- scopeFullName: name
346
- });
347
- }
348
- registerBeforeClose(fn, fullPath) {
349
- assert(typeof fn === "function", "argument should be function");
350
- assert(this.#isClosed === false, "app has been closed");
351
- if (fullPath) fn.fullPath = fullPath;
352
- this.#closeFunctionSet.add(fn);
353
- debug$4("%s register beforeClose at %o, count: %d", this.app.type, fullPath, this.#closeFunctionSet.size);
354
- }
355
- async close() {
356
- const closeFns = Array.from(this.#closeFunctionSet);
357
- debug$4("%s start trigger %d beforeClose functions", this.app.type, closeFns.length);
358
- for (const fn of closeFns.reverse()) {
359
- debug$4("%s trigger beforeClose at %o", this.app.type, fn.fullPath);
360
- await utils_default.callFn(fn);
361
- this.#closeFunctionSet.delete(fn);
362
- }
363
- this.app.emit("close");
364
- this.removeAllListeners();
365
- this.app.removeAllListeners();
366
- this.#isClosed = true;
367
- debug$4("%s closed", this.app.type);
368
- }
369
- triggerConfigWillLoad() {
370
- debug$4("trigger configWillLoad start");
371
- for (const boot of this.#boots) if (typeof boot.configWillLoad === "function") {
372
- debug$4("trigger configWillLoad at %o", boot.fullPath);
373
- boot.configWillLoad();
374
- }
375
- debug$4("trigger configWillLoad end");
376
- this.triggerConfigDidLoad();
377
- }
378
- triggerConfigDidLoad() {
379
- debug$4("trigger configDidLoad start");
380
- for (const boot of this.#boots) {
381
- if (typeof boot.configDidLoad === "function") {
382
- debug$4("trigger configDidLoad at %o", boot.fullPath);
383
- boot.configDidLoad();
384
- }
385
- if (typeof boot.beforeClose === "function") {
386
- const beforeClose = boot.beforeClose.bind(boot);
387
- this.registerBeforeClose(beforeClose, boot.fullPath);
388
- }
389
- }
390
- debug$4("trigger configDidLoad end");
391
- this.triggerDidLoad();
392
- }
393
- triggerDidLoad() {
394
- debug$4("trigger didLoad start");
395
- debug$4("loadReady start");
396
- this.loadReady.start();
397
- for (const boot of this.#boots) if (typeof boot.didLoad === "function") {
398
- const didLoad = boot.didLoad.bind(boot);
399
- this.#registerReadyCallback({
400
- scope: didLoad,
401
- ready: this.loadReady,
402
- timingKeyPrefix: "Did Load",
403
- scopeFullName: boot.fullPath + ":didLoad"
404
- });
405
- }
406
- }
407
- triggerWillReady() {
408
- debug$4("trigger willReady start");
409
- debug$4("bootReady start");
410
- this.bootReady.start();
411
- for (const boot of this.#boots) if (typeof boot.willReady === "function") {
412
- const willReady = boot.willReady.bind(boot);
413
- this.#registerReadyCallback({
414
- scope: willReady,
415
- ready: this.bootReady,
416
- timingKeyPrefix: "Will Ready",
417
- scopeFullName: boot.fullPath + ":willReady"
418
- });
419
- }
420
- }
421
- triggerDidReady(err) {
422
- debug$4("trigger didReady start");
423
- return (async () => {
424
- for (const boot of this.#boots) if (typeof boot.didReady === "function") {
425
- debug$4("trigger didReady at %o", boot.fullPath);
426
- try {
427
- await boot.didReady(err);
428
- } catch (err$1) {
429
- debug$4("trigger didReady error at %o, error: %s", boot.fullPath, err$1);
430
- this.emit("error", err$1);
431
- }
432
- }
433
- debug$4("trigger didReady end");
434
- })();
435
- }
436
- triggerServerDidReady() {
437
- debug$4("trigger serverDidReady start");
438
- return (async () => {
439
- for (const boot of this.#boots) {
440
- if (typeof boot.serverDidReady !== "function") continue;
441
- debug$4("trigger serverDidReady at %o", boot.fullPath);
442
- try {
443
- await boot.serverDidReady();
444
- } catch (err) {
445
- debug$4("trigger serverDidReady error at %o, error: %s", boot.fullPath, err);
446
- this.emit("error", err);
447
- }
448
- }
449
- debug$4("trigger serverDidReady end");
450
- })();
451
- }
452
- #initReady() {
453
- debug$4("loadReady init");
454
- this.loadReady = new Ready$1({
455
- timeout: this.readyTimeout,
456
- lazyStart: true
457
- });
458
- this.#delegateReadyEvent(this.loadReady);
459
- this.loadReady.ready((err) => {
460
- debug$4("loadReady end, err: %o", err);
461
- debug$4("trigger didLoad end");
462
- if (err) this.ready(err);
463
- else this.triggerWillReady();
464
- });
465
- debug$4("bootReady init");
466
- this.bootReady = new Ready$1({
467
- timeout: this.readyTimeout,
468
- lazyStart: true
469
- });
470
- this.#delegateReadyEvent(this.bootReady);
471
- this.bootReady.ready((err) => {
472
- debug$4("bootReady end, err: %o", err);
473
- debug$4("trigger willReady end");
474
- this.ready(err || true);
475
- });
476
- }
477
- #delegateReadyEvent(ready) {
478
- ready.once("error", (err) => ready.ready(err));
479
- ready.on("ready_timeout", (id) => this.emit("ready_timeout", id));
480
- ready.on("ready_stat", (data) => this.emit("ready_stat", data));
481
- ready.on("error", (err) => this.emit("error", err));
482
- }
483
- #registerReadyCallback(args) {
484
- const { scope, ready, timingKeyPrefix, scopeFullName } = args;
485
- if (typeof scope !== "function") throw new TypeError("boot only support function");
486
- const name = scopeFullName || utils_default.getCalleeFromStack(true, 4);
487
- const timingKey = `${timingKeyPrefix} in ` + utils_default.getResolvedFilename(name, this.app.baseDir);
488
- this.timing.start(timingKey);
489
- debug$4("[registerReadyCallback] start name: %o", name);
490
- const done = ready.readyCallback(name);
491
- process.nextTick(async () => {
492
- try {
493
- await utils_default.callFn(scope);
494
- debug$4("[registerReadyCallback] end name: %o", name);
495
- done();
496
- this.timing.end(timingKey);
497
- } catch (e) {
498
- let err = e;
499
- if (!(err instanceof Error)) err = new Error(format("%s", err));
500
- done(err);
501
- this.timing.end(timingKey);
502
- }
503
- });
504
- }
505
- };
506
-
507
- //#endregion
508
- //#region src/loader/file_loader.ts
509
- const debug$3 = debuglog("egg/core/file_loader");
510
- const FULLPATH = Symbol("EGG_LOADER_ITEM_FULLPATH");
511
- const EXPORTS = Symbol("EGG_LOADER_ITEM_EXPORTS");
512
- const CaseStyle = {
513
- camel: "camel",
514
- lower: "lower",
515
- upper: "upper"
516
- };
517
- /**
518
- * Load files from directory to target object.
519
- * @since 1.0.0
520
- */
521
- var FileLoader = class {
522
- static get FULLPATH() {
523
- return FULLPATH;
524
- }
525
- static get EXPORTS() {
526
- return EXPORTS;
527
- }
528
- options;
529
- /**
530
- * @class
531
- * @param {Object} options - options
532
- * @param {String|Array} options.directory - directories to be loaded
533
- * @param {Object} options.target - attach the target object from loaded files
534
- * @param {String} options.match - match the files when load, support glob, default to all js files
535
- * @param {String} options.ignore - ignore the files when load, support glob
536
- * @param {Function} options.initializer - custom file exports, receive two parameters, first is the inject object(if not js file, will be content buffer), second is an `options` object that contain `path`
537
- * @param {Boolean} options.call - determine whether invoke when exports is function
538
- * @param {Boolean} options.override - determine whether override the property when get the same name
539
- * @param {Object} options.inject - an object that be the argument when invoke the function
540
- * @param {Function} options.filter - a function that filter the exports which can be loaded
541
- * @param {String|Function} options.caseStyle - set property's case when converting a filepath to property list.
542
- */
543
- constructor(options) {
544
- assert(options.directory, "options.directory is required");
545
- assert(options.target, "options.target is required");
546
- this.options = {
547
- caseStyle: CaseStyle.camel,
548
- call: true,
549
- override: false,
550
- ...options
551
- };
552
- if (this.options.lowercaseFirst === true) {
553
- utils_default.deprecated("lowercaseFirst is deprecated, use caseStyle instead");
554
- this.options.caseStyle = CaseStyle.lower;
555
- }
556
- }
557
- /**
558
- * attach items to target object. Mapping the directory to properties.
559
- * `app/controller/group/repository.js` => `target.group.repository`
560
- * @returns {Object} target
561
- * @since 1.0.0
562
- */
563
- async load() {
564
- const items = await this.parse();
565
- const target = this.options.target;
566
- for (const item of items) {
567
- debug$3("[load] loading item: fullpath: %s, properties: %o", item.fullpath, item.properties);
568
- item.properties.reduce((target$1, property, index) => {
569
- let obj;
570
- const properties = item.properties.slice(0, index + 1).join(".");
571
- if (index === item.properties.length - 1) {
572
- if (property in target$1 && !this.options.override) throw new Error(`can't overwrite property '${properties}' from ${target$1[property][FULLPATH]} by ${item.fullpath}`);
573
- obj = item.exports;
574
- if (obj && !isPrimitive(obj)) {
575
- Reflect.set(obj, FULLPATH, item.fullpath);
576
- Reflect.set(obj, EXPORTS, true);
577
- }
578
- } else obj = target$1[property] || {};
579
- target$1[property] = obj;
580
- if (debug$3.enabled) debug$3("[load] loaded item properties: %o => keys: %j, index: %d", properties, Object.keys(obj), index);
581
- return obj;
582
- }, target);
583
- }
584
- return target;
585
- }
586
- /**
587
- * Parse files from given directories, then return an items list, each item contains properties and exports.
588
- *
589
- * For example, parse `app/controller/group/repository.js`
590
- *
591
- * ```
592
- * module.exports = app => {
593
- * return class RepositoryController extends app.Controller {};
594
- * }
595
- * ```
596
- *
597
- * It returns a item
598
- *
599
- * ```
600
- * {
601
- * properties: [ 'group', 'repository' ],
602
- * exports: app => { ... },
603
- * }
604
- * ```
605
- *
606
- * `Properties` is an array that contains the directory of a filepath.
607
- *
608
- * `Exports` depends on type, if exports is a function, it will be called. if initializer is specified, it will be called with exports for customizing.
609
- * @returns {Array} items
610
- * @since 1.0.0
611
- */
612
- async parse() {
613
- let files = this.options.match;
614
- if (files) files = Array.isArray(files) ? files : [files];
615
- else files = isSupportTypeScript() ? ["**/*.(js|ts)", "!**/*.d.ts"] : ["**/*.js"];
616
- let ignore = this.options.ignore;
617
- if (ignore) {
618
- ignore = Array.isArray(ignore) ? ignore : [ignore];
619
- ignore = ignore.filter((f) => !!f).map((f) => "!" + f);
620
- files = files.concat(ignore);
621
- }
622
- let directories = this.options.directory;
623
- if (!Array.isArray(directories)) directories = [directories];
624
- const filter = typeof this.options.filter === "function" ? this.options.filter : null;
625
- const items = [];
626
- debug$3("[parse] parsing directories: %j", directories);
627
- for (const directory of directories) {
628
- const filepaths = globby.sync(files, { cwd: directory });
629
- debug$3("[parse] globby files: %o, cwd: %o => %o", files, directory, filepaths);
630
- for (const filepath of filepaths) {
631
- const fullpath = path.join(directory, filepath);
632
- if (!fs.statSync(fullpath).isFile()) continue;
633
- if (filepath.endsWith(".js")) {
634
- const filepathTs = filepath.replace(/\.js$/, ".ts");
635
- if (filepaths.includes(filepathTs)) {
636
- debug$3("[parse] ignore %s, because %s exists", fullpath, filepathTs);
637
- continue;
638
- }
639
- }
640
- const properties = getProperties(filepath, this.options.caseStyle);
641
- const pathName = directory.split(/[/\\]/).slice(-1) + "." + properties.join(".");
642
- const exports = await getExports(fullpath, this.options, pathName);
643
- if (exports === null || exports === void 0 || filter && filter(exports) === false) continue;
644
- if (isClass(exports)) {
645
- exports.prototype.pathName = pathName;
646
- exports.prototype.fullPath = fullpath;
647
- }
648
- items.push({
649
- fullpath,
650
- properties,
651
- exports
652
- });
653
- debug$3("[parse] parse %s, properties %j, exports %o", fullpath, properties, exports);
654
- }
655
- }
656
- return items;
657
- }
658
- };
659
- function getProperties(filepath, caseStyle) {
660
- if (typeof caseStyle === "function") {
661
- const result = caseStyle(filepath);
662
- assert(Array.isArray(result), `caseStyle expect an array, but got ${JSON.stringify(result)}`);
663
- return result;
664
- }
665
- return defaultCamelize(filepath, caseStyle);
666
- }
667
- async function getExports(fullpath, options, pathName) {
668
- let exports = await utils_default.loadFile(fullpath);
669
- if (options.initializer) {
670
- exports = options.initializer(exports, {
671
- path: fullpath,
672
- pathName
673
- });
674
- debug$3("[getExports] after initializer => %o", exports);
675
- }
676
- if (isGeneratorFunction(exports)) throw new TypeError(`Support for generators was removed, fullpath: ${fullpath}`);
677
- if (isClass(exports) || isAsyncFunction(exports)) return exports;
678
- if (options.call && typeof exports === "function") {
679
- exports = exports(options.inject);
680
- if (exports !== null && exports !== void 0) return exports;
681
- }
682
- return exports;
683
- }
684
- function defaultCamelize(filepath, caseStyle) {
685
- return filepath.slice(0, filepath.lastIndexOf(".")).split("/").map((property) => {
686
- if (!/^[a-z][a-z0-9_-]*$/i.test(property)) throw new Error(`${property} is not match 'a-z0-9_-' in ${filepath}`);
687
- property = property.replaceAll(/[_-][a-z]/gi, (s) => s.slice(1).toUpperCase());
688
- let first = property[0];
689
- if (caseStyle === CaseStyle.lower) first = first.toLowerCase();
690
- else if (caseStyle === CaseStyle.upper) first = first.toUpperCase();
691
- return first + property.slice(1);
692
- });
693
- }
694
-
695
- //#endregion
696
- //#region src/loader/context_loader.ts
697
- const CLASS_LOADER = Symbol("classLoader");
698
- var ClassLoader = class {
699
- _cache = /* @__PURE__ */ new Map();
700
- _ctx;
701
- constructor(options) {
702
- assert(options.ctx, "options.ctx is required");
703
- const properties = options.properties;
704
- this._ctx = options.ctx;
705
- for (const property in properties) this.#defineProperty(property, properties[property]);
706
- }
707
- #defineProperty(property, values) {
708
- Object.defineProperty(this, property, { get() {
709
- let instance = this._cache.get(property);
710
- if (!instance) {
711
- instance = getInstance(values, this._ctx);
712
- this._cache.set(property, instance);
713
- }
714
- return instance;
715
- } });
716
- }
717
- };
718
- /**
719
- * Same as {@link FileLoader}, but it will attach file to `inject[fieldClass]`.
720
- * The exports will be lazy loaded, such as `ctx.group.repository`.
721
- * @augments FileLoader
722
- * @since 1.0.0
723
- */
724
- var ContextLoader = class extends FileLoader {
725
- #inject;
726
- /**
727
- * @class
728
- * @param {Object} options - options same as {@link FileLoader}
729
- * @param {String} options.fieldClass - determine the field name of inject object.
730
- */
731
- constructor(options) {
732
- assert(options.property, "options.property is required");
733
- assert(options.inject, "options.inject is required");
734
- const target = {};
735
- if (options.fieldClass) options.inject[options.fieldClass] = target;
736
- super({
737
- ...options,
738
- target
739
- });
740
- this.#inject = this.options.inject;
741
- const app = this.#inject;
742
- const property = options.property;
743
- Object.defineProperty(app.context, property, { get() {
744
- const ctx = this;
745
- if (!ctx[CLASS_LOADER]) ctx[CLASS_LOADER] = /* @__PURE__ */ new Map();
746
- const classLoader = ctx[CLASS_LOADER];
747
- let instance = classLoader.get(property);
748
- if (!instance) {
749
- instance = getInstance(target, ctx);
750
- classLoader.set(property, instance);
751
- }
752
- return instance;
753
- } });
754
- }
755
- };
756
- function getInstance(values, ctx) {
757
- const Class = values[EXPORTS] ? values : null;
758
- let instance;
759
- if (Class) if (isClass(Class)) instance = new Class(ctx);
760
- else instance = Class;
761
- else if (isPrimitive(values)) instance = values;
762
- else instance = new ClassLoader({
763
- ctx,
764
- properties: values
765
- });
766
- return instance;
767
- }
768
-
769
- //#endregion
770
- //#region src/utils/sequencify.ts
771
- const debug$2 = debuglog("egg/core/utils/sequencify");
772
- function sequence(tasks, names, result, missing, recursive, nest, optional, parent) {
773
- for (const name of names) {
774
- if (result.requires[name]) continue;
775
- const node = tasks[name];
776
- if (!node) {
777
- if (optional === true) continue;
778
- missing.push(name);
779
- } else if (nest.includes(name)) {
780
- nest.push(name);
781
- recursive.push(...nest.slice(0));
782
- nest.pop();
783
- } else if (node.dependencies.length > 0 || node.optionalDependencies.length > 0) {
784
- nest.push(name);
785
- if (node.dependencies.length > 0) sequence(tasks, node.dependencies, result, missing, recursive, nest, optional, name);
786
- if (node.optionalDependencies.length > 0) sequence(tasks, node.optionalDependencies, result, missing, recursive, nest, true, name);
787
- nest.pop();
788
- }
789
- if (!optional) {
790
- result.requires[name] = true;
791
- debug$2("task: %s is enabled by %s", name, parent);
792
- }
793
- if (!result.sequence.includes(name)) result.sequence.push(name);
794
- }
795
- }
796
- function sequencify(tasks, names) {
797
- const result = {
798
- sequence: [],
799
- requires: {}
800
- };
801
- const missing = [];
802
- const recursive = [];
803
- sequence(tasks, names, result, missing, recursive, [], false, "app");
804
- if (missing.length > 0 || recursive.length > 0) result.sequence = [];
805
- return {
806
- sequence: result.sequence.filter((item) => result.requires[item]),
807
- missingTasks: missing,
808
- recursiveDependencies: recursive
809
- };
810
- }
811
-
812
- //#endregion
813
- //#region src/loader/egg_loader.ts
814
- const debug$1 = debuglog("egg/core/loader/egg_loader");
815
- const originalPrototypes = {
816
- request: Request$1.prototype,
817
- response: Response$1.prototype,
818
- context: Context$1.prototype,
819
- application: Application.prototype
820
- };
821
- var EggLoader = class {
822
- #requiredCount = 0;
823
- options;
824
- timing;
825
- pkg;
826
- eggPaths;
827
- serverEnv;
828
- serverScope;
829
- appInfo;
830
- dirs;
831
- /**
832
- * @class
833
- * @param {Object} options - options
834
- * @param {String} options.baseDir - the directory of application
835
- * @param {EggCore} options.app - Application instance
836
- * @param {Logger} options.logger - logger
837
- * @param {Object} [options.plugins] - custom plugins
838
- * @since 1.0.0
839
- */
840
- constructor(options) {
841
- this.options = options;
842
- assert(fs.existsSync(this.options.baseDir), `${this.options.baseDir} not exists`);
843
- assert(this.options.app, "options.app is required");
844
- assert(this.options.logger, "options.logger is required");
845
- this.timing = this.app.timing || new Timing();
846
- /**
847
- * @member {Object} EggLoader#pkg
848
- * @see {@link AppInfo#pkg}
849
- * @since 1.0.0
850
- */
851
- this.pkg = readJSONSync(path.join(this.options.baseDir, "package.json"));
852
- if (process.env.EGG_TYPESCRIPT === "true" || this.pkg.egg && this.pkg.egg.typescript) {
853
- const tsConfigFile = path.join(this.options.baseDir, "tsconfig.json");
854
- if (fs.existsSync(tsConfigFile)) register({ cwd: this.options.baseDir });
855
- else this.logger.info("[@eggjs/core/egg_loader] skip register \"tsconfig-paths\" because tsconfig.json not exists at %s", tsConfigFile);
856
- }
857
- /**
858
- * All framework directories.
859
- *
860
- * You can extend Application of egg, the entry point is options.app,
861
- *
862
- * loader will find all directories from the prototype of Application,
863
- * you should define `Symbol.for('egg#eggPath')` property.
864
- *
865
- * ```ts
866
- * // src/example.ts
867
- * import { Application } from 'egg';
868
- * class ExampleApplication extends Application {
869
- * get [Symbol.for('egg#eggPath')]() {
870
- * return baseDir;
871
- * }
872
- * }
873
- * ```
874
- * @member {Array} EggLoader#eggPaths
875
- * @see EggLoader#getEggPaths
876
- * @since 1.0.0
877
- */
878
- this.eggPaths = this.getEggPaths();
879
- debug$1("Loaded eggPaths %j", this.eggPaths);
880
- /**
881
- * @member {String} EggLoader#serverEnv
882
- * @see AppInfo#env
883
- * @since 1.0.0
884
- */
885
- this.serverEnv = this.getServerEnv();
886
- debug$1("Loaded serverEnv %j", this.serverEnv);
887
- /**
888
- * @member {String} EggLoader#serverScope
889
- * @see AppInfo#serverScope
890
- */
891
- this.serverScope = options.serverScope ?? this.getServerScope();
892
- /**
893
- * @member {AppInfo} EggLoader#appInfo
894
- * @since 1.0.0
895
- */
896
- this.appInfo = this.getAppInfo();
897
- }
898
- get app() {
899
- return this.options.app;
900
- }
901
- get lifecycle() {
902
- return this.app.lifecycle;
903
- }
904
- get logger() {
905
- return this.options.logger;
906
- }
907
- /**
908
- * Get {@link AppInfo#env}
909
- * @returns {String} env
910
- * @see AppInfo#env
911
- * @private
912
- * @since 1.0.0
913
- */
914
- getServerEnv() {
915
- let serverEnv = this.options.env;
916
- const envPath = path.join(this.options.baseDir, "config/env");
917
- if (!serverEnv && fs.existsSync(envPath)) serverEnv = fs.readFileSync(envPath, "utf8").trim();
918
- if (!serverEnv && process.env.EGG_SERVER_ENV) serverEnv = process.env.EGG_SERVER_ENV;
919
- if (serverEnv) serverEnv = serverEnv.trim();
920
- else if (process.env.NODE_ENV === "test") serverEnv = "unittest";
921
- else if (process.env.NODE_ENV === "production") serverEnv = "prod";
922
- else serverEnv = "local";
923
- return serverEnv;
924
- }
925
- /**
926
- * Get {@link AppInfo#scope}
927
- * @returns {String} serverScope
928
- * @private
929
- */
930
- getServerScope() {
931
- return process.env.EGG_SERVER_SCOPE ?? "";
932
- }
933
- /**
934
- * Get {@link AppInfo#name}
935
- * @returns {String} appname
936
- * @private
937
- * @since 1.0.0
938
- */
939
- getAppname() {
940
- if (this.pkg.name) {
941
- debug$1("Loaded appname(%s) from package.json", this.pkg.name);
942
- return this.pkg.name;
943
- }
944
- const pkg = path.join(this.options.baseDir, "package.json");
945
- throw new Error(`name is required from ${pkg}`);
946
- }
947
- /**
948
- * Get home directory
949
- * @returns {String} home directory
950
- * @since 3.4.0
951
- */
952
- getHomedir() {
953
- return process.env.EGG_HOME || homedir() || "/home/admin";
954
- }
955
- /**
956
- * Get app info
957
- * @returns {AppInfo} appInfo
958
- * @since 1.0.0
959
- */
960
- getAppInfo() {
961
- const env = this.serverEnv;
962
- const scope = this.serverScope;
963
- const home = this.getHomedir();
964
- const baseDir = this.options.baseDir;
965
- /**
966
- * Meta information of the application
967
- * @class AppInfo
968
- */
969
- return {
970
- name: this.getAppname(),
971
- baseDir,
972
- env,
973
- scope,
974
- HOME: home,
975
- pkg: this.pkg,
976
- root: env === "local" || env === "unittest" ? baseDir : home
977
- };
978
- }
979
- /**
980
- * Get {@link EggLoader#eggPaths}
981
- * @returns {Array} framework directories
982
- * @see {@link EggLoader#eggPaths}
983
- * @private
984
- * @since 1.0.0
985
- */
986
- getEggPaths() {
987
- const EggCore$1 = this.options.EggCoreClass;
988
- const eggPaths = [];
989
- let proto = this.app;
990
- while (proto) {
991
- proto = Object.getPrototypeOf(proto);
992
- if (proto === Object.prototype || proto === EggCore$1?.prototype) break;
993
- const eggPath = Reflect.get(proto, Symbol.for("egg#eggPath"));
994
- if (!eggPath) continue;
995
- assert(typeof eggPath === "string", "Symbol.for('egg#eggPath') should be string");
996
- assert(fs.existsSync(eggPath), `${eggPath} not exists`);
997
- const realpath = fs.realpathSync(eggPath);
998
- if (!eggPaths.includes(realpath)) eggPaths.unshift(realpath);
999
- }
1000
- return eggPaths;
1001
- }
1002
- /** start Plugin loader */
1003
- lookupDirs;
1004
- eggPlugins;
1005
- appPlugins;
1006
- customPlugins;
1007
- allPlugins;
1008
- orderPlugins;
1009
- /** enable plugins */
1010
- plugins;
1011
- /**
1012
- * Load config/plugin.js from {EggLoader#loadUnits}
1013
- *
1014
- * plugin.js is written below
1015
- *
1016
- * ```js
1017
- * {
1018
- * 'xxx-client': {
1019
- * enable: true,
1020
- * package: 'xxx-client',
1021
- * dep: [],
1022
- * env: [],
1023
- * },
1024
- * // short hand
1025
- * 'rds': false,
1026
- * 'depd': {
1027
- * enable: true,
1028
- * path: 'path/to/depd'
1029
- * }
1030
- * }
1031
- * ```
1032
- *
1033
- * If the plugin has path, Loader will find the module from it.
1034
- *
1035
- * Otherwise Loader will lookup follow the order by packageName
1036
- *
1037
- * 1. $APP_BASE/node_modules/${package}
1038
- * 2. $EGG_BASE/node_modules/${package}
1039
- *
1040
- * You can call `loader.plugins` that retrieve enabled plugins.
1041
- *
1042
- * ```js
1043
- * loader.plugins['xxx-client'] = {
1044
- * name: 'xxx-client', // the plugin name, it can be used in `dep`
1045
- * package: 'xxx-client', // the package name of plugin
1046
- * enable: true, // whether enabled
1047
- * path: 'path/to/xxx-client', // the directory of the plugin package
1048
- * dep: [], // the dependent plugins, you can use the plugin name
1049
- * env: [ 'local', 'unittest' ], // specify the serverEnv that only enable the plugin in it
1050
- * }
1051
- * ```
1052
- *
1053
- * `loader.allPlugins` can be used when retrieve all plugins.
1054
- * @function EggLoader#loadPlugin
1055
- * @since 1.0.0
1056
- */
1057
- async loadPlugin() {
1058
- this.timing.start("Load Plugin");
1059
- this.lookupDirs = this.getLookupDirs();
1060
- this.allPlugins = {};
1061
- this.eggPlugins = await this.loadEggPlugins();
1062
- this.appPlugins = await this.loadAppPlugins();
1063
- this.customPlugins = this.loadCustomPlugins();
1064
- this.#extendPlugins(this.allPlugins, this.eggPlugins);
1065
- this.#extendPlugins(this.allPlugins, this.appPlugins);
1066
- this.#extendPlugins(this.allPlugins, this.customPlugins);
1067
- const enabledPluginNames = [];
1068
- const plugins = {};
1069
- const env = this.serverEnv;
1070
- for (const name in this.allPlugins) {
1071
- const plugin = this.allPlugins[name];
1072
- plugin.path = this.getPluginPath(plugin);
1073
- await this.#mergePluginConfig(plugin);
1074
- if (env && plugin.env.length > 0 && !plugin.env.includes(env)) {
1075
- this.logger.info("[egg/core] Plugin %o is disabled by env unmatched, require env(%o) but got env is %o", name, plugin.env, env);
1076
- plugin.enable = false;
1077
- continue;
1078
- }
1079
- plugins[name] = plugin;
1080
- if (plugin.enable) enabledPluginNames.push(name);
1081
- }
1082
- this.orderPlugins = this.getOrderPlugins(plugins, enabledPluginNames, this.appPlugins);
1083
- const enablePlugins = {};
1084
- for (const plugin of this.orderPlugins) enablePlugins[plugin.name] = plugin;
1085
- debug$1("Loaded enable plugins: %j", Object.keys(enablePlugins));
1086
- /**
1087
- * Retrieve enabled plugins
1088
- * @member {Object} EggLoader#plugins
1089
- * @since 1.0.0
1090
- */
1091
- this.plugins = enablePlugins;
1092
- this.timing.end("Load Plugin");
1093
- }
1094
- async loadAppPlugins() {
1095
- const appPlugins = await this.readPluginConfigs(path.join(this.options.baseDir, "config/plugin.default"));
1096
- debug$1("Loaded app plugins: %j", Object.keys(appPlugins).map((k) => `${k}:${appPlugins[k].enable}`));
1097
- return appPlugins;
1098
- }
1099
- async loadEggPlugins() {
1100
- const eggPluginConfigPaths = this.eggPaths.map((eggPath) => path.join(eggPath, "config/plugin.default"));
1101
- const eggPlugins = await this.readPluginConfigs(eggPluginConfigPaths);
1102
- debug$1("Loaded egg plugins: %j", Object.keys(eggPlugins).map((k) => `${k}:${eggPlugins[k].enable}`));
1103
- return eggPlugins;
1104
- }
1105
- loadCustomPlugins() {
1106
- let customPlugins = {};
1107
- const configPaths = [];
1108
- if (process.env.EGG_PLUGINS) try {
1109
- customPlugins = JSON.parse(process.env.EGG_PLUGINS);
1110
- configPaths.push("<process.env.EGG_PLUGINS>");
1111
- } catch (e) {
1112
- debug$1("parse EGG_PLUGINS failed, %s", e);
1113
- }
1114
- if (this.options.plugins) {
1115
- customPlugins = {
1116
- ...customPlugins,
1117
- ...this.options.plugins
1118
- };
1119
- configPaths.push("<options.plugins>");
1120
- }
1121
- if (customPlugins) {
1122
- const configPath = configPaths.join(" or ");
1123
- for (const name in customPlugins) this.#normalizePluginConfig(customPlugins, name, configPath);
1124
- debug$1("Loaded custom plugins: %o", customPlugins);
1125
- }
1126
- return customPlugins;
1127
- }
1128
- async readPluginConfigs(configPaths) {
1129
- if (!Array.isArray(configPaths)) configPaths = [configPaths];
1130
- const newConfigPaths = [];
1131
- for (const filename of this.getTypeFiles("plugin")) for (let configPath of configPaths) {
1132
- configPath = path.join(path.dirname(configPath), filename);
1133
- newConfigPaths.push(configPath);
1134
- }
1135
- const plugins = {};
1136
- for (const configPath of newConfigPaths) {
1137
- let filepath = this.resolveModule(configPath);
1138
- if (configPath.endsWith("plugin.default") && !filepath) filepath = this.resolveModule(configPath.replace(/plugin\.default$/, "plugin"));
1139
- if (!filepath) {
1140
- debug$1("[readPluginConfigs:ignore] plugin config not found %o", configPath);
1141
- continue;
1142
- }
1143
- const config = await utils_default.loadFile(filepath);
1144
- for (const name in config) this.#normalizePluginConfig(config, name, filepath);
1145
- this.#extendPlugins(plugins, config);
1146
- }
1147
- return plugins;
1148
- }
1149
- #normalizePluginConfig(plugins, name, configPath) {
1150
- const plugin = plugins[name];
1151
- if (typeof plugin === "boolean") {
1152
- plugins[name] = {
1153
- name,
1154
- enable: plugin,
1155
- dependencies: [],
1156
- optionalDependencies: [],
1157
- env: [],
1158
- from: configPath
1159
- };
1160
- return;
1161
- }
1162
- if (!("enable" in plugin)) Reflect.set(plugin, "enable", true);
1163
- plugin.name = name;
1164
- plugin.dependencies = plugin.dependencies || [];
1165
- plugin.optionalDependencies = plugin.optionalDependencies || [];
1166
- plugin.env = plugin.env || [];
1167
- plugin.from = plugin.from || configPath;
1168
- depCompatible(plugin);
1169
- }
1170
- async #mergePluginConfig(plugin) {
1171
- let pkg;
1172
- let config;
1173
- const pluginPackage = path.join(plugin.path, "package.json");
1174
- if (await utils_default.existsPath(pluginPackage)) {
1175
- pkg = await readJSON(pluginPackage);
1176
- config = pkg.eggPlugin;
1177
- if (pkg.version) plugin.version = pkg.version;
1178
- plugin.path = await this.#formatPluginPathFromPackageJSON(plugin.path, pkg);
1179
- }
1180
- const logger = this.options.logger;
1181
- if (!config) {
1182
- logger.warn(`[@eggjs/core/egg_loader] pkg.eggPlugin is missing in ${pluginPackage}`);
1183
- return;
1184
- }
1185
- if (config.name && config.strict !== false && config.name !== plugin.name) logger.warn(`[@eggjs/core/egg_loader] pluginName(${plugin.name}) is different from pluginConfigName(${config.name})`);
1186
- depCompatible(config);
1187
- for (const key of [
1188
- "dependencies",
1189
- "optionalDependencies",
1190
- "env"
1191
- ]) {
1192
- const values = config[key];
1193
- const existsValues = Reflect.get(plugin, key);
1194
- if (Array.isArray(values) && !existsValues?.length) Reflect.set(plugin, key, values);
1195
- }
1196
- }
1197
- getOrderPlugins(allPlugins, enabledPluginNames, appPlugins) {
1198
- if (enabledPluginNames.length === 0) return [];
1199
- const result = sequencify(allPlugins, enabledPluginNames);
1200
- debug$1("Got plugins %j after sequencify", result);
1201
- if (result.sequence.length === 0) {
1202
- const err = /* @__PURE__ */ new Error(`sequencify plugins has problem, missing: [${result.missingTasks}], recursive: [${result.recursiveDependencies}]`);
1203
- for (const missName of result.missingTasks) {
1204
- const requires = [];
1205
- for (const name in allPlugins) if (allPlugins[name].dependencies.includes(missName)) requires.push(name);
1206
- err.message += `\n\t>> Plugin [${missName}] is disabled or missed, but is required by [${requires}]`;
1207
- }
1208
- err.name = "PluginSequencifyError";
1209
- throw err;
1210
- }
1211
- const implicitEnabledPlugins = [];
1212
- const requireMap = {};
1213
- for (const name of result.sequence) {
1214
- for (const depName of allPlugins[name].dependencies) {
1215
- if (!requireMap[depName]) requireMap[depName] = [];
1216
- requireMap[depName].push(name);
1217
- }
1218
- if (!allPlugins[name].enable) {
1219
- implicitEnabledPlugins.push(name);
1220
- allPlugins[name].enable = true;
1221
- allPlugins[name].implicitEnable = true;
1222
- }
1223
- }
1224
- for (const [name, dependents] of Object.entries(requireMap)) allPlugins[name].dependents = dependents;
1225
- if (implicitEnabledPlugins.length > 0) {
1226
- let message = implicitEnabledPlugins.map((name) => ` - ${name} required by [${requireMap[name]}]`).join("\n");
1227
- this.options.logger.info(`Following plugins will be enabled implicitly.\n${message}`);
1228
- const disabledPlugins = implicitEnabledPlugins.filter((name) => appPlugins[name] && appPlugins[name].enable === false);
1229
- if (disabledPlugins.length > 0) {
1230
- message = disabledPlugins.map((name) => ` - ${name} required by [${requireMap[name]}]`).join("\n");
1231
- this.options.logger.warn(`Following plugins will be enabled implicitly that is disabled by application.\n${message}`);
1232
- }
1233
- }
1234
- return result.sequence.map((name) => allPlugins[name]);
1235
- }
1236
- getLookupDirs() {
1237
- const lookupDirs = /* @__PURE__ */ new Set();
1238
- lookupDirs.add(this.options.baseDir);
1239
- for (let i = this.eggPaths.length - 1; i >= 0; i--) {
1240
- const eggPath = this.eggPaths[i];
1241
- lookupDirs.add(eggPath);
1242
- }
1243
- lookupDirs.add(process.cwd());
1244
- return lookupDirs;
1245
- }
1246
- getPluginPath(plugin) {
1247
- if (plugin.path) return plugin.path;
1248
- if (plugin.package) assert(isValidatePackageName(plugin.package), `plugin ${plugin.name} invalid, use 'path' instead of package: "${plugin.package}"`);
1249
- return this.#resolvePluginPath(plugin);
1250
- }
1251
- #resolvePluginPath(plugin) {
1252
- const name = plugin.package || plugin.name;
1253
- try {
1254
- const pluginPkgFile = utils_default.resolvePath(`${name}/package.json`, { paths: [...this.lookupDirs] });
1255
- return path.dirname(pluginPkgFile);
1256
- } catch (err) {
1257
- debug$1("[resolvePluginPath] error: %o, plugin info: %o", err, plugin);
1258
- throw new Error(`Can not find plugin ${name} in "${[...this.lookupDirs].join(", ")}"`, { cause: err });
1259
- }
1260
- }
1261
- async #formatPluginPathFromPackageJSON(pluginPath, pluginPkg) {
1262
- let realPluginPath = pluginPath;
1263
- const exports = pluginPkg.eggPlugin?.exports;
1264
- if (exports) {
1265
- if (isESM) {
1266
- if (exports.import) realPluginPath = path.join(pluginPath, exports.import);
1267
- } else if (exports.require) realPluginPath = path.join(pluginPath, exports.require);
1268
- if (exports.typescript && isSupportTypeScript() && !await exists(realPluginPath)) {
1269
- realPluginPath = path.join(pluginPath, exports.typescript);
1270
- debug$1("[formatPluginPathFromPackageJSON] use typescript path %o", realPluginPath);
1271
- }
1272
- } else if (pluginPkg.exports?.["."] && pluginPkg.type === "module") {
1273
- let defaultExport = pluginPkg.exports["."];
1274
- if (typeof defaultExport === "string") realPluginPath = path.dirname(path.join(pluginPath, defaultExport));
1275
- else if (defaultExport?.import) {
1276
- if (typeof defaultExport.import === "string") realPluginPath = path.dirname(path.join(pluginPath, defaultExport.import));
1277
- else if (defaultExport.import.default) realPluginPath = path.dirname(path.join(pluginPath, defaultExport.import.default));
1278
- }
1279
- debug$1("[formatPluginPathFromPackageJSON] resolve plugin path from %o to %o, defaultExport: %o", pluginPath, realPluginPath, defaultExport);
1280
- }
1281
- return realPluginPath;
1282
- }
1283
- #extendPlugins(targets, plugins) {
1284
- if (!plugins) return;
1285
- for (const name in plugins) {
1286
- const plugin = plugins[name];
1287
- let targetPlugin = targets[name];
1288
- if (!targetPlugin) {
1289
- targetPlugin = {};
1290
- targets[name] = targetPlugin;
1291
- }
1292
- if (targetPlugin.package && targetPlugin.package === plugin.package) this.logger.warn("[@eggjs/core] plugin %s has been defined that is %j, but you define again in %s", name, targetPlugin, plugin.from);
1293
- if (plugin.path || plugin.package) {
1294
- delete targetPlugin.path;
1295
- delete targetPlugin.package;
1296
- }
1297
- for (const [prop, value] of Object.entries(plugin)) {
1298
- if (value === void 0) continue;
1299
- if (Reflect.get(targetPlugin, prop) && Array.isArray(value) && value.length === 0) continue;
1300
- Reflect.set(targetPlugin, prop, value);
1301
- }
1302
- }
1303
- }
1304
- /** end Plugin loader */
1305
- /** start Config loader */
1306
- configMeta;
1307
- config;
1308
- /**
1309
- * Load config/config.js
1310
- *
1311
- * Will merge config.default.js 和 config.${env}.js
1312
- *
1313
- * @function EggLoader#loadConfig
1314
- * @since 1.0.0
1315
- */
1316
- async loadConfig() {
1317
- this.timing.start("Load Config");
1318
- this.configMeta = {};
1319
- const target = {
1320
- middleware: [],
1321
- coreMiddleware: []
1322
- };
1323
- const appConfig = await this.#preloadAppConfig();
1324
- for (const filename of this.getTypeFiles("config")) for (const unit of this.getLoadUnits()) {
1325
- const isApp = unit.type === "app";
1326
- const config = await this.#loadConfig(unit.path, filename, isApp ? void 0 : appConfig, unit.type);
1327
- if (!config) continue;
1328
- debug$1("[loadConfig] Loaded config %s/%s, %j", unit.path, filename, config);
1329
- extend(true, target, config);
1330
- }
1331
- const envConfig = this.#loadConfigFromEnv();
1332
- debug$1("[loadConfig] Loaded config from env, %j", envConfig);
1333
- extend(true, target, envConfig);
1334
- target.coreMiddleware = target.coreMiddleware || [];
1335
- target.coreMiddlewares = target.coreMiddleware;
1336
- target.appMiddleware = target.middleware || [];
1337
- target.appMiddlewares = target.appMiddleware;
1338
- this.config = target;
1339
- debug$1("[loadConfig] all config: %o", this.config);
1340
- this.timing.end("Load Config");
1341
- }
1342
- async #preloadAppConfig() {
1343
- const names = ["config.default", `config.${this.serverEnv}`];
1344
- const target = {};
1345
- for (const filename of names) {
1346
- const config = await this.#loadConfig(this.options.baseDir, filename, void 0, "app");
1347
- if (!config) continue;
1348
- extend(true, target, config);
1349
- }
1350
- return target;
1351
- }
1352
- async #loadConfig(dirpath, filename, extraInject, type) {
1353
- const isPlugin = type === "plugin";
1354
- const isApp = type === "app";
1355
- let filepath = this.resolveModule(path.join(dirpath, "config", filename));
1356
- if (filename === "config.default" && !filepath) filepath = this.resolveModule(path.join(dirpath, "config/config"));
1357
- if (!filepath) return;
1358
- const config = await this.loadFile(filepath, this.appInfo, extraInject);
1359
- if (!config) return;
1360
- if (isPlugin || isApp) assert(!config.coreMiddleware, "Can not define coreMiddleware in app or plugin");
1361
- if (!isApp) assert(!config.middleware, "Can not define middleware in " + filepath);
1362
- this.#setConfigMeta(config, filepath);
1363
- return config;
1364
- }
1365
- #loadConfigFromEnv() {
1366
- const envConfigStr = process.env.EGG_APP_CONFIG;
1367
- if (!envConfigStr) return;
1368
- try {
1369
- const envConfig = JSON.parse(envConfigStr);
1370
- this.#setConfigMeta(envConfig, "<process.env.EGG_APP_CONFIG>");
1371
- return envConfig;
1372
- } catch {
1373
- this.options.logger.warn("[egg-loader] process.env.EGG_APP_CONFIG is not invalid JSON: %s", envConfigStr);
1374
- }
1375
- }
1376
- #setConfigMeta(config, filepath) {
1377
- config = extend(true, {}, config);
1378
- this.#setConfig(config, filepath);
1379
- extend(true, this.configMeta, config);
1380
- }
1381
- #setConfig(obj, filepath) {
1382
- for (const key of Object.keys(obj)) {
1383
- const val = obj[key];
1384
- if (key === "console" && val && typeof val.Console === "function" && val.Console === console.Console) {
1385
- obj[key] = filepath;
1386
- continue;
1387
- }
1388
- if (val && Object.getPrototypeOf(val) === Object.prototype && Object.keys(val).length > 0) {
1389
- this.#setConfig(val, filepath);
1390
- continue;
1391
- }
1392
- obj[key] = filepath;
1393
- }
1394
- }
1395
- /** end Config loader */
1396
- /** start Extend loader */
1397
- /**
1398
- * mixin Agent.prototype
1399
- * @function EggLoader#loadAgentExtend
1400
- * @since 1.0.0
1401
- */
1402
- async loadAgentExtend() {
1403
- await this.loadExtend("agent", this.app);
1404
- }
1405
- /**
1406
- * mixin Application.prototype
1407
- * @function EggLoader#loadApplicationExtend
1408
- * @since 1.0.0
1409
- */
1410
- async loadApplicationExtend() {
1411
- await this.loadExtend("application", this.app);
1412
- }
1413
- /**
1414
- * mixin Request.prototype
1415
- * @function EggLoader#loadRequestExtend
1416
- * @since 1.0.0
1417
- */
1418
- async loadRequestExtend() {
1419
- await this.loadExtend("request", this.app.request);
1420
- }
1421
- /**
1422
- * mixin Response.prototype
1423
- * @function EggLoader#loadResponseExtend
1424
- * @since 1.0.0
1425
- */
1426
- async loadResponseExtend() {
1427
- await this.loadExtend("response", this.app.response);
1428
- }
1429
- /**
1430
- * mixin Context.prototype
1431
- * @function EggLoader#loadContextExtend
1432
- * @since 1.0.0
1433
- */
1434
- async loadContextExtend() {
1435
- await this.loadExtend("context", this.app.context);
1436
- }
1437
- /**
1438
- * mixin app.Helper.prototype
1439
- * @function EggLoader#loadHelperExtend
1440
- * @since 1.0.0
1441
- */
1442
- async loadHelperExtend() {
1443
- if (this.app.Helper) await this.loadExtend("helper", this.app.Helper.prototype);
1444
- }
1445
- /**
1446
- * Find all extend file paths by name
1447
- * can be override in top level framework to support load `app/extends/{name}.js`
1448
- *
1449
- * @param {String} name - filename which may be `app/extend/{name}.js`
1450
- * @returns {Array} filepaths extend file paths
1451
- * @private
1452
- */
1453
- getExtendFilePaths(name) {
1454
- return this.getLoadUnits().map((unit) => path.join(unit.path, "app/extend", name));
1455
- }
1456
- /**
1457
- * Loader app/extend/xx.js to `prototype`,
1458
- * @function loadExtend
1459
- * @param {String} name - filename which may be `app/extend/{name}.js`
1460
- * @param {Object} proto - prototype that mixed
1461
- * @since 1.0.0
1462
- */
1463
- async loadExtend(name, proto) {
1464
- this.timing.start(`Load extend/${name}.js`);
1465
- const filepaths = this.getExtendFilePaths(name);
1466
- const needUnittest = "EGG_MOCK_SERVER_ENV" in process.env && this.serverEnv !== "unittest";
1467
- const length = filepaths.length;
1468
- for (let i = 0; i < length; i++) {
1469
- const filepath = filepaths[i];
1470
- filepaths.push(filepath + `.${this.serverEnv}`);
1471
- if (needUnittest) filepaths.push(filepath + ".unittest");
1472
- }
1473
- debug$1("loadExtend %s, filepaths: %j", name, filepaths);
1474
- const mergeRecord = /* @__PURE__ */ new Map();
1475
- for (const rawFilepath of filepaths) {
1476
- const filepath = this.resolveModule(rawFilepath);
1477
- if (!filepath) continue;
1478
- if (filepath.endsWith("/index.js")) this.app.deprecate(`app/extend/${name}/index.js is deprecated, use app/extend/${name}.js instead`);
1479
- else if (filepath.endsWith("/index.ts")) this.app.deprecate(`app/extend/${name}/index.ts is deprecated, use app/extend/${name}.ts instead`);
1480
- let ext = await this.requireFile(filepath);
1481
- if (isClass(ext)) ext = ext.prototype;
1482
- const properties = Object.getOwnPropertyNames(ext).concat(Object.getOwnPropertySymbols(ext)).filter((name$1) => name$1 !== "constructor");
1483
- for (const property of properties) {
1484
- if (mergeRecord.has(property)) debug$1("Property: \"%s\" already exists in \"%s\",it will be redefined by \"%s\"", property, mergeRecord.get(property), filepath);
1485
- let descriptor = Object.getOwnPropertyDescriptor(ext, property);
1486
- let originalDescriptor = Object.getOwnPropertyDescriptor(proto, property);
1487
- if (!originalDescriptor) {
1488
- const originalProto = originalPrototypes[name];
1489
- if (originalProto) originalDescriptor = Object.getOwnPropertyDescriptor(originalProto, property);
1490
- }
1491
- if (originalDescriptor) {
1492
- descriptor = { ...descriptor };
1493
- if (!descriptor.set && originalDescriptor.set) descriptor.set = originalDescriptor.set;
1494
- if (!descriptor.get && originalDescriptor.get) descriptor.get = originalDescriptor.get;
1495
- }
1496
- Object.defineProperty(proto, property, descriptor);
1497
- mergeRecord.set(property, filepath);
1498
- }
1499
- debug$1("merge %j to %s from %s", properties, name, filepath);
1500
- }
1501
- this.timing.end(`Load extend/${name}.js`);
1502
- }
1503
- /** end Extend loader */
1504
- /** start Custom loader */
1505
- /**
1506
- * load app.js
1507
- *
1508
- * @example
1509
- * - old:
1510
- *
1511
- * ```js
1512
- * module.exports = function(app) {
1513
- * doSomething();
1514
- * }
1515
- * ```
1516
- *
1517
- * - new:
1518
- *
1519
- * ```js
1520
- * module.exports = class Boot {
1521
- * constructor(app) {
1522
- * this.app = app;
1523
- * }
1524
- * configDidLoad() {
1525
- * doSomething();
1526
- * }
1527
- * }
1528
- * @since 1.0.0
1529
- */
1530
- async loadCustomApp() {
1531
- await this.#loadBootHook("app");
1532
- this.lifecycle.triggerConfigWillLoad();
1533
- }
1534
- /**
1535
- * Load agent.js, same as {@link EggLoader#loadCustomApp}
1536
- */
1537
- async loadCustomAgent() {
1538
- await this.#loadBootHook("agent");
1539
- this.lifecycle.triggerConfigWillLoad();
1540
- }
1541
- loadBootHook() {}
1542
- async #loadBootHook(fileName) {
1543
- this.timing.start(`Load ${fileName}.js`);
1544
- for (const unit of this.getLoadUnits()) {
1545
- const bootFile = path.join(unit.path, fileName);
1546
- const bootFilePath = this.resolveModule(bootFile);
1547
- if (!bootFilePath) {
1548
- debug$1("[loadBootHook:ignore] %o not found", bootFile);
1549
- continue;
1550
- }
1551
- debug$1("[loadBootHook:success] %o => %o", bootFile, bootFilePath);
1552
- const bootHook = await this.requireFile(bootFilePath);
1553
- if (isClass(bootHook)) {
1554
- bootHook.prototype.fullPath = bootFilePath;
1555
- this.lifecycle.addBootHook(bootHook);
1556
- debug$1("[loadBootHook] add BootHookClass from %o", bootFilePath);
1557
- } else if (typeof bootHook === "function") {
1558
- this.lifecycle.addFunctionAsBootHook(bootHook, bootFilePath);
1559
- debug$1("[loadBootHook] add bootHookFunction from %o", bootFilePath);
1560
- } else this.options.logger.warn("[@eggjs/core/egg_loader] %s must exports a boot class", bootFilePath);
1561
- }
1562
- this.lifecycle.init();
1563
- this.timing.end(`Load ${fileName}.js`);
1564
- }
1565
- /** end Custom loader */
1566
- /** start Service loader */
1567
- /**
1568
- * Load app/service
1569
- * @function EggLoader#loadService
1570
- * @param {Object} options - LoaderOptions
1571
- * @since 1.0.0
1572
- */
1573
- async loadService(options) {
1574
- this.timing.start("Load Service");
1575
- const servicePaths = this.getLoadUnits().map((unit) => path.join(unit.path, "app/service"));
1576
- options = {
1577
- call: true,
1578
- caseStyle: CaseStyle.lower,
1579
- fieldClass: "serviceClasses",
1580
- directory: servicePaths,
1581
- ...options
1582
- };
1583
- debug$1("[loadService] options: %o", options);
1584
- await this.loadToContext(servicePaths, "service", options);
1585
- this.timing.end("Load Service");
1586
- }
1587
- /** end Service loader */
1588
- /** start Middleware loader */
1589
- /**
1590
- * Load app/middleware
1591
- *
1592
- * app.config.xx is the options of the middleware xx that has same name as config
1593
- *
1594
- * @function EggLoader#loadMiddleware
1595
- * @param {Object} opt - LoaderOptions
1596
- * @example
1597
- * ```js
1598
- * // app/middleware/status.js
1599
- * module.exports = function(options, app) {
1600
- * // options == app.config.status
1601
- * return async next => {
1602
- * await next();
1603
- * }
1604
- * }
1605
- * ```
1606
- * @since 1.0.0
1607
- */
1608
- async loadMiddleware(opt) {
1609
- this.timing.start("Load Middleware");
1610
- const app = this.app;
1611
- const middlewarePaths = this.getLoadUnits().map((unit) => path.join(unit.path, "app/middleware"));
1612
- opt = {
1613
- call: false,
1614
- override: true,
1615
- caseStyle: CaseStyle.lower,
1616
- directory: middlewarePaths,
1617
- ...opt
1618
- };
1619
- await this.loadToApp(middlewarePaths, "middlewares", opt);
1620
- debug$1("[loadMiddleware] middlewarePaths: %j", middlewarePaths);
1621
- for (const name in app.middlewares) Object.defineProperty(app.middleware, name, {
1622
- get() {
1623
- return app.middlewares[name];
1624
- },
1625
- enumerable: false,
1626
- configurable: false
1627
- });
1628
- this.options.logger.info("Use coreMiddleware order: %j", this.config.coreMiddleware);
1629
- this.options.logger.info("Use appMiddleware order: %j", this.config.appMiddleware);
1630
- const middlewareNames = this.config.coreMiddleware.concat(this.config.appMiddleware);
1631
- debug$1("[loadMiddleware] middlewareNames: %j", middlewareNames);
1632
- const middlewaresMap = /* @__PURE__ */ new Map();
1633
- for (const name of middlewareNames) {
1634
- const createMiddleware = app.middlewares[name];
1635
- if (!createMiddleware) throw new TypeError(`Middleware ${name} not found`);
1636
- if (middlewaresMap.has(name)) throw new TypeError(`Middleware ${name} redefined`);
1637
- middlewaresMap.set(name, true);
1638
- const options = this.config[name] || {};
1639
- let mw$1 = createMiddleware(options, app);
1640
- assert(typeof mw$1 === "function", `Middleware ${name} must be a function, but actual is ${inspect(mw$1)}`);
1641
- if (isGeneratorFunction(mw$1)) {
1642
- const fullpath = Reflect.get(createMiddleware, FULLPATH);
1643
- throw new TypeError(`Support for generators was removed, middleware: ${name}, fullpath: ${fullpath}`);
1644
- }
1645
- mw$1._name = name;
1646
- mw$1 = wrapMiddleware(mw$1, options);
1647
- if (mw$1) {
1648
- if (debug$1.enabled) mw$1 = debugMiddlewareWrapper(mw$1);
1649
- app.use(mw$1);
1650
- debug$1("[loadMiddleware] Use middleware: %s with options: %j", name, options);
1651
- this.options.logger.info("[@eggjs/core/egg_loader] Use middleware: %s", name);
1652
- } else this.options.logger.info("[@eggjs/core/egg_loader] Disable middleware: %s", name);
1653
- }
1654
- this.options.logger.info("[@eggjs/core/egg_loader] Loaded middleware from %j", middlewarePaths);
1655
- this.timing.end("Load Middleware");
1656
- const mw = this.app.router.middleware();
1657
- Reflect.set(mw, "_name", "routerMiddleware");
1658
- this.app.use(mw);
1659
- }
1660
- /** end Middleware loader */
1661
- /** start Controller loader */
1662
- /**
1663
- * Load app/controller
1664
- * @param {Object} opt - LoaderOptions
1665
- * @since 1.0.0
1666
- */
1667
- async loadController(opt) {
1668
- this.timing.start("Load Controller");
1669
- const controllerBase = path.join(this.options.baseDir, "app/controller");
1670
- opt = {
1671
- caseStyle: CaseStyle.lower,
1672
- directory: controllerBase,
1673
- initializer: (obj, opt$1) => {
1674
- if (isGeneratorFunction(obj)) throw new TypeError(`Support for generators was removed, fullpath: ${opt$1.path}`);
1675
- if (!isClass(obj) && !isAsyncFunction(obj) && typeof obj === "function") {
1676
- obj = obj(this.app);
1677
- debug$1("[loadController] after init(app) => %o, meta: %j", obj, opt$1);
1678
- if (isGeneratorFunction(obj)) throw new TypeError(`Support for generators was removed, fullpath: ${opt$1.path}`);
1679
- }
1680
- if (isClass(obj)) {
1681
- obj.prototype.pathName = opt$1.pathName;
1682
- obj.prototype.fullPath = opt$1.path;
1683
- return wrapControllerClass(obj, opt$1.path);
1684
- }
1685
- if (isObject(obj)) return wrapObject(obj, opt$1.path);
1686
- if (isAsyncFunction(obj)) return wrapObject({ "module.exports": obj }, opt$1.path)["module.exports"];
1687
- return obj;
1688
- },
1689
- ...opt
1690
- };
1691
- await this.loadToApp(controllerBase, "controller", opt);
1692
- debug$1("[loadController] app.controller => %o", this.app.controller);
1693
- this.options.logger.info("[@eggjs/core/egg_loader] Controller loaded: %s", controllerBase);
1694
- this.timing.end("Load Controller");
1695
- }
1696
- /** end Controller loader */
1697
- /** start Router loader */
1698
- /**
1699
- * Load app/router.js
1700
- * @function EggLoader#loadRouter
1701
- * @since 1.0.0
1702
- */
1703
- async loadRouter() {
1704
- this.timing.start("Load Router");
1705
- await this.loadFile(path.join(this.options.baseDir, "app/router"));
1706
- this.timing.end("Load Router");
1707
- }
1708
- /** end Router loader */
1709
- /** start CustomLoader loader */
1710
- async loadCustomLoader() {
1711
- assert(this.config, "should loadConfig first");
1712
- const customLoader = this.config.customLoader || {};
1713
- for (const property of Object.keys(customLoader)) {
1714
- const loaderConfig = { ...customLoader[property] };
1715
- assert(loaderConfig.directory, `directory is required for config.customLoader.${property}`);
1716
- let directory;
1717
- if (loaderConfig.loadunit === true) directory = this.getLoadUnits().map((unit) => path.join(unit.path, loaderConfig.directory));
1718
- else directory = path.join(this.appInfo.baseDir, loaderConfig.directory);
1719
- const inject = loaderConfig.inject || "app";
1720
- debug$1("[loadCustomLoader] loaderConfig: %o, inject: %o, directory: %o", loaderConfig, inject, directory);
1721
- switch (inject) {
1722
- case "ctx": {
1723
- assert(!(property in this.app.context), `customLoader should not override ctx.${property}`);
1724
- const options = {
1725
- caseStyle: CaseStyle.lower,
1726
- fieldClass: `${property}Classes`,
1727
- ...loaderConfig,
1728
- directory
1729
- };
1730
- await this.loadToContext(directory, property, options);
1731
- break;
1732
- }
1733
- case "app": {
1734
- assert(!(property in this.app), `customLoader should not override app.${property}`);
1735
- const options = {
1736
- caseStyle: CaseStyle.lower,
1737
- initializer: (Clazz) => {
1738
- return isClass(Clazz) ? new Clazz(this.app) : Clazz;
1739
- },
1740
- ...loaderConfig,
1741
- directory
1742
- };
1743
- await this.loadToApp(directory, property, options);
1744
- break;
1745
- }
1746
- default: throw new Error("inject only support app or ctx");
1747
- }
1748
- }
1749
- }
1750
- /** end CustomLoader loader */
1751
- /**
1752
- * Load single file, will invoke when export is function
1753
- *
1754
- * @param {String} filepath - fullpath
1755
- * @param {Array} inject - pass rest arguments into the function when invoke
1756
- * @returns {Object} exports
1757
- * @example
1758
- * ```js
1759
- * app.loader.loadFile(path.join(app.options.baseDir, 'config/router.js'));
1760
- * ```
1761
- * @since 1.0.0
1762
- */
1763
- async loadFile(filepath, ...inject) {
1764
- const fullpath = filepath && this.resolveModule(filepath);
1765
- if (!fullpath) return null;
1766
- if (inject.length === 0) inject = [this.app];
1767
- let mod = await this.requireFile(fullpath);
1768
- if (typeof mod === "function" && !isClass(mod)) {
1769
- mod = mod(...inject);
1770
- if (isPromise(mod)) mod = await mod;
1771
- }
1772
- return mod;
1773
- }
1774
- /**
1775
- * @param {String} filepath - fullpath
1776
- * @private
1777
- */
1778
- async requireFile(filepath) {
1779
- const timingKey = `Require(${this.#requiredCount++}) ${utils_default.getResolvedFilename(filepath, this.options.baseDir)}`;
1780
- this.timing.start(timingKey);
1781
- const mod = await utils_default.loadFile(filepath);
1782
- this.timing.end(timingKey);
1783
- return mod;
1784
- }
1785
- /**
1786
- * Get all loadUnit
1787
- *
1788
- * loadUnit is a directory that can be loaded by EggLoader, it has the same structure.
1789
- * loadUnit has a path and a type(app, framework, plugin).
1790
- *
1791
- * The order of the loadUnits:
1792
- *
1793
- * 1. plugin
1794
- * 2. framework
1795
- * 3. app
1796
- *
1797
- * @returns {Array} loadUnits
1798
- * @since 1.0.0
1799
- */
1800
- getLoadUnits() {
1801
- if (this.dirs) return this.dirs;
1802
- this.dirs = [];
1803
- if (this.orderPlugins) for (const plugin of this.orderPlugins) this.dirs.push({
1804
- path: plugin.path,
1805
- type: "plugin"
1806
- });
1807
- for (const eggPath of this.eggPaths) this.dirs.push({
1808
- path: eggPath,
1809
- type: "framework"
1810
- });
1811
- this.dirs.push({
1812
- path: this.options.baseDir,
1813
- type: "app"
1814
- });
1815
- debug$1("Loaded dirs %j", this.dirs);
1816
- return this.dirs;
1817
- }
1818
- /**
1819
- * Load files using {@link FileLoader}, inject to {@link Application}
1820
- * @param {String|Array} directory - see {@link FileLoader}
1821
- * @param {String} property - see {@link FileLoader}, e.g.: 'controller', 'middlewares'
1822
- * @param {Object} options - see {@link FileLoader}
1823
- * @since 1.0.0
1824
- */
1825
- async loadToApp(directory, property, options) {
1826
- const target = {};
1827
- Reflect.set(this.app, property, target);
1828
- const loadOptions = {
1829
- ...options,
1830
- directory: options?.directory ?? directory,
1831
- target,
1832
- inject: this.app
1833
- };
1834
- const timingKey = `Load "${String(property)}" to Application`;
1835
- this.timing.start(timingKey);
1836
- await new FileLoader(loadOptions).load();
1837
- this.timing.end(timingKey);
1838
- }
1839
- /**
1840
- * Load files using {@link ContextLoader}
1841
- * @param {String|Array} directory - see {@link ContextLoader}
1842
- * @param {String} property - see {@link ContextLoader}
1843
- * @param {Object} options - see {@link ContextLoader}
1844
- * @since 1.0.0
1845
- */
1846
- async loadToContext(directory, property, options) {
1847
- const loadOptions = {
1848
- ...options,
1849
- directory: options?.directory || directory,
1850
- property,
1851
- inject: this.app
1852
- };
1853
- const timingKey = `Load "${String(property)}" to Context`;
1854
- this.timing.start(timingKey);
1855
- await new ContextLoader(loadOptions).load();
1856
- this.timing.end(timingKey);
1857
- }
1858
- /**
1859
- * @member {FileLoader} EggLoader#FileLoader
1860
- * @since 1.0.0
1861
- */
1862
- get FileLoader() {
1863
- return FileLoader;
1864
- }
1865
- /**
1866
- * @member {ContextLoader} EggLoader#ContextLoader
1867
- * @since 1.0.0
1868
- */
1869
- get ContextLoader() {
1870
- return ContextLoader;
1871
- }
1872
- getTypeFiles(filename) {
1873
- const files = [`${filename}.default`];
1874
- if (this.serverScope) files.push(`${filename}.${this.serverScope}`);
1875
- if (this.serverEnv === "default") return files;
1876
- files.push(`${filename}.${this.serverEnv}`);
1877
- if (this.serverScope) files.push(`${filename}.${this.serverScope}_${this.serverEnv}`);
1878
- return files;
1879
- }
1880
- resolveModule(filepath) {
1881
- let fullPath;
1882
- try {
1883
- fullPath = utils_default.resolvePath(filepath);
1884
- } catch {
1885
- return;
1886
- }
1887
- return fullPath;
1888
- }
1889
- };
1890
- function depCompatible(plugin) {
1891
- if (plugin.dep && !(Array.isArray(plugin.dependencies) && plugin.dependencies.length > 0)) {
1892
- plugin.dependencies = plugin.dep;
1893
- delete plugin.dep;
1894
- }
1895
- }
1896
- function isValidatePackageName(name) {
1897
- if (name.startsWith(".")) return false;
1898
- if (name.startsWith("/")) return false;
1899
- if (name.includes(":")) return false;
1900
- return true;
1901
- }
1902
- function wrapMiddleware(mw, options) {
1903
- if (options.enable === false) return null;
1904
- if (!options.match && !options.ignore) return mw;
1905
- const match = pathMatching(options);
1906
- const fn = (ctx, next) => {
1907
- if (!match(ctx)) return next();
1908
- return mw(ctx, next);
1909
- };
1910
- fn._name = `${mw._name}middlewareWrapper`;
1911
- return fn;
1912
- }
1913
- function debugMiddlewareWrapper(mw) {
1914
- const fn = async (ctx, next) => {
1915
- const startTime = now();
1916
- debug$1("[debugMiddlewareWrapper] [%s %s] enter middleware: %s", ctx.method, ctx.url, mw._name);
1917
- await mw(ctx, next);
1918
- const rt = diff(startTime);
1919
- debug$1("[debugMiddlewareWrapper] [%s %s] after middleware: %s [%sms]", ctx.method, ctx.url, mw._name, rt);
1920
- };
1921
- fn._name = `${mw._name}DebugWrapper`;
1922
- return fn;
1923
- }
1924
- function wrapControllerClass(Controller, fullPath) {
1925
- let proto = Controller.prototype;
1926
- const ret = {};
1927
- while (proto !== Object.prototype) {
1928
- const keys = Object.getOwnPropertyNames(proto);
1929
- for (const key of keys) {
1930
- if (key === "constructor") continue;
1931
- const d = Object.getOwnPropertyDescriptor(proto, key);
1932
- if (typeof d?.value === "function" && !Object.hasOwn(ret, key)) {
1933
- const controllerMethodName = `${Controller.name}.${key}`;
1934
- if (isGeneratorFunction(d.value)) throw new TypeError(`Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1935
- ret[key] = controllerMethodToMiddleware(Controller, key);
1936
- ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
1937
- }
1938
- }
1939
- proto = Object.getPrototypeOf(proto);
1940
- }
1941
- return ret;
1942
- }
1943
- function controllerMethodToMiddleware(Controller, key) {
1944
- return function classControllerMiddleware(...args) {
1945
- const controller = new Controller(this);
1946
- if (!this.app.config.controller?.supportParams) args = [this];
1947
- return controller[key](...args);
1948
- };
1949
- }
1950
- function wrapObject(obj, fullPath, prefix) {
1951
- const keys = Object.keys(obj);
1952
- const ret = {};
1953
- prefix = prefix ?? "";
1954
- for (const key of keys) {
1955
- const controllerMethodName = `${prefix}${key}`;
1956
- const item = obj[key];
1957
- if (isGeneratorFunction(item)) throw new TypeError(`Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1958
- if (typeof item === "function") {
1959
- if (getParamNames(item)[0] === "next") throw new Error(`controller \`${controllerMethodName}\` should not use next as argument from file ${fullPath}`);
1960
- ret[key] = objectFunctionToMiddleware(item);
1961
- ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
1962
- } else if (isObject(item)) ret[key] = wrapObject(item, fullPath, `${controllerMethodName}.`);
1963
- }
1964
- debug$1("[wrapObject] fullPath: %s, prefix: %s => %o", fullPath, prefix, ret);
1965
- return ret;
1966
- }
1967
- function objectFunctionToMiddleware(func) {
1968
- async function objectControllerMiddleware(...args) {
1969
- if (!this.app.config.controller?.supportParams) args = [this];
1970
- return await func.apply(this, args);
1971
- }
1972
- for (const key in func) Reflect.set(objectControllerMiddleware, key, Reflect.get(func, key));
1973
- return objectControllerMiddleware;
1974
- }
1975
-
1976
- //#endregion
1977
- //#region src/singleton.ts
1978
- var Singleton = class {
1979
- clients = /* @__PURE__ */ new Map();
1980
- app;
1981
- create;
1982
- name;
1983
- options;
1984
- constructor(options) {
1985
- assert(options.name, "[egg/core/singleton] Singleton#constructor options.name is required");
1986
- assert(options.app, "[egg/core/singleton] Singleton#constructor options.app is required");
1987
- assert(options.create, "[egg/core/singleton] Singleton#constructor options.create is required");
1988
- assert(!(options.name in options.app), `[egg/core/singleton] ${options.name} is already exists in app`);
1989
- this.app = options.app;
1990
- this.name = options.name;
1991
- this.create = options.create;
1992
- this.options = options.app.config[this.name] ?? {};
1993
- }
1994
- init() {
1995
- return isAsyncFunction(this.create) ? this.initAsync() : this.initSync();
1996
- }
1997
- initSync() {
1998
- const options = this.options;
1999
- assert(!(options.client && options.clients), `[egg/core/singleton] ${this.name} can not set options.client and options.clients both`);
2000
- if (options.client) {
2001
- const client = this.createInstance(options.client, options.name);
2002
- this.#setClientToApp(client);
2003
- this.#extendDynamicMethods(client);
2004
- return;
2005
- }
2006
- if (options.clients) {
2007
- for (const id of Object.keys(options.clients)) {
2008
- const client = this.createInstance(options.clients[id], id);
2009
- this.clients.set(id, client);
2010
- }
2011
- this.#setClientToApp(this);
2012
- return;
2013
- }
2014
- this.#setClientToApp(this);
2015
- }
2016
- async initAsync() {
2017
- const options = this.options;
2018
- assert(!(options.client && options.clients), `[egg/core/singleton] ${this.name} can not set options.client and options.clients both`);
2019
- if (options.client) {
2020
- const client = await this.createInstanceAsync(options.client, options.name);
2021
- this.#setClientToApp(client);
2022
- this.#extendDynamicMethods(client);
2023
- return;
2024
- }
2025
- if (options.clients) {
2026
- await Promise.all(Object.keys(options.clients).map((id) => {
2027
- return this.createInstanceAsync(options.clients[id], id).then((client) => this.clients.set(id, client));
2028
- }));
2029
- this.#setClientToApp(this);
2030
- return;
2031
- }
2032
- this.#setClientToApp(this);
2033
- }
2034
- #setClientToApp(client) {
2035
- Reflect.set(this.app, this.name, client);
2036
- }
2037
- /**
2038
- * @deprecated please use `getSingletonInstance(id)` instead
2039
- */
2040
- get(id) {
2041
- return this.clients.get(id);
2042
- }
2043
- /**
2044
- * Get singleton instance by id
2045
- */
2046
- getSingletonInstance(id) {
2047
- return this.clients.get(id);
2048
- }
2049
- createInstance(config, clientName) {
2050
- assert(!isAsyncFunction(this.create), `[egg/core/singleton] ${this.name} only support asynchronous creation, please use createInstanceAsync`);
2051
- config = {
2052
- ...this.options.default,
2053
- ...config
2054
- };
2055
- return this.create(config, this.app, clientName);
2056
- }
2057
- async createInstanceAsync(config, clientName) {
2058
- config = {
2059
- ...this.options.default,
2060
- ...config
2061
- };
2062
- return await this.create(config, this.app, clientName);
2063
- }
2064
- #extendDynamicMethods(client) {
2065
- assert(!client.createInstance, "[egg/core/singleton] singleton instance should not have createInstance method");
2066
- assert(!client.createInstanceAsync, "[egg/core/singleton] singleton instance should not have createInstanceAsync method");
2067
- try {
2068
- let extendable = client;
2069
- if (!Object.isExtensible(client) || Object.isFrozen(client)) extendable = client.__proto__ || client;
2070
- extendable.createInstance = this.createInstance.bind(this);
2071
- extendable.createInstanceAsync = this.createInstanceAsync.bind(this);
2072
- } catch (err) {
2073
- this.app.coreLogger.warn("[egg/core/singleton] %s dynamic create is disabled because of client is un-extendable", this.name);
2074
- this.app.coreLogger.warn(err);
2075
- }
2076
- }
2077
- };
2078
-
2079
- //#endregion
2080
- //#region src/egg.ts
2081
- const debug = debuglog("egg/core/egg");
2082
- const EGG_LOADER = Symbol.for("egg#loader");
2083
- var Request = class extends KoaRequest {};
2084
- var Response = class extends KoaResponse {};
2085
- var Context = class extends KoaContext {
2086
- /**
2087
- * Returns map of URL parameters for given `path` and `paramNames`.
2088
- * @example
2089
- * ##### ctx.params.id {string}
2090
- *
2091
- * `GET /api/users/1` => `'1'`
2092
- *
2093
- * ##### ctx.params.per_page {string}
2094
- *
2095
- * The number of every page, `GET /api/users?per_page=20` => `20`
2096
- */
2097
- params;
2098
- /**
2099
- * Returns array of router regexp url path captures.
2100
- */
2101
- captures;
2102
- /**
2103
- * Returns the name of the matched router.
2104
- */
2105
- routerName;
2106
- /**
2107
- * Returns the path of the matched router.
2108
- */
2109
- routerPath;
2110
- };
2111
- var EggCore = class EggCore extends KoaApplication {
2112
- options;
2113
- timing;
2114
- console;
2115
- BaseContextClass;
2116
- Controller;
2117
- Service;
2118
- Helper;
2119
- lifecycle;
2120
- loader;
2121
- #closePromise;
2122
- #router;
2123
- /** auto inject on loadService() */
2124
- serviceClasses = {};
2125
- /** auto inject on loadController() */
2126
- controller = {};
2127
- /** auto inject on loadMiddleware() */
2128
- middlewares = {};
2129
- /**
2130
- * @class
2131
- * @param {Object} options - options
2132
- * @param {String} [options.baseDir] - the directory of application
2133
- * @param {String} [options.type] - whether it's running in app worker or agent worker
2134
- * @param {Object} [options.plugins] - custom plugins
2135
- * @since 1.0.0
2136
- */
2137
- constructor(options = {}) {
2138
- options.baseDir = options.baseDir ?? process.cwd();
2139
- options.type = options.type ?? "application";
2140
- assert(typeof options.baseDir === "string", "options.baseDir required, and must be a string");
2141
- assert(options.type === "application" || options.type === "agent", "options.type should be application or agent");
2142
- super();
2143
- this.timing = new Timing();
2144
- /**
2145
- * @member {Object} EggCore#options
2146
- * @private
2147
- * @since 1.0.0
2148
- */
2149
- this.options = options;
2150
- /**
2151
- * logging for EggCore, avoid using console directly
2152
- * @member {Logger} EggCore#console
2153
- * @private
2154
- * @since 1.0.0
2155
- */
2156
- this.console = new EggConsoleLogger();
2157
- /**
2158
- * @member {BaseContextClass} EggCore#BaseContextClass
2159
- * @since 1.0.0
2160
- */
2161
- this.BaseContextClass = BaseContextClass;
2162
- /**
2163
- * Retrieve base controller
2164
- * @member {Controller} EggCore#Controller
2165
- * @since 1.0.0
2166
- */
2167
- this.Controller = this.BaseContextClass;
2168
- /**
2169
- * Retrieve base service
2170
- * @member {Service} EggCore#Service
2171
- * @since 1.0.0
2172
- */
2173
- this.Service = this.BaseContextClass;
2174
- this.lifecycle = new Lifecycle({
2175
- baseDir: options.baseDir,
2176
- app: this,
2177
- logger: this.console
2178
- });
2179
- this.lifecycle.on("error", (err) => this.emit("error", err));
2180
- this.lifecycle.on("ready_timeout", (id) => this.emit("ready_timeout", id));
2181
- this.lifecycle.on("ready_stat", (data) => this.emit("ready_stat", data));
2182
- /**
2183
- * The loader instance, the default class is {@link EggLoader}.
2184
- * If you want define
2185
- * @member {EggLoader} EggCore#loader
2186
- * @since 1.0.0
2187
- */
2188
- const Loader = this[EGG_LOADER];
2189
- assert(Loader, "Symbol.for('egg#loader') is required");
2190
- this.loader = new Loader({
2191
- baseDir: options.baseDir,
2192
- app: this,
2193
- plugins: options.plugins,
2194
- logger: this.console,
2195
- serverScope: options.serverScope,
2196
- env: options.env ?? "",
2197
- EggCoreClass: EggCore
2198
- });
2199
- }
2200
- get logger() {
2201
- return this.console;
2202
- }
2203
- get coreLogger() {
2204
- return this.console;
2205
- }
2206
- /**
2207
- * create a singleton instance
2208
- * @param {String} name - unique name for singleton
2209
- * @param {Function|AsyncFunction} create - method will be invoked when singleton instance create
2210
- */
2211
- addSingleton(name, create) {
2212
- const initPromise = new Singleton({
2213
- name,
2214
- create,
2215
- app: this
2216
- }).init();
2217
- if (initPromise) this.lifecycle.registerBeforeStart(async () => {
2218
- await initPromise;
2219
- }, `${name}-singleton-init`);
2220
- }
2221
- /**
2222
- * override koa's app.use, support generator function
2223
- * @since 1.0.0
2224
- */
2225
- use(fn) {
2226
- assert(typeof fn === "function", "app.use() requires a function");
2227
- debug("[use] add middleware: %o", fn._name || fn.name || "-");
2228
- this.middleware.push(fn);
2229
- return this;
2230
- }
2231
- /**
2232
- * Whether `application` or `agent`
2233
- * @member {String}
2234
- * @since 1.0.0
2235
- */
2236
- get type() {
2237
- return this.options.type;
2238
- }
2239
- /**
2240
- * The current directory of application
2241
- * @member {String}
2242
- * @see {@link AppInfo#baseDir}
2243
- * @since 1.0.0
2244
- */
2245
- get baseDir() {
2246
- return this.options.baseDir;
2247
- }
2248
- /**
2249
- * Alias to {@link https://npmjs.com/package/depd}
2250
- * @member {Function}
2251
- * @since 1.0.0
2252
- */
2253
- get deprecate() {
2254
- return utils_default.deprecated;
2255
- }
2256
- /**
2257
- * The name of application
2258
- * @member {String}
2259
- * @see {@link AppInfo#name}
2260
- * @since 1.0.0
2261
- */
2262
- get name() {
2263
- return this.loader ? this.loader.pkg.name : "";
2264
- }
2265
- /**
2266
- * Retrieve enabled plugins
2267
- * @member {Object}
2268
- * @since 1.0.0
2269
- */
2270
- get plugins() {
2271
- return this.loader ? this.loader.plugins : {};
2272
- }
2273
- /**
2274
- * The configuration of application
2275
- * @member {Config}
2276
- * @since 1.0.0
2277
- */
2278
- get config() {
2279
- return this.loader ? this.loader.config : {};
2280
- }
2281
- /**
2282
- * Execute scope after loaded and before app start.
2283
- *
2284
- * Notice:
2285
- * This method is now NOT recommended and regarded as a deprecated one,
2286
- * For plugin development, we should use `didLoad` instead.
2287
- * For application development, we should use `willReady` instead.
2288
- *
2289
- * @see https://eggjs.org/en/advanced/loader.html#beforestart
2290
- *
2291
- * @param {Function} scope function will execute before app start
2292
- * @param {string} [name] scope name, default is empty string
2293
- */
2294
- beforeStart(scope, name) {
2295
- this.deprecate("`beforeStart` was deprecated, please use \"Life Cycles\" instead, see https://www.eggjs.org/advanced/loader#life-cycles");
2296
- this.lifecycle.registerBeforeStart(scope, name ?? "");
2297
- }
2298
- ready(flagOrFunction) {
2299
- if (flagOrFunction === void 0) return this.lifecycle.ready();
2300
- return this.lifecycle.ready(flagOrFunction);
2301
- }
2302
- /**
2303
- * If a client starts asynchronously, you can register `readyCallback`,
2304
- * then the application will wait for the callback to ready
2305
- *
2306
- * It will log when the callback is not invoked after 10s
2307
- *
2308
- * Recommend to use {@link EggCore#beforeStart}
2309
- * @since 1.0.0
2310
- *
2311
- * @param {String} name - readyCallback task name
2312
- * @param {object} opts -
2313
- * - {Number} [timeout=10000] - emit `ready_timeout` when it doesn't finish but reach the timeout
2314
- * - {Boolean} [isWeakDep=false] - whether it's a weak dependency
2315
- * @returns {Function} - a callback
2316
- * @example
2317
- * const done = app.readyCallback('mysql');
2318
- * mysql.ready(done);
2319
- */
2320
- readyCallback(name, opts) {
2321
- this.deprecate("`readyCallback` was deprecated, please use \"Life Cycles\" instead, see https://www.eggjs.org/advanced/loader#life-cycles");
2322
- return this.lifecycle.legacyReadyCallback(name, opts);
2323
- }
2324
- /**
2325
- * Register a function that will be called when app close.
2326
- *
2327
- * Notice:
2328
- * This method is now NOT recommended directly used,
2329
- * Developers SHOULDN'T use app.beforeClose directly now,
2330
- * but in the form of class to implement beforeClose instead.
2331
- *
2332
- * @see https://eggjs.org/en/advanced/loader.html#beforeclose
2333
- *
2334
- * @param {Function} fn - the function that can be generator function or async function.
2335
- */
2336
- beforeClose(fn, name) {
2337
- this.deprecate("`beforeClose` was deprecated, please use \"Life Cycles\" instead, see https://www.eggjs.org/advanced/loader#life-cycles");
2338
- this.lifecycle.registerBeforeClose(fn, name);
2339
- }
2340
- /**
2341
- * Close all, it will close
2342
- * - callbacks registered by beforeClose
2343
- * - emit `close` event
2344
- * - remove add listeners
2345
- *
2346
- * If error is thrown when it's closing, the promise will reject.
2347
- * It will also reject after following call.
2348
- * @returns {Promise} promise
2349
- * @since 1.0.0
2350
- */
2351
- async close() {
2352
- if (this.#closePromise) return this.#closePromise;
2353
- this.#closePromise = this.lifecycle.close();
2354
- return this.#closePromise;
2355
- }
2356
- /**
2357
- * get router
2358
- * @member {Router} EggCore#router
2359
- * @since 1.0.0
2360
- */
2361
- get router() {
2362
- if (this.#router) return this.#router;
2363
- this.#router = new Router({ sensitive: true }, this);
2364
- return this.#router;
2365
- }
2366
- /**
2367
- * Alias to {@link Router#url}
2368
- * @param {String} name - Router name
2369
- * @param {Object} params - more parameters
2370
- * @returns {String} url
2371
- */
2372
- url(name, params) {
2373
- return this.router.url(name, params);
2374
- }
2375
- head(...args) {
2376
- this.router.head.apply(this.router, args);
2377
- return this;
2378
- }
2379
- get(...args) {
2380
- this.router.get.apply(this.router, args);
2381
- return this;
2382
- }
2383
- put(...args) {
2384
- this.router.put.apply(this.router, args);
2385
- return this;
2386
- }
2387
- patch(...args) {
2388
- this.router.patch.apply(this.router, args);
2389
- return this;
2390
- }
2391
- post(...args) {
2392
- this.router.post.apply(this.router, args);
2393
- return this;
2394
- }
2395
- delete(...args) {
2396
- this.router.delete.apply(this.router, args);
2397
- return this;
2398
- }
2399
- del(...args) {
2400
- this.router.del.apply(this.router, args);
2401
- return this;
2402
- }
2403
- all(...args) {
2404
- this.router.all.apply(this.router, args);
2405
- return this;
2406
- }
2407
- resources(...args) {
2408
- this.router.resources.apply(this.router, args);
2409
- return this;
2410
- }
2411
- redirect(source, destination, status = 301) {
2412
- this.router.redirect(source, destination, status);
2413
- return this;
2414
- }
2415
- register(path$1, methods, middleware, opts) {
2416
- this.router.register(path$1, methods, middleware, opts);
2417
- return this;
2418
- }
2419
- get [EGG_LOADER]() {
2420
- return EggLoader;
2421
- }
2422
- };
2423
-
2424
- //#endregion
2425
- export { BaseContextClass, CaseStyle, ClassLoader, Context, ContextLoader, EGG_LOADER, EXPORTS, EggCore, EggLoader, FULLPATH, FileLoader, KoaApplication, KoaContext, KoaRequest, KoaResponse, Lifecycle, Request, Response, Router, Singleton, Timing, sequencify, utils_default as utils };
1
+ import utils from "./utils/index.js";
2
+ export { utils };
3
+ export * from "./egg.js";
4
+ export * from "./base_context_class.js";
5
+ export * from "./lifecycle.js";
6
+ export * from "./singleton.js";
7
+ export * from "./loader/egg_loader.js";
8
+ export * from "./loader/file_loader.js";
9
+ export * from "./loader/context_loader.js";
10
+ export * from "./utils/sequencify.js";
11
+ export * from "./utils/timing.js";
12
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sa0JBQWtCLENBQUM7QUFFckMsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO0FBRWpCLGNBQWMsVUFBVSxDQUFDO0FBQ3pCLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLDRCQUE0QixDQUFDO0FBQzNDLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYyxtQkFBbUIsQ0FBQyJ9