github

package
v0.58.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package github is a minimal GitHub REST client: in-app authentication (OAuth device flow, PAT validation) and typed search/notification calls.

Nothing in this repository imports it — it exists for the hive-desktop app (hay-kot/hive-desktop), which vendors hive's internal packages at a pinned commit. Keep it building and tested here; removing it would break the desktop's vendor sync.

Index

Constants

View Source
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

View Source
var (
	ErrUnauthorized = errors.New("github: unauthorized")
	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 NewClient

func NewClient(opts ...Option) *Client

func (*Client) GetIssue added in v0.58.0

func (c *Client) GetIssue(ctx context.Context, owner, repo string, number int) (Issue, error)

GetIssue fetches and normalizes one GitHub issue.

func (*Client) GetPullRequest added in v0.58.0

func (c *Client) GetPullRequest(ctx context.Context, owner, repo string, number int) (Issue, error)

GetPullRequest fetches and normalizes one GitHub pull request.

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) SearchIssuesBatch added in v0.58.0

func (c *Client) SearchIssuesBatch(ctx context.Context, reqs []SearchRequest) ([][]SearchItem, error)

SearchIssuesBatch runs every request as an aliased search field of a single GraphQL query, newest-updated first. Results map back to requests by index: out[i] answers reqs[i]. Query text is passed via GraphQL variables ($q0, $q1, ...), never interpolated.

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

func (c *Client) User(ctx context.Context) (User, error)

User returns the authenticated user. It doubles as token validation: ErrUnauthorized means the token is missing, revoked, or expired.

func (*Client) WithTokenCopy

func (c *Client) WithTokenCopy(token string) *Client

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 Issue added in v0.58.0

type Issue struct {
	Number    int
	State     string
	Merged    bool
	UpdatedAt time.Time
}

Issue is a hydrated single issue or pull request. State is normalized to open/closed; Merged is meaningful only for pull requests.

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 Label

type Label struct {
	Name string `json:"name"`
}

Label is an issue/PR label.

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

func WithAPIBase(base string) Option

WithAPIBase overrides the REST API base URL (tests).

func WithAuthBase

func WithAuthBase(base string) Option

WithAuthBase overrides the OAuth base URL used by the device flow (tests).

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) Option

WithHTTPClient overrides the underlying HTTP client.

func WithToken

func WithToken(token string) Option

WithToken sets the bearer token used for API calls.

type RateLimitError added in v0.58.0

type RateLimitError struct {
	// ResetAt is when the limit resets. It is zero when the server supplied
	// neither Retry-After nor X-RateLimit-Reset.
	ResetAt time.Time
}

RateLimitError is a rate-limit response carrying the server-provided retry time. It unwraps to ErrRateLimited so errors.Is-based handling keeps working; callers that can honor the wait can inspect ResetAt with errors.As.

func (*RateLimitError) Error added in v0.58.0

func (e *RateLimitError) Error() string

func (*RateLimitError) Unwrap added in v0.58.0

func (e *RateLimitError) Unwrap() error

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
	Title         string
	Body          string
	State         string
	URL           string // html URL
	Repo          string // "owner/name" (repository.nameWithOwner)
	Author        string // author.login; "" for deleted (ghost) users
	Labels        []Label
	IsPullRequest bool // __typename == "PullRequest"
	Draft         bool // isDraft; always false for issues
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

SearchItem is one issue or pull request from the batched GraphQL search.

type SearchRequest added in v0.58.0

type SearchRequest struct {
	Query string // GitHub search syntax; "sort:updated-desc" is appended by the client
	Limit int    // max items for this search (GraphQL `first`)
}

SearchRequest is one search in a batched GraphQL issue/PR search.

type TokenStore

type TokenStore interface {
	Token() (string, error)
	SetToken(token string) error
	DeleteToken() error
}

TokenStore persists the GitHub token. Token returns "" (no error) when no token is stored.

type User

type User struct {
	Login     string `json:"login"`
	Name      string `json:"name"`
	AvatarURL string `json:"avatar_url"`
}

User is the authenticated GitHub user.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL