# install-artifact-from-github

> A no-dependency micro helper for developers of binary Node addons. Three bins: `save-to-github-cache` uploads pre-built binary artifacts to a GitHub release from CI; `install-from-cache` downloads the right artifact at install time, optionally verifies its SHA-256 against a hash bag pinned in the addon's `package.json`, and falls back to building from sources on any failure; `hash-github-cache` generates that hash bag at release time. Zero dependencies, ESM, Node >= 18.

## Install

npm install --save install-artifact-from-github

## Quick start

In the addon's `package.json`:

```json
{
  "scripts": {
    "save-to-github": "save-to-github-cache --artifact build/Release/ABC.node",
    "install": "install-from-cache --artifact build/Release/ABC.node",
    "verify-build": "node scripts/verify-build.js",
    "rebuild": "node-gyp rebuild"
  }
}
```

`save-to-github` runs in GitHub Actions on a tag build. `install` runs on the user's machine: it tries to download `${prefix}${platform}-${arch}-${abi}${suffix}` (`.br`, then `.gz`, then uncompressed) from the matching GitHub release, verifies its SHA-256 against the `artifactHashes` bag if the addon ships one, runs `verify-build` (or `test`), and on any failure runs `rebuild`.

## install-from-cache flags

- `--artifact path` — where to write the downloaded artifact (required).
- `--prefix s` / `--suffix s` — artifact name decoration.
- `--host url` / `--host-var ENVVAR` (default `DOWNLOAD_HOST`) — mirror; a non-HTTP value is a local path.
- `--skip-path` / `--skip-path-var` (default `DOWNLOAD_SKIP_PATH`) — drop `/${owner}/${repo}/releases/download` from the URL (mirrors).
- `--skip-ver` / `--skip-ver-var` (default `DOWNLOAD_SKIP_VER`) — drop `/${version}` from the URL (mirrors).
- `--agent module-path` / `--agent-var ENVVAR` (default `DOWNLOAD_AGENT`) — module default-exporting an `http.Agent` (proxy support; consumer brings their own proxy package).
- `--napi level` / `--napi-var ENVVAR` (default `DOWNLOAD_NAPI`) — use `napi-v${level}` instead of the Node ABI in the asset name.
- `--force-build` / `--force-build-var ENVVAR` (default `DOWNLOAD_FORCE_BUILD`) — skip the download entirely and build from sources.

Integrity (since 1.7.0): if the addon's `package.json` carries an `artifactHashes` map, the decompressed download's SHA-256 must equal `artifactHashes["${platform}-${arch}-${abiSlot}"]` before it is written; a mismatch — or a slot the bag doesn't cover — falls through to the source build. Checked only when the resolved URL falls under the addon's own release location, `${host}/${owner}/${repo}/releases/download/` — `host` from `repository.url` when it is a full URL, else `https://github.com`; a `--host` / `DOWNLOAD_HOST` mirror resolving elsewhere — another host, or another path on the same host — is the deployer's own trust root and is never checked, while one resolving back onto that prefix still is. Zero new dependencies (`node:crypto`).

Env short-circuits: `DEVELOPMENT_SKIP_GETTING_ASSET` / a `.development` file / `DOWNLOAD_FORCE_BUILD` (or `--force-build`) force a source build; `DEVELOPMENT_SHOW_VERIFICATION_RESULTS` shows verification output. Cross-build overrides: `npm install <pkg> --platform=linux --platform-arch=x64 --platform-abi=108`.

## save-to-github-cache flags

- `--artifact path` — the file to upload (required).
- `--prefix s` / `--suffix s` — artifact name decoration (must match the install side).
- `--format list` — comma-separated `br`, `gz`, `none`; default `br`.
- `--napi level` / `--napi-var ENVVAR` — same N-API slot as the install side.

Requires GitHub Actions env (`GITHUB_REPOSITORY`, `GITHUB_REF`, `GITHUB_TOKEN`) or `PERSONAL_TOKEN` for manual runs.

## hash-github-cache flags (since 1.7.0)

Generates or checks the `artifactHashes` bag in a `package.json`, run at release time (e.g. from a `prepublishOnly` hook). The bag maps each `${platform}-${arch}-${abiSlot}` slot to `sha256:<hex>` of the decompressed `.node`.

- `--write` / `--check` — write the bag into `package.json`, or exit non-zero with a slot-level diff if it is stale/missing/wrong (exactly one required).
- `--from-release [tag]` — hash the assets of the GitHub release (default tag: the `package.json` version); the default source.
- `--from dir` — hash slot-named artifacts in a local directory instead.
- `--prefix s` / `--suffix s` — artifact name decoration (must match the install / save sides).
- `--package path` — the `package.json` to read/stamp (default `./package.json`).

Recommended wiring: `"prepublishOnly": "hash-github-cache --write"` so a plain `npm publish` stamps a fresh bag into the packed tarball. `--check` also serves as a post-publish tamper monitor (re-hash the live release against the published bag).

## npm 12 note (July 2026)

npm 12 disables dependency lifecycle scripts by default, and `install-from-cache` runs as the consumer's `install` script. End users must approve the consuming addon once: `npm approve-scripts <addon>` (writes a version-pinned `allowScripts` entry to their package.json; available since npm 11.16). Without approval neither the prebuilt download nor the `node-gyp` fallback runs.

## Documentation

Full docs: https://github.com/uhop/install-artifact-from-github/wiki
