
Security News
Node.js Drops Bug Bounty Rewards After Funding Dries Up
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.
queue-it-sdk
Advanced tools
A comprehensive TypeScript SDK for building virtual waiting room systems with real-time capabilities.
# In your project
pnpm add @queue-it/queue-sdk
# Or if using the monorepo
pnpm add @queue-it/queue-sdk --workspace
import {
createRealtimeClient,
TokenUtils,
CookieUtils,
withWaitingRoom,
type QueueConfig,
type QueueState
} from '@queue-it/queue-sdk';
// Initialize realtime client
const realtimeClient = createRealtimeClient({
driver: 'socketio',
url: 'https://your-api.com',
auth: {
token: 'your-auth-token'
}
});
// Connect to realtime service
await realtimeClient.connect();
// Subscribe to queue updates
const unsubscribe = realtimeClient.subscribeQueue('limited-sneakers', (message) => {
console.log('Queue update:', message);
if (message.type === 'position_update') {
console.log(`Your position: ${message.data.position}`);
console.log(`Estimated wait time: ${message.data.estimatedWaitTime} seconds`);
}
if (message.type === 'admitted') {
console.log('You have been admitted!');
unsubscribe();
}
});
The Queue SDK uses environment variables for development and testing. Copy the env.example file to .env and modify as needed:
# Copy the example file
cp env.example .env
# API Configuration
QUEUE_API_URL=http://localhost:4000
QUEUE_WS_URL=ws://localhost:4000
# Authentication
QUEUE_AUTH_ENABLED=true
QUEUE_AUTH_COOKIE_NAME=queue-auth
# Queue Configuration
QUEUE_DEFAULT_TIMEOUT=30000
QUEUE_MAX_RETRIES=3
# Development
QUEUE_DEBUG_ENABLED=true
QUEUE_LOG_LEVEL=info
cp env.example .envFor production deployment:
createRealtimeClient(config: RealtimeConfig): RealtimeClientCreates a realtime client for queue updates.
interface RealtimeConfig {
driver: 'socketio' | 'sse'; // Transport protocol
url: string; // Server URL
auth?: { // Authentication
token?: string;
headers?: Record<string, string>;
};
options?: { // Connection options
reconnection?: boolean;
reconnectionDelay?: number;
maxReconnectionAttempts?: number;
timeout?: number;
};
}
RealtimeClient.connect(): Promise<void>Establishes connection to the realtime service.
try {
await realtimeClient.connect();
console.log('Connected to realtime service');
} catch (error) {
console.error('Connection failed:', error);
}
RealtimeClient.subscribeQueue(queueId: string, handler: QueueMessageHandler): () => voidSubscribes to queue updates. Returns an unsubscribe function.
const unsubscribe = realtimeClient.subscribeQueue('queue-id', (message) => {
switch (message.type) {
case 'queue_update':
console.log('Queue state updated:', message.data);
break;
case 'position_update':
console.log('Position:', message.data.position);
break;
case 'admitted':
console.log('Admitted to queue!');
break;
case 'error':
console.error('Error:', message.data.message);
break;
}
});
// Later, unsubscribe
unsubscribe();
RealtimeClient.disconnect(): voidDisconnects from the realtime service.
realtimeClient.disconnect();
RealtimeClient.isConnected(): booleanChecks if the client is connected.
if (realtimeClient.isConnected()) {
console.log('Client is connected');
}
TokenUtilsHandles JWT and HMAC token operations.
import { TokenUtils } from '@queue-it/queue-sdk';
const tokenUtils = new TokenUtils(
'your-hmac-secret',
'your-jwt-secret'
);
// Generate HMAC signature for enqueue ticket
const ticket = {
nonce: 'abc123',
visitorId: 'visitor-456',
queueId: 'limited-sneakers',
issuedAt: new Date(),
expiresAt: new Date(Date.now() + 3600000)
};
const signature = tokenUtils.generateTicketSignature(ticket);
// Verify ticket signature
const isValid = tokenUtils.verifyTicketSignature({
...ticket,
signature
});
// Generate JWT for queue access
const queueToken = tokenUtils.generateQueueToken(visitor, '1h');
// Verify JWT token
const decoded = tokenUtils.verifyQueueToken(queueToken);
// Generate admin token
const adminToken = tokenUtils.generateAdminToken('user-123', 'admin', '24h');
// Verify admin token
const adminData = tokenUtils.verifyAdminToken(adminToken);
// Generate secure nonce
const nonce = TokenUtils.generateNonce();
// Generate visitor ID
const visitorId = TokenUtils.generateVisitorId();
// Check if token is expired
const isExpired = TokenUtils.isExpired(expiresAt);
// Calculate time until expiration
const timeLeft = TokenUtils.timeUntilExpiration(expiresAt);
CookieUtilsManages secure HTTP-only cookies.
import { CookieUtils } from '@queue-it/queue-sdk';
const cookieUtils = new CookieUtils('yourdomain.com', true);
// Set queue token cookie
cookieUtils.setQueueTokenCookie(res, token);
// Set admin token cookie
cookieUtils.setAdminTokenCookie(res, adminToken);
// Get cookies from request
const queueToken = cookieUtils.getQueueToken(req);
const adminToken = cookieUtils.getAdminToken(req);
// Clear cookies
cookieUtils.clearQueueToken(res);
cookieUtils.clearAdminToken(res);
withWaitingRoom(config: WaitingRoomConfig)Protects routes with waiting room functionality.
// middleware.ts
import { withWaitingRoom } from '@queue-it/queue-sdk';
export default withWaitingRoom({
queueId: 'limited-sneakers',
jwtSecret: process.env.JWT_SECRET!,
hmacSecret: process.env.HMAC_SECRET!,
cookieDomain: process.env.COOKIE_DOMAIN!,
bypassToken: process.env.BYPASS_TOKEN // Optional, for testing
});
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* - waiting-room (waiting room pages)
*/
'/((?!api|_next/static|_next/image|favicon.ico|waiting-room).*)',
],
};
import { createWaitingRoomMiddleware } from '@queue-it/queue-sdk';
export default createWaitingRoomMiddleware({
queueId: 'limited-sneakers',
jwtSecret: process.env.JWT_SECRET!,
hmacSecret: process.env.HMAC_SECRET!,
cookieDomain: process.env.COOKIE_DOMAIN!
});
⚠️ IMPORTANT: The AdminClient is designed for server-side use only. It should not be used in browser/client-side code as it contains Node.js-specific dependencies that won't work in browsers. Use it in API routes, server components, or backend services only.
createAdminClient(config: AdminClientConfig): AdminClientCreates an admin client for managing queues programmatically.
import { createAdminClient } from '@queue-it/queue-sdk';
const adminClient = createAdminClient({
baseUrl: 'https://admin-api.example.com',
apiKey: 'your-admin-api-key' // Optional
});
// Create a queue
const queue = await adminClient.createQueue({
name: 'Limited Sneakers',
description: 'Queue for limited sneaker drop',
mode: 'fifo',
capacity: 1000,
triggerThreshold: 100,
rampRate: 10
});
// List all queues
const queues = await adminClient.listQueues();
// Get specific queue
const queue = await adminClient.getQueue('queue-id');
// Update queue
const updatedQueue = await adminClient.updateQueue('queue-id', {
capacity: 1500,
isActive: true
});
// Delete queue
await adminClient.deleteQueue('queue-id');
// Create queue based on client endpoint/event
const queue = await adminClient.createQueueFromEndpoint('/api/events/limited-drop', {
mode: 'timed_random',
capacity: 500,
triggerThreshold: 50,
rampRate: 5
});
// This creates a queue with name like "queue-limited-drop"
// and metadata indicating it was created from an endpoint
// Enqueue user when they hit a specific route
const result = await adminClient.enqueueUserOnRoute('/checkout', 'visitor-123', {
userAgent: 'Mozilla/5.0...',
ipAddress: '192.168.1.1'
});
// This automatically finds or creates a queue for the /checkout route
// and enqueues the user with route metadata
// Establish socket connection for admin dashboard
const realtimeClient = adminClient.createAdminRealtimeConnection({
authToken: 'admin-jwt-token',
reconnection: true,
maxReconnectionAttempts: 5
});
// Connect and subscribe to queue updates
await realtimeClient.connect();
const unsubscribe = realtimeClient.subscribeQueue('all', (message) => {
console.log('Admin queue update:', message);
});
// Enqueue a visitor manually
const enqueueResult = await adminClient.enqueueVisitor({
queueId: 'limited-sneakers',
visitorId: 'visitor-123',
metadata: {
source: 'website',
priority: 'vip'
}
});
console.log('Enqueued at position:', enqueueResult.position);
console.log('Estimated wait time:', enqueueResult.estimatedWaitTime);
// components/QueueWidget.tsx
import { createRealtimeClient, type QueueMessage } from '@queue-it/queue-sdk';
import { useEffect, useState } from 'react';
interface QueueWidgetProps {
queueId: string;
authToken: string;
}
export function QueueWidget({ queueId, authToken }: QueueWidgetProps) {
const [position, setPosition] = useState<number | null>(null);
const [estimatedWaitTime, setEstimatedWaitTime] = useState<number | null>(null);
const [isAdmitted, setIsAdmitted] = useState(false);
useEffect(() => {
const realtimeClient = createRealtimeClient({
driver: 'socketio',
url: process.env.NEXT_PUBLIC_WS_URL!,
auth: { token: authToken }
});
const connect = async () => {
try {
await realtimeClient.connect();
const unsubscribe = realtimeClient.subscribeQueue(queueId, (message: QueueMessage) => {
if (message.type === 'position_update') {
setPosition(message.data.position);
setEstimatedWaitTime(message.data.estimatedWaitTime);
} else if (message.type === 'admitted') {
setIsAdmitted(true);
unsubscribe();
}
});
return unsubscribe;
} catch (error) {
console.error('Failed to connect:', error);
}
};
const unsubscribe = connect();
return () => {
unsubscribe?.();
realtimeClient.disconnect();
};
}, [queueId, authToken]);
if (isAdmitted) {
return <div>Welcome! You have been admitted.</div>;
}
return (
<div className="queue-widget">
<h3>Queue Position</h3>
{position !== null ? (
<>
<p>Your position: <strong>{position}</strong></p>
{estimatedWaitTime !== null && (
<p>Estimated wait: <strong>{estimatedWaitTime} seconds</strong></p>
)}
</>
) : (
<p>Loading queue information...</p>
)}
</div>
);
}
// lib/auth.ts
import { TokenUtils } from '@queue-it/queue-sdk';
const tokenUtils = new TokenUtils(
process.env.HMAC_SECRET!,
process.env.JWT_SECRET!
);
export function validateQueueToken(token: string) {
try {
const decoded = tokenUtils.verifyQueueToken(token);
if (!decoded) {
return null;
}
if (TokenUtils.isExpired(decoded.expiresAt)) {
return null;
}
return decoded;
} catch (error) {
return null;
}
}
export function validateAdminToken(token: string) {
try {
return tokenUtils.verifyAdminToken(token);
} catch (error) {
return null;
}
}
// pages/api/queue/enqueue.ts
import { TokenUtils } from '@queue-it/queue-sdk';
import type { NextApiRequest, NextApiResponse } from 'next';
const tokenUtils = new TokenUtils(
process.env.HMAC_SECRET!,
process.env.JWT_SECRET!
);
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { queueId, visitorId } = req.body;
// Generate enqueue ticket
const nonce = TokenUtils.generateNonce();
const issuedAt = new Date();
const expiresAt = new Date(issuedAt.getTime() + 3600000); // 1 hour
const ticket = {
nonce,
visitorId: visitorId || TokenUtils.generateVisitorId(),
queueId,
issuedAt,
expiresAt
};
const signature = tokenUtils.generateTicketSignature(ticket);
// Here you would typically:
// 1. Add visitor to queue in Redis
// 2. Store ticket information
// 3. Emit realtime updates
res.status(200).json({
success: true,
ticket: { ...ticket, signature },
position: 1, // This would come from your queue logic
estimatedWaitTime: 300 // This would be calculated
});
} catch (error) {
console.error('Enqueue error:', error);
res.status(500).json({ error: 'Failed to enqueue visitor' });
}
}
// app.ts
import express from 'express';
import { CookieUtils, TokenUtils } from '@queue-it/queue-sdk';
const app = express();
const cookieUtils = new CookieUtils('yourdomain.com', true);
const tokenUtils = new TokenUtils(
process.env.HMAC_SECRET!,
process.env.JWT_SECRET!
);
// Middleware to validate queue tokens
app.use('/protected', (req, res, next) => {
const token = cookieUtils.getQueueToken(req);
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
const decoded = tokenUtils.verifyQueueToken(token);
if (!decoded) {
return res.status(401).json({ error: 'Invalid token' });
}
if (TokenUtils.isExpired(decoded.expiresAt)) {
cookieUtils.clearQueueToken(res);
return res.status(401).json({ error: 'Token expired' });
}
// Add user info to request
req.user = decoded;
next();
});
app.get('/protected/dashboard', (req, res) => {
res.json({
message: 'Welcome to dashboard',
visitorId: req.user.visitorId,
position: req.user.position
});
});
// hooks/useQueue.ts
import { createRealtimeClient, type QueueMessage } from '@queue-it/queue-sdk';
import { useEffect, useState, useCallback } from 'react';
interface UseQueueOptions {
queueId: string;
authToken: string;
autoConnect?: boolean;
}
export function useQueue({ queueId, authToken, autoConnect = true }: UseQueueOptions) {
const [isConnected, setIsConnected] = useState(false);
const [queueState, setQueueState] = useState<any>(null);
const [error, setError] = useState<string | null>(null);
const [realtimeClient, setRealtimeClient] = useState<any>(null);
const connect = useCallback(async () => {
try {
const client = createRealtimeClient({
driver: 'socketio',
url: process.env.NEXT_PUBLIC_WS_URL!,
auth: { token: authToken }
});
await client.connect();
setIsConnected(true);
setRealtimeClient(client);
setError(null);
// Subscribe to queue updates
client.subscribeQueue(queueId, (message: QueueMessage) => {
if (message.type === 'queue_update') {
setQueueState(message.data);
}
});
return client;
} catch (err) {
setError(err instanceof Error ? err.message : 'Connection failed');
setIsConnected(false);
throw err;
}
}, [queueId, authToken]);
const disconnect = useCallback(() => {
if (realtimeClient) {
realtimeClient.disconnect();
setIsConnected(false);
setRealtimeClient(null);
}
}, [realtimeClient]);
useEffect(() => {
if (autoConnect) {
connect();
}
return () => {
disconnect();
};
}, [autoConnect, connect, disconnect]);
return {
isConnected,
queueState,
error,
connect,
disconnect
};
}
Use these in Node.js environments (API routes, server components, backend services):
Use these in browser environments:
// Server-side: API route (pages/api/admin/queues.ts)
import { createAdminClient } from '@queue-it/queue-sdk';
export default async function handler(req, res) {
const adminClient = createAdminClient({
baseUrl: process.env.ADMIN_API_URL,
apiKey: process.env.ADMIN_API_KEY
});
if (req.method === 'POST') {
const queue = await adminClient.createQueueFromEndpoint('/api/events/sale');
res.status(200).json(queue);
}
}
// Client-side: React component
import { createRealtimeClient } from '@queue-it/queue-sdk';
function QueueComponent() {
const realtimeClient = createRealtimeClient({
driver: 'socketio',
url: process.env.NEXT_PUBLIC_WS_URL
});
// Use realtimeClient in component
}
httpOnly and secure flags in production// Example rate limiting with the SDK
import rateLimit from 'express-rate-limit';
const enqueueLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 enqueue requests per windowMs
message: 'Too many enqueue attempts, please try again later'
});
app.post('/api/queue/enqueue', enqueueLimiter, enqueueHandler);
// __tests__/TokenUtils.test.ts
import { TokenUtils } from '@queue-it/queue-sdk';
describe('TokenUtils', () => {
const tokenUtils = new TokenUtils('test-hmac-secret', 'test-jwt-secret');
test('should generate and verify HMAC signature', () => {
const ticket = {
nonce: 'test-nonce',
visitorId: 'test-visitor',
queueId: 'test-queue',
issuedAt: new Date(),
expiresAt: new Date(Date.now() + 3600000)
};
const signature = tokenUtils.generateTicketSignature(ticket);
const isValid = tokenUtils.verifyTicketSignature({ ...ticket, signature });
expect(isValid).toBe(true);
});
test('should generate and verify JWT token', () => {
const visitor = {
id: 'test-visitor',
queueId: 'test-queue',
position: 1,
joinedAt: new Date(),
lastHeartbeat: new Date(),
isActive: false,
metadata: {}
};
const token = tokenUtils.generateQueueToken(visitor);
const decoded = tokenUtils.verifyQueueToken(token);
expect(decoded).toBeTruthy();
expect(decoded?.visitorId).toBe('test-visitor');
});
});
// __tests__/integration/RealtimeClient.test.ts
import { createRealtimeClient } from '@queue-it/queue-sdk';
describe('RealtimeClient Integration', () => {
test('should connect and receive messages', async () => {
const client = createRealtimeClient({
driver: 'socketio',
url: 'http://localhost:4000'
});
const messages: any[] = [];
await client.connect();
const unsubscribe = client.subscribeQueue('test-queue', (message) => {
messages.push(message);
});
// Wait for messages
await new Promise(resolve => setTimeout(resolve, 1000));
expect(client.isConnected()).toBe(true);
expect(messages.length).toBeGreaterThan(0);
unsubscribe();
client.disconnect();
});
});
The Queue SDK requires these environment variables for production use:
# Required
JWT_SECRET=your-super-secure-jwt-secret
HMAC_SECRET=your-super-secure-hmac-secret
# Optional
COOKIE_DOMAIN=yourdomain.com
COOKIE_SECURE=true
Note: For development setup, see the Environment Setup section above.
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"esModuleInterop": true,
"skipLibCheck": true
}
}
Connection Failed
Token Validation Errors
Cookie Issues
// Enable debug logging
const realtimeClient = createRealtimeClient({
driver: 'socketio',
url: 'https://your-api.com',
options: {
reconnection: true,
reconnectionDelay: 1000,
maxReconnectionAttempts: 5
}
});
// Listen for connection events
realtimeClient.on('connect', () => console.log('Connected'));
realtimeClient.on('disconnect', () => console.log('Disconnected'));
realtimeClient.on('error', (error) => console.error('Error:', error));
MIT License - see LICENSE file for details
FAQs
Shared types, utilities, and realtime adapters for Queue-it system
We found that queue-it-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.