百科.dev
全部条目在线工具AI 编程趋势榜开源项目技术资讯提交条目
登录
< 返回工具列表
W

web-dc-api

> 编程语言
开源

web-dc-api是一个革命性的去中心化 Web 开发 SDK,让您无需任何服务器即可构建完整的互联网应用。

772 stars0 点赞1 次浏览
访问官网GitHub

工具介绍

web-dc-api是一个革命性的去中心化 Web 开发 SDK,让您无需任何服务器即可构建完整的互联网应用。

Web DC API

web-dc-api 是面向浏览器的去中心化应用 SDK。它把钱包身份、用户私有数据库、共享 KeyValue、文件、评论、消息、AI 代理、实时通信、白板和支付能力统一在一个 DC 实例中。

本文档对应仓库当前 SDK 0.2.72,示例以当前 TypeScript 类型和实现为准。

目录

  • 能力总览
  • 运行要求
  • 安装
  • 5 分钟接入
  • 初始化配置
  • 调用约定与生命周期
  • React 接入
  • 认证
  • ThreadDB 用户数据库
  • KeyValue 共享存储
    • 主题权限设计技巧
  • 文件
    • 上传文件夹
    • 遍历目录并按路径读取
    • 从代码生成目录
  • Service Worker 媒体访问
  • 评论
    • 鉴权评论主题
  • 消息与 RTM
  • AI 代理
  • RTC 音视频
  • 实时白板
  • 支付
  • 缓存与工具
  • 高级能力
  • 常见问题
  • API 索引

能力总览

需求 模块/导出 适合存储或处理 关键入口 额外前置条件
钱包登录与身份 dc.auth 登录、签名、解密、用户空间 accountLoginWithWallet dc.init()
用户私有结构化数据 dc.db 设置、笔记、草稿、个人记录 dc.initUserDB、create、find、save 登录后初始化数据库
多用户共享数据 dc.keyValue 配置、商品、排行榜、全局状态 createStore、createSharedStore、set、getWithIndex 登录;创建者公钥和权限配置
类型化 KV 仓储 EntityRepository 基于 KeyValue 的实体、索引查询 save、findById、findByIndex 已获得 KeyValueDB
文件与目录 dc.file 加密上传、CID 下载、目录遍历、流式读取 addFile、addFolder、getFileFromDir、getSeekableFileStream 登录;保管好加密密钥
时间线与留言 dc.comment 动态、评论、回复、点赞/踩/转发 addThemeObj、publishCommentToTheme 登录;明确主题作者
离线消息箱 dc.message 通知、私信、稍后拉取的消息 sendMsgToUserBox、getMsgFromUserBox 登录
在线实时消息 dc.rtm 在线单聊、在线状态、信令接收 login、sendMessageToPeer RTM Token,或可自动取 Token 的 AI 代理配置
AI 与 MCP dc.aiproxy 流式模型调用、MCP、异步资源、实时语音 DoAIProxyCall、GenerateAndPollAIResource 服务配置和用户授权
实时音视频 dc.rtc 通话、会议、屏幕共享、实时房间消息 init、callPeer、joinRoom RTC Token 服务;呼叫信令另需 RTM 登录
协作白板 dc.whiteboard 绘制、文档、翻页、视角同步 init、joinRoom、getWhiteboard 白板 Token 服务;邀请功能另需 RTM 登录
支付 dc.pay 套餐、订单、扫码支付、托管收银台 config、listRenewPackages、createPayOrder 支付服务地址
短期分布式缓存 dc.cache 有过期时间的临时值 setCacheKey、getCacheValue 登录
网络与密钥工具 dc.client / dc.util 节点信息、对称密钥、应用信息 getHostID、createSymmetricKey dc.init()

三种数据能力怎么选

能力 数据边界 查询方式 典型场景
ThreadDB (dc.db) 当前用户专属,跨设备同步 JSON 条件、排序、游标 用户设置、笔记、私有业务数据
普通 KeyValue (createStore) 同一个 key 可按写入用户分别保存 key、写入者、索引、时间 用户提交、排行榜、多人共享记录
共享 KeyValue (createSharedStore) 同一个 key 全局只保留最新值 key、索引、时间 全局配置、公告、状态标志

评论系统适合按时间线组织互动内容;消息箱适合发给指定用户;它们不应替代通用数据库。

运行要求

  • SDK 的主要运行目标是现代浏览器,而不是纯 Node.js 服务端。
  • 核心能力要求浏览器支持 ES2020、Web Crypto、IndexedDB 和 WebSocket。
  • 文件流读取还需要 ReadableStream;wrapWorker / exposeDC 等 Worker 封装需要 Web Worker。只使用核心模块时不必把 Web Worker 视为强制前提。
  • 钱包登录会打开钱包页面,请从用户点击等真实交互中触发,避免被浏览器拦截弹窗。
  • 摄像头、麦克风、屏幕共享和 Service Worker 需要 HTTPS;本地开发可使用 localhost。
  • 包入口包含依赖 window 等浏览器全局对象的 RTC/白板能力。SSR 框架中不要在服务端模块顶层导入 web-dc-api;应从客户端组件加载,或使用关闭 SSR 的动态导入,然后只在客户端创建 DC。
  • appId 是数据命名空间的一部分。上线后不要随意修改,否则应用会访问到不同的数据空间。

安装

npm / pnpm / yarn

bash
npm install web-dc-api
bash
pnpm add web-dc-api
bash
yarn add web-dc-api

包同时提供 ESM、CommonJS 和 TypeScript 类型。应用代码应从包根入口导入:

typescript
import { DC, LogLevel, ThemePermission } from "web-dc-api";

不要从 web-dc-api/lib/... 或未声明的 web-dc-api/dist/... 路径深层导入;包的公开 exports 只保证根入口、web-dc-api/sw.js 和 web-dc-api/package.json。

CDN

CDN 版本还需要先加载 grpc-libp2p-client。建议在生产环境固定版本:

xml

5 分钟接入

下面的示例完成 SDK 初始化、钱包登录、用户数据库初始化、写入和查询。链节点地址及应用信息应由部署配置提供。

…

登录成功后,account 的常用字段是:

字段 类型 用途
nftAccount string 面向用户显示的账号
appAccount Uint8Array 当前应用专用账号原始字节
account string 应用账号字符串,可用于存储或业务标识
ethAccount string EVM 兼容账号
dc.publicKey?.string() string 当前 DC 身份公钥;钱包登录成功后才是当前用户的应用公钥

dc.init() 的第 4 步会先创建临时身份,因此不能只用 dc.publicKey 是否存在来判断钱包登录状态。业务模块调用前应以 accountLoginWithWallet() 成功返回 Account 为准;需要在其他代码路径校验时,同时检查 dc.userInfo 和 dc.publicKey。正常退出请使用 await dc.exit(),不要只调用 auth.exitLogin() 后继续复用旧身份字段。

初始化配置

typescript
new DC({
  wssUrl,
  backWssUrl,
  appInfo,
  swUrl,
  logLevel,
});
字段 必填 说明
wssUrl 是 主链 WebSocket 地址
backWssUrl 是 主链连接失败时使用的备用地址;可以和主地址相同
appInfo.appId 业务上必填 稳定且唯一的应用 ID,也是数据命名空间的一部分
appInfo.appName 业务上必填 钱包及界面显示的应用名称
appInfo.appVersion 否 应用展示版本;它不是 ThreadDB 的 schema 版本
appInfo.appIcon 否 应用图标 URL
appInfo.appUrl 否 应用 URL
appInfo.themeColor 否 钱包页面使用的主题色
appInfo.rtcAppId 否 RTC/RTM 服务需要的应用 ID
swUrl 否 文件流 Service Worker 脚本地址;未设置时文件模块会尝试使用同源 /sw.js
logLevel 否 SDK 日志级别,例如 LogLevel.WARN

dc.init() 可重复调用;实例已经初始化时会直接返回 true。应用中应复用一个实例,避免建立重复的 P2P 和数据库连接。

文件模块初始化时会自动尝试注册 Service Worker。浏览器不支持、页面不是 HTTPS/localhost 或脚本不存在时,注册失败只会记录日志,不会导致整个 dc.init() 失败;不需要媒体 Range 请求或 seek 时可忽略该能力。SDK 构建产物包含 dist/sw.js,但浏览器要求 Service Worker 与应用同源,因此接入方仍需把它部署到应用根目录。完整步骤见 Service Worker 媒体访问。

调用约定与生命周期

两类错误返回方式

数据、文件、认证、评论等模块通常返回元组:

typescript
const [value, error] = await operation();
if (error) throw error;

部分更新/删除方法直接返回 Error | null:

typescript
const error = await dc.db?.save(threadId, "notes", JSON.stringify(note));
if (error) throw error;

RTM、RTC、白板和支付的大多数方法失败时会抛异常,应使用 try/catch:

typescript
try {
  await dc.rtm?.sendMessageToPeer(receiverPubkey, "hello");
} catch (error) {
  console.error(error);
}

不要只判断返回值是否为空而忽略 error;空值有时表示“记录不存在”,有时表示操作失败。

推荐生命周期

创建单例 DC
  -> dc.init()
  -> 用户手势触发 accountLoginWithWallet()
  -> 按需初始化 ThreadDB / RTM / RTC / 白板
  -> 使用业务模块
  -> dc.exit() 清理当前身份字段和钱包登录态
  -> dc.shutdown() 关闭模块、数据库、gRPC 和 P2P 连接

页面只是切换路由时通常不需要 shutdown()。只有整个应用退出或确定不再使用 SDK 时才关闭实例。

React 接入

推荐把实例和初始化 Promise 一起做成单例,避免 React Strict Mode 或并发渲染创建多个连接。钱包登录仍应放在按钮点击事件中。

…
typescript
import { getDC } from "./lib/dc-client";

export function LoginButton() {
  const login = async () => {
    const dc = await getDC();
    const auth = dc.auth;
    if (!auth) throw new Error("Auth 模块不可用");

    const [account, error] = await auth.accountLoginWithWallet();
    if (error || !account) throw error ?? new Error("登录失败");

    console.log("logged in:", account.nftAccount);
  };

  return 使用 DC 钱包登录;
}

在 Next.js、Nuxt 等 SSR 项目中,将上述文件只从客户端组件加载,或使用关闭 SSR 的动态导入。当前包入口不是 Node.js/SSR 安全入口:即使服务端不调用 new DC(),顶层导入也可能访问 window,因此不能先在服务端静态导入再延迟初始化。

认证

应用开发者最常用的是以下方法:

typescript
const auth = dc.auth;
if (!auth) throw new Error("Auth 模块不可用");

const [account, loginError] = await auth.accountLoginWithWallet();
const [currentAccount, infoError] = await auth.getLoginInfo();

const payload = new TextEncoder().encode("content to sign");
const [signature, signError] = await auth.sign(payload);

// 推荐退出方式:同时退出钱包,并清理公钥、dbThreadId、EVM 地址和账号备份连接。
await dc.exit();

auth.exitLogin() 只调用钱包侧退出,不会清理 DC 上的身份字段。dc.exit() 的清理范围更完整,但当前实现不会把 dc.userInfo / dc.accountInfo 置空,也不会关闭模块和网络连接;因此登录判断应同时检查 dc.userInfo 和 dc.publicKey,彻底停止 SDK 则另行调用 dc.shutdown()。

其他认证能力包括钱包消息签名、EIP-712 签名、NFT 账号绑定、应用账号生成、用户空间检查和存储套餐续订。普通 DApp 不应自行实现账号密码托管流程,优先使用钱包登录。

ThreadDB 用户数据库

ThreadDB 用于当前用户的私有结构化数据。dc.initUserDB() 会创建或恢复用户数据库,并设置 dc.dbThreadId;同步和维护任务会在后台继续运行。

Schema 规则

  • 每个 collection 必须有唯一 name 和 JSON Schema。
  • Schema 必须声明字符串类型的 _id,它是记录主键。创建数据时可省略,由 SDK 在校验前生成;保存时必须带回已有 _id。
  • Schema 还应声明可索引的 _mod 字段,但不要把它放进 required。SDK 会移除调用方传入的 _mod,再写入自己的修改时间标记和索引,业务代码不要覆盖它。
  • schemaVersion 是正整数,不是 "1.0.0"。集合字段或索引变化时递增。
  • reset=true 会重建数据库并导致原数据丢失,只能用于明确的开发调试场景。

CRUD

…

常用补充接口:has、deleteMany、modifiedSince、getDBRecordsCount、refreshDBFromDC、syncDBToDC、exportDBToFile。

KeyValue 共享存储

KeyValue 主题由 (appId, theme, themeAuthor) 唯一定位。themeAuthor 是创建该主题的用户公钥,必须作为应用配置长期保存;它不一定等于当前登录用户。

命名、类型和权限

  • 普通主题会自动补 keyvalue_ 前缀。
  • KeyValueStoreType.Public 主题名必须以 _pub 结尾;具备可用 SDK 身份的用户无需额外 READ 授权即可读取,写入仍需授权。
  • KeyValueStoreType.Auth 的读取和写入都需要相应授权。
  • createStore 为每个写入用户保留同 key 的独立值。
  • createSharedStore 自动规范化为 keyvalue_shared_ 前缀,同 key 全局只保留时间戳最新值。
  • 创建时传入的空间小于 100 MiB 会在实现中提升到 100 MiB。

权限使用 ThemePermission 枚举;主题创建者始终具有 ADMIN 权限。

创建或获取共享主题

…

获取共享主题时,必须把 toSharedTheme(...) 的结果传给 getStore。如果用普通主题名获取,再用 createSharedStore 创建,两次实际访问的主题名不同。

主题权限设计技巧

ThemePermission 是互斥状态枚举,不是位掩码。不要用 READ | WRITE 组合,也不要用数值大小比较权限:

权限 KeyValue 中的实际能力 建议用途
NONE 无读写权限 撤销授权或用户主动退出
APPLY 只有申请状态,不授予数据访问 用户申请加入,等待管理员审批
READ 可读,不可写 观察者、审核员
WRITE 可读写 编辑者、普通成员
ADMIN 可读写,并可管理其他用户权限 主题管理员;按最小人数授予
ONLY_WRITE 可写,但不获得主题读取权限,也不能修改授权信息 匿名投稿、设备上报、只收集不公开的数据
DEVICE 物联网管理扩展权限 仅用于配套的 IoT 流程
QUERY 查询服务专用权限 AI/服务查询流程,不可替代 READ
NOT_EXIST 服务端表示“没有授权记录”的哨兵值 不要主动配置给用户

存储类型决定读取边界,用户权限决定写入能力:

存储类型 读取 写入
KeyValueStoreType.Auth READ、WRITE、ADMIN WRITE、ADMIN、ONLY_WRITE
KeyValueStoreType.Public 已登录用户无需额外 READ 授权 WRITE、ADMIN、ONLY_WRITE

主题作者或已有 ADMIN 权限的用户可以配置其他用户。状态码 0 才表示成功:

…

authPubkey 传 "all" 可设置未单独授权用户的默认权限;某个用户的单独记录优先于 "all"。这个能力应谨慎使用:

  • 共享配置不要授予 "all" + WRITE,否则任何登录用户都能覆盖同一个 key。
  • 收集型业务可使用 KeyValueStoreType.Auth 的普通存储,并授予 "all" + ONLY_WRITE;用户可提交数据,但不能枚举或读取其他用户数据。
  • 权限初始化应放在受控的管理员/部署流程中,不要在每次客户端启动时重复执行。
  • remark 适合角色、分组等业务元数据,不要存放密钥或其他敏感信息。
  • 权限列表可用 store.getDbAuthList(limit, seekKey),或 keyValue.getDbAuthList(store, limit, seekKey) 分页读取;把返回的 nextSeekKey 传入下一页,直到它为空。

读取值和元数据

KeyValue 的原始读取结果包含业务值和 DC 元数据:

$$$dckv_extra$$$

直接 JSON.parse(raw) 会失败,应先拆分:

…

常用补充接口:getValues、getBatch、getWithTimeOrder、setWithCount、getDBCount、getDbAuthList、GetUserOwnAuth、GetUserAuth。删除一个 key 时使用 set(store, key, "", "")。

类型化仓储

SDK 导出 BaseEntity、EntityRepository、Entity、Column、Index 和 composeCompositeIndexValue。它们建立在 KeyValue 之上,提供实体校验、保存、局部更新、主键查询、单字段/复合索引查询及分页读取。

typescript
import { BaseEntity, EntityRepository } from "web-dc-api";

class Product extends BaseEntity {
  id = "";
  name = "";
  category = "";
  price = 0;

  validate() {
    if (!this.id || !this.name) throw new Error("invalid product");
  }
}

const products = new EntityRepository(Product, keyValue, store);
await products.save(
  Product.from({ id: "p-1", name: "Keyboard", category: "hardware", price: 299 }),
);
const product = await products.findById("p-1");

仓储使用 KeyValue 的索引规则;需要 findByIndex 时,应通过装饰器或底层 set 预先建立对应索引。

文件

文件模块支持普通文件、目录、完整下载、流式读取、可 seek 流和本地缓存。

…

可 seek 流会按“CID/目录路径 + 解密密钥”在内存中缓存约 100 秒;重复获取时可能返回同一个可变流实例。直接调用 seek() / read() 的多个消费者不要并发共享同一实例,需要重新开始时先 seek(0),需要强制新建时可调用 fileModule.clearFileCache(cid)。createReadableStream() 默认从当前 getPosition() 开始,但之后使用独立的流位置,不会推进实例位置;必须从头读取时传 { start: 0 }。

上传文件夹

浏览器选择文件夹时必须同时设置 webkitdirectory 和 multiple;SDK 使用每个文件的 webkitRelativePath 还原多级目录:

xml
…

进度回调中的 totalBlocks / processedBlocks 是 DC 接收的数据块数量,不等同于用户选择的源文件数量。上传时 SDK 会在根目录加入内部所有者标记 dc_ownuser;目录列表会自动隐藏它,业务代码不要自行创建同名文件。

遍历目录并按路径读取

…

目录项字段含义:

字段 含义
Name 当前文件或目录名
Type 0 为文件,1 为目录
Hash 当前项的 CID
Path 相对根目录的路径,可直接传给 getFileFromDir / getSeekableFileStreamFromDir
Size 文件在 UnixFS 中的存储字节数;目录为 0,加密文件包含分块加密开销
Content 仅 getFolderFileListWithContent 的文件项包含完整字节内容

getFileFromDir 的路径指向文件时返回 Uint8Array,指向目录时返回该目录的一级列表,因此必须用 instanceof Uint8Array 收窄类型。getFolderFileListWithContent(cid, key, recursive, peerAddr?) 会逐个下载并把所有文件内容放进内存,只适合小目录;大目录应先获取列表,再按路径读取单个文件或使用可 seek 流。已通过其他目录操作连接到同一根 CID 时才使用 cidNeedConnect.NOT_NEED,普通业务的首次读取应使用 NEED。

从代码生成目录

没有原生文件夹选择框时,可把路径和内容转换成 FileList,再复用 addFolder:

…

addFolderInLocal 只把目录构建到当前浏览器节点的本地块存储,不会向 DC 注册或持久化上传,适合本地预处理和调试,不能代替正式的 addFolder。拿到未知 CID 时可用 `isFileOr

Issues· 0 开放

查看全部 Issues在 GitHub 打开

暂无开放 Issues,或尚未同步最近议题。

> 标签

JavaScript

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月17日
分类编程语言
定价开源

> 相关工具

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言