{"_id":"@asyncarijit/rn-pushdeck","_rev":"3-772a90a693a33686a6d6c42229fb965b","name":"@asyncarijit/rn-pushdeck","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@asyncarijit/rn-pushdeck","version":"0.1.0","keywords":["react-native","ota","codepush","updates"],"author":{"name":"asyncarijit"},"license":"MIT","_id":"@asyncarijit/rn-pushdeck@0.1.0","maintainers":[{"name":"asyncarijit","email":"asyncarijit@gmail.com"}],"homepage":"https://rn-pushdeck.vercel.app","dist":{"shasum":"ca10d419c2932a73d02e1dde770babf0075e0ebd","tarball":"https://registry.npmjs.org/@asyncarijit/rn-pushdeck/-/rn-pushdeck-0.1.0.tgz","fileCount":7,"integrity":"sha512-D0Ys742L2cDxSjvQXBKxsqx/DC31zb2LMYYAmS/haCeovXSYSzipWqLEvKbey9JVEo+UDTvO4vqYVdVoOipNcQ==","signatures":[{"sig":"MEUCIHKdes7W0n9WvIrA0ZrBIVroF39DSZ5HwIYaZXgifTrcAiEAsdmcgupRavMcLQh6cyVRT/z7GUTqMTrxQoI8jRj1rzs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25554},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"asyncarijit","email":"asyncarijit@gmail.com"},"_npmVersion":"10.9.2","description":"OTA JavaScript updates for React Native apps — self-hosted CodePush alternative.","directories":{},"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","typescript":"^5.6.0","@types/react-native":"^0.72.0"},"peerDependencies":{"react-native":">=0.74.0","react-native-fs":">=2.20.0","react-native-restart":">=0.0.27","react-native-device-info":">=10.0.0","react-native-zip-archive":">=6.0.0","@react-native-async-storage/async-storage":">=1.21.0"},"peerDependenciesMeta":{"react-native-zip-archive":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/rn-pushdeck_0.1.0_1778516393831_0.2273490282290036","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@asyncarijit/rn-pushdeck","version":"0.2.0","keywords":["react-native","ota","codepush","updates"],"author":{"name":"asyncarijit"},"license":"MIT","_id":"@asyncarijit/rn-pushdeck@0.2.0","maintainers":[{"name":"asyncarijit","email":"asyncarijit@gmail.com"}],"homepage":"https://rn-pushdeck.vercel.app","dist":{"shasum":"a0d37a428e92289e7e7dc8a02022ec3f0a119766","tarball":"https://registry.npmjs.org/@asyncarijit/rn-pushdeck/-/rn-pushdeck-0.2.0.tgz","fileCount":7,"integrity":"sha512-Q3oX5svvb0QaOw23Ecf005WF1ZZJU5fjTDFha7j13ypnrbnCoAuL7/TiS4XpPMIHtxW/MNBG8XthBIB4xn8cYw==","signatures":[{"sig":"MEQCIAOAibTk7Od//m6R3wTAIhUmuw7OVv/ymKIlczY1BT+CAiBArTNhy/jVvn5+v0/yN7KHeiI5h45q6B2+dAKAk0KNHw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25580},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"asyncarijit","email":"asyncarijit@gmail.com"},"_npmVersion":"10.9.2","description":"OTA JavaScript updates for React Native apps — self-hosted CodePush alternative.","directories":{},"_nodeVersion":"22.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","typescript":"^5.6.0","@types/react-native":"^0.72.0"},"peerDependencies":{"react-native":">=0.74.0","react-native-fs":">=2.20.0","react-native-restart":">=0.0.27","react-native-device-info":">=10.0.0","react-native-zip-archive":">=6.0.0","@react-native-async-storage/async-storage":">=1.21.0"},"peerDependenciesMeta":{"react-native-zip-archive":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/rn-pushdeck_0.2.0_1778524735631_0.6112983419009752","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@asyncarijit/rn-pushdeck","version":"0.2.1","description":"OTA JavaScript updates for React Native apps — self-hosted CodePush alternative.","license":"MIT","author":{"name":"asyncarijit"},"homepage":"https://github.com/asyncArijit/RN-Pushdeck#readme","publishConfig":{"access":"public"},"main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"peerDependencies":{"react-native":">=0.74.0","react-native-fs":">=2.20.0","react-native-restart":">=0.0.27","@react-native-async-storage/async-storage":">=1.21.0","react-native-device-info":">=10.0.0","react-native-zip-archive":">=6.0.0"},"peerDependenciesMeta":{"react-native-zip-archive":{"optional":true}},"devDependencies":{"@types/react-native":"^0.72.0","tsup":"^8.5.1","typescript":"^5.6.0"},"keywords":["react-native","ota","codepush","updates"],"repository":{"type":"git","url":"git+https://github.com/asyncArijit/RN-Pushdeck.git","directory":"sdk"},"bugs":{"url":"https://github.com/asyncArijit/RN-Pushdeck/issues"},"_id":"@asyncarijit/rn-pushdeck@0.2.1","gitHead":"0b6d19af162f61f0cedb67a62c39a13248cc8867","_nodeVersion":"22.16.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-KYLLddvkWg4LVPlPQwuIolGIRfpOGl7xbbyx+LWpZjx2I+6KBQlxDXR2P/0GLb08HRA6gLM5AoijOBZNEGvTog==","shasum":"2e1ed7acb9440d81897461f625a8354d04ae2328","tarball":"https://registry.npmjs.org/@asyncarijit/rn-pushdeck/-/rn-pushdeck-0.2.1.tgz","fileCount":7,"unpackedSize":25809,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGr0Si050OE9Fm0Y8eRkJiYIWZxlje7a0FaloNR6/SR7AiEA13b4gdPPO/Q8dgIqhlnafav3HTht4av0Br/MUWrDBKA="}]},"_npmUser":{"name":"asyncarijit","email":"asyncarijit@gmail.com"},"directories":{},"maintainers":[{"name":"asyncarijit","email":"asyncarijit@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rn-pushdeck_0.2.1_1786598815317_0.9748251599528368"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-11T16:19:53.736Z","modified":"2026-08-13T05:26:55.602Z","0.1.0":"2026-05-11T16:19:54.007Z","0.2.0":"2026-05-11T18:38:55.777Z","0.2.1":"2026-08-13T05:26:55.445Z"},"author":{"name":"asyncarijit"},"license":"MIT","homepage":"https://github.com/asyncArijit/RN-Pushdeck#readme","keywords":["react-native","ota","codepush","updates"],"description":"OTA JavaScript updates for React Native apps — self-hosted CodePush alternative.","maintainers":[{"name":"asyncarijit","email":"asyncarijit@gmail.com"}],"readme":"# @asyncarijit/rn-pushdeck\n\n[![npm](https://img.shields.io/npm/v/@asyncarijit/rn-pushdeck.svg)](https://www.npmjs.com/package/@asyncarijit/rn-pushdeck)\n[![license](https://img.shields.io/npm/l/@asyncarijit/rn-pushdeck.svg)](./LICENSE)\n\nOver-the-air JavaScript updates for React Native — a self-hosted alternative to Microsoft CodePush.\n\n## Install\n\n```bash\nnpm install @asyncarijit/rn-pushdeck \\\n  react-native-fs \\\n  react-native-restart \\\n  @react-native-async-storage/async-storage \\\n  react-native-device-info\n```\n\nOptional (only if you also ship asset zips):\n\n```bash\nnpm install react-native-zip-archive\n```\n\nAfter installing native deps, rebuild your Android app:\n\n```bash\ncd android && ./gradlew clean && cd .. && npx expo run:android\n```\n\n## Set up Android (one-time)\n\nYou need to tell React Native to load JS bundles from your app's `filesDir` if a downloaded one exists. See [`INSTALL_ANDROID.md`](./INSTALL_ANDROID.md) for the exact Kotlin override.\n\niOS support is coming in a later release.\n\n## Configure\n\nIn your app's entry file (`App.tsx` or `index.js`):\n\n```ts\nimport { configure, checkForUpdate } from '@asyncarijit/rn-pushdeck';\n\nconfigure({\n  projectKey: 'psh_xxxxxxxxxx',  // get this from the rn-pushdeck dashboard\n  channel: 'production',          // optional, default 'production'\n});\n```\n\n## Check for updates\n\n```ts\nimport { useEffect } from 'react';\nimport { checkForUpdate } from '@asyncarijit/rn-pushdeck';\n\nexport default function App() {\n  useEffect(() => {\n    checkForUpdate();\n  }, []);\n  // ...\n}\n```\n\nDefault behaviour: if a newer bundle is available on your project's channel, the user sees a native dialog asking whether to update. On confirm, the bundle downloads, is saved to local storage, and the app restarts.\n\n## Customize the prompt\n\n```ts\nimport { configure } from '@asyncarijit/rn-pushdeck';\n\nconfigure({\n  projectKey: 'psh_xxx',\n  onUpdateAvailable: ({ version, force, releaseNotes, apply }) => {\n    // Show your own UI here. Call apply() when the user accepts.\n    setUpdateBanner({ version, force, releaseNotes, onAccept: apply });\n  },\n  onError: (err) => {\n    console.warn('OTA error:', err);\n  },\n});\n```\n\n`apply()` does the actual download + restart. It returns a `Promise` so you can show a progress indicator while it runs.\n\n## API\n\n```ts\nconfigure(options: ConfigOptions): void\ncheckForUpdate(): Promise<void>\nrestart(): void\ncompareSemver(a: string, b: string): number\n\ntype ConfigOptions = {\n  projectKey: string;\n  channel?: string;                          // default 'production'\n  apiUrl?: string;                           // default rn-pushdeck production\n  autoRestart?: boolean;                     // default false\n  onUpdateAvailable?: (ctx: UpdateContext) => void;\n  onError?: (err: unknown) => void;\n};\n\ntype UpdateContext = {\n  version: string;\n  releaseNotes: string | null;\n  force: boolean;\n  bundleSize: number;\n  apply: () => Promise<void>;\n};\n```\n\n## How it works\n\n1. On app launch, `checkForUpdate()` hits the rn-pushdeck **manifest endpoint** with your `projectKey` and `channel`.\n2. The endpoint returns the current bundle URL and version for that channel.\n3. The SDK compares the remote version against the locally stored one (or the native APK version if none stored).\n4. If newer, the SDK calls your `onUpdateAvailable` handler (or shows a default Alert).\n5. When the handler calls `apply()`, the SDK downloads the bundle directly from Cloudflare R2 (no API roundtrip), saves it to `filesDir/index.android.bundle`, and triggers a restart.\n6. On next launch, the native override in `MainApplication.kt` loads the downloaded bundle instead of the APK-bundled one.\n\n## When OTA is safe\n\n✅ **Safe to ship via OTA:**\n- Pure JavaScript / TypeScript changes\n- UI tweaks, business logic, copy\n- New screens, API call changes\n\n❌ **NOT safe (requires a new APK):**\n- Adding a new native module (e.g., camera)\n- Bumping a library that has native code\n- Changing AndroidManifest.xml permissions\n\nUse `minNativeVersion` (set when uploading via `pushdeck deploy --min-native 1.0.0`) to prevent serving a JS bundle to APKs that don't have the required native code.\n","readmeFilename":"README.md","repository":{"type":"git","url":"git+https://github.com/asyncArijit/RN-Pushdeck.git","directory":"sdk"},"bugs":{"url":"https://github.com/asyncArijit/RN-Pushdeck/issues"}}