Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
36b9580
feat: implement StepSearchActors
pirhoo Dec 4, 2025
eb4f3dd
feat: implement StepPostLikers
pirhoo Dec 4, 2025
dd9c6d8
feat: implement StepPostReposters
pirhoo Dec 4, 2025
c3116e6
feat: implement StepPostQuotes
pirhoo Dec 4, 2025
1bdc4e4
feat: implement StepPostThread
pirhoo Dec 4, 2025
e340b18
feat: implement StepPostUnlike
pirhoo Dec 4, 2025
2137269
feat: implement StepPostUnrepost
pirhoo Dec 4, 2025
d884be3
feat: implement StepDeletePost
pirhoo Dec 4, 2025
4de416a
feat: implement StepActorBlocks
pirhoo Dec 4, 2025
286fbef
feat: implement StepActorMutes
pirhoo Dec 4, 2025
9462b06
feat: implement StepActorKnownFollowers
pirhoo Dec 4, 2025
6f3f4e3
feat: implement StepActorSuggestions
pirhoo Dec 4, 2025
15a2e43
feat: implement StepFeed
pirhoo Dec 4, 2025
20e3676
feat: implement StepFeedGenerator
pirhoo Dec 4, 2025
45b1dd0
feat: implement StepSuggestedFeeds
pirhoo Dec 4, 2025
c06231d
feat: implement StepListFeed
pirhoo Dec 4, 2025
ee287d1
feat: implement StepListBlock
pirhoo Dec 4, 2025
c35b4b0
feat: implement StepListUnblock
pirhoo Dec 4, 2025
e136d51
feat: implement StepListMute
pirhoo Dec 4, 2025
def94a5
feat: implement StepListUnmute
pirhoo Dec 4, 2025
d9473cc
feat: implement StepNotifications
pirhoo Dec 4, 2025
e5baf5f
feat: implement StepNotificationsUnreadCount
pirhoo Dec 4, 2025
f5e72b5
feat: implement StepNotificationsUpdateSeen
pirhoo Dec 4, 2025
cb0f37f
feat: implement StepThreadMute
pirhoo Dec 4, 2025
8bbb7c0
feat: implement StepThreadUnmute
pirhoo Dec 4, 2025
a5381f2
fix: reorder exports to avoid circular dependency
pirhoo Dec 4, 2025
255e386
test: increase timing margin in hooks tests
pirhoo Dec 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 26 additions & 33 deletions docs/guide/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,40 +37,33 @@ Trotsky provides comprehensive support for the Bluesky AT Protocol. Below is a l
**StepStarterPacks** | :white_check_mark: | Get a list of starter packs by their URIs. | ```Trotsky.init(agent).starterPacks([uri1, uri2]).each()```
**StepStreamPosts** | :test_tube: | Stream posts from the firehose. | ```Trotsky.init(agent).streamPosts().each()```
**StepTimeline** | :white_check_mark: | Get the authenticated user's timeline. | ```Trotsky.init(agent).timeline().take(20).each()```
**StepSearchActors** | :white_check_mark: | Search for actors by name/handle. | ```Trotsky.init(agent).searchActors({ q: "typescript" }).each()```
**StepPostLikers** | :white_check_mark: | Get actors who liked a post. | ```Trotsky.init(agent).post("at://...").likers().each()```
**StepPostReposters** | :white_check_mark: | Get actors who reposted a post. | ```Trotsky.init(agent).post("at://...").reposters().each()```
**StepPostQuotes** | :white_check_mark: | Get quote posts of a post. | ```Trotsky.init(agent).post("at://...").quotes().each()```
**StepPostThread** | :white_check_mark: | Get a full post thread with replies. | ```Trotsky.init(agent).post("at://...").thread()```
**StepPostUnlike** | :white_check_mark: | Unlike a post. | ```Trotsky.init(agent).post("at://...").unlike()```
**StepPostUnrepost** | :white_check_mark: | Unrepost a post. | ```Trotsky.init(agent).post("at://...").unrepost()```
**StepDeletePost** | :white_check_mark: | Delete a post. | ```Trotsky.init(agent).post("at://...").delete()```
**StepActorBlocks** | :white_check_mark: | Get all actors blocked by the user. | ```Trotsky.init(agent).blocks().each()```
**StepActorMutes** | :white_check_mark: | Get all actors muted by the user. | ```Trotsky.init(agent).mutes().each()```
**StepActorKnownFollowers** | :white_check_mark: | Get known followers (mutual connections). | ```Trotsky.init(agent).actor('bsky.app').knownFollowers().each()```
**StepActorSuggestions** | :white_check_mark: | Get suggested actors to follow. | ```Trotsky.init(agent).suggestions().each()```
**StepFeed** | :white_check_mark: | Get posts from a custom feed. | ```Trotsky.init(agent).feed("at://...").each()```
**StepFeedGenerator** | :white_check_mark: | Get a custom feed generator. | ```Trotsky.init(agent).feedGenerator("at://...")```
**StepSuggestedFeeds** | :white_check_mark: | Get suggested custom feeds. | ```Trotsky.init(agent).suggestedFeeds().take(10)```
**StepListFeed** | :white_check_mark: | Get posts from a list feed. | ```Trotsky.init(agent).list("at://...").feed().each()```
**StepListBlock** | :white_check_mark: | Block a list. | ```Trotsky.init(agent).list("at://...").block()```
**StepListUnblock** | :white_check_mark: | Unblock a list. | ```Trotsky.init(agent).list("at://...").unblock()```
**StepListMute** | :white_check_mark: | Mute a list. | ```Trotsky.init(agent).list("at://...").mute()```
**StepListUnmute** | :white_check_mark: | Unmute a list. | ```Trotsky.init(agent).list("at://...").unmute()```
**StepNotifications** | :white_check_mark: | Get user notifications. | ```Trotsky.init(agent).notifications().take(20)```
**StepNotificationsUnreadCount** | :white_check_mark: | Get unread notification count. | ```Trotsky.init(agent).notificationsUnreadCount()```
**StepNotificationsUpdateSeen** | :white_check_mark: | Mark notifications as seen. | ```Trotsky.init(agent).notificationsUpdateSeen()```
**StepThreadMute** | :white_check_mark: | Mute a thread. | ```Trotsky.init(agent).post("at://...").threadMute()```
**StepThreadUnmute** | :white_check_mark: | Unmute a thread. | ```Trotsky.init(agent).post("at://...").threadUnmute()```

## Planned Features

The following features are planned for future implementation:

**Name** | **Status** | **Description** | **Potential API**
---|---|---|---
**StepActorBlocks** | :construction: | Get all actors blocked by the user. | `app.bsky.graph.getBlocks`
**StepActorKnownFollowers** | :construction: | Get known followers (mutual connections). | `app.bsky.graph.getKnownFollowers`
**StepActorMutes** | :construction: | Get all actors muted by the user. | `app.bsky.graph.getMutes`
**StepActorSuggestions** | :construction: | Get suggested actors to follow. | `app.bsky.actor.getSuggestions`
**StepDeletePost** | :construction: | Delete a post. | Delete post record
**StepFeed** | :construction: | Get posts from a custom feed. | `app.bsky.feed.getFeed`
**StepFeedGenerator** | :construction: | Get a custom feed generator. | `app.bsky.feed.getFeedGenerator`
**StepListBlock** | :construction: | Block a list. | `app.bsky.graph.listblock`
**StepListFeed** | :construction: | Get posts from a list feed. | `app.bsky.feed.getListFeed`
**StepListMute** | :construction: | Mute a list. | `app.bsky.graph.muteActorList`
**StepListUnblock** | :construction: | Unblock a list. | Delete listblock record
**StepListUnmute** | :construction: | Unmute a list. | `app.bsky.graph.unmuteActorList`
**StepNotifications** | :construction: | Get user notifications. | `app.bsky.notification.listNotifications`
**StepNotificationsUnreadCount** | :construction: | Get unread notification count. | `app.bsky.notification.getUnreadCount`
**StepNotificationsUpdateSeen** | :construction: | Mark notifications as seen. | `app.bsky.notification.updateSeen`
**StepPostLikers** | :construction: | Get actors who liked a post. | `app.bsky.feed.getLikes`
**StepPostQuotes** | :construction: | Get quote posts of a post. | `app.bsky.feed.getQuotes`
**StepPostReposters** | :construction: | Get actors who reposted a post. | `app.bsky.feed.getRepostedBy`
**StepPostThread** | :construction: | Get a full post thread with replies. | `app.bsky.feed.getPostThread`
**StepPostUnlike** | :construction: | Unlike a post. | Delete like record
**StepPostUnrepost** | :construction: | Unrepost a post. | Delete repost record
**StepSearchActors** | :construction: | Search for actors by name/handle. | `app.bsky.actor.searchActors`
**StepSuggestedFeeds** | :construction: | Get suggested custom feeds. | `app.bsky.feed.getSuggestedFeeds`
**StepThreadMute** | :construction: | Mute a thread. | `app.bsky.graph.muteThread`
**StepThreadUnmute** | :construction: | Unmute a thread. | `app.bsky.graph.unmuteThread`

<small>:white_check_mark: Implemented • :test_tube: Experimental • :x: In PR/Review • :construction: Planned</small>
<small>:white_check_mark: Implemented • :test_tube: Experimental</small>

<style scoped>
.vp-doc table {
Expand Down
76 changes: 76 additions & 0 deletions lib/core/StepActorBlocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import type { AppBskyGraphGetBlocks } from "@atproto/api"

import { StepActors, type Trotsky } from "../trotsky"

/**
* Type representing the output of the blocked actors retrieved by {@link StepActorBlocks}.
* @public
*/
export type StepActorBlocksOutput = AppBskyGraphGetBlocks.OutputSchema["blocks"]

/**
* Type representing the query parameters for retrieving blocked actors.
* @public
*/
export type StepActorBlocksQueryParams = AppBskyGraphGetBlocks.QueryParams

/**
* Type representing the cursor for paginated queries.
* @public
*/
export type StepActorBlocksQueryParamsCursor = StepActorBlocksQueryParams["cursor"] | undefined

/**
* Represents a step for retrieving the authenticated user's blocked actors using the Bluesky API.
* Supports paginated retrieval of blocked accounts.
*
* @typeParam P - Type of the parent step, extending {@link Trotsky}.
* @typeParam C - Type of the context object.
* @typeParam O - Type of the output object, extending {@link StepActorBlocksOutput}.
*
* @example
* Get and iterate through blocked actors:
* ```ts
* await Trotsky.init(agent)
* .blocks()
* .each()
* .tap((step) => {
* console.log(`Blocked: ${step.context.handle}`)
* })
* .run()
* ```
*
* @example
* Unblock all blocked actors:
* ```ts
* await Trotsky.init(agent)
* .blocks()
* .each()
* .unblock()
* .wait(2000)
* .run()
* ```
*
* @public
*/
export class StepActorBlocks<P = Trotsky, C = null, O extends StepActorBlocksOutput = StepActorBlocksOutput> extends StepActors<P, C, O> {

/**
* Applies pagination to retrieve blocked actors and sets the output.
* Fetches paginated results using the agent and appends them to the output.
*/
async applyPagination () {
this.output = await this.paginate<O, AppBskyGraphGetBlocks.Response>("blocks", (cursor) => {
return this.agent.app.bsky.graph.getBlocks(this.queryParams(cursor))
})
}

/**
* Generates query parameters for retrieving blocked actors, including the optional cursor.
* @param cursor - The cursor for paginated queries.
* @returns The query parameters for retrieving blocked actors.
*/
private queryParams (cursor: StepActorBlocksQueryParamsCursor): StepActorBlocksQueryParams {
return { cursor }
}
}
89 changes: 89 additions & 0 deletions lib/core/StepActorKnownFollowers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { AppBskyGraphGetKnownFollowers } from "@atproto/api"

import {
StepActors,
type StepActor,
type StepActorOutput
} from "../trotsky"

/**
* Type representing the output of the known followers retrieved by {@link StepActorKnownFollowers}.
* @public
*/
export type StepActorKnownFollowersOutput = AppBskyGraphGetKnownFollowers.OutputSchema["followers"]

/**
* Type representing the query parameters for retrieving known followers.
* @public
*/
export type StepActorKnownFollowersQueryParams = AppBskyGraphGetKnownFollowers.QueryParams

/**
* Type representing the cursor for paginated queries.
* @public
*/
export type StepActorKnownFollowersQueryParamsCursor = StepActorKnownFollowersQueryParams["cursor"] | undefined

/**
* Represents a step for retrieving an actor's known followers (mutual connections) using the Bluesky API.
* Supports paginated retrieval of known followers.
*
* @typeParam P - Type of the parent step, extending {@link StepActor}.
* @typeParam C - Type of the context object, extending {@link StepActorOutput}.
* @typeParam O - Type of the output object, extending {@link StepActorKnownFollowersOutput}.
*
* @example
* Get and iterate through an actor's known followers:
* ```ts
* await Trotsky.init(agent)
* .actor("bsky.app")
* .knownFollowers()
* .each()
* .tap((step) => {
* console.log(`Known follower: ${step.context.handle}`)
* })
* .run()
* ```
*
* @example
* Find mutual connections and follow them:
* ```ts
* await Trotsky.init(agent)
* .actor("friend.bsky.social")
* .knownFollowers()
* .each()
* .when((step) => !step?.context?.viewer?.following)
* .follow()
* .wait(2000)
* .run()
* ```
*
* @public
*/
export class StepActorKnownFollowers<P = StepActor, C extends StepActorOutput = StepActorOutput, O extends StepActorKnownFollowersOutput = StepActorKnownFollowersOutput> extends StepActors<P, C, O> {

/**
* Applies pagination to retrieve known followers and sets the output.
* Fetches paginated results using the agent and appends them to the output.
*/
async applyPagination () {
this.output = await this.paginate<O, AppBskyGraphGetKnownFollowers.Response>("followers", (cursor) => {
return this.agent.app.bsky.graph.getKnownFollowers(this.queryParams(cursor))
})
}

/**
* Generates query parameters for retrieving known followers, including the optional cursor.
* @param cursor - The cursor for paginated queries.
* @returns The query parameters for retrieving known followers.
* @throws
* Error if no context is found.
*/
private queryParams (cursor: StepActorKnownFollowersQueryParamsCursor): StepActorKnownFollowersQueryParams {
if (!this.context) {
throw new Error("No context found for StepActorKnownFollowers")
}

return { "actor": this.context.did, cursor }
}
}
76 changes: 76 additions & 0 deletions lib/core/StepActorMutes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import type { AppBskyGraphGetMutes } from "@atproto/api"

import { StepActors, type Trotsky } from "../trotsky"

/**
* Type representing the output of the muted actors retrieved by {@link StepActorMutes}.
* @public
*/
export type StepActorMutesOutput = AppBskyGraphGetMutes.OutputSchema["mutes"]

/**
* Type representing the query parameters for retrieving muted actors.
* @public
*/
export type StepActorMutesQueryParams = AppBskyGraphGetMutes.QueryParams

/**
* Type representing the cursor for paginated queries.
* @public
*/
export type StepActorMutesQueryParamsCursor = StepActorMutesQueryParams["cursor"] | undefined

/**
* Represents a step for retrieving the authenticated user's muted actors using the Bluesky API.
* Supports paginated retrieval of muted accounts.
*
* @typeParam P - Type of the parent step, extending {@link Trotsky}.
* @typeParam C - Type of the context object.
* @typeParam O - Type of the output object, extending {@link StepActorMutesOutput}.
*
* @example
* Get and iterate through muted actors:
* ```ts
* await Trotsky.init(agent)
* .mutes()
* .each()
* .tap((step) => {
* console.log(`Muted: ${step.context.handle}`)
* })
* .run()
* ```
*
* @example
* Unmute all muted actors:
* ```ts
* await Trotsky.init(agent)
* .mutes()
* .each()
* .unmute()
* .wait(2000)
* .run()
* ```
*
* @public
*/
export class StepActorMutes<P = Trotsky, C = null, O extends StepActorMutesOutput = StepActorMutesOutput> extends StepActors<P, C, O> {

/**
* Applies pagination to retrieve muted actors and sets the output.
* Fetches paginated results using the agent and appends them to the output.
*/
async applyPagination () {
this.output = await this.paginate<O, AppBskyGraphGetMutes.Response>("mutes", (cursor) => {
return this.agent.app.bsky.graph.getMutes(this.queryParams(cursor))
})
}

/**
* Generates query parameters for retrieving muted actors, including the optional cursor.
* @param cursor - The cursor for paginated queries.
* @returns The query parameters for retrieving muted actors.
*/
private queryParams (cursor: StepActorMutesQueryParamsCursor): StepActorMutesQueryParams {
return { cursor }
}
}
77 changes: 77 additions & 0 deletions lib/core/StepActorSuggestions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { AppBskyActorGetSuggestions } from "@atproto/api"

import { StepActors, type Trotsky } from "../trotsky"

/**
* Type representing the output of the suggested actors retrieved by {@link StepActorSuggestions}.
* @public
*/
export type StepActorSuggestionsOutput = AppBskyActorGetSuggestions.OutputSchema["actors"]

/**
* Type representing the query parameters for retrieving suggested actors.
* @public
*/
export type StepActorSuggestionsQueryParams = AppBskyActorGetSuggestions.QueryParams

/**
* Type representing the cursor for paginated queries.
* @public
*/
export type StepActorSuggestionsQueryParamsCursor = StepActorSuggestionsQueryParams["cursor"] | undefined

/**
* Represents a step for retrieving suggested actors to follow using the Bluesky API.
* Supports paginated retrieval of suggestions.
*
* @typeParam P - Type of the parent step, extending {@link Trotsky}.
* @typeParam C - Type of the context object.
* @typeParam O - Type of the output object, extending {@link StepActorSuggestionsOutput}.
*
* @example
* Get and iterate through suggested actors:
* ```ts
* await Trotsky.init(agent)
* .suggestions()
* .each()
* .tap((step) => {
* console.log(`Suggested: ${step.context.handle}`)
* })
* .run()
* ```
*
* @example
* Follow suggested actors:
* ```ts
* await Trotsky.init(agent)
* .suggestions()
* .take(10)
* .each()
* .follow()
* .wait(2000)
* .run()
* ```
*
* @public
*/
export class StepActorSuggestions<P = Trotsky, C = null, O extends StepActorSuggestionsOutput = StepActorSuggestionsOutput> extends StepActors<P, C, O> {

/**
* Applies pagination to retrieve suggested actors and sets the output.
* Fetches paginated results using the agent and appends them to the output.
*/
async applyPagination () {
this.output = await this.paginate<O, AppBskyActorGetSuggestions.Response>("actors", (cursor) => {
return this.agent.app.bsky.actor.getSuggestions(this.queryParams(cursor))
})
}

/**
* Generates query parameters for retrieving suggested actors, including the optional cursor.
* @param cursor - The cursor for paginated queries.
* @returns The query parameters for retrieving suggested actors.
*/
private queryParams (cursor: StepActorSuggestionsQueryParamsCursor): StepActorSuggestionsQueryParams {
return { cursor }
}
}
Loading