Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions .changeset/sweet-otters-profile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@germ-network/atprotoclient": minor
---

Add `GetProfiles` request and associated data to profile defs

Thanks @anna (anna@germ.network)!
6 changes: 4 additions & 2 deletions Sources/AtprotoClient/Agent/Agents/AuthPDSAgent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

import AtprotoTypes

public protocol AuthPDSAgent: Atproto.PDSAgent, Atproto.XRPC.ProxyCallable, Atproto.XRPC
extension Atproto {
public protocol AuthPDSAgent: Atproto.PDSAgent, Atproto.XRPC.ProxyCallable, Atproto.XRPC
.AuthCallable
{
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public enum BskyAppViewAuthedSocialGraphs: Sendable {
case knownFollowers
}

extension AuthPDSAgent {
extension Atproto.AuthPDSAgent {
public func streamSocialGraphs(
for actor: LexiconString.AtIdentifier,
socialGraphType: BskyAppViewAuthedSocialGraphs,
Expand Down
45 changes: 43 additions & 2 deletions Sources/AtprotoClient/Lexicon/AppBsky/Actor/ActorDefs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension Lexicon.App.Bsky.Actor.Defs {
public let description: String?
public let avatar: URL?

//public let associated: ProfileAssociated?
public let associated: ProfileAssociated?

public let indexedAt: LexiconString.Datetime?
public let createdAt: LexiconString.Datetime?
Expand All @@ -46,6 +46,7 @@ extension Lexicon.App.Bsky.Actor.Defs {
pronouns: String?,
description: String?,
avatar: URL?,
associated: ProfileAssociated?,
indexedAt: LexiconString.Datetime?,
createdAt: LexiconString.Datetime?,
viewer: ViewerState?
Expand All @@ -56,6 +57,7 @@ extension Lexicon.App.Bsky.Actor.Defs {
self.pronouns = pronouns
self.description = description
self.avatar = avatar
self.associated = associated
self.indexedAt = indexedAt
self.createdAt = createdAt
self.viewer = viewer
Expand Down Expand Up @@ -88,7 +90,7 @@ extension Lexicon.App.Bsky.Actor.Defs {

public let postsCount: Int?

//public let associated: ProfileAssociated?
public let associated: ProfileAssociated?
//public let joinedViaStarterPack: JoinedViaStarterPack?

public let indexedAt: LexiconString.Datetime?
Expand All @@ -114,6 +116,7 @@ extension Lexicon.App.Bsky.Actor.Defs {
followersCount: Int?,
followsCount: Int?,
postsCount: Int?,
associated: ProfileAssociated?,
indexedAt: LexiconString.Datetime?,
createdAt: LexiconString.Datetime?,
viewer: ViewerState?
Expand All @@ -129,6 +132,7 @@ extension Lexicon.App.Bsky.Actor.Defs {
self.followersCount = followersCount
self.followsCount = followsCount
self.postsCount = postsCount
self.associated = associated
self.indexedAt = indexedAt
self.createdAt = createdAt
self.viewer = viewer
Expand Down Expand Up @@ -190,4 +194,41 @@ extension Lexicon.App.Bsky.Actor.Defs {
self.followedBy = followedBy
}
}

/// [github]: https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/actor/defs.json
public struct ProfileAssociated: Sendable, Codable {
public let lists: Int?
public let feedgens: Int?
public let starterPacks: Int?
public let labeler: Bool?
// public let chat: ProfileAssociatedChat?
// public let activitySubscription: ProfileAssociatedActivitySubscription?
public let germ: ProfileAssociatedGerm?

public init(
lists: Int?,
feedgens: Int?,
starterPacks: Int?,
labeler: Bool?,
germ: ProfileAssociatedGerm?
) {
self.lists = lists
self.feedgens = feedgens
self.starterPacks = starterPacks
self.labeler = labeler
self.germ = germ
}
}

/// [github]: https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/actor/defs.json
public struct ProfileAssociatedGerm: Sendable, Codable {
public let messageMeUrl: URL
// possible values: [usersIFollow, everyone]
public let showButtonTo: String

public init(messageMeUrl: URL, showButtonTo: String) {
self.messageMeUrl = messageMeUrl
self.showButtonTo = showButtonTo
}
}
}
4 changes: 2 additions & 2 deletions Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfile.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// BskyGetProfile.swift
// AtprotoTypes
// GetProfile.swift
// AtprotoClient
//
// Created by Mark @ Germ on 2/26/26.
//
Expand Down
48 changes: 48 additions & 0 deletions Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfiles.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// GetProfiles.swift
// AtprotoClient
//
// Created by Anna Mistele on 6/4/26.
//

import AtprotoTypes
import Foundation
import GermConvenience

///https://docs.bsky.app/docs/api/app-bsky-actor-get-profile
///https://lexicon.garden/lexicon/did:plc:4v4y5r3lwsbtmsxhile2ljac/app.bsky.actor.getProfile/docs
extension Lexicon.App.Bsky.Actor {
public enum GetProfiles: Atproto.XRPC.Request {
public struct Id: Atproto.XRPC.EndpointId {
public static var nsid: Atproto.NSID {
.init(string: "app.bsky.actor.getProfiles")
}

public init() {}
}

public static var outputEncoding: HTTPContentType {
.json
}

public struct Parameters: QueryParametrizable {
public let actor: LexiconString.AtIdentifier

public init(actor: LexiconString.AtIdentifier) {
self.actor = actor
}

public func asQueryItems() -> [URLQueryItem] {
[.init(name: "actor", value: actor.rawValue)]
}
}

public struct Output: Sendable, Codable {
public let profiles: [Lexicon.App.Bsky.Actor.Defs.ProfileViewDetailed]
}
}
}

extension Lexicon.App.Bsky.Actor.GetProfiles: Atproto.XRPC.ResponseParsing {
public static var badRequestErrors: Set<String> { defaultErrors }
}
23 changes: 23 additions & 0 deletions Sources/AtprotoClientMocks/Lexicon/App/Bsky/ActorDefs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ extension Lexicon.App.Bsky.Actor.Defs.ProfileViewDetailed: Mockable {
followersCount: 2,
followsCount: 5,
postsCount: 10,
// TODO: Test with nil associated Germ as well
associated: .mock(),
indexedAt: .init(date: .now),
createdAt: .init(date: .distantPast),
viewer: .init(
Expand All @@ -51,3 +53,24 @@ extension Lexicon.App.Bsky.Actor.Profile: Mockable {
)
}
}

extension Lexicon.App.Bsky.Actor.Defs.ProfileAssociated: Mockable {
public static func mock() -> Lexicon.App.Bsky.Actor.Defs.ProfileAssociated {
.init(
lists: nil,
feedgens: nil,
starterPacks: nil,
labeler: nil,
germ: .mock()
)
}
}

extension Lexicon.App.Bsky.Actor.Defs.ProfileAssociatedGerm: Mockable {
public static func mock() -> Lexicon.App.Bsky.Actor.Defs.ProfileAssociatedGerm {
.init(
messageMeUrl: URL(string: "https://landing.ger.mx/newUser")!,
showButtonTo: "usersIFollow"
)
}
}
2 changes: 1 addition & 1 deletion Sources/AtprotoClientMocks/MockPDS/MockPDS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ extension MockPDS.PublicAgent: Atproto.PDSAgent {
}
}

extension MockPDS.AuthAgent: Atproto.PDSAgent, Atproto.XRPC.AuthCallable {
extension MockPDS.AuthAgent: Atproto.AuthPDSAgent {
public func response(
_ requestComponents: XRPCRequestComponents
) async throws -> HTTPDataResponse {
Expand Down
2 changes: 1 addition & 1 deletion Tests/AtprotoClientTests/OnlineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
import Testing

#if canImport(FoundationNetworking)
import FoundationNetworking
import FoundationNetworking
#endif

struct OnlineTests {
Expand Down
Loading