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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@leve.ai/socket-client

v1.1.9

Published

React client library for Leve.ai WebSocket API with x-api-key authentication, namespaces, JWT tokens, and private rooms

Readme

🏗️ Estrutura da Biblioteca

lib-react/
├── src/
│   ├── hooks/                    # React Hooks principais
│   │   ├── useSocketConnection.ts       # Conexão com API_KEY + Namespaces
│   │   ├── useChannelSubscription.ts    # Subscription automática de canais
│   │   ├── useMultiChannelSubscription.ts # Subscription em múltiplos canais
│   │   ├── useJWTAuth.ts               # Autenticação JWT com metadata
│   │   └── usePrivateRooms.ts          # Gerenciamento de salas privadas
│   ├── components/
│   │   └── SocketProvider.tsx       # Context Provider para socket
│   ├── types/
│   │   └── index.ts                 # TypeScript types completos
│   └── index.ts                     # Exports principais
├── dist/                        # Build output (gerado automaticamente)
├── package.json                 # Configuração NPM
├── vite.config.ts              # Configuração de build
└── tsconfig.json               # TypeScript config

🚀 Como Usar - Build Local

1. Build da Biblioteca

cd /Users/5ucr4m/Projects/leve.ai/socket/lib-react

# Instalar dependências
npm install

# Build completo (ESM + CJS + Types)
npm run build

# Criar package local para teste
npm pack

2. Usar em Outros Projetos (demo/app1)

cd /Users/5ucr4m/Projects/leve.ai/socket/demo/app1

# Instalar a biblioteca local
npm install ../../lib-react/leve.ai-socket-client-1.1.0.tgz

# Executar o app
npm run dev

📝 Exemplos de Uso

Básico - Conexão e Autenticação

import { useSocketConnection, useJWTAuth } from '@leve.ai/socket-client'

function App() {
  const [apiKey, setApiKey] = useState('lv_development_sk_...')
  const [namespace, setNamespace] = useState('default')

  // Socket connection com nossa biblioteca
  const { socket, isConnected, authenticated, publish, authenticate } = useSocketConnection({
    server: 'http://localhost:3001',
    apiKey: apiKey,
    namespace: namespace
  })

  // JWT Authentication
  const { generateToken } = useJWTAuth({
    server: 'http://localhost:3001',
    apiKey: apiKey
  })

  const handleGenerateJWT = async () => {
    const token = await generateToken({
      userId: 'user123',
      userType: 'customer',
      metadata: { name: 'João', region: 'SP' }
    })
    console.log('Token gerado:', token)
  }

  const handleAuth = async () => {
    await authenticate({
      userId: 'user123',
      userType: 'customer',
      token: jwtToken
    })
  }

  const handleSendMessage = () => {
    publish('chat:demo', { message: 'Hello World!' })
  }

  return (
    <div>
      <button onClick={handleGenerateJWT}>Gerar JWT</button>
      <button onClick={handleAuth}>Autenticar</button>
      <button onClick={handleSendMessage} disabled={!authenticated}>
        Enviar Mensagem
      </button>
      <p>Status: {isConnected ? 'Conectado' : 'Desconectado'}</p>
      <p>Auth: {authenticated ? 'Autenticado' : 'Não autenticado'}</p>
    </div>
  )
}

Canal Único - useChannelSubscription

import { useChannelSubscription } from '@leve.ai/socket-client'

function SingleChannelChat() {
  const { socket, authenticated } = useSocketConnection(/* ... */)

  const { messages, loading, lastMessage } = useChannelSubscription(
    'order:123:chat-support',
    {
      enabled: authenticated,
      onMessage: (message) => {
        console.log('Nova mensagem:', message)
        // Notificar usuário, tocar som, etc.
      }
    },
    socket
  )

  return (
    <div>
      <h3>Chat do Pedido #123</h3>
      <div>
        {messages.map((msg, i) => (
          <div key={i}>
            <strong>{msg.senderName}:</strong> {msg.content}
          </div>
        ))}
      </div>
    </div>
  )
}

Múltiplos Canais - useMultiChannelSubscription 🆕

import { useMultiChannelSubscription } from '@leve.ai/socket-client'

function MultiOrderChat() {
  const { socket, authenticated } = useSocketConnection(/* ... */)

  // ABORDAGEM 1: Lista fixa de pedidos
  const multiChannel = useMultiChannelSubscription(
    [
      'order:123:chat-support',
      'order:456:chat-support',
      'order:789:chat-support'
    ],
    {
      enabled: authenticated,
      onMessage: (message) => {
        console.log('Nova mensagem em qualquer pedido:', message)
      },
      onChannelMessage: (channel, message) => {
        console.log(`Pedido ${channel}:`, message)
        // Atualizar estado específico do pedido
        updatePedidoNotification(channel, message)
      }
    },
    socket
  )

  // Função para adicionar novos pedidos dinamicamente
  const addNewOrder = (orderId: string) => {
    const channel = `order:${orderId}:chat-support`
    multiChannel.subscribeToChannel(channel)
  }

  const removeOrder = (orderId: string) => {
    const channel = `order:${orderId}:chat-support`
    multiChannel.unsubscribeFromChannel(channel)
  }

  return (
    <div>
      <h2>Meus Pedidos ({multiChannel.subscribedChannels.length})</h2>

      {/* Timeline global de mensagens */}
      <div>
        <h3>Últimas Mensagens</h3>
        {multiChannel.allMessages.slice(-5).map((msg, i) => (
          <div key={i}>
            <span>{msg.channel}: {msg.senderName} - {msg.content}</span>
          </div>
        ))}
      </div>

      {/* Mensagens por pedido */}
      <div>
        {multiChannel.subscribedChannels.map(channel => {
          const messages = multiChannel.getChannelMessages(channel)
          return (
            <div key={channel}>
              <h4>{channel} ({messages.length} mensagens)</h4>
              {messages.slice(-3).map((msg, i) => (
                <div key={i}>{msg.senderName}: {msg.content}</div>
              ))}
            </div>
          )
        })}
      </div>

      {/* Controles dinâmicos */}
      <div>
        <button onClick={() => addNewOrder('999')}>
          ➕ Adicionar Pedido #999
        </button>
        <button onClick={() => removeOrder('123')}>
          ❌ Remover Pedido #123
        </button>
      </div>
    </div>
  )
}

Comparação das Abordagens

// OPÇÃO 1: Múltiplos hooks individuais
const pedido1 = useChannelSubscription('order:123:chat', { enabled: true }, socket)
const pedido2 = useChannelSubscription('order:456:chat', { enabled: true }, socket)
const pedido3 = useChannelSubscription('order:789:chat', { enabled: true }, socket)

// ✅ Pros: Simples, cada pedido é independente
// ❌ Contras: Muitos hooks, difícil gerenciar dinamicamente

// OPÇÃO 2: Hook multi-canal
const multiChannel = useMultiChannelSubscription([
  'order:123:chat', 'order:456:chat', 'order:789:chat'
], options, socket)

// ✅ Pros: Um hook, timeline global, controle dinâmico
// ✅ Ideal para: Apps com muitos canais, dashboards, notificações

🔧 Configurações de Build

package.json (NPM-ready)

{
  "name": "@leve.ai/socket-client",
  "version": "1.0.0",
  "main": "dist/index.js",
  "types": "dist/index.d.ts", 
  "module": "dist/index.esm.js",
  "exports": {
    ".": {
      "import": "./dist/index.esm.js",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  }
}

vite.config.ts (Library build)

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'LeveSocketClient',
      formats: ['es', 'cjs']
    },
    rollupOptions: {
      external: ['react', 'react-dom', 'socket.io-client']
    }
  }
})

📋 Scripts Disponíveis

npm run dev          # Watch mode para desenvolvimento
npm run build        # Build completo (Vite + TypeScript)
npm run typecheck    # Verificação de tipos
npm run lint         # ESLint
npm pack            # Criar .tgz para instalação local

🎯 Funcionalidades Implementadas

useSocketConnection

  • ✅ Conexão automática com API_KEY
  • ✅ Namespaces configuráveis ('default' ou personalizado)
  • ✅ Estados: isConnected, isConnecting, authenticated, error
  • ✅ Métodos: subscribe, unsubscribe, publish, authenticate

useJWTAuth

  • ✅ Geração de JWT com metadata personalizável
  • ✅ Validação automática de tokens
  • ✅ Estados: user, isAuthenticating, error
  • ✅ Métodos: generateToken, authenticateUser

usePrivateRooms

  • ✅ Criação de salas privadas com allowedUserIds
  • ✅ Verificação de acesso por token JWT
  • ✅ Estados: privateRooms, loading, error
  • ✅ Métodos: createPrivateRoom, joinPrivateRoom, checkAccess

useChannelSubscription

  • ✅ Subscription automática de canais
  • ✅ Buffer de mensagens com histórico
  • ✅ Estados: messages, loading, error, lastMessage
  • ✅ Callbacks configuráveis para mensagens

useMultiChannelSubscription 🆕

  • ✅ Subscription em múltiplos canais simultaneamente
  • ✅ Mensagens organizadas por canal + timeline global
  • ✅ Gerenciamento dinâmico de canais (subscribe/unsubscribe)
  • ✅ Estados: messagesByChannel, allMessages, subscribedChannels
  • ✅ Métodos: subscribeToChannel, unsubscribeFromChannel, getChannelMessages, clearChannelMessages

🌐 Compatibilidade

  • ✅ ESM (import/export moderno)
  • ✅ CommonJS (require tradicional)
  • ✅ TypeScript (types completos)
  • ✅ React 17+ (peer dependency)
  • ✅ Socket.io-client 4.7+ (dependency)

🚦 Status dos Serviços

Server Principal: ✅ Rodando em localhost:3001 Demo App1: ✅ Rodando em localhost:3001 (com biblioteca integrada)

📈 Próximos Passos

  1. Publicação NPM Oficial:

    npm login
    npm publish --access public
  2. Testes Automatizados:

    npm test  # Implementar testes com Vitest
  3. CI/CD Pipeline:

    • GitHub Actions para build e publicação automática
    • Semantic versioning com conventional commits
  4. Documentação Completa:

    • Storybook para componentes
    • Docs site com exemplos interativos

📚 API Reference - useMultiChannelSubscription

Parâmetros

function useMultiChannelSubscription(
  channels: string[],                          // Array de canais para subscribe
  options: MultiChannelSubscriptionOptions,   // Opções de configuração
  socket?: Socket | null                       // Instância do socket
): MultiChannelSubscriptionHook

Options (MultiChannelSubscriptionOptions)

interface MultiChannelSubscriptionOptions {
  enabled?: boolean                            // Habilita/desabilita subscription (default: true)
  onMessage?: (message: any) => void          // Callback para qualquer mensagem
  onChannelMessage?: (channel: string, message: any) => void  // Callback por canal
}

Retorno (MultiChannelSubscriptionHook)

interface MultiChannelSubscriptionHook {
  // Estados
  messagesByChannel: Record<string, any[]>     // Mensagens organizadas por canal
  allMessages: any[]                           // Timeline global ordenada por timestamp
  loading: boolean                             // Status de carregamento
  error: Error | null                          // Erro se houver
  lastMessage: any | null                      // Última mensagem recebida
  subscribedChannels: string[]                 // Lista de canais ativos

  // Métodos
  subscribeToChannel: (channel: string) => void       // Adicionar canal
  unsubscribeFromChannel: (channel: string) => void   // Remover canal
  getChannelMessages: (channel: string) => any[]      // Buscar mensagens de um canal
  clearChannelMessages: (channel?: string) => void    // Limpar mensagens
}

Exemplos de Uso da API

const multiChannel = useMultiChannelSubscription(
  ['order:123:chat', 'order:456:chat'],
  {
    enabled: authenticated,
    onMessage: (msg) => console.log('Nova mensagem:', msg),
    onChannelMessage: (channel, msg) => {
      console.log(`Canal ${channel}:`, msg)
      // Exemplo: Mostrar notificação específica
      showNotification(channel, msg.content)
    }
  },
  socket
)

// Acessar mensagens por canal
const pedido123Messages = multiChannel.getChannelMessages('order:123:chat')
const pedido456Messages = multiChannel.getChannelMessages('order:456:chat')

// Timeline global (todas as mensagens ordenadas)
const timelineMessages = multiChannel.allMessages

// Controle dinâmico
multiChannel.subscribeToChannel('order:789:chat')    // Adicionar novo pedido
multiChannel.unsubscribeFromChannel('order:123:chat') // Remover pedido finalizado

// Limpeza
multiChannel.clearChannelMessages('order:123:chat')  // Limpar um canal específico
multiChannel.clearChannelMessages()                  // Limpar todos os canais

// Estados úteis
const totalChannels = multiChannel.subscribedChannels.length
const totalMessages = multiChannel.allMessages.length
const isLoading = multiChannel.loading
const hasError = multiChannel.error

📝 Changelog

v1.2.0 🆕

  • NOVO: Hook useMultiChannelSubscription para múltiplos canais
  • 🔄 Subscription simultânea em vários canais
  • 📊 Timeline global + mensagens por canal
  • 🎛️ Controle dinâmico: subscribe/unsubscribe em runtime
  • 🧹 Limpeza seletiva de mensagens por canal
  • 📱 Ideal para apps com múltiplos chats/pedidos

v1.1.0 (Breaking Changes)

  • 🚨 BREAKING: Mudança de autenticação de API Key
    • ANTES: Authorization: Bearer {apiKey}
    • AGORA: x-api-key: {apiKey}
  • 🔄 Hooks atualizados: useJWTAuth, usePrivateRooms
  • 🛡️ Separação clara: x-api-key para projetos, Authorization: Bearer para JWT
  • ✅ Compatível com server-principal v1.1.0+

v1.0.0

  • 🎉 Versão inicial com API_KEY authentication
  • 🔌 WebSocket connection com namespaces
  • 🔐 JWT authentication
  • 🏠 Private rooms com controle de acesso