@bsky/sdk

中文文档
1.3.0发布于 2026/10/17MIT OR Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 3.1万

Bluesky SDK 与 @ atproto/ lex 一起使用

中文使用文档
文档目录15 节
  1. 安装
  2. 开始
  3. 使用量
  4. 会话管理
  5. 经认证的公众客户
  6. API电话
  7. 审定和类型
  8. 丰富文本
  9. 调和
  10. 高级
  11. 高级 API 呼叫
  12. 自己拿来
  13. 子路径
  14. 从@atproto/ api 升级
  15. 许可证

@bsky/ sdk (英语)

Bluesky SDK 创建于 @ atproto/ lex (韩语). 提供 Bluesky 词汇定义、打字动作、节制公用事业、丰富文本的助手和字符串公用事业.

安装

npm install @bsky/sdk @atproto/lex

@atproto/lex 提供 Client 给API拨打的电源. @bsky/sdk 提供布鲁斯基特有的词汇、行动和公用事业.

开始

import { Client } from '@atproto/lex'
import { PasswordSession } from '@atproto/lex-password-session'
import { post } from '@bsky/sdk'

const session = await PasswordSession.login({
  service: 'https://bsky.social',
  identifier: 'your.bsky.social', // your handle
  password: 'xxxx-xxxx-xxxx-xxxx', // an app password, generated in the Bluesky app
})
const client = new Client(session)

await client.call(post, { text: 'Hello, world!' })

使用量

会话管理

大多数API的电话都需要经过认证的会话. 有两种方法 管理会议:

  1. 基于密码的 App 会话管理
  2. 基于 OAuth 会话管理

基于密码的 App 会话管理

用户名/ 基于密码的认证可以使用 PasswordSession 课程从 @atproto/lex-password-session。 。 。 .

[叹息]

这种方法被贬值,有利于基于OAuth的会话管理. 没错 建议使用基于 OAuth 会话管理(通过 @atproto/oauth-client-* 软件包).

import { Client } from '@atproto/lex'
import {
  PasswordSession,
  type SessionData,
} from '@atproto/lex-password-session'

const session = await PasswordSession.login({
  service: 'https://bsky.social',
  identifier: 'your.bsky.social', // your handle
  password: 'xxxx-xxxx-xxxx-xxxx', // an app password, generated in the Bluesky app
  onUpdated: (data: SessionData) => saveToStorage(data),
  onDeleted: (data: SessionData) => clearStorage(data.did),
})
const client = new Client(session)
console.log(`Authenticated as: ${client.assertDid}`)

// Next time, resume with the persisted session data to avoid storing
// user credentials:
const resumed = await PasswordSession.resume(loadFromStorage(), {
  onUpdated: (data: SessionData) => saveToStorage(data),
  onDeleted: (data: SessionData) => clearStorage(data.did),
})

基于 OAuth 会话管理

根据应用程序所使用的环境, OAuth 客户端 备有:

每个 @atproto/oauth-client-* 执行有另一种方式来获得 可用于即时 a Client这里有一个 实例恢复先前保存的会话 :

import { Client } from '@atproto/lex'
import { OAuthClient } from '@atproto/oauth-client'

const oauthClient = new OAuthClient({
  // ...
})

const oauthSession = await oauthClient.restore('did:plc:123')

// Instantiate the lex Client using an OAuth session
const client = new Client(oauthSession)

经认证的公众客户

使用 api.* 用于处理 Bluesky 服务的常数 :

import { Client } from '@atproto/lex'
import { api } from '@bsky/sdk'

// Bluesky API (authenticated queries, proxied through the account host;
// record writes and mutations automatically target the account host directly)
const bskyClient = new Client(session, { service: api.app.service })

// Bluesky API (unauthenticated public queries)
const publicBskyClient = new Client(api.app.urlPublic)

API电话

SDK出口许多共同业务的行动. 起诉 客户端为 client.call(action, input)数字 :

import {
  blockActor,
  blockActorList,
  deleteFollow,
  deleteLike,
  deletePost,
  deleteRepost,
  follow,
  getPreferences,
  like,
  muteActor,
  muteActorList,
  post,
  repost,
  unblockActor,
  unblockActorList,
  unmuteActor,
  unmuteActorList,
  updateSeenNotifications,
  upsertProfile,
} from '@bsky/sdk'

// The DID of the user currently authenticated (or undefined)
bskyClient.did
bskyClient.assertDid // Throws if the user is not authenticated

// Feeds and content
await bskyClient.call(post, { text: 'Hello, world!' })
await bskyClient.call(deletePost, postUri)
await bskyClient.call(like, { uri, cid })
await bskyClient.call(deleteLike, likeUri)
await bskyClient.call(repost, { uri, cid })
await bskyClient.call(deleteRepost, repostUri)

// Social graph
await bskyClient.call(follow, { did })
await bskyClient.call(deleteFollow, followUri)
await bskyClient.call(muteActor, { actor })
await bskyClient.call(unmuteActor, { actor })
await bskyClient.call(blockActor, { did })
await bskyClient.call(unblockActor, blockUri)
await bskyClient.call(muteActorList, { list })
await bskyClient.call(unmuteActorList, { list })
await bskyClient.call(blockActorList, { list })
await bskyClient.call(unblockActorList, { list })

// Actors
await bskyClient.call(upsertProfile, (existing) => ({
  ...existing,
  displayName: 'Alice',
}))

// Notifications
await bskyClient.call(updateSeenNotifications, seenAt)

// Preferences
const prefs = await bskyClient.call(getPreferences)

没有专门动作的查询是一个 xrpc 使用生成的调用 词汇表——见 高级 API 呼叫。 。 。 .

审定和类型

词典包括一个完整的类型系统,具有验证和类型护栏. 例如,为了验证邮政记录:

import { app } from '@bsky/sdk/lexicons'

const post = { ... }
if (app.bsky.feed.post.$isTypeOf(post)) {
  // typescript now recognizes `post` may be an app.bsky.feed.post.Main
  // however -- we still need to validate it
  const res = app.bsky.feed.post.main.safeValidate(post)
  if (res.success) {
    // a valid record
  } else {
    // something is wrong
    console.log(res.error)
  }
}

丰富文本

一些记录(i)使用 app.bsky.richtext 词典. 目前richtext只用于链接和提及,但会随着时间推移被扩展以包括粗体,斜体等.

这是 强烈的 建议使用此软件包 RichText 图书馆。 Javascript在utf16中编码字符串,而协议(和大多数其他编程环境)则使用utf8. 二人之间的转换很困难,但是 RichText 帮你处理.

import { currentDatetimeString } from '@atproto/lex'
import { RichText } from '@bsky/sdk/richtext'

// creating richtext — detects mentions and links, resolving mentions to DIDs
const rt = await RichText.resolve(
  'Hello @alice.com, check out this link: https://example.com',
  { resolver: client },
)
const postRecord = {
  $type: 'app.bsky.feed.post',
  text: rt.text,
  facets: rt.facets,
  createdAt: currentDatetimeString(),
}

// rendering as markdown
let markdown = ''
for (const segment of rt.segments()) {
  if (segment.isLink()) {
    markdown += `[${segment.text}](${segment.link?.uri})`
  } else if (segment.isMention()) {
    markdown += `[${segment.text}](https://my-bsky-app.com/user/${segment.mention?.did})`
  } else {
    markdown += segment.text
  }
}

// calculating string lengths
const rt2 = new RichText({ text: 'Hello' })
console.log(rt2.length) // => 5
console.log(rt2.graphemeLength) // => 5
const rt3 = new RichText({ text: '👨‍👩‍👧‍👧' })
console.log(rt3.length) // => 25
console.log(rt3.graphemeLength) // => 1

调和

运用节制制度是一项具有挑战性的任务,但我们已经尽力为您简化了. 调和API帮助处理一系列广泛的任务,包括:

  • 主持人标签
  • 用户变异(包括变异者)
  • 用户屏蔽
  • 哑词
  • 隐藏员额

更多信息,请参见 调和文档。 。 。 .

import { getPreferences } from '@bsky/sdk'
import { moderatePost } from '@bsky/sdk/moderation'

// First get the user's moderation prefs and their label definitions
// =

const prefs = await bskyClient.call(getPreferences)
const labelDefs = {
  /* see the Moderation Documentation for gathering labelDefs */
}

// We call the appropriate moderation function for the content
// =

const postMod = moderatePost(postView, {
  userDid: bskyClient.assertDid,
  prefs: prefs.moderationPrefs,
  labelDefs,
})

// We then use the output to decide how to affect rendering
// =

// in feeds
if (postMod.ui('contentList').filter) {
  // don't include in feeds
}
if (postMod.ui('contentList').blur) {
  // render the whole object behind a cover (use postMod.ui('contentList').blurs to explain)
  if (postMod.ui('contentList').noOverride) {
    // do not allow the cover the be removed
  }
}
if (postMod.ui('contentList').alert || postMod.ui('contentList').inform) {
  // render warnings on the post
  // find the warnings in postMod.ui('contentList').alerts and postMod.ui('contentList').informs
}

// viewed directly
if (postMod.ui('contentView').filter) {
  // don't render the view
}
if (postMod.ui('contentView').blur) {
  // render the whole object behind a cover (use postMod.ui('contentView').blurs to explain)
  if (postMod.ui('contentView').noOverride) {
    // do not allow the cover the be removed
  }
}
if (postMod.ui('contentView').alert || postMod.ui('contentView').inform) {
  // render warnings on the post
  // find the warnings in postMod.ui('contentView').alerts and postMod.ui('contentView').informs
}

// post embeds in all contexts
if (postMod.ui('contentMedia').blur) {
  // render the whole object behind a cover (use postMod.ui('contentMedia').blurs to explain)
  if (postMod.ui('contentMedia').noOverride) {
    // do not allow the cover the be removed
  }
}

高级

高级 API 呼叫

以上动作为便利包装. 它们覆盖了大部分,但不是全部 现有方法.

《AT议定书》确定了带有反向DNA名称的方法和记录。 你们可以 使用生成的词典和客户端的 call 财务报告和审定财务报表 记录助手 :

import { currentDatetimeString } from '@atproto/lex'
import { app, com } from '@bsky/sdk/lexicons'

// Record helpers always target the user's account host
const res1 = await bskyClient.createRecord({
  $type: 'app.bsky.feed.post',
  text: 'Hello, world!',
  createdAt: currentDatetimeString(),
})
const res2 = await bskyClient.call(
  com.atproto.repo.listRecords,
  { repo: alice.did, collection: 'app.bsky.feed.post' },
  { service: null }, // target the account host rather than the Bluesky API
)
// or, using the typed record convenience helper:
const res2b = await bskyClient.list(app.bsky.feed.post, {
  repo: alice.did, // optional. Defaults to bskyClient.did (throws if unauthenticated)
})

const res3 = await bskyClient.call(app.bsky.feed.getTimeline, {
  limit: 20,
})
// res3: app.bsky.feed.getTimeline.OutputSchema

命名空间根导出自 /lexicons数字 : app, (中文(简体) ), com, (中文(简体) ), chat。 。 。 .

自己拿来

如果你想提供自己的 fetch 执行——用于伐木、嘲笑、, 复试,或没有内置环境 fetch 建筑时通过它 页:1 Client数字 :

import { Client } from '@atproto/lex'

const myFetch: typeof globalThis.fetch = async (input, init) => {
  console.log('requesting', input)
  const response = await globalThis.fetch(input, init)
  console.log('got response', response)
  return response
}

const client = new Client({
  service: 'https://example.com',
  fetch: myFetch,
})

子路径

导入目录
@bsky/sdkapi 常数,动作, DEFAULT_LABEL_SETTINGS
@bsky/sdk/lexicons产生词典定义(app, (中文(简体) ), com, (中文(简体) ), chat(中文(简体) )
@bsky/sdk/moderationmoderatePost, (中文(简体) ), moderateProfile和朋友; ModerationDecision, (中文(简体) ), ModerationUI
@bsky/sdk/richtextRichText 构建器
@bsky/sdk/utils年龄保障助手, sanitizeMutedWordValue, nux 验证

从@atproto/ api 升级

见 技能/升级/升级 包括所有删除的API及其替换.

许可证

根据麻省理工学院和Apache 2.0条款,这个项目具有双重许可证:

下游项目和终端用户可自行选择单独或共同发放许可证。 这种双重许可的动机是Apache 2.0提供的额外软件专利保证.

版本与发布记录

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

版本发布日期距今
1.3.0latest2026/10/1722 天前
1.2.02026/10/1426 天前
1.1.52026/09/291 个月前
1.1.42026/09/221 个月前
1.1.32026/09/111 个月前
1.1.22026/09/042 个月前

其他发布通道:next → 0.1.0-next.1。

关于 @bsky/sdk 的常见问题

@bsky/sdk 是什么?

Bluesky SDK 与 @ atproto/ lex 一起使用

如何安装 @bsky/sdk?

在项目目录运行 npm install @bsky/sdk,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@atproto/lex(^0.3.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@bsky/sdk 支持 TypeScript 吗?

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

@bsky/sdk 支持 ESM 还是 CommonJS?

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

@bsky/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.12.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bsky/sdk 可以商用吗?

@bsky/sdk 使用 MIT OR Apache-2.0 许可。可在 MIT、Apache-2.0 中任选其一遵守。选择 MIT 时,宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@bsky/sdk 的下载量有多少?

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

@bsky/sdk 还在维护吗?

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