egg 4.1.0-beta.3 → 4.1.0-beta.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/agent.d.ts +3 -7
  2. package/dist/agent.js +6 -10
  3. package/dist/ajv.d.ts +1 -0
  4. package/dist/ajv.js +2 -0
  5. package/dist/aop.d.ts +1 -0
  6. package/dist/aop.js +2 -0
  7. package/dist/app/extend/context.d.ts +166 -193
  8. package/dist/app/extend/context.js +259 -244
  9. package/dist/app/extend/helper.d.ts +31 -36
  10. package/dist/app/extend/helper.js +41 -45
  11. package/dist/app/extend/request.d.ts +127 -140
  12. package/dist/app/extend/request.js +258 -219
  13. package/dist/app/extend/response.d.ts +22 -32
  14. package/dist/app/extend/response.js +34 -36
  15. package/dist/app/middleware/body_parser.d.ts +2 -2
  16. package/dist/app/middleware/body_parser.js +3 -7
  17. package/dist/app/middleware/meta.d.ts +9 -10
  18. package/dist/app/middleware/meta.js +19 -13
  19. package/dist/app/middleware/notfound.d.ts +6 -10
  20. package/dist/app/middleware/notfound.js +28 -25
  21. package/dist/app/middleware/override_method.d.ts +2 -2
  22. package/dist/app/middleware/override_method.js +3 -7
  23. package/dist/app/middleware/site_file.d.ts +8 -12
  24. package/dist/app/middleware/site_file.js +52 -37
  25. package/dist/config/config.default.d.ts +3 -8
  26. package/dist/config/config.default.js +377 -256
  27. package/dist/config/config.local.d.ts +3 -10
  28. package/dist/config/config.local.js +9 -7
  29. package/dist/config/config.unittest.d.ts +3 -9
  30. package/dist/config/config.unittest.js +9 -10
  31. package/dist/config/favicon.png +0 -0
  32. package/dist/config/plugin.d.ts +3 -124
  33. package/dist/config/plugin.js +154 -53
  34. package/dist/dal.d.ts +1 -0
  35. package/dist/dal.js +2 -0
  36. package/dist/helper.d.ts +1 -0
  37. package/dist/helper.js +2 -0
  38. package/dist/index.d.ts +106 -19
  39. package/dist/index.js +89 -19
  40. package/dist/lib/agent.d.ts +12 -17
  41. package/dist/lib/agent.js +45 -54
  42. package/dist/lib/application.d.ts +47 -62
  43. package/dist/lib/application.js +249 -197
  44. package/dist/lib/core/base_context_class.d.ts +13 -17
  45. package/dist/lib/core/base_context_class.js +15 -17
  46. package/dist/lib/core/base_context_logger.d.ts +35 -39
  47. package/dist/lib/core/base_context_logger.js +60 -58
  48. package/dist/lib/core/base_hook_class.d.ts +11 -17
  49. package/dist/lib/core/base_hook_class.js +22 -26
  50. package/dist/lib/core/context_httpclient.d.ts +16 -20
  51. package/dist/lib/core/context_httpclient.js +26 -29
  52. package/dist/lib/core/httpclient.d.ts +12 -15
  53. package/dist/lib/core/httpclient.js +37 -34
  54. package/dist/lib/core/logger.d.ts +3 -7
  55. package/dist/lib/core/logger.js +36 -30
  56. package/dist/lib/core/messenger/IMessenger.d.ts +49 -53
  57. package/dist/lib/core/messenger/IMessenger.js +2 -1
  58. package/dist/lib/core/messenger/base.d.ts +7 -11
  59. package/dist/lib/core/messenger/base.js +29 -29
  60. package/dist/lib/core/messenger/index.d.ts +4 -8
  61. package/dist/lib/core/messenger/index.js +8 -11
  62. package/dist/lib/core/messenger/ipc.d.ts +55 -59
  63. package/dist/lib/core/messenger/ipc.js +138 -120
  64. package/dist/lib/core/messenger/local.d.ts +56 -61
  65. package/dist/lib/core/messenger/local.js +131 -124
  66. package/dist/lib/core/utils.d.ts +2 -5
  67. package/dist/lib/core/utils.js +66 -44
  68. package/dist/lib/define.d.ts +76 -0
  69. package/dist/lib/define.js +59 -0
  70. package/dist/lib/egg.d.ts +272 -294
  71. package/dist/lib/egg.js +574 -507
  72. package/dist/lib/error/CookieLimitExceedError.d.ts +4 -7
  73. package/dist/lib/error/CookieLimitExceedError.js +12 -15
  74. package/dist/lib/error/MessageUnhandledRejectionError.d.ts +4 -7
  75. package/dist/lib/error/MessageUnhandledRejectionError.js +12 -15
  76. package/dist/lib/error/index.d.ts +2 -3
  77. package/dist/lib/error/index.js +3 -4
  78. package/dist/lib/loader/AgentWorkerLoader.d.ts +7 -12
  79. package/dist/lib/loader/AgentWorkerLoader.js +18 -22
  80. package/dist/lib/loader/AppWorkerLoader.d.ts +12 -17
  81. package/dist/lib/loader/AppWorkerLoader.js +37 -35
  82. package/dist/lib/loader/EggApplicationLoader.d.ts +3 -7
  83. package/dist/lib/loader/EggApplicationLoader.js +4 -7
  84. package/dist/lib/loader/index.d.ts +3 -4
  85. package/dist/lib/loader/index.js +4 -5
  86. package/dist/lib/start.d.ts +18 -22
  87. package/dist/lib/start.js +42 -32
  88. package/dist/lib/types.d.ts +277 -230
  89. package/dist/lib/types.js +3 -14
  90. package/dist/lib/types.plugin.d.ts +20 -0
  91. package/dist/lib/types.plugin.js +24 -0
  92. package/dist/orm.d.ts +1 -0
  93. package/dist/orm.js +2 -0
  94. package/dist/schedule.d.ts +2 -0
  95. package/dist/schedule.js +5 -0
  96. package/dist/transaction.d.ts +1 -0
  97. package/dist/transaction.js +2 -0
  98. package/dist/urllib.d.ts +1 -1
  99. package/dist/urllib.js +2 -3
  100. package/package.json +49 -32
  101. package/dist/lib/utils.d.ts +0 -5
  102. package/dist/lib/utils.js +0 -14
package/dist/lib/egg.js CHANGED
@@ -1,512 +1,579 @@
1
- import { BaseHookClass } from "./core/base_hook_class.js";
2
- import { BaseContextClass as BaseContextClass$1 } from "./core/base_context_class.js";
1
+ import { performance } from 'node:perf_hooks';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import http, {} from 'node:http';
5
+ import inspector from 'node:inspector';
6
+ import assert from 'node:assert';
7
+ import { EggCore, Router } from '@eggjs/core';
8
+ import { utils as eggUtils } from '@eggjs/core';
9
+ // @ts-expect-error no types for 'cluster-client'
10
+ import createClusterClient, { close as closeClusterClient } from 'cluster-client';
11
+ import { extend } from '@eggjs/extend2';
12
+ import { EggContextLogger as ContextLogger, EggLoggers, EggLogger } from 'egg-logger';
13
+ import { Cookies as ContextCookies } from '@eggjs/cookies';
14
+ // @ts-expect-error no types for circular-json-for-egg
15
+ import CircularJSON from 'circular-json-for-egg';
3
16
  import Context from "../app/extend/context.js";
4
- import { create } from "./core/messenger/index.js";
17
+ import Request from "../app/extend/request.js";
18
+ import Response from "../app/extend/response.js";
19
+ import { create as createMessenger } from "./core/messenger/index.js";
5
20
  import { ContextHttpClient } from "./core/context_httpclient.js";
6
- import { HttpClient } from "./core/httpclient.js";
21
+ import { HttpClient, } from "./core/httpclient.js";
7
22
  import { createLoggers } from "./core/logger.js";
8
23
  import { convertObject } from "./core/utils.js";
9
- import { getSourceDirname } from "./utils.js";
10
- import { EggCore, Request as Request$1, Response as Response$1, Router, utils } from "@eggjs/core";
11
- import path from "node:path";
12
- import { performance } from "node:perf_hooks";
13
- import fs from "node:fs";
14
- import http from "node:http";
15
- import inspector from "node:inspector";
16
- import { AsyncLocalStorage } from "node:async_hooks";
17
- import createClusterClient, { close } from "cluster-client";
18
- import { extend } from "@eggjs/extend2";
19
- import { EggContextLogger, EggLogger, EggLoggers } from "egg-logger";
20
- import { Cookies } from "@eggjs/cookies";
21
- import CircularJSON from "circular-json-for-egg";
22
-
23
- //#region src/lib/egg.ts
24
- const EGG_PATH = Symbol.for("egg#eggPath");
25
- var Request = class extends Request$1 {};
26
- var Response = class extends Response$1 {};
24
+ import { BaseContextClass } from "./core/base_context_class.js";
25
+ import { BaseHookClass } from "./core/base_hook_class.js";
26
+ export { Request, Response };
27
+ // export egg classes
28
+ export { Context, Router };
27
29
  /**
28
- * Based on koa's Application
29
- * @see https://github.com/eggjs/egg-core
30
- * @see https://github.com/eggjs/koa/blob/master/src/application.ts
31
- * @augments EggCore
32
- */
33
- var EggApplicationCore = class extends EggCore {
34
- ContextCookies = Cookies;
35
- ContextLogger = EggContextLogger;
36
- ContextHttpClient = ContextHttpClient;
37
- HttpClient = HttpClient;
38
- HttpClientNext = HttpClient;
39
- /**
40
- * Retrieve base context class
41
- * @member {BaseContextClass} BaseContextClass
42
- * @since 1.0.0
43
- */
44
- BaseContextClass = BaseContextClass$1;
45
- /**
46
- * Retrieve base controller
47
- * @member {Controller} Controller
48
- * @since 1.0.0
49
- */
50
- Controller = BaseContextClass$1;
51
- /**
52
- * Retrieve base service
53
- * @member {Service} Service
54
- * @since 1.0.0
55
- */
56
- Service = BaseContextClass$1;
57
- /**
58
- * Retrieve base subscription
59
- * @member {Subscription} Subscription
60
- * @since 2.12.0
61
- */
62
- Subscription = BaseContextClass$1;
63
- /**
64
- * Retrieve base context class
65
- * @member {BaseHookClass} BaseHookClass
66
- */
67
- BaseHookClass = BaseHookClass;
68
- /**
69
- * Retrieve base boot
70
- * @member {Boot}
71
- * @alias BaseHookClass
72
- */
73
- Boot = BaseHookClass;
74
- #httpClient;
75
- #loggers;
76
- #clusterClients = [];
77
- messenger;
78
- agent;
79
- application;
80
- /**
81
- * @class
82
- * @param {Object} options
83
- * - {Object} [type] - type of instance, Agent and Application both extend koa, type can determine what it is.
84
- * - {String} [baseDir] - app root dir, default is `process.cwd()`
85
- * - {Object} [plugins] - custom plugin config, use it in unittest
86
- * - {String} [mode] - process mode, can be cluster / single, default is `cluster`
87
- */
88
- constructor(options) {
89
- options = {
90
- mode: "cluster",
91
- type: "application",
92
- baseDir: process.cwd(),
93
- ...options
94
- };
95
- super(options);
96
- /**
97
- * messenger instance
98
- * @member {Messenger}
99
- * @since 1.0.0
100
- */
101
- this.messenger = create(this);
102
- this.messenger.once("egg-ready", () => {
103
- this.lifecycle.triggerServerDidReady();
104
- });
105
- this.lifecycle.registerBeforeStart(async () => {
106
- await this.load();
107
- }, "load files");
108
- }
109
- /**
110
- * @deprecated please use `options` property instead
111
- */
112
- get _options() {
113
- return this.options;
114
- }
115
- async loadConfig() {
116
- await this.loader.loadConfig();
117
- }
118
- async load() {
119
- await this.loadConfig();
120
- this.ready(() => process.nextTick(() => {
121
- const dumpStartTime = Date.now();
122
- this.dumpConfig();
123
- this.dumpTiming();
124
- this.coreLogger.info("[egg] dump config after ready, %sms", Date.now() - dumpStartTime);
125
- }));
126
- this.#setupTimeoutTimer();
127
- this.console.info("[egg] App root: %s", this.baseDir);
128
- this.console.info("[egg] All *.log files save on %j", this.config.logger.dir);
129
- this.console.info("[egg] Loaded enabled plugin %j", this.loader.orderPlugins);
130
- this._unhandledRejectionHandler = this._unhandledRejectionHandler.bind(this);
131
- process.on("unhandledRejection", this._unhandledRejectionHandler);
132
- this.lifecycle.registerBeforeClose(async () => {
133
- for (const clusterClient of this.#clusterClients) await close(clusterClient);
134
- this.#clusterClients = [];
135
- if (this.type === "application" && this.options.mode === "single") await this.agent.close();
136
- for (const logger of this.loggers.values()) logger.close();
137
- this.messenger.close();
138
- process.removeListener("unhandledRejection", this._unhandledRejectionHandler);
139
- });
140
- await this.loader.load();
141
- }
142
- /**
143
- * Usage: new ApiClient({ cluster: app.cluster })
144
- */
145
- get cluster() {
146
- return this.clusterWrapper.bind(this);
147
- }
148
- /**
149
- * Wrap the Client with Leader/Follower Pattern
150
- *
151
- * @description almost the same as Agent.cluster API, the only different is that this method create Follower.
152
- *
153
- * @see https://github.com/node-modules/cluster-client
154
- * @param {Function} clientClass - client class function
155
- * @param {Object} [options]
156
- * - {Boolean} [autoGenerate] - whether generate delegate rule automatically, default is true
157
- * - {Function} [formatKey] - a method to transform the subscription info into a string,default is JSON.stringify
158
- * - {Object} [transcode|JSON.stringify/parse]
159
- * - {Function} encode - custom serialize method
160
- * - {Function} decode - custom deserialize method
161
- * - {Boolean} [isBroadcast] - whether broadcast subscription result to all followers or just one, default is true
162
- * - {Number} [responseTimeout] - response timeout, default is 3 seconds
163
- * - {Number} [maxWaitTime|30000] - leader startup max time, default is 30 seconds
164
- * @return {ClientWrapper} wrapper
165
- */
166
- clusterWrapper(clientClass, options) {
167
- const clientClassOptions = {
168
- ...this.config.clusterClient,
169
- ...options,
170
- singleMode: this.options.mode === "single",
171
- port: this.options.clusterPort,
172
- isLeader: this.type === "agent",
173
- logger: this.coreLogger,
174
- isCheckHeartbeat: this.config.env === "prod" ? true : inspector.url() === void 0
175
- };
176
- const client = createClusterClient(clientClass, clientClassOptions);
177
- this.#patchClusterClient(client);
178
- return client;
179
- }
180
- /**
181
- * print the information when console.log(app)
182
- * @return {Object} inspected app.
183
- * @since 1.0.0
184
- * @example
185
- * ```js
186
- * console.log(app);
187
- * =>
188
- * {
189
- * name: 'mock-app',
190
- * env: 'test',
191
- * subdomainOffset: 2,
192
- * config: '<egg config>',
193
- * controller: '<egg controller>',
194
- * service: '<egg service>',
195
- * middlewares: '<egg middlewares>',
196
- * urllib: '<egg urllib>',
197
- * loggers: '<egg loggers>'
198
- * }
199
- * ```
200
- */
201
- inspect() {
202
- const res = { env: this.config.env };
203
- function delegate(res$1, app, keys) {
204
- for (const key of keys) if (app[key]) res$1[key] = app[key];
205
- }
206
- function abbr(res$1, app, keys) {
207
- for (const key of keys) if (app[key]) res$1[key] = `<egg ${key}>`;
208
- }
209
- delegate(res, this, [
210
- "name",
211
- "baseDir",
212
- "subdomainOffset"
213
- ]);
214
- abbr(res, this, [
215
- "config",
216
- "controller",
217
- "httpclient",
218
- "loggers",
219
- "middlewares",
220
- "router",
221
- "serviceClasses"
222
- ]);
223
- return res;
224
- }
225
- toJSON() {
226
- return this.inspect();
227
- }
228
- /**
229
- * http request helper base on {@link httpclient}, it will auto save httpclient log.
230
- * Keep the same api with `httpclient.request(url, args)`.
231
- *
232
- * See https://github.com/node-modules/urllib#api-doc for more details.
233
- *
234
- * @param {String} url request url address.
235
- * @param {Object} options
236
- * - method {String} - Request method, defaults to GET. Could be GET, POST, DELETE or PUT. Alias 'type'.
237
- * - data {Object} - Data to be sent. Will be stringify automatically.
238
- * - dataType {String} - String - Type of response data. Could be `text` or `json`.
239
- * If it's `text`, the callback data would be a String.
240
- * If it's `json`, the data of callback would be a parsed JSON Object.
241
- * Default callback data would be a Buffer.
242
- * - headers {Object} - Request headers.
243
- * - timeout {Number} - Request timeout in milliseconds. Defaults to exports.TIMEOUT.
244
- * Include remote server connecting timeout and response timeout.
245
- * When timeout happen, will return ConnectionTimeout or ResponseTimeout.
246
- * - auth {String} - `username:password` used in HTTP Basic Authorization.
247
- * - followRedirect {Boolean} - follow HTTP 3xx responses as redirects. defaults to false.
248
- * - gzip {Boolean} - let you get the res object when request connected, default false. alias customResponse
249
- * - nestedQuerystring {Boolean} - urllib default use querystring to stringify form data which don't
250
- * support nested object, will use qs instead of querystring to support nested object by set this option to true.
251
- * - more options see https://github.com/node-modules/urllib
252
- * @return {Object}
253
- * - status {Number} - HTTP response status
254
- * - headers {Object} - HTTP response headers
255
- * - res {Object} - HTTP response meta
256
- * - data {Object} - HTTP response body
257
- *
258
- * @example
259
- * ```js
260
- * const result = await app.curl('http://example.com/foo.json', {
261
- * method: 'GET',
262
- * dataType: 'json',
263
- * });
264
- * console.log(result.status, result.headers, result.data);
265
- * ```
266
- */
267
- async curl(url, options) {
268
- return await this.httpClient.request(url, options);
269
- }
270
- /**
271
- * Create a new HttpClient instance with custom options
272
- * @param {Object} [options] HttpClient init options
273
- */
274
- createHttpClient(options) {
275
- return new this.HttpClient(this, options);
276
- }
277
- /**
278
- * HttpClient instance
279
- * @see https://github.com/node-modules/urllib
280
- * @member {HttpClient}
281
- */
282
- get httpClient() {
283
- if (!this.#httpClient) this.#httpClient = this.createHttpClient();
284
- return this.#httpClient;
285
- }
286
- /**
287
- * @deprecated please use httpClient instead
288
- * @alias httpClient
289
- * @member {HttpClient}
290
- */
291
- get httpclient() {
292
- return this.httpClient;
293
- }
294
- /**
295
- * All loggers contain logger, coreLogger and customLogger
296
- * @member {Object}
297
- * @since 1.0.0
298
- */
299
- get loggers() {
300
- if (!this.#loggers) this.#loggers = createLoggers(this);
301
- return this.#loggers;
302
- }
303
- /**
304
- * Get logger by name, it's equal to app.loggers['name'],
305
- * but you can extend it with your own logical.
306
- * @param {String} name - logger name
307
- * @return {Logger} logger
308
- */
309
- getLogger(name) {
310
- return this.loggers[name] || null;
311
- }
312
- /**
313
- * application logger, log file is `$HOME/logs/{appname}/{appname}-web`
314
- * @member {Logger}
315
- * @since 1.0.0
316
- */
317
- get logger() {
318
- return this.getLogger("logger");
319
- }
320
- /**
321
- * core logger for framework and plugins, log file is `$HOME/logs/{appname}/egg-web`
322
- * @member {Logger}
323
- * @since 1.0.0
324
- */
325
- get coreLogger() {
326
- return this.getLogger("coreLogger");
327
- }
328
- _unhandledRejectionHandler(err) {
329
- this.coreLogger.error("[egg:unhandledRejection] %s", err && err.message || err);
330
- if (!(err instanceof Error)) {
331
- const newError = new Error(String(err));
332
- if (err) {
333
- if (err.name) newError.name = err.name;
334
- if (err.message) newError.message = err.message;
335
- if (err.stack) newError.stack = err.stack;
336
- }
337
- err = newError;
338
- }
339
- if (err.name === "Error") err.name = "unhandledRejectionError";
340
- this.coreLogger.error(err);
341
- }
342
- /**
343
- * dump out the config and meta object
344
- * @private
345
- */
346
- dumpConfigToObject() {
347
- let ignoreList;
348
- try {
349
- ignoreList = Array.from(this.config.dump.ignore);
350
- } catch {
351
- ignoreList = [];
352
- }
353
- const config = extend(true, {}, {
354
- config: this.config,
355
- plugins: this.loader.allPlugins,
356
- appInfo: this.loader.appInfo
357
- });
358
- convertObject(config, ignoreList);
359
- return {
360
- config,
361
- meta: this.loader.configMeta
362
- };
363
- }
364
- /**
365
- * save app.config to `run/${type}_config.json`
366
- * @private
367
- */
368
- dumpConfig() {
369
- const rundir = this.config.rundir;
370
- try {
371
- if (!fs.existsSync(rundir)) fs.mkdirSync(rundir);
372
- const { config, meta } = this.dumpConfigToObject();
373
- const dumpFile = path.join(rundir, `${this.type}_config.json`);
374
- fs.writeFileSync(dumpFile, CircularJSON.stringify(config, null, 2));
375
- const dumpMetaFile = path.join(rundir, `${this.type}_config_meta.json`);
376
- fs.writeFileSync(dumpMetaFile, CircularJSON.stringify(meta, null, 2));
377
- } catch (err) {
378
- this.coreLogger.warn(`[egg] dumpConfig error: ${err.message}`);
379
- }
380
- }
381
- dumpTiming() {
382
- try {
383
- const items = this.timing.toJSON();
384
- const rundir = this.config.rundir;
385
- const dumpFile = path.join(rundir, `${this.type}_timing_${process.pid}.json`);
386
- fs.writeFileSync(dumpFile, CircularJSON.stringify(items, null, 2));
387
- this.coreLogger.info(this.timing.toString());
388
- this.timing.disable();
389
- for (const item of items) if (item.index > 0 && item.duration && item.duration >= this.config.dump.timing.slowBootActionMinDuration) this.coreLogger.warn("[egg][dumpTiming][slow-boot-action] #%d %dms, name: %s", item.index, item.duration, item.name);
390
- } catch (err) {
391
- this.coreLogger.warn(`[egg] dumpTiming error: ${err.message}`);
392
- }
393
- }
394
- get [EGG_PATH]() {
395
- return getSourceDirname();
396
- }
397
- #setupTimeoutTimer() {
398
- const startTimeoutTimer = setTimeout(() => {
399
- this.coreLogger.error(this.timing.toString());
400
- this.coreLogger.error(`${this.type} still doesn't ready after ${this.config.workerStartTimeout} ms.`);
401
- const items = this.timing.toJSON();
402
- for (const item of items) {
403
- if (item.end) continue;
404
- this.coreLogger.error(`unfinished timing item: ${CircularJSON.stringify(item)}`);
405
- }
406
- this.coreLogger.error("[egg][setupTimeoutTimer] check run/%s_timing_%s.json for more details.", this.type, process.pid);
407
- this.emit("startTimeout");
408
- this.dumpConfig();
409
- this.dumpTiming();
410
- }, this.config.workerStartTimeout);
411
- this.ready(() => clearTimeout(startTimeoutTimer));
412
- }
413
- get config() {
414
- return super.config;
415
- }
416
- /**
417
- * app.env delegate app.config.env
418
- * @deprecated
419
- */
420
- get env() {
421
- this.deprecate("please use app.config.env instead");
422
- return this.config.env;
423
- }
424
- set env(_) {}
425
- /**
426
- * app.proxy delegate app.config.proxy
427
- * @deprecated
428
- */
429
- get proxy() {
430
- return this.config.proxy;
431
- }
432
- set proxy(_) {}
433
- #patchClusterClient(client) {
434
- const rawCreate = client.create;
435
- client.create = (...args) => {
436
- const realClient = rawCreate.apply(client, args);
437
- this.#clusterClients.push(realClient);
438
- return realClient;
439
- };
440
- }
441
- /**
442
- * Create an anonymous context, the context isn't request level, so the request is mocked.
443
- * then you can use context level API like `ctx.service`
444
- * @member {String} EggApplication#createAnonymousContext
445
- * @param {Request} [req] - if you want to mock request like querystring, you can pass an object to this function.
446
- * @return {Context} context
447
- */
448
- createAnonymousContext(req) {
449
- const request = {
450
- headers: {
451
- host: "127.0.0.1",
452
- "x-forwarded-for": "127.0.0.1"
453
- },
454
- query: {},
455
- querystring: "",
456
- host: "127.0.0.1",
457
- hostname: "127.0.0.1",
458
- protocol: "http",
459
- secure: "false",
460
- method: "GET",
461
- url: "/",
462
- path: "/",
463
- socket: {
464
- remoteAddress: "127.0.0.1",
465
- remotePort: 7001
466
- }
467
- };
468
- if (req) for (const key in req) if (key === "headers" || key === "query" || key === "socket") Object.assign(request[key], req[key]);
469
- else request[key] = req[key];
470
- const response = new http.ServerResponse(request);
471
- return this.createContext(request, response);
472
- }
473
- /**
474
- * Run async function in the anonymous context scope
475
- * @see Context#runInAnonymousContextScope
476
- * @param {Function} scope - the first args is an anonymous ctx, scope should be async function
477
- * @param {Request} [req] - if you want to mock request like querystring, you can pass an object to this function.
478
- */
479
- async runInAnonymousContextScope(scope, req) {
480
- const ctx = this.createAnonymousContext(req);
481
- if (!scope.name) Reflect.set(scope, "_name", utils.getCalleeFromStack(true));
482
- return await this.ctxStorage.run(ctx, async () => {
483
- return await scope(ctx);
484
- });
485
- }
486
- /**
487
- * Create egg context
488
- * @function EggApplication#createContext
489
- * @param {Req} req - node native Request object
490
- * @param {Res} res - node native Response object
491
- * @return {Context} context object
492
- */
493
- createContext(req, res) {
494
- const context = Object.create(this.context);
495
- const request = context.request = Object.create(this.request);
496
- const response = context.response = Object.create(this.response);
497
- context.app = request.app = response.app = this;
498
- context.req = request.req = response.req = req;
499
- context.res = request.res = response.res = res;
500
- request.ctx = response.ctx = context;
501
- request.response = response;
502
- response.request = request;
503
- context.onerror = context.onerror.bind(context);
504
- context.originalUrl = request.originalUrl = req.url;
505
- context.starttime = Date.now();
506
- context.performanceStarttime = performance.now();
507
- return context;
508
- }
509
- };
510
-
511
- //#endregion
512
- export { Context, EggApplicationCore, Request, Response, Router };
30
+ * Based on koa's Application
31
+ * @see https://github.com/eggjs/egg-core
32
+ * @see https://github.com/eggjs/koa/blob/master/src/application.ts
33
+ * @augments EggCore
34
+ */
35
+ export class EggApplicationCore extends EggCore {
36
+ /**
37
+ * Get the current request context from AsyncLocalStorage.
38
+ * This provides access to the context object for the current request lifecycle.
39
+ * @returns {Context | undefined} The current request context, or undefined if not in a request scope.
40
+ */
41
+ get currentContext() {
42
+ return this.ctxStorage.getStore();
43
+ }
44
+ // export context base classes, let framework can impl sub class and over context extend easily.
45
+ ContextCookies = ContextCookies;
46
+ ContextLogger = ContextLogger;
47
+ ContextHttpClient = ContextHttpClient;
48
+ HttpClient = HttpClient;
49
+ // keep compatible with egg version 3.x
50
+ HttpClientNext = HttpClient;
51
+ /**
52
+ * Retrieve base context class
53
+ * @member {BaseContextClass} BaseContextClass
54
+ * @since 1.0.0
55
+ */
56
+ BaseContextClass = BaseContextClass;
57
+ /**
58
+ * Retrieve base controller
59
+ * @member {Controller} Controller
60
+ * @since 1.0.0
61
+ */
62
+ Controller = BaseContextClass;
63
+ /**
64
+ * Retrieve base service
65
+ * @member {Service} Service
66
+ * @since 1.0.0
67
+ */
68
+ Service = BaseContextClass;
69
+ /**
70
+ * Retrieve base subscription
71
+ * @member {Subscription} Subscription
72
+ * @since 2.12.0
73
+ */
74
+ Subscription = BaseContextClass;
75
+ /**
76
+ * Retrieve base context class
77
+ * @member {BaseHookClass} BaseHookClass
78
+ */
79
+ BaseHookClass = BaseHookClass;
80
+ /**
81
+ * Retrieve base boot
82
+ * @member {Boot}
83
+ * @alias BaseHookClass
84
+ */
85
+ Boot = BaseHookClass;
86
+ #httpClient;
87
+ #loggers;
88
+ #clusterClients = [];
89
+ messenger;
90
+ agent;
91
+ application;
92
+ /**
93
+ * @class
94
+ * @param {Object} options
95
+ * - {Object} [type] - type of instance, Agent and Application both extend koa, type can determine what it is.
96
+ * - {String} [baseDir] - app root dir, default is `process.cwd()`
97
+ * - {Object} [plugins] - custom plugin config, use it in unittest
98
+ * - {String} [mode] - process mode, can be cluster / single, default is `cluster`
99
+ */
100
+ constructor(options) {
101
+ options = {
102
+ mode: 'cluster',
103
+ type: 'application',
104
+ baseDir: process.cwd(),
105
+ ...options,
106
+ };
107
+ super(options);
108
+ /**
109
+ * messenger instance
110
+ * @member {Messenger}
111
+ * @since 1.0.0
112
+ */
113
+ this.messenger = createMessenger(this);
114
+ // trigger `serverDidReady` hook when all the app workers
115
+ // and agent worker are ready
116
+ this.messenger.once('egg-ready', () => {
117
+ this.lifecycle.triggerServerDidReady();
118
+ });
119
+ this.lifecycle.registerBeforeStart(async () => {
120
+ await this.load();
121
+ }, 'load files');
122
+ }
123
+ /**
124
+ * @deprecated please use `options` property instead
125
+ */
126
+ get _options() {
127
+ return this.options;
128
+ }
129
+ async loadConfig() {
130
+ await this.loader.loadConfig();
131
+ }
132
+ async load() {
133
+ await this.loadConfig();
134
+ // dump config after ready, ensure all the modifications during start will be recorded
135
+ // make sure dumpConfig is the last ready callback
136
+ this.ready(() => process.nextTick(() => {
137
+ const dumpStartTime = Date.now();
138
+ this.dumpConfig();
139
+ this.dumpTiming();
140
+ this.coreLogger.info('[egg] dump config after ready, %sms', Date.now() - dumpStartTime);
141
+ }));
142
+ this.#setupTimeoutTimer();
143
+ this.console.info('[egg] App root: %s', this.baseDir);
144
+ this.console.info('[egg] All *.log files save on %j', this.config.logger.dir);
145
+ assert(this.config.logger.dir, 'logger.dir is required');
146
+ this.console.info('[egg] Loaded enabled plugin %j', this.loader.orderPlugins);
147
+ // Listen the error that promise had not catch, then log it in common-error
148
+ this._unhandledRejectionHandler = this._unhandledRejectionHandler.bind(this);
149
+ process.on('unhandledRejection', this._unhandledRejectionHandler);
150
+ // register close function
151
+ this.lifecycle.registerBeforeClose(async () => {
152
+ // close all cluster clients
153
+ for (const clusterClient of this.#clusterClients) {
154
+ await closeClusterClient(clusterClient);
155
+ }
156
+ this.#clusterClients = [];
157
+ // single process mode will close agent before app close
158
+ if (this.type === 'application' && this.options.mode === 'single') {
159
+ await this.agent.close();
160
+ }
161
+ for (const logger of this.loggers.values()) {
162
+ logger.close();
163
+ }
164
+ this.messenger.close();
165
+ process.removeListener('unhandledRejection', this._unhandledRejectionHandler);
166
+ });
167
+ await this.loader.load();
168
+ }
169
+ /**
170
+ * Usage: new ApiClient({ cluster: app.cluster })
171
+ */
172
+ get cluster() {
173
+ return this.clusterWrapper.bind(this);
174
+ }
175
+ /**
176
+ * Wrap the Client with Leader/Follower Pattern
177
+ *
178
+ * @description almost the same as Agent.cluster API, the only different is that this method create Follower.
179
+ *
180
+ * @see https://github.com/node-modules/cluster-client
181
+ * @param {Function} clientClass - client class function
182
+ * @param {Object} [options]
183
+ * - {Boolean} [autoGenerate] - whether generate delegate rule automatically, default is true
184
+ * - {Function} [formatKey] - a method to transform the subscription info into a string,default is JSON.stringify
185
+ * - {Object} [transcode|JSON.stringify/parse]
186
+ * - {Function} encode - custom serialize method
187
+ * - {Function} decode - custom deserialize method
188
+ * - {Boolean} [isBroadcast] - whether broadcast subscription result to all followers or just one, default is true
189
+ * - {Number} [responseTimeout] - response timeout, default is 3 seconds
190
+ * - {Number} [maxWaitTime|30000] - leader startup max time, default is 30 seconds
191
+ * @return {ClientWrapper} wrapper
192
+ */
193
+ clusterWrapper(clientClass, options) {
194
+ const clientClassOptions = {
195
+ ...this.config.clusterClient,
196
+ ...options,
197
+ singleMode: this.options.mode === 'single',
198
+ // cluster need a port that can't conflict on the environment
199
+ port: this.options.clusterPort,
200
+ // agent worker is leader, app workers are follower
201
+ isLeader: this.type === 'agent',
202
+ logger: this.coreLogger,
203
+ // debug mode does not check heartbeat
204
+ isCheckHeartbeat: this.config.env === 'prod' ? true : inspector.url() === undefined,
205
+ };
206
+ const client = createClusterClient(clientClass, clientClassOptions);
207
+ this.#patchClusterClient(client);
208
+ return client;
209
+ }
210
+ /**
211
+ * print the information when console.log(app)
212
+ * @return {Object} inspected app.
213
+ * @since 1.0.0
214
+ * @example
215
+ * ```js
216
+ * console.log(app);
217
+ * =>
218
+ * {
219
+ * name: 'mock-app',
220
+ * env: 'test',
221
+ * subdomainOffset: 2,
222
+ * config: '<egg config>',
223
+ * controller: '<egg controller>',
224
+ * service: '<egg service>',
225
+ * middlewares: '<egg middlewares>',
226
+ * urllib: '<egg urllib>',
227
+ * loggers: '<egg loggers>'
228
+ * }
229
+ * ```
230
+ */
231
+ inspect() {
232
+ const res = {
233
+ env: this.config.env,
234
+ };
235
+ function delegate(res, app, keys) {
236
+ for (const key of keys) {
237
+ if (app[key]) {
238
+ res[key] = app[key];
239
+ }
240
+ }
241
+ }
242
+ function abbr(res, app, keys) {
243
+ for (const key of keys) {
244
+ if (app[key]) {
245
+ res[key] = `<egg ${key}>`;
246
+ }
247
+ }
248
+ }
249
+ delegate(res, this, ['name', 'baseDir', 'subdomainOffset']);
250
+ abbr(res, this, ['config', 'controller', 'httpclient', 'loggers', 'middlewares', 'router', 'serviceClasses']);
251
+ return res;
252
+ }
253
+ toJSON() {
254
+ return this.inspect();
255
+ }
256
+ /**
257
+ * http request helper base on {@link httpclient}, it will auto save httpclient log.
258
+ * Keep the same api with `httpclient.request(url, args)`.
259
+ *
260
+ * See https://github.com/node-modules/urllib#api-doc for more details.
261
+ *
262
+ * @param {String} url request url address.
263
+ * @param {Object} options
264
+ * - method {String} - Request method, defaults to GET. Could be GET, POST, DELETE or PUT. Alias 'type'.
265
+ * - data {Object} - Data to be sent. Will be stringify automatically.
266
+ * - dataType {String} - String - Type of response data. Could be `text` or `json`.
267
+ * If it's `text`, the callback data would be a String.
268
+ * If it's `json`, the data of callback would be a parsed JSON Object.
269
+ * Default callback data would be a Buffer.
270
+ * - headers {Object} - Request headers.
271
+ * - timeout {Number} - Request timeout in milliseconds. Defaults to exports.TIMEOUT.
272
+ * Include remote server connecting timeout and response timeout.
273
+ * When timeout happen, will return ConnectionTimeout or ResponseTimeout.
274
+ * - auth {String} - `username:password` used in HTTP Basic Authorization.
275
+ * - followRedirect {Boolean} - follow HTTP 3xx responses as redirects. defaults to false.
276
+ * - gzip {Boolean} - let you get the res object when request connected, default false. alias customResponse
277
+ * - nestedQuerystring {Boolean} - urllib default use querystring to stringify form data which don't
278
+ * support nested object, will use qs instead of querystring to support nested object by set this option to true.
279
+ * - more options see https://github.com/node-modules/urllib
280
+ * @return {Object}
281
+ * - status {Number} - HTTP response status
282
+ * - headers {Object} - HTTP response headers
283
+ * - res {Object} - HTTP response meta
284
+ * - data {Object} - HTTP response body
285
+ *
286
+ * @example
287
+ * ```js
288
+ * const result = await app.curl('http://example.com/foo.json', {
289
+ * method: 'GET',
290
+ * dataType: 'json',
291
+ * });
292
+ * console.log(result.status, result.headers, result.data);
293
+ * ```
294
+ */
295
+ async curl(url, options) {
296
+ return await this.httpClient.request(url, options);
297
+ }
298
+ /**
299
+ * Create a new HttpClient instance with custom options
300
+ * @param {Object} [options] HttpClient init options
301
+ */
302
+ createHttpClient(options) {
303
+ return new this.HttpClient(this, options);
304
+ }
305
+ /**
306
+ * HttpClient instance
307
+ * @see https://github.com/node-modules/urllib
308
+ * @member {HttpClient}
309
+ */
310
+ get httpClient() {
311
+ if (!this.#httpClient) {
312
+ this.#httpClient = this.createHttpClient();
313
+ }
314
+ return this.#httpClient;
315
+ }
316
+ /**
317
+ * @deprecated please use httpClient instead
318
+ * @alias httpClient
319
+ * @member {HttpClient}
320
+ */
321
+ get httpclient() {
322
+ return this.httpClient;
323
+ }
324
+ /**
325
+ * All loggers contain logger, coreLogger and customLogger
326
+ * @member {Object}
327
+ * @since 1.0.0
328
+ */
329
+ get loggers() {
330
+ if (!this.#loggers) {
331
+ this.#loggers = createLoggers(this);
332
+ }
333
+ return this.#loggers;
334
+ }
335
+ /**
336
+ * Get logger by name, it's equal to app.loggers['name'],
337
+ * but you can extend it with your own logical.
338
+ * @param {String} name - logger name
339
+ * @return {Logger} logger
340
+ */
341
+ getLogger(name) {
342
+ return this.loggers[name] || null;
343
+ }
344
+ /**
345
+ * application logger, log file is `$HOME/logs/{appname}/{appname}-web`
346
+ * @member {Logger}
347
+ * @since 1.0.0
348
+ */
349
+ get logger() {
350
+ return this.getLogger('logger');
351
+ }
352
+ /**
353
+ * core logger for framework and plugins, log file is `$HOME/logs/{appname}/egg-web`
354
+ * @member {Logger}
355
+ * @since 1.0.0
356
+ */
357
+ get coreLogger() {
358
+ return this.getLogger('coreLogger');
359
+ }
360
+ _unhandledRejectionHandler(err) {
361
+ this.coreLogger.error('[egg:unhandledRejection] %s', (err && err.message) || err);
362
+ if (!(err instanceof Error)) {
363
+ const newError = new Error(String(err));
364
+ // err maybe an object, try to copy the name, message and stack to the new error instance
365
+ if (err) {
366
+ if (err.name)
367
+ newError.name = err.name;
368
+ if (err.message)
369
+ newError.message = err.message;
370
+ if (err.stack)
371
+ newError.stack = err.stack;
372
+ }
373
+ err = newError;
374
+ }
375
+ if (err.name === 'Error') {
376
+ err.name = 'unhandledRejectionError';
377
+ }
378
+ this.coreLogger.error(err);
379
+ }
380
+ /**
381
+ * dump out the config and meta object
382
+ * @private
383
+ */
384
+ dumpConfigToObject() {
385
+ let ignoreList;
386
+ try {
387
+ // support array and set
388
+ ignoreList = Array.from(this.config.dump.ignore);
389
+ }
390
+ catch {
391
+ ignoreList = [];
392
+ }
393
+ const config = extend(true, {}, {
394
+ config: this.config,
395
+ plugins: this.loader.allPlugins,
396
+ appInfo: this.loader.appInfo,
397
+ });
398
+ convertObject(config, ignoreList);
399
+ return {
400
+ config,
401
+ meta: this.loader.configMeta,
402
+ };
403
+ }
404
+ /**
405
+ * save app.config to `run/${type}_config.json`
406
+ * @private
407
+ */
408
+ dumpConfig() {
409
+ const rundir = this.config.rundir;
410
+ try {
411
+ if (!fs.existsSync(rundir)) {
412
+ fs.mkdirSync(rundir);
413
+ }
414
+ // get dumped object
415
+ const { config, meta } = this.dumpConfigToObject();
416
+ // dump config
417
+ const dumpFile = path.join(rundir, `${this.type}_config.json`);
418
+ fs.writeFileSync(dumpFile, CircularJSON.stringify(config, null, 2));
419
+ // dump config meta
420
+ const dumpMetaFile = path.join(rundir, `${this.type}_config_meta.json`);
421
+ fs.writeFileSync(dumpMetaFile, CircularJSON.stringify(meta, null, 2));
422
+ }
423
+ catch (err) {
424
+ this.coreLogger.warn(`[egg] dumpConfig error: ${err.message}`);
425
+ }
426
+ }
427
+ dumpTiming() {
428
+ try {
429
+ const items = this.timing.toJSON();
430
+ const rundir = this.config.rundir;
431
+ const dumpFile = path.join(rundir, `${this.type}_timing_${process.pid}.json`);
432
+ fs.writeFileSync(dumpFile, CircularJSON.stringify(items, null, 2));
433
+ this.coreLogger.info(this.timing.toString());
434
+ // only disable, not clear bootstrap timing data.
435
+ this.timing.disable();
436
+ // show duration >= ${slowBootActionMinDuration}ms action to warning log
437
+ for (const item of items) {
438
+ // ignore #0 name: Process Start
439
+ if (item.index > 0 && item.duration && item.duration >= this.config.dump.timing.slowBootActionMinDuration) {
440
+ this.coreLogger.warn('[egg][dumpTiming][slow-boot-action] #%d %dms, name: %s', item.index, item.duration, item.name);
441
+ }
442
+ }
443
+ }
444
+ catch (err) {
445
+ this.coreLogger.warn(`[egg] dumpTiming error: ${err.message}`);
446
+ }
447
+ }
448
+ customEggPaths() {
449
+ return [path.dirname(import.meta.dirname), ...super.customEggPaths()];
450
+ }
451
+ #setupTimeoutTimer() {
452
+ const startTimeoutTimer = setTimeout(() => {
453
+ this.coreLogger.error(this.timing.toString());
454
+ this.coreLogger.error(`${this.type} still doesn't ready after ${this.config.workerStartTimeout} ms.`);
455
+ // log unfinished
456
+ const items = this.timing.toJSON();
457
+ for (const item of items) {
458
+ if (item.end)
459
+ continue;
460
+ this.coreLogger.error(`unfinished timing item: ${CircularJSON.stringify(item)}`);
461
+ }
462
+ this.coreLogger.error('[egg][setupTimeoutTimer] check run/%s_timing_%s.json for more details.', this.type, process.pid);
463
+ this.emit('startTimeout');
464
+ this.dumpConfig();
465
+ this.dumpTiming();
466
+ }, this.config.workerStartTimeout);
467
+ this.ready(() => clearTimeout(startTimeoutTimer));
468
+ }
469
+ get config() {
470
+ return super.config;
471
+ }
472
+ /**
473
+ * app.env delegate app.config.env
474
+ * @deprecated
475
+ */
476
+ get env() {
477
+ this.deprecate('please use app.config.env instead');
478
+ return this.config.env;
479
+ }
480
+ /* eslint no-empty-function: off */
481
+ set env(_) { }
482
+ /**
483
+ * app.proxy delegate app.config.proxy
484
+ * @deprecated
485
+ */
486
+ get proxy() {
487
+ // this.deprecate('please use app.config.proxy instead');
488
+ return this.config.proxy;
489
+ }
490
+ /* eslint no-empty-function: off */
491
+ set proxy(_) { }
492
+ #patchClusterClient(client) {
493
+ const rawCreate = client.create;
494
+ client.create = (...args) => {
495
+ const realClient = rawCreate.apply(client, args);
496
+ this.#clusterClients.push(realClient);
497
+ return realClient;
498
+ };
499
+ }
500
+ /**
501
+ * Create an anonymous context, the context isn't request level, so the request is mocked.
502
+ * then you can use context level API like `ctx.service`
503
+ * @member {String} EggApplication#createAnonymousContext
504
+ * @param {Request} [req] - if you want to mock request like querystring, you can pass an object to this function.
505
+ * @return {Context} context
506
+ */
507
+ createAnonymousContext(req) {
508
+ const request = {
509
+ headers: {
510
+ host: '127.0.0.1',
511
+ 'x-forwarded-for': '127.0.0.1',
512
+ },
513
+ query: {},
514
+ querystring: '',
515
+ host: '127.0.0.1',
516
+ hostname: '127.0.0.1',
517
+ protocol: 'http',
518
+ secure: 'false',
519
+ method: 'GET',
520
+ url: '/',
521
+ path: '/',
522
+ socket: {
523
+ remoteAddress: '127.0.0.1',
524
+ remotePort: 7001,
525
+ },
526
+ };
527
+ if (req) {
528
+ for (const key in req) {
529
+ if (key === 'headers' || key === 'query' || key === 'socket') {
530
+ Object.assign(request[key], req[key]);
531
+ }
532
+ else {
533
+ request[key] = req[key];
534
+ }
535
+ }
536
+ }
537
+ const response = new http.ServerResponse(request);
538
+ return this.createContext(request, response);
539
+ }
540
+ /**
541
+ * Run async function in the anonymous context scope
542
+ * @see Context#runInAnonymousContextScope
543
+ * @param {Function} scope - the first args is an anonymous ctx, scope should be async function
544
+ * @param {Request} [req] - if you want to mock request like querystring, you can pass an object to this function.
545
+ */
546
+ async runInAnonymousContextScope(scope, req) {
547
+ const ctx = this.createAnonymousContext(req);
548
+ if (!scope.name) {
549
+ Reflect.set(scope, '_name', eggUtils.getCalleeFromStack(true));
550
+ }
551
+ return await this.ctxStorage.run(ctx, async () => {
552
+ return await scope(ctx);
553
+ });
554
+ }
555
+ /**
556
+ * Create egg context
557
+ * @function EggApplication#createContext
558
+ * @param {Req} req - node native Request object
559
+ * @param {Res} res - node native Response object
560
+ * @return {Context} context object
561
+ */
562
+ createContext(req, res) {
563
+ const context = Object.create(this.context);
564
+ const request = (context.request = Object.create(this.request));
565
+ const response = (context.response = Object.create(this.response));
566
+ context.app = request.app = response.app = this;
567
+ context.req = request.req = response.req = req;
568
+ context.res = request.res = response.res = res;
569
+ request.ctx = response.ctx = context;
570
+ request.response = response;
571
+ response.request = request;
572
+ context.onerror = context.onerror.bind(context);
573
+ context.originalUrl = request.originalUrl = req.url;
574
+ context.starttime = Date.now();
575
+ context.performanceStarttime = performance.now();
576
+ return context;
577
+ }
578
+ }
579
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWdnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xpYi9lZ2cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUM3QixPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDekIsT0FBTyxJQUFJLEVBQUUsRUFBNkMsTUFBTSxXQUFXLENBQUM7QUFDNUUsT0FBTyxTQUFTLE1BQU0sZ0JBQWdCLENBQUM7QUFFdkMsT0FBTyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBRWpDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTlDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2hELGlEQUFpRDtBQUNqRCxPQUFPLG1CQUFtQixFQUFFLEVBQUUsS0FBSyxJQUFJLGtCQUFrQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEYsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sRUFBRSxnQkFBZ0IsSUFBSSxhQUFhLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUN0RixPQUFPLEVBQUUsT0FBTyxJQUFJLGNBQWMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNELHNEQUFzRDtBQUN0RCxPQUFPLFlBQVksTUFBTSx1QkFBdUIsQ0FBQztBQUlqRCxPQUFPLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUMvQyxPQUFPLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUMvQyxPQUFPLFFBQVEsTUFBTSwyQkFBMkIsQ0FBQztBQUVqRCxPQUFPLEVBQUUsTUFBTSxJQUFJLGVBQWUsRUFBbUIsTUFBTSwyQkFBMkIsQ0FBQztBQUN2RixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw4QkFB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