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

@otakit/capacitor-updater

v2.1.2

Published

Capacitor plugin for OTA updates

Readme

@otakit/capacitor-updater

Capacitor OTA updater plugin for OtaKit.

What it does

  • fetches the latest manifest for its release lane from the CDN
  • downloads and verifies OTA bundles
  • stages updates safely
  • applies staged bundles on cold start, resume, or manual command
  • uses notifyAppReady() as the health handshake
  • rolls back automatically if a newly applied bundle does not prove healthy

The plugin is intentionally small:

  • three automatic lifecycle entry points: runtime, launch, resume
  • one shared set of update primitives: check, download, apply
  • one rollback safety loop

There is no built-in splash or overlay manager in this model.

Hosted config

plugins: {
  OtaKit: {
    appId: "YOUR_OTAKIT_APP_ID",
    appReadyTimeout: 10000,

    // Optional:
    // channel: "staging",
    // runtimeVersion: "2026.04",
    // launchPolicy: "apply-staged",
    // resumePolicy: "shadow",
    // runtimePolicy: "immediate",
    // checkInterval: 600000,
  }
}

Advanced overrides for self-hosting or custom trust only:

  • cdnUrl
  • ingestUrl
  • serverUrl
  • manifestKeys
  • allowInsecureUrls

Hosted OtaKit already points at the managed ingest service and CDN and already trusts the managed manifest signing keys.

Policies

The plugin has three automatic events:

  • runtime Cold start where the current runtimeVersion lane has not been resolved yet.
  • launch Normal cold start after runtime is already resolved.
  • resume App returning from background.

Each event uses the same policy names:

type OtaKitPolicy = 'off' | 'shadow' | 'apply-staged' | 'immediate';

Semantics:

  • shadow check + download, never apply on that event
  • apply-staged apply a staged bundle if one already exists, otherwise behave like shadow
  • immediate check + download + apply

Recommended defaults:

launchPolicy = 'apply-staged';
resumePolicy = 'shadow';
runtimePolicy = 'immediate';

That means:

  • fresh install or new runtimeVersion: catch up immediately
  • later cold starts: apply already staged content if present, otherwise download the next update in the background
  • resumes: periodically check and stage in the background

If an app wants full JS control:

launchPolicy = 'off';
resumePolicy = 'off';
runtimePolicy = 'off';

Check interval

checkInterval defaults to 10 minutes and only applies to background resume checks:

  • resumePolicy: "shadow"
  • resumePolicy: "apply-staged" when there is no staged bundle to apply

Set checkInterval to 0 or a negative value to disable resume throttling.

It does not throttle:

  • launch handling
  • runtime handling
  • immediate
  • manual JS APIs

Runtime model

The plugin keeps three important pointers:

  • current the bundle the WebView is serving now
  • fallback the last known-good bundle used for rollback
  • staged a downloaded bundle waiting to be activated

Bundle lifecycle:

download -> pending -> trial -> success
                        |
                        +-> error -> rollback

If a bundle is applied and never calls notifyAppReady():

  • timeout triggers rollback while the app is running
  • or the next cold start detects the still-trial bundle and rolls back before boot continues

The last failed applied bundle is persisted so the plugin does not immediately download and apply the same broken release again.

Automatic flow

For the normal hosted path, most apps only need:

await OtaKit.notifyAppReady();

The plugin handles checking, staging, applying, rollback, and runtime-lane catch-up based on the configured policies.

Loading screen recommendation

OtaKit does not manage a splash screen or loading overlay for you.

Recommended startup order:

  1. keep a native splash screen or fullscreen loading view visible
  2. finish your normal app bootstrap
  3. call notifyAppReady()
  4. hide the splash screen or loading view

For React and Next.js apps, treat this as part of the default setup, not an optional polish step.

Manual APIs

The manual surface maps to the same internal engine:

const state = await OtaKit.getState();
const check = await OtaKit.check();
const download = await OtaKit.download();
await OtaKit.notifyAppReady();

check() returns:

type CheckResult =
  | { kind: 'no_update' }
  | { kind: 'already_staged'; latest: LatestVersion }
  | { kind: 'update_available'; latest: LatestVersion };

download() returns:

type DownloadResult = { kind: 'no_update' } | { kind: 'staged'; bundle: BundleInfo };

update() uses the same native immediate-flow operation as automatic "immediate" policies:

await OtaKit.update();

That keeps the manual convenience path atomic inside the native plugin instead of splitting it into separate download() and apply() calls.

apply() and successful update() are terminal operations:

  • on success they reload the WebView
  • they do not resolve back into the old JS context
  • call notifyAppReady() from normal startup after the reloaded app boots

There is no listener/event API in this refactor. If an app later needs a smaller reactive surface, that can be added intentionally.

Example manual flow

const check = await OtaKit.check();

if (check.kind === 'update_available') {
  const result = await OtaKit.download();
  if (result.kind === 'staged') {
    await OtaKit.apply();
  }
}

Or use the one-shot helper:

await OtaKit.update();

After the app reloads and starts again, call:

await OtaKit.notifyAppReady();

Compatibility lanes

  • channel answers "who should get this rollout?"
  • runtimeVersion answers "which native app shell can safely run this bundle?"

Use channels for rollout tracks such as beta, staging, or production.

Use runtimeVersion when a new store build creates a new compatibility boundary and you do not want devices on that native shell to keep receiving older OTA bundles.

Trust model

The plugin does not just download arbitrary zips from a URL.

  1. it fetches the latest manifest for the current app + channel + runtime lane
  2. it verifies the manifest signature when keys are configured
  3. it compares the manifest with current, staged, and last-failed local state
  4. it downloads only when a newer usable bundle exists
  5. it verifies the zip against the manifest sha256
  6. it stages and later applies the bundle

Source areas

  • src/definitions.ts: public types and config
  • src/index.ts: Capacitor registration and JS wrapper
  • src/web.ts: web fallback implementation
  • ios/Sources/UpdaterPlugin/*: iOS implementation
  • android/src/main/java/com/otakit/updater/*: Android implementation