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

@mrdoge/client

v0.1.2

Published

Mr. Doge client SDK for browsers, React Native, and edge runtimes. Authenticates via a customer-minted JWT — never embeds the API key.

Readme

@mrdoge/client

Mr. Doge SDK for browsers, React Native, and edge runtimes. Authenticates via short-lived JWT tokens your own backend mints — your API key never leaves your server.

npm install @mrdoge/client

Two-package model

| Where you run code | Use | Why | |---|---|---| | Server (Node, Bun, Deno, etc.) | @mrdoge/node | Holds the long-lived sk_live_... API key. Mints tokens. Makes data calls directly. | | Client (Browser, React Native, Cloudflare Workers, etc.) | @mrdoge/client | Holds no key. Calls your backend for short-lived tokens. Makes data calls with those. |

Setup

1. Expose a token-mint route on your backend

// Your backend (Next.js API route, Express, NestJS, anything)
import { MrDoge } from "@mrdoge/node"

const mrdoge = new MrDoge({ apiKey: process.env.MRDOGE_API_KEY! })

// e.g. Next.js App Router
export async function POST() {
  const { token, expiresAt } = await mrdoge.tokens.create({ ttl: 600 })
  return Response.json({ token, expiresAt })
}

ttl is in seconds (default 600, min 60, max 86400). You choose what works for your app: short for paranoid, long for fewer refreshes.

2. Use @mrdoge/client on your frontend

// Your frontend (React component, RN screen, Vue, etc.)
import { MrDoge } from "@mrdoge/client"

const mrdoge = new MrDoge({
  authEndpoint: "/api/mrdoge/token",
})

const matches = await mrdoge.matches.list({ date: "2026-05-13" })

That's the whole integration. Same method names, params, and return types as @mrdoge/node — the only difference is the constructor.

Method surface

Identical to @mrdoge/node (minus tokens.create, which is server-only):

| Resource | Methods | |---|---| | mrdoge.regions | list | | mrdoge.competitions | list | | mrdoge.teams | list | | mrdoge.matches | list, get, trending, search, subscribeLive, subscribe | | mrdoge.ai.picks | list | | mrdoge.ai.recommendations | list |

Available methods depend on your subscription tier. Free has discovery + static reads only; live data and AI features require paid tiers. Calling a tier-locked method returns a ForbiddenError with the upgrade URL in the message.

Subscriptions

const sub = await mrdoge.matches.subscribeLive({})

// Initial snapshot — replace your local state with this
console.log(sub.snapshot)

// Live updates — each push carries full latest state. Replace, don't merge.
sub.on("match.upd", (match) => updateUI(match))
sub.on("match.del", ({ id }) => removeFromUI(id))

// Fired when the SDK reconnects (token refresh, network drop, etc.).
// Server sends a fresh snapshot; replace your local state.
sub.on("snapshot", (newSnap) => replaceState(newSnap))

// Clean up
await sub.cancel()

Token refresh — automatic

The SDK proactively fetches a new token from authEndpoint ~30 seconds before the current one expires, then transparently reconnects with the new token. Your subscriptions persist; you'll see one disconnectedreconnectingconnected lifecycle event, but sub.on(...) listeners stay attached and a fresh snapshot fires automatically.

Custom token fetcher

If you need custom headers, signed requests, or a non-HTTP transport, use fetchToken instead of authEndpoint:

const mrdoge = new MrDoge({
  fetchToken: async () => {
    const res = await fetch("/api/mrdoge/token", {
      headers: { "x-csrf-token": getCsrfToken() },
    })
    return res.json()  // must return { token, expiresAt }
  },
})

Errors

Every error is a typed class. Use instanceof to discriminate.

import {
  UnauthorizedError,
  ForbiddenError,
  RateLimitError,
  ConnectionLimitError,
  AuthEndpointError,
} from "@mrdoge/client"

try {
  await mrdoge.ai.picks.list({})
} catch (err) {
  if (err instanceof ForbiddenError) {
    // tier doesn't include AI; show upgrade prompt
    console.log(err.data) // { method: "ai.picks.list", tier: "growth" }
  } else if (err instanceof RateLimitError) {
    await sleep(err.retryAfterMs)
  } else if (err instanceof AuthEndpointError) {
    // your authEndpoint is broken/down
  }
}

Connection lifecycle

mrdoge.on("connected",     ({ welcome })            => console.log("up", welcome.tier))
mrdoge.on("disconnected",  ({ code, reason })       => console.log("down"))
mrdoge.on("reconnecting",  ({ attempt, delayMs })   => console.log("retrying"))

await mrdoge.close()

React Native notes

Works out of the box in modern RN (0.60+). For best behavior across app backgrounding:

import { AppState } from "react-native"
import { MrDoge } from "@mrdoge/client"

const mrdoge = new MrDoge({ authEndpoint: "..." })

// Optional: nudge the connection awake when the app foregrounds
AppState.addEventListener("change", (state) => {
  if (state === "active") mrdoge.connect()
})

The SDK auto-reconnects on the next call regardless; the explicit connect() just makes the data ready when the user opens the app rather than after their first interaction.

License

Apache 2.0 — same as the rest of the SDK.