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

@resultdev/sdk

v0.12.0

Published

Result Backend SDK - authentication, database, storage, functions, realtime, AI, email, web analytics and customer support for apps built on Result.

Readme

@resultdev/sdk

The SDK for apps built on Result Backend - authentication, database, file storage, serverless functions, realtime, AI models, transactional email, web analytics and customer support, one client.

npm install @resultdev/sdk
import { createClient } from "@resultdev/sdk";

export const backend = createClient({
  baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!,
  anonKey: process.env.NEXT_PUBLIC_BACKEND_ANON_KEY!,
});

Database

const { data, error } = await backend.database
  .from("todos")
  .select()
  .order("created_at", { ascending: false });

await backend.database.from("todos").insert([{ title: "Hello" }]);
await backend.database.from("todos").update({ done: true }).eq("id", id);
await backend.database.from("todos").delete().eq("id", id);

Authentication

await backend.auth.signInWithOAuth("google", {
  redirectTo: window.location.origin,
});

await backend.auth.signUp({ email, password, name });
await backend.auth.signInWithPassword({ email, password });
const { data } = await backend.auth.getCurrentUser();
await backend.auth.signOut();

Once signed in, every database/storage/function call carries the user's session automatically - row-level-secured tables just work.

Google and GitHub are configured on every backend, and there is no callback route to build: the SDK exchanges the code when the client initializes on the page it came back to. Call it from a click handler, not an effect. An app running inside an iframe gets a popup instead of a redirect, because providers refuse to be framed; override with flow: "redirect" | "popup" | "auto".

Sessions persist across reloads, new tabs and framed previews on their own: the access token is kept in memory and the refresh token in a first-party cookie. Call getCurrentUser() once when your app mounts, since that is what restores the session, and keep a loading state while it resolves. onAuthStateChange() reports changes from that point on and does not fire for a session that already exists, so use both. Nothing is written to localStorage, and no refresh timer or callback route is needed.

Storage

const { data } = await backend.storage.from("uploads").uploadAuto(file);

Functions

await backend.functions.invoke("my-function", { method: "POST", body });

Realtime

await backend.realtime.connect();
await backend.realtime.subscribe("chat:room-1");
backend.realtime.on("new_message", (msg) => console.log(msg));
await backend.realtime.publish("chat:room-1", "new_message", { text: "Hi" });

Channels are declared once with the admin key (see the backend guide); subscribing to an undeclared channel fails with REALTIME_UNAUTHORIZED.

AI models

const completion = await backend.ai.chat.completions.create({
  model: "openai/gpt-4o-mini",
  messages: [{ role: "user", content: "Hello!" }],
});
const embeddings = await backend.ai.embeddings.create({
  model: "openai/text-embedding-3-small",
  input: "hello world",
});
const image = await backend.ai.images.generate({
  model: "google/gemini-2.5-flash-image",
  prompt: "A sunset over mountains",
});

Email

await backend.emails.send({ to, subject, html });

Web analytics

No script tag: pass your site id and pageviews, sessions and SPA route changes are tracked automatically wherever the client runs in a browser. No cookies.

export const backend = createClient({
  baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!,
  anonKey: process.env.NEXT_PUBLIC_BACKEND_ANON_KEY!,
  analytics: { siteId: "SITE_ID" },
});

backend.analytics.track("Signup", { plan: "pro" });
backend.analytics.identify("user-123");

Payments

The same code uses Result Payments or the workspace's connected live Stripe account. The provider is resolved by Result, so apps do not branch on Stripe or Paddle and do not hold payment-provider keys.

const { data: plans } = await backend.payments.plans();
await backend.payments.checkout({
  plan: "pro-monthly",
  successUrl: `${window.location.origin}/account?checkout=success`,
});

const { data: subscribed } = await backend.payments.hasAccess("pro-monthly");
const { data: purchased } = await backend.payments.hasPurchased("starter-pack");
const { data: portalUrl } = await backend.payments.portalUrl();

checkout() requires a signed-in buyer. Verified provider events write customers, subscriptions and one-time purchases into the app's own billing tables; redirects never grant access. changePlan() and cancel() also use the active provider automatically.

Customer support

A support launcher on your pages. It opens your Result support page in a panel, and conversations land in your Result support inbox. Visitors need no account.

export const backend = createClient({
  baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!,
  anonKey: process.env.NEXT_PUBLIC_BACKEND_ANON_KEY!,
  support: { handle: "acme" }, // your @handle, without the @
});

useEffect(() => {
  backend.support.mount();
  return () => backend.support.unmount();
}, []);

No support UI ships in this package. The panel frames the hosted page, so the conversation surface updates without a release.

Server-side (Next.js SSR)

import { createServerClient } from "@resultdev/sdk/ssr";

Admin operations (schema changes, service-level reads) use your app's admin key server-side - see your app's page in the Result dashboard for the credentials and the full agent prompt.