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

packet-events-js

v1.0.1

Published

A protocol library for Minecraft Java Edition in pure JavaScript

Readme

PacketEvents-JS

A robust protocol library for Minecraft Java Edition written entirely in pure JavaScript. Inspired by PacketEvents, designed to facilitate the processing and transmission of Minecraft protocol packets with full online mode support.

Features

  • Pure JavaScript - No external dependencies, only native Node.js
  • TCP Connection - Complete TCP client for Minecraft
  • Packet System - Read/write all protocol data types
  • Event System - Priority-based events with cancellation and async/await
  • Compression - Full zlib compression support
  • Encryption - Complete AES-128-CFB8 encryption support for online mode
  • Online Mode - Full Mojang/Microsoft authentication support
  • Offline Mode - Offline player UUID generation (version 3)
  • BungeeCord Forwarding - Legacy IP forwarding support
  • Velocity Forwarding - Modern forwarding with HMAC verification
  • Complete NBT - Named Binary Tag read/write
  • Chat Components - JSON Text Component with colors, formatting, and events
  • Multi-version - Support for Minecraft 1.7.2 to 1.21.11 (66 versions)
  • Packet Recorder - Record, export, import, and replay packet streams
  • Protocol Analyzer - Deep packet inspection, metrics, and traffic analysis
  • Middleware System - Plugin-based packet processing pipeline
  • Connection Manager - AutoReconnect, HealthMonitor, ConnectionPool, CircuitBreaker

Requirements

  • Node.js 18.0.0 or higher
  • ES Modules enabled

Installation

npm install packet-events-js

Or clone the repository:

git clone https://github.com/FrannnnDev/PacketEvents-JS.git
cd PacketEvents-JS

Basic Usage

Server List Ping

import { MinecraftClient, ProtocolVersion } from 'packet-events-js';

const client = new MinecraftClient({
    host: 'mc.hypixel.net',
    port: 25565,
    version: ProtocolVersion.V1_21_11
});

const status = await client.ping();
console.log(`Players: ${status.players.online}/${status.players.max}`);
console.log(`Latency: ${status.latency}ms`);

Connect to Server (Offline Mode)

import { 
    MinecraftClient, 
    ProtocolVersion, 
    Logger, 
    LogLevel,
    KeepAliveClientboundPacket, 
    KeepAliveServerboundPacket 
} from 'packet-events-js';

Logger.setGlobalLevel(LogLevel.DEBUG);

const client = new MinecraftClient({
    host: 'localhost',
    port: 25565,
    version: ProtocolVersion.V1_21_11,
    username: 'MyBot',
    offline: true
});

client.onPacket(KeepAliveClientboundPacket, async (event) => {
    const response = new KeepAliveServerboundPacket();
    response.keepAliveId = event.packet.keepAliveId;
    await client.sendPacket(response);
});

await client.login();
console.log(`Connected as ${client.playerName}`);

Encryption API

import { MinecraftEncryption, EncryptedConnection } from 'packet-events-js';

const keyPair = MinecraftEncryption.generateKeyPair();
console.log('Public Key:', keyPair.publicKey);
console.log('Private Key:', keyPair.privateKey);

const verifyToken = MinecraftEncryption.generateVerifyToken();
const sharedSecret = MinecraftEncryption.generateSharedSecret();

const encrypted = MinecraftEncryption.encryptRSA(keyPair.publicKey, sharedSecret);
const decrypted = MinecraftEncryption.decryptRSA(keyPair.privateKey, encrypted);

const aesEncrypted = MinecraftEncryption.encryptAES(sharedSecret, Buffer.from('Hello'));
const aesDecrypted = MinecraftEncryption.decryptAES(sharedSecret, aesEncrypted);

const serverHash = MinecraftEncryption.computeServerIdHash('', sharedSecret, keyPair.publicKey);

Auth Handler

import { AuthHandler, ClientAuthHandler, AuthMode } from 'packet-events-js';

const serverAuth = new AuthHandler({ mode: AuthMode.ONLINE });
serverAuth.initialize();

const publicKey = serverAuth.getPublicKey();
const verifyToken = serverAuth.generateVerifyToken();

const offlineUUID = serverAuth.generateOfflineUUID('PlayerName');

const clientAuth = new ClientAuthHandler({
    accessToken: 'token',
    selectedProfile: { id: 'uuid', name: 'Name' }
});

BungeeCord Forwarding

import { BungeeCordForwarding, UUID } from 'packet-events-js';

const uuid = UUID.randomUUID();
const handshakeAddress = BungeeCordForwarding.create(
    'play.example.com',
    '192.168.1.100',
    uuid,
    [{ name: 'textures', value: '...' }]
);

const result = BungeeCordForwarding.parse(handshakeAddress);
if (result.success) {
    console.log(`Client IP: ${result.clientIP}`);
    console.log(`UUID: ${result.uuid.toString()}`);
}

Velocity Modern Forwarding

import { VelocityForwarding, AuthHandler, AuthMode, UUID } from 'packet-events-js';

const auth = new AuthHandler({ 
    mode: AuthMode.VELOCITY, 
    velocitySecret: 'your-secret-key' 
});

const result = auth.handleVelocityForwarding(forwardingData);
if (result.success) {
    console.log(`Player: ${result.username}`);
    console.log(`UUID: ${result.uuid.toString()}`);
    console.log(`IP: ${result.clientIP}`);
}

const uuid = UUID.randomUUID();
const data = VelocityForwarding.create(
    'your-secret-key',
    '10.0.0.1',
    uuid,
    'PlayerName',
    [{ name: 'textures', value: '...', signature: '...' }]
);

Intercept Packets

import { EventPriority } from 'packet-events-js';

client.packetManager.on('packetSend', (event) => {
    if (event.packet.packetName === 'SetPlayerPosition') {
        console.log(`Moving to: ${event.packet.x}, ${event.packet.y}, ${event.packet.z}`);
        
        if (event.packet.y < 0) {
            event.cancel();
        }
    }
}, { priority: EventPriority.HIGH });

Create Custom Packets

import { 
    Packet, 
    defaultRegistry, 
    ConnectionState, 
    PacketDirection 
} from 'packet-events-js';

class MyCustomPacket extends Packet {
    static get packetId() { return 0x50; }
    static get packetName() { return 'MyPacket'; }

    constructor() {
        super();
        this.myField = 0;
    }

    read(buffer, context) {
        this.myField = buffer.readVarInt();
    }

    write(buffer, context) {
        buffer.writeVarInt(this.myField);
    }
}

defaultRegistry.register({
    packetClass: MyCustomPacket,
    state: ConnectionState.PLAY,
    direction: PacketDirection.CLIENTBOUND,
    packetId: 0x50
});

Advanced Features

Packet Recorder

Record, export, import, and replay complete packet streams:

import { PacketRecorder, PacketReplayer, PacketRecord } from 'packet-events-js';

const recorder = new PacketRecorder({
    includeRaw: true,
    maxRecords: 10000,
    filter: (packet) => true
});

recorder.start();

client.packetManager.on('packetReceive', (event) => {
    recorder.record(event.packet, 'CLIENTBOUND', 'PLAY', event.rawData);
});

const stats = recorder.getStats();
console.log(`Recorded: ${stats.totalPackets} packets, ${stats.totalBytes} bytes`);
console.log(`Duration: ${stats.duration}ms`);
console.log(`Packets by type:`, stats.packetsByType);

const exported = recorder.export();
const json = JSON.stringify(exported, null, 2);

const imported = recorder.import(JSON.parse(json));

const replayer = new PacketReplayer(recorder.records, {
    speed: 1.0,
    loop: false,
    onPacket: (record) => {
        console.log(`Replaying: ${record.packetName}`);
    }
});

await replayer.start();
replayer.pause();
replayer.resume();
replayer.stop();

Protocol Analyzer

Deep protocol analysis with metrics and traffic visualization:

import { ProtocolAnalyzer, ProtocolMetrics, PacketInspector } from 'packet-events-js';

const analyzer = new ProtocolAnalyzer({
    trackHistory: true,
    historySize: 1000,
    alertThresholds: {
        latency: 500,
        packetLoss: 0.1,
        throughputMin: 1000
    }
});

analyzer.on('alert', (alert) => {
    console.log(`Alert: ${alert.type} - ${alert.message}`);
});

analyzer.start();

client.packetManager.on('packetReceive', (event) => {
    analyzer.analyzePacket(event.packet, 'CLIENTBOUND', 'PLAY', event.rawData);
});

analyzer.recordLatency(50);

const report = analyzer.getReport();
console.log(`Packets: ${report.packets.total}`);
console.log(`Bytes: ${report.bytes.total}`);
console.log(`Avg Latency: ${report.latency.average}ms`);

const graph = analyzer.getTrafficGraph();
console.log(graph);

const metrics = new ProtocolMetrics();
metrics.recordLatency(100);
metrics.recordPacketLoss(1, 100);
console.log(`Avg Latency: ${metrics.getAverageLatency()}ms`);
console.log(`Packet Loss: ${metrics.getPacketLoss() * 100}%`);

const inspector = new PacketInspector();

const hexDump = inspector.hexDump(packetBuffer);
console.log(hexDump);

const structure = inspector.analyzeStructure(packet);
console.log(structure);

Middleware System

Plugin-based packet processing pipeline with built-in middleware:

import { 
    MiddlewarePipeline,
    LoggingMiddleware,
    RateLimitMiddleware,
    ValidationMiddleware,
    TransformMiddleware,
    CacheMiddleware,
    MetricsMiddleware
} from 'packet-events-js';

const pipeline = new MiddlewarePipeline();

pipeline.use(new LoggingMiddleware({
    logLevel: 'debug',
    includePayload: true,
    filter: (ctx) => ctx.packet.constructor.packetName !== 'KeepAlive'
}));

pipeline.use(new RateLimitMiddleware({
    maxPackets: 100,
    windowMs: 1000,
    onLimit: (ctx) => console.log('Rate limited!')
}));

pipeline.use(new ValidationMiddleware({
    rules: {
        'ChatMessage': (packet) => packet.message.length <= 256,
        'SetPlayerPosition': (packet) => Math.abs(packet.y) < 320
    },
    onInvalid: (ctx, rule) => console.log(`Invalid: ${rule}`)
}));

pipeline.use(new TransformMiddleware({
    transforms: {
        'ChatMessage': (packet) => {
            packet.message = packet.message.trim();
            return packet;
        }
    }
}));

const metricsMiddleware = new MetricsMiddleware();
pipeline.use(metricsMiddleware);

pipeline.use(async (ctx, next) => {
    console.log(`Before: ${ctx.packet.constructor.packetName}`);
    await next();
    console.log(`After: processing time ${ctx.processingTime}ms`);
});

client.packetManager.on('packetReceive', async (event) => {
    const ctx = await pipeline.process({
        packet: event.packet,
        direction: 'CLIENTBOUND',
        state: 'PLAY'
    });
    
    if (ctx.cancelled) {
        event.cancel();
    }
});

const metrics = metricsMiddleware.getMetrics();
console.log(`Processed: ${metrics.processed} packets`);
console.log(`Blocked: ${metrics.blocked} packets`);

Connection Manager

Advanced connection management with auto-reconnect, health monitoring, and connection pooling:

import { 
    AutoReconnect, 
    ReconnectStrategy,
    HealthMonitor,
    HealthStatus,
    ConnectionPool,
    CircuitBreaker
} from 'packet-events-js';

const reconnect = new AutoReconnect({
    strategy: ReconnectStrategy.EXPONENTIAL,
    baseDelay: 1000,
    maxDelay: 30000,
    maxAttempts: 10,
    jitter: true,
    onReconnect: (attempt) => console.log(`Reconnecting... attempt ${attempt}`),
    onMaxAttempts: () => console.log('Max reconnect attempts reached'),
    onSuccess: () => console.log('Reconnected!')
});

client.on('disconnect', async () => {
    await reconnect.attempt(async () => {
        await client.connect();
        await client.login();
    });
});

const healthMonitor = new HealthMonitor({
    latencyThreshold: 200,
    packetLossThreshold: 0.05,
    checkInterval: 5000
});

healthMonitor.on('statusChange', (status, previousStatus) => {
    console.log(`Health: ${previousStatus} -> ${status}`);
});

healthMonitor.on('alert', (alert) => {
    console.log(`${alert.type}: ${alert.message}`);
});

client.packetManager.on('packetReceive', (event) => {
    if (event.packet.constructor.packetName === 'KeepAliveClientbound') {
        healthMonitor.recordLatency(Date.now() - event.timestamp);
    }
});

const pool = new ConnectionPool({
    minConnections: 2,
    maxConnections: 10,
    strategy: 'least-loaded',
    healthCheck: async (conn) => conn.isConnected,
    healthCheckInterval: 30000
});

await pool.add('lobby', createClient('lobby.server.com'));
await pool.add('game1', createClient('game1.server.com'));
await pool.add('game2', createClient('game2.server.com'));

const { id, connection } = pool.get();
await connection.sendPacket(packet);
pool.release(id);

const breaker = new CircuitBreaker({
    failureThreshold: 5,
    successThreshold: 3,
    timeout: 30000,
    onOpen: () => console.log('Circuit OPEN - requests blocked'),
    onClose: () => console.log('Circuit CLOSED - requests allowed'),
    onHalfOpen: () => console.log('Circuit HALF-OPEN - testing')
});

try {
    await breaker.execute(async () => {
        await client.sendPacket(packet);
    });
} catch (error) {
    if (breaker.isOpen) {
        console.log('Circuit is open, request blocked');
    }
}

Project Structure

PacketEvents-JS/
├── src/
│   ├── index.js
│   ├── auth/
│   │   ├── AuthHandler.js
│   │   └── MojangAPI.js
│   ├── client/
│   │   └── MinecraftClient.js
│   ├── crypto/
│   │   └── Encryption.js
│   ├── events/
│   │   ├── EventEmitter.js
│   │   └── PacketEvent.js
│   ├── manager/
│   │   └── PacketManager.js
│   ├── protocol/
│   │   ├── ConnectionState.js
│   │   ├── PacketDirection.js
│   │   ├── ProtocolVersion.js
│   │   ├── types/
│   │   │   ├── VarInt.js
│   │   │   ├── UUID.js
│   │   │   ├── Position.js
│   │   │   ├── NBT.js
│   │   │   └── TextComponent.js
│   │   └── packets/
│   │       ├── Packet.js
│   │       ├── PacketRegistry.js
│   │       ├── handshake/
│   │       ├── status/
│   │       ├── login/
│   │       └── play/
│   ├── advanced/
│   │   ├── PacketRecorder.js
│   │   ├── ProtocolAnalyzer.js
│   │   ├── MiddlewareSystem.js
│   │   └── ConnectionManager.js
│   └── utils/
│       ├── PacketBuffer.js
│       └── Logger.js
└── examples/
    ├── authentication.js
    ├── basic-client.js
    ├── connection-flows.js
    ├── custom-packets.js
    ├── data-types.js
    ├── encryption.js
    ├── event-system.js
    ├── packet-buffer.js
    ├── packet-interception.js
    ├── packet-types.js
    ├── protocol-versions.js
    └── server-ping.js

Main API

MinecraftClient

const client = new MinecraftClient({
    host: string,
    port: number,
    version: ProtocolVersion,
    username: string,
    offline: boolean,
    accessToken: string,
    selectedProfile: object,
    registry: PacketRegistry
});

await client.connect();
await client.ping();
await client.login();
await client.sendPacket(packet);
await client.disconnect();

client.isConnected;
client.isReady;
client.uuid;
client.playerName;

PacketBuffer

import { PacketBuffer } from 'packet-events-js';

const buffer = PacketBuffer.writer();

buffer.writeBoolean(true);
buffer.writeByte(42);
buffer.writeShort(1000);
buffer.writeInt(100000);
buffer.writeLong(9999999999n);
buffer.writeFloat(3.14);
buffer.writeDouble(3.14159265);
buffer.writeVarInt(12345);
buffer.writeString("Hello Minecraft");
buffer.writeUUID(uuid);
buffer.writePosition(position);
buffer.writeNBT(nbtCompound);

const data = buffer.getBuffer();

const reader = PacketBuffer.reader(data);
const bool = reader.readBoolean();
const num = reader.readVarInt();
const str = reader.readString();

MinecraftEncryption

import { MinecraftEncryption, EncryptedConnection } from 'packet-events-js';

const keyPair = MinecraftEncryption.generateKeyPair();

const verifyToken = MinecraftEncryption.generateVerifyToken();
const sharedSecret = MinecraftEncryption.generateSharedSecret();

MinecraftEncryption.encryptRSA(publicKey, data);
MinecraftEncryption.decryptRSA(privateKey, data);

MinecraftEncryption.encryptAES(secret, data);
MinecraftEncryption.decryptAES(secret, data);

MinecraftEncryption.computeServerIdHash(serverId, sharedSecret, publicKey);

const conn = new EncryptedConnection(sharedSecret);
conn.enable();
const encrypted = conn.encrypt(data);
const decrypted = conn.decrypt(data);

AuthHandler

import { AuthHandler, ClientAuthHandler, AuthMode, BungeeCordForwarding, VelocityForwarding } from 'packet-events-js';

AuthMode.ONLINE;
AuthMode.OFFLINE;
AuthMode.BUNGEECORD;
AuthMode.VELOCITY;

const handler = new AuthHandler({ mode: AuthMode.ONLINE });
handler.initialize();
handler.getPublicKey();
handler.generateVerifyToken();
handler.generateOfflineUUID(username);

const bungeAuth = new AuthHandler({ mode: AuthMode.BUNGEECORD });
const result = bungeAuth.handleBungeeCordForwarding(serverAddress);

const velocityAuth = new AuthHandler({ 
    mode: AuthMode.VELOCITY, 
    velocitySecret: 'your-secret' 
});
const result2 = velocityAuth.handleVelocityForwarding(loginPluginData);

EventEmitter

import { EventPriority } from 'packet-events-js';

EventPriority.LOWEST;
EventPriority.LOW;
EventPriority.NORMAL;
EventPriority.HIGH;
EventPriority.HIGHEST;
EventPriority.MONITOR;

emitter.on('event', callback, { priority: EventPriority.HIGH });

emitter.on('packet', (event) => {
    event.cancel();
});

await emitter.emitAsync('event', data);

TextComponent

import { TextComponent, ChatColor } from 'packet-events-js';

const message = TextComponent.text('Hello!')
    .color(ChatColor.GREEN)
    .bold()
    .append(
        TextComponent.text(' World')
            .color(ChatColor.YELLOW)
            .italic()
    )
    .clickEvent('run_command', '/help')
    .showText(TextComponent.text('Click for help'));

const json = message.toString();

Supported Versions

66 versions supported from 1.7.2 to 1.21.11:

| Range | Versions | |-------|----------| | 1.21.x | 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21 | | 1.20.x | 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20 | | 1.19.x | 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19 | | 1.18.x | 1.18.2, 1.18.1, 1.18 | | 1.17.x | 1.17.1, 1.17 | | 1.16.x | 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16 | | 1.15.x | 1.15.2, 1.15.1, 1.15 | | 1.14.x | 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14 | | 1.13.x | 1.13.2, 1.13.1, 1.13 | | 1.12.x | 1.12.2, 1.12.1, 1.12 | | 1.11.x | 1.11.2, 1.11.1, 1.11 | | 1.10.x | 1.10.2, 1.10.1, 1.10 | | 1.9.x | 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9 | | 1.8.x | 1.8.9, 1.8.8, 1.8.7, 1.8.6, 1.8.5, 1.8.4, 1.8.3, 1.8.2, 1.8.1, 1.8 | | 1.7.x | 1.7.10, 1.7.9, 1.7.6, 1.7.5, 1.7.4, 1.7.2 |

Examples

See the examples folder for complete usage examples:

  • basic-client.js - Basic client connection
  • server-ping.js - Server list ping
  • packet-types.js - All packet types demonstration
  • encryption.js - Encryption usage
  • authentication.js - Authentication modes
  • event-system.js - Event system usage
  • packet-buffer.js - PacketBuffer operations
  • data-types.js - Protocol data types
  • protocol-versions.js - Protocol version utilities
  • connection-flows.js - Connection flow examples
  • custom-packets.js - Custom packet creation
  • packet-interception.js - Packet interception

References

This project is inspired by:

License

MIT License