@h-ai/cache 0.1.0-alpha.55 → 0.1.0-alpha.57

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.en.md ADDED
@@ -0,0 +1,159 @@
1
+ # @h-ai/cache
2
+
3
+ [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
4
+
5
+ [Framework home](../../README.en.md) · Related modules: [@h-ai/core](../core/README.en.md)
6
+
7
+ A unified cache module. The `cache` object provides KV / Hash / List / Set / ZSet / distributed lock operations with Memory and Redis backends.
8
+
9
+ Memory KV entries expire at their expiration time. `incr/decr/incrBy/decrBy` accept only safe integers or integer strings; invalid increments and overflow return `OPERATION_FAILED` without changing the original value. Hash names such as `__proto__` / `constructor` remain ordinary fields and do not change the returned object's prototype.
10
+
11
+ ## Use cases
12
+
13
+ - In-memory caching for development and tests
14
+ - Redis caching in production (standalone, URL, Cluster, Sentinel)
15
+ - Set caches for IAM sessions and permissions
16
+ - Distributed locks for mutual exclusion across nodes
17
+
18
+ ## Quick start
19
+
20
+ ```ts
21
+ import { cache, HaiCacheError } from '@h-ai/cache'
22
+
23
+ const initResult = await cache.init({ type: 'memory' })
24
+ if (!initResult.success) {
25
+ throw new Error(initResult.error.message)
26
+ }
27
+
28
+ await cache.kv.set('user:1', { name: '张三' }, { ex: 3600 })
29
+ const user = await cache.kv.get<{ name: string }>('user:1')
30
+
31
+ await cache.hash.hset('profile:1', { age: 18, city: 'Hangzhou' })
32
+ await cache.list.lpush('queue:jobs', 'job-1', 'job-2')
33
+ await cache.set_.sadd('role:admin:perms', 'user.read', 'user.write')
34
+ await cache.zset.zadd('rank', { member: 'u1', score: 100 })
35
+
36
+ // 分布式锁
37
+ const acquired = await cache.lock.acquire('my-lock', { ttl: 30, owner: 'node-1' })
38
+ if (acquired.success && acquired.data) {
39
+ try {
40
+ // 执行受保护的操作
41
+ }
42
+ finally {
43
+ await cache.lock.release('my-lock', 'node-1')
44
+ }
45
+ }
46
+
47
+ if (!user.success && user.error.code === HaiCacheError.NOT_INITIALIZED.code) {
48
+ // 请先调用 cache.init()
49
+ }
50
+
51
+ await cache.close()
52
+ ```
53
+
54
+ `cache.config` returns a **redacted configuration snapshot**. Redis credential fields such as `password` / `url` are sanitized automatically; do not use the snapshot to write back original secrets.
55
+
56
+ ## Initialization options
57
+
58
+ ```ts
59
+ // Memory(开发/测试)
60
+ await cache.init({ type: 'memory' })
61
+
62
+ // Redis 单机
63
+ await cache.init({
64
+ type: 'redis',
65
+ host: 'localhost',
66
+ port: 6379,
67
+ password: 'secret',
68
+ db: 0,
69
+ })
70
+
71
+ // Redis URL(优先级最高)
72
+ await cache.init({
73
+ type: 'redis',
74
+ url: 'redis://:password@localhost:6379/0',
75
+ })
76
+
77
+ // Redis 集群
78
+ await cache.init({
79
+ type: 'redis',
80
+ cluster: [
81
+ { host: 'node1', port: 6379 },
82
+ { host: 'node2', port: 6379 },
83
+ ],
84
+ })
85
+
86
+ // Redis 哨兵
87
+ await cache.init({
88
+ type: 'redis',
89
+ sentinel: {
90
+ sentinels: [{ host: 'sentinel1', port: 26379 }],
91
+ name: 'mymaster',
92
+ },
93
+ })
94
+ ```
95
+
96
+ ## API overview
97
+
98
+ - `cache.kv`: string/object key-value storage and TTL (`set/get/mget/mset/expire/ttl/...`).
99
+ - `cache.hash`: hash structures (`hset/hget/hgetall/...`).
100
+ - `cache.list`: lists (`lpush/rpush/lpop/rpop/...`).
101
+ - `cache.set_`: sets (`sadd/smembers/sismember/...`).
102
+ - `cache.zset`: sorted sets (`zadd/zrange/zrevrange/...`).
103
+ - `cache.lock`: distributed locks (`acquire/release/isLocked/extend`).
104
+ - `CacheProvider`: a public provider contract for advanced integrations and custom backends.
105
+
106
+ ## Distributed locks
107
+
108
+ Distributed mutual exclusion based on SET NX EX, suitable for deployments across multiple nodes.
109
+
110
+ ```ts
111
+ // 获取锁(TTL 30 秒,owner 用于标识持有者)
112
+ const acquired = await cache.lock.acquire('my-lock', { ttl: 30, owner: 'node-1' })
113
+ if (acquired.success && acquired.data) {
114
+ try {
115
+ // 执行受保护操作
116
+ }
117
+ finally {
118
+ await cache.lock.release('my-lock', 'node-1')
119
+ }
120
+ }
121
+
122
+ // 检查锁状态
123
+ const locked = await cache.lock.isLocked('my-lock')
124
+
125
+ // 续期锁
126
+ await cache.lock.extend('my-lock', 60, 'node-1')
127
+ ```
128
+
129
+ - **Memory backend**: Map-based storage with TTL expiration.
130
+ - **Redis backend**: atomic locking with `SET NX EX`; Lua scripts verify the owner for safe release and renewal.
131
+ - `owner` prevents accidental release of another owner's lock; a stable node identifier is recommended for multi-node deployments.
132
+
133
+ ## Error codes
134
+
135
+ All operations return `HaiResult<T>`. Common error codes:
136
+
137
+ | Error code | code | Description |
138
+ | -------------------------------------- | --------------- | ---------------------- |
139
+ | `HaiCacheError.CONNECTION_FAILED` | `hai:cache:001` | Connection failed |
140
+ | `HaiCacheError.OPERATION_FAILED` | `hai:cache:002` | Operation failed |
141
+ | `HaiCacheError.SERIALIZATION_FAILED` | `hai:cache:003` | Serialization failed |
142
+ | `HaiCacheError.DESERIALIZATION_FAILED` | `hai:cache:004` | Deserialization failed |
143
+ | `HaiCacheError.KEY_NOT_FOUND` | `hai:cache:005` | Key not found |
144
+ | `HaiCacheError.TIMEOUT` | `hai:cache:006` | Timeout |
145
+ | `HaiCacheError.NOT_INITIALIZED` | `hai:cache:010` | Not initialized |
146
+ | `HaiCacheError.UNSUPPORTED_TYPE` | `hai:cache:011` | Unsupported cache type |
147
+ | `HaiCacheError.CONFIG_ERROR` | `hai:cache:012` | Invalid configuration |
148
+
149
+ ## Tests
150
+
151
+ ```bash
152
+ pnpm --filter @h-ai/cache test
153
+ ```
154
+
155
+ > Redis tests require Docker.
156
+
157
+ ## License
158
+
159
+ Apache-2.0
package/README.ja.md ADDED
@@ -0,0 +1,159 @@
1
+ # @h-ai/cache
2
+
3
+ [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
4
+
5
+ [フレームワークのホーム](../../README.ja.md) · 関連モジュール:[@h-ai/core](../core/README.ja.md)
6
+
7
+ 統一されたキャッシュモジュールです。`cache` オブジェクトで KV / Hash / List / Set / ZSet / 分散ロックを操作し、メモリーと Redis のバックエンドに対応します。
8
+
9
+ メモリー KV は有効期限に達した時点で無効になります。`incr/decr/incrBy/decrBy` は安全な整数値または整数文字列のみを受け付け、不正な増分やオーバーフローでは元の値を保持して `OPERATION_FAILED` を返します。Hash の `__proto__` / `constructor` などは通常のフィールドとして保持され、戻り値のオブジェクトのプロトタイプを変更しません。
10
+
11
+ ## 用途
12
+
13
+ - 開発・テスト用のメモリーキャッシュ
14
+ - 本番環境の Redis キャッシュ(単一ノード、URL、Cluster、Sentinel)
15
+ - IAM セッション・権限用の集合キャッシュ
16
+ - 複数ノード間の排他制御に使う分散ロック
17
+
18
+ ## クイックスタート
19
+
20
+ ```ts
21
+ import { cache, HaiCacheError } from '@h-ai/cache'
22
+
23
+ const initResult = await cache.init({ type: 'memory' })
24
+ if (!initResult.success) {
25
+ throw new Error(initResult.error.message)
26
+ }
27
+
28
+ await cache.kv.set('user:1', { name: '张三' }, { ex: 3600 })
29
+ const user = await cache.kv.get<{ name: string }>('user:1')
30
+
31
+ await cache.hash.hset('profile:1', { age: 18, city: 'Hangzhou' })
32
+ await cache.list.lpush('queue:jobs', 'job-1', 'job-2')
33
+ await cache.set_.sadd('role:admin:perms', 'user.read', 'user.write')
34
+ await cache.zset.zadd('rank', { member: 'u1', score: 100 })
35
+
36
+ // 分布式锁
37
+ const acquired = await cache.lock.acquire('my-lock', { ttl: 30, owner: 'node-1' })
38
+ if (acquired.success && acquired.data) {
39
+ try {
40
+ // 执行受保护的操作
41
+ }
42
+ finally {
43
+ await cache.lock.release('my-lock', 'node-1')
44
+ }
45
+ }
46
+
47
+ if (!user.success && user.error.code === HaiCacheError.NOT_INITIALIZED.code) {
48
+ // 请先调用 cache.init()
49
+ }
50
+
51
+ await cache.close()
52
+ ```
53
+
54
+ `cache.config` は**機密情報をマスクした設定スナップショット**を返します。Redis の `password` / `url` などの認証情報は自動処理されるため、元の秘密情報を書き戻す用途には使わないでください。
55
+
56
+ ## 初期化設定
57
+
58
+ ```ts
59
+ // Memory(开发/测试)
60
+ await cache.init({ type: 'memory' })
61
+
62
+ // Redis 单机
63
+ await cache.init({
64
+ type: 'redis',
65
+ host: 'localhost',
66
+ port: 6379,
67
+ password: 'secret',
68
+ db: 0,
69
+ })
70
+
71
+ // Redis URL(优先级最高)
72
+ await cache.init({
73
+ type: 'redis',
74
+ url: 'redis://:password@localhost:6379/0',
75
+ })
76
+
77
+ // Redis 集群
78
+ await cache.init({
79
+ type: 'redis',
80
+ cluster: [
81
+ { host: 'node1', port: 6379 },
82
+ { host: 'node2', port: 6379 },
83
+ ],
84
+ })
85
+
86
+ // Redis 哨兵
87
+ await cache.init({
88
+ type: 'redis',
89
+ sentinel: {
90
+ sentinels: [{ host: 'sentinel1', port: 26379 }],
91
+ name: 'mymaster',
92
+ },
93
+ })
94
+ ```
95
+
96
+ ## API 一覧
97
+
98
+ - `cache.kv`:文字列・オブジェクトのキーと値、および TTL(`set/get/mget/mset/expire/ttl/...`)。
99
+ - `cache.hash`:Hash 構造(`hset/hget/hgetall/...`)。
100
+ - `cache.list`:リスト(`lpush/rpush/lpop/rpop/...`)。
101
+ - `cache.set_`:集合(`sadd/smembers/sismember/...`)。
102
+ - `cache.zset`:ソート済み集合(`zadd/zrange/zrevrange/...`)。
103
+ - `cache.lock`:分散ロック(`acquire/release/isLocked/extend`)。
104
+ - `CacheProvider`:高度な統合や独自バックエンド用の公開 Provider 契約。
105
+
106
+ ## 分散ロック
107
+
108
+ SET NX EX を利用する分散排他ロックで、複数ノードのデプロイに適しています。
109
+
110
+ ```ts
111
+ // 获取锁(TTL 30 秒,owner 用于标识持有者)
112
+ const acquired = await cache.lock.acquire('my-lock', { ttl: 30, owner: 'node-1' })
113
+ if (acquired.success && acquired.data) {
114
+ try {
115
+ // 执行受保护操作
116
+ }
117
+ finally {
118
+ await cache.lock.release('my-lock', 'node-1')
119
+ }
120
+ }
121
+
122
+ // 检查锁状态
123
+ const locked = await cache.lock.isLocked('my-lock')
124
+
125
+ // 续期锁
126
+ await cache.lock.extend('my-lock', 60, 'node-1')
127
+ ```
128
+
129
+ - **Memory バックエンド**:Map と TTL による有効期限管理。
130
+ - **Redis バックエンド**:`SET NX EX` でアトミックにロックを取得。Lua スクリプトで owner を検証して安全に解除・延長します。
131
+ - `owner` は他の所有者のロックの誤解除を防ぎます。複数ノードのデプロイでは安定したノード識別子の指定を推奨します。
132
+
133
+ ## エラーコード
134
+
135
+ すべての操作は `HaiResult<T>` を返します。主なエラーコード:
136
+
137
+ | エラーコード | code | 説明 |
138
+ | -------------------------------------- | --------------- | ---------------------- |
139
+ | `HaiCacheError.CONNECTION_FAILED` | `hai:cache:001` | 接続に失敗 |
140
+ | `HaiCacheError.OPERATION_FAILED` | `hai:cache:002` | 操作に失敗 |
141
+ | `HaiCacheError.SERIALIZATION_FAILED` | `hai:cache:003` | シリアライズに失敗 |
142
+ | `HaiCacheError.DESERIALIZATION_FAILED` | `hai:cache:004` | デシリアライズに失敗 |
143
+ | `HaiCacheError.KEY_NOT_FOUND` | `hai:cache:005` | キーが存在しない |
144
+ | `HaiCacheError.TIMEOUT` | `hai:cache:006` | タイムアウト |
145
+ | `HaiCacheError.NOT_INITIALIZED` | `hai:cache:010` | 未初期化 |
146
+ | `HaiCacheError.UNSUPPORTED_TYPE` | `hai:cache:011` | 未対応のキャッシュ種別 |
147
+ | `HaiCacheError.CONFIG_ERROR` | `hai:cache:012` | 設定エラー |
148
+
149
+ ## テスト
150
+
151
+ ```bash
152
+ pnpm --filter @h-ai/cache test
153
+ ```
154
+
155
+ > Redis 関連のテストには Docker が必要です。
156
+
157
+ ## License
158
+
159
+ Apache-2.0
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @h-ai/cache
2
2
 
3
+ [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
4
+
5
+ [框架首页](../../README.md) · 相关模块:[@h-ai/core](../core/README.md)
6
+
3
7
  统一缓存模块,通过 `cache` 对象提供 KV / Hash / List / Set / ZSet / 分布式锁 操作,支持内存与 Redis 两种后端。
4
8
 
5
9
  内存 KV 在到期时间点即视为失效;`incr/decr/incrBy/decrBy` 只接受安全整数数值或整数字符串,非法增量和溢出返回 `OPERATION_FAILED` 并保留原值。Hash 的 `__proto__` / `constructor` 等名称按普通字段保留,不修改返回对象原型。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/cache",
3
3
  "type": "module",
4
- "version": "0.1.0-alpha.55",
4
+ "version": "0.1.0-alpha.57",
5
5
  "description": "Hai Framework cache module with memory and Redis backends.",
6
6
  "license": "Apache-2.0",
7
7
  "exports": {
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "ioredis": "^5.4.2",
27
27
  "zod": "^4.4.3",
28
- "@h-ai/core": "0.1.0-alpha.55"
28
+ "@h-ai/core": "0.1.0-alpha.57"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^25.9.1",