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

@deploy-your-app/cli

v0.6.2

Published

Ship over-the-air (OTA) live updates to Capacitor and Electron apps from the command line — bundle, sign, deploy, stage rollouts, and roll back, powered by DeployYourApp (https://deployyour.app).

Readme

@deploy-your-app/cli

dya — ship over-the-air (OTA) updates to Capacitor and Electron apps from the command line. Bundle, sign, upload, roll out by percentage, and roll back JavaScript/HTML/CSS releases without an app store review cycle.

🌐 deployyour.app

Website · Documentation · CLI reference · Pricing · Compare OTA platforms · Changelog · Dashboard

npm license


What this is

dya is the command-line tool for DeployYourApp, a hosted OTA update, distribution, and diagnostics platform for Capacitor and Electron apps. It sets a project up, generates the signing keys that stay on your machine, and turns a built web directory into a signed bundle your installed apps download and apply themselves.

Use it when you want to:

  • Push a JavaScript/CSS fix to users the same day — "hot code push" / live update for Capacitor (iOS, Android) and Electron (Windows, macOS, Linux)
  • Deploy from CI with an API key, on every merge
  • Run staging and production channels off a single native binary
  • Release to 10% of devices first, then roll back in one command
  • Keep signing keys on your machine, never on a server

It needs a DeployYourApp account — every plan starts with a 30-day trial; see pricing.

The rest of the platform:

| Package | What it is | |---------|-----------| | @deploy-your-app/capacitor-update-manager | The Capacitor plugin that receives and applies these updates on iOS and Android | | @deploy-your-app/electron-update-manager | The same live-update pipeline for Electron desktop apps |

Install

npm install -g @deploy-your-app/cli
dya --version

Quick start

The fastest path for a Capacitor app is the guided setup — it signs you in, creates or links the app, generates signing/encryption keys, installs the @deploy-your-app/capacitor-update-manager plugin, writes its config, and wires notifyAppReady() into your app's entry point:

cd your-capacitor-app
dya setup

It never overwrites a source file it did not write. If src/dya.js (or src/boot/dya.ts) is already yours, that file is left alone, the module lands as dya-update, dya-ota, … and whichever name it takes is the one that gets registered — and the one later runs keep using, rather than adding a second module beside the first. Generated modules carry an @dya-generated marker comment; delete that line to take ownership of the file.

Delete a generated module and leave its import './dya' behind, and the next dya setup writes the file back — a registration with no module is a build that fails on a dangling import, so it is not a state setup reports as "already registered" and walks away from.

Then build your web assets and ship:

npm run build
dya deploy --channel production

dya init is an alias of dya setup — the same command under two names. Both need credentials, a reachable server, and a terminal on stdin and stdout — dya setup | tee setup.log is refused rather than started and then silently answered.

Setup will not guess at your signing keys. If the project holds two signing keypairs, or a dya-signing-public.pem that is not the public half of dya-signing-private.pem, it stops with Setup stopped before writing anything. — before the project config, the plugin install, or cap sync. The publicKey it embeds is derived from the private key dya deploy signs with, because that key is the only one your released apps will ever trust.

For the same reason it will not quietly replace a publicKey already embedded in capacitor.config.json. That file is committed and .dya/* is not, so a fresh clone of a shipped project has the public key and none of the private half — and a keypair generated there is a different one, so every installed app rejects everything signed with it, permanently. Replacing the embedded key therefore takes typing replace the signing key; a bare Enter keeps the embedded key and stops setup. Every refusal exits non-zero, so dya setup && npx cap sync stops rather than syncing a half-configured project.

The same phrase now guards dya keys generate and the key-generation step of setup. Minting a keypair while a different one is pinned is the same mistake one step earlier, and the fresh-clone shape — pinned public key, no private half anywhere — slips past every guard that only looks at keys on disk. Without a terminal the command refuses and exits 1 rather than defaulting either way.

What it leaves behind

Everything the CLI owns lives in one folder at your project's web root:

.dya/
  config.json                   # app ID, channel, assets path — commit this
  dya-signing-private.pem       # mode 0600 — never commit
  dya-signing-public.pem
  dya-encryption-public.pem
  dya-encryption-private.pem    # mode 0600 — never commit

plus this block in your .gitignore:

# DeployYourApp — keys and local state. Never commit these.
.dya/*
!.dya/config.json

Commit .dya/config.json and that block together. It has to be .dya/* rather than .dya/: git cannot re-include a file whose parent directory is excluded, so .dya/ would leave the config ignored — silently, since the file still exists locally — and CI would check out a project with no app ID or channel. You do not have to fix that by hand: a .dya/ line is detected, replaced with .dya/*, and reported, leaving the rest of your .gitignore untouched.

Nor do you have to check that it worked. After writing, the CLI asks real git check-ignore whether .dya/config.json is still ignored, and reports the file, line and pattern of anything that beat the block — a parent directory's .gitignore, .git/info/exclude, your global excludes file — none of which it will edit, because none of them are this project's file. With no git on PATH, outside a repository, or when git does not answer in time, the lines are still written but the success message carries the caveat — Written, but not verified: git could not say whether .dya/config.json is still ignored. — and prints the git check-ignore -v command to run yourself later. A check nobody could perform is never reported as a check that passed.

setup and deploy write the block too, before moving a stray private key into .dya/ — rules first, so an interrupted migration can only leave the key ignored, never exposed. If the .gitignore cannot be written, nothing is moved.

Projects set up by an older CLI keep working untouched. A .deployyourapp file at the project root and keys at the project root or in src-capacitor/ are still read; they are just never written any more. setup, keys generate, and deploy offer to move them into .dya/, and declining is fine.

Split project layouts

Quasar keeps the web app at the project root (package.json, src/, quasar.config.ts) and the Capacitor project in src-capacitor/ (capacitor.config.json, android/, ios/, a second package.json). The CLI resolves both and works from either directory — run it from inside src-capacitor/ and it resolves up to the web root. In such a layout the plugin is installed into both package.json files: the web root so the JS import resolves, the Capacitor root so npx cap sync sees the native plugin.

Manual flow

dya login                        # opens the dashboard to authorize the CLI
dya keys generate                # RSA-4096 signing + encryption keys into .dya/
dya deploy --channel production  # bundle, sign, upload, deploy

deploy needs appId and channel from .dya/config.json. Write it by hand if you are skipping dya setup.

Signing in

dya login needs no configuration — it points at DeployYourApp out of the box.

ℹ Authenticate your account at:
  https://app.deployyour.app/auth/cli-auth?session=cms9dczwb00006cu4ryck0hdc

Press ENTER to open in the browser...
- Waiting for you to authorize the CLI...
✓ Logged in as [email protected]

The URL is printed first, so you can copy it into a different browser or another machine instead of the default one. On a box with no desktop, dya login --no-browser prints the URL and skips the launch.

Two-factor authentication is enforced by the browser flow when your account has it enabled — the CLI never sees your password or authenticator secret, only the 30-day session token the browser hands back. It is stored with 0600 permissions in your OS config directory; dya logout clears it.

If your organization requires a 2FA code for uploads, dya deploy prompts for a fresh authenticator code at upload time. That needs a terminal, so a pipeline fails the upload with TWO_FACTOR_CODE_REQUIRED instead.

Commands

| Command | Description | |---|---| | dya login [--api-key <key>] [--no-browser] [--server <url>] | Authenticate (API key for CI; --no-browser for SSH/headless) | | dya logout | Clear stored credentials | | dya whoami | Show the signed-in account | | dya setup [--app-id <id>] [--channel <name>] [--server <url>] | Guided setup for a Capacitor project (app, keys, plugin install + config, entry-point wiring) | | dya init | Alias of dya setup | | dya deploy [--channel] [--version] [--rollout] [--message] [--no-deploy] [--allow-older] [--allow-unsigned] [--path] [--target capacitor\|electron] | Bundle, sign, upload, and deploy (refuses unsigned bundles unless --allow-unsigned) | | dya rollback [--channel] [--bundle <id>] | Roll a channel back to a previous bundle | | dya apps list / dya apps create --name <n> --app-id <id> [--platform] | Manage apps | | dya channels list / create --name <n> / delete --name <n> | Manage channels | | dya keys generate [--app-id <id>] | Generate RSA-4096 signing + encryption key pairs | | dya keys upload [--app-id <id>] | Upload existing public keys to the server | | dya orgs list / dya orgs switch [--slug <slug>] | Manage organizations (single-org accounts are selected automatically) |

--no-deploy uploads the bundle without pointing any channel at it — release it later from the dashboard. With no --version, the bundle version is your package.json version plus a UTC build stamp, e.g. 1.4.0+20260804.143022 — package.json must have a bare x.y.z version, or the deploy fails before anything is built. --version itself also takes a bare x.y.z. --rollout must be a whole number from 0 to 100.

deploy and rollback resolve --channel the same way — the flag, then channel in .dya/config.json, then production — so a bare dya rollback targets whatever a bare dya deploy shipped to. rollback prints the channel before it does anything.

Code signing

dya keys generate writes two RSA-4096 key pairs into .dya/ (private keys with 0600 permissions on macOS/Linux) and adds the .gitignore block for you, creating the file if needed. Only the signing keypair is used by dya deploy — bundles are never encrypted, and the encryption keypair it also writes currently has no consumer; do not embed its private key in your app.

One signing keypair per project. Generation is refused when a signing key already exists anywhere in the project, and if two distinct keypairs are found the CLI prints each path and fingerprint, marks the one embedded in capacitor.config.json, and exits 1 without writing anything — delete the other and re-run. It never picks for you: installed apps verify against the public key compiled into them, so signing a release with the wrong key makes every installed app reject that update and every update after it — with no server-side fix, only a new native release through the app stores.

Back the private keys up somewhere safe — a password manager or secrets vault. Lose dya-signing-private.pem and you cannot ship another update your installed apps will accept. Leak it and anyone can sign a bundle your users' apps will install.

If you run dya deploy before any keys exist, it warns that an unsigned bundle is refused by every installed client and offers to generate keys. In CI (no TTY) it does not prompt — it declines, rather than minting a key that would vanish with the build agent. If the Capacitor config already pins a publicKey, the offer is withdrawn entirely: iOS, Android, and Electron all require a valid signature before they will install anything, so a bundle signed with a new, unpinned key is rejected by every installed app exactly as permanently as an unsigned one — generating there would not be an improvement. Either way, with still no signing key resolved, dya deploy refuses to upload an unsigned bundle and exits 1 unless --allow-unsigned is passed — and even then the result cannot install: the server rejects the upload outright for an app that already has a signing key registered, and for an app with none, no installed client will ever apply the result, because signature verification is mandatory on every current platform.

dya deploy refuses to sign with a key your apps reject. Before signing, it fingerprints the signing key against the publicKey pinned in the Capacitor config and stops on a mismatch, exit 1, nothing uploaded — the upload it prevents would have looked completely successful while every device in the field rejected that bundle and every one after it. There is deliberately no --force: an override on the publishing command gets pasted into a CI script once and then suppresses the check forever. A real key rotation instead goes through dya setup, which takes the typed consent and re-pins the config, after which the fingerprints match honestly and the check passes on its own.

The pinned key is read from capacitor.config.json, .ts, or .js; a code config is not executed, only scanned for a plain publicKey string literal. When it cannot be read — code the literal is not in, invalid JSON, an unreadable file — the CLI says the check could not be performed rather than reporting a clean bill of health. Check plugins.DeployYourApp.publicKey yourself before shipping a key change in such a project.

Bundle asset policy

There is no bundle encryption. dya deploy uploads a plain, signed ZIP — an encrypted bundle is opaque to App Store review, so the pipeline instead makes bundle contents transparent: anyone can unzip an uploaded bundle and see exactly what ships. Before the ZIP is built, every file is checked against a web-asset extension allowlist and, regardless of name, against a table of native-executable magic bytes (Mach-O, ELF, Android DEX, PE/MZ, Java class); any violation is reported and the deploy exits 1 before anything is zipped or uploaded. The archive also carries a .dya-manifest.json with a per-file SHA-256 hash of every entry, which every client re-derives and checks bidirectionally during extraction.

Pointing at another environment

You almost certainly don't need this. The CLI targets deployyour.app with no setup. --server exists for working against a different DeployYourApp API — a local server during development, say — and the choice is persisted:

dya login --server http://localhost:3000

CI usage

Create an API key in the dashboard (Settings → API Keys), then:

dya login --api-key "$DEPLOY_YOUR_APP_API_KEY"
dya deploy --channel production --version "1.0.$GITHUB_RUN_NUMBER"

Never run dya setup or dya init in a pipeline — they need a terminal on both stdin and stdout, and exit 1 without one. CI does not need them: .dya/config.json is committed, so the checkout is already linked to the app.

Restore the signing key into .dya/ before deploying:

mkdir -p .dya
printf '%s' "$DYA_SIGNING_KEY_B64" | base64 -d > .dya/dya-signing-private.pem
chmod 600 .dya/dya-signing-private.pem

Omit --version to auto-generate one. All commands exit non-zero on failure, so a broken deploy fails the pipeline.


Links

| | | |---|---| | 🌐 Website | https://deployyour.app | | 📚 Documentation | https://deployyour.app/docs — quickstart, CLI commands, configuration, CI/CD | | 💰 Pricing | https://deployyour.app/pricing — 30-day trial on every plan | | 🔍 Compare | https://deployyour.app/compare | | 📊 Dashboard | https://app.deployyour.app | | 📝 Changelog | https://deployyour.app/changelog | | ✉️ Support | [email protected] |

Built and maintained by DeployYourApp. MIT licensed.