···1717 case searchActorsTypeahead(query: String, limit: Int)
18181919 // Feed endpoints
2020+ case getFeed(feed: String, limit: Int, cursor: String?)
2021 case getFeedGenerators(feeds: [String])
2122 case getTimeline(limit: Int, cursor: String?)
2223 case getAuthorFeed(did: String, limit: Int, cursor: String?, filter: String?)
···5657 case .searchActors: "/xrpc/app.bsky.actor.searchActors"
5758 case .searchActorsTypeahead: "/xrpc/app.bsky.actor.searchActorsTypeahead"
5859 // Feed
6060+ case .getFeed: "/xrpc/app.bsky.feed.getFeed"
5961 case .getFeedGenerators: "/xrpc/app.bsky.feed.getFeedGenerators"
6062 case .getTimeline: "/xrpc/app.bsky.feed.getTimeline"
6163 case .getAuthorFeed: "/xrpc/app.bsky.feed.getAuthorFeed"
···7981 var httpMethod: HTTPMethod {
8082 switch self {
8183 case .getPreferences, .getProfile, .getProfiles, .searchActors, .searchActorsTypeahead,
8282- .getFeedGenerators, .getTimeline, .getAuthorFeed, .getPostThread, .getPosts, .getActorLikes, .getLikes, .getRepostedBy,
8484+ .getFeed, .getFeedGenerators, .getTimeline, .getAuthorFeed, .getPostThread, .getPosts, .getActorLikes, .getLikes, .getRepostedBy,
8385 .getFollows, .getFollowers, .getBlocks, .getMutes,
8486 .listNotifications, .getUnreadCount:
8587 return .get
···113115 ]))
114116115117 // Feed endpoints
118118+ case .getFeed(let feed, let limit, let cursor):
119119+ var params: Parameters = ["feed": feed, "limit": limit]
120120+ if let cursor { params["cursor"] = cursor }
121121+ return .requestParameters(encoding: .urlEncoding(parameters: params))
122122+116123 case .getFeedGenerators(let feeds):
117124 return .requestParameters(encoding: .urlEncoding(parameters: ["feeds": feeds]))
118125
+11
Sources/bskyKit/BskyService.swift
···119119120120 // MARK: - Feed
121121122122+ /// Fetches a custom feed by its AT-URI.
123123+ /// - Parameters:
124124+ /// - feed: The AT-URI of the feed generator.
125125+ /// - limit: Maximum number of posts to return (default: 50, max: 100).
126126+ /// - cursor: Pagination cursor from a previous response.
127127+ /// - Returns: Feed posts with cursor for pagination.
128128+ /// - Throws: An error if the feed is not found or the request fails.
129129+ public func getFeed(feed: String, limit: Int = 50, cursor: String? = nil) async throws -> AuthorFeed {
130130+ try await router.execute(.getFeed(feed: feed, limit: limit, cursor: cursor))
131131+ }
132132+122133 /// Fetches information about custom feed generators.
123134 /// - Parameter feeds: Array of feed generator AT-URIs.
124135 /// - Returns: Details about the requested feed generators.
+31-7
Sources/bskyKit/Models/Preferences.swift
···88import Foundation
991010public struct Preferences: Codable, Sendable {
1111- public var preferences: [Preference]
1111+ public var preferences: [PreferenceItem]
1212}
13131414-public struct Preference: Codable, Sendable {
1414+public struct PreferenceItem: Codable, Sendable {
1515 public let type: String
1616- public var saved: [String]
1717- public var pinned: [String]
1818-1616+ public let items: [SavedFeedItem]?
1717+ public let saved: [String]?
1818+ public let pinned: [String]?
1919+1920 enum CodingKeys: String, CodingKey {
2021 case type = "$type"
2121- case saved
2222- case pinned
2222+ case items, saved, pinned
2323 }
2424}
25252626+public struct SavedFeedItem: Codable, Sendable, Identifiable {
2727+ public let id: String
2828+ public let type: String
2929+ public let value: String
3030+ public let pinned: Bool
3131+}
3232+3333+// MARK: - Convenience
3434+3535+public extension Preferences {
3636+ var savedFeedItems: [SavedFeedItem] {
3737+ preferences
3838+ .filter { $0.type == "app.bsky.actor.defs#savedFeedsPrefV2" }
3939+ .flatMap { $0.items ?? [] }
4040+ }
4141+4242+ var pinnedFeeds: [SavedFeedItem] {
4343+ savedFeedItems.filter(\.pinned)
4444+ }
4545+4646+ var savedFeeds: [SavedFeedItem] {
4747+ savedFeedItems.filter { !$0.pinned }
4848+ }
4949+}