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

@sprid/release

v0.1.2

Published

Build, sign and release mobile apps locally. Store copy, screenshots, binary uploads and review submissions from one app-owned configuration. Dry run by default.

Readme

@sprid/release

The store listing as a file in your repo. Name, subtitle, keywords, description, screenshots and Play graphics per locale live in release.config.ts, get reviewed like code, and are pushed to App Store Connect and Google Play with one command. Dry run by default.

Local builds, signing, binary uploads and review submission run through ship. Use build.framework: 'expo' for Expo generation or 'native' for an existing native tree. Other toolchains supply argv-based build commands and artifact paths. Listing commands and direct binary uploads need no Expo or native source tree. Bun runs the CLI; the app can use any build system.

sprid release metadata            # dry run: prints every field it would send
sprid release metadata --execute  # sends it
sprid release screenshots --asc   # only App Store Connect
sprid release graphics --execute  # Play feature graphic + icon

Install the commands with npm install -g @sprid/cli; these local tools require Bun. TS/JS configuration executes code, including during dry runs. Use trusted configs.

Config

Use release.config.ts at the repo root, or --config <file> for TS, JS, MJS or plain JSON. Relative credential and asset paths resolve beside that file. --locale en-US,sv selects exact store locale codes. Omit it to use the declared map. Only configured stores run by default; --asc / --play selects one. An iOS-only config can omit play, and a Play-only config can omit all Apple fields. listingLocales alone is sufficient. ascAppId can replace appId.

sprid release metadata --config ./store/listing.json --play --locale en-US
import { defineReleaseConfig } from "@sprid/release/config";

export default defineReleaseConfig({
  appId: "app.example.ios",       // independent iOS bundle id
  asc: { keyId: "ABC123", issuer: "00000000-…", keyPath: "./.keys/AuthKey_ABC123.p8" },
  play: { packageName: "app.example", keyPath: "./.keys/play-service-account.json" },
  listingLocales: { apple: { "en-US": "en", "en-GB": "en", sv: "sv" }, play: { "en-US": "en", "sv-SE": "sv" } },
  storeCopy: {
    en: { name: "…", subtitle: "…", keywords: "…", description: "…", promotionalText: "…" },
    sv: { name: "Example", description: "Localized app description" },
  },
  contact: { contactEmail: "[email protected]", contactWebsite: "https://example.com", defaultLanguage: "en-US" },
  playGraphics: { icon: './store/icon-512.png', featureGraphic: './store/{lang}/feature-1024x500.png' },
});

The Play icon is separate from the launcher icon inside the AAB. If playGraphics.icon is omitted, execution verifies existing icons (including default-language fallback) before changing graphics.

Credentials

Never pasted into an agent conversation. Resolved in this order:

| Store | 1 | 2 | |---|---|---| | App Store Connect | asc.keyPath (+ asc.keyId, asc.issuer) | $ASC_KEY_PATH, $ASC_KEY_ID, $ASC_ISSUER | | Google Play | play.keyPath | $GOOGLE_SERVICE_ACCOUNT_KEY_PATH |

A credentialsDir holding ios/AuthKey_<id>_ASC_API.p8 and android/google-service-account.json is also honoured, for teams that keep keys in one mounted folder outside the repo.

Validation and execution

Dry runs validate selected local copy and assets, print the payload, and return without credentials or store API calls. Remote permissions and editability are checked only on --execute.

  • Name 30, Apple subtitle 30, Apple keywords 100 characters. Keyword phrases may contain spaces (Apple guidance). Only the selected store's fields and locales are validated.
  • Locales are explicit. No localization is added automatically. To keep the old English mirroring behavior, set asc.englishUkFallback: true; an explicit en-GB map always wins. Existing configs already declaring en-GB need no change.
  • Apple metadata requires editable app information/version records. The command reports fields it cannot update. Screenshots replace the selected display type and any explicitly deprecated types. Missing local replacement files fail before deletion; a later upload failure can still leave a partial replacement.
  • Play listing updates preserve omitted fields and never rewrite release tracks. If Play rejects a draft app's edit, resolve its release state in your existing publishing pipeline before retrying.

Credentials compatibility

play.serviceAccountKeyPath remains an alias for play.keyPath. Conflicting paths are refused. ASC key id/issuer environment variables retain their existing precedence over the config; explicit key file paths take precedence over env paths.

With Sprid

Add --annotate alongside --execute to record the change in Sprid using your existing login or SPRID_PAT. Without --annotate, releases do not contact Sprid. Annotations are best effort. Store publishing works independently of Sprid.

Library use

import { pushAscMetadata, pushPlayMetadata, loadReleaseConfig } from "@sprid/release";

Listing push functions take { config, execute } and print their plan first.

Part of Sprid

This is one of the tools the free Sprid plugin drives (/sprid:store-metadata). It works on its own. https://sprid.studio/agents

© 2026 Väder AB. All rights reserved. Use is subject to Sprid's Terms of Service.

Build, upload and submit

sprid release ship                         # local plan, no changes
sprid release ship --execute --patch       # build, upload, submit
sprid release ship --execute --build-only  # signed local artifacts
sprid release ship --execute --android-only --no-bump
sprid release asc-upload --ipa ./app.ipa --execute
sprid release play-upload --aab ./app.aab --version 1.2.3 --execute
sprid release asc-submit --version 1.2.3 --build 8 --execute

ship needs configFile (version source), plus build.appDir and an explicit build.framework. Native iOS signing also needs appId, appleTeamId, build.xcodeName and signing credentials. Android can be configured alone. The built-in version reader supports Expo JSON, plain JSON with version, ios.buildNumber, android.versionCode, literal TS config, and split TS/JSON.

build.credentialsJson reads EAS-format signing files locally. Inner paths resolve beside that file (credentialsPathBase overrides). build.envFile: { path, keys } loads an explicit allowlist without printing values. requiredProdEnv rejects missing values and local URLs. Gradle memory settings change only with build.gradleJvmArgs.

For another toolchain, build.commands.ios or .android replaces that platform's native build and signing steps with { command: ['tool', 'arg'], artifact: 'path' }. Commands run in appDir; artifact paths resolve beside the release config. The command must produce a correctly signed IPA or AAB. Direct upload commands bypass all build/version assumptions.

Signing keys on EAS

Expo's EAS can hold the signing keys while this package does the building and submitting. credentials-push uploads your credentials.json (Android upload keystore, iOS distribution certificate, an App Store profile per target) to the EAS project; credentials-pull downloads them to ~/.sprid/eas-credentials/, owner-only. Set build.credentialsSource: 'eas' and ship pulls before every build, so no machine keeps its own copy. The project is eas.project (@owner/slug) or the Expo config's owner + slug; sign in with eas login or set EXPO_TOKEN. Both commands are dry runs without --execute, print fingerprints and ids only, and reuse anything EAS already holds byte for byte.

sprid release credentials-push --execute   # once, from your local credentials.json
sprid release credentials-pull --execute   # any machine, any time

--submit-only resumes an iOS build or uploads an existing AAB; asc-upload uploads an IPA. --internal targets internal testing. If Google blocks a draft app, Sprid saves the uploaded bundle as a draft on the requested track, finishes iOS, then exits with PlayConsoleRequiredError. Complete the first release in Play Console. finalizePlayRelease can resume an upload edit. Apple's first version skips the unavailable What's New field. Queued submissions are replaced only with --replace-submission. Store copy needs --push-store-copy; upload screenshots before submitting. Logs stay in .sprid-release/logs/.