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

@devant-net/reporter-core

v0.1.9

Published

Shared utilities for devq-cloud test reporters (HTTP queue, CI detection, stable IDs, test-case resolution, artifact upload).

Readme

@devant-net/reporter-core

Shared utilities for building test-runner reporters that stream results into Devant Cloud.

⚠️ Internal building block. Most users want one of the framework-specific packages instead:

What it gives you

  • DevqClient — typed wrapper around the /v1/runs/*, /v1/test-cases/* and artifact endpoints. Owns a RequestQueue so writes are non-blocking.
  • RequestQueue — bounded-retry HTTP queue with exponential backoff + jitter. flush() lets the framework's exit hook block until every in-flight request settles, so results never get dropped on shutdown.
  • detectCI() — populates the ci block on a run from environment variables. GitHub Actions, GitLab CI, CircleCI, Jenkins, Azure DevOps, plus a generic CI=true fallback.
  • resolveTestCase()@KEY tag → name match → auto-create. Same resolution order as the API expects.
  • uploadArtifacts() — multipart upload with path-traversal safety (only files inside the framework's outputDir are allowed).
  • generateStableId() — SHA-256 hash of file_path + title_path + title for cross-run identity when @KEY tags aren't present.

Wire (Devant Cloud)

| Step | Endpoint | |---|---| | Create run | POST /v1/runs | | Resolve test case | GET /v1/test-cases/by-key/:keyGET /v1/test-cases?search=…POST /v1/test-cases | | Submit results | POST /v1/runs/:id/results | | Upload artifact | POST /v1/runs/:id/results/:rid/attempts/:aid/artifacts (multipart) | | Complete run | POST /v1/runs/:id/complete |

Building a new reporter

import {
  DevqClient,
  detectCI,
  extractKey,
} from "@devant-net/reporter-core";

const client = new DevqClient({
  apiUrl: process.env.DEVQ_API_URL!,
  apiToken: process.env.DEVQ_TOKEN!,
  projectId: Number(process.env.DEVQ_PROJECT_ID),
});

// onBegin
const run = await client.createRun({
  name: `<framework> — ${new Date().toISOString()}`,
  framework: "<framework>",
  ci: detectCI(),
});

// per-test
const tc = await client.resolveTestCase({
  explicitKey: extractKey(...test.tags),
  fullName: `${test.suite} > ${test.title}`,
});

const [submitted] = await client.submitResults(run.id, [{
  test_case_id: tc.id,
  status: "pass",
  attempts: [{ attempt_no: 1, status: "pass", duration_ms: 123 }],
}]);

await client.uploadArtifacts(
  {
    runId: run.id,
    resultId: submitted.result_id,
    attemptId: submitted.attempt_ids[0]!.id,
    attemptNo: 1,
    outputDir: "/abs/path/to/test-results",
  },
  attachments,
);

// onEnd
await client.completeRun(run.id);
await client.flush();

Why this exists separate from each framework reporter

The HTTP/retry/CI-detection logic is identical across Playwright, Cypress, pytest, etc. Only the hooks (when each framework calls into the reporter) and the type adapters (mapping framework status/step trees to Devant Cloud shapes) differ. Putting the shared parts in core means each new framework reporter is ~150 lines instead of ~500.