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

@junoflow/cli

v0.3.0

Published

Command line tools for developing Juno integrations

Readme

@junoflow/cli

Develop Juno integrations locally: scaffold a project, generate types from your manifest, check it, and deploy it.

npm install --save-dev @junoflow/cli
npx juno init my-integration --url http://juno.local:8080

An integration is a git repository holding manifest.json and TypeScript. Juno fetches it at a tag, compiles it, and runs it in a sandbox. There is no packaging format and nothing is published to npm.

Commands

| Command | What it does | | ----------------------- | ------------------------------------------------------------------------------ | | juno init <name> | fetch a starting project from a Juno and write it down | | juno types | POST manifest.json, write types/ | | juno verify-types | check types/ still matches manifest.json — talks to nothing | | juno check | local verify-types + tsc --noEmit + eslint, then validate against a Juno | | juno deploy [--watch] | upload, verify, activate — and write back the returned types | | juno pull | write back the manifest and sources the instance holds |

Options

| Flag | Meaning | | --------------- | -------------------------------------------------------------------- | | --url <url> | the instance to talk to | | --name <name> | address an install under a different name than the manifest declares | | --watch | redeploy on every save (deploy) | | --force | overwrite a dirty working tree (pull) | | --here | scaffold into the current directory (init) | | --skip-local | skip the local verify-types/tsc/eslint pass (check) |

Choosing an instance

In order: --url, then $JUNO_URL, then "juno": { "target": … } in package.json. A project downloaded from a Juno already has the third, so a fresh clone deploys with no setup.

Juno has no authentication on any endpoint. An instance is a trusted-LAN appliance; do not expose one to the internet.

The loop

npm run watch          # juno deploy --watch

Add an action to manifest.json. The types regenerate, and your editor immediately red-squiggles src/integration.ts because IntegrationActions now requires a method you have not written — with the parameter and return types your JSON Schema implies. The manifest drives the types drive the compiler.

Why the types are committed

types/ is generated and checked in. CI needs no Juno, a fresh clone compiles offline, and the diff in a pull request shows that adding an action changed the interface. Most importantly, a drive-by contributor fixing a bug in someone else's integration never needs an instance — only the person changing the manifest does.

The cost of that decision is drift: edit manifest.json, forget npm run types, and every other signal stays green while types/ describes a contract you no longer declare. tsc compiles happily against stale types, eslint is happy, and the testkit's conformance check compares the manifest with your module, never with types/ — so the mismatch surfaces at deploy, or later, as a flow author calling an action whose shape changed.

juno verify-types closes it. juno types records a fingerprint of the manifest.json it generated from, as a comment in types/integration-env.d.ts:

// integration-env.d.ts for 'pushover'
// DO NOT EDIT — generated by 'juno types' from 'manifest.json'.
// juno:manifest-sha256 5c5ca8eabe12cf44

verify-types recomputes it and compares. It runs first in npm test and inside juno check, and it contacts nothing — which is the point: the mistake is caught in a contributor's CI, and that CI deliberately has no instance to ask. Reformatting manifest.json also invalidates the stamp; the fix is the same npm run types either way.

What runs where

| | offline | needs an instance | | --------------------------------------------------------------- | ------- | ----------------- | | tsc --noEmit, eslint, vitest | ✅ | | | juno verify-types (is types/ current?) | ✅ | | | structural manifest check via "$schema" in your editor | ✅ | | | reserved names, cross-surface collisions, JSON Schema compiling | | juno check | | juno init, juno types, juno deploy | | ✅ |

Everything semantic lives in the Go server. This package knows some HTTP endpoints and a config preset — that is deliberate, so there is one answer to "is this manifest valid" rather than two that can disagree.

init vs. downloading a project

Both produce the same project, from the same generator on the instance: init starts from a stub manifest, the Develop locally → Download project button starts from an integration that already exists there. Neither is a local template — the CLI writes the files it is handed, so a scaffold cannot drift from what the server ejects. To refresh an existing checkout use juno pull; a second download would clobber your working tree.