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

@lastshotlabs/snapshot

v0.8.0

Published

React frontend framework for slingshot-powered backends

Readme

Snapshot

Snapshot is a code-first React SDK for Slingshot-powered apps. Create one runtime in TypeScript, compose hooks and standalone UI components in React, and sync backend schemas when you want generated client code.

What You Get

  • createSnapshot({ apiUrl }) for auth, account, OAuth, MFA, WebAuthn, realtime, community, webhook, routing, and API primitives.
  • TanStack Query integration through a pre-bound QueryProvider.
  • Generated API types and React Query hooks from a Slingshot OpenAPI schema.
  • Standalone UI components from @lastshotlabs/snapshot/ui.
  • Vite helpers for OpenAPI sync, SSR, RSC, PPR, prefetch metadata, and static route metadata.
  • CLI commands for scaffolding apps and syncing API contracts.

Registry setup

Snapshot is published to the public npm registry. No token, no .npmrc, no scope mapping — install it like any other package:

npm install @lastshotlabs/snapshot

Every release from 0.2.0 onward is published to both npmjs.org and GitHub Packages. The two registries carry identical versions; npmjs.org is the recommended channel because it needs no authentication.

GitHub Packages requires authentication even for public packages. Only use this channel if your organization mandates it:

  1. Create a GitHub personal access token with the read:packages scope.

  2. Add to your project's .npmrc (or ~/.npmrc):

    @lastshotlabs:registry=https://npm.pkg.github.com
    //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
  3. Export the token where you install: export GITHUB_TOKEN=ghp_… (do the same in CI).

The default registry stays npmjs.org, so your other dependencies are unaffected.

Note: versions 0.1.0 and 0.1.4 on npmjs.org are abandoned early artifacts and are not installable — they carry an unresolvable file:vendor/… dependency. Use 0.2.0 or later.

Install

bun add @lastshotlabs/snapshot @tanstack/react-query @tanstack/react-router jotai react react-dom

Install optional peers only for the surfaces you use:

bun add -d vite
bun add react-server-dom-webpack

The 0.3 package boundary keeps editor, markdown, drag-and-drop, and CLI libraries out of a basic install. Add the matching optional peers when you use one of these UI surfaces:

| Surface | Install | | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | rich-input | bun add @tiptap/core @tiptap/extension-link @tiptap/extension-mention @tiptap/extension-placeholder @tiptap/extension-underline @tiptap/pm @tiptap/react @tiptap/starter-kit tiptap-markdown | | rich-text-editor | bun add @codemirror/commands @codemirror/lang-markdown @codemirror/language @codemirror/language-data @codemirror/state @codemirror/view | | Drag-and-drop surfaces such as kanban | bun add @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities | | markdown | bun add react-markdown rehype-highlight remark-gfm highlight.js | | code-block | bun add highlight.js | | chart | bun add recharts | | snapshot CLI | bun add @oclif/core @clack/prompts | | snapshot/vite sync plugin | bun add -d vite @clack/prompts |

The CLI packages are optional too, so apps that only import Snapshot runtime or UI code do not install them.

The CLI also includes snapshot doctor for registry/link/peer diagnostics and snapshot add <component> for copying an application-owned component source graph. Run snapshot add --list to inspect the generated catalog registry.

Use focused @lastshotlabs/snapshot/ui/<name> imports for the minimal dependency path. The compatibility @lastshotlabs/snapshot/ui barrel re-exports the whole catalog and therefore requires every optional UI peer.

Runtime Setup

Create a single Snapshot runtime and import it anywhere your app needs hooks or helpers.

// src/snapshot.ts
import { createSnapshot } from "@lastshotlabs/snapshot";

export const snapshot = createSnapshot({
  apiUrl: import.meta.env.VITE_API_URL,
  auth: {
    session: { mode: "cookie" },
    on: {
      unauthenticated: () => {
        void window.location.assign("/login");
      },
    },
  },
  cache: {
    staleTime: 60_000,
  },
  loginPath: "/login",
  homePath: "/",
  mfaPath: "/mfa",
});

Wrap your React tree with the instance-bound provider:

// src/main.tsx
import { createRoot } from "react-dom/client";
import { snapshot } from "./snapshot";
import { App } from "./App";

createRoot(document.getElementById("root")!).render(
  <snapshot.QueryProvider>
    <App />
  </snapshot.QueryProvider>,
);

Auth

Snapshot returns normal React hooks. Use them inside your own screens and components.

import { isMfaChallenge } from "@lastshotlabs/snapshot";
import { snapshot } from "./snapshot";

export function LoginForm() {
  const login = snapshot.useLogin();

  async function submit(email: string, password: string) {
    const result = await login.mutateAsync({ email, password });

    if (isMfaChallenge(result)) {
      window.location.assign("/mfa");
      return;
    }

    window.location.assign("/");
  }

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const form = new FormData(event.currentTarget);
        void submit(String(form.get("email")), String(form.get("password")));
      }}
    >
      <input name="email" type="email" autoComplete="email" />
      <input name="password" type="password" autoComplete="current-password" />
      <button type="submit" disabled={login.isPending}>
        Sign in
      </button>
    </form>
  );
}

Common runtime hooks include:

| Area | Hooks and helpers | | ---------- | ----------------------------------------------------------------------------------------- | | Auth | useUser, useLogin, useLogout, useRegister, useForgotPassword | | Account | useResetPassword, useVerifyEmail, useSetPassword, useDeleteAccount, useSessions | | MFA | usePendingMfaChallenge, useMfaVerify, useMfaSetup, useMfaMethods | | OAuth | getOAuthUrl, getLinkUrl, useOAuthExchange, useOAuthUnlink | | WebAuthn | useWebAuthnRegisterOptions, useWebAuthnRegister, usePasskeyLogin | | Realtime | useSocket, useRoom, useRoomEvent, useSSE, useSseEvent | | Community | container, thread, reply, reaction, moderation, notification, and search hooks | | Webhooks | endpoint, delivery, and test-delivery hooks | | Routing | protect, guest, protectedBeforeLoad, guestBeforeLoad, setNavigator | | Primitives | api, queryClient, tokenStorage, useWebSocketManager |

Route Guards

Use protect() and guest() with TanStack Router route definitions.

import { createFileRoute } from "@tanstack/react-router";
import { snapshot } from "../snapshot";

export const Route = createFileRoute("/settings")({
  ...snapshot.protect(),
  component: SettingsPage,
});

Register a router-aware navigator once so Snapshot auth flows can navigate through the router instead of falling back to browser history.

import { useEffect } from "react";
import { router } from "./router";
import { snapshot } from "./snapshot";

export function SnapshotNavigationBridge() {
  useEffect(() => {
    snapshot.setNavigator((to, opts) => {
      void router.navigate({ to: to as never, replace: opts.replace });
    });

    return () => snapshot.setNavigator(null);
  }, []);

  return null;
}

API Sync

Generate typed request helpers and React Query hooks from a Slingshot OpenAPI schema.

snapshot sync --api http://localhost:3000
snapshot sync --file ./schema.json --zod
snapshot sync --api http://localhost:3000 --watch

You can also run sync from Vite:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { snapshotSync } from "@lastshotlabs/snapshot/vite";

export default defineConfig({
  plugins: [react(), snapshotSync({ file: "./schema.json", zod: true })],
});

Standalone UI

UI components are plain React components. Import each component from its focused subpath so unused component families and optional peers stay out of the module graph.

import { ButtonBase } from "@lastshotlabs/snapshot/ui/button";
import { CardBase } from "@lastshotlabs/snapshot/ui/card";
import { RichInputBase } from "@lastshotlabs/snapshot/ui/rich-input";

export function Composer() {
  return (
    <CardBase>
      <RichInputBase
        placeholder="Write a reply"
        emitMarkdown
        onSend={({ markdown, text }) => {
          console.log(markdown ?? text);
        }}
      />
      <ButtonBase label="Publish" icon="send" />
    </CardBase>
  );
}

Every catalog component follows the same subpath convention:

import { RichInputBase } from "@lastshotlabs/snapshot/ui/rich-input";
import { EmojiPickerBase } from "@lastshotlabs/snapshot/ui/emoji-picker";
import { GifPickerBase } from "@lastshotlabs/snapshot/ui/gif-picker";

Styling

Snapshot UI uses CSS custom properties with optional token helpers.

import { resolveTokens } from "@lastshotlabs/snapshot/ui/tokens";

const css = resolveTokens({
  flavor: "neutral",
  overrides: {
    colors: {
      primary: "#2563eb",
      background: "#ffffff",
    },
    radius: "md",
    spacing: "default",
  },
});

export function SnapshotTheme() {
  return <style>{css}</style>;
}

Every standalone component accepts React props. Most components also expose className, style, and slots for targeted styling.

Realtime

Configure WebSocket and SSE endpoints in code:

export const snapshot = createSnapshot({
  apiUrl: import.meta.env.VITE_API_URL,
  ws: {
    auth: { strategy: "query-param", paramName: "token" },
    events: {
      "thread.updated": (payload) => {
        console.log(payload);
      },
    },
  },
  sse: {
    endpoints: {
      "/__sse/notifications": {
        events: {
          "community:notification.created": () => {
            console.log("new notification");
          },
        },
      },
    },
  },
});

SSR

Server rendering utilities are exported from @lastshotlabs/snapshot/ssr.

import { createReactRenderer, renderPage } from "@lastshotlabs/snapshot/ssr";

Use snapshotSsr() in Vite when a project needs the Snapshot SSR build helpers:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { snapshotSsr } from "@lastshotlabs/snapshot/vite";

export default defineConfig({
  plugins: [react(), ...snapshotSsr()],
});

CLI

| Command | Purpose | | --------------- | --------------------------------------------------- | | snapshot init | Scaffold a new code-first Snapshot application | | snapshot sync | Generate API types and hooks from an OpenAPI schema |

Package Entry Points

| Import | Purpose | | ---------------------------------------- | --------------------------------------------------------------------- | | @lastshotlabs/snapshot | createSnapshot, runtime hooks, auth/account/community/webhook types | | @lastshotlabs/snapshot/ui | Standalone UI components, tokens, actions, hooks, icons | | @lastshotlabs/snapshot/ui/rich-input | Focused rich input component bundle | | @lastshotlabs/snapshot/ui/emoji-picker | Focused emoji picker component bundle | | @lastshotlabs/snapshot/ui/gif-picker | Focused GIF picker component bundle | | @lastshotlabs/snapshot/vite | snapshotSync, snapshotSsr | | @lastshotlabs/snapshot/ssr | React SSR, RSC, PPR, cache, and prefetch helpers |