dokv-client

企业级 KV 存储客户端,支持多项目数据隔离,开箱即用。
✨ 特性
- 🚀 零配置 - 内置认证,无需任何配置即可使用
- 🔒 项目隔离 - 通过 projectId 自动隔离不同项目的数据
- 📦 轻量级 - 仅一个依赖,支持 Node.js 和浏览器
- 🔑 TypeScript - 完整的类型定义,优秀的 IDE 支持
- 🔄 自动重试 - 内置重试机制,提高可靠性
- 🎯 简单 API - 直观的方法命名,易于使用
- 🏷️ 命名空间 - 支持多租户数据隔离
- 📊 统计信息 - 内置请求统计和性能监控
- 🛡️ 错误处理 - 完善的错误处理和类型定义
📦 安装
npm install dokv-client
yarn add dokv-client
pnpm add dokv-client
🚀 快速开始
基础使用
import createClient from 'dokv-client'
const kv = createClient('my-saas-app')
await kv.set('user:123', { name: 'John', age: 30 })
const user = await kv.get('user:123')
console.log(user)
await kv.delete('user:123')
const exists = await kv.exists('user:123')
console.log(exists)
多项目隔离示例
const kvA = createClient('project-a')
await kvA.set('user:123', { name: 'Alice' })
const kvB = createClient('project-b')
await kvB.set('user:123', { name: 'Bob' })
console.log(await kvA.get('user:123'))
console.log(await kvB.get('user:123'))
TypeScript 使用
import createClient from 'dokv-client'
import type { KVItem } from 'dokv-client'
interface User {
name: string
age: number
email?: string
}
const kv = createClient('my-saas-app')
await kv.set<User>('user:123', {
name: 'John',
age: 30
})
const user = await kv.get<User>('user:123')
const userInfo = await kv.getInfo<User>('user:123')
高级功能
const kv = createClient('my-saas-app')
await kv.set('cache:data', data, { ttl: 300 })
await kv.set('config', data, {
metadata: { version: '1.0', author: 'admin' }
})
const appKV = kv.namespace('mobile-app')
await appKV.set('user:123', userData)
const keys = await appKV.list()
const adminKV = appKV.namespace('admin')
await adminKV.set('settings', adminConfig)
await kv.mset([
['key1', 'value1'],
['key2', { data: 'value2' }, { ttl: 600 }]
])
const values = await kv.mget(['key1', 'key2'])
const data = await kv.getOrSet('expensive-data',
async () => {
return await fetchExpensiveData()
},
{ ttl: 3600 }
)
📋 API 文档
核心方法
set(key, value, options?) | 设置键值对 | Promise<void> |
get(key, options?) | 获取值 | Promise<T | null> |
getInfo(key, options?) | 获取完整信息 | Promise<KVItem<T> | null> |
delete(key, options?) | 删除键值对 | Promise<boolean> |
exists(key, options?) | 检查是否存在 | Promise<boolean> |
list(options?) | 列出所有键 | Promise<string[]> |
批量操作
mset(entries) | 批量设置 | Promise<KVBatchResult[]> |
mget(keys) | 批量获取 | Promise<Array<T | null>> |
mdelete(keys) | 批量删除 | Promise<KVBatchResult[]> |
实用方法
getOrSet(key, factory, options?) | 缓存模式 | Promise<T> |
namespace(name) | 创建命名空间实例 | KVClient |
clear(namespace?) | 清空数据 | Promise<void> |
healthCheck() | 健康检查 | Promise<boolean> |
getStats() | 获取统计信息 | ClientStats |
⚙️ 配置选项
自定义配置
import { KVClient } from 'dokv-client'
const customKV = new KVClient({
projectId: 'my-saas-app',
endpoint: 'https://your-kv-endpoint.com',
token: 'your-custom-token',
timeout: 10000,
maxRetries: 5,
retryDelay: 2000,
keySeparator: '/',
debug: true
})
环境变量
支持通过环境变量配置(projectId 仍需代码中指定):
DOKV_ENDPOINT=https://custom-endpoint.com
DOKV_TOKEN=custom-token
DOKV_TIMEOUT=10000
DOKV_DEBUG=true
const kv = createClient('my-saas-app')
预定义环境
import { createClientForEnv } from 'dokv-client'
const stagingClient = createClientForEnv('my-saas-app', 'staging')
const prodClient = createClientForEnv('my-saas-app', 'production')
🔧 错误处理
import { KVError, ErrorCode } from 'dokv-client'
try {
await kv.set('key', value)
} catch (error) {
if (error instanceof KVError) {
switch (error.code) {
case ErrorCode.RATE_LIMIT_EXCEEDED:
console.log('Rate limited, waiting...')
await sleep(1000)
break
case ErrorCode.INVALID_KEY:
console.error('Invalid key format')
break
case ErrorCode.PAYLOAD_TOO_LARGE:
console.error('Data too large')
break
default:
console.error(error.message)
}
}
}
💡 最佳实践
1. 键名规范
'user:123'
'session:abc123'
'cache:api:users'
'config:app:theme'
2. 使用命名空间
const webApp = kv.namespace('web')
const mobileApp = kv.namespace('mobile')
const adminApp = kv.namespace('admin')
await webApp.set('config', webConfig)
await mobileApp.set('config', mobileConfig)
await adminApp.set('config', adminConfig)
3. 合理设置 TTL
await kv.set('cache:temp', data, { ttl: 300 })
await kv.set('session:abc', sessionData, { ttl: 3600 })
await kv.set('config:theme', themeConfig, { ttl: 86400 })
await kv.set('user:profile', userData)
4. 批量操作优化
const keys = ['key1', 'key2', 'key3']
for (const key of keys) {
await kv.get(key)
}
const values = await kv.mget(keys)
const promises = keys.map(key => kv.get(key))
const values = await Promise.all(promises)
5. 错误恢复
const data = await kv.getOrSet(
'api:data',
async () => {
const response = await fetch('/api/data')
return response.json()
},
{
ttl: 600,
returnStaleOnError: true
}
)
🔍 监控和调试
获取统计信息
const stats = kv.getStats()
console.log(stats)
kv.resetStats()
调试模式
const debugKV = new KVClient({ debug: true })
健康检查
const isHealthy = await kv.healthCheck()
if (!isHealthy) {
console.error('KV service is not available')
}
import { healthCheck } from 'dokv-client'
const isHealthy = await healthCheck()
📝 实际应用示例
用户会话管理
class SessionManager {
constructor() {
this.kv = kv.namespace('sessions')
}
async createSession(userId, data) {
const sessionId = this.generateSessionId()
const session = {
userId,
data,
createdAt: Date.now()
}
await this.kv.set(sessionId, session, { ttl: 3600 })
return sessionId
}
async getSession(sessionId) {
return await this.kv.get(sessionId)
}
async destroySession(sessionId) {
return await this.kv.delete(sessionId)
}
async extendSession(sessionId, ttl = 3600) {
const session = await this.kv.get(sessionId)
if (session) {
await this.kv.set(sessionId, session, { ttl })
return true
}
return false
}
}
API 缓存管理
class APICache {
constructor(namespace = 'api-cache') {
this.kv = kv.namespace(namespace)
}
async get(endpoint, ttl = 300) {
const cacheKey = this.getCacheKey(endpoint)
return await this.kv.getOrSet(
cacheKey,
async () => {
console.log(`Fetching data for ${endpoint}`)
const response = await fetch(endpoint)
return response.json()
},
{
ttl,
returnStaleOnError: true
}
)
}
async invalidate(endpoint) {
const cacheKey = this.getCacheKey(endpoint)
return await this.kv.delete(cacheKey)
}
async clear() {
return await this.kv.clear()
}
getCacheKey(endpoint) {
return `endpoint:${Buffer.from(endpoint).toString('base64')}`
}
}
配置管理
class ConfigManager {
constructor() {
this.kv = kv.namespace('config')
}
async get(key, defaultValue = null) {
const value = await this.kv.get(key)
return value ?? defaultValue
}
async set(key, value) {
await this.kv.set(key, value, {
metadata: {
updatedAt: new Date().toISOString(),
updatedBy: 'system'
}
})
}
async getAll() {
const keys = await this.kv.list()
const configs = {}
const values = await this.kv.mget(keys)
keys.forEach((key, index) => {
configs[key] = values[index]
})
return configs
}
async reset() {
await this.kv.clear()
}
}
🔄 迁移指南
从原生 fetch 迁移
const response = await fetch('https://dokv.pwtk.cc/kv/my-key', {
headers: {
'Authorization': 'Bearer pwtk-api-key-2025'
}
})
const data = await response.json()
import kv from 'dokv-client'
const data = await kv.get('my-key')
从其他 KV 客户端迁移
await redis.set('key', JSON.stringify(value))
const value = JSON.parse(await redis.get('key'))
await kv.set('key', value)
const value = await kv.get('key')
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📄 许可证
MIT License
📚 相关链接