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

nappup

v2.3.12

Published

Nostr App Uploader

Downloads

781

Readme

Napp Up!

  _   _                   _   _       _
 | \ | | __ _ _ __  _ __ | | | |_ __ | |
 |  \| |/ _` | '_ \| '_ \| | | | '_ \| |
 | |\  | (_| | |_) | |_) | |_| | |_) |_|
 |_| \_|\__,_| .__/| .__/ \___/| .__/(_)
             |_|   |_|         |_|

Napp Up! is a powerful CLI tool for developers to effortlessly upload and manage Nostr applications. Ship your decentralized apps to the Nostr network with a single command.

Usage

nappup [directory] [options]

Arguments

  • [directory] The root directory of your application to upload. If omitted, defaults to the current working directory (.).

Options

| Flag | Description | |------|-------------| | -s <secret_key> | Your Nostr secret key (hex, nsec, or bunker:// URL) used to sign the application event. See Authentication for alternatives. | | -d <d_tag> | The identifier (d tag) for your application. Any UTF-8 text up to 260 characters. If omitted, defaults to the directory name. Avoid generic names like dist or build - use something unique among your other apps like mycoolapp. | | -y | Skip confirmation prompt. Useful for CI/CD pipelines or automated scripts. | | -r | Force re-upload. By default, Napp Up! might skip files that haven't changed. Use this flag to ensure everything is pushed fresh; it does not create a new app version unless a file path or hash changes. | | --main | Publish to the main release channel. This is the default behavior. | | --next | Publish to the next release channel. Ideal for beta testing or staging builds. | | --draft | Publish to the draft release channel. Use this for internal testing or work-in-progress builds. | | --dotenv-private-key <hex> | Use a 32-byte hex private key to decrypt and manage encrypted credentials in .env. Prefer DOTENV_PRIVATE_KEY_NAPPUP because command-line arguments can be visible in shell history and process listings. |

Authentication

Napp Up! supports multiple ways to provide your Nostr secret key:

  1. CLI flag: Pass your secret key (hex or nsec) directly via -s:

    nappup -s nsec1...
  2. Remote signer (NIP-46): Pass a bunker:// URL to sign events via a remote signer like nak or Amber:

    nappup -s 'bunker://<pubkey>?relay=wss://relay.example.com&secret=<token>'

    Napp Up! creates a persistent NIP-46 client key before connecting. For URLs passed with -s, the latest session is stored as LAST_CLI_BUNKER_SESSION in the project's .env. A URL without secret is also valid when the remote signer uses its public key as the access capability.

  3. Environment variable: Set NOSTR_SECRET_KEY in your environment or a .env file (also supports bunker:// URLs):

    export NOSTR_SECRET_KEY=nsec1...
    nappup ./dist
  4. Auto-generated key: If no key is provided, Napp Up! will generate a new keypair automatically and store it (as nsec) in your project's .env file for future use.

When NOSTR_SECRET_KEY in .env is a bunker URL, Napp Up! adds the local client key as a #client_key=... URI fragment while retaining the query-string secret for compatibility fallback. Reconnects first use the same client key without the token and retry with the token only if necessary.

Napp Up! stores NOSTR_SECRET_KEY and LAST_CLI_BUNKER_SESSION in the official dotenvx encrypted:<base64> format, using the compressed public key in DOTENV_PUBLIC_KEY_NAPPUP. The private key is selected from --dotenv-private-key, then DOTENV_PRIVATE_KEY_NAPPUP in the process environment, and finally a built-in fallback. The public key is selected from the .env, then the process environment, and finally derived from the selected private key.

The built-in fallback makes migration automatic, but is public knowledge and therefore only hides plaintext; use an explicit private key for confidentiality. Generate one locally for storage in your secret manager with:

nappup env keygen

Alternatively, generate and export one directly into the current shell:

export DOTENV_PRIVATE_KEY_NAPPUP="$(nappup env keygen)"

env keygen writes only the generated 64-character lowercase hex key to standard output, writes a reminder to standard error, and never reads or modifies .env. Store the result in a secret manager; nappup cannot recover it.

Encrypting a replacement requires only DOTENV_PUBLIC_KEY_NAPPUP. The command below receives the new Nostr credential (a secret key or bunker URL), but does not require DOTENV_PRIVATE_KEY_NAPPUP, the separate dotenv decryption key. It does not need to decrypt or know the previous Nostr credential:

nappup env set NOSTR_SECRET_KEY
printf '%s\n' 'nsec1...' | nappup env set NOSTR_SECRET_KEY

The interactive form hides and confirms the value. Redirected stdin and a positional value are also accepted; the positional form emits a warning because it may be exposed through shell history or process listings. With only DOTENV_PUBLIC_KEY_NAPPUP, env set can encrypt a replacement, while commands that need an existing value fail clearly without the matching private key.

Existing plaintext values are encrypted automatically when used. If an explicit private key does not match the stored public key, it becomes authoritative: recoverable values are re-encrypted and inaccessible credentials are reset with a warning naming only the affected variables. This can result in a new publisher identity or bunker client key.

Use DOTENV_CONFIG_PATH to select a different dotenv file. The private key must come from the process environment or CLI and is rejected if stored inside that file.

Local development and shared credentials

To use a checkout instead of the registry package:

cd /path/to/nappup
npm link
cd /path/to/app
npm link nappup --no-save --package-lock=false

The second command links the app dependency and its local CLI to the global link. Projects that use nappup at runtime can keep a registry dependency for reproducible installs; local CLI-only projects may rely entirely on the link. npm ci removes local links, so repeat the second command afterward. When switching Node/npm installations, repeat both commands to register the checkout under the new global prefix as well.

A link shares code, not credentials: .env still defaults to the current working directory. To use one existing encrypted identity across projects, export an absolute path to its dotenv file in the shells running nappup:

export DOTENV_CONFIG_PATH="/absolute/path/to/shared/nappup.env"
nappup env set NOSTR_SECRET_KEY

Choose an existing file to retain its identity, or set the desired credential once in a new file. Supply the matching DOTENV_PRIVATE_KEY_NAPPUP if that file uses a custom encryption key. Changing credentials in a shared file affects every project using it; existing project .env files are not automatically merged or migrated. A process-level NOSTR_SECRET_KEY still takes precedence over the file.

Examples

Upload the current directory to the main channel:

nappup -s nsec1...

Or using an environment variable:

NOSTR_SECRET_KEY=nsec1... nappup

Upload a specific dist folder with a custom identifier to the next channel:

nappup ./dist -s nsec1... -d "My App #1" --next

Force re-upload a draft:

nappup ~/my-repos/projectx/build/projectx --draft -r

Programmatic Usage

Each published manifest includes an aggregate x tag that identifies the app version from its file path/hash mappings. Updating only manifest metadata or forcing a re-upload preserves that aggregate. The published_at tag records the first publication time of that aggregate and is preserved across later metadata revisions, while the event's created_at records the latest manifest revision.

Napp Up! also exports a function that works in both Node.js and the browser, so you can integrate app uploads directly into your own tooling:

import publishApp from 'nappup'

await publishApp(fileList, signer, {
  dTag: 'my-app',
  channel: 'main',       // 'main' | 'next' | 'draft'
  shouldReupload: false,
  onEvent ({ type, progress }) {
    console.log(`${type} — ${progress}%`)
  }
})
  • fileList — a FileList or array of File objects (each needs webkitRelativePath).
  • signer — a NIP-07-compatible signer. In the browser, window.nostr is used automatically if omitted.
  • onEvent — optional callback that receives progress events with a type ('services-checking', 'init', 'file-uploaded', 'complete', 'error', …) and progress (0–100).

Rejected uploads use NappupError, with a stable code from NAPPUP_ERROR_CODES. The original error is retained as cause, and some errors include structured details, so applications can show their own recovery instructions without matching CLI-oriented message text.

For terminal destination failures, error.details.failures contains { destination, filename?, reason } entries. reason retains the original error, including HTTP status, retryable, retryAfterMs, or relay category when available. Native causes and aggregated errors remain available for diagnostics. Signer failures are normalized to NAPPUP_SIGNER_LOCKED or NAPPUP_SIGNER_DENIED, including when nested inside an aggregate.

A file succeeds when at least one destination confirms a copy (each chunk for IRFS). Failures of extra replicas are logged without emitting a terminal error. Publishing the app manifest still requires a confirmed copy. Display recovery instructions for rejected operations; use specific destination guidance only when it applies to all blocking failures. Different files may succeed on different servers.

import publishApp, { NAPPUP_ERROR_CODES } from 'nappup'

try {
  await publishApp(fileList, signer)
} catch (error) {
  if (error.code === NAPPUP_ERROR_CODES.GENERIC_FOLDER_NAME) {
    // Ask the user to choose a unique app folder name.
  }
}