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,528 @@
1
+ # Native Update — Posts Batch 02
2
+
3
+ 10 LinkedIn / Facebook posts, batch 02. Each: 2700–2900 chars. Different angles from batch 01.
4
+
5
+ Series tag: **#NativeUpdateInside** (a "behind the scenes / advanced" companion arc to the `#NativeUpdate10` introductory series).
6
+
7
+ Mark consumed: replace heading with `USED — Post NN — …`.
8
+
9
+ ---
10
+
11
+ ## Post 01 — Why I built Native Update (founder note)
12
+
13
+ > "Why are you building a Capacitor OTA plugin in 2026? Hasn't someone already done this?"
14
+
15
+ I get this question a lot. Worth answering plainly.
16
+
17
+ I ship a portfolio of mobile apps on the Capacitor stack. For years, the OTA story on Capacitor felt like the third-party Wild West. The two patterns were:
18
+
19
+ 1. **DIY** — write your own bundle pull, hash check, atomic swap, rollback, telemetry. About 4 weeks of engineer time you don't have. Then maintain it forever.
20
+ 2. **Paid SaaS lock-in** — sign up for a hosted live-update service. Pay per device. Upload your bundles to their cloud. Hope they don't sunset the product or change pricing.
21
+
22
+ Both are bad trades. The first eats your runway. The second hands strategic infrastructure to a vendor you can't easily replace.
23
+
24
+ So I built the third option: **Native Update — MIT-licensed plugin + reference Laravel backend you self-host.** No per-device fees. No vendor lock-in. The plugin and the backend ship from the same monorepo and stay in sync because the same author writes both.
25
+
26
+ ### What the project costs me
27
+
28
+ Real talk on sustainability — this matters if you're picking infrastructure.
29
+
30
+ - **Time** — significant. v3.0.0 alone was ~3,000 LOC deletions and a dual-backend → single-backend migration
31
+ - **Money** — minimal. Self-hosted backend on a small VPS. Marketing site on Firebase Hosting (free tier)
32
+ - **Motivation** — strong. I use Native Update on my own projects. If I stop maintaining it, my own apps break
33
+
34
+ ### What you can expect
35
+
36
+ - Continuous maintenance because I'm the largest user
37
+ - A clear changelog and migration path on BREAKING releases (v3.0.0 has one in `docs/MIGRATION.md`)
38
+ - An MIT license that lets you fork the entire monorepo if I ever go silent
39
+ - A 7-day full-audit cooldown that keeps churn out of the commit log
40
+
41
+ ### What you should NOT expect
42
+
43
+ - 24/7 enterprise support (this is a community-maintained MIT project)
44
+ - An SLA-backed delivery guarantee (you self-host; you own uptime)
45
+ - A magical hosted-SaaS option (it's on the roadmap; not shipped yet)
46
+
47
+ ### Where this matters most
48
+
49
+ The biggest risk for small / mid-size teams: building your release pipeline on a vendor that might disappear or 10x its pricing next quarter. MIT-licensed, self-hosted infrastructure is the antidote — your release path keeps working even if I stop maintaining the project. The code is yours to fork.
50
+
51
+ If "MIT, self-hosted, author dog-foods it on their own apps" is the trade you want, this is your plugin. If you'd rather pay for managed convenience, hosted SaaS exists and serves that market — Native Update isn't competing there.
52
+
53
+ `#NativeUpdateInside` 01 of 10 — behind-the-scenes arc complementing the introductory `#NativeUpdate10` series.
54
+
55
+ **👉 https://nativeupdate.aoneahsan.com**
56
+
57
+ #NativeUpdate #FounderStory #OpenSource #Aoneahsan #BestOpenSourceCommunityProject
58
+
59
+ ---
60
+
61
+ ## Post 02 — How Native Update compares to other Capacitor OTA options
62
+
63
+ Honest comparison post. No fanboy energy. If you're picking an OTA tool for a Capacitor app, here's the landscape.
64
+
65
+ ### Capgo (capgo.app)
66
+
67
+ Mature, hosted SaaS, paid tiers. Solid product. Real engineering behind it. Pricing scales with active devices, which is the right model for a hosted service.
68
+
69
+ When Capgo wins: you want zero-ops; you'd rather pay than self-host; you're an SMB whose first 10k devices fit in their free tier.
70
+
71
+ When Native Update wins: you want MIT, self-hosted, no per-device fee; you're enterprise and can't put bundles on a third-party cloud; you want to fork the backend.
72
+
73
+ ### Capacitor's own Live Updates
74
+
75
+ Ionic offers a Live Updates product (paid, tied to Appflow). Mature, well-documented, but tightly bound to the Ionic / Appflow ecosystem.
76
+
77
+ When Live Updates wins: you're already paying for Appflow.
78
+
79
+ When Native Update wins: you don't want vendor lock-in to Ionic's hosted services.
80
+
81
+ ### DIY
82
+
83
+ Roll your own with a CDN + hash check + atomic swap script.
84
+
85
+ When DIY wins: you have a unique constraint that none of the off-the-shelf options support.
86
+
87
+ When Native Update wins: you're tempted to DIY because everything off-the-shelf is paid SaaS, but you'd actually take an MIT-licensed reference if it existed.
88
+
89
+ ### What Native Update brings to the table
90
+
91
+ - MIT-licensed end-to-end (plugin, native code, CLI, backend, examples)
92
+ - Real native Kotlin / Swift, not a JS shim
93
+ - A reference Laravel backend in the same repo
94
+ - 81 unit tests + Detox E2E
95
+ - 3 example apps validating the protocol against 3 backend postures
96
+ - v3.0.0 single-backend architecture (one mental model)
97
+ - 7-day audit cooldown (mature ops cadence)
98
+
99
+ ### What it doesn't bring
100
+
101
+ - A hosted SaaS option (yet — on the roadmap, not shipped)
102
+ - A 24/7 support contract
103
+ - Years of "thousands of independent integrators" social proof — that's still building
104
+
105
+ ### A decision framework
106
+
107
+ Ask yourself in this order:
108
+
109
+ 1. Is your release infrastructure strategic enough to own? If yes → self-host (Native Update). If no → managed SaaS (Capgo).
110
+ 2. Are you willing to operate a Laravel backend on a VPS? If yes → Native Update. If no → Capgo.
111
+ 3. Do you need to fork the entire stack on day one? If yes → Native Update (MIT). If no → either works.
112
+ 4. Are you in a regulated environment that can't put bundles on a third-party cloud? If yes → Native Update. If no → either works.
113
+
114
+ Most teams cluster on either "fully managed" or "fully self-hosted." Native Update is uncompromisingly the second. Capgo is uncompromisingly the first. Pick the one that matches your operational posture, not the one with the louder marketing.
115
+
116
+ Pick by trade-off, not by hype. If MIT + self-host fits, this is the package.
117
+
118
+ **👉 `yarn add native-update` or https://nativeupdate.aoneahsan.com**
119
+
120
+ #NativeUpdate #Comparison #Capacitor #Aoneahsan #TopFree
121
+
122
+ ---
123
+
124
+ ## Post 03 — The security model: bundle hashes, signed URLs, threat model
125
+
126
+ `#NativeUpdateInside` 03 of 10.
127
+
128
+ Updating a hybrid app's JS bundle from a remote server has a real threat surface. Most "live update" pitches gloss over it. Here's exactly what Native Update does — and what it doesn't.
129
+
130
+ ### The threats we model
131
+
132
+ 1. **Hostile network** — attacker on the user's Wi-Fi (coffee shop, airport, compromised home router) tries to swap your bundle for malicious JS during download.
133
+ 2. **Compromised CDN** — your bundle host is compromised; attacker uploads a bad bundle in place of yours.
134
+ 3. **Stale bundle replay** — attacker captures an old bundle and tries to force the device to apply it (downgrade attack).
135
+ 4. **Wrong-bundle delivery** — server bug or operator mistake serves a bundle to the wrong channel / wrong binary version.
136
+
137
+ ### What Native Update does about each
138
+
139
+ 1. **Hostile network → SHA-256 hash verification.** The CLI computes the SHA-256 of the bundle at upload time and stores it with the release record. The device re-computes the hash after download and refuses to apply if it doesn't match. A swapped bundle fails the check.
140
+ 2. **Compromised CDN → server-stored hashes.** The hash lives in the database (not in the bundle URL or its metadata file on the CDN). An attacker who compromises the CDN alone cannot change what hash the device expects — they'd also need to compromise the backend.
141
+ 3. **Stale bundle replay → version + release-ID gating.** The device records the release ID it last applied and checks that the offered release is newer. A captured-and-replayed older bundle is rejected.
142
+ 4. **Wrong-bundle delivery → channel + binary-version constraints on the server.** The release record carries a channel and a binary-version constraint. The device passes its channel + binary version on every check; the server only offers releases that match.
143
+
144
+ ### What Native Update does NOT do (be honest about this)
145
+
146
+ - **No code signing of the bundle itself.** The hash check + HTTPS transport is your integrity story. If you need code-sign-grade assurance, layer your own signing on top — the protocol is open.
147
+ - **No "user-level" auth on bundle download by default.** Bundles are typically signed-URL gated by the backend. If you need per-user auth, you can wire that in via the protocol.
148
+ - **No bypass of network-stack TLS.** If your backend's TLS is broken, that's your problem; Native Update assumes HTTPS works.
149
+
150
+ ### Why this matters
151
+
152
+ A plugin that updates JS at runtime is a plugin that can compromise your entire app at runtime. The hash + version-gating pattern Native Update uses is the minimum bar — but it IS that bar, by default, with no special configuration. Don't skip the threat-model conversation when you adopt any OTA tool.
153
+
154
+ **👉 Read the security docs: https://nativeupdate.aoneahsan.com**
155
+
156
+ #NativeUpdate #Security #ThreatModel #Aoneahsan #SaaSApp
157
+
158
+ ---
159
+
160
+ ## Post 04 — Common OTA mistakes I see teams make
161
+
162
+ `#NativeUpdateInside` 04. Pattern-recognition from helping teams adopt OTA on hybrid apps. The same handful of mistakes show up over and over.
163
+
164
+ ### Mistake 1: marking everything mandatory
165
+
166
+ The temptation is "I want users on the latest, so every release is mandatory." The cost: every mandatory update is a chance for the user to bounce out at the worst moment. They opened the app to do one thing, got blocked on a force-update screen, lost goodwill.
167
+
168
+ Fix: optional by default. Mandatory only for security patches and "binary contains an irrecoverable bug" emergencies.
169
+
170
+ ### Mistake 2: skipping canary
171
+
172
+ "It's a small change, ship it to 100% of production." Then 0.3% of devices crash on boot, you get 30 angry tickets in 20 minutes, and you're rolling back at 3 AM.
173
+
174
+ Fix: canary every release (5–10%), watch Sentry for an hour, then ramp. The CLI's `promote --rollout` flow is built for this. 26 hours from staging to 100% is the right pace, not 5 minutes.
175
+
176
+ ### Mistake 3: shipping without Sentry
177
+
178
+ If your OTA bundle breaks on a subset of devices and you have no error monitoring, you'll find out via support tickets — hours late, with no diagnostic context.
179
+
180
+ Fix: tag every Sentry event with the Native Update release ID. Two lines:
181
+
182
+ ```ts
183
+ const release = await NativeUpdate.getCurrentRelease();
184
+ Sentry.setTag('nativeupdate.release', release.id);
185
+ ```
186
+
187
+ You'll see "release X-Y is throwing for these users" in Sentry within minutes of the rollout.
188
+
189
+ ### Mistake 4: trying to OTA native changes
190
+
191
+ "We added a new Capacitor plugin and want to push it via OTA." It doesn't work. New plugins, new permissions, anything in `Info.plist` / `AndroidManifest.xml` are binary releases. The plugin can't help. Plan for a binary release, OTA the rest.
192
+
193
+ ### Mistake 5: no release-version display in the app
194
+
195
+ When debugging "user says feature X is broken," your first question is "what release are they on?" If your app doesn't display the Native Update release ID somewhere (settings screen, About page), you can't answer that.
196
+
197
+ Fix: show `getCurrentRelease().id` in your About screen. 5 lines of code. Saves hours of triage.
198
+
199
+ ### Mistake 6: confusing channels with feature flags
200
+
201
+ Channels are for *release distribution*. Feature flags are for *runtime conditional logic within a release*. Use channels for "should this device get this bundle?" and a feature-flag system (LaunchDarkly, Statsig, your own backend) for "should this user see this UI?". Different tools, different problems.
202
+
203
+ ### Mistake 7: no rollback rehearsal
204
+
205
+ You only learn how `rollback` actually works the first time you need it. Practice it on staging *before* the production fire.
206
+
207
+ **👉 Avoid the mistakes from day one: https://nativeupdate.aoneahsan.com**
208
+
209
+ #NativeUpdate #BestPractices #ReleaseManagement #Aoneahsan #TopFree
210
+
211
+ ---
212
+
213
+ ## Post 05 — Multi-app Native Update: one backend, many apps
214
+
215
+ `#NativeUpdateInside` 05.
216
+
217
+ A pattern more teams adopt as their app portfolio grows: **one Native Update backend serving multiple apps.**
218
+
219
+ ### The setup
220
+
221
+ Each app gets:
222
+ - Its own app key (generated from Nova admin)
223
+ - Its own channels (`production-app-A`, `staging-app-A`, `production-app-B`, etc. — or just rely on the app-key namespace)
224
+ - Its own binary-version space
225
+ - Its own release history
226
+
227
+ But shares:
228
+ - One Laravel + Nova install
229
+ - One database
230
+ - One CDN / Storage bucket (with key-prefixed paths)
231
+ - One operations footprint
232
+
233
+ ### Why this is the right pattern for portfolio teams
234
+
235
+ - **Single ops surface.** One backend to monitor, patch, and back up.
236
+ - **Single Nova admin.** Operators see all apps in one place. Switching is a dropdown.
237
+ - **Shared infrastructure cost.** A small VPS that handles 10k devices for one app handles 10k for ten apps just as well. The expensive part is bandwidth, which scales linearly per app.
238
+ - **Single auth model.** Token scoping happens per app + per channel; one token system covers everything.
239
+ - **Easier policy enforcement.** Want every app in the portfolio to have a 7-day staging soak before promote-to-production? One operational rule, applied across all apps.
240
+
241
+ ### The Nova admin model
242
+
243
+ Nova's resource UI handles the multi-app case naturally. Each App resource owns its Channels, Releases, and Devices. The relationship hierarchy is:
244
+
245
+ ```
246
+ App
247
+ ├── Channels (production / staging / canary / custom)
248
+ │ └── Releases (versioned bundles)
249
+ │ └── DeviceTelemetry (which device on which release)
250
+ ```
251
+
252
+ You browse by app first, then drill in. Operators never see app B's data when working on app A.
253
+
254
+ ### When NOT to multi-app a single backend
255
+
256
+ - **Compliance separation.** If app A handles PHI and app B doesn't, separate backends make audit boundaries cleaner.
257
+ - **Wildly different scale.** If app A pushes 10x the traffic of every other app combined, dedicated infra is easier to reason about.
258
+ - **Independent ownership.** If two different teams own two apps and can't agree on backend ops, separate them.
259
+
260
+ ### Real numbers
261
+
262
+ A small VPS (1 vCPU, 2 GB RAM) running the Laravel backend handles bundle distribution for tens of thousands of devices across many apps comfortably. The bottleneck is bandwidth — a CDN in front of bundle storage solves that. Compute is essentially free at this scale; you're paying for storage and egress, both commodity-priced and predictable.
263
+
264
+ The numbers reality is the opposite of what most teams expect: the *backend* is cheap, the *bandwidth* is the line item. Plan accordingly when you size your CDN budget — DAU × bundle-size × release-frequency is your ballpark monthly egress.
265
+
266
+ **👉 Multi-app docs: https://nativeupdate.aoneahsan.com**
267
+
268
+ #NativeUpdate #Architecture #MultiApp #Aoneahsan #SaaSApp
269
+
270
+ ---
271
+
272
+ ## Post 06 — A quick tour of the Nova admin
273
+
274
+ `#NativeUpdateInside` 06.
275
+
276
+ Nova is the admin layer of the Native Update backend. If you've never used Laravel Nova, here's what you get out of the box, no extra UI work.
277
+
278
+ ### What Nova gives you
279
+
280
+ - A clean, opinionated CRUD interface
281
+ - Resource pages (Apps, Channels, Releases, Devices, etc.) with list / detail / edit views
282
+ - Filters, search, batch actions
283
+ - Permissions (admin / operator / read-only)
284
+ - Activity log (who promoted what, when)
285
+ - Custom Nova actions for domain operations (rollback, promote-between-channels)
286
+ - Dashboards (rollout progress, device distribution)
287
+
288
+ ### The screens you'll use most
289
+
290
+ **Releases.** A table of every release ever, filterable by app + channel + status. Click a row → full release detail (bundle hash, size, upload time, rollout %, current device distribution). One-click rollback action.
291
+
292
+ **Channels.** Per-app list of channels and their currently-active release. Promote actions live here.
293
+
294
+ **Devices.** A telemetry view — one row per device, showing app, current release, last-seen, platform, crash status. Filter by "stuck on old release" or "failed last update apply" to spot rollout issues.
295
+
296
+ **Apps.** Top-level config. Generate app keys, set CDN base URLs, configure default channel.
297
+
298
+ ### Why Nova vs a custom dashboard
299
+
300
+ I built `website/` as a marketing/dashboard site too — but Nova covers the *operator* use case (CRUD on releases / channels / devices) better than any custom UI I'd hand-roll. The website is for end-customer-facing dashboards (read-only, polished). Nova is for operations (full power, less pretty, that's fine).
301
+
302
+ Splitting the UI like this was the right call. Nova handles 95% of operator work in zero UI engineering. The website handles customer-facing work where you'd invest in UI anyway.
303
+
304
+ ### Operator setup in 5 minutes
305
+
306
+ 1. Backend up (`docker compose up`)
307
+ 2. `php artisan nova:user` to create your first admin
308
+ 3. Log in to `/nova`
309
+ 4. Create an App resource for your first app
310
+ 5. Generate an app key
311
+ 6. Drop the key into your client's `capacitor.config.ts`
312
+
313
+ You're operational. From there, every release flows through the CLI; Nova is your read/manage UI.
314
+
315
+ ### Why Nova matters for non-technical operators
316
+
317
+ Release management eventually gets handed off to non-engineering operators — release managers, QA leads, support triaging "what release is this user on?" Nova's CRUD UI works for them without ramping on Laravel. Click, filter, read; never touch SQL or the CLI. That's the right boundary between engineering work (CLI, code) and operational work (Nova).
318
+
319
+ Nova also makes "who promoted what, when" reviews trivial — every action is logged in the activity log. Auditors love it. You'll love it the first time someone asks "who pushed X at 3 AM?"
320
+
321
+ **👉 See the Nova screens: https://nativeupdate.aoneahsan.com**
322
+
323
+ #NativeUpdate #LaravelNova #AdminPanel #Aoneahsan #SaaSApp
324
+
325
+ ---
326
+
327
+ ## Post 07 — How v3.0.0 migration actually went
328
+
329
+ `#NativeUpdateInside` 07.
330
+
331
+ Practical retrospective on the v3.0.0 BREAKING release. Not a "we shipped it, all good" puff piece — the actual rough edges and what we learned.
332
+
333
+ ### What changed
334
+
335
+ v2.x supported two backend postures: Laravel HTTP (canonical) and Firestore-direct (the device read release metadata directly via Firebase SDK). v3.0.0 removed the Firestore path. Single Laravel HTTP backend now. ~3,000 LOC deleted.
336
+
337
+ ### The rough edges
338
+
339
+ - **Internal types referenced Firestore in places we didn't expect.** First pass missed a couple of `website/src/types/firestore.ts` and `website/src/types/index.ts` files; cleanup commit caught them later.
340
+ - **Tests had implicit Firestore dependencies via mocks.** Removing the path required updating test fixtures, not just deleting the implementation.
341
+ - **Documentation drift.** Some doc pages still referenced "Firestore or Laravel" weeks after the code was gone. Caught in the next audit pass.
342
+ - **Existing v2 integrators on the Firestore path needed a real migration guide** — not "just switch to Laravel," but "here's how to model your existing release data in Laravel's schema."
343
+
344
+ ### What we did to make migration smooth
345
+
346
+ - Wrote `docs/MIGRATION.md` before shipping the BREAKING release, not after
347
+ - Bumped the major version number (v3.0.0) per semver, not v2.x.something
348
+ - Kept the v2.x branch alive for security patches
349
+ - Documented the new HTTP protocol in detail so integrators with custom backends could update their implementations
350
+
351
+ ### What I'd do differently next time
352
+
353
+ - **Audit ALL files (not just `src/`) for the removed feature.** The website type files were stragglers; a grep would have caught them in one pass instead of two.
354
+ - **Update the public README + landing page on the same commit as the BREAKING release.** A 2-day window where the README still talked about Firestore caused at least one confused issue.
355
+ - **Ship the migration guide as a release-note GitHub issue too**, not just a markdown file in the repo — discoverability matters.
356
+
357
+ ### Why BREAKING is sometimes the right call
358
+
359
+ When you're carrying ~3,000 LOC of duplication that complicates every other decision, the cost of "preserving compatibility" is more than the cost of asking integrators to migrate once. v3.0.0's test matrix shrunk by ~40%; new feature velocity went up; doc burden halved. Worth it.
360
+
361
+ The lesson: don't be precious about BREAKING releases when the alternative is technical-debt accumulation that slows everyone, including future integrators. Major versions exist precisely so you can clean house occasionally.
362
+
363
+ **👉 v2 → v3 guide: https://nativeupdate.aoneahsan.com**
364
+
365
+ #NativeUpdate #Migration #Retrospective #Aoneahsan #BestOpenSourceCommunityProject
366
+
367
+ ---
368
+
369
+ ## Post 08 — Performance: how heavy is OTA on your users?
370
+
371
+ `#NativeUpdateInside` 08.
372
+
373
+ Honest look at the runtime cost of Native Update on a user's device. The TL;DR: small. The longer answer is worth understanding.
374
+
375
+ ### Bundle download
376
+
377
+ Typical Capacitor app's JS bundle: 200–800 KB gzipped. On Wi-Fi, that's ~1–3 seconds. On a decent 4G connection, ~2–6 seconds. On 3G, ~10–30 seconds.
378
+
379
+ Native Update downloads in the background after the app starts (so the user is using the app on the *current* bundle while the next one downloads). The download throttles based on network type — by default, no aggressive cellular usage.
380
+
381
+ ### Disk
382
+
383
+ Two bundles on disk at any time: the active one and (during transitions) the pending one. ~1–2 MB total. Negligible on any modern device.
384
+
385
+ ### Memory
386
+
387
+ Effectively zero overhead. The plugin itself is small (a few KB of JS + the native bridges). Bundle application doesn't consume meaningful RAM beyond what running the app already does.
388
+
389
+ ### CPU
390
+
391
+ Hash verification is the most CPU-intensive operation. SHA-256 over a 500 KB bundle is sub-second on any phone made in the last 5 years. Atomic swap is a file-system rename — instant.
392
+
393
+ ### Battery
394
+
395
+ Background downloads consume battery proportional to network activity. The plugin's default config avoids cellular unless explicitly opted-in, and respects iOS / Android background-task budgets. A typical OTA download is similar in battery cost to loading a webpage with images.
396
+
397
+ ### Cold-start time
398
+
399
+ This is where teams often worry, fairly. The plugin runs `checkForUpdate()` early in app launch. The check is a small HTTPS call (a few KB request, a few KB response). On a healthy network: <100ms. On a slow network: it runs async so it doesn't block app start by default.
400
+
401
+ If `autoCheck: true` is set and a new bundle is available, the download happens in the background; the user starts the app on the current bundle and gets the new one on the next launch. Zero perceived cold-start impact.
402
+
403
+ ### What if the user is offline?
404
+
405
+ The check fails silently (no network = no new release possible). The user starts the app on the current bundle. No error toast, no broken state. The next time they're online and open the app, the check succeeds and they pick up any pending release.
406
+
407
+ ### The honest worst case
408
+
409
+ User is on a slow 3G connection, you've configured aggressive cellular downloads, the bundle is 1 MB. You're using ~30 seconds of background bandwidth and a noticeable percentage of their data plan for that release. Don't do this. The defaults exist for a reason — Wi-Fi-only background downloads is the right starting point.
410
+
411
+ **👉 Performance docs: https://nativeupdate.aoneahsan.com**
412
+
413
+ #NativeUpdate #Performance #MobileEngineering #Aoneahsan #TopFree
414
+
415
+ ---
416
+
417
+ ## Post 09 — Telemetry, analytics, and what you can actually see
418
+
419
+ `#NativeUpdateInside` 09.
420
+
421
+ When you push an OTA release, what can you actually observe? Native Update gives you three categories of telemetry, each useful for a different question.
422
+
423
+ ### Category 1: Release-state telemetry
424
+
425
+ Per-device: which release ID is currently active, when was it applied, did the application succeed or fail, what's the device's platform / binary version, last-seen timestamp.
426
+
427
+ This answers: "Is my rollout actually progressing?" "Are some devices stuck on an old release?" "Did a release land on devices that should have rejected it (binary-version mismatch)?"
428
+
429
+ Surfaced in: Nova admin Devices view, with filters and aggregations.
430
+
431
+ ### Category 2: Apply-failure telemetry
432
+
433
+ Per-attempted-application: did the bundle download succeed? Did hash verification pass? Did the atomic swap complete? If anything failed, why?
434
+
435
+ This answers: "Why didn't 5% of devices pick up the new release?" "Is there a download path issue (network, CDN, firewall)?" "Is there a corruption issue (hash mismatches at scale = your CDN is misbehaving)?"
436
+
437
+ Surfaced in: backend logs + Nova admin failure dashboard. Threshold-based alerting is on the roadmap.
438
+
439
+ ### Category 3: Post-apply runtime telemetry
440
+
441
+ This is NOT something Native Update provides directly — it's what you get from your existing analytics + error monitoring (Amplitude, Sentry, Mixpanel, your own backend) once tagged with the Native Update release ID.
442
+
443
+ Pattern:
444
+
445
+ ```ts
446
+ const release = await NativeUpdate.getCurrentRelease();
447
+ Sentry.setTag('nativeupdate.release', release.id);
448
+ Amplitude.setUserProperty('nativeupdate_release', release.id);
449
+ ```
450
+
451
+ This answers: "Did the new release change conversion?" "Are users on the new release crashing more or less?" "What's the per-release retention curve?"
452
+
453
+ Native Update gives you the release ID; your existing analytics stack does the rest.
454
+
455
+ ### What you don't get out of the box
456
+
457
+ - A built-in product analytics platform (intentional — use the one you already have)
458
+ - A built-in error monitoring service (intentional — Sentry / Bugsnag / Rollbar do this better)
459
+ - A built-in A/B testing framework (intentional — you can use channels for it, or layer LaunchDarkly / Statsig)
460
+
461
+ The principle: do release distribution + state observability well; let other tools handle their domains.
462
+
463
+ ### Wiring it all together
464
+
465
+ Add Sentry. Tag with release ID. Add Amplitude / Mixpanel. Tag with release ID. Now every event in your analytics + error stack is attributable to a specific Native Update release. Combined with Nova's release-state view, you have full observability of every rollout.
466
+
467
+ **👉 Telemetry docs: https://nativeupdate.aoneahsan.com**
468
+
469
+ #NativeUpdate #Telemetry #Observability #Aoneahsan #SaaSApp
470
+
471
+ ---
472
+
473
+ ## Post 10 — Roadmap, contribution, and how to get involved
474
+
475
+ `#NativeUpdateInside` 10 — last in this batch.
476
+
477
+ Where Native Update is going, and how you can help if you want to.
478
+
479
+ ### Shipped (where we are)
480
+
481
+ - v3.0.0 single-backend architecture (Laravel HTTP only)
482
+ - Native Kotlin + Swift implementations
483
+ - CLI for full release loop
484
+ - Laravel + Nova reference backend
485
+ - 3 example apps validating the protocol
486
+ - 81 unit tests + Detox E2E suite
487
+ - React marketing/dashboard site with full observability stack (Sentry + Clarity + Amplitude)
488
+ - 7-day full-audit cooldown tracker
489
+
490
+ ### Roadmap (what's next)
491
+
492
+ - **More example apps** — Vue + Capacitor, Svelte + Capacitor (the protocol is framework-agnostic; the examples should reflect that)
493
+ - **Hosted SaaS option** — for teams who don't want to self-host the Laravel backend. Will be opt-in; self-host stays MIT and primary
494
+ - **More CLI commands** — audit logs export, metrics export, batch operations
495
+ - **Plugin: incremental bundle updates** — instead of pushing the full bundle, push only the diff. Bigger lift, big wins on bandwidth at scale
496
+ - **Plugin: signed bundles** — code-sign-grade integrity on top of the SHA-256 check, for teams with stricter compliance needs
497
+ - **More backend implementations** — reference Express server (currently in example apps) graduating into a maintained alternative backend; potentially a Cloudflare Workers reference
498
+
499
+ ### How to contribute
500
+
501
+ The project is MIT-licensed. Contributions welcome at every level:
502
+
503
+ - **Bug reports** — open an issue with a reproduction in one of the example apps. The faster I can reproduce, the faster I can fix.
504
+ - **Documentation PRs** — anything from typo fixes to whole sections. Docs are MD files in `docs/`.
505
+ - **Plugin features** — propose first via an issue (so we don't duplicate effort), then PR.
506
+ - **Backend features** — same flow.
507
+ - **Example apps** — if you've integrated the plugin against a stack we don't have an example for (Vue, Svelte, etc.), a PR adding it is high-value.
508
+ - **Translations** — the marketing site is English-only currently; PRs adding i18n welcome.
509
+
510
+ ### What I'm NOT looking for
511
+
512
+ - Driveby refactors with no issue link
513
+ - "Add my favorite framework" without an example app to back it up
514
+ - License changes (MIT stays MIT — non-negotiable)
515
+
516
+ ### How to follow
517
+
518
+ The project ships from a single monorepo. Watching the repo + following the release notes is the highest-signal subscription. The marketing site has a changelog page if you prefer that surface, and the `#NativeUpdate10` + `#NativeUpdateInside` social series cover features and architecture stories as they ship.
519
+
520
+ **👉 https://nativeupdate.aoneahsan.com — repo, docs, changelog all linked**
521
+
522
+ #NativeUpdate #OpenSource #ContributingMatters #Aoneahsan #BestOpenSourceCommunityProject
523
+
524
+ ---
525
+
526
+ ## End of Posts Batch 02
527
+
528
+ 10 posts, each 2700–2900 chars. Mark `USED — ` once shared.