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

debrid-ts

v0.1.1

Published

Typed API clients for debrid services (Real-Debrid, AllDebrid, Premiumize) behind one provider-agnostic interface.

Readme

debrid-ts

Typed TypeScript clients for debrid services — Real-Debrid, AllDebrid and Premiumize — with every documented endpoint as a method, plus one provider-agnostic interface so your code can swap providers by changing a constructor.

  • Zero dependencies, ESM only, works anywhere fetch exists (Node ≥ 18.17, Bun, Deno, browsers, edge runtimes)
  • Full wire types for every endpoint (Rd*, Ad*, Pm*)
  • Normalized Torrent / UserInfo / DownloadLink shapes across providers
  • Consistent errors (DebridError with HTTP status and provider error code)
  • Optional request timeout and HTTP 429 retries; injectable fetch for tests
npm install debrid-ts

Quick start

import { RealDebrid } from 'debrid-ts'

const rd = new RealDebrid(process.env.RD_TOKEN!)

const user = await rd.getUser()
console.log(user.username, user.premium, user.expiresAt)

const torrent = await rd.addMagnet('magnet:?xt=urn:btih:...')
await rd.selectTorrentFiles(torrent.id, 'all') // Real-Debrid only starts after this
// ... poll rd.getTorrent(torrent.id) until status === 'downloaded' ...
const links = await rd.getDownloadLinks(torrent.id) // direct, unrestricted URLs

One interface, any provider

Every client implements DebridProvider:

import { AllDebrid, Premiumize, RealDebrid, type DebridProvider } from 'debrid-ts'

const provider: DebridProvider =
  process.env.PROVIDER === 'ad' ? new AllDebrid(process.env.AD_KEY!)
  : process.env.PROVIDER === 'pm' ? new Premiumize(process.env.PM_KEY!)
  : new RealDebrid(process.env.RD_TOKEN!)

if (await provider.isCached(infoHash)) {
  const torrent = await provider.addMagnet(`magnet:?xt=urn:btih:${infoHash}`)
  const links = await provider.getDownloadLinks(torrent.id)
}
interface DebridProvider {
  readonly name: string
  getUser(): Promise<UserInfo>
  isCached(hashOrMagnet: string): Promise<boolean>
  addMagnet(magnet: string, options?: { host?: string }): Promise<Torrent>
  listTorrents(offset?: number, limit?: number): Promise<Torrent[]>
  getDownloadLinks(torrentId: string): Promise<DownloadLink[]>
}

Provider differences worth knowing

| | Real-Debrid | AllDebrid | Premiumize | | --- | --- | --- | --- | | isCached() | Probe: adds the magnet, selects all files, checks for downloaded, deletes it. An uncached torrent may start for a few seconds. (RD disabled its cache endpoint.) | Probe: uploads the magnet, reads ready, deletes it. | Real lookup via /cache/check, no side effects. | | After addMagnet() | Call selectTorrentFiles() to start. | Starts automatically. | Starts automatically. | | getDownloadLinks() | Unrestricts each host link (one request per file). | Unlocks each /f/ file link (one request per file, delayed links are awaited). | Reads the resulting file/folder; links are direct. | | listTorrents() paging | Server-side. | Client-side slice (API returns all). | Client-side slice (API returns all). | | Torrent.hash / bytes | ✅ | ✅ | Empty — the transfer list has neither. |

Providers

Real-Debrid

const rd = new RealDebrid(token) // https://real-debrid.com/apitoken, or an OAuth access token

Covers every endpoint in the API docs: /disable_access_token, /time, /user, /unrestrict, /traffic, /streaming, /downloads, /torrents, /hosts, /settings. Raw methods return wire types (RdUser, RdTorrentInfo, …).

OAuth helpers are static. For scripts and opensource apps (no client secret), use the device flow with Real-Debrid's public opensource client id:

const device = await RealDebrid.getDeviceCode(undefined, { newCredentials: true })
console.log(`Open ${device.verification_url} and enter ${device.user_code}`)

const { credentials, token } = await RealDebrid.waitForDeviceToken({
  deviceCode: device.device_code,
  expiresIn: device.expires_in,
  interval: device.interval,
})
const rd = new RealDebrid(token.access_token)

// later, when the access token expires:
const refreshed = await RealDebrid.refreshToken({
  clientId: credentials.client_id,
  clientSecret: credentials.client_secret,
  refreshToken: token.refresh_token,
})

Also available: getAuthorizeUrl() + exchangeCode() (website flow), getDeviceToken() / getDeviceCredentials() (single polls) and getTokenWithPassword().

AllDebrid

const ad = new AllDebrid(apiKey) // https://alldebrid.com/apikeys/

Covers every non-deprecated endpoint in the API docs: hosts, user, links (unlock, streaming, delayed, redirector), magnets (upload, .torrent upload, status incl. live mode, files, delete, restart), saved/recent links and reseller vouchers. The { status, data } envelope is unwrapped for you; { status: "error" } throws DebridError.

Get an apikey from a user with the PIN flow:

const pin = await AllDebrid.getPin()
console.log(`Open ${pin.user_url}`)
const apiKey = await AllDebrid.waitForPin(pin)

Premiumize

const pm = new Premiumize(apiKey) // https://www.premiumize.me/account, or an OAuth access token

Covers every endpoint in the API docs: /account, /folder (incl. search and upload), /item, /transfer, /cache, /services, /zip, plus OAuth 2.0 statics (PKCE / auth code via getAuthorizeUrl() + exchangeCode(), device flow via getDeviceCode() + waitForDeviceToken(), and the legacy password grant).

Options

Every client (and every static OAuth helper) accepts:

new RealDebrid(token, {
  timeout: 15_000, // per-request timeout in ms (default: none)
  maxRetries: 2,   // retry HTTP 429 responses, honoring Retry-After (default: 0)
  fetch: myFetch,  // custom fetch (proxies, tests, ...)
})

Errors

Every failure — HTTP errors and errors reported inside a 200 envelope — is a DebridError:

import { DebridError } from 'debrid-ts'

try {
  await ad.unlockLink(url)
} catch (error) {
  if (error instanceof DebridError) {
    error.status  // HTTP status (200 for envelope errors)
    error.code    // provider code: 'bad_token', 'LINK_DOWN', 'not_found', ...
    error.details // raw error payload from the provider
  }
}

Contributing

See CONTRIBUTING.md.

License

MIT