@hile/core 1.0.18 → 1.0.19

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 CHANGED
@@ -138,7 +138,7 @@ const container = new Container({
138
138
  订阅事件:
139
139
 
140
140
  ```typescript
141
- const off = container.onEvent((event) => {
141
+ const off = container.on((event) => {
142
142
  if (event.type === 'service:ready') {
143
143
  console.log(`service#${event.id} ready in ${event.durationMs}ms`)
144
144
  }
@@ -218,8 +218,8 @@ const result = await container.resolve(service)
218
218
  | `register(fn)` | 注册服务(同函数引用去重) |
219
219
  | `resolve(props)` | 加载服务(执行、等待或返回缓存) |
220
220
  | `shutdown()` | 销毁所有服务并执行清理回调 |
221
- | `onEvent(listener)` | 订阅容器事件,返回取消订阅函数 |
222
- | `offEvent(listener)` | 取消订阅 |
221
+ | `on(listener)` | 订阅容器事件,返回取消订阅函数 |
222
+ | `off(listener)` | 取消订阅 |
223
223
  | `getLifecycle(id)` | 获取服务生命周期阶段 |
224
224
  | `getDependencyGraph()` | 获取依赖图 `{ nodes, edges }` |
225
225
  | `getStartupOrder()` | 获取服务启动顺序(首次启动顺序) |
package/SKILL.md CHANGED
@@ -1,180 +1,112 @@
1
1
  ---
2
2
  name: hile-core
3
- description: @hile/core 的代码生成与使用规范。适用于定义/加载 Hile 服务、生命周期 shutdown 编排、或涉及 defineService、loadService、Container 等话题。
3
+ description: "@hile/core 的代码生成与使用规范。适用于定义/加载 Hile 服务、生命周期编排、依赖图与容器事件相关场景。"
4
4
  ---
5
5
 
6
6
  # @hile/core SKILL
7
7
 
8
- 本文档用于约束 AI 与开发者在使用 `@hile/core` 时的代码生成方式,目标是保证服务定义、依赖加载与资源销毁行为一致且可维护。
8
+ 本文档面向代码生成器与维护者,目标是确保生成代码严格符合容器语义。
9
9
 
10
- ## 1. 架构概览
10
+ ## 1. 强约束(必须遵守)
11
11
 
12
- Hile `Container` 为核心,服务遵循“定义 → 加载”两阶段:
12
+ 1. 服务必须使用 `async (shutdown)` 形态定义。
13
+ 2. 只能通过 `defineService` / `container.register` 产出服务对象。
14
+ 3. 只能通过 `loadService` / `container.resolve` 获取服务实例。
15
+ 4. 外部资源创建后必须立即注册 `shutdown`。
16
+ 5. 禁止在模块顶层缓存 `await loadService(...)` 结果。
17
+ 6. 依赖服务必须在服务函数内部加载。
18
+ 7. 多个 teardown 默认按 LIFO 顺序执行。
13
19
 
14
- - 单例:同一服务函数仅初始化一次
15
- - 并发合并:并发加载同一服务时共享同一初始化过程
16
- - 失败回收:初始化失败时自动执行已注册的清理回调
20
+ ## 2. 生命周期与超时约束
17
21
 
18
- 模块默认导出全局容器,并提供 `defineService` / `loadService` 便捷函数。
22
+ 容器生命周期:`init -> ready -> stopping -> stopped`。
19
23
 
20
- ## 2. 关键类型
24
+ - 启动超时:`new Container({ startTimeoutMs })`
25
+ - 销毁超时:`new Container({ shutdownTimeoutMs })`
21
26
 
22
- ```typescript
23
- type ServiceCutDownFunction = () => unknown | Promise<unknown>;
24
- type ServiceCutDownHandler = (fn: ServiceCutDownFunction) => void;
25
- type ServiceFunction<R> = (shutdown: ServiceCutDownHandler) => R | Promise<R>;
26
-
27
- const sericeFlag = Symbol('service');
27
+ 生成代码时:
28
28
 
29
- interface ServiceRegisterProps<R> {
30
- id: number;
31
- fn: ServiceFunction<R>;
32
- flag: typeof sericeFlag;
33
- }
34
- ```
29
+ - 不要吞掉启动超时错误。
30
+ - 不要假设 teardown 一定成功;应允许 `service:shutdown:error` 事件出现。
35
31
 
36
- ## 3. 标准模板
32
+ ## 3. 可观测事件约束
37
33
 
38
- ### 3.1 定义服务
34
+ 允许订阅:`container.on(listener)`。
39
35
 
40
- ```typescript
41
- import { defineService } from '@hile/core'
36
+ 关键事件:
42
37
 
43
- export const xxxService = defineService(async (shutdown) => {
44
- const resource = await createResource()
45
- shutdown(() => resource.close())
46
- return resource
47
- })
48
- ```
38
+ - `service:init`
39
+ - `service:ready`
40
+ - `service:error`
41
+ - `service:shutdown:start`
42
+ - `service:shutdown:done`
43
+ - `service:shutdown:error`
44
+ - `container:shutdown:start`
45
+ - `container:shutdown:done`
46
+ - `container:error`
49
47
 
50
48
  规则:
51
49
 
52
- - 服务函数第一个参数固定为 `shutdown`
53
- - 推荐必须使用 `async`
54
- - `defineService` 结果需使用模块级 `export const` 暴露
55
- - 命名建议以 `Service` 结尾
50
+ - 订阅后必须在生命周期结束时取消订阅。
51
+ - 记录错误时保留原始 error 对象。
56
52
 
57
- ### 3.2 加载服务
53
+ ## 4. 依赖图与循环依赖
58
54
 
59
- ```typescript
60
- import { loadService } from '@hile/core'
61
- import { databaseService } from './services/database'
55
+ 容器会自动记录服务依赖并检测循环依赖:
62
56
 
63
- const db = await loadService(databaseService)
64
- ```
57
+ - `getDependencyGraph()`
58
+ - `getStartupOrder()`
65
59
 
66
60
  规则:
67
61
 
68
- - 始终通过 `loadService` 获取实例
69
- - `loadService` 返回 Promise,必须 `await`
62
+ - 不要绕开容器手动构建“隐式全局单例依赖”。
63
+ - 出现 `circular dependency detected` 时应通过拆分服务职责或引入中间层服务解决。
70
64
 
71
- ### 3.3 服务依赖服务
65
+ ## 5. 反模式(禁止)
72
66
 
73
- ```typescript
74
- import { defineService, loadService } from '@hile/core'
75
- import { databaseService } from './database'
76
-
77
- export const userService = defineService(async (shutdown) => {
78
- const db = await loadService(databaseService)
79
- return new UserRepository(db)
80
- })
81
- ```
82
-
83
- 规则:
84
-
85
- - 在服务函数内部加载依赖
86
- - 不在模块顶层缓存 `loadService` 结果
87
-
88
- ### 3.4 注册清理回调
67
+ ### 5.1 顶层缓存实例
89
68
 
90
69
  ```typescript
91
- export const connectionService = defineService(async (shutdown) => {
92
- const a = await connectA()
93
- shutdown(() => a.close())
94
-
95
- const b = await connectB()
96
- shutdown(() => b.close())
70
+ //
71
+ const db = await loadService(dbService)
97
72
 
98
- return { a, b }
99
- })
73
+ //
74
+ export async function query(sql: string) {
75
+ const db = await loadService(dbService)
76
+ return db.query(sql)
77
+ }
100
78
  ```
101
79
 
102
- 规则:
103
-
104
- - 资源创建后立即注册清理
105
- - 回调按 LIFO 执行
106
- - 支持异步回调
107
-
108
- ### 3.5 全局优雅关闭
80
+ ### 5.2 手动伪造服务对象
109
81
 
110
82
  ```typescript
111
- import container from '@hile/core'
83
+ //
84
+ const fake = { id: 1, fn: async () => 1 }
112
85
 
113
- process.on('SIGTERM', async () => {
114
- await container.shutdown()
115
- process.exit(0)
116
- })
86
+ //
87
+ const real = defineService(async () => 1)
117
88
  ```
118
89
 
119
- ## 4. 强制规则
120
-
121
- 1. 服务函数必须使用 `async`,避免同步 `throw` 破坏销毁机制。
122
- 2. 不要手动构造 `ServiceRegisterProps`。
123
- 3. 不要在工厂函数里动态调用 `defineService` 生成新引用。
124
- 4. 不要在模块顶层 `await loadService(...)`。
125
- 5. 每个外部资源都应对应一次 `shutdown` 注册。
126
-
127
- ## 5. 常见反模式
128
-
129
- ### 同步 throw
90
+ ### 5.3 不注册资源清理
130
91
 
131
92
  ```typescript
132
93
  // ✗
133
- export const bad = defineService((shutdown) => {
134
- const r = createSync()
135
- shutdown(() => r.close())
136
- throw new Error('boom')
94
+ export const bad = defineService(async () => {
95
+ return await createPool()
137
96
  })
138
97
 
139
98
  // ✓
140
99
  export const good = defineService(async (shutdown) => {
141
- const r = await createAsync()
142
- shutdown(() => r.close())
143
- throw new Error('boom')
100
+ const pool = await createPool()
101
+ shutdown(() => pool.end())
102
+ return pool
144
103
  })
145
104
  ```
146
105
 
147
- ### 顶层缓存服务实例
148
-
149
- ```typescript
150
- // ✗
151
- const db = await loadService(databaseService)
152
-
153
- // ✓
154
- export async function query(sql: string) {
155
- const db = await loadService(databaseService)
156
- return db.query(sql)
157
- }
158
- ```
159
-
160
- ## 6. API 速查
161
-
162
- ### 便捷函数
163
-
164
- | 函数 | 说明 |
165
- |---|---|
166
- | `defineService(fn)` | 注册服务到默认容器 |
167
- | `loadService(props)` | 加载服务实例 |
168
- | `isService(props)` | 判断是否为合法服务注册对象 |
169
-
170
- ### Container
106
+ ## 6. 边界条件清单
171
107
 
172
- | 方法 | 说明 |
173
- |---|---|
174
- | `register(fn)` | 注册服务 |
175
- | `resolve(props)` | 解析服务 |
176
- | `hasService(fn)` | 检查函数是否已注册 |
177
- | `hasMeta(id)` | 检查运行时元数据 |
178
- | `getIdByService(fn)` | 通过函数获取 ID |
179
- | `getMetaById(id)` | 通过 ID 获取元数据 |
180
- | `shutdown()` | 销毁所有服务 |
108
+ - [ ] 服务同步抛错路径是否可观测
109
+ - [ ] 异步 reject 路径是否会触发 teardown
110
+ - [ ] teardown 抛错是否不覆盖原始业务错误
111
+ - [ ] 并发 resolve 同一服务是否只初始化一次
112
+ - [ ] shutdown 重复调用是否幂等
package/dist/index.d.ts CHANGED
@@ -73,8 +73,8 @@ export declare class Container {
73
73
  private getId;
74
74
  private hasPath;
75
75
  private trackDependency;
76
- onEvent(listener: (event: ContainerEvent) => void): () => boolean;
77
- offEvent(listener: (event: ContainerEvent) => void): void;
76
+ on(listener: (event: ContainerEvent) => void): () => boolean;
77
+ off(listener: (event: ContainerEvent) => void): void;
78
78
  getLifecycle(id: number): ServiceLifecycleStage | undefined;
79
79
  getDependencyGraph(): {
80
80
  nodes: number[];
package/dist/index.js CHANGED
@@ -83,11 +83,11 @@ export class Container {
83
83
  this.dependents.get(childId).add(parentId);
84
84
  }
85
85
  }
86
- onEvent(listener) {
86
+ on(listener) {
87
87
  this.listeners.add(listener);
88
88
  return () => this.listeners.delete(listener);
89
89
  }
90
- offEvent(listener) {
90
+ off(listener) {
91
91
  this.listeners.delete(listener);
92
92
  }
93
93
  getLifecycle(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hile/core",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "Hile core - lightweight async service container",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -23,5 +23,5 @@
23
23
  "@types/node": "^25.3.1",
24
24
  "vitest": "^4.0.18"
25
25
  },
26
- "gitHead": "81347b9de460b693ed82af46c0f4a287d4527323"
26
+ "gitHead": "4bb9d38b309e72c720f2cba579ce5c498d27e044"
27
27
  }