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

@rightkit/app-update

v0.4.2

Published

Shared runtime update policy helper for Right Suite Tauri apps.

Readme

@rightkit/app-update

Runtime update-policy helper for Right Suite Tauri apps. It coordinates the app's updater check and install, classifies a release as patch or update from the manifest, treats only patches as eligible by default, auto-installs an eligible release only when shouldAutoInstall returns true (default: never, so the app calls installAvailable()), defers installs while the host's canInstall returns false, and reports status through callbacks.

It does not build, sign, publish or upload anything. @rightkit/release owns that lane. The package has no direct Tauri dependency. The app injects its updater check function, header loaders, eligibility policy and safe-to-install predicate.

| Item | Value | |---|---| | Where it runs | App webview UI (Tauri apps) | | Rust pair | None. No Rust crate in crates/ implements the updater. rightkit-device has no updater code. | | Version | see INDEX.md | | License | MIT OR Apache-2.0 |

Entry points

| Import | Contents | |---|---| | @rightkit/app-update | createAutoUpdateClient(config), fetchReleaseStatus(url, fetch?), updateTierFromManifest(rawJson), UPDATE_HOST_CONTRACT_VECTORS, createPersistedCheckCache(options); types PersistedCheckCache, PersistedCheckCacheOptions, PersistedCheckResult, CheckCacheStore, UpdateTier, AutoUpdateClient, AutoUpdateClientConfig, AutoUpdateStatus, ReleaseStatus, RuntimeUpdate, CheckForUpdate, UpdateHeaders, UpdateDownloadEvent, UpdateInstallOptions, UpdateHostContractVector | | @rightkit/app-update/contract-vectors | UPDATE_HOST_CONTRACT_VECTORS, UpdateHostContractVector, UpdateTier (the main entry re-exports them) | | @rightkit/app-update/react | UpdateOverlay, UpdateConsentCard (optional react peer; the root entry never imports React) | | @rightkit/app-update/native | createNativeUpdateClient(transport), NativeUpdateClientError, UPDATE_MESSAGES; types NativeUpdateClient, NativeUpdateTransport, UpdateCheckView, UpdateStatusView, UpdateProgress, UpdateDownloadResult, UpdateInstallResult, UpdateKind, UpdateRefusal, UpdateState, UpdateErrorCode, UpdateMessageCode, Unlisten. The renderer side of the native updater; see Native bridge. |

Peer dependencies: none. No runtime dependencies.

Example

import { createAutoUpdateClient, updateTierFromManifest } from "@rightkit/app-update";

const client = createAutoUpdateClient({
  check: (options) => check(options),        // the app's Tauri updater check
  getHeaders: () => ({ Authorization: `Bearer ${activationToken}` }),
  getInstallHeaders: async (tier) =>
    tier === "update" ? { Authorization: `Bearer ${await loadSignedEntitlement()}` } : undefined,
  onStatus: (status) => render(status),
});

const status = await client.checkOnce();
if (status.kind === "available") await client.installAvailable();

Status flow: checking, then available, then downloading, then ready. ready is emitted only after downloadAndInstall resolves. A failed install emits { kind: "error" } and never ready.

Opt-in additions

  • verifyMetadata(update, ctx) config hook: reject update metadata before it is offered. Tauri's updater plugin still verifies the artifact signature against the app's configured pubkey; this package performs no signature verification itself (delegated, by design).
  • relaunch + relaunchAfterInstall: relaunch after ready.
  • strictInstallHeaders (default on; false is the deprecated escape): without getInstallHeaders the artifact download gets no headers, so manifest-check credentials are never reused for it.
  • createBootProbation: boot-probation state machine; the host supplies storage. A version that does not acknowledge within maxBootAttempts boots yields { kind: "reinstall_required", failedVersion, fromVersion, guidance: "reinstall" } (and onBootFailure); the host shows reinstall guidance. Nothing is restored: no .previous copy is kept or restored, and previousInstallPath / PREVIOUS_SUFFIX / onRollback are deprecated and only help hosts clean a stale copy left by an older RightKit.
  • createPersistedCheckCache(options): an update-check cache persisted through a host CheckCacheStore (read/write text) with a last-known-good fallback; a record stamped more than maxFutureSkewMs (default 60000) in the future is distrusted, failures are never persisted, corrupt records are treated as absent, and a write failure is reported as persistError without failing the check.
  • createCheckGate: check cache and debounce. resolveChannel / validateChannels: channel endpoint selection. compareVersions / isNewerVersion: semver compare. assertSingleUpdatesVersion: duplicate-copy guard.
  • @rightkit/app-update/contract-vectors: test fixtures subpath (the main entry still re-exports them). Four vectors (free and pro, patch and feature update); every app adapter runs them.

GitHub Releases endpoint and the suite updater public key

A channel endpoint may be a GitHub Releases static manifest: validateChannels and resolveChannel accept any https URL, so a public GitHub app configures

const channels = { stable: { endpoints: ["https://github.com/<owner>/<repo>/releases/latest/download/latest.json"] } };

right-release publish-update with distribution.provider: "github-releases" uploads that latest.json (Tauri v2 static format) with the signed bundles; see the @rightkit/release README, "GitHub Releases updater lane". The URL resolves to the newest non-draft, non-prerelease release, so a prerelease channel needs its own endpoint.

There is one updater trust root for every RightKit app: the Right Suite updater key (key id 29395F9FF466261D), the same key sign-updater.mjs signs with for the R2 lane. An app does not provision its own. The app's tauri.conf.json carries the key's public half in plugins.updater.pubkey (the base64 text of the key's .pub file); copy the value from any shipped suite app, or from the .pub file beside the updater private key on the release host. Tauri's updater verifies each downloaded artifact against that value; this package does no signature verification itself. Set distribution.updaterKeyId: "29395F9FF466261D" in the release config and publish-update also refuses to publish a signature made by any other key.

Update overlay model and consent

deriveUpdateOverlay(status) maps an AutoUpdateStatus to a render-ready model (phase, bounded progress, reason, offered actions). An ineligible Pro update offers no download or install action. createUpdateConsent() is the per-action approval state: request('download'|'install'), allowOnce(run) (consumes the approval, exposes busy and error), deny(). Download and install are separate approvals. Signature and digest verification stay in the updater plugin and verifyMetadata; a failed run never proceeds to install.

Staged download and install

client.downloadAvailable() is the download step. It confirms the already-verified, eligible update and returns { ok: true, handle, status } with a staged status. Nothing is installed. client.installStaged(handle) is the install step; it accepts only the current handle, so a newer check invalidates it. client.installAvailable() runs both steps and keeps its previous status sequence.

The runtime adapter (Tauri updater) exposes only the combined downloadAndInstall, so the download step is a verify-only prefetch: it does not fetch the artifact bytes. The bytes are fetched during installStaged. Use createUpdateConsentRunner(client) as the allowOnce runner so the download approval runs only downloadAvailable and the install approval runs only installStaged.

Native bridge (@rightkit/app-update/native)

createNativeUpdateClient(transport) is the renderer's only view of a native updater. The transport is { invoke, listen } (Tauri's invoke and listen). It calls rightkit_update_check, rightkit_update_status, rightkit_update_download, rightkit_update_install and rightkit_update_cancel and listens to rightkit://update-progress, and returns only whitelisted DTO fields (UpdateCheckView, UpdateStatusView, ...) with closed enums and fixed message codes. UPDATE_MESSAGES maps each code to its text; its keys are exactly the UpdateMessage codes rightkit-tauri-shell sends (a test compares them with update.rs) and the text names no licence, key or account. The error codes are unconfigured, busy, unresolved, network, store, verify, forbidden, unsupported and unknown. No URL, header, token or path crosses the IPC boundary. A refusal or failed download or install is a normal result (state: "refused" | "failed" with a reason and message). A rejected command, a malformed reply or a handle id of the wrong shape throws NativeUpdateClientError with a closed code and fixed text, never the native error text. dispose() removes the progress listener, including one whose listen call has not resolved yet, and later calls throw unsupported. This client needs a host that registers those five commands: the rightkit-tauri-shell update feature does, and until an app builds with it there is nothing to call. The in-process client above (createAutoUpdateClient) is unchanged and does not use it.

React subpath

@rightkit/app-update/react exports UpdateOverlay and UpdateConsentCard, typed against UpdateOverlayModel and UpdateConsentState. react is an optional peer dependency; the root entry never imports React.

Known issues

  • getInstallHeaders is the place to put artifact credentials; set it explicitly (returning undefined for public patches). With the default strictInstallHeaders the download sends no headers when it is absent. Only strictInstallHeaders: false reuses the manifest-check headers, which can send a manifest credential to a different artifact origin; it is a deprecated compatibility escape.
  • UPDATE_HOST_CONTRACT_VECTORS is test data exported from the runtime entry. Within this repository only the package's own test uses it. Consumer tests import it too (npm audit 2026-10-08, updates finding 1).
  • @rightkit/tauri 0.2.0 in this tree declares @rightkit/app-update as a peer (^0.2.5, packages/tauri/package.json:21-23), not a pinned dependency; an older published @rightkit/tauri that pins 0.2.4 can still give a consumer two copies of this package (npm audit 2026-10-08).