egg 4.1.2-beta.2 → 4.1.2-beta.20
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/README.md +7 -4
- package/dist/index.d.ts +27 -1
- package/dist/index.js +9 -2
- package/dist/lib/agent.d.ts +6 -0
- package/dist/lib/agent.js +13 -1
- package/dist/lib/core/httpclient.js +4 -0
- package/dist/lib/core/utils.d.ts +26 -1
- package/dist/lib/core/utils.js +71 -1
- package/dist/lib/egg.d.ts +39 -0
- package/dist/lib/egg.js +136 -16
- package/dist/lib/loader/AppWorkerLoader.js +1 -1
- package/dist/lib/snapshot.d.ts +46 -0
- package/dist/lib/snapshot.js +59 -0
- package/dist/lib/start.d.ts +16 -1
- package/dist/lib/start.js +29 -11
- package/dist/lib/types.d.ts +20 -1
- package/dist/lib/types.js +5 -1
- package/package.json +94 -39
package/README.md
CHANGED
|
@@ -21,14 +21,17 @@
|
|
|
21
21
|
Follow the commands listed below.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
+
$ corepack enable utoo
|
|
24
25
|
$ mkdir showcase && cd showcase
|
|
25
|
-
$
|
|
26
|
-
|
|
27
|
-
$
|
|
26
|
+
$ ut create egg@beta
|
|
27
|
+
# Or with npm:
|
|
28
|
+
$ npm init egg --type=simple
|
|
29
|
+
$ ut install
|
|
30
|
+
$ ut run dev
|
|
28
31
|
$ open http://localhost:7001
|
|
29
32
|
```
|
|
30
33
|
|
|
31
|
-
> Node.js >=
|
|
34
|
+
> Node.js >= 22.18.0 required.
|
|
32
35
|
|
|
33
36
|
## Documentations
|
|
34
37
|
|
package/dist/index.d.ts
CHANGED
|
@@ -14,11 +14,37 @@ import { BaseContextClass } from "./lib/core/base_context_class.js";
|
|
|
14
14
|
import Helper from "./app/extend/helper.js";
|
|
15
15
|
import { SingleModeAgent, SingleModeApplication, StartEggOptions, startEgg } from "./lib/start.js";
|
|
16
16
|
import { EggConfigFactory, EggPluginFactory, EggPluginMeta, EggPluginOptions, PartialEggConfig, defineConfig, defineConfigFactory, definePluginFactory } from "./lib/define.js";
|
|
17
|
+
import { buildSnapshot, restoreSnapshot } from "./lib/snapshot.js";
|
|
17
18
|
import { CookieLimitExceedError } from "./lib/error/CookieLimitExceedError.js";
|
|
18
19
|
import { MessageUnhandledRejectionError } from "./lib/error/MessageUnhandledRejectionError.js";
|
|
20
|
+
import { CreateTransparentProxyOptions, createTransparentProxy } from "./lib/core/utils.js";
|
|
19
21
|
import { BaseHookClass } from "./lib/core/base_hook_class.js";
|
|
20
22
|
import { Singleton, SingletonCreateMethod, SingletonOptions } from "@eggjs/core";
|
|
21
23
|
import { EggLogger, EggLogger as Logger, LoggerLevel } from "egg-logger";
|
|
22
24
|
import { AccessLevel, Acl, BackgroundTaskHelper, ContextEventBus, ContextProto, Cookies, EggObjectFactory, EggObjectLifecycle, EggProtoImplClass, EggQualifier, EggType, Event, EventBus, EventContext, Events, HTTPBody, HTTPContext, HTTPController, HTTPCookies, HTTPHeaders, HTTPMethod, HTTPMethodEnum, HTTPParam, HTTPParamType, HTTPQueries, HTTPQuery, HTTPRequest, Host, ImplDecorator, IncomingHttpHeaders, Inject, InjectOptional, LifecycleDestroy, LifecycleInit, LifecyclePostConstruct, LifecyclePostInject, LifecyclePreDestroy, LifecyclePreInject, LifecyclePreLoad, MetadataUtil, Middleware, MultiInstanceProto, MultiInstancePrototypeGetObjectsContext, ObjectInfo, ObjectInitType, ObjectInitTypeLike, QualifierImplDecoratorUtil, QualifierUtil, SingletonProto } from "@eggjs/tegg";
|
|
23
25
|
export * from "@eggjs/cluster";
|
|
24
|
-
|
|
26
|
+
|
|
27
|
+
//#region src/index.d.ts
|
|
28
|
+
declare const Config: typeof EggAppConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Egg Application Config, can be injected into Proto, e.g. SingletonProto/ContextProto/HttpController.
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { Inject, Config } from 'egg';
|
|
35
|
+
*
|
|
36
|
+
* @SingletonProto()
|
|
37
|
+
* class FooService {
|
|
38
|
+
* @Inject()
|
|
39
|
+
* config: Config;
|
|
40
|
+
*
|
|
41
|
+
* async bar() {
|
|
42
|
+
* console.log(this.config.env);
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
* @since 4.1.0
|
|
47
|
+
*/
|
|
48
|
+
type Config = EggAppConfig;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { AccessLevel, Acl, Agent, AgentWorkerLoader, AppWorkerLoader, Application, BackgroundTaskHelper, BaseContextClass, BaseHookClass as Boot, ClientErrorResponse, Config, Context, type ContextEventBus, ContextHttpClient, ContextProto, BaseContextClass as Controller, BaseContextClass as Service, BaseContextClass as Subscription, CookieLimitExceedError, Cookies, type CreateTransparentProxyOptions, CustomLoaderConfig, EggAppConfig, EggAppInfo, EggApplicationCore, EggApplicationCoreOptions, EggConfigFactory, EggContext, HttpClient as EggContextHttpClient, HttpClient as EggHttpClient, HttpClient, EggEnvType, type EggLogger, EggLoggerConfig, type EggObjectFactory, type EggObjectLifecycle, EggPlugin, EggPluginFactory, EggPluginItem, EggPluginMeta, EggPluginOptions, type EggProtoImplClass, EggQualifier, EggType, Event, type EventBus, EventContext, type Events, HTTPBody, HTTPContext, HTTPController, HTTPCookies, HTTPHeaders, HTTPMethod, HTTPMethodEnum, HTTPParam, HTTPParamType, HTTPQueries, HTTPQuery, HTTPRequest, Helper, type Helper as IHelper, Host, HttpClientConfig, HttpClientOptions, HttpClientRequestOptions, HttpClientRequestURL, HttpClientResponse, ILifecycleBoot as IBoot, ILifecycleBoot, IController, IEggPluginItem, IService, type ImplDecorator, type IncomingHttpHeaders, Inject, InjectOptional, LifecycleDestroy, LifecycleInit, LifecyclePostConstruct, LifecyclePostInject, LifecyclePreDestroy, LifecyclePreInject, LifecyclePreLoad, Logger, type LoggerLevel, MessageUnhandledRejectionError, MetadataUtil, Middleware, MiddlewareFunc, MultiInstanceProto, type MultiInstancePrototypeGetObjectsContext, Next, type ObjectInfo, ObjectInitType, type ObjectInitTypeLike, PartialDeep, PartialEggConfig, PowerPartial, QualifierImplDecoratorUtil, QualifierUtil, Request, RequestObjectBody, Response, Router, type SingleModeAgent, type SingleModeApplication, Singleton, type SingletonCreateMethod, type SingletonOptions, SingletonProto, StartEggOptions, buildSnapshot, createTransparentProxy, defineConfig, defineConfigFactory, definePluginFactory, restoreSnapshot, startEgg as start, startEgg };
|
package/dist/index.js
CHANGED
|
@@ -8,18 +8,25 @@ import { ContextHttpClient } from "./lib/core/context_httpclient.js";
|
|
|
8
8
|
import { HttpClient } from "./lib/core/httpclient.js";
|
|
9
9
|
import { CookieLimitExceedError } from "./lib/error/CookieLimitExceedError.js";
|
|
10
10
|
import { MessageUnhandledRejectionError } from "./lib/error/MessageUnhandledRejectionError.js";
|
|
11
|
+
import { createTransparentProxy } from "./lib/core/utils.js";
|
|
11
12
|
import { EggApplicationCore, Router } from "./lib/egg.js";
|
|
12
13
|
import { AppWorkerLoader } from "./lib/loader/AppWorkerLoader.js";
|
|
13
14
|
import { AgentWorkerLoader } from "./lib/loader/AgentWorkerLoader.js";
|
|
14
15
|
import "./lib/loader/index.js";
|
|
15
16
|
import { Agent } from "./lib/agent.js";
|
|
16
17
|
import { Application } from "./lib/application.js";
|
|
17
|
-
import "./lib/types.js";
|
|
18
|
+
import { EggAppConfig } from "./lib/types.js";
|
|
18
19
|
import { startEgg } from "./lib/start.js";
|
|
19
20
|
import { defineConfig, defineConfigFactory, definePluginFactory } from "./lib/define.js";
|
|
21
|
+
import { buildSnapshot, restoreSnapshot } from "./lib/snapshot.js";
|
|
20
22
|
import { Singleton } from "@eggjs/core";
|
|
23
|
+
import { EggLogger as Logger } from "egg-logger";
|
|
21
24
|
import { AccessLevel, Acl, BackgroundTaskHelper, ContextProto, Cookies, EggQualifier, EggType, Event, EventContext, HTTPBody, HTTPContext, HTTPController, HTTPCookies, HTTPHeaders, HTTPMethod, HTTPMethodEnum, HTTPParam, HTTPParamType, HTTPQueries, HTTPQuery, HTTPRequest, Host, Inject, InjectOptional, LifecycleDestroy, LifecycleInit, LifecyclePostConstruct, LifecyclePostInject, LifecyclePreDestroy, LifecyclePreInject, LifecyclePreLoad, MetadataUtil, Middleware, MultiInstanceProto, ObjectInitType, QualifierImplDecoratorUtil, QualifierUtil, SingletonProto } from "@eggjs/tegg";
|
|
22
25
|
|
|
23
26
|
export * from "@eggjs/cluster"
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
//#region src/index.ts
|
|
29
|
+
const Config = EggAppConfig;
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { AccessLevel, Acl, Agent, AgentWorkerLoader, AppWorkerLoader, Application, BackgroundTaskHelper, BaseContextClass, BaseHookClass as Boot, Config, Context, ContextHttpClient, ContextProto, BaseContextClass as Controller, BaseContextClass as Service, BaseContextClass as Subscription, CookieLimitExceedError, Cookies, EggAppConfig, EggApplicationCore, EggQualifier, EggType, Event, EventContext, HTTPBody, HTTPContext, HTTPController, HTTPCookies, HTTPHeaders, HTTPMethod, HTTPMethodEnum, HTTPParam, HTTPParamType, HTTPQueries, HTTPQuery, HTTPRequest, Helper, Host, HttpClient, Inject, InjectOptional, LifecycleDestroy, LifecycleInit, LifecyclePostConstruct, LifecyclePostInject, LifecyclePreDestroy, LifecyclePreInject, LifecyclePreLoad, Logger, MessageUnhandledRejectionError, MetadataUtil, Middleware, MultiInstanceProto, ObjectInitType, QualifierImplDecoratorUtil, QualifierUtil, Request, Response, Router, Singleton, SingletonProto, buildSnapshot, createTransparentProxy, defineConfig, defineConfigFactory, definePluginFactory, restoreSnapshot, startEgg as start, startEgg };
|
package/dist/lib/agent.d.ts
CHANGED
|
@@ -15,6 +15,12 @@ declare class Agent extends EggApplicationCore {
|
|
|
15
15
|
* @param {Object} options - see {@link EggApplicationCore}
|
|
16
16
|
*/
|
|
17
17
|
constructor(options?: Omit<EggApplicationCoreOptions, "type">);
|
|
18
|
+
/**
|
|
19
|
+
* Start the keepalive timer that prevents the agent process from exiting
|
|
20
|
+
* when it has no pending I/O. Called from configDidLoad so that the timer
|
|
21
|
+
* is not created during snapshot build (configDidLoad is skipped in snapshot mode).
|
|
22
|
+
*/
|
|
23
|
+
protected startKeepAlive(): void;
|
|
18
24
|
protected customEggLoader(): typeof AgentWorkerLoader;
|
|
19
25
|
_wrapMessenger(): void;
|
|
20
26
|
close(): Promise<void>;
|
package/dist/lib/agent.js
CHANGED
|
@@ -18,6 +18,15 @@ var Agent = class extends EggApplicationCore {
|
|
|
18
18
|
...options,
|
|
19
19
|
type: "agent"
|
|
20
20
|
});
|
|
21
|
+
this.lifecycle.addBootHook({ configDidLoad: () => this.startKeepAlive() });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Start the keepalive timer that prevents the agent process from exiting
|
|
25
|
+
* when it has no pending I/O. Called from configDidLoad so that the timer
|
|
26
|
+
* is not created during snapshot build (configDidLoad is skipped in snapshot mode).
|
|
27
|
+
*/
|
|
28
|
+
startKeepAlive() {
|
|
29
|
+
if (this.#agentAliveHandler) return;
|
|
21
30
|
this.#agentAliveHandler = setInterval(() => {
|
|
22
31
|
this.coreLogger.info("[]");
|
|
23
32
|
}, 1440 * 60 * 1e3);
|
|
@@ -46,7 +55,10 @@ var Agent = class extends EggApplicationCore {
|
|
|
46
55
|
}
|
|
47
56
|
}
|
|
48
57
|
async close() {
|
|
49
|
-
|
|
58
|
+
if (this.#agentAliveHandler) {
|
|
59
|
+
clearInterval(this.#agentAliveHandler);
|
|
60
|
+
this.#agentAliveHandler = void 0;
|
|
61
|
+
}
|
|
50
62
|
await super.close();
|
|
51
63
|
}
|
|
52
64
|
};
|
|
@@ -17,6 +17,10 @@ var HttpClient = class extends HttpClient$1 {
|
|
|
17
17
|
};
|
|
18
18
|
super(initOptions);
|
|
19
19
|
this.#app = app;
|
|
20
|
+
if (config.interceptors?.length) {
|
|
21
|
+
const originalDispatcher = this.getDispatcher();
|
|
22
|
+
this.setDispatcher(originalDispatcher.compose(...config.interceptors));
|
|
23
|
+
}
|
|
20
24
|
}
|
|
21
25
|
async request(url, options) {
|
|
22
26
|
options = options ?? {};
|
package/dist/lib/core/utils.d.ts
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
//#region src/lib/core/utils.d.ts
|
|
2
2
|
declare function convertObject(obj: any, ignore?: string | RegExp | (string | RegExp)[]): any;
|
|
3
3
|
declare function safeParseURL(url: string): URL | null;
|
|
4
|
+
interface CreateTransparentProxyOptions<T> {
|
|
5
|
+
/**
|
|
6
|
+
* Factory function to lazily create the real object.
|
|
7
|
+
* Called at most once, on first property access.
|
|
8
|
+
*/
|
|
9
|
+
createReal: () => T;
|
|
10
|
+
/**
|
|
11
|
+
* Whether to bind functions from the real object to the real instance.
|
|
12
|
+
* Defaults to true.
|
|
13
|
+
*/
|
|
14
|
+
bindFunctions?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a Proxy that behaves like the real object, but remains transparent to
|
|
18
|
+
* monkeypatch libraries (e.g. defineProperty-based overrides like egg-mock's `mm()`).
|
|
19
|
+
*
|
|
20
|
+
* - Lazily creates the real object on first access.
|
|
21
|
+
* - Allows overriding properties on the proxy target (overlay) — e.g. via `Object.defineProperty`.
|
|
22
|
+
* - Delegates everything else to the real object.
|
|
23
|
+
*
|
|
24
|
+
* This is used to defer HttpClient construction so plugins can modify
|
|
25
|
+
* `config.httpclient.lookup` after the first access to `app.httpClient` but
|
|
26
|
+
* before any actual HTTP request is made.
|
|
27
|
+
*/
|
|
28
|
+
declare function createTransparentProxy<T extends object>(options: CreateTransparentProxyOptions<T>): T;
|
|
4
29
|
//#endregion
|
|
5
|
-
export { convertObject, safeParseURL };
|
|
30
|
+
export { CreateTransparentProxyOptions, convertObject, createTransparentProxy, safeParseURL };
|
package/dist/lib/core/utils.js
CHANGED
|
@@ -43,6 +43,76 @@ function safeParseURL(url) {
|
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Create a Proxy that behaves like the real object, but remains transparent to
|
|
48
|
+
* monkeypatch libraries (e.g. defineProperty-based overrides like egg-mock's `mm()`).
|
|
49
|
+
*
|
|
50
|
+
* - Lazily creates the real object on first access.
|
|
51
|
+
* - Allows overriding properties on the proxy target (overlay) — e.g. via `Object.defineProperty`.
|
|
52
|
+
* - Delegates everything else to the real object.
|
|
53
|
+
*
|
|
54
|
+
* This is used to defer HttpClient construction so plugins can modify
|
|
55
|
+
* `config.httpclient.lookup` after the first access to `app.httpClient` but
|
|
56
|
+
* before any actual HTTP request is made.
|
|
57
|
+
*/
|
|
58
|
+
function createTransparentProxy(options) {
|
|
59
|
+
const { createReal, bindFunctions = true } = options;
|
|
60
|
+
if (typeof createReal !== "function") throw new TypeError("createReal must be a function");
|
|
61
|
+
let real;
|
|
62
|
+
let cachedError;
|
|
63
|
+
const boundFnCache = /* @__PURE__ */ new WeakMap();
|
|
64
|
+
const getReal = () => {
|
|
65
|
+
if (real) return real;
|
|
66
|
+
if (cachedError) throw cachedError;
|
|
67
|
+
try {
|
|
68
|
+
return real = createReal();
|
|
69
|
+
} catch (err) {
|
|
70
|
+
cachedError = err;
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const hasOwn = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== void 0;
|
|
75
|
+
return new Proxy({}, {
|
|
76
|
+
get(target, prop, receiver) {
|
|
77
|
+
const r = getReal();
|
|
78
|
+
if (hasOwn(target, prop)) return Reflect.get(target, prop, receiver);
|
|
79
|
+
const value = Reflect.get(r, prop);
|
|
80
|
+
if (bindFunctions && typeof value === "function") {
|
|
81
|
+
let bound = boundFnCache.get(value);
|
|
82
|
+
if (!bound) {
|
|
83
|
+
bound = value.bind(r);
|
|
84
|
+
boundFnCache.set(value, bound);
|
|
85
|
+
}
|
|
86
|
+
return bound;
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
},
|
|
90
|
+
set(target, prop, value) {
|
|
91
|
+
const r = getReal();
|
|
92
|
+
if (hasOwn(target, prop)) return Reflect.set(target, prop, value);
|
|
93
|
+
return Reflect.set(r, prop, value);
|
|
94
|
+
},
|
|
95
|
+
has(target, prop) {
|
|
96
|
+
return Reflect.has(target, prop) || Reflect.has(getReal(), prop);
|
|
97
|
+
},
|
|
98
|
+
ownKeys(target) {
|
|
99
|
+
return [...new Set([...Reflect.ownKeys(getReal()), ...Reflect.ownKeys(target)])];
|
|
100
|
+
},
|
|
101
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
102
|
+
return Reflect.getOwnPropertyDescriptor(target, prop) ?? Reflect.getOwnPropertyDescriptor(getReal(), prop);
|
|
103
|
+
},
|
|
104
|
+
deleteProperty(target, prop) {
|
|
105
|
+
if (hasOwn(target, prop)) return Reflect.deleteProperty(target, prop);
|
|
106
|
+
return Reflect.deleteProperty(getReal(), prop);
|
|
107
|
+
},
|
|
108
|
+
getPrototypeOf() {
|
|
109
|
+
return Reflect.getPrototypeOf(getReal());
|
|
110
|
+
},
|
|
111
|
+
defineProperty(target, prop, descriptor) {
|
|
112
|
+
return Reflect.defineProperty(target, prop, descriptor);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
46
116
|
|
|
47
117
|
//#endregion
|
|
48
|
-
export { convertObject, safeParseURL };
|
|
118
|
+
export { convertObject, createTransparentProxy, safeParseURL };
|
package/dist/lib/egg.d.ts
CHANGED
|
@@ -82,6 +82,12 @@ declare class EggApplicationCore extends EggCore {
|
|
|
82
82
|
*/
|
|
83
83
|
Boot: typeof BaseHookClass;
|
|
84
84
|
options: Required<EggApplicationCoreOptions>;
|
|
85
|
+
/**
|
|
86
|
+
* Promise that resolves when the `load()` method has finished.
|
|
87
|
+
* This is useful for callers that need to ensure config and metadata
|
|
88
|
+
* are fully loaded before proceeding.
|
|
89
|
+
*/
|
|
90
|
+
readonly loadFinished: Promise<void>;
|
|
85
91
|
readonly messenger: IMessenger;
|
|
86
92
|
agent?: Agent;
|
|
87
93
|
application?: Application;
|
|
@@ -194,6 +200,13 @@ declare class EggApplicationCore extends EggCore {
|
|
|
194
200
|
createHttpClient(options?: HttpClientOptions): HttpClient;
|
|
195
201
|
/**
|
|
196
202
|
* HttpClient instance
|
|
203
|
+
*
|
|
204
|
+
* Returns a transparent proxy that defers actual HttpClient construction
|
|
205
|
+
* until a method/property is first accessed. This allows plugins to modify
|
|
206
|
+
* `config.httpclient.lookup` or other options during lifecycle hooks
|
|
207
|
+
* (e.g. `configWillLoad`, `didLoad`) even after `app.httpClient` is
|
|
208
|
+
* first referenced.
|
|
209
|
+
*
|
|
197
210
|
* @see https://github.com/node-modules/urllib
|
|
198
211
|
* @member {HttpClient}
|
|
199
212
|
*/
|
|
@@ -231,6 +244,27 @@ declare class EggApplicationCore extends EggCore {
|
|
|
231
244
|
get coreLogger(): EggLogger;
|
|
232
245
|
_unhandledRejectionHandler(err: any): void;
|
|
233
246
|
/**
|
|
247
|
+
* Clean up non-serializable resources before V8 heap serialization.
|
|
248
|
+
* Closes messenger (IPC listeners), logger streams and flush timers
|
|
249
|
+
* (file descriptors), and removes the process-level unhandledRejection
|
|
250
|
+
* listener.
|
|
251
|
+
*
|
|
252
|
+
* The `EggLoggers` instance is intentionally kept (not discarded): plugins
|
|
253
|
+
* such as `@eggjs/schedule` capture individual logger references during the
|
|
254
|
+
* load phase, before serialization. Replacing them with a fresh `EggLoggers`
|
|
255
|
+
* on restore would leave those captured references pointing at closed
|
|
256
|
+
* streams (`... log stream had been closed`). Instead, `snapshotDidDeserialize`
|
|
257
|
+
* reopens these same logger objects in place.
|
|
258
|
+
*/
|
|
259
|
+
protected snapshotWillSerialize(): void;
|
|
260
|
+
/**
|
|
261
|
+
* Restore non-serializable resources after V8 heap deserialization.
|
|
262
|
+
* Recreates messenger, re-registers the egg-ready listener, reopens the
|
|
263
|
+
* logger streams closed during serialize, and re-attaches the process-level
|
|
264
|
+
* unhandledRejection listener.
|
|
265
|
+
*/
|
|
266
|
+
protected snapshotDidDeserialize(): void;
|
|
267
|
+
/**
|
|
234
268
|
* dump out the config and meta object
|
|
235
269
|
* @private
|
|
236
270
|
*/
|
|
@@ -244,6 +278,11 @@ declare class EggApplicationCore extends EggCore {
|
|
|
244
278
|
*/
|
|
245
279
|
dumpConfig(): void;
|
|
246
280
|
dumpTiming(): void;
|
|
281
|
+
/**
|
|
282
|
+
* Generate and save startup manifest for faster subsequent startups.
|
|
283
|
+
* Only generates when no valid manifest was loaded (avoids overwriting during manifest-accelerated starts).
|
|
284
|
+
*/
|
|
285
|
+
dumpManifest(): void;
|
|
247
286
|
protected customEggPaths(): string[];
|
|
248
287
|
get config(): EggAppConfig$1;
|
|
249
288
|
/**
|
package/dist/lib/egg.js
CHANGED
|
@@ -7,9 +7,9 @@ import { ContextHttpClient } from "./core/context_httpclient.js";
|
|
|
7
7
|
import { HttpClient } from "./core/httpclient.js";
|
|
8
8
|
import { createLoggers } from "./core/logger.js";
|
|
9
9
|
import { create } from "./core/messenger/index.js";
|
|
10
|
-
import { convertObject } from "./core/utils.js";
|
|
10
|
+
import { convertObject, createTransparentProxy } from "./core/utils.js";
|
|
11
11
|
import assert from "node:assert";
|
|
12
|
-
import { EggCore, Router, utils } from "@eggjs/core";
|
|
12
|
+
import { EggCore, ManifestStore, Router, utils } from "@eggjs/core";
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import fs from "node:fs";
|
|
15
15
|
import http from "node:http";
|
|
@@ -79,7 +79,16 @@ var EggApplicationCore = class extends EggCore {
|
|
|
79
79
|
Boot = BaseHookClass;
|
|
80
80
|
#httpClient;
|
|
81
81
|
#loggers;
|
|
82
|
+
#startTimeoutTimer;
|
|
82
83
|
#clusterClients = [];
|
|
84
|
+
#loadFinishedResolve;
|
|
85
|
+
#loadFinishedReject;
|
|
86
|
+
/**
|
|
87
|
+
* Promise that resolves when the `load()` method has finished.
|
|
88
|
+
* This is useful for callers that need to ensure config and metadata
|
|
89
|
+
* are fully loaded before proceeding.
|
|
90
|
+
*/
|
|
91
|
+
loadFinished;
|
|
83
92
|
messenger;
|
|
84
93
|
agent;
|
|
85
94
|
application;
|
|
@@ -99,6 +108,10 @@ var EggApplicationCore = class extends EggCore {
|
|
|
99
108
|
...options
|
|
100
109
|
};
|
|
101
110
|
super(options);
|
|
111
|
+
this.loadFinished = new Promise((resolve, reject) => {
|
|
112
|
+
this.#loadFinishedResolve = resolve;
|
|
113
|
+
this.#loadFinishedReject = reject;
|
|
114
|
+
});
|
|
102
115
|
/**
|
|
103
116
|
* messenger instance
|
|
104
117
|
* @member {Messenger}
|
|
@@ -108,8 +121,18 @@ var EggApplicationCore = class extends EggCore {
|
|
|
108
121
|
this.messenger.once("egg-ready", () => {
|
|
109
122
|
this.lifecycle.triggerServerDidReady();
|
|
110
123
|
});
|
|
124
|
+
this.lifecycle.addBootHook({
|
|
125
|
+
snapshotWillSerialize: () => this.snapshotWillSerialize(),
|
|
126
|
+
snapshotDidDeserialize: () => this.snapshotDidDeserialize()
|
|
127
|
+
});
|
|
111
128
|
this.lifecycle.registerBeforeStart(async () => {
|
|
112
|
-
|
|
129
|
+
try {
|
|
130
|
+
await this.load();
|
|
131
|
+
this.#loadFinishedResolve();
|
|
132
|
+
} catch (err) {
|
|
133
|
+
this.#loadFinishedReject(err);
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
113
136
|
}, "load files");
|
|
114
137
|
}
|
|
115
138
|
/**
|
|
@@ -123,27 +146,38 @@ var EggApplicationCore = class extends EggCore {
|
|
|
123
146
|
}
|
|
124
147
|
async load() {
|
|
125
148
|
await this.loadConfig();
|
|
126
|
-
this.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
149
|
+
if (!this.options.snapshot) {
|
|
150
|
+
this.ready(() => process.nextTick(() => {
|
|
151
|
+
const dumpStartTime = Date.now();
|
|
152
|
+
this.dumpConfig();
|
|
153
|
+
this.dumpTiming();
|
|
154
|
+
this.dumpManifest();
|
|
155
|
+
ManifestStore.flushCompileCache();
|
|
156
|
+
this.coreLogger.info("[egg] dump config after ready, %sms", Date.now() - dumpStartTime);
|
|
157
|
+
}));
|
|
158
|
+
this.#setupTimeoutTimer();
|
|
159
|
+
}
|
|
133
160
|
this.console.info("[egg] App root: %s", this.baseDir);
|
|
134
161
|
this.console.info("[egg] All *.log files save on %j", this.config.logger.dir);
|
|
135
162
|
assert(this.config.logger.dir, "logger.dir is required");
|
|
136
163
|
this.console.info("[egg] Loaded enabled plugin %j", this.loader.orderPlugins);
|
|
137
164
|
this._unhandledRejectionHandler = this._unhandledRejectionHandler.bind(this);
|
|
138
165
|
process.on("unhandledRejection", this._unhandledRejectionHandler);
|
|
139
|
-
this.lifecycle.registerBeforeClose(async () => {
|
|
166
|
+
if (!this.lifecycle.registerBeforeClose(async () => {
|
|
140
167
|
for (const clusterClient of this.#clusterClients) await close(clusterClient);
|
|
141
168
|
this.#clusterClients = [];
|
|
142
|
-
if (this.type === "application" && this.options.mode === "single") await this.agent
|
|
169
|
+
if (this.type === "application" && this.options.mode === "single") await this.agent?.close();
|
|
170
|
+
ManifestStore.flushCompileCache();
|
|
143
171
|
for (const logger of this.loggers.values()) logger.close();
|
|
144
172
|
this.messenger.close();
|
|
145
173
|
process.removeListener("unhandledRejection", this._unhandledRejectionHandler);
|
|
146
|
-
})
|
|
174
|
+
})) {
|
|
175
|
+
this.#clearStartTimeoutTimer();
|
|
176
|
+
process.removeListener("unhandledRejection", this._unhandledRejectionHandler);
|
|
177
|
+
this.messenger.close();
|
|
178
|
+
if (this.#loggers) for (const logger of this.#loggers.values()) logger.close();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
147
181
|
await this.loader.load();
|
|
148
182
|
}
|
|
149
183
|
/**
|
|
@@ -282,11 +316,18 @@ var EggApplicationCore = class extends EggCore {
|
|
|
282
316
|
}
|
|
283
317
|
/**
|
|
284
318
|
* HttpClient instance
|
|
319
|
+
*
|
|
320
|
+
* Returns a transparent proxy that defers actual HttpClient construction
|
|
321
|
+
* until a method/property is first accessed. This allows plugins to modify
|
|
322
|
+
* `config.httpclient.lookup` or other options during lifecycle hooks
|
|
323
|
+
* (e.g. `configWillLoad`, `didLoad`) even after `app.httpClient` is
|
|
324
|
+
* first referenced.
|
|
325
|
+
*
|
|
285
326
|
* @see https://github.com/node-modules/urllib
|
|
286
327
|
* @member {HttpClient}
|
|
287
328
|
*/
|
|
288
329
|
get httpClient() {
|
|
289
|
-
if (!this.#httpClient) this.#httpClient = this.createHttpClient();
|
|
330
|
+
if (!this.#httpClient) this.#httpClient = createTransparentProxy({ createReal: () => this.createHttpClient() });
|
|
290
331
|
return this.#httpClient;
|
|
291
332
|
}
|
|
292
333
|
/**
|
|
@@ -346,6 +387,56 @@ var EggApplicationCore = class extends EggCore {
|
|
|
346
387
|
this.coreLogger.error(err);
|
|
347
388
|
}
|
|
348
389
|
/**
|
|
390
|
+
* Clean up non-serializable resources before V8 heap serialization.
|
|
391
|
+
* Closes messenger (IPC listeners), logger streams and flush timers
|
|
392
|
+
* (file descriptors), and removes the process-level unhandledRejection
|
|
393
|
+
* listener.
|
|
394
|
+
*
|
|
395
|
+
* The `EggLoggers` instance is intentionally kept (not discarded): plugins
|
|
396
|
+
* such as `@eggjs/schedule` capture individual logger references during the
|
|
397
|
+
* load phase, before serialization. Replacing them with a fresh `EggLoggers`
|
|
398
|
+
* on restore would leave those captured references pointing at closed
|
|
399
|
+
* streams (`... log stream had been closed`). Instead, `snapshotDidDeserialize`
|
|
400
|
+
* reopens these same logger objects in place.
|
|
401
|
+
*/
|
|
402
|
+
snapshotWillSerialize() {
|
|
403
|
+
this.messenger.close();
|
|
404
|
+
if (this.#loggers) for (const logger of this.#loggers.values()) logger.close();
|
|
405
|
+
process.removeListener("unhandledRejection", this._unhandledRejectionHandler);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Restore non-serializable resources after V8 heap deserialization.
|
|
409
|
+
* Recreates messenger, re-registers the egg-ready listener, reopens the
|
|
410
|
+
* logger streams closed during serialize, and re-attaches the process-level
|
|
411
|
+
* unhandledRejection listener.
|
|
412
|
+
*/
|
|
413
|
+
snapshotDidDeserialize() {
|
|
414
|
+
this.messenger = create(this);
|
|
415
|
+
this.messenger.once("egg-ready", () => {
|
|
416
|
+
this.lifecycle.triggerServerDidReady();
|
|
417
|
+
});
|
|
418
|
+
this.#reopenLoggers();
|
|
419
|
+
process.on("unhandledRejection", this._unhandledRejectionHandler);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Reopen logger resources that `snapshotWillSerialize` released.
|
|
423
|
+
*
|
|
424
|
+
* `transport.reload()` reopens each `FileTransport` stream on the existing
|
|
425
|
+
* logger objects (so references captured before the snapshot keep working).
|
|
426
|
+
* `FileBufferTransport`, however, clears its flush interval in `close()` and
|
|
427
|
+
* does not restart it in `reload()`, so buffered logs would never flush after
|
|
428
|
+
* restore. Restart that interval explicitly to keep the willSerialize /
|
|
429
|
+
* didDeserialize resource pairing complete.
|
|
430
|
+
*/
|
|
431
|
+
#reopenLoggers() {
|
|
432
|
+
if (!this.#loggers) return;
|
|
433
|
+
for (const logger of this.#loggers.values()) for (const transport of logger.values()) {
|
|
434
|
+
transport.reload();
|
|
435
|
+
const bufferTransport = transport;
|
|
436
|
+
if (typeof bufferTransport._createInterval === "function" && !bufferTransport._timer) bufferTransport._timer = bufferTransport._createInterval();
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
349
440
|
* dump out the config and meta object
|
|
350
441
|
* @private
|
|
351
442
|
*/
|
|
@@ -397,11 +488,40 @@ var EggApplicationCore = class extends EggCore {
|
|
|
397
488
|
this.coreLogger.warn(`[egg] dumpTiming error: ${err.message}`);
|
|
398
489
|
}
|
|
399
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Generate and save startup manifest for faster subsequent startups.
|
|
493
|
+
* Only generates when no valid manifest was loaded (avoids overwriting during manifest-accelerated starts).
|
|
494
|
+
*/
|
|
495
|
+
dumpManifest() {
|
|
496
|
+
try {
|
|
497
|
+
if (this.loader.serverEnv === "local" && process.env.EGG_MANIFEST !== "true") return;
|
|
498
|
+
if (this.loader.manifest.data.generatedAt) return;
|
|
499
|
+
const manifest = this.loader.generateManifest();
|
|
500
|
+
ManifestStore.enableCompileCache(this.baseDir);
|
|
501
|
+
ManifestStore.write(this.baseDir, manifest).catch((err) => {
|
|
502
|
+
this.coreLogger.warn("[egg] dumpManifest write error: %s", err.message);
|
|
503
|
+
});
|
|
504
|
+
} catch (err) {
|
|
505
|
+
this.coreLogger.warn("[egg] dumpManifest error: %s", err.message);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
400
508
|
customEggPaths() {
|
|
509
|
+
const bundleStore = ManifestStore.getBundleStore();
|
|
510
|
+
if (bundleStore && path.resolve(bundleStore.baseDir) === path.resolve(this.baseDir)) {
|
|
511
|
+
const bundledFrameworkDir = path.join(bundleStore.baseDir, "node_modules", "egg", "dist");
|
|
512
|
+
const importMetaRewritten = !!import.meta.dirname && path.resolve(import.meta.dirname) === path.resolve(bundleStore.baseDir);
|
|
513
|
+
if (fs.existsSync(bundledFrameworkDir) || importMetaRewritten) return [bundledFrameworkDir, ...super.customEggPaths()];
|
|
514
|
+
}
|
|
401
515
|
return [path.dirname(import.meta.dirname), ...super.customEggPaths()];
|
|
402
516
|
}
|
|
517
|
+
#clearStartTimeoutTimer() {
|
|
518
|
+
if (this.#startTimeoutTimer) {
|
|
519
|
+
clearTimeout(this.#startTimeoutTimer);
|
|
520
|
+
this.#startTimeoutTimer = void 0;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
403
523
|
#setupTimeoutTimer() {
|
|
404
|
-
|
|
524
|
+
this.#startTimeoutTimer = setTimeout(() => {
|
|
405
525
|
this.coreLogger.error(this.timing.toString());
|
|
406
526
|
this.coreLogger.error(`${this.type} still doesn't ready after ${this.config.workerStartTimeout} ms.`);
|
|
407
527
|
const items = this.timing.toJSON();
|
|
@@ -414,7 +534,7 @@ var EggApplicationCore = class extends EggCore {
|
|
|
414
534
|
this.dumpConfig();
|
|
415
535
|
this.dumpTiming();
|
|
416
536
|
}, this.config.workerStartTimeout);
|
|
417
|
-
this.ready(() =>
|
|
537
|
+
this.ready(() => this.#clearStartTimeoutTimer());
|
|
418
538
|
}
|
|
419
539
|
get config() {
|
|
420
540
|
return super.config;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Application } from "./application.js";
|
|
2
|
+
import { StartEggOptions } from "./start.js";
|
|
3
|
+
|
|
4
|
+
//#region src/lib/snapshot.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Build a V8 startup snapshot of an egg application.
|
|
8
|
+
*
|
|
9
|
+
* Call this from the snapshot entry script passed to
|
|
10
|
+
* `node --snapshot-blob=snapshot.blob --build-snapshot snapshot_entry.js`.
|
|
11
|
+
*
|
|
12
|
+
* It loads all metadata (plugins, configs, extensions, services, controllers,
|
|
13
|
+
* router, tegg modules), triggers snapshotWillSerialize hooks to clean up
|
|
14
|
+
* non-serializable resources (file handles, timers, process listeners),
|
|
15
|
+
* then registers a V8 deserialize callback to stash the app for later restore.
|
|
16
|
+
*
|
|
17
|
+
* Example snapshot entry script:
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { buildSnapshot } from 'egg';
|
|
20
|
+
* await buildSnapshot({ baseDir: __dirname });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Example restoring from snapshot:
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { restoreSnapshot } from 'egg';
|
|
26
|
+
* const app = await restoreSnapshot();
|
|
27
|
+
* // app is fully restored with resources recreated, ready for server creation
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function buildSnapshot(options?: Pick<StartEggOptions, "framework" | "baseDir" | "env" | "plugins">): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Restore an egg application from a V8 startup snapshot.
|
|
33
|
+
*
|
|
34
|
+
* Triggers the snapshotDidDeserialize lifecycle hooks to recreate
|
|
35
|
+
* non-serializable resources (messenger, loggers, process listeners)
|
|
36
|
+
* and resumes the lifecycle from configDidLoad through didReady.
|
|
37
|
+
*
|
|
38
|
+
* Returns the fully restored Application instance with all metadata
|
|
39
|
+
* pre-loaded (plugins, configs, extensions, services, controllers, router).
|
|
40
|
+
*/
|
|
41
|
+
declare function restoreSnapshot(): Promise<Application>;
|
|
42
|
+
declare global {
|
|
43
|
+
var __egg_snapshot_app: unknown;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { buildSnapshot, restoreSnapshot };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { startEgg } from "./start.js";
|
|
2
|
+
import v8 from "node:v8";
|
|
3
|
+
|
|
4
|
+
//#region src/lib/snapshot.ts
|
|
5
|
+
/**
|
|
6
|
+
* Build a V8 startup snapshot of an egg application.
|
|
7
|
+
*
|
|
8
|
+
* Call this from the snapshot entry script passed to
|
|
9
|
+
* `node --snapshot-blob=snapshot.blob --build-snapshot snapshot_entry.js`.
|
|
10
|
+
*
|
|
11
|
+
* It loads all metadata (plugins, configs, extensions, services, controllers,
|
|
12
|
+
* router, tegg modules), triggers snapshotWillSerialize hooks to clean up
|
|
13
|
+
* non-serializable resources (file handles, timers, process listeners),
|
|
14
|
+
* then registers a V8 deserialize callback to stash the app for later restore.
|
|
15
|
+
*
|
|
16
|
+
* Example snapshot entry script:
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { buildSnapshot } from 'egg';
|
|
19
|
+
* await buildSnapshot({ baseDir: __dirname });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Example restoring from snapshot:
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { restoreSnapshot } from 'egg';
|
|
25
|
+
* const app = await restoreSnapshot();
|
|
26
|
+
* // app is fully restored with resources recreated, ready for server creation
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
async function buildSnapshot(options = {}) {
|
|
30
|
+
const app = await startEgg({
|
|
31
|
+
...options,
|
|
32
|
+
snapshot: true
|
|
33
|
+
});
|
|
34
|
+
if (app.agent) await app.agent.triggerSnapshotWillSerialize();
|
|
35
|
+
await app.triggerSnapshotWillSerialize();
|
|
36
|
+
v8.startupSnapshot.setDeserializeMainFunction((snapshotData) => {
|
|
37
|
+
globalThis.__egg_snapshot_app = snapshotData.app;
|
|
38
|
+
}, { app });
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Restore an egg application from a V8 startup snapshot.
|
|
42
|
+
*
|
|
43
|
+
* Triggers the snapshotDidDeserialize lifecycle hooks to recreate
|
|
44
|
+
* non-serializable resources (messenger, loggers, process listeners)
|
|
45
|
+
* and resumes the lifecycle from configDidLoad through didReady.
|
|
46
|
+
*
|
|
47
|
+
* Returns the fully restored Application instance with all metadata
|
|
48
|
+
* pre-loaded (plugins, configs, extensions, services, controllers, router).
|
|
49
|
+
*/
|
|
50
|
+
async function restoreSnapshot() {
|
|
51
|
+
const app = globalThis.__egg_snapshot_app;
|
|
52
|
+
if (!app) throw new Error("No egg application found in snapshot. Ensure the process was started from a snapshot built with buildSnapshot().");
|
|
53
|
+
if (app.agent) await app.agent.triggerSnapshotDidDeserialize();
|
|
54
|
+
await app.triggerSnapshotDidDeserialize();
|
|
55
|
+
return app;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { buildSnapshot, restoreSnapshot };
|
package/dist/lib/start.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EggPlugin } from "./types.js";
|
|
2
2
|
import { Agent } from "./agent.js";
|
|
3
3
|
import { Application } from "./application.js";
|
|
4
|
+
import { LoaderFS } from "@eggjs/core";
|
|
4
5
|
|
|
5
6
|
//#region src/lib/start.d.ts
|
|
6
7
|
interface StartEggOptions {
|
|
@@ -13,6 +14,16 @@ interface StartEggOptions {
|
|
|
13
14
|
mode?: "single";
|
|
14
15
|
env?: string;
|
|
15
16
|
plugins?: EggPlugin;
|
|
17
|
+
/** Skip lifecycle hooks, only trigger loadMetadata for manifest generation */
|
|
18
|
+
metadataOnly?: boolean;
|
|
19
|
+
/** Loader-facing filesystem abstraction */
|
|
20
|
+
loaderFS?: LoaderFS;
|
|
21
|
+
/**
|
|
22
|
+
* When true, load application metadata for V8 startup snapshot construction.
|
|
23
|
+
* The lifecycle stops after configWillLoad (no servers, timers, or connections)
|
|
24
|
+
* and skips `egg-ready` broadcast. `ready()` resolves when loading completes.
|
|
25
|
+
*/
|
|
26
|
+
snapshot?: boolean;
|
|
16
27
|
}
|
|
17
28
|
interface SingleModeApplication extends Application {
|
|
18
29
|
agent: SingleModeAgent;
|
|
@@ -21,7 +32,11 @@ interface SingleModeAgent extends Agent {
|
|
|
21
32
|
app: SingleModeApplication;
|
|
22
33
|
}
|
|
23
34
|
/**
|
|
24
|
-
* Start egg with single process
|
|
35
|
+
* Start egg with single process.
|
|
36
|
+
*
|
|
37
|
+
* When `options.snapshot` is true, loads application metadata for V8 startup
|
|
38
|
+
* snapshot construction. The lifecycle stops after `configWillLoad` (no servers,
|
|
39
|
+
* timers, or connections) and skips `egg-ready` broadcast.
|
|
25
40
|
*/
|
|
26
41
|
declare function startEgg(options?: StartEggOptions): Promise<SingleModeApplication>;
|
|
27
42
|
//#endregion
|
package/dist/lib/start.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { Agent } from "./agent.js";
|
|
2
2
|
import { Application } from "./application.js";
|
|
3
3
|
import "./types.js";
|
|
4
|
+
import { ManifestStore } from "@eggjs/core";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { importModule } from "@eggjs/utils";
|
|
6
7
|
import { readJSON } from "utility";
|
|
7
8
|
|
|
8
9
|
//#region src/lib/start.ts
|
|
9
|
-
|
|
10
|
-
* Start egg with single process
|
|
11
|
-
*/
|
|
12
|
-
async function startEgg(options = {}) {
|
|
13
|
-
options.baseDir = options.baseDir ?? process.cwd();
|
|
14
|
-
options.mode = "single";
|
|
10
|
+
async function resolveFrameworkClasses(options) {
|
|
15
11
|
if (!options.framework) try {
|
|
16
12
|
options.framework = (await readJSON(path.join(options.baseDir, "package.json"))).egg.framework;
|
|
17
13
|
} catch {}
|
|
@@ -22,13 +18,35 @@ async function startEgg(options = {}) {
|
|
|
22
18
|
AgentClass = framework.Agent;
|
|
23
19
|
ApplicationClass = framework.Application;
|
|
24
20
|
}
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
return {
|
|
22
|
+
AgentClass,
|
|
23
|
+
ApplicationClass
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Start egg with single process.
|
|
28
|
+
*
|
|
29
|
+
* When `options.snapshot` is true, loads application metadata for V8 startup
|
|
30
|
+
* snapshot construction. The lifecycle stops after `configWillLoad` (no servers,
|
|
31
|
+
* timers, or connections) and skips `egg-ready` broadcast.
|
|
32
|
+
*/
|
|
33
|
+
async function startEgg(options = {}) {
|
|
34
|
+
options.baseDir = options.baseDir ?? process.cwd();
|
|
35
|
+
options.mode = "single";
|
|
36
|
+
if (!options.snapshot) ManifestStore.enableCompileCache(options.baseDir);
|
|
37
|
+
const { AgentClass, ApplicationClass } = await resolveFrameworkClasses(options);
|
|
38
|
+
let agent;
|
|
39
|
+
if (!options.metadataOnly) {
|
|
40
|
+
agent = new AgentClass({ ...options });
|
|
41
|
+
await agent.ready();
|
|
42
|
+
}
|
|
27
43
|
const application = new ApplicationClass({ ...options });
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
if (agent) {
|
|
45
|
+
application.agent = agent;
|
|
46
|
+
agent.application = application;
|
|
47
|
+
}
|
|
30
48
|
await application.ready();
|
|
31
|
-
application.messenger.broadcast("egg-ready");
|
|
49
|
+
if (!options.metadataOnly && !options.snapshot) application.messenger.broadcast("egg-ready");
|
|
32
50
|
return application;
|
|
33
51
|
}
|
|
34
52
|
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import "./egg.js";
|
|
|
7
7
|
import { Application } from "./application.js";
|
|
8
8
|
import { EggAppConfig as EggAppConfig$1, EggAppInfo, FileLoaderOptions } from "@eggjs/core";
|
|
9
9
|
import { EggLoggerOptions, EggLoggersOptions } from "egg-logger";
|
|
10
|
-
import { RequestOptions } from "urllib";
|
|
10
|
+
import { Dispatcher, RequestOptions } from "urllib";
|
|
11
11
|
import { LookupFunction, Socket } from "node:net";
|
|
12
12
|
import { PartialDeep } from "type-fest";
|
|
13
13
|
|
|
@@ -61,6 +61,24 @@ interface HttpClientConfig {
|
|
|
61
61
|
*/
|
|
62
62
|
allowH2?: boolean;
|
|
63
63
|
lookup?: LookupFunction;
|
|
64
|
+
/**
|
|
65
|
+
* Interceptors for request composition, applied via `Dispatcher.compose()`.
|
|
66
|
+
* Each interceptor receives a `dispatch` function and returns a new `dispatch` function.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* // config.default.ts
|
|
71
|
+
* config.httpclient = {
|
|
72
|
+
* interceptors: [
|
|
73
|
+
* (dispatch) => (opts, handler) => {
|
|
74
|
+
* opts.headers = { ...opts.headers, 'x-trace-id': generateTraceId() };
|
|
75
|
+
* return dispatch(opts, handler);
|
|
76
|
+
* },
|
|
77
|
+
* ],
|
|
78
|
+
* };
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
interceptors?: Dispatcher.DispatcherComposeInterceptor[];
|
|
64
82
|
}
|
|
65
83
|
/**
|
|
66
84
|
* Powerful Partial, Support adding ? modifier to a mapped property in deep level
|
|
@@ -73,6 +91,7 @@ interface HttpClientConfig {
|
|
|
73
91
|
* @deprecated use `PartialDeep` instead
|
|
74
92
|
*/
|
|
75
93
|
type PowerPartial<T> = PartialDeep<T>;
|
|
94
|
+
declare const EggAppConfig: ObjectConstructor;
|
|
76
95
|
interface EggAppConfig extends EggAppConfig$1 {
|
|
77
96
|
workerStartTimeout: number;
|
|
78
97
|
baseDir: string;
|
package/dist/lib/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "egg",
|
|
3
|
-
"version": "4.1.2-beta.
|
|
3
|
+
"version": "4.1.2-beta.20",
|
|
4
4
|
"description": "A web application framework for Node.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"./lib/loader/AgentWorkerLoader": "./dist/lib/loader/AgentWorkerLoader.js",
|
|
71
71
|
"./lib/loader/AppWorkerLoader": "./dist/lib/loader/AppWorkerLoader.js",
|
|
72
72
|
"./lib/loader/EggApplicationLoader": "./dist/lib/loader/EggApplicationLoader.js",
|
|
73
|
+
"./lib/snapshot": "./dist/lib/snapshot.js",
|
|
73
74
|
"./lib/start": "./dist/lib/start.js",
|
|
74
75
|
"./lib/types": "./dist/lib/types.js",
|
|
75
76
|
"./lib/types.plugin": "./dist/lib/types.plugin.js",
|
|
@@ -81,9 +82,94 @@
|
|
|
81
82
|
},
|
|
82
83
|
"publishConfig": {
|
|
83
84
|
"access": "public",
|
|
85
|
+
"exports": {
|
|
86
|
+
".": "./dist/index.js",
|
|
87
|
+
"./agent": "./dist/agent.js",
|
|
88
|
+
"./ajv": "./dist/ajv.js",
|
|
89
|
+
"./aop": "./dist/aop.js",
|
|
90
|
+
"./app/extend/context": "./dist/app/extend/context.js",
|
|
91
|
+
"./app/extend/helper": "./dist/app/extend/helper.js",
|
|
92
|
+
"./app/extend/request": "./dist/app/extend/request.js",
|
|
93
|
+
"./app/extend/response": "./dist/app/extend/response.js",
|
|
94
|
+
"./app/middleware/body_parser": "./dist/app/middleware/body_parser.js",
|
|
95
|
+
"./app/middleware/meta": "./dist/app/middleware/meta.js",
|
|
96
|
+
"./app/middleware/notfound": "./dist/app/middleware/notfound.js",
|
|
97
|
+
"./app/middleware/override_method": "./dist/app/middleware/override_method.js",
|
|
98
|
+
"./app/middleware/site_file": "./dist/app/middleware/site_file.js",
|
|
99
|
+
"./config/config.default": "./dist/config/config.default.js",
|
|
100
|
+
"./config/config.local": "./dist/config/config.local.js",
|
|
101
|
+
"./config/config.unittest": "./dist/config/config.unittest.js",
|
|
102
|
+
"./config/plugin": "./dist/config/plugin.js",
|
|
103
|
+
"./dal": "./dist/dal.js",
|
|
104
|
+
"./errors": "./dist/errors.js",
|
|
105
|
+
"./helper": "./dist/helper.js",
|
|
106
|
+
"./lib/agent": "./dist/lib/agent.js",
|
|
107
|
+
"./lib/application": "./dist/lib/application.js",
|
|
108
|
+
"./lib/core/base_context_class": "./dist/lib/core/base_context_class.js",
|
|
109
|
+
"./lib/core/base_context_logger": "./dist/lib/core/base_context_logger.js",
|
|
110
|
+
"./lib/core/base_hook_class": "./dist/lib/core/base_hook_class.js",
|
|
111
|
+
"./lib/core/context_httpclient": "./dist/lib/core/context_httpclient.js",
|
|
112
|
+
"./lib/core/httpclient": "./dist/lib/core/httpclient.js",
|
|
113
|
+
"./lib/core/logger": "./dist/lib/core/logger.js",
|
|
114
|
+
"./lib/core/messenger": "./dist/lib/core/messenger/index.js",
|
|
115
|
+
"./lib/core/messenger/base": "./dist/lib/core/messenger/base.js",
|
|
116
|
+
"./lib/core/messenger/IMessenger": "./dist/lib/core/messenger/IMessenger.js",
|
|
117
|
+
"./lib/core/messenger/ipc": "./dist/lib/core/messenger/ipc.js",
|
|
118
|
+
"./lib/core/messenger/local": "./dist/lib/core/messenger/local.js",
|
|
119
|
+
"./lib/core/utils": "./dist/lib/core/utils.js",
|
|
120
|
+
"./lib/define": "./dist/lib/define.js",
|
|
121
|
+
"./lib/egg": "./dist/lib/egg.js",
|
|
122
|
+
"./lib/error": "./dist/lib/error/index.js",
|
|
123
|
+
"./lib/error/CookieLimitExceedError": "./dist/lib/error/CookieLimitExceedError.js",
|
|
124
|
+
"./lib/error/MessageUnhandledRejectionError": "./dist/lib/error/MessageUnhandledRejectionError.js",
|
|
125
|
+
"./lib/loader": "./dist/lib/loader/index.js",
|
|
126
|
+
"./lib/loader/AgentWorkerLoader": "./dist/lib/loader/AgentWorkerLoader.js",
|
|
127
|
+
"./lib/loader/AppWorkerLoader": "./dist/lib/loader/AppWorkerLoader.js",
|
|
128
|
+
"./lib/loader/EggApplicationLoader": "./dist/lib/loader/EggApplicationLoader.js",
|
|
129
|
+
"./lib/snapshot": "./dist/lib/snapshot.js",
|
|
130
|
+
"./lib/start": "./dist/lib/start.js",
|
|
131
|
+
"./lib/types": "./dist/lib/types.js",
|
|
132
|
+
"./lib/types.plugin": "./dist/lib/types.plugin.js",
|
|
133
|
+
"./orm": "./dist/orm.js",
|
|
134
|
+
"./schedule": "./dist/schedule.js",
|
|
135
|
+
"./transaction": "./dist/transaction.js",
|
|
136
|
+
"./urllib": "./dist/urllib.js",
|
|
137
|
+
"./package.json": "./package.json"
|
|
138
|
+
},
|
|
84
139
|
"tag": "beta"
|
|
85
140
|
},
|
|
141
|
+
"scripts": {
|
|
142
|
+
"typecheck": "tsgo --noEmit"
|
|
143
|
+
},
|
|
86
144
|
"dependencies": {
|
|
145
|
+
"@eggjs/ajv-plugin": "4.0.2-beta.20",
|
|
146
|
+
"@eggjs/aop-plugin": "4.0.2-beta.20",
|
|
147
|
+
"@eggjs/cluster": "4.0.2-beta.20",
|
|
148
|
+
"@eggjs/controller-plugin": "4.0.2-beta.20",
|
|
149
|
+
"@eggjs/cookies": "4.0.2-beta.20",
|
|
150
|
+
"@eggjs/core": "7.0.2-beta.20",
|
|
151
|
+
"@eggjs/dal-plugin": "4.0.2-beta.20",
|
|
152
|
+
"@eggjs/development": "5.0.2-beta.20",
|
|
153
|
+
"@eggjs/errors": "3.0.2-beta.20",
|
|
154
|
+
"@eggjs/eventbus-plugin": "4.0.2-beta.20",
|
|
155
|
+
"@eggjs/extend2": "5.0.2-beta.20",
|
|
156
|
+
"@eggjs/i18n": "4.0.2-beta.20",
|
|
157
|
+
"@eggjs/jsonp": "4.0.2-beta.20",
|
|
158
|
+
"@eggjs/logrotator": "5.0.2-beta.20",
|
|
159
|
+
"@eggjs/multipart": "5.0.2-beta.20",
|
|
160
|
+
"@eggjs/onerror": "4.0.2-beta.20",
|
|
161
|
+
"@eggjs/orm-plugin": "4.0.2-beta.20",
|
|
162
|
+
"@eggjs/schedule": "6.0.2-beta.20",
|
|
163
|
+
"@eggjs/schedule-plugin": "4.0.2-beta.20",
|
|
164
|
+
"@eggjs/security": "5.0.2-beta.20",
|
|
165
|
+
"@eggjs/session": "5.0.2-beta.20",
|
|
166
|
+
"@eggjs/static": "4.0.2-beta.20",
|
|
167
|
+
"@eggjs/tegg": "4.0.2-beta.20",
|
|
168
|
+
"@eggjs/tegg-config": "4.0.2-beta.20",
|
|
169
|
+
"@eggjs/tegg-plugin": "4.0.2-beta.20",
|
|
170
|
+
"@eggjs/utils": "5.0.2-beta.20",
|
|
171
|
+
"@eggjs/view": "4.0.2-beta.20",
|
|
172
|
+
"@eggjs/watcher": "5.0.2-beta.20",
|
|
87
173
|
"circular-json-for-egg": "^1.0.0",
|
|
88
174
|
"cluster-client": "^3.7.0",
|
|
89
175
|
"egg-logger": "^3.5.0",
|
|
@@ -97,37 +183,13 @@
|
|
|
97
183
|
"sendmessage": "^3.0.1",
|
|
98
184
|
"type-fest": "^5.0.1",
|
|
99
185
|
"urllib": "^4.8.2",
|
|
100
|
-
"utility": "^2.5.0"
|
|
101
|
-
"@eggjs/ajv-plugin": "4.0.2-beta.2",
|
|
102
|
-
"@eggjs/cluster": "4.0.2-beta.2",
|
|
103
|
-
"@eggjs/aop-plugin": "4.0.2-beta.2",
|
|
104
|
-
"@eggjs/controller-plugin": "4.0.2-beta.2",
|
|
105
|
-
"@eggjs/core": "7.0.2-beta.2",
|
|
106
|
-
"@eggjs/cookies": "4.0.2-beta.2",
|
|
107
|
-
"@eggjs/dal-plugin": "4.0.2-beta.2",
|
|
108
|
-
"@eggjs/development": "5.0.2-beta.2",
|
|
109
|
-
"@eggjs/errors": "3.0.2-beta.2",
|
|
110
|
-
"@eggjs/eventbus-plugin": "4.0.2-beta.2",
|
|
111
|
-
"@eggjs/i18n": "4.0.2-beta.2",
|
|
112
|
-
"@eggjs/extend2": "5.0.2-beta.2",
|
|
113
|
-
"@eggjs/jsonp": "4.0.2-beta.2",
|
|
114
|
-
"@eggjs/logrotator": "5.0.2-beta.2",
|
|
115
|
-
"@eggjs/multipart": "5.0.2-beta.2",
|
|
116
|
-
"@eggjs/onerror": "4.0.2-beta.2",
|
|
117
|
-
"@eggjs/orm-plugin": "4.0.2-beta.2",
|
|
118
|
-
"@eggjs/schedule": "6.0.2-beta.2",
|
|
119
|
-
"@eggjs/schedule-plugin": "4.0.2-beta.2",
|
|
120
|
-
"@eggjs/security": "5.0.2-beta.2",
|
|
121
|
-
"@eggjs/session": "5.0.2-beta.2",
|
|
122
|
-
"@eggjs/static": "4.0.2-beta.2",
|
|
123
|
-
"@eggjs/tegg-config": "4.0.2-beta.2",
|
|
124
|
-
"@eggjs/tegg-plugin": "4.0.2-beta.2",
|
|
125
|
-
"@eggjs/utils": "5.0.2-beta.2",
|
|
126
|
-
"@eggjs/view": "4.0.2-beta.2",
|
|
127
|
-
"@eggjs/tegg": "4.0.2-beta.2",
|
|
128
|
-
"@eggjs/watcher": "5.0.2-beta.2"
|
|
186
|
+
"utility": "^2.5.0"
|
|
129
187
|
},
|
|
130
188
|
"devDependencies": {
|
|
189
|
+
"@eggjs/koa": "3.1.2-beta.20",
|
|
190
|
+
"@eggjs/mock": "7.0.2-beta.20",
|
|
191
|
+
"@eggjs/supertest": "9.0.2-beta.20",
|
|
192
|
+
"@eggjs/tracer": "4.0.2-beta.20",
|
|
131
193
|
"@types/koa-bodyparser": "^4.3.12",
|
|
132
194
|
"address": "2",
|
|
133
195
|
"assert-file": "1",
|
|
@@ -140,19 +202,12 @@
|
|
|
140
202
|
"runscript": "^2.0.1",
|
|
141
203
|
"sdk-base": "^5.0.1",
|
|
142
204
|
"spy": "^1.0.0",
|
|
143
|
-
"typescript": "^5.9.3"
|
|
144
|
-
"@eggjs/koa": "3.1.2-beta.2",
|
|
145
|
-
"@eggjs/supertest": "9.0.2-beta.2",
|
|
146
|
-
"@eggjs/tracer": "4.0.2-beta.2",
|
|
147
|
-
"@eggjs/mock": "7.0.2-beta.2"
|
|
205
|
+
"typescript": "^5.9.3"
|
|
148
206
|
},
|
|
149
207
|
"engines": {
|
|
150
208
|
"node": ">=22.18.0"
|
|
151
209
|
},
|
|
152
210
|
"egg": {
|
|
153
211
|
"framework": true
|
|
154
|
-
},
|
|
155
|
-
"scripts": {
|
|
156
|
-
"typecheck": "tsgo --noEmit"
|
|
157
212
|
}
|
|
158
|
-
}
|
|
213
|
+
}
|