{"_id":"@aiao/rxdb-plugin-storage","_rev":"6-d8b97a1fd810d40aeb036d1311e12c5d","name":"@aiao/rxdb-plugin-storage","dist-tags":{"latest":"0.0.25"},"versions":{"0.0.20":{"name":"@aiao/rxdb-plugin-storage","version":"0.0.20","_id":"@aiao/rxdb-plugin-storage@0.0.20","maintainers":[{"name":"aiao","email":"hero63418@gmail.com"}],"dist":{"shasum":"27124fe117c6d65edd751434c7f330fc53c695d8","tarball":"https://registry.npmjs.org/@aiao/rxdb-plugin-storage/-/rxdb-plugin-storage-0.0.20.tgz","fileCount":18,"integrity":"sha512-u7wFTxy6NVB1vkV4385485VvqV2rSUu1IbuUUUzr69buUtXm19p3LLzM9u9maHcBx369zKF4qZhn+wQzMYixmA==","signatures":[{"sig":"MEUCIQCBl3irD4SS4zOz3dnTCP2RDatACrOXoSEMq1cmTngYoAIgNM9jRm/ArwS6vE683LY9ScJdCELVIfgciihMKVvMIZI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41682},"main":"./dist/index.js","type":"module","_from":"file:aiao-rxdb-plugin-storage-0.0.20.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","@aiao/source":"./src/index.ts"},"./package.json":"./package.json"},"_npmUser":{"name":"aiao","email":"hero63418@gmail.com"},"_resolved":"/private/var/folders/1s/1sk5kvms7jj4z6glj40__v300000gn/T/4cb9a64b162ca1d42139542386f3fd96/aiao-rxdb-plugin-storage-0.0.20.tgz","_integrity":"sha512-u7wFTxy6NVB1vkV4385485VvqV2rSUu1IbuUUUzr69buUtXm19p3LLzM9u9maHcBx369zKF4qZhn+wQzMYixmA==","_npmVersion":"11.9.0","description":"> Implements: [US-502 Storage 插件](../../requirements/stories/plugin/US-502-storage-plugin.md)","directories":{},"_nodeVersion":"24.14.0","dependencies":{"rxjs":"^7.8.2","@aiao/rxdb":"0.0.20"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@aiao/rxdb-adapter-wa-sqlite":"0.0.20"},"_npmOperationalInternal":{"tmp":"tmp/rxdb-plugin-storage_0.0.20_1779247067468_0.8386196268109831","host":"s3://npm-registry-packages-npm-production"}},"0.0.21":{"name":"@aiao/rxdb-plugin-storage","version":"0.0.21","_id":"@aiao/rxdb-plugin-storage@0.0.21","maintainers":[{"name":"aiao","email":"hero63418@gmail.com"}],"dist":{"shasum":"583369c75afc956e00c9aef7a216c87d27ea2380","tarball":"https://registry.npmjs.org/@aiao/rxdb-plugin-storage/-/rxdb-plugin-storage-0.0.21.tgz","fileCount":18,"integrity":"sha512-gN6LT1AdG0lUQW2RLh45+jrvSdZkacsP+n2HW1ShH8nWGABMVRHqgFHilK6Qaj8bgFo/YH8gRP6ZtM1qbypkxg==","signatures":[{"sig":"MEUCIQCsVbiy1bs3ASrj8JJscynP+M3ffR2kIGHDSQKCdEcbrgIgaInDsz6xvlIwn15vyGRH4SUjJphNntq+Yh3h0nyvwwU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46447},"main":"./dist/index.js","type":"module","_from":"file:aiao-rxdb-plugin-storage-0.0.21.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","@aiao/source":"./src/index.ts"},"./package.json":"./package.json"},"_npmUser":{"name":"aiao","email":"hero63418@gmail.com"},"_resolved":"/private/var/folders/1s/1sk5kvms7jj4z6glj40__v300000gn/T/59771025c1cfb2fd61ff2f084c711cfc/aiao-rxdb-plugin-storage-0.0.21.tgz","_integrity":"sha512-gN6LT1AdG0lUQW2RLh45+jrvSdZkacsP+n2HW1ShH8nWGABMVRHqgFHilK6Qaj8bgFo/YH8gRP6ZtM1qbypkxg==","_npmVersion":"11.16.0","description":"> Implements: [US-502 Storage 插件](../../requirements/stories/plugin/US-502-storage-plugin.md)","directories":{},"_nodeVersion":"24.18.0","dependencies":{"rxjs":"^7.8.2","@aiao/rxdb":"0.0.21"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@aiao/rxdb-adapter-wa-sqlite":"0.0.21"},"_npmOperationalInternal":{"tmp":"tmp/rxdb-plugin-storage_0.0.21_1784362953101_0.9383048859165763","host":"s3://npm-registry-packages-npm-production"}},"0.0.22":{"name":"@aiao/rxdb-plugin-storage","version":"0.0.22","_id":"@aiao/rxdb-plugin-storage@0.0.22","maintainers":[{"name":"aiao","email":"hero63418@gmail.com"}],"dist":{"shasum":"1c52d22552cbaa766cce70e2b0f301757170bbc4","tarball":"https://registry.npmjs.org/@aiao/rxdb-plugin-storage/-/rxdb-plugin-storage-0.0.22.tgz","fileCount":18,"integrity":"sha512-O9fJpXIsfj9NBkPp6n6tPDOk3cFCdnnz0rXNTrZDYuNGU05jxcdZOLVRhQCJPFPhsSCgWQhObBRKyazEE3JePQ==","signatures":[{"sig":"MEUCIQDHrCzlJuxHOCts5yjhQzFZ/MklKEOyZsMXgPEpOvatiAIgLgEUaTKWaSlekTqAmW0Vu0N+6VpnEcGS/3WFQZMXFBs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46447},"main":"./dist/index.js","type":"module","_from":"file:aiao-rxdb-plugin-storage-0.0.22.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","@aiao/source":"./src/index.ts"},"./package.json":"./package.json"},"_npmUser":{"name":"aiao","email":"hero63418@gmail.com"},"_resolved":"/private/var/folders/1s/1sk5kvms7jj4z6glj40__v300000gn/T/7b062e3857a1e0e7c7df1ea31a12e995/aiao-rxdb-plugin-storage-0.0.22.tgz","_integrity":"sha512-O9fJpXIsfj9NBkPp6n6tPDOk3cFCdnnz0rXNTrZDYuNGU05jxcdZOLVRhQCJPFPhsSCgWQhObBRKyazEE3JePQ==","_npmVersion":"10.9.2","description":"> Implements: [US-502 Storage 插件](../../requirements/stories/plugin/US-502-storage-plugin.md)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"rxjs":"^7.8.2","@aiao/rxdb":"0.0.22"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@aiao/rxdb-adapter-wa-sqlite":"0.0.22"},"_npmOperationalInternal":{"tmp":"tmp/rxdb-plugin-storage_0.0.22_1785482860563_0.054721219118139874","host":"s3://npm-registry-packages-npm-production"}},"0.0.23":{"name":"@aiao/rxdb-plugin-storage","version":"0.0.23","_id":"@aiao/rxdb-plugin-storage@0.0.23","maintainers":[{"name":"aiao","email":"hero63418@gmail.com"}],"dist":{"shasum":"fb93e897acceaf96105703ee1c0c7601f7c39cbf","tarball":"https://registry.npmjs.org/@aiao/rxdb-plugin-storage/-/rxdb-plugin-storage-0.0.23.tgz","fileCount":18,"integrity":"sha512-tQKVx9m+tNxdglC+5Xa/t11PFCtWl33MYNtWbrLmEXf0apgI1vlF+mhMItsEYU9du/AeHKPH/1UjiawNBBeNCQ==","signatures":[{"sig":"MEYCIQDqoAxAf8MbaqXbcW1NExCu5clQtCkQUxxbJ9sD61/PcAIhAPLvUVh6DoRbtEromjOEKbqZoRc11eEnUO14LqK2G5je","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46447},"main":"./dist/index.js","type":"module","_from":"file:aiao-rxdb-plugin-storage-0.0.23.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","@aiao/source":"./src/index.ts"},"./package.json":"./package.json"},"_npmUser":{"name":"aiao","email":"hero63418@gmail.com"},"_resolved":"/private/var/folders/1s/1sk5kvms7jj4z6glj40__v300000gn/T/12242c9b73f67a988bd9244a00d143d4/aiao-rxdb-plugin-storage-0.0.23.tgz","_integrity":"sha512-tQKVx9m+tNxdglC+5Xa/t11PFCtWl33MYNtWbrLmEXf0apgI1vlF+mhMItsEYU9du/AeHKPH/1UjiawNBBeNCQ==","_npmVersion":"10.9.2","description":"> Implements: [US-502 Storage 插件](../../requirements/stories/plugin/US-502-storage-plugin.md)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"rxjs":"^7.8.2","@aiao/rxdb":"0.0.23"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@aiao/rxdb-adapter-wa-sqlite":"0.0.23"},"_npmOperationalInternal":{"tmp":"tmp/rxdb-plugin-storage_0.0.23_1785736186049_0.40083442476170505","host":"s3://npm-registry-packages-npm-production"}},"0.0.24":{"name":"@aiao/rxdb-plugin-storage","version":"0.0.24","license":"MIT","_id":"@aiao/rxdb-plugin-storage@0.0.24","maintainers":[{"name":"aiao","email":"hero63418@gmail.com"}],"dist":{"shasum":"3ddfb4ac4401f845449be75b178092f32ef46ac3","tarball":"https://registry.npmjs.org/@aiao/rxdb-plugin-storage/-/rxdb-plugin-storage-0.0.24.tgz","fileCount":28,"integrity":"sha512-DqMcAuU0sgF36j5sER1nTBh3q9HcDaKBr3Ovz8fQi9VVR2h3PiiF8meaGGBLtgBgH9j099V8F4+PAk5f2mzXUA==","signatures":[{"sig":"MEUCIAYD695f24jNaWTZm7oFiAstTvZ8azZT+DND3wvrKXYTAiEA+P3Ggjx54dfBCcecSZNmlmVjrp53ZGILA2DTyTVzA7U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":161426},"main":"./dist/index.js","type":"module","_from":"file:aiao-rxdb-plugin-storage-0.0.24.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"_npmUser":{"name":"aiao","email":"hero63418@gmail.com"},"_resolved":"/private/var/folders/1s/1sk5kvms7jj4z6glj40__v300000gn/T/e6c1282eb1197e74e8837d3e75c64801/aiao-rxdb-plugin-storage-0.0.24.tgz","_integrity":"sha512-DqMcAuU0sgF36j5sER1nTBh3q9HcDaKBr3Ovz8fQi9VVR2h3PiiF8meaGGBLtgBgH9j099V8F4+PAk5f2mzXUA==","_npmVersion":"11.19.0","description":"> Implements: [US-502 Storage 插件](https://github.com/aiao-io/aiao/blob/main/requirements/stories/plugin/US-502-storage-plugin.md)","directories":{},"_nodeVersion":"26.7.0","dependencies":{"rxjs":"^7.8.2","@aiao/rxdb":"0.0.24"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@aiao/rxdb-adapter-wa-sqlite":"0.0.24"},"_npmOperationalInternal":{"tmp":"tmp/rxdb-plugin-storage_0.0.24_1786439131814_0.6550627596044969","host":"s3://npm-registry-packages-npm-production"}},"0.0.25":{"name":"@aiao/rxdb-plugin-storage","version":"0.0.25","license":"MIT","repository":{"type":"git","url":"git+https://github.com/aiao-io/rxdb.git","directory":"packages/rxdb-plugin-storage"},"type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{"./package.json":"./package.json",".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"publishConfig":{"access":"public"},"dependencies":{"rxjs":"^7.8.2","@aiao/rxdb":"0.0.25"},"devDependencies":{"@aiao/rxdb-adapter-wa-sqlite":"0.0.25"},"_id":"@aiao/rxdb-plugin-storage@0.0.25","description":"> Implements: [US-502 Storage 插件](https://github.com/aiao-io/rxdb/blob/main/requirements/stories/plugin/US-502-storage-plugin.md)","bugs":{"url":"https://github.com/aiao-io/rxdb/issues"},"homepage":"https://github.com/aiao-io/rxdb#readme","_integrity":"sha512-dGaN1nM6xdX3oR28q6HlSPctMIZfwvmnEPvMh1Tsnvm83P/PnJ1MYUObkeYGCdAu4JlD0QWu2eIXWwylkMF9bw==","_resolved":"/tmp/6908980a1728cf31ea6186933f9a29a1/aiao-rxdb-plugin-storage-0.0.25.tgz","_from":"file:aiao-rxdb-plugin-storage-0.0.25.tgz","_nodeVersion":"26.7.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-dGaN1nM6xdX3oR28q6HlSPctMIZfwvmnEPvMh1Tsnvm83P/PnJ1MYUObkeYGCdAu4JlD0QWu2eIXWwylkMF9bw==","shasum":"e8c798beef20341472a15c9b54211a3c1e4a2a3c","tarball":"https://registry.npmjs.org/@aiao/rxdb-plugin-storage/-/rxdb-plugin-storage-0.0.25.tgz","fileCount":28,"unpackedSize":161570,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aiao%2frxdb-plugin-storage@0.0.25","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDhCEaGkSX/IXmM0gp1tlTiSZRD5dxeUW2Bg5tWrBg8tgIgXt7Dd9npIEbmZEbF88E7cHM5nLXXPioXwVjHm18LxUM="}]},"_npmUser":{"name":"aiao","email":"hero63418@gmail.com"},"directories":{},"maintainers":[{"name":"aiao","email":"hero63418@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rxdb-plugin-storage_0.0.25_1786694786846_0.7163288714246425"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-20T03:17:47.321Z","modified":"2026-08-14T08:06:27.447Z","0.0.20":"2026-05-20T03:17:47.667Z","0.0.21":"2026-07-18T08:22:33.251Z","0.0.22":"2026-07-31T07:27:40.742Z","0.0.23":"2026-08-03T05:49:46.183Z","0.0.24":"2026-08-11T09:05:31.958Z","0.0.25":"2026-08-14T08:06:27.042Z"},"license":"MIT","description":"> Implements: [US-502 Storage 插件](https://github.com/aiao-io/rxdb/blob/main/requirements/stories/plugin/US-502-storage-plugin.md)","maintainers":[{"name":"aiao","email":"hero63418@gmail.com"}],"readme":"# @aiao/rxdb-plugin-storage\n\n> Implements: [US-502 Storage 插件](https://github.com/aiao-io/rxdb/blob/main/requirements/stories/plugin/US-502-storage-plugin.md)\n\n基于 RxDB 与 Origin Private File System（OPFS）的浏览器文件存储插件：文件体写入 OPFS，文件元数据写入 RxDB。\n\n## 能力范围\n\n- 上传、覆盖、读取、删除和按目录清理文件\n- 创建、列出和重命名目录\n- 重命名文件\n- 从远程 URL 拉取并永久缓存到 OPFS\n- 通过 `Blob` URL 预览或下载文件\n- 通过 RxDB 查询、监听文件元数据\n- 对文件体与元数据的跨存储更新执行补偿回滚\n\n以下能力尚未实现：\n\n- 自定义 `rxdb-file://` 协议或 `file://` URL\n- stale-while-revalidate、ETag、TTL 或远程版本协商\n- 缩略图生成和多级加载链路\n- LRU 淘汰、流式分块上传和断点续传\n- 跨设备文件体同步\n\n## 数据模型\n\n```ts\ninterface StorageFileMeta {\n  id: string;\n  name: string;\n  mimeType: string;\n  size: number;\n  opfsPath: string;\n  contentVersion: number;\n  createdAt: Date;\n  updatedAt: Date;\n}\n```\n\n- `opfsPath` 是相对于插件 `rootDir` 的路径。\n- `contentVersion` 在覆盖写入或远程缓存更新时递增。\n- 文件名和目录名只允许单个合法路径段；`/`、`\\\\`、空段、`.`、`..` 和首尾空格会被拒绝，不会被静默改写。\n\n## 公开 API\n\n```ts\ninterface RxDBStoragePluginOptions {\n  rootDir?: string;\n  previewLimitBytes?: number;\n}\n\ninterface UploadOptions {\n  path?: string;\n  overwrite?: boolean;\n}\n\ninterface FetchRemoteOptions {\n  url: string;\n  mimeType?: string;\n  signal?: AbortSignal;\n}\n\ninterface RenameOptions {\n  overwrite?: boolean;\n}\n\nclass RxdbFileStorage {\n  readonly activeObjectUrlCount: number;\n\n  init(): Promise<void>;\n\n  upload(file: File, options?: UploadOptions): Promise<StorageFileMeta>;\n  read(fileId: string): Promise<Blob>;\n  fetch(opfsPath: string, options: FetchRemoteOptions): Promise<Blob>;\n\n  preview(fileId: string): Promise<StoragePreviewResult>;\n  createObjectUrl(fileId: string): Promise<string>;\n  revokeObjectUrl(url: string): void;\n  download(fileId: string, options?: { suggestedName?: string }): Promise<void>;\n\n  getMeta(fileId: string): Promise<StorageFileMeta | null>;\n  list(options?: { path?: string; recursive?: boolean }): Promise<StorageFileMeta[]>;\n  listEntries(options?: { path?: string }): Promise<StorageBrowserEntry[]>;\n  watch(fileId: string): Observable<StorageFileMeta | null>;\n\n  createDirectory(name: string, options?: { path?: string }): Promise<string>;\n  rename(fileId: string, newName: string, options?: RenameOptions): Promise<StorageFileMeta>;\n  renameDirectory(directoryPath: string, newName: string, options?: RenameOptions): Promise<string>;\n  delete(fileId: string): Promise<void>;\n  clear(path?: string): Promise<void>;\n\n  destroy(): void;\n}\n```\n\n`list()` 的目录语义：\n\n- 省略 `path` — 返回整库全部文件元数据（跨目录）。\n- 指定 `path` — 只返回该目录的**直属**文件；`''` 与 `'/'` 等价，都表示根目录。\n- 指定 `path` + `recursive: true` — 连同子目录一并返回。\n\n`listEntries()` 只看直属层级，同时返回直属文件和子目录。\n\n`fetch()` 的缓存键是规范化后的 `opfsPath`：\n\n- 已有缓存时直接返回 OPFS 文件，不发网络请求。\n- 同一路径并发请求共享一个 in-flight 请求。\n- 非 2xx、离线、Abort 或 MIME 缺失不会污染现有缓存。\n- 这是永久缓存，不包含自动刷新策略。\n\n## 错误类型\n\n```ts\nStorageInvalidPathError;\nStorageConflictError;\nStorageUnavailableError;\nStoragePreviewLimitError;\nStorageOfflineError;\nStorageFetchError;\nStorageMimeTypeMissingError;\n```\n\n调用方应按错误类型处理，不要匹配英文错误消息。\n\n当主操作失败且补偿回滚也失败时，服务会抛 `AggregateError`，其中第一个错误仍是原始失败原因。\n\n## 使用方式\n\n```ts\nimport { rxDBPluginStorage } from '@aiao/rxdb-plugin-storage';\n\nrxdb.use(rxDBPluginStorage, {\n  rootDir: 'files',\n  previewLimitBytes: 50 * 1024 * 1024\n});\n\nawait rxdb.storage.init();\n\nconst meta = await rxdb.storage.upload(file, {\n  path: '/avatars',\n  overwrite: true\n});\n\nconst preview = await rxdb.storage.preview(meta.id);\ntry {\n  image.src = preview.url;\n} finally {\n  preview.dispose();\n}\n```\n\n远程缓存：\n\n```ts\nconst blob = await rxdb.storage.fetch('images/avatar.png', {\n  url: 'https://static.example.com/avatar.png',\n  signal: abortController.signal\n});\n```\n\n## 运行要求\n\n- `rxdb.config.sync.local.adapter` 必须存在，元数据必须落到本地适配器。\n- 运行环境必须支持 `navigator.storage.getDirectory()`。\n- `showSaveFilePicker` 可用时 `download()` 使用文件选择器；否则回退到临时 `<a download>`。\n- `watch()` 监听本插件触发的元数据变化，不监视其他代码直接修改 OPFS 的行为。\n- `destroy()` 会回收本实例创建的全部对象 URL。\n\n## 一致性策略\n\nOPFS 与 RxDB 不共享事务。插件采用补偿日志维持用户可见一致性：\n\n- 写入失败：恢复旧文件，或删除本次新建的孤儿文件。\n- 元数据创建/更新失败：恢复对应文件体。\n- 删除文件失败：重建已删除的元数据。\n- 文件或目录重命名失败：按逆序恢复元数据、目标文件和本次新建目录。\n\n这不是跨进程的分布式事务；同一路径仍应由一个应用实例串行修改。\n\n## 开发命令\n\n```bash\npnpm nx run rxdb-plugin-storage:typecheck\npnpm nx run rxdb-plugin-storage:lint --max-warnings=0\npnpm nx test rxdb-plugin-storage --run --browser.enabled=false --coverage.enabled=false\npnpm nx run rxdb-plugin-storage:test-browser --run --coverage.enabled=false\npnpm nx run rxdb-plugin-storage:build\n```\n","readmeFilename":"README.md","homepage":"https://github.com/aiao-io/rxdb#readme","repository":{"type":"git","url":"git+https://github.com/aiao-io/rxdb.git","directory":"packages/rxdb-plugin-storage"},"bugs":{"url":"https://github.com/aiao-io/rxdb/issues"}}