Developer guide (full text) · in Chinese for now. The developer guide is bilingual, and AI assistants can follow this document as is (Markdown).

开发者指南

2026-10-16 由主编写窗口编写(CHANGELOG 第 291 条,D-249);2026-10-17 第 312 条按签名指针(§6.5,D-283)改原第 8 节(现第 16 节)第 3 项;第 315 条按直接网页托管(§6.6,D-281、D-286~D-288)加同一节第 5 项;2026-10-22(UTC+8)按 D-335~D-353 改成开发者指南:前面加「做产品」的 8 节(两种模版、存 3 家、权限、文件网址、改和删、费用、做不到的、客户端库),原来的须知挪到第 9~18 节;2026-10-23(UTC+8)按 D-354 加示例代码的下载地址,按 D-356 在第 8 节加中继网关的接口一览,按 D-359 在接口一览后的说明和第 16 节第 5 项加网站统计。写给基于 TapeRelay 做产品(网盘、视频站、网页应用)的开发者。规范见 spec/SPEC.md(英文版 spec/SPEC.en.md);运营方看 docs/OPERATORS.md;给 AI 的版本见 DEVELOPERS-FOR-AI.md。

一句话

中继网关替你存文件、传文件;权限靠容器(持有人的签名),不靠 API key;每个文件同时存 3 家不同运营方。 TapeRelay 不替你运行程序;公开文件谁都能读,而且收不回来;密钥、密码不要放进来,要保密的内容用加密文件。

1. 两种做法

模版 A:用开发者的容器 模版 B:用用户的容器
适合 网盘、内容平台:用户不用钱包,用你自己的账号体系登录 DeWEB 视频站、个人网站:用户用自己的钱包、自己的容器
文件记在 你(开发者)的容器名下 用户的容器名下
谁签名 你的后台:持有一个专用钱包的私钥,浏览器把要发的请求交给后台,后台核对后逐个签名(文件不经过后台) 用户的钱包授权一把会话密钥,授权里写明应用(你的容器)和范围(例如上传、更新列表)
删除 后台先隐藏(能恢复),到期后批量释放 用户的钱包在每台各签一次
你要有 一个后台(Node.js,示例 100 多行) 只要静态网页,没有后台
示例 examples/template-a/ examples/template-b/

两种可以混用:例如平台的公共内容放在你的容器(A),用户自己的作品放在用户的容器(B)。官方前端(ui/app/)就是一个完整的 B 做法。

示例代码(两个模版和它们的测试,连同用到的客户端库)下载:curl -fsSL https://taperelay.hivehubs.app/download/examples | tar -xz,解开是 taperelay-examples/;在里面的 TapeRelay/ 目录先 npm ci --ignore-scripts(要 Node.js 20.19 以上),本文的路径都相对这个目录。

模版 A 的专用钱包:私钥只放在后台的密钥文件里(示例从 TapeRelay/ 目录里的 .env 读)。后台被攻破,攻击者就能做容器持有人能做的一切(删光文件、把容器转走),所以这个钱包只当这一个容器的持有人,只充一点付手续费的 BNB;不要用放钱的钱包。

2. 存 3 家:怎么挑、怎么传

3. 权限:靠容器,不靠 API key

服务器只认两种签名:容器持有人的钱包,和持有人授权的会话密钥(§8)。没有账号、没有 API key。

范围 能做什么
objects 上传、认领、列出、查用量
send 以这个容器的名义交出文件通知
inbox 拉取收件箱、标记已读
pointers 写签名指针

只要你用得到的范围;钱包签名时用户看得到应用和范围。释放(删除)只认钱包,哪种授权都不行(§5.3)。

4. 播放和下载:按文件读取的网址

5. 改和删

6. 费用

7. 做不到的

8. 客户端库速查

client/src/index.mjs,普通 JavaScript,浏览器和 Node.js 都能用(只依赖 @noble)。浏览器里的网址布局照 examples/static.mjs。

做什么 用什么
连服务器 createClient({ fetch });client.info(名字)、client.usage(名字, 授权)
挑运营方 parseOperatorList、checkOperator、pickOperators({ count: 3, features, exclude })
发现文件 discoveryJson、serverEntryOf、parseDiscovery、writeSiteFile(链上,交易)、DISCOVERY_PATH
授权 keyWallet(Node 里用私钥)、eip1193Wallet(浏览器钱包);authorizeSession({ app, scopes })、splitByScopes、sessionAuth、walletAuth
模版 A 的签名 浏览器 remoteAuth({ account, endpoint });后台 createRemoteSigner({ wallet, account, servers }) 的 check、sign
上传 planPublicFile(文件, { withManifest: true })、uploadToServers(client, 服务器, 授权, 文件, { plan, onProgress }) → { stored, ok, pending, settled }
读 fileUrl(给 <video>,不核对)、readFile、readObject(核对)、fileObjects(一个文件的全部对象)
副本 checkReplicas、repairReplicas
删除 client.release(名字, 钱包授权, 对象)
指针 makePointer、signPointer、publishPointer、readPointer

中继网关的接口

每台中继网关都提供这些接口(规范附录 A)。一般不用直接调:客户端库会签名、核对。权限一栏:公开不要签名;写范围的,认持有人的钱包或有这个范围的会话密钥;仅钱包只认持有人的钱包。

接口 做什么 客户端库 权限
GET /v1/info 服务器信息:配额、价格、支持的功能 client.info 公开
GET /v1/usage/{account} 用量和配额 client.usage objects
POST /v1/objects 上传一个对象 client.upload objects
POST /v1/objects/claim 认领服务器上已有的对象 client.claim objects
GET /v1/objects 列出记在名下的对象 client.list objects
GET /v1/objects/{sha256} 读一个对象,支持 Range client.getObject 公开
HEAD /v1/objects/{sha256} 查是否存在、多大 client.has 公开
POST /v1/objects/release 释放(删除),一次最多 1,000 个 client.release 仅钱包
GET /v1/files/{account}/{manifest} 读整个文件,可以直接播放(第 4 节;也支持 HEAD) fileUrl 公开
PUT /v1/pointers/{account}/{name} 写签名指针 client.putPointer pointers
GET /v1/pointers/{account}/{name} 读签名指针 client.getPointer 公开
POST /v1/outbox 发通知,由自己的服务器转交 client.submitNotice send
GET /v1/outbox/{id} 查投递状态 client.outboxStatus 公开
GET /v1/inbox/{account} 拉取收到的通知 client.inbox inbox
POST /v1/inbox/{account}/read 标记已读 client.markRead inbox
POST /v1/revocations 撤销会话密钥(持有人的签名在请求体里) client.revoke 仅钱包

{account} 是容器地址(eip155:56:0x…),{manifest} 是清单对象的 SHA-256。/v1/files 和按范围授权,只在 /v1/info 的 features 列出 files、scopes 的服务器上能用。另有服务器之间转交通知的 POST /v1/inbox/{account}、给网站排行汇总用的 GET /v1/stats/sites(§10.7),和运营方自己用的 /v1/admin/*,开发者用不到。

9. 能放什么、不能放什么

能放 不能放
网页(HTML、JS、CSS、WebAssembly)、图片、视频、文档、数据文件 后台程序、数据库服务、定时任务(TapeRelay 不运行它们)
只给自己或指定的人看的内容(用加密文件) 任何密钥、密码、API Key、私钥、助记词(放进公开文件就等于公开)

10. 公开文件谁都能读

11. 密钥放在哪里

  1. 放在你自己的后台或云函数里:网页去调你的后台,由后台带着密钥去调第三方服务。
  2. 网页里只放本来就能公开的 Key:限定了域名、只读、额度很小的那种。
  3. 节点网址里带着密钥的(例如某些区块链节点服务的网址),同样只能放在你的后台。

12. 要保密的内容:加密文件

13. 谁能写、怎样自动部署

14. 运营方能看到什么

能看到 看不到
谁(IP 地址)、什么时候读了哪个文件、文件多大 加密文件的内容
文件是哪个容器存的、什么时候存的 你的钱包私钥、会话密钥的私钥
文件通知:谁发给谁、通知的是哪个文件(通知不加密,§12)

运营方可能因法律原因下架某个文件(读取回 451,客户端换下一台,§5.4):这也是要多存几家的原因之一(第 2 节、第 17 节)。

15. TapeRelay 能不能运行程序

服务器上不能,也不应该。 原因:

  1. 核对不了结果:TapeRelay 的一切都能按哈希、签名核对,所以你不必信任运营方。程序的运行结果没法这样核对,只能信运营方,就丢掉了最根本的保证。
  2. 安全和滥用:在运营方的机器上跑别人的代码,要隔离、要限资源,还要防挖矿和攻击,第三方运营方负担很重。
  3. 定位:TapeRelay 学的是 SMTP/IMAP 的分工,只管「存」和「送」;v0.1 只按存储量计费,算力没法计费。

浏览器里能。 存进去的网页、脚本,会在访问者的浏览器里运行,跟静态网站托管一样。推荐的分工:

放在哪里 放什么
TapeRelay 界面(静态网页)、图片视频、公开的数据文件;要保密的数据用加密文件
链上合约 需要大家都信得过的逻辑和状态(转账、记账、权限)
你自己的服务器 密钥、要调第三方服务的后台、需要保密的计算

16. 在浏览器里运行的隐患

  1. 钓鱼网页:谁都能存一个冒充别人的页面。教用户认准你的容器名字(tape:// 地址),不要只看页面长得像不像。
  2. 网站之间要互相隔离:否则一个网站的脚本可能读到另一个网站存在浏览器里的东西。这由 TapeKit 外壳和网关负责;本协议的网关送出文件时带 TapeKit 给链上网站的那组安全设置(内容安全策略、nosniff 等,§13.2)。参考前端对收到的文件只给下载,不在页面里打开。
  3. 网页更新的权限:按哈希存的网页别人改不了。用「签名指针」(规范 §6.5,第 312 条起有)让一个名字换成新的版本时,谁能签指针谁就能推送更新:
    • 网站的指针只用钱包签,不要交给会话密钥(参考前端「发布到名字」勾「用钱包签」)。会话密钥最长 24 小时、可以撤销,但读的人查不到撤销:会话密钥被偷,小偷签的指针在那份授权到期之前都算数;撤销之后等授权到期(最长 24 小时),再用钱包发布一次就改回来了(D-283:版号不得大于签名时间,谁都签不出能长期压住你的版号)。
    • 要「谁读到的都一定是最新的」,用链上的那种放法(规范 §6.2 第 1 种):指针存在运营方的服务器上,读的人问遍你的每台服务器、取最新的,但一台服务器能少给(只给旧的);你的服务器都被拔掉时,读的人就读不到。
    • 容器转手之后,原来的持有人签的指针一律作废;新持有人发布时版号取当时的秒数,最多等 5 分钟。
    • 名字的位子删不掉:每个容器在每台服务器上最多 100 个名字,规范里还没有删名字的办法(I-232 第 3 点、I-234 第 2 点,以后再定)。会话密钥被偷(授权到期之前,最长 24 小时)、或者容器转手之前的原持有人,都能把 100 个位子写满;之后你只能改指这 100 个名字,起不了新名字,撤销、转手、等到期都腾不出位子。所以要紧的名字(例如 www)先用钱包发布一次占住,会话密钥只交给你信得过的设备。
  4. 流量:读取目前不计费,热门网页可能把免费运营方的流量拖垮,运营方会限流。热门内容请选能承受流量的运营方,或者多存几家。
  5. 直接网页托管(规范 §6.6,第 315 条起有;运营方自愿开):把一个文件夹作为网站上传后,开了托管的运营方给出能在普通浏览器里打开的网址。要知道:
    • 普通浏览器不核对:看到的就是运营方给的,运营方能改、能换掉整个网站。只放无关紧要的东西;要核对的,让人用参考前端(或以后的 TapeKit 外壳)按名字打开,逐个文件核对哈希。
    • 网址里的名字:按名字的网址是「容器地址--名字」,总是这个名字最新的一版;告诉访客认准里面的容器地址,谁都能放一个长得像的网站。
    • 浏览量公开(规范 §10.7,D-359):开了托管的运营方默认公布按名字的网站每天的浏览量和流量(同一个访客每天最多算 10 次),官方的网站排行(https://taperelay.hivehubs.app/sites)把各家的数字加在一起排,列出容器地址和名字;按哈希的网址不统计。数字是运营方自报的。
    • 不要用 cookie 存要紧的东西:同一个托管域名下的网站互不同源,但托管域名还没加入公共后缀列表时,别的网站的脚本能写 cookie 给你的网站(D-288)。登录凭证之类的放在你自己的后台。
    • 按名字的网站,同一个网址的内容会换主人(I-237 第 5 点):「容器地址--名字」这个网址给的是这个名字最新的指针指的网站。容器转手、会话密钥被偷时,新的内容就在同一个网址下,能读到访客浏览器里这个网址下存的东西(localStorage、IndexedDB、cookie)。按名字的网站不要在浏览器里存要紧的东西;按哈希的网址内容固定,没有这个问题。
    • 路径照 TapeKit:访问目录自动找 index.html;单页应用把「退回的页面」设成 index.html(fallbackPath:没有扩展名的路径找不到时退回它);notFound 是都找不到时给的 404 页。一个网站最多 2,000 个文件(D-281)。

17. 让文件一直在

18. 上线前的检查清单