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

@prophetdo/beta

v0.0.18-beta

Published

The official client SDK for building Prophet app front-ends

Readme

@prophetdo/beta

The official client SDK for building Prophet app front-ends. This package combines the Prophet client, React bindings, SDK, UI components, and styles into a single install.

Install

npm install @prophetdo/beta

Quick Start

Import the base styles in your app entry point, then wrap your app in ProphetApp:

// main.tsx
import "@prophetdo/beta/styles.css";
import { ProphetApp } from "@prophetdo/beta/react";
import { App } from "./App";

function main() {
  return (
    <ProphetApp
      org="your-org"
      app="your-app"
      platform="https://beta.prophet.do"
    >
      <App />
    </ProphetApp>
  );
}
// App.tsx
import { useSubscribe, useMutation, useCurrentUser } from "@prophetdo/beta/react";
import { Button, Card, Input } from "@prophetdo/beta/ui";

function App() {
  const { data: todos } = useSubscribe("listTodos", { list_id: "default" });
  const addTodo = useMutation("addTodo");
  const { user } = useCurrentUser();

  return (
    <Card>
      <h1>Welcome, {user?.name}</h1>
      <ul>
        {todos?.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
      <Button onClick={() => addTodo({ list_id: "default", title: "New todo" })}>
        Add Todo
      </Button>
    </Card>
  );
}

Package Exports

@prophetdo/beta

Core client for connecting to a Prophet app over WebSockets.

import { createProphetClient, ProphetClient } from "@prophetdo/beta";

| Export | Description | | --------------------- | ------------------------------------------------- | | createProphetClient | Factory to create a configured ProphetClient | | ProphetClient | Core client class for subscriptions and mutations | | ProphetError | Error class for Prophet client errors | | WebSocketManager | Low-level WebSocket connection manager | | applyChanges | Utility to apply change entries to a data set |

@prophetdo/beta/react

React hooks and components for building Prophet apps.

import { ProphetApp, useSubscribe, useMutation } from "@prophetdo/beta/react";

Components

| Component | Description | | -------------- | -------------------------------------------------------------- | | ProphetApp | Top-level wrapper that connects to your Prophet app | | Switch | Client-side route switch | | Route | Declares a route pattern and renders children when matched | | Link | Client-side navigation link |

Hooks

| Hook | Description | | ----------------- | --------------------------------------------------------- | | useSubscribe | Subscribe to a live query — returns reactive data | | useMutation | Get a function to execute a mutation | | useBatchMutation| Execute multiple mutations in a single batch | | useCurrentUser | Get the currently authenticated user | | useUser | Look up a user by ID | | useMembers | Subscribe to members/presence on an entity | | usePresence | Track and broadcast presence state | | useFile | Load a file record by ID | | useUploadFile | Get a function to upload files | | useAI | Access the AI client for server-side AI endpoints | | useLocation | Read and set the current client-side location | | useRoute | Match the current location against a route pattern | | useParams | Read route parameters from the matched route |

@prophetdo/beta/ui

Pre-built UI components based on shadcn/ui and Radix UI primitives, styled with Tailwind CSS and designed to work with Prophet's theme.

import { Button, Dialog, DialogTrigger, DialogContent, Input, Select } from "@prophetdo/beta/ui";

| Component | Exports | Built on | | --- | --- | --- | | Avatar | Avatar, AvatarImage, AvatarFallback | @radix-ui/react-avatar | | Badge | Badge, badgeVariants | — | | Button | Button, buttonVariants | @radix-ui/react-slot | | Calendar | Calendar | react-day-picker | | Card | Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter | — | | ColorPicker | ColorPicker | — | | Command | Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut | cmdk | | Dialog | Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose | @radix-ui/react-dialog | | DropdownMenu | DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent | @radix-ui/react-dropdown-menu | | Input | Input | — | | Label | Label | @radix-ui/react-label | | Popover | Popover, PopoverTrigger, PopoverContent | @radix-ui/react-popover | | RadioGroup | RadioGroup, RadioGroupItem | @radix-ui/react-radio-group | | ScrollArea | ScrollArea, ScrollBar | @radix-ui/react-scroll-area | | Select | Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SelectGroup, SelectLabel, SelectSeparator | @radix-ui/react-select | | Separator | Separator | @radix-ui/react-separator | | Switch | Switch | @radix-ui/react-switch | | Table | Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption | — | | Tabs | Tabs, TabsList, TabsTrigger, TabsContent | @radix-ui/react-tabs | | Textarea | Textarea | — | | Tooltip | Tooltip, TooltipTrigger, TooltipContent, TooltipProvider | @radix-ui/react-tooltip |

A cn utility is also exported for merging Tailwind classes:

import { cn } from "@prophetdo/beta/ui";

@prophetdo/beta/share

Pre-built sharing UI: a ShareButton trigger and a configurable ShareDialog for managing permissions on any entity. The dialog integrates with Prophet's user system automatically and supports any scope model your app defines.

import { ShareButton, ShareDialog } from "@prophetdo/beta/share";

| Export | Description | | --- | --- | | ShareButton | A styled button with the share icon. Accepts variant ("ghost" | "outline") and an optional label. | | ShareDialog | A configurable permissions dialog. Apps provide scopes, current members, and mutation callbacks. |

ShareButton

Drop-in share trigger:

import { ShareButton } from "@prophetdo/beta/share";

<ShareButton onClick={() => setShareOpen(true)} />
<ShareButton variant="outline" label="Share" onClick={() => setShareOpen(true)} />

ShareDialog

The dialog handles user search, org-wide access, and member management. You configure it by providing your app's scopes and wiring up mutations. If the built-in props don't cover your needs (e.g. custom permission levels, approval workflows, or app-specific UI), treat this component as a starting point — copy the source into your app and customize it to match your exact permission and scope model.

import { useState } from "react";
import { useMembers, useMutation } from "@prophetdo/beta/react";
import { ShareButton, ShareDialog } from "@prophetdo/beta/share";
import type { ShareScope } from "@prophetdo/beta/share";

// Define the scopes your app supports
const SCOPES: ShareScope[] = [
  { name: "editor", label: "Editor" },
  { name: "viewer", label: "Viewer" },
];

function DocumentToolbar({ documentId }: { documentId: string }) {
  const [shareOpen, setShareOpen] = useState(false);
  const { data: members } = useMembers(DocumentMembers, { entity: documentId });
  const shareUser = useMutation("shareDocument");
  const unshareUser = useMutation("unshareDocument");
  const shareOrg = useMutation("shareDocumentOrg");
  const unshareOrg = useMutation("unshareDocumentOrg");

  return (
    <>
      <ShareButton variant="outline" label="Share" onClick={() => setShareOpen(true)} />

      <ShareDialog
        open={shareOpen}
        onOpenChange={setShareOpen}
        title="Share Document"
        scopes={SCOPES}
        members={members ?? {}}
        onShareUser={(userId, scope) =>
          shareUser({ document: documentId, user: userId, scope })
        }
        onUnshareUser={(userId) =>
          unshareUser({ document: documentId, user: userId })
        }
        onShareOrg={(scope) =>
          shareOrg({ document: documentId, scope })
        }
        onUnshareOrg={() =>
          unshareOrg({ document: documentId })
        }
      />
    </>
  );
}

Props reference:

| Prop | Type | Description | | --- | --- | --- | | open | boolean | Whether the dialog is visible | | onOpenChange | (open: boolean) => void | Called when dialog should open/close | | title | string | Dialog header text (default: "Share") | | scopes | ShareScope[] | Available roles, e.g. [{ name: "editor", label: "Editor" }] | | members | Record<string, string[]> | Current members keyed by scope. Use "authenticatedUsers" for org-wide. | | ownerScope | string | Which scope represents owners (default: "owner") — owners can't be removed | | onShareUser | (userId, scope) => void | Called when a user is invited | | onUnshareUser | (userId) => void | Called when a user is removed | | onShareOrg | (scope) => void | Called when org-wide access is granted. Omit to hide org sharing. | | onUnshareOrg | () => void | Called when org-wide access is revoked |

@prophetdo/beta/styles.css

Base stylesheet that includes Prophet's theme variables, Tailwind base layers, and bundled font-face rules (Barlow, Zain, JetBrains Mono). Import this once in your app entry point:

import "@prophetdo/beta/styles.css";

@prophetdo/beta/sdk

The platform SDK for managing Prophet apps, deployments, users, files, and secrets programmatically.

import { ProphetAPI } from "@prophetdo/beta/sdk";

const api = new ProphetAPI({
  baseUrl: "https://beta.prophet.do",
  token: "your-api-token",
});

const apps = await api.listApps();

Usage Examples

Subscribing to Data

useSubscribe takes a query name (defined in your Prophet manifest) and its arguments, and returns live-updating data:

import { useSubscribe } from "@prophetdo/beta/react";

function NotesList({ folderId }: { folderId: string }) {
  const { data: notes, error } = useSubscribe("listNotes", { folder_id: folderId });

  if (error) return <div>Error: {error.message}</div>;
  if (!notes) return <div>Loading...</div>;

  return (
    <ul>
      {notes.map((note) => (
        <li key={note.id}>{note.title}</li>
      ))}
    </ul>
  );
}

Running Mutations

useMutation returns a callable function for the named mutation:

import { useMutation } from "@prophetdo/beta/react";

function CreateNote({ folderId }: { folderId: string }) {
  const createNote = useMutation("createNote");

  const handleCreate = async () => {
    const result = await createNote({ folder_id: folderId, title: "Untitled" });
    console.log("Created:", result);
  };

  return <button onClick={handleCreate}>New Note</button>;
}

Batch Mutations

Use useBatchMutation when you need to execute multiple mutations atomically:

import { useBatchMutation } from "@prophetdo/beta/react";

function BulkActions() {
  const { mutate, flush } = useBatchMutation();

  const archiveAll = async (ids: string[]) => {
    for (const id of ids) {
      mutate("archiveNote", { id });
    }
    await flush();
  };

  return <button onClick={() => archiveAll(selectedIds)}>Archive Selected</button>;
}

Presence

Track who's online and broadcast cursor positions or other ephemeral state:

import { usePresence } from "@prophetdo/beta/react";

function Cursors({ documentId }: { documentId: string }) {
  const { peers, update } = usePresence("document", documentId, {
    cursor: { x: 0, y: 0 },
  });

  const handleMouseMove = (e: React.MouseEvent) => {
    update({ cursor: { x: e.clientX, y: e.clientY } });
  };

  return (
    <div onMouseMove={handleMouseMove}>
      {peers.map((peer) => (
        <div
          key={peer.userId}
          style={{ position: "absolute", left: peer.data.cursor.x, top: peer.data.cursor.y }}
        >
          {peer.userName}
        </div>
      ))}
    </div>
  );
}

Client-Side Routing

Prophet includes a lightweight client-side router:

import { Switch, Route, Link } from "@prophetdo/beta/react";

function App() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/settings">Settings</Link>
    </nav>
    <Switch>
      <Route path="/" exact>
        <HomePage />
      </Route>
      <Route path="/notes/:id">
        <NoteDetail />
      </Route>
      <Route path="/settings">
        <Settings />
      </Route>
    </Switch>
  );
}
import { useParams } from "@prophetdo/beta/react";

function NoteDetail() {
  const { id } = useParams<{ id: string }>();
  const { data: notes } = useSubscribe("getNote", { id });
  // ...
}

License

MIT