@h-ai/cli 0.1.0-alpha.54 → 0.1.0-alpha.55

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 (64) hide show
  1. package/README.md +4 -0
  2. package/package.json +7 -7
  3. package/templates/base/package.json.hbs +1 -1
  4. package/templates/skills/AGENTS.md +8 -22
  5. package/templates/skills/CLAUDE.md +3 -16
  6. package/templates/skills/bridges/admin/AGENTS.md +3 -16
  7. package/templates/skills/bridges/admin/CLAUDE.md +3 -11
  8. package/templates/skills/bridges/admin/copilot-instructions.md +2 -39
  9. package/templates/skills/bridges/api/AGENTS.md +5 -18
  10. package/templates/skills/bridges/api/CLAUDE.md +3 -11
  11. package/templates/skills/bridges/api/copilot-instructions.md +3 -38
  12. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +24 -59
  13. package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +1 -15
  14. package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +5 -45
  15. package/templates/skills/bridges/h5/AGENTS.md +4 -17
  16. package/templates/skills/bridges/h5/CLAUDE.md +3 -11
  17. package/templates/skills/bridges/h5/copilot-instructions.md +2 -37
  18. package/templates/skills/bridges/mobile-app/AGENTS.md +5 -18
  19. package/templates/skills/bridges/mobile-app/CLAUDE.md +3 -11
  20. package/templates/skills/bridges/mobile-app/copilot-instructions.md +2 -38
  21. package/templates/skills/bridges/website/AGENTS.md +4 -17
  22. package/templates/skills/bridges/website/CLAUDE.md +3 -11
  23. package/templates/skills/bridges/website/copilot-instructions.md +2 -37
  24. package/templates/skills/copilot-instructions.md +2 -36
  25. package/templates/skills/hai-ai/SKILL.md +35 -389
  26. package/templates/skills/hai-ai/guide.md +383 -0
  27. package/templates/skills/hai-ai/reference.md +1 -1
  28. package/templates/skills/hai-api-client/SKILL.md +6 -6
  29. package/templates/skills/hai-api-contract/SKILL.md +10 -25
  30. package/templates/skills/hai-app-create/SKILL.md +29 -388
  31. package/templates/skills/hai-app-create/reference.md +350 -0
  32. package/templates/skills/hai-app-review/SKILL.md +9 -23
  33. package/templates/skills/hai-app-tests/SKILL.md +29 -494
  34. package/templates/skills/hai-app-tests/reference.md +442 -0
  35. package/templates/skills/hai-audit/SKILL.md +6 -6
  36. package/templates/skills/hai-build/SKILL.md +19 -338
  37. package/templates/skills/hai-build/reference.md +326 -0
  38. package/templates/skills/hai-cache/SKILL.md +27 -32
  39. package/templates/skills/hai-capacitor/SKILL.md +19 -366
  40. package/templates/skills/hai-capacitor/reference.md +352 -0
  41. package/templates/skills/hai-ci/SKILL.md +6 -21
  42. package/templates/skills/hai-core/SKILL.md +25 -566
  43. package/templates/skills/hai-core/reference.md +533 -0
  44. package/templates/skills/hai-crypto/SKILL.md +6 -20
  45. package/templates/skills/hai-datapipe/SKILL.md +9 -23
  46. package/templates/skills/hai-deploy/SKILL.md +6 -24
  47. package/templates/skills/hai-framework-sync/SKILL.md +8 -20
  48. package/templates/skills/hai-iam/SKILL.md +27 -371
  49. package/templates/skills/hai-iam/reference.md +343 -0
  50. package/templates/skills/hai-kit/SKILL.md +6 -6
  51. package/templates/skills/hai-payment/SKILL.md +6 -26
  52. package/templates/skills/hai-pr-review/SKILL.md +6 -22
  53. package/templates/skills/hai-reach/SKILL.md +19 -317
  54. package/templates/skills/hai-reach/reference.md +303 -0
  55. package/templates/skills/hai-reldb/SKILL.md +19 -472
  56. package/templates/skills/hai-reldb/reference.md +452 -0
  57. package/templates/skills/hai-scheduler/SKILL.md +6 -6
  58. package/templates/skills/hai-serv/SKILL.md +27 -759
  59. package/templates/skills/hai-serv/reference.md +736 -0
  60. package/templates/skills/hai-storage/SKILL.md +7 -25
  61. package/templates/skills/hai-ui/SKILL.md +29 -625
  62. package/templates/skills/hai-ui/reference.md +598 -0
  63. package/templates/skills/hai-vecdb/SKILL.md +18 -303
  64. package/templates/skills/hai-vecdb/reference.md +291 -0
@@ -0,0 +1,326 @@
1
+ # hai-build — 详细用法
2
+
3
+ 从 [SKILL.md](SKILL.md) 选择主题后读取对应小节。代码片段展示 API 用法;省略的业务变量、schema、依赖与 return 上下文需由应用补齐。
4
+
5
+ 框架开发、CLI、服务端最低 Node.js 版本统一为 22.12.0;包与脚手架 engines、共享 node22 编译目标和 CI 最低版本必须同步。不再按 Node 20 编写兼容分支。
6
+
7
+ tsup 包的 Turbo `build` 依赖不缓存的 `build:clean`(仅清本包 dist),再执行构建或恢复缓存。不要移除此步骤:Turbo 缓存恢复不会自动移除另一模式的多余文件。
8
+
9
+ 使用 Turbo 时,影响构建的环境变量必须进入任务 `env`,共享构建配置进入 `globalDependencies`。框架的 `HAI_DOCKER_PROD_BUILD=true` 关闭声明和 sourcemap,应与普通构建使用不同缓存;PUBLIC/VITE/TAURI 变量同样参与构建缓存。切换后验证实际产物并恢复普通开发构建。
10
+
11
+ > 本技能是 hai-framework 应用开发的起点。帮助理解项目结构、定位正确的技能、并遵循 **TDD 驱动的标准工作流**。支持 SSR Web、SPA、Android/iOS 原生 App 等多端构建。
12
+
13
+ ## 适用场景
14
+
15
+ - 初次接触项目,需要了解整体架构与模块关系
16
+ - 不确定应使用哪个技能来完成任务
17
+ - 需要了解模块初始化顺序与依赖关系
18
+ - 需要执行跨模块操作或全局配置变更
19
+ - 多端构建切换(SSR ↔ SPA ↔ 原生 App)
20
+
21
+ ## 项目架构
22
+
23
+ ### 技术栈
24
+
25
+ | 层次 | 技术 |
26
+ | -------- | ------------------------------ |
27
+ | 框架 | SvelteKit 2 + Svelte 5 (Runes) |
28
+ | 样式 | TailwindCSS 4 + DaisyUI 5 |
29
+ | 语言 | TypeScript 5.7+ (strict) |
30
+ | 构建 | Vite + tsup |
31
+ | 包管理 | pnpm |
32
+ | 单元测试 | Vitest |
33
+ | E2E 测试 | Playwright |
34
+ | 原生 App | Capacitor 7 |
35
+ | 公共 API | oRPC contract + Hono + typed client |
36
+ | 认证 | Bearer access token + httpOnly refresh cookie(浏览器推荐) |
37
+
38
+ ### 多端构建模式
39
+
40
+ | 模式 | Adapter | 认证方式 | 部署目标 |
41
+ | ------- | -------------- | --------------------- | ----------------------- |
42
+ | SSR Web | adapter-node | Bearer access token + Cookie | Node.js 服务器 |
43
+ | SPA | adapter-static | Bearer access token + httpOnly refresh cookie | CDN / 静态托管 |
44
+ | Android | adapter-static | Bearer access token + Capacitor secure storage | Capacitor → Android APK |
45
+ | iOS | adapter-static | Bearer access token + Capacitor secure storage | Capacitor → iOS IPA |
46
+
47
+ **Adapter 切换**:
48
+
49
+ ```typescript
50
+ // svelte.config.js — 使用 kit 提供的 createAdapter
51
+ import { createAdapter } from '@h-ai/kit/adapter'
52
+
53
+ const config = {
54
+ kit: {
55
+ adapter: createAdapter(), // 根据 VITE_ADAPTER 环境变量自动选择
56
+ },
57
+ }
58
+ ```
59
+
60
+ - `VITE_ADAPTER=node`(默认)→ adapter-node(SSR)
61
+ - `VITE_ADAPTER=static` → adapter-static(SPA / 原生 App)
62
+
63
+ ### 目录结构
64
+
65
+ ```
66
+ 项目根/
67
+ config/ # 模块配置(YAML)
68
+ _core.yml # Core 配置(必须)
69
+ _db.yml # DB 配置(按需)
70
+ _cache.yml # Cache 配置(按需)
71
+ _iam.yml # IAM 配置(按需)
72
+ _storage.yml # Storage 配置(按需)
73
+ _ai.yml # AI 配置(按需)
74
+ src/
75
+ app.html # HTML 入口
76
+ app.d.ts # 全局类型声明
77
+ hooks.server.ts # 服务端 Hook(模块初始化 + 请求管道)
78
+ lib/
79
+ api.ts # @h-ai/api-client 初始化(SPA / 原生 App 使用)
80
+ capacitor.ts # Capacitor 初始化(原生 App)
81
+ server/
82
+ init.ts # 模块初始化入口(单例,SSR)
83
+ procedures/ # 应用私有 oRPC procedures(仅 API Service 场景)
84
+ paraglide/ # i18n 生成文件(禁止手动修改)
85
+ components/ # 应用组件
86
+ routes/
87
+ +layout.svelte # 根布局
88
+ +page.svelte # 首页
89
+ (auth)/ # 认证相关页面组
90
+ api/ # API 端点
91
+ v1/ # API v1 版本
92
+ payment/ # 支付端点(按需)
93
+ static/ # 静态资源
94
+ messages/ # i18n 翻译文件
95
+ capacitor.config.ts # Capacitor 配置(原生 App)
96
+ ```
97
+
98
+ ### 模块依赖图
99
+
100
+ ```
101
+ core(基础能力:配置、日志、i18n、HaiResult)
102
+ ├── crypto(加密:SM2/SM3/SM4)
103
+ ├── db(数据库:SQLite/PostgreSQL/MySQL)
104
+ ├── cache(缓存:内存/Redis)
105
+ ├── storage(存储:本地/S3)
106
+ ├── ai(AI:LLM/MCP/Agent)
107
+ ├── iam(身份管理)← 依赖 crypto + db + cache
108
+ ├── payment(支付)← 依赖 db + crypto
109
+ ├── api-contract(公共 HTTP API 契约)← 纯定义,依赖 core + zod + oRPC contract
110
+ ├── serv(Hono + oRPC API Service)← 依赖 api-contract;features 按需依赖 iam/storage/ai
111
+ ├── kit(SvelteKit 集成)← Hook / guard / validate / response,不定义公共 contract
112
+ ├── api-client(typed API 客户端)← 依赖 api-contract + oRPC client
113
+ ├── capacitor(原生能力)← 纯浏览器端
114
+ └── ui(UI 组件库)← 依赖 core
115
+ ```
116
+
117
+ ### 模块初始化顺序
118
+
119
+ #### SSR 模式(hooks.server.ts)
120
+
121
+ 在 `src/lib/server/init.ts` 中按依赖顺序初始化:
122
+
123
+ ```typescript
124
+ import { core } from '@h-ai/core'
125
+ import { cache, CacheConfigSchema } from '@h-ai/cache'
126
+ import { reldb, ReldbConfigSchema } from '@h-ai/reldb'
127
+ import { iam, IamConfigSchema } from '@h-ai/iam'
128
+
129
+ // 放入应用已有的启动函数;并发防护和关闭钩子复用当前模板。
130
+ core.init({ configDir: './config' })
131
+ const dbConfig = core.config.validate('db', ReldbConfigSchema)
132
+ if (!dbConfig.success) return dbConfig
133
+ const cacheConfig = core.config.validate('cache', CacheConfigSchema)
134
+ if (!cacheConfig.success) return cacheConfig
135
+ const iamConfig = core.config.validate('iam', IamConfigSchema)
136
+ if (!iamConfig.success) return iamConfig
137
+ const db = await reldb.init(dbConfig.data)
138
+ if (!db.success) return db
139
+ const cached = await cache.init(cacheConfig.data)
140
+ if (!cached.success) {
141
+ await reldb.close()
142
+ return cached
143
+ }
144
+ const identity = await iam.init(iamConfig.data)
145
+ if (!identity.success) {
146
+ await cache.close()
147
+ await reldb.close()
148
+ return identity
149
+ }
150
+ // 应用结束时 await iam.close()、cache.close()、reldb.close();
151
+ // 检查关闭结果;core 无 close,kit/api-contract/serv 不需要 init。
152
+ ```
153
+
154
+ #### SPA / 原生 App 模式(src/lib/api.ts)
155
+
156
+ ```typescript
157
+ import { apiClient } from '@h-ai/api-client'
158
+
159
+ export async function initApi() {
160
+ return apiClient.init({
161
+ baseUrl: import.meta.env.VITE_API_BASE_URL,
162
+ auth: {}, // 浏览器默认 httpOnly cookie;原生 App 传入 Capacitor TokenStorage
163
+ timeout: 15_000,
164
+ })
165
+ }
166
+
167
+ export { apiClient }
168
+ ```
169
+
170
+ #### 原生 App 追加初始化(src/lib/capacitor.ts)
171
+
172
+ ```typescript
173
+ import { capacitor } from '@h-ai/capacitor'
174
+
175
+ export async function initCapacitor() {
176
+ const initialized = await capacitor.init()
177
+ if (!initialized.success) return initialized
178
+ return capacitor.statusBar.configure({ style: 'dark' })
179
+ }
180
+ ```
181
+
182
+ ### 配置文件格式
183
+
184
+ 所有模块配置使用 YAML 保存默认值;`HAI_<配置名>_<YAML 路径>` 环境变量
185
+ 自动覆盖对应叶子项,且优先级更高:
186
+
187
+ ```yaml
188
+ # config/_core.yml
189
+ name: my-app
190
+ env: development
191
+ logging:
192
+ level: info
193
+ ```
194
+
195
+ 以上字段分别对应 `HAI_CORE_NAME`、`HAI_CORE_ENV`、
196
+ `HAI_CORE_LOGGING_LEVEL`。
197
+
198
+ ## 技能导航
199
+
200
+ 根据任务类型选择正确的技能:
201
+
202
+ ### 模块使用(API 与集成)
203
+
204
+ | 任务 | 技能 | 触发关键词 |
205
+ | --------------------- | ---------------- | ------------------------------------------------- |
206
+ | 配置/日志/i18n/HaiResult | `hai-core` | core.init, core.logger, core.config, HaiResult |
207
+ | 数据库操作 | `hai-reldb` | reldb.init, SQL, CRUD, 事务, 分页, DDL |
208
+ | 缓存操作 | `hai-cache` | cache.init, cache.kv.get/set, TTL, Redis |
209
+ | 文件存储 | `hai-storage` | storage.init, 上传, 下载, S3, 本地存储 |
210
+ | 加密/签名/哈希 | `hai-crypto` | crypto.init, SM2, SM3, SM4, 加密, 签名 |
211
+ | 身份认证/授权 | `hai-iam` | iam.init, 登录, 注册, RBAC, Token, Bearer |
212
+ | AI/LLM/MCP | `hai-ai` | ai.init, LLM, MCP, Agent, 工具调用 |
213
+ | 公共 API 契约 | `hai-api-contract` | apiContract.create, contract, schema, oRPC, HaiResult |
214
+ | API Service 运行时 | `hai-serv` | serv.createApp, Hono, procedures, OpenAPI, docs, route guard |
215
+ | SvelteKit 集成 | `hai-kit` | kit.createHandle, guard, middleware, validate, response |
216
+ | UI 组件 | `hai-ui` | 表单, 按钮, 表格, Modal, Toast, 移动端组件 |
217
+ | typed API 客户端 | `hai-api-client` | apiClient.init, typed client, Bearer, 401 refresh, custom fetch |
218
+ | 原生 App 能力 | `hai-capacitor` | capacitor, 相机, 推送, 状态栏, 设备信息 |
219
+ | 支付 | `hai-payment` | payment, 微信支付, 支付宝, Stripe, 订单 |
220
+
221
+ ### 开发流程
222
+
223
+ | 任务 | 技能 | 触发关键词 |
224
+ | ---------------------- | ---------------- | -------------------------------------- |
225
+ | 创建页面/组件/API/模型 | `hai-app-create` | 新建页面, 添加组件, API 端点, 数据模型 |
226
+ | 代码审查与规范化 | `hai-app-review` | 审查, review, 规范, 优化 |
227
+ | 编写/补充测试 | `hai-app-tests` | 测试, test, 单测, 覆盖率, TDD, E2E |
228
+ | CI/CD 与质量门禁 | `hai-ci` | CI, CD, GitHub Actions, workflow, secret scan |
229
+ | PR / Issue 交付审查 | `hai-pr-review` | PR, pull request, issue, CODEOWNERS, 自动 Review, AI Review |
230
+ | hai-framework 同步 | `hai-framework-sync` | hai-framework, skills 同步, framework:use:local, framework:watch |
231
+
232
+ ## TDD 开发工作流(强制)
233
+
234
+ > 所有新功能开发必须遵循 TDD:**先写测试 → 确认失败 → 再实现 → 确认通过 → 重构**。
235
+
236
+ ### 完整流程
237
+
238
+ ```
239
+ 需求分析 → 设计测试用例 → 编写测试(Red)→ 运行测试确认失败
240
+ → 编写实现(Green)→ 运行测试确认通过
241
+ → 重构优化(Refactor)→ 运行质量门禁
242
+ ```
243
+
244
+ ### 按阶段使用的技能
245
+
246
+ | 阶段 | 主要技能 | 说明 |
247
+ | ------------------- | ---------------- | ------------------------------------------ |
248
+ | 需求分析 + 测试设计 | `hai-app-tests` | 拆分测试点,确定单元测试与 E2E 测试 |
249
+ | Red:编写测试 | `hai-app-tests` | 编写 Vitest 单元测试 + Playwright E2E 测试 |
250
+ | Green:编写实现 | `hai-app-create` | 按照创建规范编写服务/路由/组件 |
251
+ | Refactor:重构审查 | `hai-app-review` | 代码规范审查、分层检查、日志/i18n 合规 |
252
+
253
+ ### 快速指令
254
+
255
+ ```bash
256
+ # Red:运行测试确认新增目标用例因预期行为缺失而失败(既有回归保持通过)
257
+ pnpm --filter <app-name> test
258
+ pnpm --filter <app-name> test:e2e
259
+
260
+ # Green:运行测试确认全部通过
261
+ pnpm --filter <app-name> test
262
+ pnpm --filter <app-name> test:e2e
263
+
264
+ # Refactor:质量门禁
265
+ pnpm typecheck && pnpm lint && pnpm test
266
+ ```
267
+
268
+ ## 统一编码规范
269
+
270
+ ### 强制规则
271
+
272
+ - **禁止 `any`**:不确定类型用 `unknown`,在边界处做类型缩窄
273
+ - **禁止 `console.log`**:使用 `core.logger`(trace/debug/info/warn/error/fatal)
274
+ - **禁止硬编码密钥**:使用环境变量,新增变量需在 `.env` 中写入占位符
275
+ - **禁止硬编码用户文案**:所有用户可见文本必须使用 i18n key
276
+ - **禁止修改 `src/lib/paraglide`** 生成文件
277
+
278
+ ### HaiResult 模式
279
+
280
+ 返回 `HaiResult<T>` 的领域操作按以下模式处理;工具、工厂和流式 API 以签名为准:
281
+
282
+ ```typescript
283
+ const result = await reldb.sql.query('SELECT * FROM users')
284
+ if (!result.success) {
285
+ // result.error: { code, message, details? }
286
+ core.logger.error('Query failed', { error: result.error })
287
+ return kit.response.internalError()
288
+ }
289
+ // result.data 可安全使用
290
+ return kit.response.ok(result.data)
291
+ ```
292
+
293
+ ### 质量门禁
294
+
295
+ 每次变更后按顺序执行:
296
+
297
+ ```bash
298
+ pnpm typecheck # TypeScript 类型检查
299
+ pnpm lint # ESLint 检查
300
+ pnpm test # Vitest 单元测试
301
+ ```
302
+
303
+ ## 标准工作流
304
+
305
+ ### 变更前:需求分析 + 测试设计
306
+
307
+ 1. 列出将修改的文件路径
308
+ 2. 确认哪些类型/接口会变
309
+ 3. 搜索确认引用关系(避免遗漏)
310
+ 4. **设计测试用例清单**(单元测试 + E2E 测试)
311
+
312
+ ### 变更中:TDD 三步走
313
+
314
+ 1. **Red**:编写单元测试(Vitest)+ E2E 测试(Playwright),确认新增目标用例失败、既有回归通过
315
+ 2. **Green**:按技能指引完成功能实现,逐步让测试通过
316
+ 3. **Refactor**:审查代码规范、重构优化
317
+
318
+ ### 变更后:验证
319
+
320
+ 1. `pnpm typecheck` 通过
321
+ 2. `pnpm lint` 通过
322
+ 3. `pnpm test` 通过(单元测试)
323
+ 4. `pnpm --filter <app-name> test:e2e` 通过(E2E 测试)
324
+ 5. 搜索确认所有引用点已更新
325
+
326
+ 原生交付必须单独执行 Tauri/Gradle/Xcode 打包,并在目标 OS/设备验证安装启动、登录/退出、重启会话、安全 TokenStore、真实 API 域名与覆盖升级。Web 构建/E2E 不代替原生验收。保存提交、包 hash、平台/工具链及逐项结果;缺平台写未验证,禁止静默 skip。hai-framework 仓库参考 `.github/workflows/native.yml` 与 desktop-app / mobile-app README 的「原生交付与验收」章节。
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hai-cache
3
- description: 使用 @h-ai/cache 进行内存或 Redis 缓存操作(kv/hash/list/set/zset/分布式锁);当需求涉及缓存读写、TTL 管理、集合运算、排行榜、缓存一致性策略或分布式互斥锁时使用。
3
+ description: "使用 @h-ai/cache 的 Memory/Redis 缓存、TTL、集合、排行榜和锁。"
4
4
  ---
5
5
 
6
6
  # hai-cache
@@ -9,24 +9,20 @@ description: 使用 @h-ai/cache 进行内存或 Redis 缓存操作(kv/hash/lis
9
9
 
10
10
  | 项目 | 契约 |
11
11
  | --- | --- |
12
- | 能力 | 使用 @h-ai/cache 进行内存或 Redis 缓存操作(kv/hash/list/set/zset/分布式锁);当需求涉及缓存读写、TTL 管理、集合运算、排行榜、缓存一致性策略或分布式互斥锁时使用。 |
13
- | 适用场景 | 当任务与 `hai-cache` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
14
- | 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
15
- | 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
16
- | 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
12
+ | 能力 | 使用 @h-ai/cache 的 Memory/Redis 缓存、TTL、集合、排行榜和锁 |
13
+ | 适用场景 | 缓存读写、过期策略或共享资源互斥 |
14
+ | 输入 | CacheConfigInput、key/value、TTL、每次获锁的唯一 owner |
15
+ | 输出 | 缓存和锁操作的 HaiResult,获锁 data 为 boolean |
16
+ | 限制 | 仅服务端;Memory 不跨节点。release/extend 携带本次 owner,避免锁过期后误操作新持有者。 |
17
17
 
18
18
  > `@h-ai/cache` 提供统一缓存接口,支持 Memory 与 Redis 后端,包含 KV / Hash / List / Set / ZSet / 分布式锁 六类操作。
19
19
 
20
20
  内存 KV 在到期时间点即失效。整数计数器拒绝 null/boolean/array、非整数增量和安全整数溢出,失败不修改原值;Hash 的 `__proto__` / `constructor` 名称按普通字段保留。
21
21
 
22
- ---
23
-
24
22
  ## 运行环境
25
23
 
26
24
  > ⚠️ **服务端模块(Node.js only)。** 浏览器端无需直接操作缓存,由服务端模块(如 IAM、Scheduler)内部使用。
27
25
 
28
- ---
29
-
30
26
  ## 适用场景
31
27
 
32
28
  - 缓存热点数据减少数据库查询
@@ -36,8 +32,6 @@ description: 使用 @h-ai/cache 进行内存或 Redis 缓存操作(kv/hash/lis
36
32
  - 排行榜(ZSet)与队列(List)
37
33
  - 分布式锁(多节点部署互斥控制)
38
34
 
39
- ---
40
-
41
35
  ## 使用步骤
42
36
 
43
37
  ### 1. 配置
@@ -68,8 +62,6 @@ await cache.close()
68
62
 
69
63
  `cache.config` 返回的是脱敏后的配置快照;Redis `password` / `url` 等敏感值不会原样暴露给日志或调试输出。
70
64
 
71
- ---
72
-
73
65
  ## 核心 API
74
66
 
75
67
  ### KV 操作(`cache.kv`)
@@ -116,32 +108,35 @@ await cache.zset.zadd('rank:daily', { member: 'u1', score: 100 })
116
108
  | `extend` | 续期锁 TTL(支持 owner 验证) |
117
109
 
118
110
  ```typescript
119
- // 获锁(TTL 30 秒,owner 用于标识持有者)
120
- const acquired = await cache.lock.acquire('my-lock', { ttl: 30, owner: 'node-1' })
111
+ // 每次尝试生成唯一 owner,后续释放/续期复用同一个值
112
+ const owner = core.id.generate()
113
+ const acquired = await cache.lock.acquire('my-lock', { ttl: 30, owner })
121
114
  if (acquired.success && acquired.data) {
122
115
  try {
123
- // 受保护的操作
116
+ // 长任务仅在仍持有锁时续期;失败或 data=false 时停止依赖锁的后续操作
117
+ const extended = await cache.lock.extend('my-lock', 60, owner)
118
+ if (!extended.success || !extended.data) {
119
+ logger.warn('Lock extension failed; protected work cancelled')
120
+ }
121
+ else {
122
+ // 受保护的操作
123
+ }
124
124
  }
125
125
  finally {
126
- await cache.lock.release('my-lock', 'node-1')
126
+ await cache.lock.release('my-lock', owner)
127
127
  }
128
128
  }
129
129
 
130
- // 续期
131
- await cache.lock.extend('my-lock', 60, 'node-1')
132
-
133
130
  // 检查
134
131
  const locked = await cache.lock.isLocked('my-lock')
135
132
  ```
136
133
 
137
134
  **最佳实践:**
138
135
 
139
- - `owner` 使用稳定的节点标识(如 `nodeId`),不要每次随机生成
136
+ - `owner` 每次获锁尝试唯一,释放/续期复用该值;仅用 nodeId 会使同节点旧任务误释放过期后重新获得的锁
140
137
  - 释放锁时传入 `owner` 防止误释放他人锁
141
138
  - Memory 后端适合开发/测试;Redis 后端用 Lua 脚本保证 release/extend 原子性
142
139
 
143
- ---
144
-
145
140
  ## 错误码 — `HaiCacheError`
146
141
 
147
142
  | 错误码 | code | 说明 |
@@ -156,11 +151,9 @@ const locked = await cache.lock.isLocked('my-lock')
156
151
  | `HaiCacheError.UNSUPPORTED_TYPE` | `hai:cache:011` | 不支持的缓存类型 |
157
152
  | `HaiCacheError.CONFIG_ERROR` | `hai:cache:012` | 配置错误 |
158
153
 
159
- ---
160
-
161
154
  ## 常见模式
162
155
 
163
- ### 缓存穿透保护
156
+ ### 缓存命中与回源(未缓存空值,不防穿透)
164
157
 
165
158
  ```typescript
166
159
  async function getUserCached(userId: string) {
@@ -181,22 +174,24 @@ async function getUserCached(userId: string) {
181
174
 
182
175
  ```typescript
183
176
  const lockKey = 'batch:import'
184
- const acquired = await cache.lock.acquire(lockKey, { ttl: 60, owner: nodeId })
177
+ const owner = core.id.generate()
178
+ const acquired = await cache.lock.acquire(lockKey, { ttl: 60, owner })
185
179
  if (acquired.success && acquired.data) {
186
180
  try {
187
181
  await runBatchImport()
188
182
  }
189
183
  finally {
190
- await cache.lock.release(lockKey, nodeId)
184
+ await cache.lock.release(lockKey, owner)
191
185
  }
192
186
  }
193
- else {
187
+ else if (acquired.success) {
194
188
  logger.info('Another node is running the import')
195
189
  }
190
+ else {
191
+ logger.error('Lock acquisition failed', { code: acquired.error.code })
192
+ }
196
193
  ```
197
194
 
198
- ---
199
-
200
195
  ## 相关 Skills
201
196
 
202
197
  - `hai-build`:模块初始化顺序(cache 在 db 之后、iam 之前)