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

@hammerbot/job-runner

v0.1.0

Published

Déclare des jobs (cron/webhook), obtiens télémétrie OpenTelemetry + dashboard. Extrait de coderhammer/automations.

Readme

@hammerbot/job-runner

Déclare des jobs (cron ou webhook), obtiens gratuitement : exécution planifiée, télémétrie OpenTelemetry (span par job + sous-étapes, persistés en SQLite), un flux temps réel (SSE) et un dashboard web complet — sans écrire une ligne de serveur, de base de données ni de front.

Extrait de coderhammer/automations, qui en est désormais le premier consommateur.

Quickstart

// index.ts — tout le service tient ici
import "dotenv/config";
import { start } from "@hammerbot/job-runner";
import { workflows } from "./workflows.js";
import { myWebhookHandler } from "./jobs/myWebhook.js";

start({
  workflows,
  webhooks: [{ path: "/webhooks/my-source", handler: myWebhookHandler }],
});
// workflows.ts — le manifest : déclare tes jobs
import type { WorkflowDefinition } from "@hammerbot/job-runner";
import { runDailyReport } from "./jobs/dailyReport.js";

export const workflows: WorkflowDefinition[] = [
  {
    id: "daily-report",
    name: "Rapport quotidien",
    description: "Envoie le rapport de la veille.",
    schedule: "0 8 * * *", // cron (fuseau TZ, défaut Europe/Paris)
    trigger: "cron",
    inputs: [],
    run: () => runDailyReport(),
  },
];

C'est tout. GET / sert le dashboard, GET /healthz le health check, GET /api/* l'API d'exécutions, POST /api/workflows/:id/trigger un déclenchement manuel.

Configuration (variables d'env)

| Variable | Défaut | Rôle | |---|---|---| | PORT | 3000 | port HTTP | | ACTIVATE_CRONS | (off) | true pour planifier réellement les crons (laisser off en dev pour éviter les effets de bord en double avec la prod) | | TZ | Europe/Paris | fuseau des crons | | DATA_DIR | ./.data | dossier du fichier SQLite (monter un volume en prod) | | DB_FILENAME | jobs.db | nom du fichier SQLite. Pour migrer un service existant, pointer sur le fichier déjà présent sur le volume (ex. automations.db) pour conserver l'historique | | OTEL_SERVICE_NAME | jobs | nom de service dans la ressource OpenTelemetry |

Instrumenter un job

Un job = un span racine (withSpan) + un span enfant par étape externe (withChildSpan).

import { withSpan, withChildSpan } from "@hammerbot/job-runner";

export async function runDailyReport(): Promise<void> {
  await withSpan("daily-report", {}, async (span) => {
    const data = await withChildSpan(span, "fetch-data", {}, fetchData);
    await withChildSpan(span, "post-slack", {}, async (postSpan) => {
      const channel = process.env.SLACK_CHANNEL;
      if (!channel) throw new Error("SLACK_CHANNEL manquant");
      postSpan.setAttribute("slack.channel", channel);
      await postSlackMessage(channel, format(data));
    });
  });
}

Règles (issues d'incidents réels, à respecter pour un waterfall lisible) :

  • Le waterfall ne doit pas avoir de trou : tout temps non trivial (même un calcul CPU d'agrégation/formatage entre deux appels) mérite son withChildSpan, sinon la barre racine dépasse la somme de ses enfants — illisible.
  • Ne jamais valider une précondition de config avant d'ouvrir le span qui en a besoin. Une vérif en tête de fonction fait échouer le span racine « à l'aveugle » ; mets-la dans le withChildSpan concerné (cf. exemple ci-dessus).
  • Les appels fetch() sortants sont auto-instrumentés (undici) et se rattachent au span actif — pas besoin de les wrapper à la main, mais garde un withChildSpan autour de la logique métier qui les entoure.
  • Handlers de webhook : ne jamais laisser une fonction en tête d'un handler async (ex. verifySignature) throw sans try/catch — un throw synchrone dans un handler Express async crashe le process.

Modèle de consommation (première implémentation)

Le paquet n'est pas encore publié sur un registre npm. En attendant, il se consomme par dépendance git avec le dist/ commité dans ce repo :

{ "dependencies": { "@hammerbot/job-runner": "git+ssh://[email protected]/coderhammer/job-runner.git#<sha>" } }

Le dashboard prébuildé, les migrations et le serveur compilé voyagent dans dist/, donc aucune étape de build côté consommateur.

Suivi prévu : publier sur GitHub Packages (registre npm privé) pour remplacer la dépendance git par une version sémantique, et brancher une CI de publication. Voir la PR de migration d'automations pour les implications côté Docker/CI (auth du repo privé au npm ci).

Développer le dashboard

npm run dev:client lance Vite (HMR) en proxifiant /api vers un serveur consommateur tournant sur :3000. npm run build régénère dist/ (tsc + Vite + migrations).