@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/betaQuick 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
