文档/Storage API
通用开发

Storage API

Storage API

概述

插件存储 SDK 提供两类能力:

  • 文件型持久化存储(usePluginStorage
  • SQLite 结构化存储(usePluginSqlite,需 sdkapi >= 260215

介绍

快速开始

EXAMPLE.TS
import { usePluginStorage } from '@talex-touch/utils/plugin/sdk'

const storage = usePluginStorage()

// 保存配置
await storage.setFile('settings.json', { theme: 'dark', fontSize: 14 })

// 读取配置
const settings = await storage.getFile('settings.json')
console.log(settings) // { theme: 'dark', fontSize: 14 }

SQLite 快速开始(结构化数据)

EXAMPLE.TS
import { usePluginSqlite } from '@talex-touch/utils/plugin/sdk'

const sqlite = usePluginSqlite()

await sqlite.execute(
  'CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, done INTEGER NOT NULL DEFAULT 0)'
)

await sqlite.execute('INSERT INTO todos (title, done) VALUES (?, ?)', ['Write docs', 0])

const result = await sqlite.query<{ id: number; title: string; done: number }>(
  'SELECT id, title, done FROM todos ORDER BY id DESC LIMIT 20'
)
console.log(result.rows)

容量限制

  • 每个插件 10MB,超出后写入会被拒绝
  • 数据存储在 <userData>/config/plugins/<pluginName>/ 目录下
  • 系统自动处理文件名清理,防止路径遍历攻击

SQLite 权限要求

使用 usePluginSqlite() 时,插件 manifest 必须声明:

EXAMPLE.JSON
{
  "sdkapi": 260428,
  "permissions": {
    "required": ["storage.sqlite"],
    "optional": []
  },
  "permissionReasons": {
    "storage.sqlite": "将插件业务数据存储到本地 SQLite 数据库"
  }
}

API 参考

获取 Storage 实例

EXAMPLE.TS
import { usePluginStorage } from '@talex-touch/utils/plugin/sdk'

const storage = usePluginStorage()

注意:必须在插件渲染器上下文中调用。

文件操作

getFile(fileName)

读取存储文件内容。

EXAMPLE.TS
const config = await storage.getFile('config.json')
// 如果文件不存在,返回 null
参数类型说明
fileNamestring文件名(支持子目录如 data/cache.json
返回值Promise<any>文件内容(自动 JSON 解析),不存在返回 null

setFile(fileName, content)

写入存储文件。

EXAMPLE.TS
await storage.setFile('settings.json', { 
  theme: 'dark',
  shortcuts: ['Cmd+K']
})
// 返回 { success: true }
参数类型说明
fileNamestring文件名
contentany要存储的内容(自动 JSON 序列化)
返回值Promise<{ success: boolean, error?: string }>操作结果

deleteFile(fileName)

删除存储文件。

EXAMPLE.TS
await storage.deleteFile('old-cache.json')

listFiles()

列出插件所有存储文件。

EXAMPLE.TS
const files = await storage.listFiles()
// ['settings.json', 'data/cache.json']

clearAll()

清空插件所有存储数据。

EXAMPLE.TS
await storage.clearAll()
// ⚠️ 此操作不可逆

SQLite 操作

execute(sql, params?)
执行插入/更新/删除/DDL 语句。

query<T>(sql, params?)
执行查询语句并返回类型化行数据。

transaction(statements)
在一个事务中执行多条语句(全成功或全回滚)。

EXAMPLE.TS
const sqlite = usePluginSqlite()

await sqlite.transaction([
  {
    sql: 'INSERT INTO todos (title, done) VALUES (?, ?)',
    params: ['A', 0]
  },
  {
    sql: 'INSERT INTO todos (title, done) VALUES (?, ?)',
    params: ['B', 0]
  }
])

高级功能

getStats()

获取存储统计信息。

EXAMPLE.TS
const stats = await storage.getStats()
// {
//   totalSize: 1024,      // 总大小(字节)
//   fileCount: 3,         // 文件数量
//   limit: 10485760,      // 容量限制(10MB)
//   usagePercent: 0.01    // 使用率
// }

getTree()

获取存储目录树结构。

EXAMPLE.TS
const tree = await storage.getTree()
// [
//   { name: 'settings.json', type: 'file', size: 256 },
//   { name: 'data', type: 'directory', children: [...] }
// ]

getFileDetails(fileName)

获取文件详细信息。

EXAMPLE.TS
const details = await storage.getFileDetails('settings.json')
// {
//   name: 'settings.json',
//   size: 256,
//   createdAt: 1702123456789,
//   modifiedAt: 1702123456789
// }

openFolder()

在系统文件管理器中打开插件存储目录。

EXAMPLE.TS
await storage.openFolder()
// 打开 Finder/Explorer

监听变更

监听存储文件的变化,适用于多窗口同步场景。

EXAMPLE.TS
const unsubscribe = storage.onDidChange('settings.json', (data) => {
  console.log('配置已更新:', data)
  // 重新加载配置
})

// 停止监听
unsubscribe()

技术原理

  • 数据以文件形式保存在插件独立目录中,避免跨插件访问。
  • 写入时自动进行文件名清理与 JSON 序列化,降低安全风险。
  • SQLite 数据文件位于 <userData>/modules/plugins/<pluginName>/data/plugin-sdk.sqlite

最佳实践

1. 结构化配置管理

EXAMPLE.TS
interface PluginSettings {
  theme: 'light' | 'dark'
  language: string
  shortcuts: Record<string, string>
}

async function loadSettings(): Promise<PluginSettings> {
  const defaults: PluginSettings = {
    theme: 'dark',
    language: 'zh-CN',
    shortcuts: {}
  }
  
  const saved = await storage.getFile('settings.json')
  return { ...defaults, ...saved }
}

async function saveSettings(settings: PluginSettings) {
  await storage.setFile('settings.json', settings)
}

2. 缓存过期处理

EXAMPLE.TS
interface CacheEntry<T> {
  data: T
  expiresAt: number
}

async function getCached<T>(key: string): Promise<T | null> {
  const entry = await storage.getFile(`cache/${key}.json`) as CacheEntry<T> | null
  
  if (!entry) return null
  if (Date.now() > entry.expiresAt) {
    await storage.deleteFile(`cache/${key}.json`)
    return null
  }
  
  return entry.data
}

async function setCache<T>(key: string, data: T, ttlMs: number = 3600000) {
  const entry: CacheEntry<T> = {
    data,
    expiresAt: Date.now() + ttlMs
  }
  await storage.setFile(`cache/${key}.json`, entry)
}

3. 容量监控

EXAMPLE.TS
async function checkStorageQuota() {
  const stats = await storage.getStats()
  
  if (stats.usagePercent > 0.8) {
    console.warn('[Plugin] 存储空间使用超过 80%,考虑清理旧数据')
    // 清理过期缓存
    await cleanExpiredCache()
  }
}

调试技巧

  1. 查看当前存储内容:使用 openFolder() 直接查看文件
  2. DevTools 调试pnpm core:dev 模式下会在 Console 打印存储变更日志
  3. IPC 命令:使用 plugin:storage:get-file 直接查询

类型定义

EXAMPLE.TS
interface StorageStats {
  totalSize: number
  fileCount: number
  limit: number
  usagePercent: number
}

interface StorageTreeNode {
  name: string
  type: 'file' | 'directory'
  size?: number
  children?: StorageTreeNode[]
}

interface FileDetails {
  name: string
  size: number
  createdAt: number
  modifiedAt: number
}