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

@smarthivelabs-devs/hive-socket-node

v1.1.0

Published

Node.js SDK for Hive-Socket — push notifications, events, and real-time messages to connected clients

Downloads

119

Readme

@smarthivelabs-devs/hive-socket-node

Node.js SDK for Hive-Socket — push real-time notifications and broadcast typed messages to connected clients from any backend service.

v1.1.0 adds hive.broadcast.toRoom() for sending structured typed messages received by useMessages() on the client. Use this for full-duplex features (live competitions, collaborative editing, presence) where clients need to act on the payload, not just display a notification.

Install

npm install @smarthivelabs-devs/hive-socket-node
# or
yarn add @smarthivelabs-devs/hive-socket-node
# or
pnpm add @smarthivelabs-devs/hive-socket-node

Requirements: Node 18+ (uses native fetch). No peer dependencies.

Supports both ESM and CommonJS:

// ESM
import { createHiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';

// CommonJS
const { createHiveSocketClient } = require('@smarthivelabs-devs/hive-socket-node');

Environment variables

Add to your backend .env:

HIVE_SOCKET_URL=https://socket.smarthivelabs.dev
HIVE_SOCKET_API_KEY=shai_<your-key>          # same value as INTERNAL_API_KEY on the Hive-Socket server
SMARTHIVE_PROJECT_ID=<your-auth-project-id>  # project ID from SmartHive Auth dashboard

HIVE_SOCKET_API_KEY — copy the value of INTERNAL_API_KEY set on the Hive-Socket server. This is a shared secret between your backends and Hive-Socket.

SMARTHIVE_PROJECT_ID — the project ID issued by SmartHive Auth when you registered your product. Pass this as projectId in every notify call so Hive-Socket scopes messages and notifications to the correct project.


Quick start

import { createHiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';

const hive = createHiveSocketClient({
  baseUrl: process.env.HIVE_SOCKET_URL!,
  apiKey: process.env.HIVE_SOCKET_API_KEY!,
});

// Push a notification to a user
await hive.notify.user('user-id-123', {
  projectId: process.env.SMARTHIVE_PROJECT_ID!,
  title: 'New message',
  body: 'Alice sent you a message',
  type: 'message',
});

API

createHiveSocketClient(config)

Creates a client instance. Create once and reuse across your application.

const hive = createHiveSocketClient({
  baseUrl: process.env.HIVE_SOCKET_URL!,    // e.g. https://socket.smarthivelabs.dev
  apiKey: process.env.HIVE_SOCKET_API_KEY!, // shai_* internal API key
  timeout: 10_000,                          // Optional. Request timeout in ms. Default: 10000
});

hive.notify.user(userId, payload)

Push a notification to a specific user. Delivered instantly to all their connected devices. If the user is offline, the notification is persisted and delivered on their next login.

await hive.notify.user(userId, {
  projectId: string,          // SmartHive Auth project ID (process.env.SMARTHIVE_PROJECT_ID)
  title: string,              // Notification title
  body: string,               // Notification body
  type: NotificationType,     // 'info' | 'success' | 'warning' | 'error' | 'message'
  metadata?: Record<string, unknown>, // Optional — any JSON data
  sourceService?: string,     // Optional — identifies the sending service
});

Example — payment confirmed:

await hive.notify.user(userId, {
  projectId: process.env.SMARTHIVE_PROJECT_ID!,
  title: 'Payment confirmed',
  body: `₦${amount.toLocaleString()} received`,
  type: 'success',
  metadata: { paymentId, amount },
  sourceService: 'payment-backend',
});

Example — new comment:

await hive.notify.user(comment.authorId, {
  projectId: workspace.projectId,
  title: 'New reply',
  body: `${commenter.name} replied to your comment`,
  type: 'message',
  metadata: { commentId: comment.id, threadId: comment.threadId },
  sourceService: 'workspace-backend',
});

hive.notify.room(roomId, payload)

Broadcast a notification to all users currently in a room. Room notifications are ephemeral — not persisted to the database.

await hive.notify.room(roomId, {
  projectId: string,          // SmartHive Auth project ID (process.env.SMARTHIVE_PROJECT_ID)
  title: string,
  body: string,
  type: NotificationType,
  metadata?: Record<string, unknown>,
  sourceService?: string,
});

Example — quiz started:

await hive.notify.room(`course:${courseId}`, {
  projectId: process.env.SMARTHIVE_PROJECT_ID!,
  title: 'Quiz started',
  body: 'Chapter 3 quiz is now live',
  type: 'info',
  sourceService: 'hivedemia-backend',
});

Example — live vote update:

await hive.notify.room(`event:${eventId}`, {
  projectId: process.env.SMARTHIVE_PROJECT_ID!,
  title: 'Results updated',
  body: 'New votes have been counted',
  type: 'info',
  metadata: { candidateId, totalVotes },
  sourceService: 'votyhive-backend',
});

hive.broadcast.toRoom(roomId, payload) (v1.1.0)

Broadcast a typed structured message to all sockets in a room. Messages are received by clients via useMessages(roomId) — they arrive as message:new events, distinct from notification:new produced by notify.*. Use this for real-time game state, collaborative state changes, or any payload where the client needs to react to the message type programmatically.

await hive.broadcast.toRoom(roomId, {
  projectId: string,            // SmartHive Auth project ID
  type: string,                 // your event type, e.g. "competition.question-change"
  payload: Record<string, unknown>, // arbitrary JSON
  senderId?: string,            // optional — defaults to "system"
});

Example — competition state advance:

await hive.broadcast.toRoom(`competition:${competitionId}`, {
  projectId: process.env.SMARTHIVE_PROJECT_ID!,
  type: 'competition.question-change',
  payload: { questionIndex: 2, questionEndsAt: '2026-05-24T12:00:30.000Z' },
  senderId: 'hivedemia-api',
});

Difference between notify.room and broadcast.toRoom:

| | notify.room | broadcast.toRoom | |---|---|---| | Client hook | useNotifications() | useMessages(roomId) | | Wire event | notification:new | message:new | | Persisted | Yes (offline delivery) | No (ephemeral) | | Best for | In-app alerts, toasts | Game state, live sync |


hive.health()

Check server health and current connection count.

const { status, connections, uptime } = await hive.health();
// { status: 'ok', connections: 42, uptime: 3600 }

Error handling

import {
  HiveSocketAuthError,
  HiveSocketNetworkError,
  HiveSocketError,
} from '@smarthivelabs-devs/hive-socket-node';

try {
  await hive.notify.user(userId, payload);
} catch (err) {
  if (err instanceof HiveSocketAuthError) {
    // HTTP 401 — wrong API key
    // Check HIVE_SOCKET_API_KEY matches INTERNAL_API_KEY on the server
  } else if (err instanceof HiveSocketNetworkError) {
    // Network failure or request timed out
    // Safe to retry with exponential backoff
  } else if (err instanceof HiveSocketError) {
    // Other server error
    console.error(err.message, err.statusCode);
  }
}

NestJS integration

Create a shared module

// hive-socket.module.ts
import { Module, Global } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { createHiveSocketClient, HiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';

export const HIVE_SOCKET = Symbol('HIVE_SOCKET');

@Global()
@Module({
  providers: [
    {
      provide: HIVE_SOCKET,
      inject: [ConfigService],
      useFactory: (config: ConfigService) =>
        createHiveSocketClient({
          baseUrl: config.getOrThrow('HIVE_SOCKET_URL'),
          apiKey: config.getOrThrow('HIVE_SOCKET_API_KEY'),
        }),
    },
  ],
  exports: [HIVE_SOCKET],
})
export class HiveSocketModule {}

Inject into any service

// notifications.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { HiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';
import { HIVE_SOCKET } from './hive-socket.module';

@Injectable()
export class NotificationsService {
  constructor(
    @Inject(HIVE_SOCKET) private readonly hive: HiveSocketClient,
  ) {}

  async sendPaymentNotification(userId: string, projectId: string, amount: number) {
    await this.hive.notify.user(userId, {
      projectId,
      title: 'Payment received',
      body: `Your payment of ₦${amount.toLocaleString()} was confirmed`,
      type: 'success',
      metadata: { amount },
      sourceService: 'payment-service',
    });
  }

  async announceToRoom(roomId: string, projectId: string, message: string) {
    await this.hive.notify.room(roomId, {
      projectId,
      title: 'Announcement',
      body: message,
      type: 'info',
      sourceService: 'admin-service',
    });
  }
}

Express / Next.js API route

Express

// routes/messages.ts
import { Router } from 'express';
import { hive } from '../lib/hive-socket'; // your singleton

const router = Router();

router.post('/messages', async (req, res) => {
  const { userId, projectId, text } = req.body;

  // ... save message to your DB ...

  await hive.notify.user(userId, {
    projectId,
    title: 'New message',
    body: text.slice(0, 100),
    type: 'message',
    sourceService: 'workspace-api',
  });

  res.json({ ok: true });
});

Next.js App Router

// app/api/notify/route.ts
import { createHiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';

const hive = createHiveSocketClient({
  baseUrl: process.env.HIVE_SOCKET_URL!,
  apiKey: process.env.HIVE_SOCKET_API_KEY!,
});

export async function POST(req: Request) {
  const { userId, projectId, title, body } = await req.json();

  await hive.notify.user(userId, {
    projectId,
    title,
    body,
    type: 'info',
  });

  return Response.json({ ok: true });
}

Notification types

| Type | When to use | |------|-------------| | 'message' | New chat message or direct message | | 'info' | General information (quiz started, event begins) | | 'success' | Positive outcome (payment confirmed, grade posted) | | 'warning' | Requires attention (deadline approaching, low balance) | | 'error' | Something failed (payment declined, submission error) |


Security

How the API key is sent and validated

Every request from this SDK includes an x-internal-api-key header:

POST /notify/user
x-internal-api-key: shai_<your-key>

The Hive-Socket server compares this header against its INTERNAL_API_KEY env var using a constant-time comparison (no timing attacks). If the key doesn't match the request is rejected with HTTP 401.

This key is a shared secret between your backends and Hive-Socket. It must never be used in browser or mobile code — it gives unrestricted ability to send notifications to any user.

What the server enforces

| Guarantee | How | |-----------|-----| | Only trusted backends can push notifications | x-internal-api-key validated on every request | | Notifications are scoped to the correct project | projectId from your payload scopes DB storage and room routing | | userId comes from your backend, not the client | Clients never call notify endpoints — only your server-side code does |

What you must do

  • Store the key in environment variables only. Never commit it to source control or embed it in client-side code.
  • Use the same key value as INTERNAL_API_KEY on the Hive-Socket server. They must match exactly.
  • Use a different key per environment — generate a separate key for dev and prod, set them independently.
  • Rotate by updating both env vars — update INTERNAL_API_KEY on Hive-Socket and HIVE_SOCKET_API_KEY on your backends, then redeploy. There is no revocation endpoint; rotation is instant once both sides are updated.
  • Always pass projectId from your own config (process.env.SMARTHIVE_PROJECT_ID) — never accept it from user input. It is the SmartHive Auth project ID for your product.

Types

import type {
  HiveSocketConfig,
  HiveNotifyPayload,
  HiveBroadcastPayload,
  HiveHealthResponse,
  NotificationType,
} from '@smarthivelabs-devs/hive-socket-node';
interface HiveSocketConfig {
  baseUrl: string;
  apiKey: string;
  timeout?: number; // ms, default 10000
}

interface HiveNotifyPayload {
  projectId: string;
  title: string;
  body: string;
  type: 'info' | 'success' | 'warning' | 'error' | 'message';
  metadata?: Record<string, unknown>;
  sourceService?: string;
}

interface HiveBroadcastPayload {
  projectId: string;
  type: string;
  payload: Record<string, unknown>;
  senderId?: string;
}

interface HiveHealthResponse {
  status: 'ok';
  connections: number;
  uptime: number;
}