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

@hearthforge/plugin-reference

v0.2.0

Published

A complete HearthForge plugin for a fake two-container game — the SDK's executable spec

Readme

@hearthforge/plugin-reference

A real plugin for a fake game. It exists so HearthForge's game-agnostic wiring — provision → running, console, live data, backup/restore, self-heal, identity re-stamping — can be proven ONCE against a realm that boots in seconds, instead of once per real game.

It is held to every real-plugin law: all seven adapters implemented honestly (no return true stubs), 100% i18n copy, config opaque to core, full SDK compliance. Core must never be able to tell it from a real game. A core change that needs a reference-plugin special case is a broken seam — fix the seam.

The game

One image, hearthforge-refgame, three roles selected by REF_ROLE (packages/plugin-reference/image/, three stdlib-only JS files, no npm deps):

| role | port(s) | what it is | |---|---|---| | store | 7801 | the "database": a line protocol (PING/SET/GET/LIST/DEL/SAVE) over /data/store.json, write-through + fsync | | core | 7777 game, 7787 admin | the "game server": dials the store with retry, simulates a REF_BOOT_MS world load, then binds both ports and logs [core] ready | | leaderboard | 7811 | module-only: TOP / INIT over /data/board.json |

Everything the platform touches is a real protocol: the admin port demands AUTH <REF_ADMIN_PASSWORD> before any command, the command-plane probe is an authenticated info round-trip (steady-scoped, so a dead plane can never wedge a boot — readiness is the tcp dial), graceful stop is a command the server obeys (SAVE then exit 0), and crash writes /data/crash/last.txt and exits 3.

The framing rule (one line, two forms)

Every request is ONE newline-terminated line and every reply is exactly one (a list reply is JSON on that single line). A line carries its ARGUMENTS in one of two forms, and image/line-protocol.js — required by both server.js and refctl.js, so writer and parser cannot drift — is the only implementation:

| form | looks like | who writes it | |---|---|---| | argv (canonical) | ["stamp-realm","Probe Realm",""] | every programmatic writer: refctl admin <verb> [arg…], the plugin's encodeArgv (src/refnet/line-protocol.ts), the core's own store calls | | space (legacy/human) | say hello world | the operator console — what a person typed, and commands whose last argument runs to end-of-line (say, HELLO) |

Space framing cannot express a multi-argument command whose arguments contain spaces, and a realm name is copy: stamp-realm "Probe Realm" <host> arrived as name="Probe" with publicHost shifted into the tail — silent data corruption, not a quoting inconvenience. JSON also escapes a newline, so an argv-form request can never split into two commands. A malformed argv line is answered ERR, never re-read as the space form: guessing is how a shifted argument becomes invisible.

Compatibility: the image and the plugin version together, so this was a clean break. The space form survives only because the console genuinely needs it; refctl admin now takes ARGV (refctl admin stamp-realm 'Probe Realm' host), never a shell string. AUTH <secret> is compared whole-line and is unaffected.

src/refnet/line-protocol.spec.ts round-trips the plugin's encoder through the image's actual parser, and src/refnet/admin-protocol.socket.spec.ts runs the real server.js roles as child processes and stamps a space-bearing realm name through both writers over real sockets.

The image's own contracts — enforced in server.js, not merely declared

  • No secret ⇒ no command plane. With REF_ADMIN_PASSWORD empty the core logs a refusal and does not bind the admin port. An empty secret would otherwise pre-authenticate every connection (authed = ADMIN_PASSWORD === "") — a wide-open plane that can crash, stop and re-stamp the realm — while the panel's own AuthAdapter refuses to use it anyway. validateConfig rejects such a config too: two independent ends of one rule. The game port and the store keep serving.
  • [<role>] ready means the ports are bound, and it is the bootstrap's wait-log-pattern target. wait-healthy (container RUNNING) is not a port-bound signal — the core binds only after REF_BOOT_MS, so every exec against an admin/board port is gated on the ready line.
  • Crash notes live under the DATA dir (/data/crash/last.txt), never under the /app WORKDIR — the declared crash glob is absolute for that reason, and ReferencePlugin.analyzeCrash parses what it captures.

refctl.js is the in-image CLI the agent execs (the rcon-cli analog): refctl ping, refctl admin <cmd…>, refctl stop, refctl board-init, refctl top. It reads its endpoints and the admin secret from its own container env, so no credential ever appears in a command line.

Building the image

scripts/build-images.sh refgame

That is the ONE command. It tags hearthforge-refgame:latest — the exact reference the generated compose asks for. refgame is not in the publish matrix, so unlike the published images it is NOT tagged :ci-local: that build is the only artifact there is, and any other tag leaves every provision failing "image not found".

The generated compose sets pull_policy: never — the image exists on no registry, so a docker compose pull must never reach out for it. A deploy on a node without the image fails loud ("image not found"), which is the honest outcome: build it there first.

Single-node test article. A remote agent node would need the image loaded by hand (docker save | docker load). That is fine and deliberate — this game is for the local gate, not for operators.

Loading it

It is NOT in the panel's default plugin list. Name it explicitly:

HEARTHFORGE_PLUGINS=@hearthforge/plugin-azerothcore,@hearthforge/plugin-minecraft,@hearthforge/plugin-reference

Production defaults stay at the two real games.

Concurrent realms: pick a port, or suppress host publishing. The core publishes its game port 1:1 (gamePort, default 7777 — PortRequirement.configKey, the allocation model), so two reference realms on ONE panel coexist by taking different ports: the wizard pre-flight (POST /instances/port-plan) suggests the next free one and a collision is refused with 409. Realms from DIFFERENT panels on one daemon are invisible to each other's plan — for that regime (the gate, parallel dev worktrees) run the panel with HEARTHFORGE_SUPPRESS_HOST_PORTS=1 (what the gate does) and core strips host publishing — every realm is then reachable only in-network, which is all the platform itself needs (the agent execs refctl; probes dial container IPs). Without it, keep to ONE reference realm per daemon.

Keeping it honest (the anti-drift rule)

Any NEW adapter or manifest capability lands with its reference implementation in the same PR. The reference plugin is the contract's executable spec; a capability no reference implementation exercises is a capability nothing tests generically.