native-update 1.4.9 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/Readme.md +35 -9
  2. package/android/manifest-additions.xml +28 -0
  3. package/android/src/main/AndroidManifest.xml +3 -7
  4. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +21 -13
  5. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +15 -0
  6. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +23 -7
  7. package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +346 -31
  8. package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +32 -34
  9. package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +10 -1
  10. package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +18 -18
  11. package/cli/AGENTS.md +43 -0
  12. package/cli/CLAUDE.md +65 -0
  13. package/cli/commands/backend-create.js +56 -15
  14. package/cli/commands/bundle-create.js +39 -7
  15. package/cli/commands/monitor.js +72 -51
  16. package/cli/index.js +10 -24
  17. package/cli/package.json +11 -3
  18. package/dist/esm/app-review/app-review-manager.js +0 -1
  19. package/dist/esm/app-review/index.js +0 -1
  20. package/dist/esm/app-review/platform-review-handler.js +0 -1
  21. package/dist/esm/app-review/review-conditions-checker.js +0 -1
  22. package/dist/esm/app-review/review-rate-limiter.js +0 -1
  23. package/dist/esm/app-review/types.js +0 -1
  24. package/dist/esm/app-update/app-update-checker.js +0 -1
  25. package/dist/esm/app-update/app-update-installer.d.ts +1 -0
  26. package/dist/esm/app-update/app-update-installer.js +19 -8
  27. package/dist/esm/app-update/app-update-manager.js +0 -1
  28. package/dist/esm/app-update/app-update-notifier.js +0 -1
  29. package/dist/esm/app-update/index.js +0 -1
  30. package/dist/esm/app-update/platform-app-update.js +12 -3
  31. package/dist/esm/app-update/types.js +0 -1
  32. package/dist/esm/background-update/background-scheduler.js +0 -1
  33. package/dist/esm/background-update/index.js +0 -1
  34. package/dist/esm/background-update/notification-manager.js +0 -1
  35. package/dist/esm/config/support.js +0 -1
  36. package/dist/esm/core/analytics.d.ts +13 -0
  37. package/dist/esm/core/analytics.js +15 -1
  38. package/dist/esm/core/cache-manager.js +0 -1
  39. package/dist/esm/core/config.d.ts +6 -30
  40. package/dist/esm/core/config.js +1 -8
  41. package/dist/esm/core/errors.d.ts +1 -0
  42. package/dist/esm/core/errors.js +1 -1
  43. package/dist/esm/core/event-emitter.d.ts +0 -3
  44. package/dist/esm/core/event-emitter.js +8 -3
  45. package/dist/esm/core/logger.js +0 -1
  46. package/dist/esm/core/performance.js +0 -1
  47. package/dist/esm/core/plugin-manager.js +3 -1
  48. package/dist/esm/core/security.d.ts +22 -3
  49. package/dist/esm/core/security.js +46 -7
  50. package/dist/esm/definitions.d.ts +13 -40
  51. package/dist/esm/definitions.js +0 -1
  52. package/dist/esm/index.d.ts +3 -4
  53. package/dist/esm/index.js +3 -3
  54. package/dist/esm/live-update/bundle-manager.d.ts +8 -0
  55. package/dist/esm/live-update/bundle-manager.js +20 -1
  56. package/dist/esm/live-update/certificate-pinning.js +0 -1
  57. package/dist/esm/live-update/delta-processor.d.ts +1 -1
  58. package/dist/esm/live-update/delta-processor.js +3 -1
  59. package/dist/esm/live-update/download-manager.d.ts +36 -5
  60. package/dist/esm/live-update/download-manager.js +70 -24
  61. package/dist/esm/live-update/rollout-checker.d.ts +1 -1
  62. package/dist/esm/live-update/rollout-checker.js +5 -6
  63. package/dist/esm/live-update/update-manager.d.ts +12 -1
  64. package/dist/esm/live-update/update-manager.js +38 -11
  65. package/dist/esm/live-update/version-manager.d.ts +9 -12
  66. package/dist/esm/live-update/version-manager.js +40 -68
  67. package/dist/esm/plugin.js +82 -89
  68. package/dist/esm/security/crypto.js +11 -7
  69. package/dist/esm/security/validator.js +0 -1
  70. package/dist/esm/types/rollout.d.ts +85 -0
  71. package/dist/esm/types/rollout.js +25 -0
  72. package/dist/esm/web.d.ts +26 -1
  73. package/dist/esm/web.js +214 -75
  74. package/dist/plugin.cjs.js +1 -2
  75. package/dist/plugin.esm.js +1 -2
  76. package/dist/plugin.js +2 -3
  77. package/docs/AGENTS.md +38 -0
  78. package/docs/CHANGELOG.md +275 -0
  79. package/docs/CLAUDE.md +101 -0
  80. package/docs/MANUAL-TASKS.md +17 -0
  81. package/docs/MARKETING_WEBSITE_TRACKER.md +18 -2
  82. package/docs/MIGRATION.md +170 -0
  83. package/docs/PACKAGES.md +167 -0
  84. package/docs/PERFORMANCE.md +110 -0
  85. package/docs/PROJECT_COMPLETION_TRACKER.md +4 -35
  86. package/docs/README.md +12 -2
  87. package/docs/REMAINING_FEATURES.md +123 -76
  88. package/docs/ROADMAP.md +200 -120
  89. package/docs/SECURITY-IF-REPO-PUBLIC.md +232 -0
  90. package/docs/TESTING_REQUIREMENTS.md +1 -112
  91. package/docs/ai-knowledge-base/00-project-profile.md +38 -0
  92. package/docs/ai-knowledge-base/01-features.md +46 -0
  93. package/docs/ai-knowledge-base/02-routes.md +72 -0
  94. package/docs/ai-knowledge-base/03-tech-stack.md +57 -0
  95. package/docs/ai-knowledge-base/README.md +23 -0
  96. package/docs/analytics-tracking.md +37 -0
  97. package/docs/capacitor-official-plugins.md +46 -0
  98. package/docs/capawesome-plugins.md +29 -0
  99. package/docs/deployment/HOSTINGER_DEPLOY.md +370 -0
  100. package/docs/deployment/PRODUCTION-DEPLOY-CHECKLIST.md +184 -0
  101. package/docs/docs-site/plan.md +201 -0
  102. package/docs/docs-site/scope.md +127 -0
  103. package/docs/docs-site/tracker.json +235 -0
  104. package/docs/error-handling-tracking.md +37 -0
  105. package/docs/features/laravel-nova-backend/ASSESSMENT-SUMMARY.md +96 -0
  106. package/docs/features/laravel-nova-backend/IMPLEMENTATION-PLAN.md +504 -0
  107. package/docs/features/laravel-nova-backend/progress-tracker.json +184 -0
  108. package/docs/guides/testing-guide.md +15 -41
  109. package/docs/package-audit.md +41 -0
  110. package/docs/play-store/ASO-METADATA.md +5 -0
  111. package/docs/play-store/DATA-SAFETY.md +5 -0
  112. package/docs/play-store/DECLARATIONS.md +5 -0
  113. package/docs/play-store/README.md +27 -0
  114. package/docs/play-store/RELEASE-NOTES.md +99 -0
  115. package/docs/play-store/RELEASE-STEPS.md +6 -0
  116. package/docs/play-store/STORE-LISTING.md +7 -0
  117. package/docs/play-store/SUBMISSION-CHECKLIST.md +5 -0
  118. package/docs/production-readiness.md +1 -1
  119. package/docs/project-audit/2026-05-16/00-FINALIZATION-PLAN.md +123 -0
  120. package/docs/project-audit/2026-05-16/01-BATCH-PLAN.md +227 -0
  121. package/docs/project-audit/2026-05-16/02-AUDIT-FINDINGS.md +144 -0
  122. package/docs/project-audit/2026-05-16/sessions/batch-01.md +42 -0
  123. package/docs/project-audit/2026-05-16/sessions/batch-02.md +74 -0
  124. package/docs/project-audit/2026-05-16/sessions/batch-03.md +71 -0
  125. package/docs/project-audit/2026-05-16/sessions/batch-04.md +88 -0
  126. package/docs/project-audit/2026-05-16/sessions/batch-05.md +63 -0
  127. package/docs/project-audit/2026-05-16/sessions/batch-06.md +103 -0
  128. package/docs/project-audit/2026-05-16/sessions/batch-07.md +61 -0
  129. package/docs/project-audit/2026-05-16/sessions/batch-08.md +101 -0
  130. package/docs/project-audit/2026-05-16/sessions/batch-09.md +105 -0
  131. package/docs/project-audit/2026-05-16/sessions/batch-10.md +102 -0
  132. package/docs/project-audit/AUDIT-HISTORY.md +74 -0
  133. package/docs/project-audit/BATCH-PLAN.md +168 -0
  134. package/docs/project-audit/MARKETING-WEBSITE-FINDINGS-2026-05-11.md +73 -0
  135. package/docs/project-audit/PRODUCTION-READINESS-AUDIT-2026-05-08.md +275 -0
  136. package/docs/project-finalization/00-tracker.json +60 -0
  137. package/docs/project-knowledge-base/01-system-overview.md +227 -0
  138. package/docs/project-knowledge-base/02-routes-pages-forms-users.md +352 -0
  139. package/docs/project-knowledge-base/03-tech-stack-modules-services.md +379 -0
  140. package/docs/project-knowledge-base/04-data-models-integrations.md +244 -0
  141. package/docs/project-knowledge-base/05-docs-corpus-inventory.md +256 -0
  142. package/docs/project-knowledge-base/06-operations-testing-legal-content.md +208 -0
  143. package/docs/project-knowledge-base/README.md +103 -0
  144. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-05-19.md +81 -0
  145. package/docs/rules-tracker.md +102 -0
  146. package/docs/security/PRE-LAUNCH-PENTEST-CHECKLIST.md +116 -0
  147. package/docs/seo-aeo-rules.json +3043 -0
  148. package/docs/social-media-marketing/README.md +81 -0
  149. package/docs/social-media-marketing/posts-batch-01.md +613 -0
  150. package/docs/social-media-marketing/posts-batch-02.md +528 -0
  151. package/docs/social-media-marketing/whatsapp-messages-batch-01.md +458 -0
  152. package/docs/social-media-marketing/whatsapp-status-batch-01.md +355 -0
  153. package/docs/tracking/finalization-2026-05-16-tracker.json +346 -0
  154. package/docs/tracking/full-audit-tracker.json +121 -0
  155. package/docs/tracking/production-readiness-audit-tracker.json +429 -0
  156. package/docs/tracking/seo-checklist-tracker.json +333 -0
  157. package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +66 -9
  158. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +306 -52
  159. package/ios/Plugin/NativeUpdatePlugin.swift +22 -9
  160. package/ios/Plugin/Security/SecurityManager.swift +13 -14
  161. package/package.json +37 -38
  162. package/cli/node_modules/.yarn-integrity +0 -16
  163. package/cli/node_modules/commander/LICENSE +0 -22
  164. package/cli/node_modules/commander/Readme.md +0 -1148
  165. package/cli/node_modules/commander/esm.mjs +0 -16
  166. package/cli/node_modules/commander/index.js +0 -26
  167. package/cli/node_modules/commander/lib/argument.js +0 -145
  168. package/cli/node_modules/commander/lib/command.js +0 -2179
  169. package/cli/node_modules/commander/lib/error.js +0 -43
  170. package/cli/node_modules/commander/lib/help.js +0 -462
  171. package/cli/node_modules/commander/lib/option.js +0 -329
  172. package/cli/node_modules/commander/lib/suggestSimilar.js +0 -100
  173. package/cli/node_modules/commander/package-support.json +0 -16
  174. package/cli/node_modules/commander/package.json +0 -80
  175. package/cli/node_modules/commander/typings/esm.d.mts +0 -3
  176. package/cli/node_modules/commander/typings/index.d.ts +0 -884
  177. package/cli/yarn.lock +0 -8
  178. package/dist/esm/__tests__/bundle-manager.test.d.ts +0 -1
  179. package/dist/esm/__tests__/bundle-manager.test.js +0 -151
  180. package/dist/esm/__tests__/bundle-manager.test.js.map +0 -1
  181. package/dist/esm/__tests__/config.test.d.ts +0 -1
  182. package/dist/esm/__tests__/config.test.js +0 -70
  183. package/dist/esm/__tests__/config.test.js.map +0 -1
  184. package/dist/esm/__tests__/delta-processor.test.d.ts +0 -1
  185. package/dist/esm/__tests__/delta-processor.test.js +0 -77
  186. package/dist/esm/__tests__/delta-processor.test.js.map +0 -1
  187. package/dist/esm/__tests__/firestore-schema.test.d.ts +0 -1
  188. package/dist/esm/__tests__/firestore-schema.test.js +0 -74
  189. package/dist/esm/__tests__/firestore-schema.test.js.map +0 -1
  190. package/dist/esm/__tests__/integration.test.d.ts +0 -1
  191. package/dist/esm/__tests__/integration.test.js +0 -78
  192. package/dist/esm/__tests__/integration.test.js.map +0 -1
  193. package/dist/esm/__tests__/manifest-reader.test.d.ts +0 -1
  194. package/dist/esm/__tests__/manifest-reader.test.js +0 -271
  195. package/dist/esm/__tests__/manifest-reader.test.js.map +0 -1
  196. package/dist/esm/__tests__/rollout-checker.test.d.ts +0 -1
  197. package/dist/esm/__tests__/rollout-checker.test.js +0 -210
  198. package/dist/esm/__tests__/rollout-checker.test.js.map +0 -1
  199. package/dist/esm/__tests__/security.test.d.ts +0 -1
  200. package/dist/esm/__tests__/security.test.js +0 -54
  201. package/dist/esm/__tests__/security.test.js.map +0 -1
  202. package/dist/esm/__tests__/version-manager.test.d.ts +0 -1
  203. package/dist/esm/__tests__/version-manager.test.js +0 -45
  204. package/dist/esm/__tests__/version-manager.test.js.map +0 -1
  205. package/dist/esm/app-review/app-review-manager.js.map +0 -1
  206. package/dist/esm/app-review/index.js.map +0 -1
  207. package/dist/esm/app-review/platform-review-handler.js.map +0 -1
  208. package/dist/esm/app-review/review-conditions-checker.js.map +0 -1
  209. package/dist/esm/app-review/review-rate-limiter.js.map +0 -1
  210. package/dist/esm/app-review/types.js.map +0 -1
  211. package/dist/esm/app-update/app-update-checker.js.map +0 -1
  212. package/dist/esm/app-update/app-update-installer.js.map +0 -1
  213. package/dist/esm/app-update/app-update-manager.js.map +0 -1
  214. package/dist/esm/app-update/app-update-notifier.js.map +0 -1
  215. package/dist/esm/app-update/index.js.map +0 -1
  216. package/dist/esm/app-update/platform-app-update.js.map +0 -1
  217. package/dist/esm/app-update/types.js.map +0 -1
  218. package/dist/esm/background-update/background-scheduler.js.map +0 -1
  219. package/dist/esm/background-update/index.js.map +0 -1
  220. package/dist/esm/background-update/notification-manager.js.map +0 -1
  221. package/dist/esm/config/support.js.map +0 -1
  222. package/dist/esm/core/analytics.js.map +0 -1
  223. package/dist/esm/core/cache-manager.js.map +0 -1
  224. package/dist/esm/core/config.js.map +0 -1
  225. package/dist/esm/core/errors.js.map +0 -1
  226. package/dist/esm/core/event-emitter.js.map +0 -1
  227. package/dist/esm/core/logger.js.map +0 -1
  228. package/dist/esm/core/performance.js.map +0 -1
  229. package/dist/esm/core/plugin-manager.js.map +0 -1
  230. package/dist/esm/core/security.js.map +0 -1
  231. package/dist/esm/definitions.js.map +0 -1
  232. package/dist/esm/firestore/firestore-client.d.ts +0 -109
  233. package/dist/esm/firestore/firestore-client.js +0 -264
  234. package/dist/esm/firestore/firestore-client.js.map +0 -1
  235. package/dist/esm/firestore/index.d.ts +0 -11
  236. package/dist/esm/firestore/index.js +0 -11
  237. package/dist/esm/firestore/index.js.map +0 -1
  238. package/dist/esm/firestore/manifest-reader.d.ts +0 -87
  239. package/dist/esm/firestore/manifest-reader.js +0 -294
  240. package/dist/esm/firestore/manifest-reader.js.map +0 -1
  241. package/dist/esm/firestore/schema.d.ts +0 -507
  242. package/dist/esm/firestore/schema.js +0 -73
  243. package/dist/esm/firestore/schema.js.map +0 -1
  244. package/dist/esm/index.js.map +0 -1
  245. package/dist/esm/live-update/bundle-manager.js.map +0 -1
  246. package/dist/esm/live-update/certificate-pinning.js.map +0 -1
  247. package/dist/esm/live-update/delta-processor.js.map +0 -1
  248. package/dist/esm/live-update/download-manager.js.map +0 -1
  249. package/dist/esm/live-update/rollout-checker.js.map +0 -1
  250. package/dist/esm/live-update/update-manager.js.map +0 -1
  251. package/dist/esm/live-update/version-manager.js.map +0 -1
  252. package/dist/esm/plugin.js.map +0 -1
  253. package/dist/esm/security/crypto.js.map +0 -1
  254. package/dist/esm/security/validator.js.map +0 -1
  255. package/dist/esm/web.js.map +0 -1
  256. package/dist/plugin.cjs.js.map +0 -1
  257. package/dist/plugin.esm.js.map +0 -1
  258. package/dist/plugin.js.map +0 -1
  259. package/docs/FIREBASE_INTEGRATION_TRACKER.md +0 -321
  260. package/docs/FIREBASE_QUERIES_AND_INDEXES_AUDIT.md +0 -221
  261. package/docs/examples/firebase-backend-example.md +0 -27
  262. package/docs/guides/no-cost-backend-implementation-plan.md +0 -77
  263. package/docs/guides/no-cost-firestore-google-drive-backend.md +0 -60
  264. package/docs/play-console-rejection-rules.json +0 -428
  265. /package/docs/{MARKETING_WEBSITE_PLAN.md → archive/MARKETING_WEBSITE_PLAN.md} +0 -0
@@ -0,0 +1,613 @@
1
+ # Native Update — Posts Batch 01
2
+
3
+ 10 LinkedIn / Facebook posts. Each: 2700–2900 chars (~490–510 words). Hard cap because LinkedIn rejects > 3,000 chars.
4
+
5
+ Story arc: Problem → Plugin intro → OTA → Store-version check → In-app review → Backend → CLI → Example apps → v3.0.0 architecture → Getting started.
6
+
7
+ Series tag: **#NativeUpdate10** — used on every post so curious readers can pull the rest.
8
+
9
+ Mark a post as consumed: replace its heading with `USED — Post NN — …`.
10
+
11
+ ---
12
+
13
+ ## Post 01 — The 7-day fix that almost killed our launch
14
+
15
+ > "It's a one-line fix. We just need to push it." — Every mobile dev, two minutes before remembering App Store review exists.
16
+
17
+ If you've shipped a mobile app, you know the feeling. Production is on fire. A typo in a regex is rejecting half the signups. A pricing string says "$9" instead of "$19". The fix is three characters. The deploy path is **seven days**.
18
+
19
+ For a *web* product you'd ship the fix in 90 seconds and go to bed. For a *mobile* product you write a Slack apology, draft a status-page update, and pray for a fast reviewer.
20
+
21
+ I've been on the wrong side of that timer enough times that I built the thing I wished existed: **Native Update** — an MIT-licensed Capacitor plugin (and full SaaS ecosystem around it) that lets your app pull a fresh JS/HTML/CSS bundle on next launch. No resubmission required.
22
+
23
+ ### What OTA actually means (and what it does NOT)
24
+
25
+ OTA replaces the **web layer** of your hybrid app — the bundled JavaScript, HTML, and CSS that renders inside the WebView. It does **not** replace native Kotlin or Swift code, does **not** add new Capacitor plugins to a shipped binary, and does **not** circumvent App Store / Play Store policy on what you're allowed to change.
26
+
27
+ If your fix is "change the price in a React component" — OTA, 60 seconds.
28
+ If your fix is "add a new Bluetooth Capacitor plugin" — that's still a binary release.
29
+
30
+ Important boundary. A lot of "live update" pitches blur it. We don't.
31
+
32
+ ### What's in the box
33
+
34
+ - The plugin: `native-update` on NPM
35
+ - Native Kotlin (Android) + Swift (iOS) — real native code, not a JS shim
36
+ - Laravel 11 + Nova 5 SaaS backend (MIT, self-host)
37
+ - CLI for release management — one command builds, hashes, uploads, rolls out
38
+ - React marketing/dashboard site (Sentry + Clarity + Amplitude wired)
39
+ - 3 example apps as living integration tests
40
+ - 81 passing unit tests + Detox E2E suite
41
+ - MIT license throughout
42
+
43
+ This is the opener of a 10-part series (`#NativeUpdate10`). Posts 02–10 cover: ecosystem tour, OTA deep-dive, store-version checks, in-app review, the Laravel backend, CLI, example apps, v3.0.0 BREAKING story, getting started.
44
+
45
+ If you build with Capacitor and you've felt the 7-day-review handcuffs, save this post and follow the series.
46
+
47
+ ### Why this exists
48
+
49
+ The bet behind Native Update: hybrid mobile apps deserve the same iteration speed as web apps. Capacitor already has the runtime. What was missing was a credible OTA story — plugin + backend + CLI + examples — that wasn't paid-SaaS lock-in. So I built one. MIT, self-hosted, the piece that closes the loop between "I shipped a fix" and "every user has it."
50
+
51
+ **👉 Try it: `yarn add native-update` or https://nativeupdate.aoneahsan.com**
52
+
53
+ #NativeUpdate #CapacitorPlugin #OTAUpdates #Aoneahsan #TopFree
54
+
55
+ ---
56
+
57
+ ## Post 02 — What's actually in the box (Native Update, end to end)
58
+
59
+ Most "Capacitor plugin" announcements ship one thing: a TypeScript package on NPM. You install, read a 40-line README, discover the iOS side won't compile, open an issue, wait.
60
+
61
+ I wanted to ship something different. **Native Update is a monorepo, not just a package.** Eight workspaces, all MIT-licensed:
62
+
63
+ - `src/` — the Capacitor plugin (TypeScript)
64
+ - `android/` — Kotlin native implementation
65
+ - `ios/` — Swift native implementation
66
+ - `cli/` — release-management CLI
67
+ - `backend/` — Laravel 11 + Nova 5 SaaS backend
68
+ - `website/` — React + Vite marketing/dashboard
69
+ - `example-apps/` — 3 reference integrations
70
+ - `e2e/` — Detox E2E tests on real devices
71
+
72
+ Post 02 in the **`#NativeUpdate10`** series.
73
+
74
+ ### Why ecosystem instead of "just the plugin"
75
+
76
+ Every hybrid-update library I integrated before played out the same:
77
+
78
+ 1. Plugin is fine.
79
+ 2. Plugin docs assume a backend you don't have.
80
+ 3. "Recommended backend" is paid SaaS with no migration path.
81
+ 4. Six months in, you've built three quarters of a backend yourself.
82
+
83
+ So I shipped the backend in the same repo. MIT. Self-host. The plugin and CLI talk to it over HTTP — but the protocol is portable; the Express example app shows how to wrap your own service in it.
84
+
85
+ ### Three independent capabilities
86
+
87
+ The plugin exposes three things. Use one, two, or all three:
88
+
89
+ 1. **Live / OTA updates** — pull a fresh bundle on next launch
90
+ 2. **App-store update checks** — detect users on stale binaries, soft nudge or hard gate
91
+ 3. **In-app review prompts** — wrap iOS `SKStoreReviewController` and Google Play In-App Review
92
+
93
+ Each has its own API surface, its own native implementations in `android/` and `ios/`, and its own unit tests. None depends on the others.
94
+
95
+ ### What's in the box, in detail
96
+
97
+ - The plugin: `native-update` on NPM, Capacitor SDK
98
+ - Native Kotlin (Android) — real Kotlin, full atomic-swap implementation, hash verification on device
99
+ - Native Swift (iOS) — same parity, same correctness
100
+ - Laravel 11 + Nova 5 backend — bundle hosting, channel + rollout management, Nova admin UI
101
+ - CLI — Node.js binary; one command does build → hash → upload → register → rollout %
102
+ - React + Vite marketing/dashboard site — Sentry + Microsoft Clarity + Amplitude wired with page-view auto-track since 2026-05-06
103
+ - Detox E2E suite — runs the full OTA flow on real devices in CI
104
+
105
+ ### What's NOT in the box (honest disclosure)
106
+
107
+ - No native code OTA — JS/HTML/CSS only
108
+ - No bypass of App Store / Play Store policy
109
+ - Not a React Native plugin (Capacitor / Ionic / hybrid-WebView only)
110
+ - Not free-tier hostable — the Laravel backend needs a small VPS, ~$5–10/month
111
+
112
+ **👉 5-minute integration: clone the repo, `cd example-apps/react-capacitor`, `yarn && yarn dev`. https://nativeupdate.aoneahsan.com**
113
+
114
+ #NativeUpdate #Capacitor #OpenSource #Aoneahsan #BestOpenSourceCommunityProject
115
+
116
+ ---
117
+
118
+ ## Post 03 — OTA updates: the 60-second deploy path
119
+
120
+ > "Production is broken." → 60 seconds later → "Production is fixed."
121
+
122
+ Post 03 in the **`#NativeUpdate10`** series. Today: how Native Update's OTA path actually works.
123
+
124
+ ### The flow
125
+
126
+ 1. You build your web bundle (`yarn build`)
127
+ 2. The CLI hashes it, uploads to your backend, registers a release on a channel (`production` / `staging` / `canary`)
128
+ 3. The app on next launch asks the backend: "Newer release on my channel for my binary version?"
129
+ 4. If yes: download, verify SHA-256 hash, atomic swap on next start, report back
130
+ 5. If the new bundle crashes on boot: **rollback** to the prior known-good bundle automatically
131
+
132
+ That's the whole loop.
133
+
134
+ ### What you control
135
+
136
+ - **Channel** — production / staging / canary / whatever you name
137
+ - **Rollout %** — ship to 5% → watch error rate → ramp to 100%
138
+ - **Binary version constraint** — a bundle built for `2.4.x` never lands on `2.3.x`
139
+ - **Mandatory vs. optional** — block app entry until applied, or apply on next natural restart
140
+
141
+ ### What the plugin handles for you
142
+
143
+ Atomic swap (no half-applied bundles). SHA-256 verification on the device (no MITM swap on hostile coffee-shop Wi-Fi). Rollback on crash-on-boot — automatic, the prior bundle stays on disk. Background download throttling so you're not killing battery / data on cellular. Telemetry: success / fail / which release landed where.
144
+
145
+ ### Where OTA earns its keep
146
+
147
+ - Hot fixes for production JS crashers
148
+ - Copy / pricing / banner / legal text changes
149
+ - A/B tests that don't need new native capabilities
150
+ - Region-specific variants (channel-pin a subset of users)
151
+ - Fast rollbacks when a release misbehaves — flip the channel back, devices pull prior bundle next launch
152
+
153
+ ### Where OTA does NOT apply
154
+
155
+ - New native Capacitor plugins
156
+ - Anything in `Info.plist` / `AndroidManifest.xml`
157
+ - New permissions
158
+ - Anything Apple or Google would call "a different app"
159
+
160
+ I keep saying this on purpose — the OTA pitch gets fluffed in marketing, and integrators end up planning around capabilities the technology doesn't have. The boundary is real. Inside it, OTA is great. Outside it, you're shipping a binary.
161
+
162
+ ### The "but App Store policy?" question
163
+
164
+ Both Apple and Google allow JS / HTML / CSS bundle updates within hybrid apps. The constraint is: don't use OTA to deliver a fundamentally different app than the one they reviewed. Bug fixes, copy changes, A/B tests, feature flags = all fine and within policy. Pivot from a productivity app to a betting app overnight = they will notice. Be a good citizen and you'll be fine.
165
+
166
+ **👉 5 minutes against the example app: `yarn add native-update` or https://nativeupdate.aoneahsan.com**
167
+
168
+ #NativeUpdate #OTAUpdates #LiveUpdates #Aoneahsan #TopFree
169
+
170
+ ---
171
+
172
+ ## Post 04 — Your users are on v1.0. The store has v3.2. Now what?
173
+
174
+ Post 04 in the **`#NativeUpdate10`** series.
175
+
176
+ Hybrid apps live in two worlds: the web layer (you can OTA) and the native binary (you can't). Sooner or later you ship a native change — a new Capacitor plugin, a permission, a major bump — and the binary on the user's device is a generation behind the binary in the store.
177
+
178
+ OTA can't fix that. The user has to update the binary. The question is whether you ask them or surprise them.
179
+
180
+ ### The polite-nudge problem
181
+
182
+ Every mobile team has seen these tickets:
183
+ - "Feature X doesn't work for me." (User on v1.0; feature shipped in v3.0.)
184
+ - "Why does it keep crashing?" (Crash patched in v2.4; user has auto-update off.)
185
+ - "I can't sign in." (Auth library upgraded in v2.7; old binary signs incompatible JWTs.)
186
+
187
+ You can spend three engineers triaging these, or detect the version drift in the app and tell the user, in the app, that a fresh binary is waiting.
188
+
189
+ ### What the plugin does
190
+
191
+ Native Update's app-store update check exposes:
192
+ - A check call: "is there a newer binary in the store?"
193
+ - Current store version (so you can show "1.4.0 → 3.2.0")
194
+ - A boolean for "is the gap big enough to enforce an update?" — controlled by your backend, not hardcoded
195
+ - Native deep-link helpers to open App Store / Play Store
196
+
197
+ You decide the UX. The plugin gives you the signal. Common patterns:
198
+
199
+ - **Soft nudge.** Dismissible banner: "A newer version is available." User updates when convenient.
200
+ - **Hard gate.** "This version is no longer supported." Used sparingly — for security patches.
201
+ - **Educational toast.** "You're on 1.4.0. Latest is 3.2.0. Tap to see what's new."
202
+
203
+ ### The "what's new" trick
204
+
205
+ When you nudge a user, *show them why*. The plugin gives you the version string; your backend can give you the changelog. Two-line copy like "We patched the sign-in bug you hit yesterday" converts five times better than "An update is available."
206
+
207
+ ### Three patterns that work in production
208
+
209
+ 1. **Banner on every cold launch.** Dismissible, low-friction. 90% of teams should start here.
210
+ 2. **Modal every 7 days.** More aggressive — for apps where version drift causes broken-state experiences.
211
+ 3. **Hard gate at a backend-defined floor.** Reserve for security patches and "binary contains an irrecoverable bug."
212
+
213
+ The plugin gives the signal; UX and backend rules are yours.
214
+
215
+ ### Honest limits
216
+
217
+ App stores rate-limit version-check endpoints — once per session is plenty. iOS doesn't allow programmatic in-place updates; the button you show must deep-link to App Store. Android allows in-app updates via Play Core; the plugin exposes that path natively.
218
+
219
+ **👉 Wire the version check on cold launch + soft-nudge banner — cut "you should update" tickets within a week. https://nativeupdate.aoneahsan.com**
220
+
221
+ #NativeUpdate #AppStoreUpdates #MobileDev #Aoneahsan #TopFree
222
+
223
+ ---
224
+
225
+ ## Post 05 — The polite way to ask for a 5-star review
226
+
227
+ Post 05 in the **`#NativeUpdate10`** series.
228
+
229
+ iOS (since 10.3) and Android (Google Play In-App Review) both ship a **native review prompt** — a small modal that asks for a rating without yanking the user out to the store. They're rate-limited by the OS, styled to fit the platform, and the platform owners actively prefer them over custom prompts.
230
+
231
+ Native Update wraps both in a one-line API.
232
+
233
+ ### Why use the native prompt instead of building your own
234
+
235
+ - **Recommended path.** Apple's HIG says use `SKStoreReviewController`. Google says use Play In-App Review. Doing your own is harder and gains nothing.
236
+ - **Silent on failure.** If the user already rated, or OS rate-limit kicks in, the prompt doesn't show. No spam.
237
+ - **Inline.** Whole review happens without leaving your app. Tap stars, write a sentence, submit, back to your app.
238
+ - **Trusted UI.** Users have seen this exact modal on twenty other apps.
239
+
240
+ ### The capability surface
241
+
242
+ ```ts
243
+ if (await NativeUpdate.canRequestReview()) {
244
+ await NativeUpdate.requestReview();
245
+ }
246
+ ```
247
+
248
+ Two lines. Cross-platform branching for free.
249
+
250
+ ### When to ask
251
+
252
+ Don't ask:
253
+ - On first open (no opinion yet)
254
+ - After an error (you'll get one star)
255
+ - During checkout (you'll lose the conversion)
256
+
257
+ Do ask:
258
+ - After a *successful* completion of the user's primary task
259
+ - After 3+ sessions
260
+ - Never twice in one session (the OS rate-limits anyway)
261
+
262
+ A canonical pattern: "Did the user just finish their second-or-greater positive flow? Has it been more than a week since the last ask? Yes → request." Two booleans, one if-statement, ship it.
263
+
264
+ ### What this is NOT
265
+
266
+ - Not a custom review form (the OS owns the form)
267
+ - Not a way to force a 5-star (the user can submit any rating)
268
+ - Not a way to detect what they rated — by design, Apple and Google don't expose this
269
+
270
+ ### What this DOES give you
271
+
272
+ - The platform-recommended prompt with one line of code
273
+ - Cross-platform branching for free
274
+ - A `canRequest` helper so you can plan UI without tripping OS rate limits
275
+ - Clean fallback if the OS suppresses the prompt (you keep going; nothing breaks)
276
+
277
+ ### Real-world wiring example
278
+
279
+ E-commerce app: trigger after the user's *second* successful order, not their first. They've experienced the loop twice; one good experience could be luck, two is a pattern.
280
+
281
+ Content app: trigger after the user has consumed N pieces of content AND opened the app on M+ different days.
282
+
283
+ Fitness app: trigger after the user's first completed workout streak (e.g., 3 days in a row).
284
+
285
+ The plugin doesn't care — it gives you `requestReview()`. *When* you call it is product judgment.
286
+
287
+ **👉 Find your "user just succeeded" moment, drop in `requestReview()` after it. https://nativeupdate.aoneahsan.com**
288
+
289
+ #NativeUpdate #InAppReview #MobileUX #Aoneahsan #SaaSApp
290
+
291
+ ---
292
+
293
+ ## Post 06 — Laravel + Nova: the admin backend the plugin ships with
294
+
295
+ Post 06 in the **`#NativeUpdate10`** series.
296
+
297
+ Most Capacitor live-update plugins make you bring your own backend, then sell you a paid one when you give up. I shipped one in the same MIT-licensed repo.
298
+
299
+ ### Why Laravel 11 + Nova 5
300
+
301
+ - **Why a real framework instead of "a few Express routes?"** Hosting bundles + managing channels + rollouts + version-gating + admin UI is a CRUD problem with auth, validation, queues, and storage. Frameworks are good at CRUD problems.
302
+ - **Why Laravel?** Long-term ecosystem. Robust validation. Eloquent for the data layer. Queue for background work. Storage abstraction that doesn't lock you to one provider. Stable major versions. Predictable deploy.
303
+ - **Why Nova?** Admin UI is half the work. Nova gives you CRUD UI for releases, channels, devices, and analytics in hours, not weeks.
304
+
305
+ ### What the backend exposes
306
+
307
+ - Releases endpoint (the device asks "newer release on my channel?")
308
+ - Bundle download endpoint (signed, hash-checkable, served via Storage)
309
+ - Telemetry ingest (devices report success / fail of update applications)
310
+ - Admin endpoints (Nova-backed CRUD on releases, channels, rollouts, version constraints)
311
+ - Auth (token-based for the dashboard, signed-URL pattern for bundles)
312
+
313
+ ### What's in Nova admin
314
+
315
+ Releases (create / list / detail / rollback). Channels. Devices (which release they're on, last-seen, platform). Apps (multi-app config). Analytics dashboards (preferences, /me, rollouts) — added in v3.0.0.
316
+
317
+ ### What's NOT in the backend
318
+
319
+ No paywall. No cloud lock-in. No "free tier with rate limits that punish you for succeeding." No required third-party services. Storage / queues / cache are all pluggable.
320
+
321
+ ### Self-hosting reality check
322
+
323
+ Small VPS (1 vCPU, 2 GB RAM) handles thousands of devices for the bundle-distribution workload. Expensive part is bandwidth — bundles are small (200 KB–1 MB), but 100k DAU × 500 KB = ~50 GB egress per release. Use a CDN. Cheap part is everything else — Laravel + Nova are dead boring to operate, which is exactly what you want from infrastructure.
324
+
325
+ ### Why "ships with a backend" matters more than it sounds
326
+
327
+ Most plugin authors stop at the npm package. They list endpoints in the README and say "implement these." Six months later, the abandoned issue tracker has a dozen "any backend recommendations?" questions. Native Update gives you the reference implementation, in the same repo, MIT-licensed, with the same release cadence as the plugin. Decoupled enough that you can swap it; integrated enough that the protocol can never drift.
328
+
329
+ **👉 Clone the repo, `cd backend`, `docker compose up`, you're running. https://nativeupdate.aoneahsan.com**
330
+
331
+ #NativeUpdate #Laravel #LaravelNova #Aoneahsan #SaaSApp
332
+
333
+ ---
334
+
335
+ ## Post 07 — The CLI: one command, one rolled-out bundle
336
+
337
+ > The fewer steps between "code committed" and "users on the new bundle," the more you'll actually ship.
338
+
339
+ Post 07 in the **`#NativeUpdate10`** series.
340
+
341
+ Every release path I've seen die slowly died the same way: too many manual steps. "Build, then upload, then SSH, then update a config row, then bump a version, then notify ops." Six steps becomes weekly batches becomes "we don't really do live updates."
342
+
343
+ The Native Update CLI collapses that into one command.
344
+
345
+ ### Before vs after
346
+
347
+ **Before:** 6 manual steps, two pages of Confluence runbook, prayer.
348
+
349
+ **After:**
350
+
351
+ ```bash
352
+ nativeupdate release \
353
+ --channel production \
354
+ --rollout 10 \
355
+ --binary "2.4.x"
356
+ ```
357
+
358
+ Builds the web bundle. Computes SHA-256. Authenticates. Uploads. Registers the release. Sets rollout %. Pins the binary-version constraint. Returns release ID + a one-line "ramp to 100%" command.
359
+
360
+ ### The four CLI muscles
361
+
362
+ 1. **`release`** — the 90% case (above)
363
+ 2. **`rollback <release-id>`** — flip a channel back; devices pull prior bundle next launch
364
+ 3. **`promote --from staging --to production`** — promote between channels; metadata preserved
365
+ 4. **`status`** — show active release on each channel + what's queued
366
+
367
+ ### The auth model
368
+
369
+ Backend-issued token, scoped to an app + a list of channels. CI uses a token with rights to push to staging/canary; a human uses one with production rights. Two-key reality. Tokens revocable from Nova admin.
370
+
371
+ ### Why this isn't "just a bash script"
372
+
373
+ Started as one. Got promoted when:
374
+
375
+ - Hash verification needed proper retries
376
+ - Bundle uploads needed resumable / chunked transfers for slow links
377
+ - Rollout management needed atomicity (two CI jobs landing at once shouldn't race)
378
+ - Operators wanted a `--dry-run` before pulling the trigger
379
+
380
+ ### Where this fits in CI
381
+
382
+ Build job → produces `dist/`. Test job → must pass. Release-staging → `nativeupdate release --channel staging --rollout 100` on every successful main merge. Release-canary → manual trigger, `--rollout 5`. Release-production → manual, gradual `--rollout 10 → 50 → 100`.
383
+
384
+ ### A typical week with the CLI
385
+
386
+ Monday: `release --channel staging --rollout 100` after merging the week's PRs.
387
+ Tuesday: QA team flags a regression on staging. `rollback`, fix the bug, `release` again.
388
+ Wednesday: `promote --to production --rollout 5`. Watch Sentry.
389
+ Thursday: `--rollout 50`. Watch some more.
390
+ Friday: `--rollout 100`. Done. Drinks.
391
+
392
+ That's the rhythm. The CLI is the thing that makes it possible. The fewer keystrokes between your code and your users, the more often you'll actually push.
393
+
394
+ **👉 Replace your manual upload step today and reclaim half a Friday a month. https://nativeupdate.aoneahsan.com**
395
+
396
+ #NativeUpdate #DevOps #CLI #Aoneahsan #TopFree
397
+
398
+ ---
399
+
400
+ ## Post 08 — Three example apps, because you shouldn't trust a plugin without them
401
+
402
+ Post 08 in the **`#NativeUpdate10`** series.
403
+
404
+ My filter for adopting a new mobile plugin: **is there an example app, and does it run?** If yes to both, the plugin is real. If either is no, I'm cautious.
405
+
406
+ Native Update ships three example apps in the monorepo. Maintained alongside the plugin. Living integration tests.
407
+
408
+ ### example-apps/react-capacitor
409
+
410
+ The canonical one. Vite + React + Capacitor, integrated end-to-end.
411
+
412
+ What it demonstrates:
413
+ - Wiring `native-update` into `App.tsx`
414
+ - Configuring channels and binary version in `capacitor.config.ts`
415
+ - `checkForUpdate()` on launch
416
+ - "Downloading…" UI while a bundle pulls in the background
417
+ - Handling the post-update reload
418
+ - Manual "check now" button for testing rollouts
419
+ - `requestReview()` after a contrived "successful action"
420
+
421
+ If you've never integrated the plugin, this is the example you copy from.
422
+
423
+ ### example-apps/node-express
424
+
425
+ A small Express service mimicking the Laravel backend's HTTP surface.
426
+
427
+ Why it exists: some integrators want to validate the plugin against their own backend before adopting Laravel. The Express example documents the exact endpoints they need to implement. It's not the production answer — it's a blueprint.
428
+
429
+ ### example-apps/firebase-backend
430
+
431
+ The historical Firestore-direct path was removed in v3.0.0 (post 09 is that story). The Firebase example *remains* as a reference for integrators who want the Native Update protocol wrapped around Firebase functions on top of Firestore data they own.
432
+
433
+ The plugin itself talks Laravel-shaped HTTP. The example shows the protocol can wrap any backend you control.
434
+
435
+ ### Why three and not one
436
+
437
+ Each app exercises a different backend posture:
438
+ - React-Capacitor → canonical Laravel backend
439
+ - Node-Express → hand-rolled implementation of the protocol
440
+ - Firebase-backend → Firebase-functions wrapper
441
+
442
+ If the plugin works against all three, the protocol is portable. That's the design constraint.
443
+
444
+ ### What the apps catch
445
+
446
+ API drift. Compilation breaks on Capacitor major bumps. Bundle-format regressions. iOS / Android divergences when one platform's native code changes. They're not a substitute for the 81 unit tests + Detox E2E suite, but they're a substitute for "I tried the plugin in a real app and the wheels fell off."
447
+
448
+ A plugin without an example app is a plugin you'll be integrating at 2 AM with zero reference for what "working" actually looks like.
449
+
450
+ **👉 Clone the monorepo, `cd example-apps/react-capacitor`, `yarn && yarn dev` — working integration in 5 min. https://nativeupdate.aoneahsan.com**
451
+
452
+ #NativeUpdate #Capacitor #OpenSource #Aoneahsan #BestOpenSourceCommunityProject
453
+
454
+ ---
455
+
456
+ ## Post 09 — Why we deleted 3,000 lines of Firestore (the v3.0.0 story)
457
+
458
+ > "The best architecture decision is the one you can describe in one sentence."
459
+
460
+ Post 09 in the **`#NativeUpdate10`** series.
461
+
462
+ Native Update v3.0.0 was a deliberate BREAKING release. ~3,000 lines deleted. The plugin SDK and the website both refactored to talk only to the Laravel HTTP API. v2.x integrators on the Firestore path had to migrate.
463
+
464
+ We don't take BREAKING releases lightly. Here's the reasoning, with all the trade-offs.
465
+
466
+ ### What v2.x looked like
467
+
468
+ The plugin supported two backend postures:
469
+ 1. **Laravel HTTP** — the canonical backend
470
+ 2. **Firestore direct** — the device read release metadata directly via Firebase SDK
471
+
472
+ On paper this was flexible. In practice it created a shadow API surface: every backend behavior implemented twice, authorization rules modeled in two places, telemetry ingested in two places, tests covering two paths.
473
+
474
+ ### The cost of "two right ways"
475
+
476
+ - **Surface duplication.** Every release-metadata change required updates in both paths.
477
+ - **Test matrix explosion.** "Does this work on Laravel? On Firestore? When I switch?"
478
+ - **Onboarding friction.** New integrators wasted time deciding which path before integrating.
479
+ - **Documentation rot.** Two paths means two doc trees, one always out of date.
480
+ - **Operational opacity.** Diagnosing a v2.x bug started with "which backend are you on?"
481
+
482
+ The plugin was carrying ~3,000 lines to support a path that was complicating every other decision.
483
+
484
+ ### Why removal won
485
+
486
+ - **Laravel was already feature-complete.** Anything Firestore did, Laravel already did, often better.
487
+ - **Single source of truth.** One backend = one authorization model, one telemetry ingest, one set of release-metadata semantics.
488
+ - **Cleaner mental model.** "Native Update talks HTTP to a Laravel backend you control." One sentence. Done.
489
+ - **Test suite shrunk by ~40%.** Every remaining test is more meaningful.
490
+ - **Documentation halved.**
491
+
492
+ ### What integrators on Firestore lost
493
+
494
+ Honest list:
495
+ - "No extra service to run" — Firestore-direct was attractive because teams already had Firebase
496
+ - A few minor knobs that made sense in Firestore but didn't translate cleanly
497
+
498
+ ### What integrators got
499
+
500
+ Simpler integration surface. Stable, predictable API. A real admin (Nova UI, not "write Firestore queries"). Server-side-only secrets. Faster plugin releases (every change reasoned about in one model).
501
+
502
+ ### The lesson
503
+
504
+ If you maintain "two right ways" inside one library and one is consistently winning on every axis (test coverage, doc clarity, ops sanity, integrator velocity), the other isn't a feature — it's a tax.
505
+
506
+ **👉 v2.x users: read `docs/MIGRATION.md`, schedule the upgrade, all new features land in v3.x. https://nativeupdate.aoneahsan.com**
507
+
508
+ #NativeUpdate #SoftwareArchitecture #BreakingChanges #Aoneahsan #BestOpenSourceCommunityProject
509
+
510
+ ---
511
+
512
+ ## Post 10 — Five-minute integration: from `yarn add` to your first OTA
513
+
514
+ Post 10 — final in the **`#NativeUpdate10`** series. The actual five-minute walkthrough.
515
+
516
+ ### Pre-reqs
517
+
518
+ - A Capacitor app you control
519
+ - A backend URL where Native Update is running (self-host the Laravel from `backend/`, or your own service speaking the protocol)
520
+ - An app token from your backend
521
+
522
+ ### Step 1 — Install
523
+
524
+ ```bash
525
+ yarn add native-update
526
+ npx cap sync
527
+ ```
528
+
529
+ Plugin installed, iOS pod install runs, Android Gradle module linked.
530
+
531
+ ### Step 2 — Configure
532
+
533
+ In `capacitor.config.ts`:
534
+
535
+ ```ts
536
+ plugins: {
537
+ NativeUpdate: {
538
+ backendUrl: 'https://updates.your-domain.com',
539
+ appKey: process.env.NATIVE_UPDATE_APP_KEY,
540
+ channel: 'production',
541
+ autoCheck: true,
542
+ },
543
+ }
544
+ ```
545
+
546
+ ### Step 3 — Wire the API
547
+
548
+ ```ts
549
+ import { NativeUpdate } from 'native-update';
550
+
551
+ // On launch:
552
+ const r = await NativeUpdate.checkForUpdate();
553
+ if (r.updateAvailable) await NativeUpdate.downloadAndApply();
554
+
555
+ // Stale binary check:
556
+ const v = await NativeUpdate.getStoreVersion();
557
+ if (v.updateRecommended) showSoftNudgeBanner(v.latestVersion);
558
+
559
+ // After a successful action:
560
+ if (await NativeUpdate.canRequestReview()) {
561
+ await NativeUpdate.requestReview();
562
+ }
563
+ ```
564
+
565
+ Three calls, three independent capabilities.
566
+
567
+ ### Step 4 — Build a release
568
+
569
+ ```bash
570
+ yarn build
571
+ nativeupdate release --channel staging --rollout 100 --binary "1.0.x"
572
+ ```
573
+
574
+ CLI builds, hashes, uploads, registers. Returns release ID.
575
+
576
+ ### Step 5 — Verify
577
+
578
+ Open the app on a test device. Plugin checks backend, sees newer release on `staging`, downloads, applies on next start. Restart. You're on the new bundle.
579
+
580
+ ### Step 6 — Promote to production
581
+
582
+ ```bash
583
+ nativeupdate promote --from staging --to production --rollout 10
584
+ # watch error rate for an hour
585
+ nativeupdate promote --rollout 50
586
+ nativeupdate promote --rollout 100
587
+ ```
588
+
589
+ ### Common first-time gotchas
590
+
591
+ - **Hash mismatch** → re-built but didn't re-upload. Re-run `release`.
592
+ - **iOS doesn't see the update** → missed `npx cap sync`. Re-sync, rebuild in Xcode.
593
+ - **"No update" but there is one** → channel mismatch.
594
+ - **Crash after apply** → rollback kicks in automatically. Check Sentry.
595
+
596
+ ### After integration
597
+
598
+ - Add a "tap to check for updates" button in Settings for power users
599
+ - Wire `requestReview()` after your strongest "user succeeded" moment
600
+ - Wire store-update-check on cold launch with a soft-nudge banner
601
+ - Add Sentry — when an OTA bundle breaks, you want to see it before users do
602
+
603
+ **👉 Five steps. Five minutes. Run them today. `yarn add native-update` or https://nativeupdate.aoneahsan.com**
604
+
605
+ End of `#NativeUpdate10`. If a teammate is stuck on a 7-day review queue, share the package with them. Save them a week.
606
+
607
+ #NativeUpdate #GettingStarted #CapacitorPlugin #Aoneahsan #TopFree
608
+
609
+ ---
610
+
611
+ ## End of Posts Batch 01
612
+
613
+ 10 posts, each ~2700–2900 chars, ready for LinkedIn / Facebook. Mark `USED — ` once shared.