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

@ysdk/react

v0.1.2

Published

React hooks for collaborative apps. Multiplayer state that feels like useState.

Readme

@ysdk/react

React hooks for collaborative apps. Multiplayer state that feels like useState.

Built on Yjs. Works with any Yjs WebSocket server. No vendor lock-in.

Install

npm install @ysdk/react

Quick start

Option A: YSDK Cloud (zero setup)

import { YSDKProvider } from '@ysdk/react'

function App() {
  return (
    <YSDKProvider cloud={{ apiKey: "ysdk_live_...", room: "my-room" }}>
      <MyApp />
    </YSDKProvider>
  )
}

Option B: Self-hosted

npx y-websocket
import { YSDKProvider } from '@ysdk/react'

function App() {
  return (
    <YSDKProvider url="ws://localhost:1234" room="my-room">
      <MyApp />
    </YSDKProvider>
  )
}

3. Use shared state

import { useShared } from '@ysdk/react'

function Counter() {
  const [count, setCount] = useShared('count', 0)
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}

Open two browser tabs. Click the button. Both tabs update.

API

<YSDKProvider>

Connects to a Yjs sync server and provides shared state to all child components.

// YSDK Cloud (zero setup, hosted infrastructure)
<YSDKProvider cloud={{ apiKey: "ysdk_live_...", room: "my-room" }}>

// Self-hosted (any y-websocket server)
<YSDKProvider url="ws://localhost:1234" room="my-room">

// Bring your own Y.Doc (you handle sync)
<YSDKProvider doc={myYDoc}>

// Local only (no sync, useful for testing)
<YSDKProvider>

| Prop | Type | Description | |------|------|-------------| | cloud | { apiKey, room, baseUrl? } | Connect to YSDK Cloud | | url | string? | WebSocket server URL (self-hosted) | | room | string? | Room name (used with url) | | doc | Y.Doc? | Bring your own Yjs document |

useShared<T>(key, defaultValue)

Shared state. Works like useState but syncs across all clients.

const [name, setName] = useShared('name', 'Anonymous')

Values are stored in a shared Y.Map. Objects are stored as whole values (last-write-wins on the entire object, not per-field). For deep collaborative object editing, use useYSDK() to access the raw Y.Doc.

useSharedArray<T>(key)

Shared array with CRDT merge semantics. Concurrent insertions merge cleanly.

const [items, ops] = useSharedArray('todos')

ops.push({ text: 'Buy milk', done: false })
ops.insert(0, { text: 'First item', done: false })
ops.delete(2)
ops.clear()

| Operation | Description | |-----------|-------------| | ops.push(...items) | Append to end | | ops.insert(index, ...items) | Insert at position | | ops.delete(index, count?) | Remove items | | ops.clear() | Remove all items | | ops.length | Current item count |

useSharedText(key, defaultValue?)

Shared text with character-by-character CRDT merging.

const { value, setValue, ytext } = useSharedText('title', 'Untitled')

// Simple usage - like a controlled input
<input value={value} onChange={e => setValue(e.target.value)} />

// Advanced - bind ytext directly to CodeMirror, ProseMirror, Tiptap, etc.
// import { yCollab } from 'y-codemirror.next'
// extensions: [yCollab(ytext, awareness)]

| Property | Type | Description | |----------|------|-------------| | value | string | Current text as plain string | | ytext | Y.Text | Raw Yjs text for editor bindings | | setValue | (text: string) => void | Replace entire text content |

usePresence<T>(initialState?)

Track who's connected and share ephemeral user state.

const { peers, setPresence, count } = usePresence({
  name: 'Andy',
  cursor: { x: 0, y: 0 },
})

// Update your cursor
onMouseMove={(e) => setPresence({ cursor: { x: e.clientX, y: e.clientY } })}

// Render other people's cursors
{peers.map((peer, i) => (
  <Cursor key={i} x={peer.cursor.x} y={peer.cursor.y} name={peer.name} />
))}

| Property | Type | Description | |----------|------|-------------| | peers | T[] | Other users' presence state | | setPresence | (state: Partial<T>) => void | Update your presence (merges) | | count | number | Number of connected peers |

useBroadcast<T>(channel)

Fire-and-forget messages to all connected clients. Not persisted.

const { broadcast, onMessage } = useBroadcast('reactions')

// Send
broadcast({ emoji: '🎉', x: 100, y: 200 })

// Receive
useEffect(() => {
  return onMessage((data, senderId) => {
    showReaction(data.emoji, data.x, data.y)
  })
}, [])

useYSDK()

Escape hatch to the raw Yjs document and awareness instance.

const { doc, awareness } = useYSDK()

// Full Yjs API access
const ymap = doc.getMap('my-custom-map')

Self-hosting

Any Yjs WebSocket server works. The simplest:

npx y-websocket

For production, consider Hocuspocus which adds auth, persistence, and webhooks on top of Yjs.

Limitations (v0.1)

  • useShared stores objects as opaque values (last-write-wins on whole object, not per-field CRDT merge). Use useYSDK() for deep collaborative objects.
  • useBroadcast uses awareness state internally. Not suitable for high-frequency events (>10/sec). Late joiners may see the last broadcast message.
  • Changing url or room on YSDKProvider after mount creates a new document (previous state is lost).
  • No built-in persistence. State exists only while at least one client is connected (unless your server persists).

License

MIT