mcpField
C
connector-x

connector-x

github.com/caffeinelabs开发28.0k 次安装1 周前更新
代码仓库

关于 connector-x

connector-x 提供根据 X API 规范生成的 Motoko 绑定,并说明如何通过 X API v2 发帖,面向构建代表用户发布内容的 canister 的开发者,采用 OAuth 2.0 PKCE。

主要功能

  1. 01X API v2 的 Motoko 绑定
  2. 02使用 TweetsApi.createPosts 发帖
  3. 03OAuth 2.0 PKCE Bearer Token 配置
  4. 04默认发送非复制 HTTP 请求
  5. 05从 JSON 中省略空值可选字段
  6. 06令牌刷新与速率限制说明

适用场景

  1. 01通过 Motoko canister 发布帖子
  2. 02使用 OAuth 2.0 PKCE 授权用户
  3. 03发送前配置帖子字段

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/caffeinelabs/skills --skill connector-x

安装后在 Claude Code 中输入/connector-x确认已加载。

详细介绍

使用 x-client 发布到 X

针对 X API v2 的 Motoko 绑定, 根据 X 的 OpenAPI 规范生成。写入接口是 TweetsApi.createPosts (POST /2/tweets);请求模型是 TweetCreateRequest。

后端

一个精简的 canister,代表持有 OAuth 2.0 bearer token 的用户发布推文(token 的获取和刷新在 canister 端完成,详见下文)。默认不进行复制,因此只需提供 token;所有可选字段都必须存在,null 表示“未提供”:

import { createPosts } "mo:x-client/Apis/TweetsApi";
import { type TweetCreateRequest } "mo:x-client/Models/TweetCreateRequest";
import { defaultConfig } "mo:x-client/Config";

actor {
  // Post a tweet on behalf of a user holding an OAuth 2.0 bearer token.
  public func postTweet(accessToken : Text, body : Text) : async () {
    let cfg = { defaultConfig with auth = ?#bearer accessToken };
    let req : TweetCreateRequest = {
      text_ = ?body;
      for_super_followers_only = null;
      poll = null;
      reply = null;
      reply_settings = null;
      media = null;
      geo = null;
      quote_tweet_id = null;
      nullcast = null;
      direct_message_deep_link = null;
      community_id = null;
      card_uri = null;
      edit_options = null;
      made_with_ai = null;
      paid_partnership = null;
      share_with_followers = null;
    };
    ignore await* createPosts(cfg, req);
  };
}

文本字段为 text_ : ?Text(末尾的下划线可避免与 Motoko 关键字冲突;序列化后对应 JSON 键 "text")。

OAuth 2.0 设置 — PKCE,无客户端密钥

所有写入接口(尤其是 /2/tweets)都需要每位用户各自的 OAuth 2.0 bearer token。x-client 专为 PKCE 流程构建,因此无需客户端密钥,只需要公开的 Client ID。

  1. 访问 X Developer Portal, 创建一个 Project(免费套餐 = 每月 1500 条帖子)和一个 App。

  2. App → Settings → User authentication settings → Edit,开启 OAuth 2.0。 Type of App:Web App, Automated App or Bot(PKCE)。不要选择 Native App 或 "Confidential Client"——这些选项会强制使用本客户端不支持的客户端密钥流程。

  3. Callback URI:接收 ?code=… 的 canister HTTPS 端点,必须完全匹配 (例如 https://<canister-id>.ic0.app/oauth/x/callback)。

  4. 授权时要请求的作用域:

    Scope用途
    tweet.writecreatePosts / 发布所必需
    tweet.read在 UI 中显示“已连接为 @…”
    users.read解析已通过身份验证的用户
    offline.access签发刷新令牌(访问令牌有效期约为 2 小时)
  5. 保存;复制 OAuth 2.0 Client ID(约 30 个字符的公开字符串)。它不是 密钥——可以安全地提交、记录日志或硬编码。

部署模式——选择一种或同时支持两种:由管理员一次性设置的单个canister 级 Client ID(默认),或适用于不应共享速率限制配额的多租户应用的每用户 Client ID。

授权时会请求作用域,但如果未勾选,相应作用域会在签发的 token 中悄然缺失——调用 createPosts 时出现“Insufficient OAuth scope”,几乎总是因为缺少 tweet.write。

调用默认不进行复制

每次 x-client 调用都会在 IC 上发起一次 http_request。该软件包在 defaultConfig 中提供 is_replicated = ?false:X 会产生副作用(发布会更改 状态),其速率限制标头和响应时间戳也会因请求而异,因此,进行复制 调用——每个子网节点都发出请求,IC 要求响应完全一致,消耗约 13 倍 cycles——会导致重复发布并无法通过共识。无需手动设置;默认值就是正确的。只有在确实需要共识时,才将其覆盖为 is_replicated = ?true。

可选字段:保持为 null

x-client 会从出站 JSON 中移除值为 null 的可选字段(通过 serde-core 的 skip_null_fields 选项),因此 /2/tweets 只会收到你设置的字段。构造 TweetCreateRequest 时,设置 text_ = ?"…",其他所有字段均设为 null(如上方代码片段所示),请求正文即可通过验证。Motoko 要求在赋值时提供记录中的所有字段——使用 null 表示“未提供”。

非 null 可选字段的子对象规则

如果将 poll、reply、geo、media 或 edit_options 设为 ?Some,X 会校验相应子对象自身的必填字段——不能发送空对象,因此要么将字段保留为 null,要么完整填充:

  • poll — options(≥ 2)和 duration_minutes。
  • reply — in_reply_to_tweet_id。
  • media — media_ids(必须预先上传)。
  • geo — place_id。

令牌刷新

访问令牌会过期(约 2 小时)。每次调用前,如果距离 expires_at 已进入安全缓冲期,canister 应通过 POST 向 https://api.x.com/2/oauth2/token 发送 grant_type=refresh_token,并提供存储的 refresh_token 和 Client ID。 X 每次刷新都会轮换 refresh token——请存储新的 access_token 和 refresh_token;重用旧的 refresh token 会返回 400,并需要重新授权。x-client 不处理刷新——这由 canister 负责; 标准代码示例请参见 posting-to-x 扩展。

速率限制

免费套餐:每个应用每月可发布 1500 条帖子、读取 500 次。在生产环境中遇到 HTTP 429 时应退避;切勿静默重试帖子(重试可能会导致推文重复)。X 的速率限制标头会随响应正文返回,但该软件包不会对其进行解析。

评论

支持 Markdown