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

@nomyx/gun-sync

v1.3.0

Published

A lightweight, powerful library for synchronizing application state in real-time using Gun.js.

Downloads

4

Readme

@nomyx/gun-sync

A lightweight, powerful library for synchronizing application state in real-time using Gun.js with React hooks and TypeScript support.

Features

  • 🔄 Real-time state synchronization using Gun.js peer-to-peer database
  • ⚛️ React hooks for seamless integration with React applications
  • 🔐 User authentication with built-in auth lifecycle management
  • 👥 Presence tracking to monitor active users
  • 📝 Collection management with CRUD operations
  • 🎯 TypeScript support with full type definitions
  • 🌐 Context provider for easy Gun instance sharing
  • Lightweight with minimal dependencies

Installation

npm install @nomyx/gun-sync gun

Quick Start

1. Setup with Context Provider

import React from 'react';
import { GunProvider } from '@nomyx/gun-sync';
import App from './App';

function Root() {
  return (
    <GunProvider peers={['https://gun-manhattan.herokuapp.com/gun']}>
      <App />
    </GunProvider>
  );
}

2. Use Hooks in Components

import React from 'react';
import { useGunState, useGunUser } from '@nomyx/gun-sync';

function MyComponent() {
  // Synchronized state
  const [message, setMessage] = useGunState('chat', 'currentMessage', '');
  
  // User authentication
  const [userState, userActions] = useGunUser();
  
  return (
    <div>
      <input 
        value={message} 
        onChange={(e) => setMessage(e.target.value)}
        placeholder="Type a message..."
      />
      
      {userState.isLoggedIn ? (
        <button onClick={userActions.signOut}>Sign Out</button>
      ) : (
        <button onClick={() => userActions.signIn('username', 'password')}>
          Sign In
        </button>
      )}
    </div>
  );
}

API Reference

Core Functions

createSync(config: SyncConfig): IGunInstance

Creates and initializes a Gun instance with the specified peer configuration.

import { createSync } from '@nomyx/gun-sync';

const gun = createSync({
  peers: ['https://gun-manhattan.herokuapp.com/gun']
});

Context

<GunProvider peers={string[]}>

Provides a Gun instance to all descendant components.

<GunProvider peers={['wss://gun-us.herokuapp.com/gun']}>
  <App />
</GunProvider>

useGun(): IGunInstance

Accesses the Gun instance from context.

const gun = useGun();

State Management Hooks

useGunState<T>(scope: string, key: string, initialValue: T, gunInstance?: IGunInstance)

Synchronizes a piece of state with Gun.js, similar to useState.

const [count, setCount] = useGunState('app', 'counter', 0);

// Update state
setCount(count + 1);

// Or with function
setCount(prev => prev + 1);

useGunValue<T>(scope: string, key: string, initialValue: T, gunInstance?: IGunInstance)

Read-only access to synchronized values.

const currentUser = useGunValue('app', 'currentUser', null);

useGunSet<T>(scope: string, gunInstance?: IGunInstance)

Manages a synchronized collection of items.

const [items, { addItem, updateItem, removeItem }] = useGunSet<Todo>('todos');

// Add new item (returns generated ID)
const id = addItem({ text: 'Learn Gun.js', completed: false });

// Update item
updateItem(id, { completed: true });

// Remove item
removeItem(id);

Authentication

useGunUser(gunInstance?: IGunInstance)

Manages user authentication lifecycle.

const [userState, userActions] = useGunUser();

// User state
userState.isLoggedIn;   // boolean
userState.isLoading;    // boolean
userState.user;         // user object or null
userState.error;        // error message or undefined

// User actions
await userActions.signUp('alice', 'password123');
await userActions.signIn('alice', 'password123');
userActions.signOut();

Presence Tracking

useGunPresence(scope: string, gunInstance?: IGunInstance)

Tracks active users within a scope.

const activeUsers = useGunPresence('chat-room-1');

// Returns array of PresenceInfo objects
activeUsers.forEach(user => {
  console.log(`User ${user.id} last seen: ${new Date(user.lastSeen)}`);
});

Advanced Usage

Without Context Provider

You can use hooks with a specific Gun instance:

import { createSync, useGunState } from '@nomyx/gun-sync';

function MyComponent() {
  const gun = createSync({ peers: ['https://gun-manhattan.herokuapp.com/gun'] });
  const [data, setData] = useGunState('app', 'data', null, gun);
  
  return <div>{data}</div>;
}

Type Safety

All hooks support TypeScript generics for type safety:

interface User {
  id: string;
  name: string;
  email: string;
}

const [users, userActions] = useGunSet<User>('users');
const [currentUser, setCurrentUser] = useGunState<User | null>('app', 'currentUser', null);

Examples

Real-time Chat

import React, { useState } from 'react';
import { useGunSet, useGunUser } from '@nomyx/gun-sync';

interface Message {
  text: string;
  author: string;
  timestamp: number;
}

function Chat() {
  const [messages, { addItem }] = useGunSet<Message>('chat-messages');
  const [userState] = useGunUser();
  const [newMessage, setNewMessage] = useState('');

  const sendMessage = () => {
    if (newMessage.trim() && userState.user) {
      addItem({
        text: newMessage,
        author: userState.user.alias,
        timestamp: Date.now()
      });
      setNewMessage('');
    }
  };

  return (
    <div>
      <div>
        {messages
          .sort((a, b) => a.timestamp - b.timestamp)
          .map(msg => (
            <div key={msg.id}>
              <strong>{msg.author}:</strong> {msg.text}
            </div>
          ))
        }
      </div>
      
      {userState.isLoggedIn && (
        <div>
          <input
            value={newMessage}
            onChange={(e) => setNewMessage(e.target.value)}
            onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
          />
          <button onClick={sendMessage}>Send</button>
        </div>
      )}
    </div>
  );
}

Collaborative Todo List

import React from 'react';
import { useGunSet } from '@nomyx/gun-sync';

interface Todo {
  text: string;
  completed: boolean;
  createdAt: number;
}

function TodoList() {
  const [todos, { addItem, updateItem, removeItem }] = useGunSet<Todo>('todos');

  const addTodo = (text: string) => {
    addItem({
      text,
      completed: false,
      createdAt: Date.now()
    });
  };

  const toggleTodo = (id: string) => {
    const todo = todos.find(t => t.id === id);
    if (todo) {
      updateItem(id, { completed: !todo.completed });
    }
  };

  return (
    <div>
      <input
        placeholder="Add todo..."
        onKeyPress={(e) => {
          if (e.key === 'Enter') {
            addTodo(e.currentTarget.value);
            e.currentTarget.value = '';
          }
        }}
      />
      
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
            />
            <span style={{ 
              textDecoration: todo.completed ? 'line-through' : 'none' 
            }}>
              {todo.text}
            </span>
            <button onClick={() => removeItem(todo.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Peer Dependencies

  • React >= 16.8.0
  • Gun.js ^0.2020.1239

License

ISC

Contributing

Issues and pull requests are welcome! Please check out the GitHub repository.

Support

For questions and support, please visit the Gun.js community chat.