Documentation
¶
Overview ¶
Package github is a minimal GitHub REST client for the desktop data layer. It owns in-app authentication (OAuth device flow, PAT validation) and the typed API calls the feed needs (search, notifications). It deliberately has no feed concepts: profiles, unread state, and polling live in internal/feed.
Index ¶
- Constants
- Variables
- type Client
- func (c *Client) Notifications(ctx context.Context, limit int, ifModifiedSince string) (NotificationsResult, error)
- func (c *Client) PollDeviceFlow(ctx context.Context, clientID string, auth DeviceAuth) (string, error)
- func (c *Client) SearchIssues(ctx context.Context, query string, limit int) (SearchResult, error)
- func (c *Client) StartDeviceFlow(ctx context.Context, clientID string, scopes []string) (DeviceAuth, error)
- func (c *Client) User(ctx context.Context) (User, error)
- func (c *Client) WithTokenCopy(token string) *Client
- type DeviceAuth
- type KeychainStore
- type Label
- type MemoryTokenStore
- type Notification
- type NotificationSubject
- type NotificationsResult
- type Option
- type PullRequest
- type Repository
- type SearchItem
- type SearchResult
- type TokenStore
- type User
Constants ¶
const EnvToken = "HIVE_GITHUB_TOKEN"
EnvToken is the environment override for the GitHub token. It takes precedence over the keychain so headless environments (CI, server builds) never need keychain access.
Variables ¶
var ( ErrRateLimited = errors.New("github: rate limited") ErrUnreachable = errors.New("github: unreachable") )
Sentinel errors form the taxonomy the UI maps onto design states (unauthorized -> re-auth, rate limited / unreachable -> "GitHub unreachable").
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a GitHub REST v3 client. The zero value is not usable; construct with NewClient.
func (*Client) Notifications ¶
func (c *Client) Notifications(ctx context.Context, limit int, ifModifiedSince string) (NotificationsResult, error)
Notifications lists the user's notification inbox, including read threads, so the app can mirror the full inbox and keep triage state locally. A non-empty ifModifiedSince makes the request conditional: authenticated 304 responses are free of rate-limit cost, so polling an unchanged inbox costs nothing.
func (*Client) PollDeviceFlow ¶
func (c *Client) PollDeviceFlow(ctx context.Context, clientID string, auth DeviceAuth) (string, error)
PollDeviceFlow polls the token endpoint until the user authorizes the device, the code expires, or ctx is canceled. It blocks; run it in a goroutine and honor ctx for cancellation.
func (*Client) SearchIssues ¶
SearchIssues runs a GitHub issue/PR search query, newest-updated first.
func (*Client) StartDeviceFlow ¶
func (c *Client) StartDeviceFlow(ctx context.Context, clientID string, scopes []string) (DeviceAuth, error)
StartDeviceFlow requests a device + user code pair for the OAuth device flow. clientID is the public OAuth app client ID.
func (*Client) User ¶
User returns the authenticated user. It doubles as token validation: ErrUnauthorized means the token is missing, revoked, or expired.
func (*Client) WithTokenCopy ¶
WithTokenCopy returns a copy of the client using the given token.
type DeviceAuth ¶
type DeviceAuth struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURI string `json:"verification_uri"`
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval"`
}
DeviceAuth is the pending device authorization the UI presents: the user opens VerificationURI and enters UserCode.
type KeychainStore ¶
type KeychainStore struct{}
KeychainStore stores the token in the OS keychain, with the EnvToken environment variable as a read-only override.
func NewKeychainStore ¶
func NewKeychainStore() *KeychainStore
func (*KeychainStore) DeleteToken ¶
func (s *KeychainStore) DeleteToken() error
func (*KeychainStore) SetToken ¶
func (s *KeychainStore) SetToken(token string) error
func (*KeychainStore) Token ¶
func (s *KeychainStore) Token() (string, error)
type MemoryTokenStore ¶
type MemoryTokenStore struct {
// contains filtered or unexported fields
}
MemoryTokenStore is an in-memory TokenStore for tests and mock mode.
func NewMemoryTokenStore ¶
func NewMemoryTokenStore(token string) *MemoryTokenStore
func (*MemoryTokenStore) DeleteToken ¶
func (s *MemoryTokenStore) DeleteToken() error
func (*MemoryTokenStore) SetToken ¶
func (s *MemoryTokenStore) SetToken(token string) error
func (*MemoryTokenStore) Token ¶
func (s *MemoryTokenStore) Token() (string, error)
type Notification ¶
type Notification struct {
ID string `json:"id"`
Unread bool `json:"unread"`
Reason string `json:"reason"`
UpdatedAt time.Time `json:"updated_at"`
Subject NotificationSubject `json:"subject"`
Repository Repository `json:"repository"`
}
Notification is one thread from the notifications inbox.
type NotificationSubject ¶
type NotificationSubject struct {
Title string `json:"title"`
URL string `json:"url"`
Type string `json:"type"` // "Issue" | "PullRequest" | "Release" | ...
}
NotificationSubject describes what a notification thread is about.
func (NotificationSubject) Number ¶
func (s NotificationSubject) Number() int
Number parses the issue/PR number from the subject API URL. Returns 0 for subjects without one (releases, discussions).
type NotificationsResult ¶
type NotificationsResult struct {
Items []Notification
NotModified bool
LastModified string
PollInterval int
}
NotificationsResult is one notifications poll. When NotModified is true the inbox has not changed since the ifModifiedSince timestamp and Items is nil — the caller keeps its cached copy. LastModified echoes the response's Last-Modified header for the next conditional request, and PollInterval is the server-mandated minimum seconds between polls (X-Poll-Interval, 0 when the header is absent).
type Option ¶
type Option func(*Client)
func WithAPIBase ¶
WithAPIBase overrides the REST API base URL (tests).
func WithAuthBase ¶
WithAuthBase overrides the OAuth base URL used by the device flow (tests).
func WithHTTPClient ¶
WithHTTPClient overrides the underlying HTTP client.
type PullRequest ¶
type PullRequest struct {
HTMLURL string `json:"html_url"`
}
PullRequest marks a search item as a pull request; the search API includes the key only for PRs.
type Repository ¶
type Repository struct {
FullName string `json:"full_name"`
}
Repository identifies the repository a notification belongs to.
type SearchItem ¶
type SearchItem struct {
Number int `json:"number"`
Title string `json:"title"`
Body string `json:"body"`
State string `json:"state"`
HTMLURL string `json:"html_url"`
RepositoryURL string `json:"repository_url"`
User User `json:"user"`
Labels []Label `json:"labels"`
PullRequest *PullRequest `json:"pull_request"`
Draft bool `json:"draft"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
SearchItem is one issue or pull request from the search API.
func (SearchItem) IsPullRequest ¶
func (i SearchItem) IsPullRequest() bool
IsPullRequest reports whether the search item is a pull request.
func (SearchItem) Repo ¶
func (i SearchItem) Repo() string
Repo returns the "owner/name" slug parsed from the repository API URL.
type SearchResult ¶
type SearchResult struct {
TotalCount int `json:"total_count"`
Items []SearchItem `json:"items"`
}
SearchResult is the response of the issue/PR search API.