npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lujax/github-sdk

v1.0.0

Published

TypeScript-first GitHub REST API SDK - ergonomic, typed, near-zero dependencies

Downloads

334

Readme

@lujax/github-sdk

A TypeScript-first, ergonomic wrapper around the GitHub REST API. Calls api.github.com directly using native fetch — no Octokit, no third-party HTTP library.

  • Clean TypeScript domain types — camelCase interfaces instead of raw snake_case API responses
  • Typed errorsGithubApiError, InvalidTokenError, MissingConfigError instead of guessing at response shapes
  • Service-based APIgithub.pullRequests.list() instead of hand-building fetch calls
  • Built-in rate limiting, retries, and ETag caching — no extra config required
  • PAT or GitHub App auth, swappable behind one interface
  • Near-zero dependenciesjose for GitHub App JWT signing is the only runtime dependency

Installation

npm install @lujax/github-sdk

Requires Node.js 18 or later (uses native fetch).

Quick start

import { GithubClient } from "@lujax/github-sdk";

const github = new GithubClient({
    token: process.env.GITHUB_TOKEN,
    owner: "lujax-dev",
    repo: "github-sdk",
});

const pullRequests = await github.pullRequests.list();
const repo = await github.repositories.get();

owner, repo, and org are all optional on GithubClientConfig — each service asserts the config it actually needs at construction time, throwing MissingConfigError immediately if something's missing rather than failing later on a request. A GithubClient instance is scoped to one owner/repo pair; to work with multiple repositories, create multiple clients.

Authentication

Personal Access Token (PAT)

The simplest option — pass a token string directly:

const github = new GithubClient({
    token: process.env.GITHUB_TOKEN,
    owner: "lujax-dev",
    repo: "github-sdk",
});

GitHub App

For production use as a GitHub App, pass a GitHubAppAuth instance via auth instead of token. It signs a JWT from your App's private key, exchanges it for an installation access token, and refreshes it automatically as it nears expiry — no extra code required:

import { GithubClient, GitHubAppAuth } from "@lujax/github-sdk";

const github = new GithubClient({
    auth: new GitHubAppAuth({
        appId: process.env.GITHUB_APP_ID,
        privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
        installationId: process.env.GITHUB_APP_INSTALLATION_ID,
    }),
    owner: "lujax-dev",
    repo: "github-sdk",
});

token and auth are both optional individually, but at least one is required — GithubClient throws InvalidTokenError otherwise. If both are set, auth takes precedence.

Both strategies implement the same GitHubAuth interface ({ getToken(): Promise<string> }), so you can switch between them — e.g. PAT locally, GitHub App in production — without changing any other code. PatAuth (also exported) wraps a token identically to passing token directly; use auth: new PatAuth(token) if you'd rather keep every strategy behind the same auth field.

Services

Each service is scoped to the owner/repo/org set on the client and exposed as a property:

| Service | Access | Requires | What it covers | | ------------- | ---------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | Pull Requests | github.pullRequests | owner, repo | list/get/create/update/merge, commits, files, reviews, cycleTime(), isMerged() | | Repositories | github.repositories | owner, repo (some methods need org instead) | get/update/delete, topics, tags, languages, contributors, security settings, org-scoped listing | | Issues | github.issues | owner, repo | list/get/create/update, comments | | Releases | github.releases | owner, repo | list/get/getLatest/getByTag/create/update/delete | | Workflows | github.workflows | owner, repo | list/get workflows, list/get/cancel/re-run runs, trigger dispatch | | Organizations | github.organizations | org | get/update, listings, membership management | | Users | github.users | — | authenticated user, lookup by username/ID, list |

There's no standalone commits service — list commits on a PR via github.pullRequests.listCommits(pullNumber).

Every public method has JSDoc with a runnable example — full signatures are in the source, e.g. PullRequestService.ts, RepositoryService.ts. For complete standalone scripts, see /examples.

Error handling

All non-2xx API responses throw typed errors instead of returning a raw error shape:

import {
    GithubApiError,
    InvalidTokenError,
    MissingConfigError,
} from "@lujax/github-sdk";

try {
    await github.pullRequests.get(9999);
} catch (err) {
    if (err instanceof GithubApiError) {
        console.error(err.status, err.message, err.documentationUrl);
    }
}
  • GithubSdkError — base class for every error the SDK throws
  • GithubApiError — thrown on any non-ok GitHub API response; carries .status, .documentationUrl, and .details
  • InvalidTokenError — thrown when a GithubClient is constructed without token or auth
  • MissingConfigError — thrown when a service is constructed without the owner/repo/org it needs

HTTP behaviour

Built into every request, with no configuration needed:

  • Rate limiting — proactively waits out the reset window when x-ratelimit-remaining hits 0, instead of letting requests fail with a 403
  • Retries — 3 attempts with 1s/2s/4s backoff on 5xx and 429 responses
  • ETag caching — repeat GETs send If-None-Match; a 304 returns the cached body for free and doesn't count against your rate limit

Contributing

See CONTRIBUTING.md for setup, the module pattern, and the PR process.

License

MIT