@claudewerk/bridge-substrate

中文文档
0.2.3发布于 2026/10/27MITTypeScriptES Module近 30 天下载 1816

L2底物:有命名,可持久协调的物体,活于一包可信赖-ws连接的两侧. 作包-mq + 包-可信赖-ws + 信封-编码c + 双键-auth.

中文使用文档
文档目录20 节
  1. 它的四件包裹
  2. 接线
  3. 储存可插接(在耐久状态生活的地方)
  4. 两个条目: Bun和浏览器
  5. 同步持久存储配置文件( 中继 + 浏览器)
  6. 恰好通过强制断开(资金流动)
  7. 对象模型
  8. 动词( O) env.kind (中文(简体) )
  9. 两种承认水平
  10. 每个对象测序+严格的FIFO
  11. 持久性发包箱+去dupe(精确地说)
  12. 徒劳/反弹法
  13. 握手(全跨层拖拉)
  14. 这个 auth 选择是一个值,需要它
  15. 这个 authorize 门也是需要的 也是因为这个原因
  16. 端对端加密接合
  17. 可观察性(可插、供应商中立)
  18. 版式
  19. 这证明什么
  20. 被推迟(清洁接缝,未建)

桥基- L2 命名对象引擎( F1 CORE)

关键石. 它组成了四个经过证明的 独立制造的包 底盘: 命名、持久协调对象 双侧 连接 ——"活在两边的名队". 没错 克劳德沃克 - 不可知论它对经纪人一无所知 引擎是一个更大的系统 驱动器.

A 类 Substrate 位于一个认证连接的两侧, 拥有 名称 对象 (F1级: session + 键 queue),并说 底部动词 超过 铁丝网 -- -- 采用每个物体严格的FIFO测序,两个识别级,a 耐用发包箱 + dedupe 完全对接, 以及无效/ 授权决赛 法律规定.

bun install     # links the four packages via workspace:* (run at the monorepo root)
bun test        # 19 tests, all green (254 across the workspace)

# two-node CLI demo (see examples/README.md):
bun examples/client.ts --name C1 --port 7801
bun examples/client.ts --name C2 --port 7802 --connect 7801

有个可跑可走的车手 双节点 CLI (单位:千美元)open 编号 : send 编号 : req 编号 : close 编号 : disconnect 编号 : connect以图像化 对象的生命周期,两个相克级别, 并完全通过断开.

它的四件包裹

软件包在基底的作用
bun-reliable-wsl1载体: 二进制接线、握手、重接、WS交货包、, AuthContext 满分 Negotiated 倾斜+ connId + 键 transcriptHash
envelope-codec框架编码器( r)cborCodec: {env, body} - > CBOR 字节,不透明的车体与二进制 零基数64
mutual-key-auth页:1 AuthProvider (单位:千美元)asAuthProvider:相互挑战/回应、角色绝对、跨层降级约束 -- -- 现在 无克 (见出处
bun-mq持久对象 发件箱 +该 除尘器分类账 (收押金) ack, (中文(简体) ), StaleReceiptError, 7天的调试窗口)

接线

   SUBSTRATE A  (dialer)                               SUBSTRATE B  (listener)
   ─────────────────────                               ───────────────────────
   app: open / req / send / close                    open? -> accept/reject; req -> res
        │  ▲                                                        ▲   │
        ▼  │ answer (accept/res/end/err)   end-to-end, keyed to id  │   ▼
   ┌──────────┐  per-object durable outbox                  dedupe ledger  ┌──────────┐
   │  Outbox  │  (bun-mq, one seq authority)   (bun-mq (peer,id) >= 7d)    │ Sequencer│
   └──────────┘  at-most-one-un-acked-in-flight        in-seq delivery ────└──────────┘
        │  ▲                                                        ▲   │
        │  │  ◀──────────── ack (hop delivery-ack, receipt-fenced) ─┘   │
        ▼  │  ──────────── open/send/req/res/accept/reject/close ──────▶│

   Link:  bun-reliable-ws  ═══ ws (binary), may drop + reconnect ═══
   Codec: envelope-codec   frame = { env{v,kind,obj,objKind,id,seq,receipt}, body } -> CBOR
   Auth:  mutual-key-auth  challenge/response, bound to connId + full cross-layer tuple

与流量相同的堆栈 + 组成 :

flowchart LR
  subgraph A["Substrate A · dialer"]
    AApp["app: open / req / send / close"]
    AOut["Outbox<br/>durable bun-mq · 1 seq authority<br/>at-most-1-unacked-in-flight"]
    ASeq["Sequencer<br/>in-seq · gap buffer · resync"]
    AApp --> AOut
    ASeq --> AApp
  end

  subgraph B["Substrate B · listener"]
    BApp["app: accept/reject · req→res"]
    BOut["Outbox"]
    BDed["Dedupe ledger<br/>(peer,id) ≥ 7d"]
    BSeq["Sequencer"]
    BApp --> BOut
    BDed --> BSeq
    BSeq --> BApp
  end

  AOut ==>|"open/send/req/res/accept/reject/close"| BDed
  BOut -.->|"ack · hop delivery-ack · receipt-fenced"| AOut
  BOut ==>|"answer · accept/res/end/err · keyed to id"| ASeq

  AOut <--> L
  BOut <--> L
  L["LINK<br/>bun-reliable-ws — binary ws, drop+reconnect<br/>envelope-codec — {env,body} → CBOR, zero base64<br/>mutual-key-auth — bound to connId + full cross-layer tuple"]

储存可插接(在耐久状态生活的地方)

每个对等端的发件箱,收件箱,去dupe分类账和对象注册都进入一个 Store (bun-mq的坚持合同). 默认不需要配置; 主机 想要状态在 ITS OWN 数据库中插入一个商店:

选项国家生活的地方
无内存, 不持久
dbPath /接受者 dbPathFor(peerId)a SQLite 文件下方打开并关闭
storage /接受者 storageFor(peerId)(单位:千美元) Store 所建主机; 底盘永远不会关闭

接受方优先发言: storageFor,则 storage,则 dbPathFor,则 dbPath。每个耐用密钥都用对等码来显示,所以 One store 可以服务每个 鼠标。 在主机数据库中保留桥状态,在主机表格旁边 在主机交易中:

import { createPeerAcceptor, sqliteStore } from "@claudewerk/bridge-substrate";

const bridgeStore = sqliteStore(appDb, { tablePrefix: "bridge_" }); // appDb opened { strict: true }
const peers = createPeerAcceptor({ peerId: "broker", auth, authorize, storageFor: () => bridgeStore });

A 类 queue 接受对象 acceptQueue() 然后将其耐用收件箱保存在 主机数据库:主机可以数出,检查和像管理 其余数据。 离开对等者留下一行供主机保留 或删除.

两个条目: Bun和浏览器

@claudewerk/bridge-substrate 是Bun入口(货车工厂,SQLite). @claudewerk/bridge-substrate/client 是浏览器条目: 同一引擎 (单位:千美元)SubstrateCore,并导出为 Substrate),物体表面,发包箱, 接受路径和去dupe,没有 bun:sqlite,没有载体和没有 node:*编辑 阿宝 Substrate 是同一类加 dbPath; 没有任何第二份副本 逻辑. bun build --target=browser src/client.ts 是一个考验.

同步持久存储配置文件( 中继 + 浏览器)

对于只能是同步的商店(RFC0005§8.3). 同步 上面的剖面图没有变化;这是加上两种表格.

中继形式:溪流前的无国籍边缘 (RFC 0006 第9.1.1节,第7.5节). 边缘没有持久状态;任何复制品都可以为任何会话服务.

const edge = new SubstrateCore(link, {
  authorize, peerId: "edge", remotePeerId: browserId,
  relay: {
    sink: jetStreamSink(js, "GATE_IN"),      // store(op) -> Promise<{seq, duplicate?}>, idempotent by (peer, id)
    feed: jetStreamFeed(js, "GATE_EVENTS"),  // resume(target, fromSeq): push the object's stream from fromSeq
  },
});
  • 入境: 每一个接受的操作都前往 sink.store a. 每物体序列链; 页:1 ack ("已存")只在解后发去. 失败的商店发送不 ack并放弃了背后的操作;浏览器重新发送. 重播失败 在水槽旁边,然后重新打包。 从浏览器中采纳对象和边框.
  • 出道:每个对象的浏览器所带方向是流. 框架带 之后的溪流和 prev (前一个框架的后几个),所以一个丢失的框架被告知 除间隙外; 浏览器恢复 resync{fromSeq} 在任何复制品.
  • examples/jetstream-adapter.ts 是 JetStream 的无依赖形状 适配器; memorySink 编号 : memoryFeed (src/memory-stream.ts)为假相.

日记窗体: IndexedDB 上的浏览器发送框 (RFC 0006 第8.1.1.1节).

import { createClientSubstrate, openIdbJournal } from "@claudewerk/bridge-substrate/client";

const journal = await openIdbJournal({ name: `bridge:${me}:${edgeId}` });
const s = await createClientSubstrate(link, { authorize, peerId: me, remotePeerId: edgeId, journal, resumeFeeds: true });

每个操作都写入索引数据库( 等待, 一个严格可持久交易) 在它到达铁丝网之前, 释放出它的跳起, 并在重新装入后怨恨。 A 类 失败的写入( quota) 拒绝 send。此处不支持 : acceptQueue。 。 。 .

恰好通过强制断开(资金流动)

sequenceDiagram
  participant A as Substrate A (Outbox)
  participant Wire as ws link
  participant B as Substrate B (Dedupe→app)

  A->>A: enqueue send(id=M-1, seq=n) — durable, BEFORE the wire
  A->>Wire: send{id:M-1, receipt:r1}
  Wire->>B: send{id:M-1, receipt:r1}
  B->>B: admit(peer,M-1)=fresh → commit, deliver to app once
  Note over Wire: 💥 connection drops — ack lost
  B--xWire: ack{M-1, r1}  (never arrives)
  Wire-->>A: reconnect (new connId, same peer → rebind)
  A->>Wire: RESEND send{id:M-1, receipt:r1}  (same producer-stable id)
  Wire->>B: send{id:M-1}
  B->>B: admit(peer,M-1)=DUP → skip app (dedupe wins)
  B->>Wire: ack{M-1, r1}  (branchless re-ack)
  Wire->>A: ack{M-1, r1}
  A->>A: q.ack(r1) receipt-fenced → outbox row freed
  Note over A,B: delivered exactly once · FIFO intact

对象模型

一个 对象 是双方都存在的指定协调终点:

  • 地址 - 一个不透明的符号 底部MATCHES,从不分析. 字符集 [a-z0-9._/-]{1,128}; 一个 @ 实值 routing_not_supported。 。 。 . objKind (单位:千美元)session | queue)是一个明确的信封字段,而不是从名称中解析.
  • 生命周期 - 说吧 open - > (中文) accept 编号 : reject,然后活着,然后 close (或 a 个) 终端 err) (中文(简体) ). 两个终点跟踪对象的 与会者; 杀人 动词仅来自经核实的参与者.
  • 会议 -- 支持 req编号 :res (端对接)和单向 send。 。 。 .
  • 队列 - 同一机器,面向发送(单向) send + 键 ack) (中文(简体) ).

动词( O)env.kind(中文(简体) )

动词方向含义
open 编号 : accept 编号 : reject打开器qq接受者建立或拒绝对象
close任何参与者终止对象( 授权终局)
send + 键 ack生产商 - > 端点单向信息; ack 是跳跃快递包
req 编号 : res呼叫者 qq 呼叫者请求 + 端对端答案
err调用对象/ 底盘终端错误( 接收器从代码中得出的类)
end被调用者终端答尾
chunk 编号 : resync- 说吧chunk 是一个F2接合; resync 内部控制接缝

两种承认水平

  1. 跳接快递 (单位:千美元)ack, QoS-1, 这个连接). 由接收器发送 行动组被长期投入到破烂分类账中 它释放了发送者 发件箱行, 收受额 通过回声 env.receipt输了 连接 - > 发送者在重新连接上重传同一框架 - > 接收器 脱发 重新交付和 重装。这就是交付 以及严格FIFO的强制措施(在飞行中,大多数行动都是未撤销的) 每个物体).
  2. 端对端答案 (单位:千美元)accept编号 :reject编号 :res编号 :end编号 :err键入 生产稳定 id, (中文(简体) ), 连接不可知 - 它解决了呼叫者 承诺只要可以交付,就通过任何次的再连接.

每个对象测序+严格的FIFO

每个对象都有一个 后续权力 每个方向 Outbox) (中文(简体) ). 帧走 严格退出 一次性无抵押,所以通过订购的载体 接收器的 Sequencer 查看它们并经过;重排/再交付被缓冲 在内部 [nextExpected, +window],以下的后缀是重复(仅重置), 30多岁时的空隙要求 resync。 。 。 .

持久性发包箱+去dupe(精确地说)

每个 open编号 :send编号 :req (和每个回答) 持久排队 在此之前 击中了 电线. id 是一个 生产商-稳定独能键 -- -- 薄荷一次,再用 每一次重试,从不尝试。 接收器被 (peer, id) 为期7天 通过 bun-mq 的持久去dupe 表(它消耗了 + 重新启动),所以 脱地取胜于墓碑 即使是在原作之后 重送也会崩溃 已经交付.

徒劳/反弹法

  • (a) 接收人出错类别 没有电线 final 旗帜 接收器将代码分类为 terminal 或者说 retryable (单位:千美元)finality.ts) (中文(简体) ).
  • (b) 核准的最终结果 - 说吧 close编号 :err 杀死物体的,是荣耀的 仅来自经核实的参与者;否决未经授权的终局框架 之前,它甚至可以 扰动以下的边界.
  • (c) 完全反弹 - 未知对象的框( 或错误的地址) 输出一个终端 err墓志铭 数字 (不是每个名字),所以 稍后为合法 open 同一名称仍然有效.
  • (d) 一个 err 永远没有 err - 一个无法运行的 err 永远无法反弹.
  • (e) 清理终端 - 一个终端回答/弹出 清除发送者的行动和 输出 a bridge/futile 活动.

握手(全跨层拖拉)

L1通过 bun-reliable-ws + 键 cborCodec + 键 asAuthProvider认证 手抄本 绑定整个谈判的tuple -- -- 版本、功能、选择 每个槽中的名称( e)auth, (中文(简体) ), e2eSeal, (中文(简体) ), e2eSign, (中文(简体) ), codec, (中文(简体) ), 已调试 (作为谈判的地物),和 connId - 所以降级约束是 完成所有层.

这个 auth 选择是一个值,需要它

createDialerSubstrate 编号 : createListenerSubstrate 带 auth: () => AuthProvider 或者说 auth: "none"。没有默认和第三个选项, 因此,部署不能通过留下一些东西来达成一个未经证实的联系 出; 写入 auth: "none" 和SSH一样谨慎 Ciphers none,这是 当警告实现的时候, 两个广告 auth 名称列表和 电线提供商来源于这个值,所以他们不能不同意.

这个 authorize 门也是需要的 也是因为这个原因

auth 解决WHO的同伴. authorize 解决它可能做什么,它是 因此授权不能最终终止 通过一个忽略。 它需要一个 拦截器数字 : (ctx) => Denial | void, (中文(简体) ), 无法返回的地方 deny(code) 拒绝.

import { createListenerSubstrate, scopeAuthorizer, compositeInterceptor, deny, ALLOW_ALL } from "@claudewerk/bridge-substrate";

createListenerSubstrate({
  peerId: "gate",
  // One key record per peer, chosen by the id the peer claimed in its hello.
  auth: substrateAuth({ myKey, peerRecordFor: (peer) => keyRecords.get(peer), method: AUTH_METHOD }),
  authorize: scopeAuthorizer({
    scopesOf: (peer) => keyRecords.get(peer)?.scopes,  // unknown peer -> refused
    matrix: { producer: ["open", "send", "close"], admin: ["*"] },
  }),
});

城门所坐之处是其全部价值. 每一个入境业务都提供 在地址和动词验证后,将“和”改为“和” 在此之前 对象查询, 即 测序器、持久承诺和跳入- 所以一个被拒绝的对等点生成不 在此对象中,不移动接收边框,并且从未被告知其操作 已经接受。 进入的溪流 establish 穿过同一个链子,被拒绝 与 establish_fail{unauthorized} 在分配标签之前; objKind: "stream" 这不是绕出大门的路.

这是一个CHAIN,因为观察是常见的情况:一个返回的拦截器 没有任何允许,所以追踪和审计 是成员与政策 首先拒绝停止其他的.

authorize: compositeInterceptor([
  (ctx) => void log.info("inbound", { peer: ctx.peer, verb: ctx.verb, obj: ctx.obj }),
  (ctx) => (ctx.obj.startsWith("admin/") ? deny("unauthorized") : undefined),
  scopeAuthorizer({ scopesOf, matrix }),
]);

运出的政策是逐一拒绝 并称共同键自动 scopeAllows 而不是重复规则 -- -- 一个定义,两个呼叫者. ALLOW_ALL 这是 命名退出并还原A1前态势:任何经认证的对等方都可能这样做 任何关于这个连接. ctx.cap 带有不透明能力符号 显示打开器( o)open(kind, addr, { cap }) 编号 : openStream(addr, { cap }); 计 数 底盘渡过它,从不剖析.

端对端加密接合

src/e2e.ts 这是什么 e2eSeal 财务报告和审定财务报表 e2eSign 插槽名称的意思。 一个登记处 每个插槽都持有这个构建工具的套间;一个主机的广告是准确的 这些名字和解决一个谈判名称 通过同一地图,所以 列表和线条不能漂移。 未经执行的谈判名称是: 拒绝在准备, 从来没有跳过.

今天运送的唯一套房是 none这是诚实的答案 点对点部署: TLS 已经覆盖每个跳, 以及真正的套房 中继器必须带有无法读取的内容。 增加一是二,你觉得呢 登记条目,谈判不变.

可观察性(可插、供应商中立)

底物保持无依赖状态,但有工具。 四个狭隘的关切 -- Logger 编号 : Metrics 编号 : Events 编号 : Tracer - 每一个都有 无效 默认( 0) 费用)a 复合 (fan-out to N.) (英语). 通过一个 observability 包到主机 工厂; 重汇 (OTel, Prometheus) 是适配器 在接口后面, 永远不会 道诸相.

import { createListenerSubstrate, observe, inMemoryMetrics, ALLOW_ALL } from "@claudewerk/bridge-substrate";

const metrics = inMemoryMetrics();                       // snapshot() feeds a dashboard
createListenerSubstrate({ peerId: "host", authorize: ALLOW_ALL, auth: "none", observability: observe({ metrics }) });
// ... later:
metrics.snapshot().gauges.filter(g => g.name === "substrate.outbox.depth"); // per-object backlog

默认是 NO_OBSERVABILITY ——无文书是规范而自由. 接收 信号 : substrate.ops.enqueued/acked, (中文(简体) ), substrate.outbox.depth{obj} (每个对象) 积压), substrate.ack.latency_ms 编号 : substrate.answer.latency_ms, (中文(简体) ), substrate.ingress.op{verb}, (中文(简体) ), substrate.dedupe.duplicate, (中文(简体) ), substrate.seq.deferred, (中文(简体) ), substrate.authorize.denied{verb,objKind,code}, (中文(简体) ), substrate.bounce, (中文(简体) ), substrate.futile{code}, (中文(简体) ), substrate.conn.ready/ended。适配器: consoleLogger/Metrics/Events (调试), inMemoryMetrics (磁盘); OTel 适配器是预定的下一个。 见 src/observe.ts + 键 src/observe-adapters.ts。 。 。 .

版式

src/
  wire.ts        Env / Frame types, verbs, objKind, address validation
  observe.ts     pluggable observability: Logger/Metrics/Events/Tracer, null + composite
  observe-adapters.ts  console + in-memory sinks (OTel deferred)
  codec.ts       cborCodec as a WS Codec (zero glue)
  auth.ts        asAuthProvider as a WS AuthProvider (zero glue)
  host.ts        createDialer/ListenerSubstrate; capabilities; per-peer rebind
  link.ts        the structural Link surface (subset of ReliableConnection)
  substrate-core.ts  the engine: object registry, routing, the two ack levels, laws
                 (platform-neutral: no bun:, no node:, no carrier)
  substrate.ts   the Bun door: the same class plus `dbPath` (a SQLite file)
  client.ts      the browser entry: the engine and client surface, no Bun-only module
  async-sink.ts  async profile: the AsyncSink contract + the per-object commit chain
  feed.ts        relay outbound: external-seq feed (stream seq + prev), FeedHost
  memory-stream.ts  JetStream-shaped memory stream, memorySink, memoryFeed (fakes)
  journal.ts     journal form: DurableJournal, its serial writer, restore
  idb-journal.ts the browser outbox store over IndexedDB
  client-substrate.ts  createClientSubstrate: restore from the journal, then build
  object.ts      SubstrateObject: state machine + app-facing verbs
  outbox.ts      durable per-object outbox, strict-FIFO one-in-flight, receipt-fenced
  sequencer.ts   per-object in-seq delivery, gap buffer, out_of_seq, resync
  dedupe.ts      durable (peer,id) dedupe ledger over the bun-mq Store
  finality.ts    error-class derivation + per-op-id tombstones
test/
  handshake.test.ts    four packages compose; connId agrees on both ends
  session.test.ts      open+accept, req->res, send->ack, reject, close
  reliability.test.ts  exactly-once across a forced disconnect; strict FIFO under redelivery
  futility.test.ts     non-participant close rejected; unknown-object bounce+tombstone; bad address
  auth.test.ts         wrong key fails; tampered tuple breaks the proof
  primitives.test.ts   unit tests for outbox / sequencer / dedupe

这证明什么

超过一个 真实 两者之间的可靠ws连接 Substrate 实例 :

  • 第二届会议 open A->B(接受), req - > (中文) res单向 send - > (中文) ack· ;
  • 完全通过强制断开+重接 (再发送+去dupe);
  • 严格 FIFO (一) 在重新交付下保存的每个物体;
  • (单位:千美元) close编号 :err 从a 非参加者 被拒绝(物体还活着);
  • 一个框架到一个 未知对象 输出一个终端 err + 个人编号 墓碑(后为正文) open - 名称不变;
  • 认证/降级: 错误的密钥出错; 被篡改过的谈判拖曳 (connId /) 跨层集)打破了方向证明.

被推迟(清洁接缝,未建)

F1CORE在这里停留。 后来的阶段在代码中命名了接合:

  • F2 批量转让 -- -- 数据 chunk 动词 + sendChunk (已宣布), - 没有电线).
  • F3 同行生命周期 -- 活动/无法接触/固态/已终止(底物) 是每平方 + 可重置,即钩子).
  • F4发现+提议/同意/合法 ——同路由器上的新动词.
  • F5状态@ 1 (Yjs) - 第三个 objKind 在同一物体机器上.

序列状态和墓碑为内饰(耐用外框+去dupe载体) 完全通过重新启动; 持久测序器/通石持久性是一个 后相接相接相. 见 FINDINGS.md 为所降示的经典.

版本与发布记录

@claudewerk/bridge-substrate 共发布 5 个版本,首次发布于 2026/09/28;过去 12 个月发布了 5 个版本。

版本发布日期距今
0.2.3latest2026/10/2713 天前
0.2.22026/09/301 个月前
0.2.12026/09/281 个月前
0.2.02026/09/281 个月前
0.1.02026/09/281 个月前

关于 @claudewerk/bridge-substrate 的常见问题

@claudewerk/bridge-substrate 是什么?

L2底物:有命名,可持久协调的物体,活于一包可信赖-ws连接的两侧. 作包-mq + 包-可信赖-ws + 信封-编码c + 双键-auth.

如何安装 @claudewerk/bridge-substrate?

在项目目录运行 npm install @claudewerk/bridge-substrate,或使用 pnpm add / yarn add / bun add。

@claudewerk/bridge-substrate 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@claudewerk/bridge-substrate 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@claudewerk/bridge-substrate 可以商用吗?

@claudewerk/bridge-substrate 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@claudewerk/bridge-substrate 的下载量有多少?

根据 npm 官方下载统计,@claudewerk/bridge-substrate 在 2026/10/10 – 2026/11/08 这 30 天内被下载 1,816 次,日均约 61 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@claudewerk/bridge-substrate 还在维护吗?

最新版本 0.2.3 发布于 2026/10/27(13 天前);至今共发布 5 个版本,其中过去 12 个月发布了 5 个;首次发布于 2026/09/28。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。