用你的容器Your container
网盘、内容平台Cloud drives, content platforms
- 用户Users
- 不用钱包No wallet needed
- 文件记在Owner
- 你的容器Your container
- 谁签名Signer
- 后台,用专用钱包Your backend, with a dedicated wallet
- 你要有You run
- Node.js 后台A Node.js backend
给开发者 · 网盘 · 视频站 · 网页应用For developers · drives · video sites · web apps
中继网关替你存文件、传文件 · 不用 API keyRelay gateways store and deliver your files · no API keys
同时传 3 家 · 存好 2 家就能用 · 第 3 家自动重试Upload to 3 at once · usable once 2 have it · the 3rd retries automatically
协议和客户端库都一样,区别在文件记在谁的容器名下、由谁签名。Same protocol, same library. They differ in whose container owns the files and who signs.
网盘、内容平台Cloud drives, content platforms
DeWEB 视频站、个人网站DeWEB video sites, personal sites
两种可以混用;官方前端就是一个完整的模版 B。You can mix both; the official front end is a complete template B.
模版 A 要用专用钱包:只当这一个容器的持有人,只放少量 BNB。后台被攻破,攻击者能做持有人能做的一切。Template A needs a dedicated wallet that holds only this container and a little BNB — a breached backend can do anything the holder can.
先跑测试:只连本机,不要钱包。Start with the tests — local only, no wallet.
要 Node.js 20.19 以上 · 也可以直接下载Needs Node.js 20.19+ · or download the archive
curl -fsSL https://taperelay.hivehubs.app/download/examples | tar -xz
cd taperelay-examples/TapeRelay && npm ci --ignore-scripts起 3 台本机测试服务器,走一遍上传、删除、补副本。Starts 3 local test servers and runs upload, delete and repair.
node examples/template-a/test/test-template-a.mjs用专用钱包持有一个容器;在官方前端「开发者控制台 → 运营方」挑 3 家写进发现文件,并在各家买够空间。Hold a container with a dedicated wallet. In the official front end (Developer console → Operators), pick 3 into its discovery file and buy enough space at each.
TapeRelay 目录里的 .env 加 TEMPLATE_A_WALLET_KEY;config.json 填 account、servers。Add TEMPLATE_A_WALLET_KEY to .env in the TapeRelay folder; set account and servers in config.json.
node examples/template-a/server.mjs # 打开 http://127.0.0.1:8280/# open http://127.0.0.1:8280/上线时放在 HTTPS 反向代理后面。In production, put it behind an HTTPS reverse proxy.
起 4 台本机测试服务器,用假链、假钱包走一遍挑 3 家、授权、上传、删除。Starts 4 local test servers with a fake chain and wallet: pick 3, authorize, upload, delete.
node examples/template-b/test/test-template-b.mjspublic/site-config.json 填 app(你的容器地址)和 appName。In public/site-config.json, set app (your container address) and appName.
node examples/template-b/serve.mjs # 预览 http://127.0.0.1:8290/# preview at http://127.0.0.1:8290/
node examples/template-b/serve.mjs --out # 导出到 examples/template-b/out/# export to examples/template-b/out/把 out/ 放到任意 HTTPS 静态网站。用户要有状态为 ok 的 TapeOut 容器和少量 BNB。Host out/ on any HTTPS static host. Users need a TapeOut container in the ok state and a little BNB.
Claude Code、Codex、Cursor 都行。手册要求它不碰密钥、不替你发链上交易。Claude Code, Codex or Cursor. The runbook forbids touching keys or sending on-chain transactions for you.
请照这份手册,帮我基于 TapeRelay 做一个能上传、播放、删除文件的产品:Follow this runbook to help me build a product on TapeRelay that uploads, plays and deletes files: https://taperelay.hivehubs.app/docs/DEVELOPERS-FOR-AI.md存几份、谁能写、怎么读、怎么改删、花多少钱。Copies, permissions, reading, edits and deletes, costs.
随机挑 3 家不同运营方,同时上传。存好 2 家就能用,第 3 家自动重试,缺了再补。Pick 3 different operators at random and upload to all at once. Usable once 2 have it; the 3rd retries, and gaps get repaired.
pickOperatorsuploadToServersrepairReplicas
服务器只认容器持有人的钱包,和它授权的会话密钥(写明服务器和范围,最长 24 小时)。Servers accept only the container holder's wallet, or a session key it authorizes for named servers and scopes, up to 24 hours.
authorizeSessionremoteAuth
按文件读取的网址不要签名,直接放进 <video>、<img>,能拖动进度。浏览器不核对内容,要核对用 readFile。File URLs need no signature: use them in <video> or <img>, and seeking works. Browsers don't verify them — use readFile when you must.
fileUrlreadFile
内容不能原地修改:传新版本,再改指向(你的数据库,或签名指针)。Content never changes in place: upload a new version, then repoint (your database or a signed pointer).
publishPointerreadPointer
只认持有人的钱包。别的文件还在用的块不能释放;释放后运营方还会保留一段时间。Holder's wallet only. Don't release chunks other files still use; operators keep the bytes for a while afterwards.
fileObjectsclient.release
存储按容器买套餐,每家有免费额度;写发现文件付少量 BNB 手续费;下载流量目前不收费。Storage is a per-container plan, with a free quota at each operator. Writing the discovery file costs a little BNB. Downloads are free for now.
/v1/info → quota
每台中继网关都提供这些接口。一般不用直接调:客户端库会签名、核对。Every relay gateway serves these endpoints. You rarely call them directly — the client library signs and verifies for you.
| 接口Endpoint | 做什么Purpose | 客户端库Library | 权限Access |
|---|---|---|---|
| 服务器Server | |||
GET/v1/info | 服务器信息:配额、价格、支持的功能Server info: quota, pricing, features | client.info | 公开Public |
GET/v1/usage/{account} | 用量和配额Usage and quota | client.usage | objects |
| 对象Objects | |||
POST/v1/objects | 上传一个对象Upload an object | client.upload | objects |
POST/v1/objects/claim | 认领服务器上已有的对象Claim objects the server already has | client.claim | objects |
GET/v1/objects | 列出记在名下的对象List your objects | client.list | objects |
GET/v1/objects/{sha256} | 读一个对象,支持 RangeRead an object (Range supported) | client.getObject | 公开Public |
HEAD/v1/objects/{sha256} | 查是否存在、多大Check existence and size | client.has | 公开Public |
POST/v1/objects/release | 释放(删除),一次最多 1,000 个Release (delete), up to 1,000 at a time | client.release | 仅钱包Wallet only |
| 文件与指针Files and pointers | |||
GET/v1/files/{account}/{manifest} | 读整个文件,可以直接播放Read a whole file; plays directly | fileUrl | 公开Public |
PUT/v1/pointers/{account}/{name} | 写签名指针Write a signed pointer | client.putPointer | pointers |
GET/v1/pointers/{account}/{name} | 读签名指针Read a signed pointer | client.getPointer | 公开Public |
| 通知Notices | |||
POST/v1/outbox | 发通知,由自己的服务器转交Send a notice; your server forwards it | client.submitNotice | send |
GET/v1/outbox/{id} | 查投递状态Delivery status | client.outboxStatus | 公开Public |
GET/v1/inbox/{account} | 拉取收到的通知Pull received notices | client.inbox | inbox |
POST/v1/inbox/{account}/read | 标记已读Mark as read | client.markRead | inbox |
| 授权Authorization | |||
POST/v1/revocations | 撤销会话密钥Revoke a session key | client.revoke | 仅钱包Wallet only |
{account} 是容器地址,写成 eip155:56:0x…;{manifest} 是清单对象的 SHA-256。{account} is a container address such as eip155:56:0x…; {manifest} is the manifest object's SHA-256./v1/files 和按范围授权,只在 /v1/info 的 features 列出 files、scopes 的服务器上能用。/v1/files and scoped sessions work only where features in /v1/info lists files and scopes.POST /v1/inbox/{account}、给网站排行汇总用的 GET /v1/stats/sites,和运营方自己用的 /v1/admin/*,开发者用不到。Server-to-server POST /v1/inbox/{account}, GET /v1/stats/sites for the site ranking and the operator-only /v1/admin/* aren't for apps.client/src/index.mjs:浏览器和 Node.js 通用,只依赖 @noble。client/src/index.mjs works in browsers and Node.js and depends only on @noble.
import * as T from '/TapeRelay/client/src/index.mjs';
// account:用户的容器地址;servers:发现文件里的 3 台;app:你的容器地址// account: the user's container; servers: the 3 in its discovery file; app: your container
const client = T.createClient({ fetch });
const [address] = await window.ethereum.request({ method: 'eth_requestAccounts' });
const wallet = T.eip1193Wallet(window.ethereum, address); // 钱包要在 BNB Smart Chain 上// the wallet must be on BNB Smart Chain
// 授权一次:钱包签名,写明应用和范围// Authorize once: one wallet signature naming the app and scopes
const session = await T.authorizeSession({
wallet, account, app,
scopes: ['objects', 'pointers'],
...(await T.splitByScopes(client, servers)),
now: Math.floor(Date.now() / 1000),
seconds: 8 * 3600,
});
const auth = T.sessionAuth(session);
// 模版 A 换成:T.remoteAuth({ account, endpoint })// Template A instead: T.remoteAuth({ account, endpoint })
// 同时传 3 台,存好 2 台就返回// Upload to all 3; returns once 2 have it
const plan = await T.planPublicFile(file, {
name: file.name, contentType: file.type, withManifest: true,
});
const up = await T.uploadToServers(client, servers, auth, file, { plan });
// 播放:按文件读取的网址,不要签名// Play: a file URL, no signature needed
video.src = T.fileUrl(up.ok[0], account, plan.manifestObject.sha256);checkOperatorpickOperatorsdiscoveryJsonparseDiscoverywriteSiteFileeip1193WalletkeyWalletauthorizeSessionsessionAuthwalletAuthremoteAuthcreateRemoteSignerplanPublicFileuploadToServersfileUrlreadFilereadObjectcheckReplicasrepairReplicasmakePointersignPointerpublishPointerreadPointerfileObjectsclient.release