@hile/micro-dynamic-configs 2.0.0 → 2.0.1

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 (2) hide show
  1. package/package.json +4 -4
  2. package/SKILL.md +0 -174
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hile/micro-dynamic-configs",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -22,10 +22,10 @@
22
22
  "vitest": "^4.0.18"
23
23
  },
24
24
  "dependencies": {
25
- "@hile/ioredis": "^1.1.2",
26
- "@hile/micro": "^2.0.0",
25
+ "@hile/ioredis": "^2.0.0",
26
+ "@hile/micro": "^2.0.1",
27
27
  "ioredis": "^5.10.0",
28
28
  "zod": "^4.4.3"
29
29
  },
30
- "gitHead": "d28b20bc22ee08c45cbf4596672705cb96e8e461"
30
+ "gitHead": "8e0fd1f78b5a8abd21218d1f596ada2533a0c8e7"
31
31
  }
package/SKILL.md DELETED
@@ -1,174 +0,0 @@
1
- ---
2
- name: micro-dynamic-configs
3
- description: Code generation and contribution rules for @hile/micro-dynamic-configs. Use when editing this package or when the user asks about dynamic config patterns or API.
4
- ---
5
-
6
- # @hile/micro-dynamic-configs
7
-
8
- 面向 AI 编码模型与维护者的代码生成规范。阅读后应能正确使用本库编写符合架构规则的代码。
9
-
10
- ---
11
-
12
- ## 1. 架构总览
13
-
14
- 通过 `@hile/micro` 的 pub/sub 机制推送配置变更,每个 schema 字段一个独立 topic。
15
-
16
- ```
17
- Publisher Config Server Subscriber
18
- │ │ │
19
- │ save({ key: val }) │ │
20
- ├──────────────────────────► │ │
21
- │ │ publisher.update(newValue) │
22
- │ │ ──────────────────────────────► │
23
- │ │ (通过 Registry 广播 topic) │
24
- │ │ │
25
- │ │ app.subscribe('ns:key', cb) │
26
- │ │ ◄────────────────────────────── │
27
- ```
28
-
29
- - **Config Server** (`MicroDynamicConfigsServer`) — 持有配置数据,校验、持久化,通过 `app.publish` 注册 publisher
30
- - **Subscriber** — 直接用 `app.subscribe(topic, callback)` 接收推送,无需客户端层
31
- - **Publisher** — 调用 `server.save()` 修改配置,数据流:validate → Redis 持久化 → 内存更新 → `publisher.update()` → `change:key` 事件
32
-
33
- ---
34
-
35
- ## 2. 类型签名
36
-
37
- ### MicroDynamicConfigsServer
38
-
39
- ```typescript
40
- class MicroDynamicConfigsServer<
41
- T extends Application,
42
- Z extends ZodObject<ZodRawShape>
43
- > extends EventEmitter
44
-
45
- constructor(options: {
46
- app: T // Application 实例
47
- redis: Redis // ioredis 实例
48
- schema: Z // Zod schema 定义配置结构
49
- redis_key: string // Redis 存储键名
50
- })
51
-
52
- // 从 Redis 加载持久化数据,为每个 schema 字段注册 publisher,返回 teardown 函数
53
- initialize(): Promise<() => Promise<void>>
54
-
55
- // 持久化并推送变更
56
- save(value: Partial<z.infer<Z>>): Promise<number>
57
-
58
- // 当前配置快照(只读)
59
- get value(): z.infer<Z>
60
- ```
61
-
62
- ### 事件
63
-
64
- | 事件 | 参数 | 说明 |
65
- |------|------|------|
66
- | `change:{field}` | `(newValue, oldValue)` | 字段变更时触发,每个字段独立事件名 |
67
-
68
- ---
69
-
70
- ## 3. Topic 约定
71
-
72
- 每个 schema 字段一个 topic,格式为:
73
-
74
- ```
75
- {namespace}:{field}
76
- ```
77
-
78
- 例如 namespace `config-svc`、字段 `name`、`port`、`debug`:
79
-
80
- - `config-svc:name`
81
- - `config-svc:port`
82
- - `config-svc:debug`
83
-
84
- ### 订阅
85
-
86
- ```typescript
87
- const values: Record<string, any> = {};
88
- const unsub = await app.subscribe('config-svc:name', (v) => values.name = v);
89
- // unsub() 取消订阅
90
- ```
91
-
92
- ---
93
-
94
- ## 4. 代码生成强制规则
95
-
96
- ### 4.1 save() 必须分两轮执行
97
-
98
- ```typescript
99
- // ✓ 正确:先 validate 再 apply
100
- // Pass 1: validate & diff
101
- const entries = [];
102
- for (const key of keys) {
103
- const parsed = schema.parse(value[key]);
104
- if (!deepEqual(old, parsed)) entries.push({ key, parsed });
105
- }
106
- // Pass 2: persist → memory → publish + emit
107
- await redis.set(key, JSON.stringify(next));
108
- update memory;
109
- emit 'change:{key}' events;
110
-
111
- // ✗ 禁止:validate 和 mutate 混在一轮
112
- for (const key of keys) {
113
- this._value[key] = parsed; // ❌ 后续字段失败时 _value 已脏
114
- }
115
- ```
116
-
117
- ### 4.2 initialize() 中注册 publisher
118
-
119
- ```typescript
120
- // ✓ 正确:initialize 时调用 app.publish 注册所有字段
121
- const publisher = await this.app.publish(`${namespace}:${key}`, initialValue);
122
- this.publishers.set(key, publisher);
123
-
124
- // save 时通过 publisher.update 推送
125
- await this.publishers.get(key)!.update(newValue);
126
-
127
- // teardown 时 unpublish
128
- await publisher.unpublish();
129
-
130
- // ✗ 禁止:save 中每次调用 app.publish(应复用 initialize 时注册的 publisher)
131
- ```
132
-
133
- ### 4.3 teardown 必须清理所有资源
134
-
135
- ```typescript
136
- // ✓ 正确:teardown 需 unpublish + clear + removeAllListeners
137
- return async () => {
138
- for (const publisher of this.publishers.values()) {
139
- await publisher.unpublish();
140
- }
141
- this.publishers.clear();
142
- this.removeAllListeners();
143
- };
144
- ```
145
-
146
- ### 4.4 deep diff 避免无效推送
147
-
148
- ```typescript
149
- // ✓ 正确:值未变化时跳过 publish
150
- if (isDeepStrictEqual(oldValue, parsed)) {
151
- continue; // 不写入 entries,不触发 publish 和事件
152
- }
153
- ```
154
-
155
- ---
156
-
157
- ## 5. 边界条件清单
158
-
159
- - [ ] `save()` 传入空对象 `{}` — 返回 0,无操作
160
- - [ ] `save()` 传入 schema 中不存在的字段 — 跳过,不报错
161
- - [ ] `save()` 中单个字段校验失败 — 整个操作 reject,`_value` 不变
162
- - [ ] `save()` 中所有字段值与当前一致 — 返回 0,不写 Redis 不推送
163
- - [ ] `save()` Redis 写入失败 — throw,`_value` 不变
164
- - [ ] `initialize()` 时 Redis 无数据 — 使用 schema 默认值
165
- - [ ] 多个字段同时变更 — 一轮 `save()` 中逐个 `publisher.update()` + `change:key` 事件
166
- - [ ] Deep diff 检测嵌套对象变化 — 嵌套字段内容不变时跳过 publish
167
-
168
- ---
169
-
170
- ## 6. 依赖
171
-
172
- - `@hile/micro` — 提供 `Application`、`app.publish`/`app.subscribe`
173
- - `ioredis` — Redis 持久化
174
- - `zod` — Schema 定义与校验