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

@hivetech/poker-engine

v1.0.1

Published

A deterministic, dependency-free no-limit Texas Hold'em state machine.

Readme

@hivetech/poker-engine

A deterministic, dependency-free no-limit Texas Hold'em state machine for Node.js.

The engine accepts serializable commands and returns a new authoritative state, domain events, or a typed error. It does not perform I/O, mutate input state, manage a database, or hide private cards for you unless you request a player-safe projection.

Requirements

  • Node.js 22 or newer
  • Native ECMAScript modules

The published package contains compiled JavaScript and TypeScript declarations and has no runtime dependencies.

Install

npm install @hivetech/poker-engine

Quick start

import {
  createShuffledDeck,
  createTable,
  getLegalActions,
  transition,
} from "@hivetech/poker-engine";

let state = createTable({
  smallBlind: 5,
  bigBlind: 10,
  minBuyIn: 1_000,
  maxSeats: 6,
});

function dispatch(command) {
  const result = transition(state, command);
  if (!result.ok) {
    console.error(result.error.code, result.error.message);
    return false;
  }

  state = result.state;
  for (const event of result.events) {
    console.log(event);
  }
  return true;
}

dispatch({ type: "seat-player", playerId: "alice", stack: 1_000, seat: 0 });
dispatch({ type: "seat-player", playerId: "bob", stack: 1_000, seat: 1 });
dispatch({ type: "start-hand", deck: createShuffledDeck() });

const actor = state.hand.players.find(
  (player) => player.seat === state.hand.currentActorSeat,
);

console.log(getLegalActions(state, actor.playerId));
dispatch({
  type: "act",
  playerId: actor.playerId,
  action: { kind: "call" },
});

transition leaves the input object untouched. A rejected command returns the exact input state:

type TransitionResult =
  | { ok: true; state: TableState; events: readonly DomainEvent[] }
  | { ok: false; state: TableState; error: EngineError };

Commands

The TableCommand union supports:

  • seat-player
  • leave-player
  • set-sitting-out
  • add-chips
  • set-forced-bets
  • start-hand
  • act

Player actions are fold, check, call, bet-to, and raise-to. Bet and raise amounts always mean the player's final total commitment for the current street:

dispatch({
  type: "act",
  playerId: "alice",
  action: { kind: "raise-to", amount: 60 },
});

Use getLegalActions to obtain the exact call amount and permitted bet/raise range:

[
  { kind: "fold" },
  { kind: "call", amount: 20 },
  { kind: "raise-to", minAmount: 50, maxAmount: 980 },
];

Normal invalid input—acting out of turn, checking into a bet, under-raising, or using an invalid stack—returns a stable EngineErrorCode. Corrupt or internally impossible state throws PokerEngineInvariantError.

Deterministic dealing and replay

start-hand requires a complete, unique 52-card deck. The first element is the next card dealt. This keeps the transition itself pure and makes replay exact.

Use createShuffledDeck() for a cryptographically shuffled Node.js deck, or supply a recorded/test deck:

dispatch({ type: "start-hand", deck: createShuffledDeck() });

Commands—including each starting deck—are JSON-serializable. They can be replayed directly:

import { replayCommands } from "@hivetech/poker-engine";

const replay = replayCommands(tableConfig, commandLog);
if (!replay.ok) {
  console.error(`Command ${replay.commandIndex} failed`, replay.error);
}

The authoritative state is also JSON-serializable. It contains the deck and every hole card, so do not send it directly to untrusted clients.

Safe player and spectator views

Use projectTable and projectEvents at an application boundary:

import { projectEvents, projectTable } from "@hivetech/poker-engine";

const aliceView = projectTable(state, { kind: "player", playerId: "alice" });
const publicView = projectTable(state, { kind: "spectator" });

const aliceEvents = projectEvents(events, {
  kind: "player",
  playerId: "alice",
});

Projections remove the deck and burned cards. During play, a player sees only their own hole cards and a spectator sees none. At showdown, non-folded hands are revealed; a hand won by folds remains hidden.

Table behavior

  • Two through ten configurable seats, including sparse seating
  • Correct heads-up button, blind, and action order
  • Uniform ante or big-blind ante
  • Partial forced bets and all-ins
  • Minimum-bet and full-raise enforcement
  • Short all-ins and cumulative action-reopening rules
  • Main pots, nested side pots, unmatched-bet refunds, and folded-player eligibility
  • Integer split-pot payouts, with odd chips awarded clockwise after the button
  • Standard burns and automatic board runout when no decisions remain
  • Waiting players, sitting out/in, mid-hand departure, and between-hand chip additions
  • Dependency-free five-to-seven-card high-hand evaluation

The engine deliberately does not provide networking, persistence, bankrolls, timers, tournament blind schedules, straddles, run-it-twice, Omaha, or limit betting. A host application can change blinds and antes between hands with set-forced-bets.

Antes are posted before blinds. If a player's stack cannot cover a forced bet, the remaining stack is posted and the player is all-in.

Cards and hand evaluation

Cards use compact rank and suit values:

import {
  evaluateHand,
  parseCard,
} from "@hivetech/poker-engine";

const result = evaluateHand(
  "As Ks Qs Js Ts 2d 2c".split(" ").map(parseCard),
);

console.log(result.category); // "straight-flush"
console.log(result.tiebreak); // [14]

Ranks are 2 through 9, T, J, Q, K, and A. Suits are c, d, h, and s.

Development

npm ci
npm run typecheck
npm test
npm pack --dry-run

The test suite exhaustively verifies all 2,598,960 five-card combinations, exercises generated legal-action sequences, checks chip conservation and replay, and includes regressions for the original repository's payout, all-in, TypeScript, and packaging reports.

See MIGRATION.md when moving from @chevtek/poker-engine.

License

MIT