evaengine 0.11.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai/analysis.md +657 -0
- package/.ai/architecture/runtime.md +504 -0
- package/.ai/contracts/public-api.md +447 -0
- package/.ai/external-project-guide.md +248 -0
- package/.ai/vision.md +314 -0
- package/README.md +51 -62
- package/bin/engine +15 -21
- package/index.js +2 -18
- package/package.json +60 -64
- package/src/index.js +57 -0
- package/bin/engine-babel +0 -38
- package/lib/commands/index.js +0 -25
- package/lib/commands/index.js.map +0 -1
- package/lib/commands/interface.js +0 -51
- package/lib/commands/interface.js.map +0 -1
- package/lib/commands/make_entity.js +0 -549
- package/lib/commands/make_entity.js.map +0 -1
- package/lib/commands/tramp.js +0 -53
- package/lib/commands/tramp.js.map +0 -1
- package/lib/config/index.js +0 -98
- package/lib/config/index.js.map +0 -1
- package/lib/di.js +0 -99
- package/lib/di.js.map +0 -1
- package/lib/engine.js +0 -558
- package/lib/engine.js.map +0 -1
- package/lib/entities/index.js +0 -283
- package/lib/entities/index.js.map +0 -1
- package/lib/exceptions/index.js +0 -522
- package/lib/exceptions/index.js.map +0 -1
- package/lib/index.js +0 -105
- package/lib/index.js.map +0 -1
- package/lib/middlewares/auth.js +0 -97
- package/lib/middlewares/auth.js.map +0 -1
- package/lib/middlewares/auth_kong.js +0 -48
- package/lib/middlewares/auth_kong.js.map +0 -1
- package/lib/middlewares/debug.js +0 -68
- package/lib/middlewares/debug.js.map +0 -1
- package/lib/middlewares/index.js +0 -45
- package/lib/middlewares/index.js.map +0 -1
- package/lib/middlewares/providers.js +0 -102
- package/lib/middlewares/providers.js.map +0 -1
- package/lib/middlewares/session.js +0 -76
- package/lib/middlewares/session.js.map +0 -1
- package/lib/middlewares/trace.js +0 -241
- package/lib/middlewares/trace.js.map +0 -1
- package/lib/middlewares/validator.js +0 -71
- package/lib/middlewares/validator.js.map +0 -1
- package/lib/middlewares/view_cache.js +0 -160
- package/lib/middlewares/view_cache.js.map +0 -1
- package/lib/services/cache.js +0 -234
- package/lib/services/cache.js.map +0 -1
- package/lib/services/config.js +0 -140
- package/lib/services/config.js.map +0 -1
- package/lib/services/env.js +0 -40
- package/lib/services/env.js.map +0 -1
- package/lib/services/event_manager.js +0 -110
- package/lib/services/event_manager.js.map +0 -1
- package/lib/services/http_client.js +0 -178
- package/lib/services/http_client.js.map +0 -1
- package/lib/services/index.js +0 -70
- package/lib/services/index.js.map +0 -1
- package/lib/services/interface.js +0 -12
- package/lib/services/interface.js.map +0 -1
- package/lib/services/joi.js +0 -28
- package/lib/services/joi.js.map +0 -1
- package/lib/services/jwt_token.js +0 -120
- package/lib/services/jwt_token.js.map +0 -1
- package/lib/services/jwt_token_kong.js +0 -111
- package/lib/services/jwt_token_kong.js.map +0 -1
- package/lib/services/logger.js +0 -172
- package/lib/services/logger.js.map +0 -1
- package/lib/services/namespace.js +0 -188
- package/lib/services/namespace.js.map +0 -1
- package/lib/services/now.js +0 -69
- package/lib/services/now.js.map +0 -1
- package/lib/services/providers.js +0 -195
- package/lib/services/providers.js.map +0 -1
- package/lib/services/redis.js +0 -77
- package/lib/services/redis.js.map +0 -1
- package/lib/services/rest_client.js +0 -136
- package/lib/services/rest_client.js.map +0 -1
- package/lib/swagger/index.js +0 -684
- package/lib/swagger/index.js.map +0 -1
- package/lib/utils/api_scaffold.js +0 -253
- package/lib/utils/api_scaffold.js.map +0 -1
- package/lib/utils/case_converter.js +0 -48
- package/lib/utils/case_converter.js.map +0 -1
- package/lib/utils/crc32.js +0 -22
- package/lib/utils/crc32.js.map +0 -1
- package/lib/utils/datetime.js +0 -21
- package/lib/utils/datetime.js.map +0 -1
- package/lib/utils/host.js +0 -48
- package/lib/utils/host.js.map +0 -1
- package/lib/utils/index.js +0 -61
- package/lib/utils/index.js.map +0 -1
- package/lib/utils/pagination.js +0 -269
- package/lib/utils/pagination.js.map +0 -1
- package/lib/utils/random.js +0 -33
- package/lib/utils/random.js.map +0 -1
- package/lib/utils/smart_query.js +0 -342
- package/lib/utils/smart_query.js.map +0 -1
- package/lib/utils/test.js +0 -62
- package/lib/utils/test.js.map +0 -1
- package/lib/utils/wrapper.js +0 -9
- package/lib/utils/wrapper.js.map +0 -1
package/.ai/analysis.md
ADDED
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
# EvaEngine Architecture Analysis
|
|
2
|
+
|
|
3
|
+
**分析版本**: 2026
|
|
4
|
+
**项目**: EvaEngine.js
|
|
5
|
+
**定位**: Node.js application runtime framework
|
|
6
|
+
|
|
7
|
+
## 1. Executive Summary
|
|
8
|
+
|
|
9
|
+
EvaEngine 的核心目标不是单纯封装 Express,而是为复杂 Node.js 应用提供一个可持续演化的运行时骨架。
|
|
10
|
+
|
|
11
|
+
它把应用启动、配置、依赖注入、基础设施服务、HTTP middleware、CLI command、Entity/ORM、事件与文档生成组织在同一个 Runtime 中。
|
|
12
|
+
|
|
13
|
+
核心思想可以概括为:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
Application
|
|
17
|
+
-> Runtime / Engine
|
|
18
|
+
-> Provider registration
|
|
19
|
+
-> DI Container
|
|
20
|
+
-> Service / Middleware / Command
|
|
21
|
+
-> Domain and persistence capability
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
项目当前属于 **application runtime framework**,而不是纯 HTTP framework。
|
|
25
|
+
|
|
26
|
+
它解决的是:
|
|
27
|
+
|
|
28
|
+
- 如何统一 Web、CLI、Cron 等不同入口。
|
|
29
|
+
- 如何集中管理基础设施能力及其生命周期。
|
|
30
|
+
- 如何让服务可以替换、mock 和按配置选择实现。
|
|
31
|
+
- 如何自动发现 Entity、Command、Swagger metadata 等应用组件。
|
|
32
|
+
- 如何避免业务代码直接依赖 Redis、Logger、Config、JWT、HTTP client 等基础设施。
|
|
33
|
+
|
|
34
|
+
当前代码仍带有明显的 2018 年 Node 生态特征,例如全局 DI、模块级状态、ORM 与 Domain 耦合、旧式 request/later 依赖以及部分静态 metadata 处理。但其 Runtime、Provider、Metadata、Command/Event 方向仍然适合后续 Aurora Runtime 设计。
|
|
35
|
+
|
|
36
|
+
## 2. Core Goals
|
|
37
|
+
|
|
38
|
+
### 2.1 Unified Application Runtime
|
|
39
|
+
|
|
40
|
+
`EvaEngine` 是应用运行时的中心对象。它持有应用元数据、运行模式、命令注册表、HTTP server、Cron handler 和默认错误处理器。
|
|
41
|
+
|
|
42
|
+
支持的运行模式主要包括:
|
|
43
|
+
|
|
44
|
+
- Web/HTTP
|
|
45
|
+
- CLI
|
|
46
|
+
- Cron command
|
|
47
|
+
- HTTPS server
|
|
48
|
+
- Background-like command execution
|
|
49
|
+
|
|
50
|
+
这些入口都通过同一个 Engine 和同一套 DI/Provider 机制进入应用。
|
|
51
|
+
|
|
52
|
+
### 2.2 Capability-Oriented Infrastructure
|
|
53
|
+
|
|
54
|
+
基础设施被包装为可注入的 capability,例如:
|
|
55
|
+
|
|
56
|
+
- `Config`
|
|
57
|
+
- `Env`
|
|
58
|
+
- `Logger`
|
|
59
|
+
- `Redis`
|
|
60
|
+
- `Cache`
|
|
61
|
+
- `HttpClient`
|
|
62
|
+
- `RestClient`
|
|
63
|
+
- `JsonWebToken`
|
|
64
|
+
- `Namespace`
|
|
65
|
+
- `Now`
|
|
66
|
+
- `EventManager`
|
|
67
|
+
- `ValidatorBase`
|
|
68
|
+
|
|
69
|
+
业务或 middleware 不应该自行创建这些对象,而应通过 DI 获取 Provider 注册的服务。
|
|
70
|
+
|
|
71
|
+
### 2.3 Convention and Metadata Driven Application
|
|
72
|
+
|
|
73
|
+
EvaEngine 使用约定、扫描和 metadata 生成应用结构:
|
|
74
|
+
|
|
75
|
+
- Command 有静态 `getName()`、`getDescription()`、`getSpec()`。
|
|
76
|
+
- Entity 从目录扫描并注册到 Entity registry。
|
|
77
|
+
- Swagger 从 source files、注释、异常和 Sequelize model 生成文档。
|
|
78
|
+
- Provider 通过类集合批量注册。
|
|
79
|
+
- Middleware 通过 Provider 绑定为命名服务。
|
|
80
|
+
|
|
81
|
+
## 3. Problems Solved
|
|
82
|
+
|
|
83
|
+
### 3.1 Application Composition
|
|
84
|
+
|
|
85
|
+
没有 Runtime framework 时,Web server、CLI、Cron 往往各自初始化配置、Logger、Redis 和数据库,导致:
|
|
86
|
+
|
|
87
|
+
- 初始化顺序不一致。
|
|
88
|
+
- 服务重复创建。
|
|
89
|
+
- 配置读取分散。
|
|
90
|
+
- 测试替换困难。
|
|
91
|
+
- 不同入口的行为不一致。
|
|
92
|
+
|
|
93
|
+
Engine 通过统一的 bootstrap 和 provider registration 解决这些问题。
|
|
94
|
+
|
|
95
|
+
### 3.2 Dependency Coupling
|
|
96
|
+
|
|
97
|
+
直接使用:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
const redis = require('redis');
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
会使业务代码与具体实现绑定。EvaEngine 通过:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
Provider -> DI binding -> Service abstraction -> concrete implementation
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
允许替换实现、注入 mock,并支持按配置选择 JWT provider 等实现。
|
|
110
|
+
|
|
111
|
+
### 3.3 Cross-Cutting Concerns
|
|
112
|
+
|
|
113
|
+
Logger、Trace、Auth、Session、Validator、View Cache 等横切能力集中在 middleware/provider 层,而不是散落在每个 Controller 或 Command 中。
|
|
114
|
+
|
|
115
|
+
### 3.4 ORM and Documentation Automation
|
|
116
|
+
|
|
117
|
+
Entity scanner 和 Swagger generator 试图把数据库模型、源代码注释、异常类型转换为运行时 registry 和公开 API 文档,降低重复声明成本。
|
|
118
|
+
|
|
119
|
+
## 4. Core Abstractions
|
|
120
|
+
|
|
121
|
+
### 4.1 EvaEngine / Runtime
|
|
122
|
+
|
|
123
|
+
文件:`src/engine.js`
|
|
124
|
+
|
|
125
|
+
Engine 负责:
|
|
126
|
+
|
|
127
|
+
- 保存 `projectRoot`、`configPath`、`sourceRoot`、`mode`、`port` 等 metadata。
|
|
128
|
+
- 创建 Express application/router。
|
|
129
|
+
- 注册基础 Service Provider。
|
|
130
|
+
- 注册 Web/CLI middleware provider。
|
|
131
|
+
- 注册 Command。
|
|
132
|
+
- 启动 HTTP/HTTPS server。
|
|
133
|
+
- 解析并运行 CLI command。
|
|
134
|
+
- 注册 Cron command。
|
|
135
|
+
- 提供默认错误处理和 server error handling。
|
|
136
|
+
- 维护 Cron handler 并清理它们。
|
|
137
|
+
|
|
138
|
+
Engine 是 Kernel/Runtime 层的主要实现,但当前职责偏多,未来可以拆成:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
Kernel
|
|
142
|
+
RuntimeContext
|
|
143
|
+
ProviderRegistry
|
|
144
|
+
CommandBus
|
|
145
|
+
HttpRuntime
|
|
146
|
+
CliRuntime
|
|
147
|
+
CronRuntime
|
|
148
|
+
ShutdownCoordinator
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 4.2 DI Container
|
|
152
|
+
|
|
153
|
+
文件:`src/di.js`
|
|
154
|
+
|
|
155
|
+
DI 对 `constitute.Container` 做了轻量包装,支持:
|
|
156
|
+
|
|
157
|
+
- `DI.get(key)`
|
|
158
|
+
- `DI.bindClass(name, Class)`
|
|
159
|
+
- `DI.bindValue(name, value)`
|
|
160
|
+
- `DI.bindMethod(name, method)`
|
|
161
|
+
- `DI.reset()`
|
|
162
|
+
- `DI.registerServiceProviders()`
|
|
163
|
+
- `DI.registerMockedProviders()`
|
|
164
|
+
|
|
165
|
+
DI 同时维护:
|
|
166
|
+
|
|
167
|
+
- 实际 container。
|
|
168
|
+
- 命名服务到 class/value/method 的 `bound` registry。
|
|
169
|
+
|
|
170
|
+
这是一个运行时 DI,而非类型安全 DI。它的主要价值是生命周期和可替换性,不是编译期检查。
|
|
171
|
+
|
|
172
|
+
### 4.3 ServiceProvider
|
|
173
|
+
|
|
174
|
+
文件:`src/services/providers.js`
|
|
175
|
+
|
|
176
|
+
`ServiceProvider` 是基础扩展抽象:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
class ServiceProvider {
|
|
180
|
+
constructor(engine) {}
|
|
181
|
+
get name() {}
|
|
182
|
+
register() {}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
现有 Provider 负责把具体服务绑定进 DI,例如:
|
|
187
|
+
|
|
188
|
+
- `ConfigProvider`
|
|
189
|
+
- `LoggerProvider`
|
|
190
|
+
- `RedisProvider`
|
|
191
|
+
- `CacheProvider`
|
|
192
|
+
- `HttpClientProvider`
|
|
193
|
+
- `RestClientProvider`
|
|
194
|
+
- `NamespaceProvider`
|
|
195
|
+
- `JsonWebTokenProvider`
|
|
196
|
+
- `EventManagerProvider`
|
|
197
|
+
- `NowProvider`
|
|
198
|
+
|
|
199
|
+
Provider 是 EvaEngine 最重要、也最值得保留的抽象之一,因为它定义了能力装配边界。
|
|
200
|
+
|
|
201
|
+
### 4.4 ServiceInterface
|
|
202
|
+
|
|
203
|
+
文件:`src/services/interface.js`
|
|
204
|
+
|
|
205
|
+
当前接口很薄,主要提供 `getProto()`。实际 service contract 由具体 service 的 public methods 决定。
|
|
206
|
+
|
|
207
|
+
主要服务包括:
|
|
208
|
+
|
|
209
|
+
- Config: 配置加载、查询、reload、Spring Config 解析。
|
|
210
|
+
- Logger: debug/verbose/info/warn/error/dump。
|
|
211
|
+
- Redis: getInstance、setOptions、cleanup、isConnected。
|
|
212
|
+
- Cache: get/set/del/has/flush/namespace。
|
|
213
|
+
- HTTP/REST Client: request、dumpRequest、dumpResponse。
|
|
214
|
+
- JWT: save/find/clear/encode/decode。
|
|
215
|
+
- EventManager: listener registration and emit。
|
|
216
|
+
|
|
217
|
+
### 4.5 Command
|
|
218
|
+
|
|
219
|
+
文件:`src/commands/interface.js`
|
|
220
|
+
|
|
221
|
+
Command 是 Web 之外的主要应用入口抽象:
|
|
222
|
+
|
|
223
|
+
```js
|
|
224
|
+
class Command {
|
|
225
|
+
constructor(argv) {}
|
|
226
|
+
getArgv() {}
|
|
227
|
+
setArgv(argv) {}
|
|
228
|
+
getOptions() {}
|
|
229
|
+
static getName() {}
|
|
230
|
+
static getDescription() {}
|
|
231
|
+
static getSpec() {}
|
|
232
|
+
run() {}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Command 通过 Engine 注册,并可由 CLI 或 Cron 调用。
|
|
237
|
+
|
|
238
|
+
理想分层应为:
|
|
239
|
+
|
|
240
|
+
```text
|
|
241
|
+
CLI / Cron / HTTP
|
|
242
|
+
-> Command
|
|
243
|
+
-> UseCase
|
|
244
|
+
-> Domain Service
|
|
245
|
+
-> Repository
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
当前 Command 仍可能直接访问 DI、Entity 和基础设施,UseCase boundary 尚未独立形成。
|
|
249
|
+
|
|
250
|
+
### 4.6 Middleware
|
|
251
|
+
|
|
252
|
+
Middleware 由 provider 注册为命名服务:
|
|
253
|
+
|
|
254
|
+
- session
|
|
255
|
+
- auth
|
|
256
|
+
- debug
|
|
257
|
+
- view_cache
|
|
258
|
+
- validator
|
|
259
|
+
- trace
|
|
260
|
+
|
|
261
|
+
Middleware 解决 HTTP 横切关注点,但部分 middleware 同时承担业务策略和基础设施访问,边界仍偏重。
|
|
262
|
+
|
|
263
|
+
### 4.7 Entity Registry
|
|
264
|
+
|
|
265
|
+
文件:`src/entities/index.js`
|
|
266
|
+
|
|
267
|
+
Entity 系统包括:
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
Entity path
|
|
271
|
+
-> filesystem scanner
|
|
272
|
+
-> Sequelize model factory
|
|
273
|
+
-> entity registry
|
|
274
|
+
-> association setup
|
|
275
|
+
-> query/persistence helper
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
`Entities` 负责:
|
|
279
|
+
|
|
280
|
+
- 扫描 Entity 文件。
|
|
281
|
+
- 创建 Sequelize model。
|
|
282
|
+
- 维护 `entities` registry。
|
|
283
|
+
- 调用 `associate`。
|
|
284
|
+
- 提供 query、transaction、uniqueInsert 等 persistence helper。
|
|
285
|
+
- 将 model metadata 提供给 Swagger。
|
|
286
|
+
|
|
287
|
+
当前 Entity 与 Sequelize persistence model 强耦合,还不是独立的 Domain Entity。
|
|
288
|
+
|
|
289
|
+
### 4.8 Swagger Metadata Pipeline
|
|
290
|
+
|
|
291
|
+
文件:`src/swagger/index.js`
|
|
292
|
+
|
|
293
|
+
Swagger pipeline 大致为:
|
|
294
|
+
|
|
295
|
+
```text
|
|
296
|
+
Source files
|
|
297
|
+
-> Glob scanner
|
|
298
|
+
-> Acorn comments/parser
|
|
299
|
+
-> Doctrine/JSDoc parser
|
|
300
|
+
-> Annotation/Fragment model
|
|
301
|
+
-> Exceptions + Sequelize models merge
|
|
302
|
+
-> Swagger JSON
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
这是 Metadata-driven automation 的典型实现,也是 EvaEngine 与 Aurora Knowledge Runtime 可以共享的思想。
|
|
306
|
+
|
|
307
|
+
## 5. Lifecycle Design
|
|
308
|
+
|
|
309
|
+
### 5.1 Current Lifecycle
|
|
310
|
+
|
|
311
|
+
当前典型 Web lifecycle:
|
|
312
|
+
|
|
313
|
+
```text
|
|
314
|
+
new EvaEngine(meta)
|
|
315
|
+
-> bootstrap()
|
|
316
|
+
-> register base service providers
|
|
317
|
+
-> register web service providers
|
|
318
|
+
-> register middleware providers
|
|
319
|
+
-> bind services into DI
|
|
320
|
+
-> register commands/controllers/entities as needed
|
|
321
|
+
-> run(port)
|
|
322
|
+
-> create HTTP server
|
|
323
|
+
-> attach error handlers
|
|
324
|
+
-> listen
|
|
325
|
+
-> request lifecycle
|
|
326
|
+
-> cleanup selected resources
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
CLI lifecycle:
|
|
330
|
+
|
|
331
|
+
```text
|
|
332
|
+
new EvaEngine(meta, 'cli')
|
|
333
|
+
-> register CLI providers
|
|
334
|
+
-> register commands
|
|
335
|
+
-> getCLI()/runCLI()
|
|
336
|
+
-> instantiate command
|
|
337
|
+
-> command.run()
|
|
338
|
+
-> cleanup Redis when caller performs cleanup
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Cron lifecycle:
|
|
342
|
+
|
|
343
|
+
```text
|
|
344
|
+
runCrontab(sequence, commandString)
|
|
345
|
+
-> validate command registry
|
|
346
|
+
-> register CLI providers
|
|
347
|
+
-> parse schedule
|
|
348
|
+
-> create later interval
|
|
349
|
+
-> invoke command.run() per round
|
|
350
|
+
-> clearCrontabs()
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 5.2 Lifecycle Strengths
|
|
354
|
+
|
|
355
|
+
- Provider registration发生在 Runtime bootstrap 阶段。
|
|
356
|
+
- 服务按需由 DI 构造。
|
|
357
|
+
- Command 在执行时实例化。
|
|
358
|
+
- Redis、HTTP server、Cron handler 有明确的获取或清理入口。
|
|
359
|
+
- Web、CLI、Cron 使用同一套服务抽象。
|
|
360
|
+
|
|
361
|
+
### 5.3 Lifecycle Limitations
|
|
362
|
+
|
|
363
|
+
当前没有完整的统一 lifecycle protocol:
|
|
364
|
+
|
|
365
|
+
```text
|
|
366
|
+
register()
|
|
367
|
+
boot()
|
|
368
|
+
start()
|
|
369
|
+
shutdown()
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Provider 主要只有 `register()`,因此:
|
|
373
|
+
|
|
374
|
+
- 资源建立时机依赖 service 的 `getInstance()`。
|
|
375
|
+
- shutdown 不由 Kernel 统一协调。
|
|
376
|
+
- server、Redis、HTTP client、Cron 的清理责任分散。
|
|
377
|
+
- 多次 bootstrap 或多个 Engine 实例可能产生状态污染。
|
|
378
|
+
|
|
379
|
+
未来建议:
|
|
380
|
+
|
|
381
|
+
```text
|
|
382
|
+
Provider.register(context)
|
|
383
|
+
Provider.boot(context)
|
|
384
|
+
Provider.start(context)
|
|
385
|
+
Provider.stop(context)
|
|
386
|
+
Provider.shutdown(context)
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
并由 `RuntimeContext` 管理所有 disposable resources。
|
|
390
|
+
|
|
391
|
+
## 6. Extension Mechanism
|
|
392
|
+
|
|
393
|
+
### 6.1 Service Providers
|
|
394
|
+
|
|
395
|
+
新增基础设施能力的主要方式:
|
|
396
|
+
|
|
397
|
+
1. 创建 `ServiceProvider` 子类。
|
|
398
|
+
2. 实现稳定的 `name`。
|
|
399
|
+
3. 在 `register()` 中绑定 class/value/method。
|
|
400
|
+
4. 将 Provider 加入 Engine 对应 provider list。
|
|
401
|
+
|
|
402
|
+
这是最清晰、最成熟的扩展机制。
|
|
403
|
+
|
|
404
|
+
### 6.2 Middleware Providers
|
|
405
|
+
|
|
406
|
+
新增 HTTP 横切能力时:
|
|
407
|
+
|
|
408
|
+
1. 创建 middleware factory。
|
|
409
|
+
2. 创建对应 Provider。
|
|
410
|
+
3. 使用 `DI.bindMethod(name, middlewareFactory)`。
|
|
411
|
+
4. 在 Runtime bootstrap 阶段注册。
|
|
412
|
+
|
|
413
|
+
### 6.3 Commands
|
|
414
|
+
|
|
415
|
+
通过继承 `Command` 并实现静态 metadata 扩展:
|
|
416
|
+
|
|
417
|
+
```js
|
|
418
|
+
class MyCommand extends Command {
|
|
419
|
+
static getName() {}
|
|
420
|
+
static getDescription() {}
|
|
421
|
+
static getSpec() {}
|
|
422
|
+
async run() {}
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Engine 的 command registry 通过 `getName()` 建立命名路由。
|
|
427
|
+
|
|
428
|
+
### 6.4 Entity Files
|
|
429
|
+
|
|
430
|
+
将 Entity factory 放入约定目录即可被 scanner 发现。Entity 可以提供 `associate` 方法完成关联关系注册。
|
|
431
|
+
|
|
432
|
+
### 6.5 Configuration-Based Implementations
|
|
433
|
+
|
|
434
|
+
部分能力根据配置选择实现:
|
|
435
|
+
|
|
436
|
+
- JWT provider: local JWT 或 Kong JWT。
|
|
437
|
+
- Cache: Redis store 或 Null store。
|
|
438
|
+
- Namespace: enabled 或 disabled。
|
|
439
|
+
- Logger: environment/config 控制 level 和 file transport。
|
|
440
|
+
|
|
441
|
+
这属于 conditional binding,是 Provider 机制的核心价值。
|
|
442
|
+
|
|
443
|
+
## 7. Public Contract Candidates
|
|
444
|
+
|
|
445
|
+
以下 API 从入口导出、文档、测试和用户使用方式看,属于明显的 public contract。
|
|
446
|
+
|
|
447
|
+
### Package Entry
|
|
448
|
+
|
|
449
|
+
`src/index.js`/package main 导出的:
|
|
450
|
+
|
|
451
|
+
- `EvaEngine`
|
|
452
|
+
- `Command`
|
|
453
|
+
- `DI`
|
|
454
|
+
- `Entities`
|
|
455
|
+
- `engine` constants and helpers
|
|
456
|
+
- `express`
|
|
457
|
+
- `commands`
|
|
458
|
+
- `exceptions`
|
|
459
|
+
- `middlewares`
|
|
460
|
+
- `services`
|
|
461
|
+
- `providers`
|
|
462
|
+
- `swagger`
|
|
463
|
+
- `Joi`
|
|
464
|
+
- `sequelize`
|
|
465
|
+
- `wrapper`
|
|
466
|
+
- `utils`
|
|
467
|
+
|
|
468
|
+
### Engine Contract
|
|
469
|
+
|
|
470
|
+
- `new EvaEngine(meta, mode)`
|
|
471
|
+
- `getMeta()`
|
|
472
|
+
- `getDI()`
|
|
473
|
+
- `bootstrap()`
|
|
474
|
+
- `registerCommands()`
|
|
475
|
+
- `getCommands()`
|
|
476
|
+
- `clearCommands()`
|
|
477
|
+
- `run()`
|
|
478
|
+
- `runHttps()`
|
|
479
|
+
- `runCLI()`
|
|
480
|
+
- `runCommand()`
|
|
481
|
+
- `runCrontab()`
|
|
482
|
+
- `clearCrontabs()`
|
|
483
|
+
- `setDefaultErrorHandler()`
|
|
484
|
+
- `getDefaultErrorHandler()`
|
|
485
|
+
- `getServer()`
|
|
486
|
+
- `getVersion()`
|
|
487
|
+
|
|
488
|
+
### DI Contract
|
|
489
|
+
|
|
490
|
+
- `DI.get()`
|
|
491
|
+
- `DI.bindClass()`
|
|
492
|
+
- `DI.bindValue()`
|
|
493
|
+
- `DI.bindMethod()`
|
|
494
|
+
- `DI.reset()`
|
|
495
|
+
- `DI.registerServiceProviders()`
|
|
496
|
+
- `DI.registerMockedProviders()`
|
|
497
|
+
|
|
498
|
+
### Provider Contract
|
|
499
|
+
|
|
500
|
+
- `ServiceProvider`
|
|
501
|
+
- `name`
|
|
502
|
+
- `register()`
|
|
503
|
+
- Provider classes exported by `services/providers.js` and `middlewares/providers.js`
|
|
504
|
+
|
|
505
|
+
### Command Contract
|
|
506
|
+
|
|
507
|
+
- `Command`
|
|
508
|
+
- `Command.getName()`
|
|
509
|
+
- `Command.getDescription()`
|
|
510
|
+
- `Command.getSpec()`
|
|
511
|
+
- `Command.run()`
|
|
512
|
+
- `Command.getArgv()`
|
|
513
|
+
- `Command.getOptions()`
|
|
514
|
+
|
|
515
|
+
### Service Contract
|
|
516
|
+
|
|
517
|
+
The following methods are public because tests, providers or consumers call them directly:
|
|
518
|
+
|
|
519
|
+
- `Config.setPath/get/reload/getMergedFiles/resolveSpringConfig`
|
|
520
|
+
- `Logger.setLevel/setLabel/setLogFile/debug/verbose/info/warn/error/dump`
|
|
521
|
+
- `Redis.setOptions/getInstance/isConnected/cleanup`
|
|
522
|
+
- `Cache.get/set/del/has/flush/namespace`
|
|
523
|
+
- `HttpClient.request/dumpRequest/dumpResponse`
|
|
524
|
+
- `RestClient.request/setBaseUrl`
|
|
525
|
+
- `JsonWebToken.save/find/clear/encode/decode`
|
|
526
|
+
- `EventManager.addListener/emit/getAllowEvents/getEmitter`
|
|
527
|
+
- `Now.setNow/getNow/getTimestamp`
|
|
528
|
+
- `Entities.scan/init/getAll/getInstance/query/uniqueInsert/getTransaction`
|
|
529
|
+
|
|
530
|
+
### Middleware Contract
|
|
531
|
+
|
|
532
|
+
- Middleware factory returns `(req, res, next) => ...`.
|
|
533
|
+
- Auth sets `req.auth` and `X-Uid`.
|
|
534
|
+
- Trace sets B3 headers and trace metadata.
|
|
535
|
+
- Validator accepts schema factory/options/validator override.
|
|
536
|
+
- Session returns Express-compatible middleware.
|
|
537
|
+
|
|
538
|
+
## 8. Internal Implementation
|
|
539
|
+
|
|
540
|
+
以下代码应视为内部实现,除非用户明确依赖它们:
|
|
541
|
+
|
|
542
|
+
- `constitute.Container` 的具体使用方式。
|
|
543
|
+
- `DI` 内部 `bound` map 的数据结构。
|
|
544
|
+
- Engine 的 `baseServiceProviders`、`serviceProvidersForWeb`、`serviceProvidersForCLI` 数组。
|
|
545
|
+
- Engine 内部 `app` singleton、`server` 字段和 `crontabJobHandlers` 数组。
|
|
546
|
+
- Config 的文件合并实现、动态模块加载和默认配置对象。
|
|
547
|
+
- Redis 的 client cache 和连接选项拼接。
|
|
548
|
+
- Cache 的 `Store`、`NullStore`、`RedisStore`、`RedisNamespaceStore` 实现细节。
|
|
549
|
+
- Entity scanner 的 filesystem/filter 实现。
|
|
550
|
+
- Sequelize model factory 的具体加载方式。
|
|
551
|
+
- Swagger 的 Acorn/Doctrine/Glob pipeline 实现细节。
|
|
552
|
+
- `request` 原型 debug patch。
|
|
553
|
+
- `moment`、`later`、`ioredis`、`winston` 等具体库。
|
|
554
|
+
- `test/` 中所有 fixture、bootstrap、mock helpers。
|
|
555
|
+
- `lib/`、coverage reports、generated Swagger files。
|
|
556
|
+
|
|
557
|
+
内部实现可以重构,只要上述 public behavior 和导出 contract 保持兼容。
|
|
558
|
+
|
|
559
|
+
## 9. Architectural Boundaries
|
|
560
|
+
|
|
561
|
+
当前可以识别出以下逻辑层:
|
|
562
|
+
|
|
563
|
+
```text
|
|
564
|
+
Runtime / Kernel
|
|
565
|
+
src/engine.js
|
|
566
|
+
src/di.js
|
|
567
|
+
src/services/providers.js
|
|
568
|
+
|
|
569
|
+
Infrastructure
|
|
570
|
+
Config, Env, Logger, Redis, Cache
|
|
571
|
+
HttpClient, RestClient, Namespace
|
|
572
|
+
Sequelize integration
|
|
573
|
+
|
|
574
|
+
Application / Interface
|
|
575
|
+
Commands
|
|
576
|
+
Middleware
|
|
577
|
+
CLI / HTTP / Cron entry points
|
|
578
|
+
|
|
579
|
+
Domain / Persistence
|
|
580
|
+
Entities and model helpers
|
|
581
|
+
EventManager
|
|
582
|
+
JWT and business-facing services
|
|
583
|
+
|
|
584
|
+
Metadata / Automation
|
|
585
|
+
Swagger scanner
|
|
586
|
+
Entity scanner
|
|
587
|
+
Command metadata
|
|
588
|
+
Exception metadata
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
这个分层目前是隐式的,并非严格 module boundary。尤其 Entity 同时承担 Domain registry、ORM model loading、SQL helper 和 metadata source,属于未来重构的主要切入点。
|
|
592
|
+
|
|
593
|
+
## 10. Main Architectural Risks
|
|
594
|
+
|
|
595
|
+
### Global State
|
|
596
|
+
|
|
597
|
+
DI container、Config cache、Redis client、Express app 等状态容易跨 Engine 或测试实例共享。多 Runtime 并存时需要显式 Context 隔离。
|
|
598
|
+
|
|
599
|
+
### Infrastructure Leakage
|
|
600
|
+
|
|
601
|
+
Entity 直接暴露 Sequelize model,Cache 直接暴露 Redis semantics,HTTP client 包含 request 内部 patch。这些实现细节容易泄露到业务层。
|
|
602
|
+
|
|
603
|
+
### Lifecycle Fragmentation
|
|
604
|
+
|
|
605
|
+
Provider 没有统一 shutdown contract,资源清理由调用者或测试自行负责。
|
|
606
|
+
|
|
607
|
+
### Weak Type Contract
|
|
608
|
+
|
|
609
|
+
命名字符串 DI 和动态 metadata 缺少编译期检查。TypeScript interface、typed tokens 和 typed provider registry 可以降低风险。
|
|
610
|
+
|
|
611
|
+
### Event Reliability
|
|
612
|
+
|
|
613
|
+
当前 EventManager 是进程内事件机制,没有 queue、retry、dead letter、schema 或 delivery guarantee,不适合直接承担跨进程业务事件。
|
|
614
|
+
|
|
615
|
+
### Legacy Package Coupling
|
|
616
|
+
|
|
617
|
+
虽然 Runtime 已可在 Node 24 原生 ESM 下运行,但 `request`、`later`、`continuation-local-storage`、Sequelize model conventions 等仍带有旧生态耦合,应在后续版本逐步替换。
|
|
618
|
+
|
|
619
|
+
## 11. Recommended Future Direction
|
|
620
|
+
|
|
621
|
+
如果以 2026 重构 EvaEngine,建议保留思想而不是原样保留实现:
|
|
622
|
+
|
|
623
|
+
```text
|
|
624
|
+
Kernel
|
|
625
|
+
-> RuntimeContext
|
|
626
|
+
-> ProviderRegistry
|
|
627
|
+
-> Lifecycle Coordinator
|
|
628
|
+
-> CommandBus
|
|
629
|
+
-> UseCase
|
|
630
|
+
-> Domain
|
|
631
|
+
-> Repository
|
|
632
|
+
-> Storage
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
推荐演进:
|
|
636
|
+
|
|
637
|
+
1. 使用 TypeScript 和 typed dependency tokens。
|
|
638
|
+
2. 将 Config、Logger、Redis、HTTP 等 capability 定义为 interface。
|
|
639
|
+
3. 将 Provider lifecycle 扩展为 register/boot/start/stop/shutdown。
|
|
640
|
+
4. 将 Engine singleton 状态下沉到 RuntimeContext。
|
|
641
|
+
5. 将 Entity 拆分为 Domain Entity、Repository、Persistence Model。
|
|
642
|
+
6. 将 EventManager 升级为 typed in-process event bus,并为跨进程事件接入 queue。
|
|
643
|
+
7. 使用 OpenTelemetry 统一 Logs/Metrics/Traces。
|
|
644
|
+
8. 将 Command 作为 UseCase adapter,而不是业务逻辑容器。
|
|
645
|
+
9. 保留 Metadata registry,但使用明确 schema 和 versioned metadata。
|
|
646
|
+
10. 将 Swagger、OpenAPI、AI tool schema 等视为同一类 contract generation pipeline。
|
|
647
|
+
|
|
648
|
+
## 12. Final Assessment
|
|
649
|
+
|
|
650
|
+
EvaEngine 的最大价值不在某个 HTTP helper 或 ORM wrapper,而在四个架构判断:
|
|
651
|
+
|
|
652
|
+
1. **Runtime**:不同应用入口共享生命周期和能力。
|
|
653
|
+
2. **Provider**:基础设施能力可以注册、替换和按配置选择。
|
|
654
|
+
3. **Metadata**:应用组件能够被扫描、理解并自动生成文档/注册信息。
|
|
655
|
+
4. **Command/Event**:复杂应用可以通过明确入口和事件解耦。
|
|
656
|
+
|
|
657
|
+
这些思想与 Aurora Runtime、Knowledge Runtime 和 AI 产品基础设施高度相关。后续重构应把 EvaEngine 视为一个 Runtime architecture prototype:保留其边界意识与扩展方向,重新实现类型、生命周期、可观测性、可靠事件和云原生资源管理。
|