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

@openota/native-android

v0.2.0

Published

OpenOTA Runtime Engine — Android native module (BundleManager, verification, staging, activation, rollback)

Readme

@openota/native-android

Android native runtime module for OpenOTA — bundle staging, verification, activation, and rollback, exposed to JS as the OpenOTA TurboModule.

This package contains no JS API of its own — it's a native-only companion to @openota/sdk, which provides the TypeScript API and the TurboModule spec that this module's Kotlin implementation satisfies. Install both together; React Native's autolinking picks up this package's native Android sources automatically.

Install

npm install @openota/sdk @openota/native-android

No further setup is required beyond a standard React Native New Architecture (TurboModules) build — the module is autolinked via its codegenConfig in package.json.

Required integration: OpenOTAReactHost + runtimeVersion

Your MainApplication.kt (or MainApplication.java) must build its reactHost with OpenOTAReactHost.create(), not React Native's own getDefaultReactHost(), and pass an explicit runtimeVersion. Both are non-optional:

  • Skipping the explicit runtimeVersion makes OTA updates fail native verification with INVALID_RUNTIME (see below).
  • Using getDefaultReactHost() directly — even with jsBundleFilePath = BundleLoader.getJSBundleFile(...) — resolves the active bundle exactly once, when the ReactHost is first constructed at process start. After that, ReactHost.reload() (what RestartManager calls post-activation) replays that same stale resolution instead of picking up the bundle that was just activated or rolled back. OpenOTAReactHost.create() wraps the same bridgeless ReactHost machinery but re-resolves BundleLoader.getJSBundleFile() on every reload, so activation and rollback actually take effect.
import com.openota.runtime.OpenOTAReactHost

// Must exactly match "runtimeVersion" in this app's openota.config.json.
private const val OPENOTA_RUNTIME_VERSION = "1.0.0"

class MainApplication : Application(), ReactApplication {
  override val reactHost: ReactHost by lazy {
    OpenOTAReactHost.create(
      context = applicationContext,
      packageList = PackageList(this).packages,
      runtimeVersion = OPENOTA_RUNTIME_VERSION,
    )
  }
  // ...
}

runtimeVersion vs. version vs. package.json's version vs. Android versionName

These are four different, independent concepts. None of them controls any of the others:

| Concept | Example | Meaning | |---|---|---| | OTA release version | 1.0.4 | Identifies which OTA bundle this is (openota release --version 1.0.4). Changes on every release. | | runtimeVersion | 1.0.0 | Native binary compatibility generation. An OTA bundle is only served to devices whose native runtime reports this exact value. Must be valid semver (^\d+\.\d+\.\d+$) — the OpenOTA server rejects anything else. Stays the same across many OTA releases; only bump it when a native dependency or native API changes in a way that makes older JS bundles unsafe to run against the new binary. | | package.json version | 0.0.1 | npm package metadata. Has no relationship to either of the above and must never be used to derive runtimeVersion — that was the root cause of a real production bug (see the CLI's manifest.service.ts history). | | Android versionName | 1.0 | The APK's own display version. Not required to be valid semver (Android accepts any string), so it may not even be usable as a runtimeVersion suggestion as-is — openota init only auto-suggests it when it already happens to match X.Y.Z. |

Example compatibility matrix for an app whose native binary is runtimeVersion = "1.0.0":

1.0.1 → runtimeVersion 1.0.0   ✓ compatible
1.0.2 → runtimeVersion 1.0.0   ✓ compatible
1.0.3 → runtimeVersion 1.0.0   ✓ compatible
1.0.4 → runtimeVersion 1.0.0   ✓ compatible
2.0.0 → runtimeVersion 2.0.0   ✗ rejected by this app (and 1.0.0-generation bundles are rejected by a 2.0.0 app)

If you ship a new APK with a breaking native change, bump OPENOTA_RUNTIME_VERSION (and the corresponding openota.config.json) to "2.0.0". BundleVerifier will then correctly refuse to activate 1.0.0-generation bundles on 2.0.0 devices, and vice versa — this is enforced natively, independent of the JS SDK.

Why this can't be automatic

openota.config.json is a JavaScript/CLI-side file — there is no reliable, safe way for Kotlin code to read it directly from a developer's machine or from inside a release APK. The native runtime has no way to derive the correct runtimeVersion on its own (Android's versionName is a plausible-looking but incorrect proxy — they're different concepts that happen to look similar). The one correct mechanism is the explicit parameter BundleLoader.getJSBundleFile(context, runtimeVersion) already supports; pick one value, put it in both places, and keep them in sync deliberately.

License

MIT