boltZharp Docs
terminalSDKs

Zharp CLI

@zharp/cli uploads what Zharp needs to make stack traces readable — JavaScript source maps, Android mappings, Flutter Dart symbols and iOS dSYMs.

Most builds don't need it directly: the JavaScript bundler plugins and the Android Gradle plugin do the same during the build. Use the CLI for other bundlers, Flutter, iOS, or a CI step of your own. See Readable stack traces for how it fits together.

Install

npm install --save-dev @zharp/cli    # or run it with npx @zharp/cli …

Requires Node 18.18 or later; no dependencies. The command is zharp; zharp --help lists the commands and --version prints the version.

Environment variables

VariableInstead ofNotes
ZHARP_AUTH_TOKEN—Required to upload. A workspace API key with the artifacts:write scope — a CI secret, not the app key. See The upload key.
ZHARP_APP--appThe application ID: the number in the app's dashboard URL.
ZHARP_RELEASE--releaseA release name, for filtering. Matching is by debug ID.
ZHARP_URL—The Zharp API. Default https://api.zharp.io.

Commands

sourcemaps inject <dir>

Gives every .js, .mjs and .cjs file that has a source map a debug ID: appended to the file (a line that registers it for the Zharp SDKs, and //# debugId=<uuid>) and written into the map. Lines are only added after the code, so the map stays valid. The ID comes from the file's content, so running it twice changes nothing, and a file that already has a //# debugId= keeps it.

sourcemaps upload <dir>

Uploads each injected file and its map. Run it after inject, on the files you deploy:

zharp sourcemaps inject dist
zharp sourcemaps upload dist --app 42 --release "$GIT_SHA" --delete-after
FlagWhat it does
--app <id>The application. Required unless ZHARP_APP is set.
--release <name>Files the upload under a release.
--delete-afterDeletes the .map files once uploaded, so your source isn't deployed.
--include <glob> / --exclude <glob>Repeatable, relative to the directory.
--dry-runShows what would happen; changes and sends nothing. Works on every command.
--url <url>The Zharp API, on any command (or ZHARP_URL).

Keep sourcesContent in your maps (most bundlers do by default) and Zharp shows the code around each frame.

proguard upload <mapping.txt>

zharp proguard upload app/build/outputs/mapping/release/mapping.txt --app 42 --uuid <build-uuid>

--uuid is the build's UUID that the Gradle plugin writes into the app and prints. The plugin normally uploads for you; use this with uploadMappings = false.

dart-symbols upload <dir>

flutter build apk --obfuscate --split-debug-info=build/symbols   --extra-gen-snapshot-options=--save-obfuscation-map=build/obfuscation.json
zharp dart-symbols upload build/symbols --app 42

Each *.symbols file is uploaded under its build ID — the build_id an obfuscated Dart stack prints — with its architecture. An obfuscation map (obfuscation.json or *.obfuscation.json in or next to the folder) is found and uploaded once per build, so class and method names in error types and messages are restored too; --obfuscation-map <file> points at another one.

dsym upload <path>

zharp dsym upload "$DWARF_DSYM_FOLDER_PATH" --app 42

A .dSYM or a folder of them. Each architecture is uploaded under its Mach-O UUID. For an Xcode build phase, see iOS.

Behaviour

  • Native symbol files are uploaded gzipped; up to 200 MB a file. Uploading the same file for the same build again replaces it.
  • Network errors, 408, 429 and 5xx are retried three times with backoff. A rejected key, a missing scope or an unknown app fails at once with what to fix.
  • Exit code 1 on any error.

As a library

import { injectDirectory, uploadSourcemaps, resolveConnection } from "@zharp/cli";

injectDirectory("dist");
await uploadSourcemaps("dist", resolveConnection({ app: 42 }), { release: "web@1.4.0", deleteAfter: true });