Skip to content

Commit

Permalink
Merge pull request #10 from MasterJ93/docc
Browse files Browse the repository at this point in the history
Merge DocC to `gh-pages`
  • Loading branch information
MasterJ93 authored Apr 17, 2024
2 parents aeb7f1d + f1e1b06 commit 5b4780c
Show file tree
Hide file tree
Showing 4,530 changed files with 5,145 additions and 4,356 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
2 changes: 1 addition & 1 deletion CNAME
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cjrriley.com
cjrriley.com
9 changes: 9 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@
"version" : "1.0.0"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5",
"version" : "1.5.4"
}
},
{
"identity" : "swiftsoup",
"kind" : "remoteSourceControl",
Expand Down
9 changes: 6 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@ let package = Package(
targets: ["ATProtoKit"]),
],
dependencies: [
.package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.7.0"),
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"),
.package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.7.0")
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0")
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "ATProtoKit",
dependencies: ["SwiftSoup"]
),
dependencies: [
"SwiftSoup",
.product(name: "Logging", package: "swift-log")
])
// .testTarget(
// name: "ATProtoKitTests",
// dependencies: ["ATProtoKit"]),
Expand Down
97 changes: 95 additions & 2 deletions Sources/ATProtoKit/ATProtoKit.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,49 @@
import Foundation
import Logging

/// Defines a protocol for configurations in the `ATProtoKit` API library.
///
/// `ATProtoKitConfiguration` defines the basic requirements for any configuration class or structure
/// within `ATProtoKit`. Any class that conforms to this protocol must be geared for sending API calls to the AT Protocol. Creating a class
/// that conforms to this is useful if you have additional lexicons specific to the service you're running.
///
/// For logging-related tasks, make sure you set up the logging instide the `init()` method and attach it to the `logger` property.
/// ```swift
/// public init(session: UserSession? = nil, logIdentifier: String? = nil, logCategory: String?, logLevel: Logger.Level? = .info) {
/// self.session = session
/// self.logIdentifier = logIdentifier ?? Bundle.main.bundleIdentifier ?? "com.cjrriley.ATProtoKit"
/// self.logCategory = logCategory ?? "ATProtoKit"
/// self.logLevel = logLevel
///
/// #if canImport(os)
/// LoggingSystem.bootstrap { label in
/// ATLogHandler(subsystem: label, category: logCategory ?? "ATProtoKit")
/// }
/// #else
/// LoggingSystem.bootstrap(StreamLogHandler.standardOutput)
/// #endif
///
/// logger = Logger(label: logIdentifier ?? "com.cjrriley.ATProtoKit")
/// logger.logLevel = logLevel ?? .info
/// }
/// ```
public protocol ATProtoKitConfiguration {
/// Represents an authenticated user session within the AT Protocol. Optional.
var session: UserSession? { get }
/// Specifies the logger that will be used for emitting log messages.
///
/// - Note: Be sure to create an instance inside the `init()` method. This is important
var logger: Logger { get }
/// Specifies the identifier for managing log outputs. Optional.
///
/// This should default to the bundle identifier if it's in an Apple platform (`CFBundleIdentifier`).
var logIdentifier: String? { get }
/// Specifies the category name the logs in the logger within ATProtoKit will be in. Optional.
var logCategory: String? { get }
/// Specifies the highest level of logs that will be outputted. Optional.
///
/// This should default to `.info`
var logLevel: Logger.Level? { get }
/// Prepares an authorization value for API requests based on `session` and `pdsURL`.
///
/// This determines whether the "Authorization" header will be included in the request payload. It takes both `shouldAuthenticate` and `pdsURL` into account if
Expand Down Expand Up @@ -88,12 +124,42 @@ extension ATProtoKitConfiguration {
public class ATProtoKit: ATProtoKitConfiguration {
/// Represents an authenticated user session within the AT Protocol. Optional.
public let session: UserSession?
/// Specifies the logger that will be used for emitting log messages.
public private(set) var logger: Logger
/// Specifies the identifier for managing log outputs. Optional. Defaults to the project's `CFBundleIdentifier`.
public let logIdentifier: String?
/// Specifies the category name the logs in the logger within ATProtoKit will be in. Optional. Defaults to `ATProtoKit`.
///
/// - Note: This property is ignored if you're using `StreamLogHandler`.
public let logCategory: String?
/// Specifies the highest level of logs that will be outputted. Optional. Defaults to `.info`.
public let logLevel: Logger.Level?

/// Initializes a new instance of `ATProtoKit`.
///
/// This will also handle some of the logging-related setup. The identifier will either be your project's `CFBundleIdentifier` or an identifier named
/// `com.cjrriley.ATProtoKit`. However, you can manually override this.
/// - Parameters:
/// - session: The authenticated user session within the AT Protocol. Optional.
public init(session: UserSession? = nil) {
/// - logIdentifier: Specifies the identifier for managing log outputs. Optional. Defaults to the project's `CFBundleIdentifier`.
/// - logCategory: Specifies the category name the logs in the logger within ATProtoKit will be in. Optional. Defaults to `ATProtoKit`.
/// - logLevel: Specifies the highest level of logs that will be outputted. Optional. Defaults to `.info`.
public init(session: UserSession? = nil, logIdentifier: String? = nil, logCategory: String? = nil, logLevel: Logger.Level? = .info) {
self.session = session
self.logIdentifier = logIdentifier ?? Bundle.main.bundleIdentifier ?? "com.cjrriley.ATProtoKit"
self.logCategory = logCategory ?? "ATProtoKit"
self.logLevel = logLevel

#if canImport(os)
LoggingSystem.bootstrap { label in
ATLogHandler(subsystem: label, category: logCategory ?? "ATProtoKit")
}
#else
LoggingSystem.bootstrap(StreamLogHandler.standardOutput)
#endif

logger = Logger(label: logIdentifier ?? "com.cjrriley.ATProtoKit")
logger.logLevel = logLevel ?? .info
}

/// Determines the appropriate Personal Data Server (PDS) URL.
Expand Down Expand Up @@ -137,12 +203,39 @@ public class ATProtoKit: ATProtoKitConfiguration {
public class ATProtoAdmin: ATProtoKitConfiguration {
/// Represents an authenticated user session within the AT Protocol. Optional.
public let session: UserSession?
/// Specifies the logger that will be used for emitting log messages.
public private(set) var logger: Logger
/// Specifies the identifier for managing log outputs. Optional. Defaults to the project's `CFBundleIdentifier`.
public let logIdentifier: String?
/// Specifies the category name the logs in the logger within ATProtoKit will be in. Optional. Defaults to `ATProtoKit`.
///
/// - Note: This property is ignored if you're using `StreamLogHandler`.
public let logCategory: String?
/// Specifies the highest level of logs that will be outputted. Optional. Defaults to `.info`.
public let logLevel: Logger.Level?

/// Initializes a new instance of `ATProtoAdmin`.
/// - Parameters:
/// - session: The authenticated user session within the AT Protocol.
public init(session: UserSession? = nil) {
/// - logIdentifier: Specifies the identifier for managing log outputs. Optional. Defaults to the project's `CFBundleIdentifier`.
/// - logCategory: Specifies the category name the logs in the logger within ATProtoKit will be in. Optional. Defaults to `ATProtoKit`.
/// - logLevel: Specifies the highest level of logs that will be outputted. Optional. Defaults to `.info`.
public init(session: UserSession? = nil, logIdentifier: String? = nil, logCategory: String? = nil, logLevel: Logger.Level? = .info) {
self.session = session
self.logIdentifier = logIdentifier ?? Bundle.main.bundleIdentifier ?? "com.cjrriley.ATProtoKit"
self.logCategory = logCategory ?? "ATProtoKit"
self.logLevel = logLevel

#if canImport(os)
LoggingSystem.bootstrap { label in
ATLogHandler(subsystem: label, category: logCategory ?? "ATProtoKit")
}
#else
LoggingSystem.bootstrap(StreamLogHandler.standardOutput)
#endif

logger = Logger(label: logIdentifier ?? "com.cjrriley.ATProtoKit")
logger.logLevel = logLevel ?? .info
}
}

Expand Down
154 changes: 152 additions & 2 deletions Sources/ATProtoKit/Models/Lexicons/app.bsky/Feed/BskyFeedDefs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,44 @@ public struct FeedViewPost: Codable {
// TODO: Check to see if this is correct.
/// The user who reposted the post. Optional.
public var reason: FeedReasonRepost? = nil
/// The feed generator's context.
///
/// - Note: According to the AT Protocol specifications: "Context provided by feed generator that may be passed back alongside interactions."
public let feedContext: String

public init(post: FeedPostView, reply: FeedReplyReference? = nil, reason: FeedReasonRepost? = nil, feedContext: String) {
self.post = post
self.reply = reply
self.reason = reason
self.feedContext = feedContext
}

public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.post = try container.decode(FeedPostView.self, forKey: .post)
self.reply = try container.decodeIfPresent(FeedReplyReference.self, forKey: .reply)
self.reason = try container.decodeIfPresent(FeedReasonRepost.self, forKey: .reason)
self.feedContext = try container.decode(String.self, forKey: .feedContext)
}

public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encode(self.post, forKey: .post)
try container.encodeIfPresent(self.reply, forKey: .reply)
try container.encodeIfPresent(self.reason, forKey: .reason)
// Truncate `description` to 2000 characters before encoding
// `maxGraphemes`'s limit is 300, but `String.count` should respect that limit
try truncatedEncodeIfPresent(self.feedContext, withContainer: &container, forKey: .feedContext, upToLength: 2000)
}

public enum CodingKeys: CodingKey {
case post
case reply
case reason
case feedContext
}
}

/// A data model for a reply reference definition.
Expand Down Expand Up @@ -310,14 +348,20 @@ public struct FeedGeneratorView: Codable {
public var avatarImageURL: URL? = nil
/// The number of likes for the feed generator.
public var likeCount: Int? = nil
/// Indicates whether the feed generator can accept interactions.
///
/// - Note: According to the AT Protocol specifications: "Context that will be passed through to client and may be passed to feed generator back alongside interactions."
public let canAcceptInteractions: Bool?
/// An array of labels. Optional.
public let labels: [Label]?
/// The viewer's state for the feed generator.
public var viewer: FeedGeneratorViewerState? = nil
/// The last time the feed generator was indexed.
@DateFormatting public var indexedAt: Date

public init(feedURI: String, cidHash: String, feedDID: String, creator: ActorProfileView, displayName: String, description: String?, descriptionFacets: [Facet]?, avatarImageURL: URL?, likeCount: Int?, labels: [Label]?, viewer: FeedGeneratorViewerState?, indexedAt: Date) {
public init(feedURI: String, cidHash: String, feedDID: String, creator: ActorProfileView, displayName: String, description: String?,
descriptionFacets: [Facet]?, avatarImageURL: URL?, likeCount: Int?, canAcceptInteractions: Bool?, labels: [Label]?,
viewer: FeedGeneratorViewerState?, indexedAt: Date) {
self.feedURI = feedURI
self.cidHash = cidHash
self.feedDID = feedDID
Expand All @@ -327,6 +371,7 @@ public struct FeedGeneratorView: Codable {
self.descriptionFacets = descriptionFacets
self.avatarImageURL = avatarImageURL
self.likeCount = likeCount
self.canAcceptInteractions = canAcceptInteractions
self.labels = labels
self.viewer = viewer
self._indexedAt = DateFormatting(wrappedValue: indexedAt)
Expand All @@ -343,6 +388,7 @@ public struct FeedGeneratorView: Codable {
self.descriptionFacets = try container.decodeIfPresent([Facet].self, forKey: .descriptionFacets)
self.avatarImageURL = try container.decodeIfPresent(URL.self, forKey: .avatarImageURL)
self.likeCount = try container.decodeIfPresent(Int.self, forKey: .likeCount)
self.canAcceptInteractions = try container.decodeIfPresent(Bool.self, forKey: .canAcceptInteractions)
self.labels = try container.decodeIfPresent([Label].self, forKey: .labels)
self.viewer = try container.decodeIfPresent(FeedGeneratorViewerState.self, forKey: .viewer)
self.indexedAt = try container.decode(DateFormatting.self, forKey: .indexedAt).wrappedValue
Expand All @@ -359,7 +405,7 @@ public struct FeedGeneratorView: Codable {

// Truncate `description` to 3000 characters before encoding
// `maxGraphemes`'s limit is 300, but `String.count` should respect that limit
try truncatedEncodeIfPresent(self.description, withContainer: &container, forKey: .displayName, upToLength: 3000)
try truncatedEncodeIfPresent(self.description, withContainer: &container, forKey: .description, upToLength: 3000)

try container.encodeIfPresent(self.descriptionFacets, forKey: .descriptionFacets)
try container.encodeIfPresent(self.avatarImageURL, forKey: .avatarImageURL)
Expand All @@ -368,6 +414,7 @@ public struct FeedGeneratorView: Codable {
if let likeCount = self.likeCount, likeCount >= 0 {
try container.encode(likeCount, forKey: .likeCount)
}
try container.encodeIfPresent(self.canAcceptInteractions, forKey: .canAcceptInteractions)
try container.encodeIfPresent(self.labels, forKey: .labels)
try container.encodeIfPresent(self.viewer, forKey: .viewer)
try container.encode(self._indexedAt, forKey: .indexedAt)
Expand All @@ -383,6 +430,7 @@ public struct FeedGeneratorView: Codable {
case descriptionFacets = "descriptionFacets"
case avatarImageURL = "avatar"
case likeCount
case canAcceptInteractions = "acceptsInteractions"
case labels
case viewer
case indexedAt
Expand Down Expand Up @@ -458,6 +506,108 @@ public struct FeedThreadgateView: Codable {
}
}

/// The main data model definition for an interaction for an item in a feed generator.
///
/// - SeeAlso: This is based on the [`app.bsky.feed.defs`][github] lexicon.
///
/// [github]: https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/feed/defs.json
public struct FeedInteraction: Codable {
/// The item itself. Optional.
public let item: String?
/// The interaction event of the feed generator. Optional.
public let event: FeedInteractionEvent?
/// The feed generator's context. Optional.
///
/// - Note: According to the AT Protocol specifications: "Context on a feed item that was orginally supplied by the feed generator on getFeedSkeleton."
public let feedContext: String?

public init(item: String, event: FeedInteractionEvent, feedContext: String) {
self.item = item
self.event = event
self.feedContext = feedContext
}

public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.item = try container.decode(String.self, forKey: .item)
self.event = try container.decode(FeedInteractionEvent.self, forKey: .event)
self.feedContext = try container.decode(String.self, forKey: .feedContext)
}

public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encode(self.item, forKey: .item)
try container.encode(self.event, forKey: .event)
// Truncate `description` to 2000 characters before encoding
// `maxGraphemes`'s limit is 300, but `String.count` should respect that limit
try truncatedEncodeIfPresent(self.feedContext, withContainer: &container, forKey: .feedContext, upToLength: 2000)
}

enum CodingKeys: CodingKey {
case item
case event
case feedContext
}
}

/// A data model definition for an interaction event.
///
/// - SeeAlso: This is based on the [`app.bsky.feed.defs`][github] lexicon.
///
/// [github]: https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/feed/defs.json
public enum FeedInteractionEvent: Codable {
/// Indicates the feed generator should request less content similar to the feed's item.
///
/// - Note: According to the AT Protocol specifications: "Request that less content like the given feed item be shown in the feed."
case requestLess
/// Indicates the feed generator should request more content similar to the feed's item.
///
/// - Note: According to the AT Protocol specifications: "Request that more content like the given feed item be shown in the feed."
case requestMore
/// Indicates the feed generator clicked on the feed's item.
///
/// - Note: According to the AT Protocol specifications: "User clicked through to the feed item."
case clickthroughItem
/// Indicates the user clicked on the author of the feed's item.
///
/// - Note: According to the AT Protocol specifications: "User clicked through to the author of the feed item."
case clickthroughAuthor
/// Indicates the user clicked on the reposter of the feed's item.
///
/// - Note: According to the AT Protocol specifications: "User clicked through to the reposter of the feed item."
case clickthroughReposter
/// Indicates the user clicked on the embedded content of the feed's item.
///
/// - Note: According to the AT Protocol specifications: "User clicked through to the embedded content of the feed item."
case clickthroughEmbed
/// Indicates the user has viewed the item in the feed.
///
/// - Note: According to the AT Protocol specifications: "Feed item was seen by user."
case interactionSeen
/// Indicates the user has liked the item of the feed.
///
/// - Note: According to the AT Protocol specifications: "User liked the feed item."
case interactionLike
/// Indicates the user has reposted the item of the feed.
///
/// - Note: According to the AT Protocol specifications: "User reposted the feed item."
case interactionRepost
/// Indicates the user has replied to the item of the feed.
///
/// - Note: According to the AT Protocol specifications: "User replied to the feed item."
case interactionReply
/// Indicates the user has quote posted the feed's item.
///
/// - Note: According to the AT Protocol specifications: "User quoted the feed item."
case interactionQuote
/// Indicates the user has shared the feed's item.
///
/// - Note: According to the AT Protocol specifications: "User shared the feed item."
case interactionShare
}

// MARK: - Union Types
/// A reference containing the list of the types of embeds.
///
Expand Down
Loading

0 comments on commit 5b4780c

Please sign in to comment.