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

@codemagic/capacitor-patch

v0.1.0

Published

Capacitor client SDK for Codemagic Patch — over-the-air web-asset updates for Capacitor, Ionic and Cordova-on-Capacitor apps.

Readme

@codemagic/capacitor-patch

Capacitor client SDK for Codemagic Patch — over-the-air web-asset updates for Capacitor, Ionic and Cordova-on-Capacitor apps.

This package is only the on-device side. You also need a Patch server (self-hosted) and the cmpatch-capacitor CLI, which sets up apps and deployments, publishes releases and operates them — the monorepo has both, plus a dashboard and a local evaluation stack. The React Native counterpart of this SDK is @codemagic/react-native-patch.

Status: 0.x. The package is on npm, but its API may still change between minor versions. See Installation.

Why this exists

Codemagic Patch's server, CLI and delivery protocol are framework-agnostic by design — PROTOCOL.md states plainly that "the server and client treat the payload as an opaque directory tree." A Capacitor payload is exactly that: a directory of web assets.

Capacitor also happens to be the easiest OTA target of any framework. @capacitor/core ships the entire install mechanism (WebView.setServerBasePath, getServerBasePath, persistServerBasePath), so applying an update means pointing the WebView at a directory. There is no bundler to integrate, no bytecode, and no New Architecture matrix.

How it relates to the rest of Patch

  • Same server. The server needs no Capacitor-specific changes; this client speaks the published protocol against an unmodified deployment, and the dashboard shows a Capacitor app like any other.
  • Its own CLI. cmpatch-capacitor covers OTA operation from the command line — sign-in, apps, deployments, releases, promotion, rollback, metrics — and publishes the built web assets as they are, without analysing a native project. It computes no native fingerprint, so the native app version is what scopes a release — read its note on that before your first release.
  • Same protocol. No new manifest format, no new hashing scheme, no new wire contract. The delivery-protocol layer (src/protocol/) is a port of the React Native client's, and the native hashing, archive extraction and delta patching come from the same C libraries the React Native client vendors.
  • Not a CodePush plugin. This targets the Patch protocol, not the retired CodePush one.

What you get

  • Binary patches when available, for smaller downloads (falls back once to a full bundle on any patch failure or hash mismatch)
  • Signature verification when you configure a public key (RS256, skipped rather than silently passed when no key is configured)
  • Automatic crash-loop rollback if a new package fails before the app reports ready, after a configurable number of launches (maxLaunchAttempts, default 3)
  • Configuration via capacitor.config.ts, with a native-resource override for CI
  • A one-call start() that checks on launch and, optionally, on every return to the foreground; CodePush-style sync(); or step-by-step APIs when you need control
  • All four install modes: on next restart, immediately, on next resume, or while in the background

Requirements

  • Capacitor 7.0.0 or 8.x — see Support policy below
  • Android minSdkVersion 24+
  • Android native build with CMake/NDK support (for the vendored C — package hashing, archive extraction, delta patching)
  • iOS native build with either Swift Package Manager or CocoaPods, and mixed Swift/Objective-C++ compilation

Support policy

The two most recent Capacitor majors are supported; the oldest is dropped once a new major ships (currently 7 and 8 — CI runs the full suite against both). This tracks Capacitor's own release cadence rather than a fixed calendar window.

Installation

npm install @codemagic/capacitor-patch
npx cap sync

To try an unreleased build instead, build it from a clone of this repository and install it by path:

# in your clone of this repository
corepack enable && yarn install
yarn workspace @codemagic/capacitor-patch build

# in your Capacitor app
npm install /path/to/codemagic-patch/client-capacitor
npx cap sync

cap sync copies the plugin into both native projects and regenerates their dependency manifests (CocoaPods Podfile/SPM package list on iOS, Gradle module list on Android) — no separate pod install step, unlike a bare React Native install.

Quick start

Configuration lives in capacitor.config.ts, one block per platform:

// capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'Example',
  webDir: 'www',
  plugins: {
    CodemagicPatch: {
      ios: {
        deploymentKey: '<ios-deployment-key>',
        apiUrl: 'https://updates.example.com',
        downloadBaseUrl: 'https://storage.example.com/codemagic-patch',
        // publicKey: '-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----',
      },
      android: {
        deploymentKey: '<android-deployment-key>',
        apiUrl: 'https://updates.example.com',
        downloadBaseUrl: 'https://storage.example.com/codemagic-patch',
        // publicKey: '-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----',
      },
    },
  },
};

export default config;

Then run npx cap sync so both native projects pick up the change. See Configuration for where each value comes from and what each one means.

Call start() once your app has rendered its first screen:

import { CheckFrequency, start } from '@codemagic/capacitor-patch';

start({ checkFrequency: CheckFrequency.ON_APP_RESUME });

start() checks for an update, downloads and installs it when appropriate, and reports the running bundle as healthy so a bad package can roll back. With CheckFrequency.ON_APP_RESUME it checks again each time the app returns to the foreground; the default, ON_APP_START, checks once. It is this SDK's counterpart of the React Native SDK's Patch.wrap(App), and takes the same options. It never throws, and resolves to the first check's status ('up-to-date', 'update-installed', 'embedded-revert-applied', 'sync-in-progress' or 'error').

Call it after the first screen renders, not earlier in bootstrap. Starting is what marks the running bundle as healthy. If your app crashes before that point, the update is rolled back after maxLaunchAttempts launches; if you call start() before your UI has actually come up, a crash after that point no longer counts. See Usage for the step-by-step APIs when you need more control.

Configuration

| Key | Required | Meaning | | --- | --- | --- | | deploymentKey | yes | Deployment key for this app/platform/track. Use a separate key per platform — the manifest path carries no platform segment, so a shared key lets releases overwrite each other | | apiUrl | yes | API server origin (the server's SERVER_URL), e.g. https://updates.example.com. The SDK appends /v1/... | | downloadBaseUrl | yes | Artifact origin (the server's PUBLIC_BASE_URL), e.g. https://storage.example.com/codemagic-patch. May include a bucket/path prefix; the SDK appends manifest/artifact paths | | publicKey | no | PEM public key (SPKI, -----BEGIN PUBLIC KEY-----); required only when enforcing client-side signature verification | | maxLaunchAttempts | no | How many consecutive launches a newly installed update may boot without notifyAppReady() before it is rolled back as a crash. Positive integer, default 3. An invalid value logs a warning and uses the default rather than blocking boot |

Each platform block is independent — configure at least one, and every block you provide needs deploymentKey, apiUrl, and downloadBaseUrl (publicKey and maxLaunchAttempts are optional). Where the values come from: the deployment key is the DEPLOYMENT KEY column of cmpatch-capacitor deployment list --app <app-name> (or the deployment's page in the dashboard); the API URL and download base URL are printed by the self-host installer when the server is set up.

Native resource override. For teams injecting per-environment values in CI without rewriting capacitor.config.ts, the same values can be set as native resources instead — CodemagicPatchDeploymentKey/CodemagicPatchApiUrl/ CodemagicPatchDownloadBaseUrl/CodemagicPatchPublicKey/ CodemagicPatchMaxLaunchAttempts in Android strings.xml or iOS Info.plist (the same names the React Native SDK reads). Precedence: native resource > capacitor.config.ts.

Catching config mistakes before they ship: run npx codemagic-patch-check-config path/to/capacitor.config.json in CI. It fails if both platform blocks resolve to the same deploymentKey (the exact mistake the protocol cautions against), or if a maxLaunchAttempts is not a positive integer, which the app itself would only warn about at runtime. It reads JSON only: with a capacitor.config.ts, run it after npx cap sync and point it at the resolved copy that writes, such as android/app/src/main/assets/capacitor.config.json.

Usage

The simplest integration is start() (see Quick start). Underneath it is sync(), which checks for an update, downloads it, installs it and reports app readiness in one call; call it yourself to check at moments of your own choosing (start() can still run alongside, and overlapping calls resolve to 'sync-in-progress' rather than a second update cycle). Neither throws; both resolve to a status string.

For finer control, drive the steps yourself and call notifyAppReady() once the app has started successfully (so the update is not rolled back):

import {
  checkForUpdate,
  downloadUpdate,
  installUpdate,
  notifyAppReady,
} from '@codemagic/capacitor-patch';

await notifyAppReady();

const check = await checkForUpdate();
if (check.action === 'ota-update') {
  const localPackage = await downloadUpdate(check.remotePackage);
  await installUpdate(localPackage); // defaults to ON_NEXT_RESTART
}

To choose when an installed update takes effect, pass an InstallMode to start(), sync() or installUpdate(). It is exported as a value as well as a type, matching the React Native SDK. Plain strings ('IMMEDIATE') still type-check:

import { InstallMode, start } from '@codemagic/capacitor-patch';

start({ installMode: InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 60_000 });

| InstallMode | The update takes effect… | | --- | --- | | ON_NEXT_RESTART (default) | on the next cold start | | IMMEDIATE (default for mandatory updates) | right away, by reloading the WebView | | ON_NEXT_RESUME | when the app next returns to the foreground | | ON_NEXT_SUSPEND | while the app is in the background |

For the last two, minimumBackgroundDuration (milliseconds) sets how long the app must have been in the background first. Without it, a brief interruption counts: on iOS, pulling down Notification Centre briefly takes the app out of the foreground too. Mandatory updates use mandatoryInstallMode instead of installMode. Foreground and background transitions come from the plugin's own native lifecycle events, so no other plugin is needed.

getRunningBundleUpdateMetadata() reports the running OTA release ({ label, packageHash, releaseNotes }, or null on the embedded bundle). isNextVersionReady() answers a different question — whether a different package is already installed and waiting for the next reload, so you can show an "Update ready" prompt without confusing it with what's currently running:

import { isNextVersionReady, restartApp } from '@codemagic/capacitor-patch';

if (await isNextVersionReady()) {
  // show your own "Update ready — restart now?" prompt, then:
  await restartApp();
}

restartApp, allowRestart/disallowRestart, and hydrate are also exported for controlling reload timing. See src/definitions.ts and src/protocol/types.ts for the full API surface.

Example app

example-app/ is an Ionic + Angular reference app wired to this plugin by path. It exercises the whole cycle on a device or simulator — check, download, install, restart, and crash rollback — and is the quickest way to see the SDK working against your own Patch server.

Documentation

| Document | What it covers | | --- | --- | | Root README | Running and self-hosting the Patch server, the dashboard, the local evaluation stack | | cmpatch-capacitor | The CLI: signing in, apps and deployment keys, publishing and operating releases, and what the target binary version has to guarantee | | PROTOCOL.md | The client ↔ server delivery contract this SDK implements | | Migrating from Appflow Live Updates | Maps Appflow channels, config, and the JS API onto their Codemagic Patch equivalents | | example-app/ | Running the reference app against a Patch server | | src/protocol/ | How the delivery-protocol layer maps onto the React Native client's sources |

Licence

Apache-2.0 — see LICENSE. This matches the React Native client SDK and the CLI; only server/ carries the Codemagic Server License, and this package does not depend on it.

Vendored third-party code keeps its own licence and attribution — see NOTICE.