@bekindlabs/mitte-beat-reporter
A Vitest reporter that streams your test cycle to a Mitte!Beat tenant as making beats — a failing test is a red cube, the passing test that follows turns it green. It is the write half of the beat: your TDD rhythm becomes a live signal on the board.
Install
npm i -D @bekindlabs/mitte-beat-reporter
npx mitte-beat-init --url https://<your-project>.supabase.co/functions/v1/ingest-event --secret <your ingest secret> --track <your track>
init wires the reporter into your Vitest config, writes the ingest creds to
.env, and makes sure .env is gitignored. Re-running is safe — it leaves an
already-wired config untouched, and a .env key already holding the same value
is left as is. A value you pass that differs from what's in .env replaces it
(MITTE_BEAT_* are mitte-beat-only keys), and a key you don't pass is left
alone. --track <track> sets MITTE_BEAT_TRACK, which the reporter needs to
attribute your beats to a lane (see below).
npm test now sends a making beat per test cycle.
Or wire it by hand
init only edits a config that has a reporters array or a test {} block; for
anything else add the reporter as an instance — an import plus a
new MitteBeatReporter() entry, no options object:
// vite.config.js / vitest.config.js
import MitteBeatReporter from '@bekindlabs/mitte-beat-reporter'
export default {
test: {
reporters: ['default', new MitteBeatReporter()],
},
}
Use the instance form, not the string form.
reporters: ['default', '@bekindlabs/mitte-beat-reporter']works in many setups but is resolved through vite'sServerModuleRunner, which silently fails to instantiate the reporter in some projects (certain monorepo / vite setups) — no beats, no error. The instance form is loaded by the config's native Node ESM and works on every version and host tested (spike #200027061).
…and set the env the reporter self-configures from:
MITTE_BEAT_INGEST_URL=https://<your-project>.supabase.co/functions/v1/ingest-event
MITTE_BEAT_INGEST_SECRET=<your ingest secret>
MITTE_BEAT_TRACK=<your track> # optional — auto-derived from a dev-<track> branch
MITTE_BEAT_STORY=200026812 # optional — attributes cubes to a delivery
MITTE_BEAT_TRACK names which lane made the beat and must match one of your
tenant's configured lanes. The reporter resolves it in order: an explicit
MITTE_BEAT_TRACK wins; otherwise it extracts the lane from a dev-<track> git
branch (so a Strike Trio worktree needs no per-session config); off such a branch
with no env set, it warns and broadcasts nothing rather than guessing a lane that
doesn't exist. Set MITTE_BEAT_TRACK only if your branches don't follow the
dev-<track> convention.
What it sends
On each run the reporter sends one append-only event per leaf test to your own ingest endpoint, authenticated with your own secret. Each event carries:
| field | value |
|---|---|
cycle |
a stable id: repo-relative file path + describe suite + test name |
state |
red (failing) or green (passing) |
module |
the test file basename (e.g. eventToCube) |
track |
MITTE_BEAT_TRACK |
story |
MITTE_BEAT_STORY, when set |
ts |
the run timestamp |
kind |
always test |
This is a self-report: your data, your token, your Beat tenant — not
third-party collection. The reporter never reads your source code; it only walks
Vitest's task tree. It never holds a privileged key — the ingest function alone
runs as service_role.
Safe by default
- Missing config → no-op. Missing
MITTE_BEAT_INGEST_URL,MITTE_BEAT_INGEST_SECRET, orMITTE_BEAT_TRACKand the reporter warns once (naming what's missing) and does nothing. CI and unconfigured runs are never affected. - Never blocks your tests. The ingest call is wrapped in an abort timeout (default 3s). A hung or unreachable endpoint is aborted and degrades to a warning — your test results and exit are untouched.
Don't install in a dev-omit shell. If
NODE_ENV=productionis set (or npm is configured withomit=dev/production=true),npm i -Dprunes every devDependency — vitest, jsdom and the rest — andnpm testthen runs zero tests. This is npm's behavior, not the reporter's. Install in a normal shell. If it already happened,npm installrestores your test deps;mitte-beat-initalso detects the missing deps and prints this same recovery hint.
Options
The no-args form needs none, but every field can be passed explicitly to the constructor (explicit wins over env):
import MitteBeatReporter from '@bekindlabs/mitte-beat-reporter'
reporters: ['default', new MitteBeatReporter({ track: 'sosuke', timeoutMs: 5000 })]
| option | env | default |
|---|---|---|
ingestUrl |
MITTE_BEAT_INGEST_URL |
— (required) |
ingestSecret |
MITTE_BEAT_INGEST_SECRET |
— (required) |
track |
MITTE_BEAT_TRACK |
dev-<track> branch |
story |
MITTE_BEAT_STORY |
— |
timeoutMs |
— | 3000 |
repoRoot |
— | process.cwd() |
License
MIT