Skip to content

zapstore/zsp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zsp

A fast CLI tool for publishing Android apps to Nostr relays. Used by Zapstore.

Features

  • APK acquisition from GitHub, GitLab, Codeberg, F-Droid, web pages, or local files
  • APK parsing to extract package info, version, certificate fingerprint, icon, and permissions
  • Metadata enrichment from GitHub, GitLab, F-Droid, or Google Play Store
  • Blossom uploads for icons, screenshots, APKs
  • Nostr event signing via private key, NIP-46 bunker, or browser extension (NIP-07)
  • Relay publishing of compliant software events

Installation

From Source

go install github.com/zapstore/zsp@latest

Pre-built Binaries

Download from releases.

Quick Start

zsp publish --wizard

The interactive wizard guides you through the setup process and helps determine the best options for your app.


APK Sources

zsp supports multiple sources for fetching APKs. The source type is auto-detected from URLs.

GitHub Releases

Fetches APKs from GitHub release assets. Automatically selects the best arm64-v8a APK.

repository: https://github.com/AeonBTC/mempal
zsp -r github.com/AeonBTC/mempal

GitLab Releases

Fetches APKs from GitLab release links.

repository: https://gitlab.com/AuroraOSS/AuroraStore

For self-hosted GitLab without "gitlab" in the domain:

release_source:
  url: https://git.mycompany.com/team/app
  type: gitlab

Codeberg / Gitea / Forgejo

Fetches APKs from Gitea-compatible forges.

repository: https://codeberg.org/Freeyourgadget/Gadgetbridge

F-Droid

Fetches APKs from F-Droid or IzzyOnDroid repositories.

# APKs from F-Droid, source code from GitHub
repository: https://github.com/AntennaPod/AntennaPod
release_source: https://f-droid.org/packages/de.danoeh.antennapod

Web Scraping

Fetch APKs from any web page using regex patterns.

repository: https://github.com/AntennaPod/AntennaPod
release_source:
  url: https://f-droid.org/packages/de.danoeh.antennapod/
  asset_url: https://f-droid\.org/repo/de\.danoeh\.antennapod_[0-9]+\.apk

Direct APK URL (no scraping):

release_source: https://example.com/downloads/app.apk

Local Files

Publish a local APK file.

release_source: ./build/outputs/apk/release/app-release.apk
repository: https://github.com/user/app
zsp app.apk -r github.com/user/app

Metadata Enrichment

zsp can fetch app metadata from external sources to enrich your publication.

Sources

Source Data Retrieved
github Name, description, topics, license, website, README
gitlab Name, description, topics, license
fdroid Name, summary, description, categories, icon, screenshots
playstore Name, description, icon, screenshots

Priority

When multiple sources are used, metadata is merged with this priority:

  1. YAML config (always wins)
  2. APK metadata (app label)
  3. Play Store
  4. Others

Usage

# CLI flags (can be repeated)
zsp -m github -m playstore

# Or in YAML
metadata_sources:
  - playstore
  - github

Configuration Reference

Minimal Config

repository: https://github.com/user/app

Full Config

# ═══════════════════════════════════════════════════════════════════
# SOURCE CONFIGURATION
# ═══════════════════════════════════════════════════════════════════

# Source code repository URL or NIP-34 naddr (for display in app store)
repository: https://github.com/user/app

# Where to fetch APKs (if different from repository)
# Can be URL string, local path, or object with type/asset_url for web scraping
# Local paths: ./build/app-release.apk, ../builds/*.apk
release_source: https://f-droid.org/packages/com.example.app

# Regex pattern to filter APK assets from releases
# (rarely needed - system auto-selects best arm64-v8a APK)
match: ".*arm64.*\\.apk$"

# ═══════════════════════════════════════════════════════════════════
# APP METADATA
# ═══════════════════════════════════════════════════════════════════

# App name (overrides APK label)
name: My App

# Short one-line description
summary: A wonderful app for doing things

# Full description (supports markdown)
description: |
  My App is a powerful tool that helps you accomplish your goals.
  
  Features:
  - Feature one
  - Feature two

# Category tags
tags:
  - productivity
  - tools
  - nostr

# SPDX license identifier
license: MIT

# App homepage
website: https://myapp.example.com

# ═══════════════════════════════════════════════════════════════════
# MEDIA
# ═══════════════════════════════════════════════════════════════════

# App icon (local path or URL, otherwise extracted from APK)
icon: ./assets/icon.png

# Screenshots (local paths or URLs)
images:
  - ./screenshots/screen1.png
  - https://example.com/screenshot2.png

# ═══════════════════════════════════════════════════════════════════
# RELEASE CONFIGURATION
# ═══════════════════════════════════════════════════════════════════

# Release notes file or URL (extracts section matching version if Keep a Changelog format)
release_notes: ./CHANGELOG.md

# Release channel: main (default), beta, nightly, dev
release_channel: main

# Git commit hash for reproducible builds
commit: abc123def456

# ═══════════════════════════════════════════════════════════════════
# NOSTR-SPECIFIC
# ═══════════════════════════════════════════════════════════════════

# Nostr NIPs supported by this app (for Nostr clients)
supported_nips:
  - "01"
  - "07"
  - "46"

# Minimum version users should update to
min_allowed_version: "1.0.0"
min_allowed_version_code: 100

# ═══════════════════════════════════════════════════════════════════
# VARIANTS
# ═══════════════════════════════════════════════════════════════════

# APK variant patterns (for apps with multiple builds)
variants:
  fdroid: ".*-fdroid-.*\\.apk$"
  google: ".*-google-.*\\.apk$"

# ═══════════════════════════════════════════════════════════════════
# METADATA SOURCES
# ═══════════════════════════════════════════════════════════════════

# External sources for metadata enrichment
# Note: metadata is fetched automatically for new releases (use --skip-metadata to disable)
metadata_sources:
  - playstore
  - fdroid

CLI Reference

Usage Patterns

zsp [config.yaml]              # Config file (default: ./zapstore.yaml)
zsp <app.apk> [-r <repo>]      # Local APK with optional source repo
zsp -r <repo>                  # Fetch latest release from repo
zsp apk --extract <app.apk>    # Extract APK metadata as JSON
zsp                            # Interactive wizard
zsp --wizard                   # Wizard with existing config as defaults

Flags

Flag Description
-r <url> Source code repository URL (GitHub/GitLab/Codeberg). Also fetches releases from here unless -s is specified.
-s <url> Release/download source URL (F-Droid, web page, etc). Use alone for closed-source apps.
-m <source> Fetch metadata from source (repeatable). Fetched automatically for new releases.
-y Auto-confirm all prompts
-n, --dry-run Parse & build events without publishing
-h, --help Show help
-v, --version Print version
Flag Description
--wizard Run interactive wizard (recommended for first-time setup)
--match <pattern> Regex pattern to filter APK assets (rarely needed - system auto-selects best APK)
--commit <hash> Git commit hash for reproducible builds
--check Verify config fetches arm64-v8a APK (exit 0=success)
--skip-preview Skip the browser preview prompt
--port <port> Custom port for browser preview/signing
--overwrite-release Bypass cache, re-publish unchanged release
--skip-metadata Skip fetching metadata from external sources (useful for frequent releases)
--quiet Minimal output, no prompts (implies -y)
--verbose Debug output
--no-color Disable colored output

Environment Variables

Variable Required Description
SIGN_WITH Yes Signing method (see below)
GITHUB_TOKEN No GitHub API token (avoids rate limits)
RELAY_URLS No Comma-separated relay URLs
BLOSSOM_URL No Custom Blossom CDN server

Defaults

  • RELAY_URLS: wss://relay.zapstore.dev
  • BLOSSOM_URL: https://cdn.zapstore.dev

Signing Methods

Private Key (nsec)

Direct signing with a Nostr private key.

SIGN_WITH=nsec1... zsp zapstore.yaml

⚠️ Security: Private keys in environment variables can be exposed via /proc/*/environ on Linux or shell history. For production, prefer bunker or browser signing.

Hex Private Key

64-character hex private key (converted to nsec internally).

SIGN_WITH=0123456789abcdef... zsp zapstore.yaml

Public Key (npub) - Unsigned Output

Output unsigned events for external signing workflows.

SIGN_WITH=npub1... zsp zapstore.yaml > unsigned-events.json

NIP-46 Bunker (Remote Signing)

Sign via a remote signer like nsecBunker.

SIGN_WITH="bunker://pubkey?relay=wss://relay.example.com&secret=..." zsp

Browser Extension (NIP-07)

Sign using your browser's Nostr extension (Alby, nos2x, Flamingo, etc.).

SIGN_WITH=browser zsp

This opens a browser window where you approve signing. Supports batch signing for efficiency.


Nostr Events

zsp publishes three NIP-82 compliant event types:

Kind 32267 - Software Application

App metadata (name, description, icon, screenshots, platforms).

{
  "kind": 32267,
  "tags": [
    ["d", "com.example.app"],
    ["name", "My App"],
    ["summary", "A wonderful app"],
    ["icon", "https://cdn.zapstore.dev/abc123..."],
    ["image", "https://cdn.zapstore.dev/def456..."],
    ["t", "productivity"],
    ["f", "android-arm64-v8a"],
    ["license", "MIT"],
    ["repository", "https://github.com/user/app"]
  ],
  "content": "Full app description..."
}

Kind 30063 - Software Release

Version information and references to assets.

{
  "kind": 30063,
  "tags": [
    ["d", "com.example.app@1.2.3"],
    ["i", "com.example.app"],
    ["version", "1.2.3"],
    ["c", "main"],
    ["e", "<asset-event-id>", "wss://relay.zapstore.dev"]
  ],
  "content": "Release notes..."
}

Kind 3063 - Software Asset

Binary metadata (hash, size, certificate, URLs).

{
  "kind": 3063,
  "tags": [
    ["i", "com.example.app"],
    ["x", "sha256hash..."],
    ["version", "1.2.3"],
    ["version_code", "123"],
    ["url", "https://github.com/.../app.apk"],
    ["m", "application/vnd.android.package-archive"],
    ["size", "12345678"],
    ["f", "android-arm64-v8a"],
    ["apk_certificate_hash", "certsha256..."],
    ["min_platform_version", "21"],
    ["target_platform_version", "34"]
  ]
}

APK Selection

When a release contains multiple APKs, zsp uses smart ranking to select the best one:

  1. Architecture filtering: Removes x86, x86_64, armeabi-v7a (prefers arm64-v8a)
  2. Pattern matching: Applies match regex if configured
  3. ML-based ranking: Scores APKs by filename patterns (universal, arm64, etc.)
  4. Interactive selection: In interactive mode, presents ranked options

Match Patterns

# Only mainnet builds
match: ".*-mainnet\\.apk$"

# Only arm64 builds  
match: ".*arm64.*\\.apk$"

# Exclude debug builds
match: "^(?!.*debug).*\\.apk$"

CI/CD Integration

GitHub Actions

- name: Publish to Zapstore
  env:
    SIGN_WITH: ${{ secrets.NOSTR_NSEC }}
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    zsp -y zapstore.yaml

Check Mode

Verify your config fetches a valid APK without publishing:

zsp publish --check zapstore.yaml
# Exit 0 = success, prints package ID
# Exit 1 = failure

Dry Run

Build events without publishing:

zsp --dry-run zapstore.yaml

Advanced Examples

F-Droid APK with Play Store Metadata

repository: https://github.com/AntennaPod/AntennaPod
release_source: https://f-droid.org/packages/de.danoeh.antennapod
metadata_sources:
  - playstore

Multi-variant App (e.g., F-Droid + Google Play builds)

repository: https://github.com/niccokunzmann/mundraub-android
match: ".*-fdroid-.*\\.apk$"
variants:
  fdroid: ".*-fdroid-.*\\.apk$"
  google: ".*-google-.*\\.apk$"

Self-hosted GitLab

release_source:
  url: https://git.mycompany.com/mobile/app
  type: gitlab

Web Page with Dynamic APK URL

release_source:
  url: https://example.com/downloads
  asset_url: https://cdn\.example\.com/releases/app-v[0-9.]+\.apk

Reproducible Build with Commit Hash

repository: https://github.com/AeonBTC/mempal
commit: a1b2c3d4e5f6

Or via CLI:

zsp --commit a1b2c3d4e5f6 zapstore.yaml

NIP-34 Repository Reference

repository: naddr1qqxnzd3exsmnjd3exqunjv...

Extract APK Metadata

zsp apk --extract app.apk

Outputs JSON with package ID, version, certificate hash, architectures, permissions, and extracts icon to disk.


License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages