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

@munigan/wow-combatlog-parser

v0.2.1

Published

Streaming parser for World of Warcraft WotLK 3.3.5 combat logs

Readme

@munigan/wow-combatlog-parser

Streaming parser for World of Warcraft WotLK 3.3.5 combat log files. Zero runtime dependencies, dual ESM/CJS, works in browser, Node 18+, Deno, and Bun.

Install

pnpm add @munigan/wow-combatlog-parser

API

Three functions, one streaming pipeline:

scanLog(stream, options?) — Detect raids

Lightweight first pass. Reads the entire log in a single stream and returns detected raids, encounters, and players with class/spec. Does not track consumables, combat stats, or other detailed data.

import { scanLog } from "@munigan/wow-combatlog-parser";

const stream = file.stream(); // ReadableStream<Uint8Array> (.txt or .txt.gz)
const { raids } = await scanLog(stream);

for (const raid of raids) {
  console.log(raid.raidInstance, raid.encounters.length, raid.playerCount);
}

parseLog(stream, selections, options?) — Extract raid details

Second pass filtered by time ranges from scanLog. Tracks consumables, combat stats (damage done/taken), buff uptime, deaths with recap, and external buffs.

import { parseLog } from "@munigan/wow-combatlog-parser";

const { raids } = await parseLog(file.stream(), [{
  dates: raid.dates,
  startTime: raid.startTime,
  endTime: raid.endTime,
  timeRanges: raid.timeRanges,
}]);

for (const encounter of raids[0].encounters) {
  console.log(encounter.bossName, encounter.combatStats, encounter.deaths);
}

parseLogStream(stream, selections, callbacks, options?) — Incremental parsing

Callback-based streaming parse that delivers encounters one at a time. Ideal for saving to a database as you go — async callbacks are awaited (backpressure).

import { parseLogStream } from "@munigan/wow-combatlog-parser";

await parseLogStream(file.stream(), selections, {
  onEncounter: async (encounter) => {
    await db.encounters.insert(encounter);
  },
  onComplete: async (summary) => {
    await db.raids.update({ raidId, ...summary });
  },
});

Typical flow: scanLog → user picks raids → parseLog or parseLogStream with RaidSelection[].

What it extracts

From scanLog (lightweight, client-side):

  • Raid instance, dates, time ranges
  • Encounters: boss name, duration (ms precision), kill/wipe, difficulty
  • Players: name, class (~380 spells), spec (~90 spells)

From parseLog / parseLogStream (server-side, full extraction):

  • Everything above, plus:
  • Combat stats: per-player damage done (useful) and damage taken (raw), with pet→owner merging and NPC whitelist filtering
  • Consumables: potions, engineering bombs, Flame Cap — with pre-pot detection
  • Buff uptime: flask/elixir and food uptime % (raid-wide and per-encounter)
  • Deaths: death recap with last 10 damage/heal events, killing blow identification
  • Externals: 16 tracked buffs (Bloodlust, Power Infusion, Tricks, Innervate, Hand of Salvation, etc.) with count and uptime

Gzip support

Pass .txt or .txt.gz files — compression is auto-detected via gzip magic bytes. No configuration needed. WoW combat logs compress 12-13x with gzip (591 MB → 48 MB).

File size limit

All functions accept maxBytes option (default: 1 GB decompressed). Exceeding it throws FileTooLargeError.

Supported raids

9 instances, 63 bosses: Naxxramas (15), Obsidian Sanctum (1), Eye of Eternity (1), Vault of Archavon (4), Ulduar (14), Trial of the Crusader (5), Onyxia's Lair (1), Icecrown Citadel (12), Ruby Sanctum (1).

Architecture

Single-pass streaming state machine. Constant memory — state is bounded by player/encounter count, not file size.

ReadableStream<Uint8Array>
  → maybeDecompress (gzip auto-detect)
  → byteCounter (maxBytes enforcement)
  → TextDecoderStream
  → LineSplitter
  → parseLine() → LogEvent
  → CombatLogStateMachine
      ├─ EncounterTracker (boss detection, kill/wipe/idle/coward)
      ├─ RaidSeparator (segment tracking, Jaccard merging)
      ├─ CombatTracker (damage done/taken, pet→owner merging)
      ├─ ConsumableTracker (potions/bombs/flame cap, pre-pot)
      ├─ BuffUptimeTracker (flask/elixir/food intervals)
      ├─ DeathTracker (circular buffer recap)
      ├─ ExternalsTracker (cross-player buff intervals)
      └─ Player detection (class/spec, participation)
  → ScanResult / ParseResult / callbacks

Development

pnpm install
pnpm run build        # tsup → dist/
pnpm run test         # vitest (260 tests)
pnpm run typecheck    # tsc --noEmit
pnpm run bench <file> # memory/GC profiling
pnpm run bench:micro  # per-function benchmarks

License

MIT