@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
Maintainers
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 pack2. 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
Publicação NPM Oficial:
npm login npm publish --access publicTestes Automatizados:
npm test # Implementar testes com VitestCI/CD Pipeline:
- GitHub Actions para build e publicação automática
- Semantic versioning com conventional commits
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
): MultiChannelSubscriptionHookOptions (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
useMultiChannelSubscriptionpara 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}
- ANTES:
- 🔄 Hooks atualizados:
useJWTAuth,usePrivateRooms - 🛡️ Separação clara:
x-api-keypara projetos,Authorization: Bearerpara 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
