{"_id":"@deploy-your-app/capacitor-update-manager","_rev":"7-c80f1116d5180b1c46220d69d80daebd","name":"@deploy-your-app/capacitor-update-manager","dist-tags":{"latest":"0.5.1"},"versions":{"0.2.0":{"name":"@deploy-your-app/capacitor-update-manager","version":"0.2.0","keywords":["capacitor","plugin","live-update","ota","deploy-your-app"],"author":{"name":"DeployYourApp"},"license":"MIT","_id":"@deploy-your-app/capacitor-update-manager@0.2.0","maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"homepage":"https://deployyour.app","bugs":{"email":"info@deployyour.app"},"dist":{"shasum":"aeb68e34d0d6be3127875c5f9904915fd50e59ef","tarball":"https://registry.npmjs.org/@deploy-your-app/capacitor-update-manager/-/capacitor-update-manager-0.2.0.tgz","fileCount":25,"integrity":"sha512-rgjWa7NakThKL1N2/4Vcjs5YgvHrmOZvln5mQ8VbsoHHeTtfrpewdkpwV6JJV3U50ObHjDlD+kVl61Pna5Juyw==","signatures":[{"sig":"MEUCIEolV49j67Frkj0daHNnPYUpEEEG7nBHA+9p9KP2JoryAiEAye5n2Cy9Ah9kimeKpTPv9oCdtuTIWXNcZ03fSWoDVYA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":285184},"main":"./dist/index.js","type":"module","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js"}},"gitHead":"ae6b2b645f83defd9a19f33b557879c8fbf647c3","scripts":{"build":"node build.js","prepublishOnly":"node build.js"},"_npmUser":{"name":"craigzyc","email":"craigzych@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_npmVersion":"10.9.4","description":"Live update and analytics plugin for CapacitorJS apps — part of the DeployYourApp platform","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.0","@deploy-your-app/shared":"workspace:*"},"peerDependencies":{"@capacitor/core":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-update-manager_0.2.0_1785529260034_0.7463050373907558","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@deploy-your-app/capacitor-update-manager","version":"0.2.1","keywords":["capacitor","plugin","live-update","ota","deploy-your-app"],"author":{"name":"DeployYourApp"},"license":"MIT","_id":"@deploy-your-app/capacitor-update-manager@0.2.1","maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"homepage":"https://deployyour.app","bugs":{"email":"info@deployyour.app"},"dist":{"shasum":"dcf7385fe5f52b0a459b0b918fa21bb3a74c6b0a","tarball":"https://registry.npmjs.org/@deploy-your-app/capacitor-update-manager/-/capacitor-update-manager-0.2.1.tgz","fileCount":25,"integrity":"sha512-BBPfxbLENQWzUdPognidIqjCwZ0EWybkhFmOJRDv2cXX19meho8JeoMXLMgW99bPn8hU+jr/4JHXy0QdP14ZTQ==","signatures":[{"sig":"MEYCIQCtX67CfYIo7SvAoQr9l7Wi5eURpaaINJrZZ643GPj40AIhAI0dlBEPKuQoRhUlmAwb6UMMUJ2+g94Hv2MArEyhZMZ2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":315883},"main":"./dist/index.js","type":"module","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"9a0951a72506b064604fe139f4aa2738b3f2cb51","scripts":{"build":"node build.js","prepublishOnly":"node build.js"},"_npmUser":{"name":"craigzyc","email":"craigzych@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/Craigzyc/DeployYourApp.git","type":"git","directory":"packages/plugin"},"_npmVersion":"10.9.4","description":"Live update and analytics plugin for CapacitorJS apps — part of the DeployYourApp platform","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.0","@deploy-your-app/shared":"workspace:*"},"peerDependencies":{"@capacitor/core":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-update-manager_0.2.1_1785620698140_0.004677526637143048","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@deploy-your-app/capacitor-update-manager","version":"0.4.1","keywords":["capacitor","plugin","live-update","ota","deploy-your-app"],"author":{"name":"DeployYourApp"},"license":"MIT","_id":"@deploy-your-app/capacitor-update-manager@0.4.1","maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"homepage":"https://deployyour.app","bugs":{"email":"info@deployyour.app"},"dist":{"shasum":"5510c92b8097f2a94a53a6a1a0e91672057b3af9","tarball":"https://registry.npmjs.org/@deploy-your-app/capacitor-update-manager/-/capacitor-update-manager-0.4.1.tgz","fileCount":25,"integrity":"sha512-fQG162S3v8bO2ViyGuNkD7vBPXdaWdiipOZIo0pR7q0aHLmkvBiA46OpUUi6cwZJ0544QmEaOAx//X3XzObObA==","signatures":[{"sig":"MEQCIDz1dXnucRsT+2lb0XQ+mYD9cYw6A80bzJetPh3HFkn/AiAfLIeo37r9ggoTlAd1iMx/3QAJSd4rluZG2b+12HF4Ig==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":327601},"main":"./dist/index.js","type":"module","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"459e55ef483794b2d60f0e11429d8f235d965961","scripts":{"build":"node build.js","prepublishOnly":"node build.js"},"_npmUser":{"name":"craigzyc","email":"craigzych@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/Craigzyc/DeployYourApp.git","type":"git","directory":"packages/plugin"},"_npmVersion":"10.9.4","description":"Live update and analytics plugin for CapacitorJS apps — part of the DeployYourApp platform","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.0","@deploy-your-app/shared":"workspace:*"},"peerDependencies":{"@capacitor/core":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-update-manager_0.4.1_1785886499483_0.4770726194360413","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"@deploy-your-app/capacitor-update-manager","version":"0.4.2","keywords":["capacitor","plugin","live-update","ota","deploy-your-app"],"author":{"name":"DeployYourApp"},"license":"MIT","_id":"@deploy-your-app/capacitor-update-manager@0.4.2","maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"homepage":"https://deployyour.app","bugs":{"email":"info@deployyour.app"},"dist":{"shasum":"e44292a424a44824b803dc65275c1477b7fc6af2","tarball":"https://registry.npmjs.org/@deploy-your-app/capacitor-update-manager/-/capacitor-update-manager-0.4.2.tgz","fileCount":37,"integrity":"sha512-K9BsdH9rr2iTkBVvQKCR5DLWxgTZ08rcSJEu1Cc4eGs8m48ntRBWgCEYH4DjBgf8zvX5FYdOcoWZNQKDjALLSw==","signatures":[{"sig":"MEYCIQCSYT+4PSjwdvA4FLkMD1n0Ui/ipCTtOQ7ozxURDWf5OgIhAO5EOHOOmT48GJIznbs+PovFU6B3UIfiVoMisu54NupO","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":488354},"main":"./dist/index.js","type":"module","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"d8a53efc63f518f1df2f6b95733ebf06274396c9","scripts":{"build":"node build.js","prepublishOnly":"node build.js"},"_npmUser":{"name":"craigzyc","email":"craigzych@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/Craigzyc/DeployYourApp.git","type":"git","directory":"packages/plugin"},"_npmVersion":"10.9.4","description":"Live update and analytics plugin for CapacitorJS apps — part of the DeployYourApp platform","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.0","@deploy-your-app/shared":"workspace:*"},"peerDependencies":{"@capacitor/core":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-update-manager_0.4.2_1785933197287_0.2692695419337521","host":"s3://npm-registry-packages-npm-production"}},"0.4.3":{"name":"@deploy-your-app/capacitor-update-manager","version":"0.4.3","keywords":["capacitor","plugin","live-update","ota","deploy-your-app"],"author":{"name":"DeployYourApp"},"license":"MIT","_id":"@deploy-your-app/capacitor-update-manager@0.4.3","maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"homepage":"https://deployyour.app","bugs":{"email":"info@deployyour.app"},"dist":{"shasum":"021490893e18c5720b4e50148020cb84d2f43a83","tarball":"https://registry.npmjs.org/@deploy-your-app/capacitor-update-manager/-/capacitor-update-manager-0.4.3.tgz","fileCount":37,"integrity":"sha512-ACYTwkd9jUDnI0doQ84MEMe4IC4Litae+U0JF0eO3RXR+eF7zPf2XMY+lCY/NbBWgVlj617WbDIXw6W5blpHVQ==","signatures":[{"sig":"MEYCIQCeshKImhkWyx4FtKdo2dVb1It0Rk+/uE3209ilUl68egIhAILTy8S/s1gM2as9bgC9IMXiSPtKfkHfcvgfoMeNe2W4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":488397},"main":"./dist/index.js","type":"module","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"081b61292a1ef1df2c27e31984fa3c35e3fb5cd7","scripts":{"build":"node build.js","prepublishOnly":"node build.js"},"_npmUser":{"name":"craigzyc","email":"craigzych@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/Craigzyc/DeployYourApp.git","type":"git","directory":"packages/plugin"},"_npmVersion":"10.9.4","description":"Live update and analytics plugin for CapacitorJS apps — part of the DeployYourApp platform","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.0","@deploy-your-app/shared":"workspace:*"},"peerDependencies":{"@capacitor/core":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-update-manager_0.4.3_1785937964185_0.6587856228438351","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@deploy-your-app/capacitor-update-manager","version":"0.5.0","keywords":["capacitor","plugin","live-update","ota","deploy-your-app"],"author":{"name":"DeployYourApp"},"license":"MIT","_id":"@deploy-your-app/capacitor-update-manager@0.5.0","maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"homepage":"https://deployyour.app","bugs":{"email":"info@deployyour.app"},"dist":{"shasum":"fb35cb25c129b4c4c2bfee63370c7ed68b86f024","tarball":"https://registry.npmjs.org/@deploy-your-app/capacitor-update-manager/-/capacitor-update-manager-0.5.0.tgz","fileCount":37,"integrity":"sha512-BzRyFBGM/K5mC7RF3nJYdhX6VizgD4eoZpsv9AOFqOdcMj48n/uHG5CKiwa3r3H6pY0WDjQF2S8YVInLt90www==","signatures":[{"sig":"MEUCIHZ2UxmKu0pbMGlgW0JVuLdX73ymW1kuVcol0ssSsK3VAiEA7vxGhYwi5heutfiE0+ROvcsIQ1+7Zsqfaom6Fy0DsBQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":502061},"main":"./dist/index.js","type":"module","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"23701bbf4a740bc0980888a4f2b8f8aa883d1999","scripts":{"test":"node --test","build":"node build.js","prepublishOnly":"node build.js"},"_npmUser":{"name":"craigzyc","email":"craigzych@gmail.com"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"repository":{"url":"git+https://github.com/Craigzyc/DeployYourApp.git","type":"git","directory":"packages/plugin"},"_npmVersion":"10.9.4","description":"Live update and analytics plugin for CapacitorJS apps — part of the DeployYourApp platform","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"esbuild":"^0.24.0","@deploy-your-app/shared":"workspace:*"},"peerDependencies":{"@capacitor/core":">=6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/capacitor-update-manager_0.5.0_1786042711910_0.5893804693408873","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@deploy-your-app/capacitor-update-manager","version":"0.5.1","description":"Capacitor OTA live updates for iOS and Android — ship JS/HTML/CSS without an app store review. Signed bundles, update channels, staged rollouts, auto-rollback, and analytics, powered by DeployYourApp (https://deployyour.app).","type":"module","main":"./dist/index.js","types":"./types/index.d.ts","exports":{".":{"types":"./types/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"keywords":["capacitor","capacitor-plugin","capacitor-update","live-update","live-updates","hot-update","hot-code-push","code-push","ota","ota-updates","over-the-air","app-updates","mobile","ios","android","rollback","deployment","deploy-your-app"],"license":"MIT","author":{"name":"DeployYourApp"},"homepage":"https://deployyour.app","bugs":{"email":"info@deployyour.app"},"publishConfig":{"access":"public"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"devDependencies":{"esbuild":"^0.24.0","@deploy-your-app/shared":"0.2.0"},"peerDependencies":{"@capacitor/core":">=6.0.0"},"scripts":{"build":"node build.js","test":"node --test"},"_id":"@deploy-your-app/capacitor-update-manager@0.5.1","_integrity":"sha512-zUGUHZedVPe7pbF0j/ktk3W+BLAOBZo+JHnZquiPEU3CUgK5kOaJGoyUK5/RICSVFNarfHofOMbhiglFjS8oeA==","_resolved":"C:\\Users\\craig\\AppData\\Local\\Temp\\a3e5c9bb9d384492a90b0d874a113da1\\deploy-your-app-capacitor-update-manager-0.5.1.tgz","_from":"file:deploy-your-app-capacitor-update-manager-0.5.1.tgz","_nodeVersion":"22.22.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-zUGUHZedVPe7pbF0j/ktk3W+BLAOBZo+JHnZquiPEU3CUgK5kOaJGoyUK5/RICSVFNarfHofOMbhiglFjS8oeA==","shasum":"6c53dc2245bff1290d05ab0fecbe747edec05758","tarball":"https://registry.npmjs.org/@deploy-your-app/capacitor-update-manager/-/capacitor-update-manager-0.5.1.tgz","fileCount":37,"unpackedSize":524526,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCVR9DWGsD2EXe9JiARbe+uGdpWkixVywIsBAaw1YvurwIhAKgWpXl7r2I9FlNIATMXX5qdIjuT4AeXHvb90qB9SoD0"}]},"_npmUser":{"name":"craigzyc","email":"craigzych@gmail.com"},"directories":{},"maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/capacitor-update-manager_0.5.1_1786891181856_0.8584522010540674"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-31T20:20:59.829Z","modified":"2026-08-16T14:39:42.238Z","0.2.0":"2026-07-31T20:21:00.212Z","0.2.1":"2026-08-01T21:44:58.291Z","0.4.1":"2026-08-04T23:34:59.653Z","0.4.2":"2026-08-05T12:33:17.496Z","0.4.3":"2026-08-05T13:52:44.360Z","0.5.0":"2026-08-06T18:58:32.057Z","0.5.1":"2026-08-16T14:39:42.059Z"},"bugs":{"email":"info@deployyour.app"},"author":{"name":"DeployYourApp"},"license":"MIT","homepage":"https://deployyour.app","keywords":["capacitor","capacitor-plugin","capacitor-update","live-update","live-updates","hot-update","hot-code-push","code-push","ota","ota-updates","over-the-air","app-updates","mobile","ios","android","rollback","deployment","deploy-your-app"],"description":"Capacitor OTA live updates for iOS and Android — ship JS/HTML/CSS without an app store review. Signed bundles, update channels, staged rollouts, auto-rollback, and analytics, powered by DeployYourApp (https://deployyour.app).","maintainers":[{"name":"craigzyc","email":"craigzych@gmail.com"}],"readme":"# @deploy-your-app/capacitor-update-manager\n\n**Over-the-air (OTA) live updates for Capacitor apps.** Ship JavaScript, HTML,\nand CSS changes to installed iOS and Android apps without going through app\nstore review — signed bundles, update channels, percentage rollouts, automatic\nrollback, and update analytics.\n\n### 🌐 [deployyour.app](https://deployyour.app)\n\n[**Website**](https://deployyour.app) · [**Documentation**](https://deployyour.app/docs) ·\n[**Pricing**](https://deployyour.app/pricing) · [**Compare OTA platforms**](https://deployyour.app/compare) ·\n[**Changelog**](https://deployyour.app/changelog) · [**Dashboard**](https://app.deployyour.app)\n\n[![npm](https://img.shields.io/npm/v/@deploy-your-app/capacitor-update-manager.svg)](https://www.npmjs.com/package/@deploy-your-app/capacitor-update-manager)\n![license](https://img.shields.io/npm/l/@deploy-your-app/capacitor-update-manager.svg)\n\n---\n\n## What this is\n\nThis is the Capacitor client SDK for [DeployYourApp](https://deployyour.app), a\nhosted OTA update, distribution, and diagnostics platform for Capacitor and\nElectron apps. The plugin checks for updates, downloads and verifies signed\nbundles, activates them, and rolls back automatically when a bundle fails to\nstart. The server side — apps, channels, rollouts, devices, and analytics —\nlives in your [DeployYourApp dashboard](https://app.deployyour.app), so the\nplugin needs an account (every plan starts with a 30-day trial; see\n[pricing](https://deployyour.app/pricing)).\n\n**Use it when you want to:**\n\n- Push a JavaScript/CSS bugfix to users the same day, instead of waiting on an\n  app store review cycle — \"hot code push\" / live update for Capacitor\n- Run `staging` and `production` update channels off one binary\n- Roll a release out to a percentage of devices, then roll it back instantly\n  if something breaks\n- Distribute internal corporate apps and keep them current\n- See what version each device is actually running\n\n**The rest of the platform:**\n\n| Package | What it is |\n|---------|-----------|\n| [`@deploy-your-app/cli`](https://www.npmjs.com/package/@deploy-your-app/cli) | `dya` — sets this plugin up, then bundles, signs, and deploys your updates |\n| [`@deploy-your-app/electron-update-manager`](https://www.npmjs.com/package/@deploy-your-app/electron-update-manager) | The same live-update pipeline for Electron desktop apps |\n\n## Installation\n\n```bash\nnpm install @deploy-your-app/capacitor-update-manager\nnpx cap sync\n```\n\nRequires Capacitor 6+. No extra native setup is needed — CocoaPods / Gradle pick everything up from `npx cap sync` (the iOS pod pulls in ZIPFoundation automatically).\n\n> Tip: if you use the DeployYourApp CLI, `dya setup` installs and configures this plugin for you interactively — including generating the init module below and registering it in your app's entry point. It never overwrites a source file it did not write: if the filename it wants is already yours, it picks the next free one (`dya-update`, `dya-ota`, …), registers that instead, and keeps using that name on later runs. The `publicKey` it writes into `capacitor.config.json` is derived from the signing private key `dya deploy` uses, and setup refuses to write anything if the two disagree — or if a *different* public key is already embedded here, which is what a fresh clone of a shipped project looks like. Replacing that one takes typing `replace the signing key`; pressing Enter keeps it and stops setup.\n\n## Quick Start\n\n### 1. Configure (`capacitor.config.js`)\n\n```js\nexport default {\n  appId: 'com.yourcompany.yourapp',\n  plugins: {\n    DeployYourApp: {\n      appId: 'your-app-id',                    // from the DeployYourApp dashboard\n      channel: 'production',\n      publicKey: '-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----',\n    },\n  },\n};\n```\n\nThat is the whole configuration — the plugin talks to [deployyour.app](https://deployyour.app) by default.\n\n`publicKey` is **required**. Signature verification is mandatory and has no fail-open path: without a public key the plugin refuses every download with `SIGNATURE_REQUIRED`. Generate the pair with `dya keys generate`; `dya setup` writes the public half into your Capacitor config for you.\n\n`updateUrl` / `statsUrl` only need setting to point the app at a different DeployYourApp API — a local server during development, say. They are **base** URLs (e.g. `http://localhost:3000`); the plugin appends `/api/update` and `/api/stats` itself. A non-default API also needs its bundle storage host listed in `allowedDownloadHosts`.\n\n### 2. Confirm each successful launch\n\n```js\nimport { DeployYourApp } from '@deploy-your-app/capacitor-update-manager';\n\n// Call once your app has finished booting. If this is not called within\n// `appReadyTimeout` after an update, the plugin rolls back automatically.\nawait DeployYourApp.notifyAppReady();\n```\n\nIf your web sources cannot resolve that bare import — a Quasar/Capacitor project keeps the plugin in `src-capacitor/node_modules`, which the web bundler does not see — use Capacitor's own seam and get the identical API:\n\n```js\nimport { registerPlugin } from '@capacitor/core';\nconst DeployYourApp = registerPlugin('DeployYourApp');\n```\n\nNothing in this package's JavaScript is load-bearing: every guarantee below holds at the native bridge boundary, so both forms behave the same. (Before 0.5.0 that was not true — see [Migrating to 0.5.0](https://deployyour.app/docs/plugin/api-reference).)\n\nThat's the whole integration. With the default `autoUpdate: true`, the plugin checks for updates on launch (and every `checkInterval` seconds), downloads new bundles in the background, verifies them, and activates them on the next app launch.\n\n#### Quasar\n\nQuasar generates its own `main.ts`, so the call belongs in a [boot file](https://quasar.dev/quasar-cli-vite/boot-files) — the framework's designated place for startup side effects — rather than in `App.vue`.\n\n```ts\n// src/boot/dya.ts\nimport { defineBoot } from '#q-app/wrappers';\nimport { DeployYourApp } from '@deploy-your-app/capacitor-update-manager';\n\nexport default defineBoot(async () => {\n  try {\n    await DeployYourApp.notifyAppReady();\n  } catch (err) {\n    // A boot file that throws aborts Quasar's whole boot chain.\n    console.warn('[DeployYourApp] notifyAppReady() failed:', err);\n  }\n});\n```\n\n`#q-app/wrappers` and `defineBoot` are the current names, introduced in `@quasar/app-vite` v2 and `@quasar/app-webpack` v4. On older versions use the previous path instead — `import { boot } from 'quasar/wrappers'` and `export default boot(...)`. Copy whichever form your own `quasar.config` file uses; `dya setup` detects it from your `package.json` (falling back to what the config imports) and generates the matching file.\n\nThen register it in `quasar.config.ts`:\n\n```ts\nboot: ['dya'],\n```\n\nA Quasar project keeps the Capacitor project in `src-capacitor/`, which has its own `package.json`. Install this plugin in **both** — the web root so the import above resolves, and `src-capacitor/` so `npx cap sync` picks up the native code. `dya setup` writes the boot file, the `boot: []` entry, and both installs for you. If you already have a `src/boot/dya.ts` of your own, setup leaves it untouched and registers the boot file it did write under another name.\n\n#### Other frameworks\n\nAnywhere else, a side-effecting module imported once from your entry file does the same job:\n\n```js\n// src/dya.js\nimport { DeployYourApp } from '@deploy-your-app/capacitor-update-manager';\n\nDeployYourApp.notifyAppReady();\n```\n\n```js\n// src/main.js — one line, after your other imports\nimport './dya';\n```\n\n### Manual update flow (optional)\n\nSet `autoUpdate: false` to drive updates yourself:\n\n```js\nconst update = await DeployYourApp.checkForUpdate();\nif (update.available) {\n  const { id } = await DeployYourApp.download({\n    url: update.url,\n    version: update.version,\n    checksum: update.checksum,\n    signature: update.signature,\n  });\n\n  // Activates the bundle and reloads the webview immediately.\n  await DeployYourApp.apply({ id });\n}\n```\n\n## Configuration\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `appId` | `string` | **required** | Your app ID from DeployYourApp |\n| `updateUrl` | `string` | `https://api.deployyour.app` | Update server **base** URL (no path — `/api/update` is appended) |\n| `statsUrl` | `string` | `https://api.deployyour.app` | Analytics server **base** URL (no path — `/api/stats` is appended) |\n| `allowedDownloadHosts` | `string[]` | `['storage.deployyour.app']` | Extra hosts allowed to serve bundle downloads. The `updateUrl` and `statsUrl` hosts are always allowed. Bundles are fetched over https only |\n| `channel` | `string` | `'production'` | Update channel (persisted when changed via `setChannel()`) |\n| `autoUpdate` | `boolean` | `true` | Check + download automatically; activate per `applyMode` |\n| `applyMode` | `string` | `'whenIdle'` | When auto-updates activate: `'whenIdle'` / `'onLaunch'` (next launch), `'immediate'` (reload now), `'background'` (download only, you call `apply()`). The server can override per-update; `mandatory` updates always apply immediately. |\n| `appReadyTimeout` | `number` | `10000` | Ms to wait for `notifyAppReady()` before auto-rollback |\n| `checkInterval` | `number` | `600` | Seconds between automatic update checks (`0` disables repeat checks) |\n| `publicKey` | `string` | **required** | RSA public key (PEM) for bundle signature verification. Without it every download fails with `SIGNATURE_REQUIRED` |\n| `analyticsEnabled` | `boolean` | `true` | Enable batched analytics |\n| `analyticsBatchSize` | `number` | `20` | Events before auto-flush |\n| `analyticsFlushInterval` | `number` | `30` | Seconds between auto-flush |\n| `autoDeleteFailed` | `boolean` | `true` | Auto-delete failed bundles |\n| `autoDeletePrevious` | `boolean` | `true` | Auto-delete old bundles after a successful update |\n| `resetWhenUpdate` | `boolean` | `true` | Reset to the built-in bundle when the native app version changes (store update) |\n| `directUpdate` | `string` | — | **Deprecated.** Legacy alias for `applyMode` |\n\n## API Reference\n\n### Update Lifecycle\n\n| Method | Description |\n|--------|-------------|\n| `checkForUpdate(options?)` | Check server for available updates (`{ channel? }`) |\n| `download(options)` | Download, verify, policy-check, and store a bundle |\n| `apply(options)` | Activate a downloaded bundle and reload the webview (`{ id }`) |\n| `notifyAppReady(options?)` | Confirm the bundle loaded — prevents rollback. Rejects `READY_TOKEN_MISMATCH` if the calling document is not the bundle on trial |\n| `reset()` | Delete all downloaded bundles and revert to the built-in bundle |\n| `reload()` | Force reload the webview |\n\n### Bundle Management\n\n| Method | Description |\n|--------|-------------|\n| `getCurrentBundle()` | Get active bundle info (`{ id: 'builtin', ... }` when none) |\n| `getNextBundle()` | Get the bundle staged for next launch: `{ bundle: BundleInfo \\| null }` |\n| `listBundles()` | List all downloaded bundles |\n| `deleteBundle({ id })` | Remove a stored bundle |\n\n### Channel Management\n\n| Method | Description |\n|--------|-------------|\n| `getChannel()` | Get current update channel |\n| `setChannel({ channel })` | Switch update channel (persisted; used by the next check) |\n\n### Device Identity\n\n| Method | Description |\n|--------|-------------|\n| `getDeviceId()` | Get stable device UUID |\n| `setCustomId({ customId })` | Set a custom device identifier (e.g. employee ID) |\n\n### Analytics\n\n| Method | Description |\n|--------|-------------|\n| `trackEvent({ name, properties? })` | Track a custom event |\n| `trackPageView({ path, title? })` | Track a page view |\n| `trackError({ message, stack?, fatal? })` | Track an error |\n| `flushAnalytics()` | Flush buffered events immediately |\n\n`eventData` is stored verbatim — see [Data collected by this SDK](#data-collected-by-this-sdk) before putting anything user-derived in it.\n\n### Version Info\n\n| Method | Description |\n|--------|-------------|\n| `getNativeVersion()` | Get the native app version |\n| `getPluginVersion()` | Get the plugin version |\n| `setVersionOverride({ version })` | Report a fake version to the update server (testing). Empty string clears it |\n| `getVersionOverride()` | Get the active version override (`''` when unset) |\n\n## Events\n\n```js\nimport { DeployYourApp, DYA_EVENTS } from '@deploy-your-app/capacitor-update-manager';\n\nDeployYourApp.addListener(DYA_EVENTS.DOWNLOAD_PROGRESS, (data) => {\n  console.log(`Download: ${data.percent}%`);\n});\n\nDeployYourApp.addListener(DYA_EVENTS.UPDATE_AVAILABLE, (data) => {\n  console.log(`Update ${data.version} available`);\n});\n```\n\n| Event | Data | Description |\n|-------|------|-------------|\n| `downloadProgress` | `{ percent, bytesDownloaded, totalBytes }` | Download progress (throttled to whole-percent changes) |\n| `updateAvailable` | `{ version, message? }` | A check found a new update |\n| `noUpdateAvailable` | — | A check found nothing new |\n| `downloadComplete` | `{ id, version }` | Download finished (manual or auto) |\n| `downloadFailed` | `{ message }` | Download or auto-update error |\n| `updateApplied` | `{ id, version }` | Bundle activated |\n| `updateFailed` | `{ message }` | `apply()` failed |\n| `rollback` | `{ from, to, reason, attempts? }` | Auto-rollback triggered (`reason: 'appReadyTimeout'` or `'crashLoop'`; `attempts` is the launch count for `'crashLoop'`) |\n| `appReady` | — | `notifyAppReady()` confirmed |\n| `appReadyRejected` | `{ bundleId, servedBundleId, message }` | `notifyAppReady()` was refused because the calling document could not be shown to be running the bundle on trial; the call also rejects with `READY_TOKEN_MISMATCH` |\n| `appVersionChange` | `{ previousVersion, currentVersion }` | Native app version changed; reset to built-in (`resetWhenUpdate`) |\n\nThe events that can legitimately land during launch, before your listener code has run, are retained by Capacitor and delivered to the first listener that attaches: **`updateAvailable`**, **`downloadComplete`**, **`downloadFailed`**, **`updateApplied`**, **`updateFailed`**, **`rollback`**, **`appReadyRejected`**, and **`appVersionChange`**. Both platforms retain exactly these.\n\nThe remaining three — `downloadProgress`, `noUpdateAvailable`, and `appReady` — are delivered live and lost if nothing is listening at that moment. Register your listeners before calling `checkForUpdate()` (or before `notifyAppReady()`, for `appReady`) if you depend on them.\n\n## Error Codes\n\nRejected calls carry a stable `code` you can branch on:\n\n`MISSING_PARAMS`, `NETWORK_ERROR`, `PARSE_ERROR`, `DOWNLOAD_FAILED`, `CHECKSUM_MISMATCH`, `SIGNATURE_REQUIRED`, `SIGNATURE_INVALID`, `BUNDLE_NOT_FOUND`, `INVALID_URL`, `EXTRACTION_FAILED`, `ASSET_TYPE_REJECTED`, `MANIFEST_MISSING`, `MANIFEST_MISMATCH`, `READY_TOKEN_MISMATCH`, `STORAGE_ERROR`, `UNKNOWN`.\n\n| Code | Meaning |\n|------|---------|\n| `SIGNATURE_REQUIRED` | `publicKey` is not configured, or the server sent no signature. There is no unsigned install path |\n| `ASSET_TYPE_REJECTED` | A bundle entry is not a web asset — its extension is outside the allowlist, or its leading bytes are a native executable's |\n| `MANIFEST_MISSING` | The bundle carries no readable `.dya-manifest.json`, or one whose `manifestVersion` is not `1`. Re-deploy with a current `dya` CLI |\n| `MANIFEST_MISMATCH` | The extracted files and the manifest disagree: a wrong hash, a file with no manifest entry, a manifest entry with no file, or a `files` map that is absent or malformed in a manifest that otherwise parsed |\n\n```js\ntry {\n  await DeployYourApp.download(update);\n} catch (err) {\n  if (err.code === 'CHECKSUM_MISMATCH') {\n    // corrupted download — retry\n  }\n}\n```\n\n## Update Flow\n\n1. **Check** — `POST {updateUrl}/api/update` with app ID, device ID, platform, versions\n2. **Download** — Fetch the bundle ZIP with progress events\n3. **Verify** — SHA-256 checksum + RSA signature validation over the raw ZIP, before the archive is opened. Both are mandatory\n4. **Extract under policy** — Unzip into the app's bundle storage (Zip-Slip protected, size-capped), rejecting any file that is not a web asset\n5. **Manifest check** — Every extracted file must match `.dya-manifest.json`, in both directions\n6. **Apply** — Point the Capacitor webview at the new bundle and reload (immediately via `apply()` / `applyMode: 'immediate'`, or on the next launch otherwise)\n7. **Ready check** — `notifyAppReady()` must be called within `appReadyTimeout`\n8. **Rollback** — Auto-reverts to the previous bundle (or built-in) if the ready check never arrives\n\nA bundle that crashes the app *before* `appReadyTimeout` can elapse would never\ntrip the timer at all. A persisted launch counter covers that case: after 3\nconsecutive launches without `notifyAppReady()`, the bundle is rolled back and a\n`rollback` event with `reason: 'crashLoop'` is emitted.\n\nOnly one download runs at a time, and the currently active bundle can never be\nre-downloaded over itself. Version strings are validated against\n`^[0-9A-Za-z.\\-+]{1,64}$` before being used as directory names, and each bundle\nis extracted to a staging directory that is swapped into place only after it is\nverified to contain a servable `index.html`.\n\n## No hidden or debug surface\n\nThis plugin installs no gesture recognizers and no touch listeners, and it\nexposes no hidden or undocumented entry point. Every capability it has is a\ndocumented method or event in the tables above.\n\nIf your app wants a debug affordance — a hidden gesture to reach a diagnostics\nscreen, for example — implement it in your own app code, where you control\nwhether it ships and can document it for App Review. It does not belong in an\nupdate plugin that every install embeds. See\n[App Store review](https://deployyour.app/docs/plugin/app-store-review).\n\n## Data collected by this SDK\n\nYou are the data controller for your end users. This SDK sends data to DeployYourApp on your\nbehalf, and **you must disclose it in your own privacy policy**. Full detail, including app\nstore questionnaire guidance, is at <https://deployyour.app/privacy>.\n\n### Sent on every update check (`POST /api/update`) and stored\n\n| Field | Notes |\n|-------|-------|\n| `deviceId` | Random UUID v4 generated by the plugin on first run and stored locally. **Not** an IDFA, GAID, ANDROID_ID, MAC address, or hardware serial, and not derived from one. |\n| `platform` | `ios` or `android` |\n| `nativeVersion` | Version of the installed app binary |\n| `pluginVersion` | This plugin's version |\n| first seen / last seen | Set server-side on each check-in |\n| channel subscriptions | Which update channels this device follows |\n\n**Transmitted but discarded by the server.** The Android implementation also sends\n`osVersion`, the device manufacturer and model, `customId`, `currentBundleId`, and\n`nativeBuild`. The server validates against a strict schema that excludes these, so they are\nstripped and never stored. Do not rely on them being available in the dashboard.\n\n**Never collected:** geolocation, advertising IDs, contacts, photos, phone number, IMEI,\ninstalled-app lists, or your app's own data.\n\n### Analytics (`POST /api/stats`) — **on by default**\n\n`analyticsEnabled` defaults to `true`. Events are buffered and flushed every 20 events or 30\nseconds, and each stores `eventType`, `eventData`, `bundleVersion`, `timestamp`, and the\ndevice ID.\n\n**The plugin emits its own events without you calling anything.** While `analyticsEnabled` is\n`true`, both platforms send these as the update lifecycle runs:\n\n`update_check`, `update_available`, `update_download_start`, `update_download_complete`,\n`update_download_fail`, `update_verify_pass`, `update_verify_fail`, `update_apply`,\n`update_app_ready`, `update_rollback`\n\nThese carry update metadata only — bundle version, size, duration, error code — never end-user\ndata. Your own calls to `trackEvent()`, `trackPageView()`, and `trackError()` are sent on the\nsame channel. `eventData` is arbitrary JSON stored verbatim: **whatever your app puts in it, we\nstore.** A stack trace passed to `trackError()` containing a user's email means that email is\nstored. Audit your call sites.\n\n### Turning it off\n\nDisabling analytics stops analytics events and `/api/stats` requests. It does not stop update\nchecks: every `/api/update` request still includes the persistent `deviceId` so the service can\nselect and deliver updates for that installation.\n\n```js\n// capacitor.config.js\nexport default {\n  plugins: {\n    DeployYourApp: {\n      appId: 'your-app-id',\n      analyticsEnabled: false, // no events sent; update checks still work\n    },\n  },\n};\n```\n\nTo stop contacting our servers entirely, also set `autoUpdate: false` and `checkInterval: 0`\nand never call `checkForUpdate()`.\n\n### On-device storage\n\nThe plugin persists the device ID, selected channel, custom ID, and version override in\n`UserDefaults` (iOS) / `SharedPreferences` (Android), and under the `dya_*` `localStorage`\nkeys on web. In the EU/UK, storing an identifier on a user's device engages ePrivacy consent\nrules; update delivery is a plausible strict-necessity case, analytics generally is not.\n\n### What you need to disclose\n\nName DeployYourApp as a processor; describe the device identifier and the technical version\nfields; describe your own analytics events if you leave analytics on; state your legal basis\nand retention. The iOS SDK privacy manifest declares linked, non-tracking **Device ID** for\n**App Functionality** and **Analytics**, plus linked, non-tracking **Product Interaction**,\n**Performance Data**, and **Other Diagnostic Data** for **Analytics**. The latter categories\ncover default lifecycle durations, byte counts, and failure reasons. Those declarations describe\nthis SDK's collection; they do not replace your host\napp's privacy manifest or App Store Connect answers. Keep those answers consistent with the\nSDK configuration and every other data flow in your shipped app. Retention, deletion, and export\nare covered in the linked doc; note that per-device deletion is not self-serve yet and goes\nthrough info@deployyour.app.\n\n## Security\n\n- Bundles are downloaded over **https only**, from an allow-listed host — the\n  `updateUrl`/`statsUrl` hosts plus `allowedDownloadHosts`. Plain http is\n  accepted only from `localhost`, for local development. Rejections carry\n  `code: 'INVALID_URL'`.\n- Bundle integrity verified via SHA-256 checksum\n- RSA signature verification is **mandatory** and ensures bundles came from your build pipeline (the CLI generates RSA-4096 keys; both platforms derive the modulus size from the key itself, so any RSA key size is accepted). There is no fail-open path: no `publicKey`, no update\n- **Bundles are not encrypted.** They are plain, signed ZIPs, so anyone holding a bundle URL — App Review included — can see exactly what a bundle contains. See [Bundle asset policy](#bundle-asset-policy)\n- ZIP extraction is Zip-Slip protected with per-file (100 MB) and total (500 MB) size caps; symlink entries are skipped on iOS and neutralised on Android (see [Bundle asset policy](#bundle-asset-policy))\n- Signing private keys never leave developer machines\n\n## Bundle asset policy\n\nThe native extractor on both platforms limits published bundles to allowlisted\nweb-asset paths and rejects known executable headers before publication. See\n[App Store review](https://deployyour.app/docs/plugin/app-store-review).\n\n**1. Extension allowlist.** Every *file* entry must end in one of:\n\n```\nhtml htm css js mjs cjs json map webmanifest\nsvg png jpg jpeg gif webp avif ico bmp\nwoff woff2 ttf otf eot\nmp3 mp4 webm ogg wav m4a\ntxt xml csv md\nwasm\n```\n\nOnly the final extension counts, so `bundle.js.map` is allowed and\n`evil.js.dylib` is not. A file with no extension is rejected. Directory entries\nare exempt — they have no extension, and requiring one would reject every\nnested folder.\n\n**Symlink entries differ by platform.** On iOS they are skipped and never\nwritten. On Android they cannot be identified: a ZIP records symlink-ness in\nthe central directory's external attributes, and `java.util.zip.ZipEntry`\nexposes no accessor for it. Such an entry is therefore extracted as an ordinary\nfile whose *content* is the link target path — never as a link, so it cannot\nredirect a later write out of the bundle directory. It must then pass the\nextension allowlist and the manifest hash check like any other file, and a\nmanifest generated from a real build tree does not list it, so it is rejected\nrather than installed.\n\n**2. Executable magic-byte rejection.** The first four bytes of every extracted\nfile are checked regardless of its name, so a native binary renamed to `app.js`\nis still refused:\n\n| Leading bytes | Format |\n|---------------|--------|\n| `FE ED FA CE` | Mach-O |\n| `FE ED FA CF` | Mach-O |\n| `CE FA ED FE` | Mach-O |\n| `CF FA ED FE` | Mach-O |\n| `CA FE BA BE` | Mach-O fat binary or Java class |\n| `BE BA FE CA` | Mach-O fat binary |\n| `CA FE BA BF` | 64-bit Mach-O fat binary |\n| `BF BA FE CA` | 64-bit Mach-O fat binary |\n| `7F 45 4C 46` | ELF |\n| `64 65 78 0A` | Android DEX |\n| `4D 5A`       | PE executable |\n\n**3. Per-file manifest.** Every bundle carries a `.dya-manifest.json` at its\nroot, written by `dya deploy`:\n\n```json\n{\n  \"manifestVersion\": 1,\n  \"bundleVersion\": \"1.4.0\",\n  \"createdAt\": \"2026-08-04T00:00:00.000Z\",\n  \"files\": { \"index.html\": \"<sha256 hex>\", \"assets/app.js\": \"<sha256 hex>\" }\n}\n```\n\nThe check is bidirectional: every manifest entry must exist on disk with the\ndeclared hash, **and** every extracted file must appear in the manifest. A\none-way check would let an attacker add a file or remove one. The manifest\nitself is the only file exempt from appearing in `files` — it cannot list its\nown hash.\n\nThe CLI excludes a source `.dya-manifest.json` and source symlinks from both\nhashing and archiving, then writes exactly one generated manifest after the\ndirectory walk. The ZIP's non-directory file entries are therefore exactly\nthe manifest `files` set plus that generated manifest; the upload service\nrejects archives with anything other than one root manifest.\n\n`manifestVersion` is validated: anything other than `1` is rejected with\n`MANIFEST_MISSING`, naming the version found and the version expected. A\nmanifest the app cannot interpret is treated as one it does not have.\n\nA bundle produced by an older CLI has no manifest and is rejected with\n`MANIFEST_MISSING`. There is no fallback path; re-deploy with a current `dya`.\n\nThese byte and filename checks are limited technical evidence about which files\ncan be published. They cannot guarantee App Store compliance or determine\nwhether web code changes reviewed functionality. Apply the operational release\nboundary in the App Review guidance, and keep store metadata, review notes, and\nprivacy answers accurate for every available release.\n\n## Native release validation\n\nThe repository's `Native release validation` workflow runs the Android JUnit\nand iOS XCTest suites against exact Capacitor 6, 7, and 8 releases. Each matrix entry packs\nthis npm package, installs that tarball into a clean Capacitor consumer, syncs\nthe native platform, and compiles a representative app. The iOS gate also\nchecks the built `App.app` for `PrivacyInfo.xcprivacy`.\n\nRun the same smoke gates on a machine with the corresponding native toolchain:\n\n```sh\npnpm test:native:android -- 6.2.1\npnpm test:native:ios -- 6.2.1\n```\n\nThe scripts reject versions outside the supported Capacitor 6-8 range.\n\n## Platform Support\n\n- **iOS** — Swift implementation (iOS 13+, ZIPFoundation for extraction)\n- **Android** — Kotlin implementation\n- **Web** — Partial: analytics, channel/device identity, and version override work (backed by `localStorage`); update download/apply are unavailable and `checkForUpdate()` always reports no update\n\nFor **Windows, macOS, and Linux desktop apps**, use the sibling package\n[`@deploy-your-app/electron-update-manager`](https://www.npmjs.com/package/@deploy-your-app/electron-update-manager)\n— same signed-bundle pipeline, same dashboard, same `dya deploy`.\n\n---\n\n## Links\n\n| | |\n|---|---|\n| 🌐 Website | <https://deployyour.app> |\n| 📚 Documentation | <https://deployyour.app/docs> — [plugin setup](https://deployyour.app/docs/plugin/setup), [configuration](https://deployyour.app/docs/plugin/configuration), [update lifecycle](https://deployyour.app/docs/plugin/update-lifecycle), [App Store review](https://deployyour.app/docs/plugin/app-store-review) |\n| 💰 Pricing | <https://deployyour.app/pricing> — 30-day trial on every plan |\n| 🔍 Compare | <https://deployyour.app/compare> |\n| 📊 Dashboard | <https://app.deployyour.app> |\n| 📝 Changelog | <https://deployyour.app/changelog> |\n| ✉️ Support | <info@deployyour.app> |\n\nBuilt and maintained by [DeployYourApp](https://deployyour.app). MIT licensed.\n","readmeFilename":"README.md"}