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

@braulio-dev/hopper

v0.1.1

Published

End to end verification for Minecraft server plugins

Readme

hopper

End to end testing for Minecraft server plugins. One command builds your plugin, deploys it to a real server, restarts the server, checks the startup log, runs scenarios with real bots, and exits nonzero on any failure.

What a run does

  1. Build. Runs your build commands in order and stops at the first failure.
  2. Collect. Finds the built files with your globs.
  3. Deploy. Copies them into the server's plugins folder. Any file it replaces is backed up first.
  4. Restart. Stops and starts the server and waits until it is ready.
  5. Scan startup. Reads the startup log for plugin load failures, enable errors, missing dependencies and stack traces. Known issues you list are hidden and counted.
  6. Scenarios. Connects bots and runs each scenario file.
  7. Report. Prints a short summary, writes a JSON report and saves full logs.

A rerun with no source changes since the last pass exits 0 at once. --force runs anyway.

Install

npm install --save-dev --save-exact @braulio-dev/hopper

It needs Node 22 or newer. Pin the version so every machine and CI runs the same one.

Configure

Create hopper.config.ts in your project:

import { defineConfig } from '@braulio-dev/hopper'

export default defineConfig({
  version: 1,

  build: {
    steps: [
      { name: 'compile', command: './gradlew compileJava', kind: 'compile' },
      { name: 'unit tests', command: './gradlew test', kind: 'test' },
      { name: 'package', command: './gradlew shadowJar', kind: 'package' },
    ],
  },

  artifacts: { include: ['build/libs/*.jar'] },

  target: {
    // Where the server runs. See the setup guides below.
  },

  startup: {
    knownIssues: [
      { id: 'noisy-plugin', match: /SomePlugin\] Could not find config/, reason: 'harmless on test servers' },
    ],
  },
})

Build commands are plain shell commands, so any build tool works.

| Key | What it sets | | --- | --- | | build.steps | Commands to run in order. kind: 'test' steps are skipped by --skip-tests. | | artifacts | Globs for the files to deploy. | | target | Where the server runs and how to control it. | | topology | direct, or proxied to join through a proxy and switch to a backend. | | auth | offline bot names, or microsoft accounts. | | scenarios | Scenario folder, globs and the bot connect timeout. | | startup | Extra scan rules, known issues, failOn and settleMs. | | fingerprint | Files that decide whether anything changed. | | deploy | How many backups to keep. | | secrets | The env file to read secrets from. | | selector | Optional. Skip scenarios a change cannot affect. |

Choose a setup

| Setup | Guide | | --- | --- | | A throwaway server the tool downloads and runs, for local runs and CI | docs/setup/local-managed.md | | A server folder you already run on your machine | docs/setup/local-existing.md | | A server on a Pterodactyl panel, direct or behind a proxy | docs/setup/pterodactyl.md |

Write scenarios

A scenario is a file in scenarios/ that exports a name, the bots it needs and a default async function.

import type { ScenarioContext } from '@braulio-dev/hopper/scenario'

export const name = 'greeting'
export const description = 'The greet command replies to the player'
export const bots = ['alice']

export default async function ({ bot, console: server, assert }: ScenarioContext) {
  const marker = await bot.command('/greet')
  await bot.expectChat(/Hello, alice/, { after: marker, timeoutMs: 5000 })

  const lines = await server.run('minecraft:list')
  assert.ok(lines.length > 0, 'the server console answered')
}
  • bot.command and bot.chat return a marker. Pass it as after so only newer chat counts.
  • bot.expectChat and every assert.* record a failure and keep going. bot.waitForChat throws, for setup that has to succeed.
  • bot.inventory(), bot.sidebar(), bot.openWindow() and bot.position() read state.
  • console.run(command) runs a server command and returns what it printed.
  • Scenarios share one server, so each one cleans up what it changed.

The full API is in @braulio-dev/hopper/scenario. It is versioned, and a scenario written for another version is refused with a clear message.

Run

npx hopper run

| Flag | Effect | | --- | --- | | --only <scenario> | Run one scenario. | | --skip-tests | Skip build steps with kind: 'test'. | | --no-build | Skip the build. | | --no-deploy | Skip the deploy. | | --no-restart | Skip the restart and the startup scan. | | --force | Run even if nothing changed since the last pass. | | --all | Run every scenario even when a selector is configured. | | --config <path> | Use a config file that is not found automatically. |

Other commands:

  • npx hopper status says whether the current source has passed a full run.
  • npx hopper auth login signs in Microsoft accounts once.
  • npx hopper auth status shows which accounts have a usable sign in.

| Exit code | Meaning | | --- | --- | | 0 | Passed, or skipped because nothing changed. | | 1 | A build, startup scan or scenario failed. | | 2 | The config or setup is wrong, such as a missing secret. | | 3 | The tool could not reach or control the server. |

The report is written to .plugin-e2e/report.json and the full logs to .plugin-e2e/logs/. Add .plugin-e2e/ to your .gitignore.

Secrets

Secrets are never written in the config. Reference them instead:

apiKey: { env: 'PTERODACTYL_API_KEY' }

The value is read from the environment, then from a .env file next to the config, then asked for when a person is at the terminal. Unattended runs fail with the name of the missing variable. Every secret is masked in the console, the logs and the report.

More

Safety

  • It never edits or deletes world data, player data or plugins it did not deploy.
  • It backs up every file it replaces and keeps the last few backups.
  • It never kills a server it did not start, and never force kills a remote one.
  • It never restarts a proxy unless the config allows it.
  • It never retries a failed assertion.

License

MIT