index.d.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. import KoaApplication = require('koa');
  2. import { Logger, EggConsoleLogger } from 'egg-logger';
  3. import depd = require('depd');
  4. type EggType = 'application' | 'agent';
  5. interface PlainObject<T = any> {
  6. [key: string]: T;
  7. }
  8. export interface EggCoreOptions {
  9. /** egg type, application or agent */
  10. type?: EggType;
  11. /** the directory of application */
  12. baseDir?: EggAppInfo['baseDir'];
  13. /** server scope */
  14. serverScope?: string;
  15. /** custom plugins */
  16. plugins?: Plugins;
  17. }
  18. export interface EggLoaderOptions {
  19. /** Application instance */
  20. app: EggCore;
  21. /** the directory of application */
  22. baseDir: EggAppInfo['baseDir'];
  23. /** egg logger */
  24. logger: Logger;
  25. /** server scope */
  26. serverScope?: string;
  27. /** custom plugins */
  28. plugins?: Plugins;
  29. }
  30. export interface PluginInfo {
  31. /** the plugin name, it can be used in `dep` */
  32. name: string;
  33. /** the package name of plugin */
  34. package: string;
  35. /** whether enabled */
  36. enable: boolean;
  37. /** the directory of the plugin package */
  38. path: string;
  39. /** the dependent plugins, you can use the plugin name */
  40. dependencies: string[];
  41. /** the optional dependent plugins. */
  42. optionalDependencies: string[];
  43. /** specify the serverEnv that only enable the plugin in it */
  44. env: string[];
  45. /** the file plugin config in. */
  46. from: string;
  47. }
  48. export interface Plugins extends PlainObject<PluginInfo> { }
  49. export interface EggCoreBase<Config> extends KoaApplication {
  50. /**
  51. * Whether `application` or `agent`
  52. * @member {String}
  53. * @since 1.0.0
  54. */
  55. type: EggType;
  56. /**
  57. * The current directory of application
  58. * @member {String}
  59. * @see {@link EggAppInfo#baseDir}
  60. * @since 1.0.0
  61. */
  62. baseDir: EggAppInfo['baseDir'];
  63. /**
  64. * The name of application
  65. * @member {String}
  66. * @see {@link EggAppInfo#name}
  67. * @since 1.0.0
  68. */
  69. name: EggAppInfo['name'];
  70. /**
  71. * Convert a generator function to a promisable one.
  72. *
  73. * Notice: for other kinds of functions, it directly returns you what it is.
  74. *
  75. * @param {Function} fn The inputted function.
  76. * @return {AsyncFunction} An async promise-based function.
  77. * @example
  78. * ```javascript
  79. * const fn = function* (arg) {
  80. return arg;
  81. };
  82. const wrapped = app.toAsyncFunction(fn);
  83. wrapped(true).then((value) => console.log(value));
  84. * ```
  85. */
  86. toAsyncFunction<T = any>(fn: (...args: any[]) => IterableIterator<T>): (...args: any[]) => Promise<T>;
  87. /**
  88. * Convert an object with generator functions to a Promisable one.
  89. * @param {Mixed} obj The inputted object.
  90. * @return {Promise} A Promisable result.
  91. * @example
  92. * ```javascript
  93. * const fn = function* (arg) {
  94. return arg;
  95. };
  96. const arr = [ fn(1), fn(2) ];
  97. const promise = app.toPromise(arr);
  98. promise.then(res => console.log(res));
  99. * ```
  100. */
  101. toPromise<T = any>(obj: any): Promise<T>;
  102. /**
  103. * register an callback function that will be invoked when application is ready.
  104. * @see https://github.com/node-modules/ready
  105. * @since 1.0.0
  106. * @param {boolean|Error|Function} flagOrFunction -
  107. * @return {Promise|null} return promise when argument is undefined
  108. * @example
  109. * const app = new Application(...);
  110. * app.ready(err => {
  111. * if (err) throw err;
  112. * console.log('done');
  113. * });
  114. */
  115. ready(fn?: (err?: Error) => void): any;
  116. /**
  117. * Close all, it wil close
  118. * - callbacks registered by beforeClose
  119. * - emit `close` event
  120. * - remove add listeners
  121. *
  122. * If error is thrown when it's closing, the promise will reject.
  123. * It will also reject after following call.
  124. * @return {Promise} promise
  125. * @since 1.0.0
  126. */
  127. close(): Promise<any>;
  128. /**
  129. * If a client starts asynchronously, you can register `readyCallback`,
  130. * then the application will wait for the callback to ready
  131. *
  132. * It will log when the callback is not invoked after 10s
  133. *
  134. * Recommend to use {@link EggCore#beforeStart}
  135. * @since 1.0.0
  136. *
  137. * @param {String} name - readyCallback task name
  138. * @param {object} opts -
  139. * - {Number} [timeout=10000] - emit `ready_timeout` when it doesn't finish but reach the timeout
  140. * - {Boolean} [isWeakDep=false] - whether it's a weak dependency
  141. * @return {Function} - a callback
  142. * @example
  143. * const done = app.readyCallback('mysql');
  144. * mysql.ready(done);
  145. */
  146. readyCallback(name: string, opts?: { timeout?: number; isWeakDep?: boolean }): () => void;
  147. /**
  148. * The loader instance, the default class is {@link EggLoader}.
  149. * If you want define
  150. * @member {EggLoader} EggCore#loader
  151. * @since 1.0.0
  152. */
  153. loader: EggLoader<this, Config>;
  154. /**
  155. * The configuration of application
  156. * @member {Config}
  157. * @since 1.0.0
  158. */
  159. config: Config;
  160. /**
  161. * Retrieve enabled plugins
  162. * @member {Object}
  163. * @since 1.0.0
  164. */
  165. plugins: Plugins;
  166. /**
  167. * Register a function that will be called when app close
  168. */
  169. beforeClose(fn: () => void): void;
  170. /**
  171. * Execute scope after loaded and before app start
  172. */
  173. beforeStart(scope: () => void): void;
  174. /**
  175. * Alias to {@link https://npmjs.com/package/depd}
  176. * @member {Function}
  177. * @since 1.0.0
  178. */
  179. deprecate: depd.Deprecate;
  180. }
  181. export interface EggCore<Config = PlainObject> extends EggCoreBase<Config> {
  182. Controller: typeof BaseContextClass;
  183. Service: typeof BaseContextClass;
  184. }
  185. export class EggCore {
  186. /**
  187. * @constructor
  188. * @param {Object} options - options
  189. * @param {String} [options.baseDir=process.cwd()] - the directory of application
  190. * @param {String} [options.type=application|agent] - whether it's running in app worker or agent worker
  191. * @param {Object} [options.plugins] - custom plugins
  192. * @since 1.0.0
  193. */
  194. constructor(options?: EggCoreOptions);
  195. }
  196. /**
  197. * egg app info
  198. * @example
  199. * ```js
  200. * // config/config.default.ts
  201. * import { EggAppInfo } from 'egg';
  202. *
  203. * export default (appInfo: EggAppInfo) => {
  204. * return {
  205. * keys: appInfo.name + '123456',
  206. * };
  207. * }
  208. * ```
  209. */
  210. export interface EggAppInfo {
  211. /** package.json */
  212. pkg: PlainObject;
  213. /** the application name from package.json */
  214. name: string;
  215. /** current directory of application */
  216. baseDir: string;
  217. /** equals to serverEnv */
  218. env: string;
  219. /** home directory of the OS */
  220. HOME: string;
  221. /** baseDir when local and unittest, HOME when other environment */
  222. root: string;
  223. }
  224. /**
  225. * BaseContextClass is a base class that can be extended,
  226. * it's instantiated in context level,
  227. * {@link Helper}, {@link Service} is extending it.
  228. */
  229. export class BaseContextClass<
  230. Context = any,
  231. Application = any,
  232. EggAppConfig = any,
  233. Service = any
  234. > {
  235. constructor(ctx: Context);
  236. /** request context */
  237. protected ctx: Context;
  238. /** Application */
  239. protected app: Application;
  240. /** Application config object */
  241. protected config: EggAppConfig;
  242. /** service */
  243. protected service: Service;
  244. }
  245. export interface FileLoaderOption {
  246. /** directories to be loaded */
  247. directory: string | string[];
  248. /** attach the target object from loaded files */
  249. target: object;
  250. /** match the files when load, support glob, default to all js files */
  251. match?: string | string[];
  252. /** ignore the files when load, support glob */
  253. ignore?: string | string[];
  254. /** 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` */
  255. initializer?(obj: object, options: { path: string; pathName: string; }): any;
  256. /** determine whether invoke when exports is function */
  257. call?: boolean;
  258. /** determine whether override the property when get the same name */
  259. override?: boolean;
  260. /** an object that be the argument when invoke the function */
  261. inject?: object;
  262. /** a function that filter the exports which can be loaded */
  263. filter?(obj: object): boolean;
  264. /** set property's case when converting a filepath to property list. */
  265. caseStyle?: string | ((str: string) => string[]);
  266. }
  267. export interface ContextLoaderOption extends Partial<FileLoaderOption> {
  268. /** directories to be loaded */
  269. directory: string | string[];
  270. /** required inject */
  271. inject: object;
  272. /** property name defined to target */
  273. property: string;
  274. /** determine the field name of inject object. */
  275. fieldClass?: string;
  276. }
  277. declare interface FileLoaderBase {
  278. /**
  279. * attach items to target object. Mapping the directory to properties.
  280. * `app/controller/group/repository.js` => `target.group.repository`
  281. * @return {Object} target
  282. * @since 1.0.0
  283. */
  284. load(): object;
  285. /**
  286. * Parse files from given directories, then return an items list, each item contains properties and exports.
  287. *
  288. * For example, parse `app/controller/group/repository.js`
  289. *
  290. * ```js
  291. * module.exports = app => {
  292. * return class RepositoryController extends app.Controller {};
  293. * }
  294. * ```
  295. *
  296. * It returns a item
  297. *
  298. * ```js
  299. * {
  300. * properties: [ 'group', 'repository' ],
  301. * exports: app => { ... },
  302. * }
  303. * ```
  304. *
  305. * `Properties` is an array that contains the directory of a filepath.
  306. *
  307. * `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.
  308. * @return {Array} items
  309. * @since 1.0.0
  310. */
  311. parse(): Array<{ fullpath: string; properties: string[]; exports: any; }>;
  312. }
  313. declare interface ContextLoaderBase extends FileLoaderBase {}
  314. export interface FileLoader {
  315. /**
  316. * Load files from directory to target object.
  317. * @since 1.0.0
  318. */
  319. new (options: FileLoaderOption): FileLoaderBase;
  320. }
  321. export interface ContextLoader {
  322. /**
  323. * Same as {@link FileLoader}, but it will attach file to `inject[fieldClass]`. The exports will be lazy loaded, such as `ctx.group.repository`.
  324. * @extends FileLoader
  325. * @since 1.0.0
  326. */
  327. new (options: ContextLoaderOption): ContextLoaderBase;
  328. }
  329. export class EggLoader<
  330. T = EggCore,
  331. Config = any,
  332. Options extends EggLoaderOptions = EggLoaderOptions
  333. > {
  334. app: T;
  335. eggPaths: string[];
  336. pkg: PlainObject;
  337. appInfo: EggAppInfo;
  338. serverScope: string;
  339. plugins: Plugins;
  340. config: Config;
  341. options: Options;
  342. /**
  343. * @constructor
  344. * @param {Object} options - options
  345. * @param {String} options.baseDir - the directory of application
  346. * @param {EggCore} options.app - Application instance
  347. * @param {Logger} options.logger - logger
  348. * @param {Object} [options.plugins] - custom plugins
  349. * @since 1.0.0
  350. */
  351. constructor(options: EggLoaderOptions);
  352. /**
  353. * Get home directory
  354. * @return {String} home directory
  355. * @since 3.4.0
  356. */
  357. getHomedir(): EggAppInfo['HOME'];
  358. /**
  359. * Get app info
  360. * @return {EggAppInfo} appInfo
  361. * @since 1.0.0
  362. */
  363. getAppInfo(): EggAppInfo;
  364. // Low Level API
  365. /**
  366. * Load single file, will invoke when export is function
  367. *
  368. * @param {String} filepath - fullpath
  369. * @param {Array} arguments - pass rest arguments into the function when invoke
  370. * @return {Object} exports
  371. * @example
  372. * ```js
  373. * app.loader.loadFile(path.join(app.options.baseDir, 'config/router.js'));
  374. * ```
  375. * @since 1.0.0
  376. */
  377. loadFile<T = any>(filepath: string, ...inject: any[]): T;
  378. /**
  379. * Get all loadUnit
  380. *
  381. * loadUnit is a directory that can be loaded by EggLoader, it has the same structure.
  382. * loadUnit has a path and a type(app, framework, plugin).
  383. *
  384. * The order of the loadUnits:
  385. *
  386. * 1. plugin
  387. * 2. framework
  388. * 3. app
  389. *
  390. * @return {Array} loadUnits
  391. * @since 1.0.0
  392. */
  393. getLoadUnits(): Array<{ path: string; type: string; }>;
  394. getEggPaths(): string[];
  395. getServerEnv(): string;
  396. /**
  397. * Load files using {@link FileLoader}, inject to {@link Application}
  398. * @param {String|Array} directory - see {@link FileLoader}
  399. * @param {String} property - see {@link FileLoader}
  400. * @param {Object} opt - see {@link FileLoader}
  401. * @since 1.0.0
  402. */
  403. loadToApp(directory: string | string[], property: string, opt?: Partial<FileLoaderOption>): void;
  404. /**
  405. * Load files using {@link ContextLoader}
  406. * @param {String|Array} directory - see {@link ContextLoader}
  407. * @param {String} property - see {@link ContextLoader}
  408. * @param {Object} opt - see {@link ContextLoader}
  409. * @since 1.0.0
  410. */
  411. loadToContext(directory: string | string[], property: string, opt?: Partial<ContextLoaderOption>): void;
  412. getTypeFiles(filename: string): string[];
  413. resolveModule(filepath: string): string | undefined;
  414. FileLoader: FileLoader;
  415. ContextLoader: ContextLoader;
  416. // load methods
  417. protected loadConfig(): void;
  418. protected loadController(opt?: Partial<FileLoaderOption>): void;
  419. protected loadCustomLoader(): void;
  420. protected loadCustomApp(): void;
  421. protected loadCustomAgent(): void;
  422. protected loadAgentExtend(): void;
  423. protected loadApplicationExtend(): void;
  424. protected loadRequestExtend(): void;
  425. protected loadResponseExtend(): void;
  426. protected loadContextExtend(): void;
  427. protected loadHelperExtend(): void;
  428. protected loadMiddleware(opt?: Partial<FileLoaderOption>): void;
  429. protected loadPlugin(): void;
  430. protected loadRouter(): void;
  431. protected loadService(opt?: Partial<ContextLoaderOption>): void;
  432. }