@chatto/client

中文文档
0.5.0发布于 2026/11/09Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 2514

框架无关的Chatto客户端:连接、实时投影和响应式存储

中文使用文档
文档目录17 节
  1. 客户端和服务器
  2. 答复信件
  3. 事件、状况和状态
  4. 直播时间表和房间商店
  5. 准备和失败
  6. 请求
  7. 无国籍请求
  8. 除错输出
  9. 隐私
  10. 带有UI的应用程序
  11. 本地存储和浏览器登录
  12. 本地密码登录
  13. 东道国国
  14. 丝绒
  15. 语音通话
  16. 反应
  17. 发展

Chatto 客户端

@chatto/client 是查托0.5服务器的客户端. 它连接到一个或 更多服务器,通过实时API保持数据流,并曝光 数据是反应状态 它也有请求和消息循环 和整合用。 它只保存服务器数据:主机状态 UI属于主机. 它不依赖UI框架。 捆绑 Chatto前端,ChattoBot,和"跑步机器人"的例子使用.

安装方式 npm install @chatto/clientnpm 软件包包含 ES 模块 和 TypeScript 声明,包括生成的协议类型。 使用节点.js 22岁或更晚的婴儿。 Svelte 可选; 使用时安装 Svelte 5 @chatto/client/svelte。模块路径可以在1.0之前改变.

客户端和服务器

一个客户端是一组孤立的服务器 具有实时传输和 工作背景。 为每个独立主机创建一个客户端. 一个进程可以 拥有多个客户端,每个客户端可以连接多个服务器:

import { createClient } from '@chatto/client';

const client = createClient();
process.on('SIGTERM', () => client.close());
try {
  const eu = client.connect({ serverUrl: 'https://eu.example', apiKey: euKey });
  const us = client.connect({ serverUrl: 'https://us.example', apiKey: usKey });
  await Promise.all([
    eu.run((ctx) => ctx.reply(`Hello from EU, you said: ${ctx.message.body}`)),
    us.run((ctx) => ctx.reply('Hello from US'))
  ]);
} finally {
  // Close every server and stop all background work.
  client.close();
}

connect() 添加一个带有固定无记名符号的服务器, 如 bot API 密钥, 并归还它。 该标志只保存在记忆中: 它永远不会被更新或 写入设备存储 . client.server(id) 返回服务器 客户有。 都一样 Server 类型:服务器的数据、事件和 请求是一个对象.

server.reportPresence() 在服务器运行时将账户显示为在线 打开:一旦服务器接受密钥,客户端就会发送出存在心跳 每30秒钟一次。 之后 close(),账户显示在60之内的离线 秒数。 它永远不会改变账户 保存的存在选择.

答复信件

server.run(handler) 等待服务器接受密钥, 同时 服务器无法访问,然后调用 handler 发送到 取景者(密钥的帐户)。 默认这些是直接消息, 并回复了观众的留言。 作用, @here,以及 @all 提及是单独的原因(role_mention, (中文(简体) ), here_mention, (中文(简体) ), all_mention) 使您能够 reasons。消息为 处理有序。 处理器收到上下文 :

await server.run(
  async (ctx) => {
    ctx.message; // the addressed message: id, roomId, threadRootId, authorId, body, reasons
    const thread = await ctx.readThread(); // messages with `fromViewer`
    await ctx.withTyping(async () => {
      await ctx.reply(await answer(thread.messages));
    });
    await ctx.addReaction('eyes');
  },
  {
    signal, // stops the loop; without it, the loop stops when the server closes
    reasons: ['mention', 'direct_message'], // default: also 'reply'
    onStatus: (status) => console.log(status.state),
    onError: (error) => console.error(error) // keep running after a failure
  }
);

ctx.signal 当循环因任何理由停止时中止; 传递给 你自己的可以工作. ctx.conversationKey 将对话范围到 观众、房间、线条和发送者. ctx.refreshTyping() 刷新输入 指标一次.

run 何时决定 signal 中止或服务器关闭 。 它拒绝当 服务器拒绝密钥或不支持此客户端,并且,不 onError,与处理器的第一个失败.

事件、状况和状态

  • server.consumeEvents({ signal, onEvent, onStatus }) 处理 按顺序排列实时事件. run 用起来. onEvent(event, { signal }) 接收到一个信号,当循环因任何原因停止时,会中止 当服务器结束会话时的例子。 多达1 000起事件等待 对于一个慢处理器;除此之外,它们被放弃,并报告有缺口.
  • onStatus 接收 connecting, (中文(简体) ), ready,以及 reconnectingA级 ready 状态为 gap: true 意味着事件可能缺失,例如 因为服务器在重新连接后无法恢复流 。 虽然 run 等待服务器, a connecting 具有 error 报告 每一次尝试都失败,例如无法到达的服务器.
  • 一个服务器 connect 添加接收创建时的事件, 也 在此之前 ready() 决断,并保存在第一个 consumeEvents 或者说 run 电话 后一召报先有漏.
  • onEvent(listener) 财务报告和审定财务报表 onSnapshot(listener) 接收事件和新 直接快照,无回环.
  • 服务器的数据是被动的:例如 roomList.rooms, (中文(简体) ), notifications.occurrences, (中文(简体) ), projection.users,以及 rooms.messages(id) {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}一个呼号 直播室时间表.

直播时间表和房间商店

rooms.messages(roomId) 财务报告和审定财务报表 rooms.thread(roomId, rootId) 返回一个活 时间表。 时间线读取它的最新一页 当你第一次得到它。 实时 发送后添加新信件并应用编辑和删除,所以主机 不为每次更改再次读取线程.

  • isCurrent 当装入最新页面而未读取或重新连接时为真 正在等待重新装入 . events 然后有最新消息.
  • loadError 错误的读取失败, 或失去房间。 打电话 restoreLatestWindow() 在读取失败后再次读取.
  • 默认情况下,客户端会保留最近使用的10个房间的商店 (时间线、文件列表、针头列表和成员列表)和最近20个 使用线程. 一个呼叫 rooms.messages, (中文(简体) ), rooms.files, (中文(简体) ), rooms.pins,或 rooms.members 使用房间;呼叫 rooms.thread 只使用线程。 客户 处理旧的仓库; 下一个调用返回新商店, 它 又读了 不要同时使用更多的房间或线程. 留着 设置客户端选项 keepRecent,例如 createClient({ keepRecent: { threads: 50 } })。 。 。 .
  • 已处理的时间表不再更新, 也永远不会更新 。 如果你坚持 跨越漫长的等待时间,例如直到 isCurrent时停止 isDisposed 成为真实的, 并再次获得时间线.

使用 readThread 而不是当你需要一个快照 而没有实时更新.

rooms.members(roomId) 在不启动目录的情况下返回成员存储 扫描 打电话 store.loadRoomMembers(roomId) 消费者需要完整名单时; 服务器商店将推迟此请求, 直至得知房间访问 。 使用 members.searchMembers(query) 不装满 列表中选择一个选项。 空查询返回绑定的建议页。 回收刷新器 只有明确要求的目录.

对于引用,呼叫 members.retainMentions(handles) 并释放 当内容离开视图时返回订阅 。 读取 mentionMembers 用于当前配置。 这些共享的, 房间扫描的搜索只匹配 页面,不要求完整目录。 缺少的手柄保持纯文本 . 访问和成员更改了丢弃的缓存匹配和旧的栅栏读取.

准备和失败

  • ready() 当服务器拒绝密钥, 当服务器是 无法到达或失败, 或当服务器发布时不支持此功能 客户端。 背景服务器重试; 调用 ready() 再来一次 等待下一次尝试. run() 等待通过这些重复.
  • sessionEnded 当服务器拒绝或撤销密钥时,则变为真实. realtimeUnsupported 当服务器不支持时变为真实 客户端的实时协议. 这两起事件都没有到来,而且事件 循环拒绝; 关闭服务器.
  • 一个服务器 connect 添加后保留一个持久的 WebSocket, 也在 客户端,有一个选定的活服务器.
  • server.close() 从客户端中删除服务器并停止其实时 交货。 飞行中的请求失败, 即使服务器应用了它们, 没有 发出新的请求。 当最后一个服务器 connect 增加了关闭, 客户端停止计时器,所以一个节点主机可以退出.

请求

服务器和无国籍者 Api 拥有同样的请求助手。 每个 请求有十秒的超时, 不自动重试; 失败的写入可以 仍然到达服务器 .

帮助对
getMessage({ roomId, messageId })读取一个信件, 包括没有下载地址的附件元数据
createMessage(destination, body, { inReplyTo })发送一个消息; 返回其 id
prepareMessage(destination, body, { inReplyTo })为明确重试准备一个逻辑发送
postMessage(destination, body)发送任意长度的文本, 以 8000 个代码点为部分
reply(message, body)在信件线索中标注
readThread(location, { after, limit })读取线程; after 仅读取新信件
readAttachment({ roomId, attachmentId }, opts)读取文件; maxImageSize 更改服务器上的图像大小
refreshTyping(destination)刷新打字指标一次
withTyping(destination, work)显示打字指标,同时 work 运行
addReaction({ roomId, messageId }, emoji)对消息的反应
addressedMessage(event, { reasons })承认一个事件是给观众的讯息

请求帮助者接受 { signal } 作为他们最后的论点。 准备的行动 收进去 send({ signal })。 。 。 . postMessage, (中文(简体) ), reply, (中文(简体) ), 财务报告和审定财务报表 ctx.reply 返回 ids 新信件内容。 其他帮助者包括: conversationKey, (中文(简体) ), replyDestination, (中文(简体) ), withTyping 财务报告和审定财务报表 startTyping 页:1 自定义输入更新,以及 createDeliveryTracker 用于重放过滤器.

等待最后答复 withTyping(destination, work) 发布前 留言。 帮助者停止计时器 等待任何等待更新,与 2秒请求超时。 无法成功刷新 在消息后恢复打字指示符.

信件机构可以包含emoji的短码,例如: Hello :wave:编辑 服务器保存此文本。 客户端选择如何显示. 对于定制渲染器, @chatto/client/messaging/emojiShortcodes 出口 resolveEmoji(name) 页:1 对大小写敏感的内置名称和 emojiShortcodes(text) 源区域 有 Unicode 或未知结果。 在Unicode 字母、数字和组合旁的标记 标记或下划线. emojiShortcodeQuery(textBeforeCursor) 读取一个部分名称,其自动完成的开放边界相同。 解析 先标出并只扫描出品;留下代码和URL不变. 自定义emoji 未支持资产.

Skin-tone 短码使用 Slack 语法 : :thumbsup::skin-tone-4: 显示为 👍🏽. 通音从2 (光)到6 (暗). 支持的混合通配对使用两个 数字在一个后缀中,例如 :couple::skin-tone-2-6:不支持的组合 保持文字状态。 反应API没有周围的结肠取同名. 旧服务器可以拒绝这些反应名称;没有连接底部增加值 所需经费。 现有名称和Unicode消息内容保持不变.

emojiNameFromUnicode(emoji) 返回选定的稳定反应名称 Unicode emoji,包括其语气. 未知序列返回 undefined。 。 。 . 对新选择使用此帮助; 保持现有反应名称不变 .

mise codegen-emoji 构建客户端语气映射、服务器映射和转换器映射 (单位:千美元)tools/emoji-map.json)来自gemoji和被捆绑的Unicode Emoji 15.0数据. 转换器应该查找此地图中的完整名称, 而不是附加 a 修饰为基格. 生成的地图在运行时不需要网络呼叫 .

对于需要重试安全性的发送,保留准备操作:

const send = server.prepareMessage(destination, 'Hello');
const { id } = await send.send({ signal });
// After a lost response, call send.send() again with the same operation.

每个准备的发送分配一个UUID. 精确重试使用此密钥和相同 参数。 UI 消息 API 也曝光 prepareMessage(input) 并保留 上传附件ID. 准备的寄件留在记忆中。 他们不再重复了 距离第一次投球还有30分钟 MessageSendExpiredError。 。 。 . 在启动新发送前检查原始结果 。 需要重试安全性 所有用于支持信息创建的复制件; 旧服务器可以 忽略密钥. postMessage 财务报告和审定财务报表 reply 能够发送多个部件; 重试 整个帮手开始给这些零件发新信.

对于具有可更新证书的服务器,隐私重置无效保留 发送。 他们的下一个 send() 掷出 StaleResponseError 不再张贴. 在启动新发送前检查原始结果 。 固定托肯寄出还剩 跨隐私重置有效,但服务器关闭后无法发送.

对于任何其他请求, service(Service) 创建输入的连接客户端 服务器的认证. @chatto/client/types 有协议的 信息和服务,以及 @chatto/client/types/admin 行政部门 API : (英语)

import { UserService } from '@chatto/client/types';

const { user } = await server.service(UserService).getUser({
  target: { case: 'userId', value: authorId }
});

无国籍请求

createApi 提出没有实时连接或保留状态的请求, 例如,在webhook处理器中,或用于在工作结束后可以继续的工作 服务器关闭 :

import { createApi } from '@chatto/client';

const api = createApi({ serverUrl, apiKey });
const { viewerId } = await api.ready({ signal }); // read once, then reused
await api.reply(message, 'Done', { signal });

它使用Connect JSON,拒绝重定向,并装入没有商店. 过 viewerId 当主机已经知道密钥的账户时, 例如 从 server.ready()· ; ready() 然后不发出请求.

除错输出

除错输出关闭了外部浏览器. 打电话 setDebugLogging(true) 写下来 到操纵台.

隐私

只请求联系所配置的服务器 。 每个服务器都收到主机的 IP地址,其证书,以及请求数据. 客户端不登录 符号或信件内容。 客户端移除其私人数据的复制件 认证、授权和隐私界限,并报告这些 与主机的边框; 参见 东道国国。 。 。 .

带有UI的应用程序

一个应用程序创建了一个拥有设备存储和源服务器的客户端, 启动运行时间,并报告用户查看的服务器。 只有这个 服务器保留一个持久的 WebSocket; 其它的则通过投票赶上:

import { createClient } from '@chatto/client';

export const client = createClient({
  storage: 'device', // restore and keep the server catalogue and sessions
  originServer: true, // the page's own server uses its cookie session
  liveServers: 'selected'
});

client.start(); // pair each start() with a stop(), for example on unmount
client.setActiveServer(serverId);
const server = client.server(serverId);

一个进程可以有一个客户端和设备存储, 以及一个来源 服务器.

如果主机之前获取发现 registry.addServer,将答复作为 serverInfo 在第三个参数中避免另一个启动请求. server.serverInfo.init() 共享飞行中发现请求。 继续 和解, 读取 server.serverInfo.discovery 用于答复,或 null 打开 失败。 后一通电话提出了新的要求.

本地存储和浏览器登录

本地主机可以通过 persistence: ServerRegistryPersistence 改为 createClient 改为 storage: 'device'此适配器恢复服务器注册和 单独存储认证。 最新的认证记录覆盖 综合目录快照; null 是清场记录。 写作 在返回之前必须持续完成。 失败的写入必须丢出或返回 false 从 writeAuthentication。读取返回必须返回承诺值. 主机拥有加密,访问控制,以及专属流程访问. 别 让两个进程在不进行共同协调的情况下延长同一个保存的会话.

SDK在发送更新前会保存刷新请求ID. 重新启动时 重新使用该标识,然后在替换证书之前保存和核实 返回新访问符 。 更新请求省略 cookie并拒绝 调头 保留所有认证字段,包括 OAuth 客户端ID 和 在持久记录中刷新请求ID .

@chatto/client/auth/oauth 提供 createOAuthFlow, (中文(简体) ), isOAuthCallback,以及 exchangeOAuthCode 为本地主机。 供应发现的授权 URL,the 主机的公开 OAuth 客户端 ID, 和一个字面回回回回 HTTP 调用 URL 或内置 chatto://desktop/servers/callback?mode=popup 调用。 这个 主机在系统浏览器中打开返回的授权 URL并接收 召回电话。 帮助者使用 S256 PKCE, 交易状态, 精确回调 验证,可选的发行人检查,以及有界限的活字交换. 留着 流动和回调记忆。 永远不要登录他们的代码或核查人。 主机拥有 环回听器、取消、同意UI和客户端元数据文档.

通过交回的证书 persistedBearerSession,将其与 emptyServerSession(),并向 registry.addServer。 。 。 . SDK随后拥有更新和实时状态.

本地密码登录

passwordLogin(origin, { login, password }, { signal }) 返回可再生人类 允许直接密码登录的服务器上的证书。 本地主机供应 他们自己的安全密码域。 请求有15秒的超时和 64 KiB响应限制. 它省略了饼干,拒绝方向调整,并接受HTTPS 或回回回 HTTP 源代码,没有路径、查询或片段.

通过证书 persistedBearerSession 从 @chatto/client/auth/bearerSession,将其与 emptyServerSession() 从 @chatto/client/server/sessions,并向 client.registry.addServer(registration, session)。然后SDK 拥有符号 更新和实时状态。 此函数不保存密码或会话 . 出错会暴露一个状态和一个固定消息,从不显示服务器响应机构. 远程 signOutServer 请求还省略了 cookie 并拒绝重定向 .

东道国国

客户端保存服务器数据. 主机保持自己的状态, 如侧边栏 分组、 搜索结果、 调用媒体或查询缓存, 每个服务器旁边 :

  • 尽可能从服务器获取衍生状态 。 随 服务器,不需要清理.
  • 复制服务器数据的主机必须在服务器上清除副本 边界事件 : onReset, (中文(简体) ), onRoomAccessLost, (中文(简体) ), onRoomAccessRestored, (中文(简体) ), onUserDeleted, (中文(简体) ), onAuthorityChanged, (中文(简体) ), onPermissionsChanged, (中文(简体) ), onSessionEnded,以及 onDispose。 。 。 . onUpdate 报告每个应用事件 资源。 服务器在移除后同步发布每个事件 它的拷贝.
  • 向隐私边界投放的收听器失败私有数据 清除:然后服务器不报告其投影为当前 。 这个 服务器等待承诺 onPermissionsChanged 听众返回 .
  • registry.watchStores(setup) 电话 setup 每个服务器,当 注册在服务器收到实时数据之前创建它.

丝绒

导入 @chatto/client/svelte 一次,在组件读取服务器之前. 斯韦尔特然后用组件读取音轨, $derived,以及 $effect数字 :

<script lang="ts">
  import '@chatto/client/svelte';
  import { client } from '$lib/client';

  let { serverId } = $props();
  const server = $derived(client.server(serverId));
</script>

{#each server?.roomList.rooms ?? [] as room (room.id)}
  <p>{room.name}</p>
{/each}

其他框架可以使用 setReadHook 财务报告和审定财务报表 subscribe 从 @chatto/client/reactivity 同样的.

语音通话

服务器跟踪其当前呼叫 projection.activeCalls客户端 包含没有媒体执行。 连接呼叫的主机执行 并留一个电话到 onRoomAccessLost 财务报告和审定财务报表 onDispose。 。 。 .

反应

软件包有一个小的信号库 @chatto/client/reactivity数字 : signal, (中文(简体) ), computed, (中文(简体) ), effect, (中文(简体) ), effectRoot, (中文(简体) ), batch, (中文(简体) ), untrack, (中文(简体) ), subscribe, (中文(简体) ), ReactiveMap,以及 ReactiveSet。计算值是懒惰的. 当最外层写入结束时,效果会同步运行.

发展

mise test-chatto-client   # type checks, lint, and tests

src/types.ts 财务报告和审定财务报表 src/types/admin.ts 从 @chatto/api-types· ; mise codegen-proto 更新它们和软件包 检查过期时失败 .

见 维持状态 用于包检查和放行指令.

客户端和捆绑生成的协议代码使用Apache-2.0; npm 包包括许可证和 a NOTICE 文档.

版本与发布记录

@chatto/client 共发布 17 个版本,首次发布于 2026/10/24;过去 12 个月发布了 17 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.5.0latest2026/11/09今天
0.5.0-rc.5next2026/11/063 天前
0.5.0-rc.42026/11/035 天前
0.5.0-rc.32026/11/036 天前
0.5.0-rc.22026/11/027 天前
0.5.0-beta.292026/11/017 天前

关于 @chatto/client 的常见问题

@chatto/client 是什么?

框架无关的Chatto客户端:连接、实时投影和响应式存储

如何安装 @chatto/client?

在项目目录运行 npm install @chatto/client,或使用 pnpm add / yarn add / bun add。

@chatto/client 支持 TypeScript 吗?

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

@chatto/client 支持 ESM 还是 CommonJS?

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

@chatto/client 可以商用吗?

@chatto/client 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@chatto/client 的下载量有多少?

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

@chatto/client 还在维护吗?

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