native-update 2.0.0 → 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 (258) hide show
  1. package/Readme.md +28 -14
  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/LiveUpdatePlugin.kt +196 -29
  6. package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +21 -36
  7. package/cli/AGENTS.md +15 -1
  8. package/cli/CLAUDE.md +15 -1
  9. package/cli/commands/backend-create.js +56 -15
  10. package/cli/commands/bundle-create.js +39 -7
  11. package/cli/commands/monitor.js +72 -51
  12. package/cli/index.js +10 -24
  13. package/cli/package.json +11 -3
  14. package/dist/esm/app-review/app-review-manager.js +0 -1
  15. package/dist/esm/app-review/index.js +0 -1
  16. package/dist/esm/app-review/platform-review-handler.js +0 -1
  17. package/dist/esm/app-review/review-conditions-checker.js +0 -1
  18. package/dist/esm/app-review/review-rate-limiter.js +0 -1
  19. package/dist/esm/app-review/types.js +0 -1
  20. package/dist/esm/app-update/app-update-checker.js +0 -1
  21. package/dist/esm/app-update/app-update-installer.d.ts +1 -0
  22. package/dist/esm/app-update/app-update-installer.js +19 -8
  23. package/dist/esm/app-update/app-update-manager.js +0 -1
  24. package/dist/esm/app-update/app-update-notifier.js +0 -1
  25. package/dist/esm/app-update/index.js +0 -1
  26. package/dist/esm/app-update/platform-app-update.js +12 -3
  27. package/dist/esm/app-update/types.js +0 -1
  28. package/dist/esm/background-update/background-scheduler.js +0 -1
  29. package/dist/esm/background-update/index.js +0 -1
  30. package/dist/esm/background-update/notification-manager.js +0 -1
  31. package/dist/esm/config/support.js +0 -1
  32. package/dist/esm/core/analytics.d.ts +13 -0
  33. package/dist/esm/core/analytics.js +15 -1
  34. package/dist/esm/core/cache-manager.js +0 -1
  35. package/dist/esm/core/config.d.ts +0 -15
  36. package/dist/esm/core/config.js +0 -4
  37. package/dist/esm/core/errors.d.ts +1 -0
  38. package/dist/esm/core/errors.js +1 -1
  39. package/dist/esm/core/event-emitter.d.ts +0 -3
  40. package/dist/esm/core/event-emitter.js +8 -3
  41. package/dist/esm/core/logger.js +0 -1
  42. package/dist/esm/core/performance.js +0 -1
  43. package/dist/esm/core/plugin-manager.js +3 -1
  44. package/dist/esm/core/security.d.ts +11 -0
  45. package/dist/esm/core/security.js +27 -1
  46. package/dist/esm/definitions.d.ts +0 -11
  47. package/dist/esm/definitions.js +0 -1
  48. package/dist/esm/index.d.ts +3 -2
  49. package/dist/esm/index.js +3 -1
  50. package/dist/esm/live-update/bundle-manager.d.ts +8 -0
  51. package/dist/esm/live-update/bundle-manager.js +20 -1
  52. package/dist/esm/live-update/certificate-pinning.js +0 -1
  53. package/dist/esm/live-update/delta-processor.d.ts +1 -1
  54. package/dist/esm/live-update/delta-processor.js +3 -1
  55. package/dist/esm/live-update/download-manager.js +9 -2
  56. package/dist/esm/live-update/rollout-checker.d.ts +1 -1
  57. package/dist/esm/live-update/rollout-checker.js +5 -6
  58. package/dist/esm/live-update/update-manager.js +0 -1
  59. package/dist/esm/live-update/version-manager.d.ts +0 -12
  60. package/dist/esm/live-update/version-manager.js +0 -68
  61. package/dist/esm/plugin.js +69 -43
  62. package/dist/esm/security/crypto.js +11 -7
  63. package/dist/esm/security/validator.js +0 -1
  64. package/dist/esm/types/rollout.d.ts +85 -0
  65. package/dist/esm/types/rollout.js +25 -0
  66. package/dist/esm/web.d.ts +8 -0
  67. package/dist/esm/web.js +148 -54
  68. package/dist/plugin.cjs.js +1 -2
  69. package/dist/plugin.esm.js +1 -2
  70. package/dist/plugin.js +2 -3
  71. package/docs/CHANGELOG.md +124 -0
  72. package/docs/CLAUDE.md +1 -1
  73. package/docs/MANUAL-TASKS.md +17 -0
  74. package/docs/MARKETING_WEBSITE_TRACKER.md +18 -2
  75. package/docs/MIGRATION.md +83 -0
  76. package/docs/PACKAGES.md +167 -0
  77. package/docs/PERFORMANCE.md +110 -0
  78. package/docs/PROJECT_COMPLETION_TRACKER.md +4 -35
  79. package/docs/README.md +0 -1
  80. package/docs/REMAINING_FEATURES.md +123 -76
  81. package/docs/ROADMAP.md +200 -120
  82. package/docs/SECURITY-IF-REPO-PUBLIC.md +232 -0
  83. package/docs/TESTING_REQUIREMENTS.md +1 -112
  84. package/docs/ai-knowledge-base/00-project-profile.md +38 -0
  85. package/docs/ai-knowledge-base/01-features.md +46 -0
  86. package/docs/ai-knowledge-base/02-routes.md +72 -0
  87. package/docs/ai-knowledge-base/03-tech-stack.md +57 -0
  88. package/docs/ai-knowledge-base/README.md +23 -0
  89. package/docs/analytics-tracking.md +37 -0
  90. package/docs/capacitor-official-plugins.md +46 -0
  91. package/docs/capawesome-plugins.md +29 -0
  92. package/docs/deployment/HOSTINGER_DEPLOY.md +75 -34
  93. package/docs/deployment/PRODUCTION-DEPLOY-CHECKLIST.md +184 -0
  94. package/docs/docs-site/plan.md +201 -0
  95. package/docs/docs-site/scope.md +127 -0
  96. package/docs/docs-site/tracker.json +235 -0
  97. package/docs/error-handling-tracking.md +37 -0
  98. package/docs/guides/testing-guide.md +15 -41
  99. package/docs/package-audit.md +41 -0
  100. package/docs/play-store/ASO-METADATA.md +5 -0
  101. package/docs/play-store/DATA-SAFETY.md +5 -0
  102. package/docs/play-store/DECLARATIONS.md +5 -0
  103. package/docs/play-store/README.md +27 -0
  104. package/docs/play-store/RELEASE-NOTES.md +99 -0
  105. package/docs/play-store/RELEASE-STEPS.md +6 -0
  106. package/docs/play-store/STORE-LISTING.md +7 -0
  107. package/docs/play-store/SUBMISSION-CHECKLIST.md +5 -0
  108. package/docs/production-readiness.md +1 -1
  109. package/docs/project-audit/2026-05-16/00-FINALIZATION-PLAN.md +123 -0
  110. package/docs/project-audit/2026-05-16/01-BATCH-PLAN.md +227 -0
  111. package/docs/project-audit/2026-05-16/02-AUDIT-FINDINGS.md +144 -0
  112. package/docs/project-audit/2026-05-16/sessions/batch-01.md +42 -0
  113. package/docs/project-audit/2026-05-16/sessions/batch-02.md +74 -0
  114. package/docs/project-audit/2026-05-16/sessions/batch-03.md +71 -0
  115. package/docs/project-audit/2026-05-16/sessions/batch-04.md +88 -0
  116. package/docs/project-audit/2026-05-16/sessions/batch-05.md +63 -0
  117. package/docs/project-audit/2026-05-16/sessions/batch-06.md +103 -0
  118. package/docs/project-audit/2026-05-16/sessions/batch-07.md +61 -0
  119. package/docs/project-audit/2026-05-16/sessions/batch-08.md +101 -0
  120. package/docs/project-audit/2026-05-16/sessions/batch-09.md +105 -0
  121. package/docs/project-audit/2026-05-16/sessions/batch-10.md +102 -0
  122. package/docs/project-audit/AUDIT-HISTORY.md +74 -0
  123. package/docs/project-audit/BATCH-PLAN.md +168 -0
  124. package/docs/project-audit/MARKETING-WEBSITE-FINDINGS-2026-05-11.md +73 -0
  125. package/docs/project-audit/PRODUCTION-READINESS-AUDIT-2026-05-08.md +275 -0
  126. package/docs/project-finalization/00-tracker.json +60 -0
  127. package/docs/project-knowledge-base/01-system-overview.md +39 -30
  128. package/docs/project-knowledge-base/02-routes-pages-forms-users.md +87 -81
  129. package/docs/project-knowledge-base/03-tech-stack-modules-services.md +140 -108
  130. package/docs/project-knowledge-base/04-data-models-integrations.md +191 -254
  131. package/docs/project-knowledge-base/05-docs-corpus-inventory.md +83 -20
  132. package/docs/project-knowledge-base/06-operations-testing-legal-content.md +67 -29
  133. package/docs/project-knowledge-base/README.md +27 -14
  134. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-05-19.md +81 -0
  135. package/docs/rules-tracker.md +102 -0
  136. package/docs/security/PRE-LAUNCH-PENTEST-CHECKLIST.md +116 -0
  137. package/docs/social-media-marketing/README.md +81 -0
  138. package/docs/social-media-marketing/posts-batch-01.md +613 -0
  139. package/docs/social-media-marketing/posts-batch-02.md +528 -0
  140. package/docs/social-media-marketing/whatsapp-messages-batch-01.md +458 -0
  141. package/docs/social-media-marketing/whatsapp-status-batch-01.md +355 -0
  142. package/docs/tracking/finalization-2026-05-16-tracker.json +346 -0
  143. package/docs/tracking/full-audit-tracker.json +121 -0
  144. package/docs/tracking/production-readiness-audit-tracker.json +429 -0
  145. package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +16 -3
  146. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +71 -47
  147. package/ios/Plugin/NativeUpdatePlugin.swift +14 -9
  148. package/package.json +29 -29
  149. package/cli/node_modules/.yarn-integrity +0 -16
  150. package/cli/node_modules/commander/LICENSE +0 -22
  151. package/cli/node_modules/commander/Readme.md +0 -1148
  152. package/cli/node_modules/commander/esm.mjs +0 -16
  153. package/cli/node_modules/commander/index.js +0 -26
  154. package/cli/node_modules/commander/lib/argument.js +0 -145
  155. package/cli/node_modules/commander/lib/command.js +0 -2179
  156. package/cli/node_modules/commander/lib/error.js +0 -43
  157. package/cli/node_modules/commander/lib/help.js +0 -462
  158. package/cli/node_modules/commander/lib/option.js +0 -329
  159. package/cli/node_modules/commander/lib/suggestSimilar.js +0 -100
  160. package/cli/node_modules/commander/package-support.json +0 -16
  161. package/cli/node_modules/commander/package.json +0 -80
  162. package/cli/node_modules/commander/typings/esm.d.mts +0 -3
  163. package/cli/node_modules/commander/typings/index.d.ts +0 -884
  164. package/cli/yarn.lock +0 -8
  165. package/dist/esm/__tests__/bundle-manager.test.d.ts +0 -1
  166. package/dist/esm/__tests__/bundle-manager.test.js +0 -151
  167. package/dist/esm/__tests__/bundle-manager.test.js.map +0 -1
  168. package/dist/esm/__tests__/config.test.d.ts +0 -1
  169. package/dist/esm/__tests__/config.test.js +0 -70
  170. package/dist/esm/__tests__/config.test.js.map +0 -1
  171. package/dist/esm/__tests__/delta-processor.test.d.ts +0 -1
  172. package/dist/esm/__tests__/delta-processor.test.js +0 -77
  173. package/dist/esm/__tests__/delta-processor.test.js.map +0 -1
  174. package/dist/esm/__tests__/firestore-schema.test.d.ts +0 -1
  175. package/dist/esm/__tests__/firestore-schema.test.js +0 -74
  176. package/dist/esm/__tests__/firestore-schema.test.js.map +0 -1
  177. package/dist/esm/__tests__/integration.test.d.ts +0 -1
  178. package/dist/esm/__tests__/integration.test.js +0 -78
  179. package/dist/esm/__tests__/integration.test.js.map +0 -1
  180. package/dist/esm/__tests__/manifest-reader.test.d.ts +0 -1
  181. package/dist/esm/__tests__/manifest-reader.test.js +0 -271
  182. package/dist/esm/__tests__/manifest-reader.test.js.map +0 -1
  183. package/dist/esm/__tests__/rollout-checker.test.d.ts +0 -1
  184. package/dist/esm/__tests__/rollout-checker.test.js +0 -210
  185. package/dist/esm/__tests__/rollout-checker.test.js.map +0 -1
  186. package/dist/esm/__tests__/security-enforcement.test.d.ts +0 -1
  187. package/dist/esm/__tests__/security-enforcement.test.js +0 -95
  188. package/dist/esm/__tests__/security-enforcement.test.js.map +0 -1
  189. package/dist/esm/__tests__/security.test.d.ts +0 -1
  190. package/dist/esm/__tests__/security.test.js +0 -54
  191. package/dist/esm/__tests__/security.test.js.map +0 -1
  192. package/dist/esm/__tests__/version-manager.test.d.ts +0 -1
  193. package/dist/esm/__tests__/version-manager.test.js +0 -45
  194. package/dist/esm/__tests__/version-manager.test.js.map +0 -1
  195. package/dist/esm/app-review/app-review-manager.js.map +0 -1
  196. package/dist/esm/app-review/index.js.map +0 -1
  197. package/dist/esm/app-review/platform-review-handler.js.map +0 -1
  198. package/dist/esm/app-review/review-conditions-checker.js.map +0 -1
  199. package/dist/esm/app-review/review-rate-limiter.js.map +0 -1
  200. package/dist/esm/app-review/types.js.map +0 -1
  201. package/dist/esm/app-update/app-update-checker.js.map +0 -1
  202. package/dist/esm/app-update/app-update-installer.js.map +0 -1
  203. package/dist/esm/app-update/app-update-manager.js.map +0 -1
  204. package/dist/esm/app-update/app-update-notifier.js.map +0 -1
  205. package/dist/esm/app-update/index.js.map +0 -1
  206. package/dist/esm/app-update/platform-app-update.js.map +0 -1
  207. package/dist/esm/app-update/types.js.map +0 -1
  208. package/dist/esm/background-update/background-scheduler.js.map +0 -1
  209. package/dist/esm/background-update/index.js.map +0 -1
  210. package/dist/esm/background-update/notification-manager.js.map +0 -1
  211. package/dist/esm/config/support.js.map +0 -1
  212. package/dist/esm/core/analytics.js.map +0 -1
  213. package/dist/esm/core/cache-manager.js.map +0 -1
  214. package/dist/esm/core/config.js.map +0 -1
  215. package/dist/esm/core/errors.js.map +0 -1
  216. package/dist/esm/core/event-emitter.js.map +0 -1
  217. package/dist/esm/core/logger.js.map +0 -1
  218. package/dist/esm/core/performance.js.map +0 -1
  219. package/dist/esm/core/plugin-manager.js.map +0 -1
  220. package/dist/esm/core/security.js.map +0 -1
  221. package/dist/esm/definitions.js.map +0 -1
  222. package/dist/esm/firestore/firestore-client.d.ts +0 -109
  223. package/dist/esm/firestore/firestore-client.js +0 -264
  224. package/dist/esm/firestore/firestore-client.js.map +0 -1
  225. package/dist/esm/firestore/index.d.ts +0 -11
  226. package/dist/esm/firestore/index.js +0 -11
  227. package/dist/esm/firestore/index.js.map +0 -1
  228. package/dist/esm/firestore/manifest-reader.d.ts +0 -87
  229. package/dist/esm/firestore/manifest-reader.js +0 -294
  230. package/dist/esm/firestore/manifest-reader.js.map +0 -1
  231. package/dist/esm/firestore/schema.d.ts +0 -507
  232. package/dist/esm/firestore/schema.js +0 -73
  233. package/dist/esm/firestore/schema.js.map +0 -1
  234. package/dist/esm/index.js.map +0 -1
  235. package/dist/esm/live-update/bundle-manager.js.map +0 -1
  236. package/dist/esm/live-update/certificate-pinning.js.map +0 -1
  237. package/dist/esm/live-update/delta-processor.js.map +0 -1
  238. package/dist/esm/live-update/download-manager.js.map +0 -1
  239. package/dist/esm/live-update/rollout-checker.js.map +0 -1
  240. package/dist/esm/live-update/update-manager.js.map +0 -1
  241. package/dist/esm/live-update/version-manager.js.map +0 -1
  242. package/dist/esm/plugin.js.map +0 -1
  243. package/dist/esm/security/crypto.js.map +0 -1
  244. package/dist/esm/security/validator.js.map +0 -1
  245. package/dist/esm/web.js.map +0 -1
  246. package/dist/plugin.cjs.js.map +0 -1
  247. package/dist/plugin.esm.js.map +0 -1
  248. package/dist/plugin.js.map +0 -1
  249. package/docs/FIREBASE_INTEGRATION_TRACKER.md +0 -321
  250. package/docs/FIREBASE_QUERIES_AND_INDEXES_AUDIT.md +0 -221
  251. package/docs/examples/firebase-backend-example.md +0 -27
  252. package/docs/features/laravel-nova-backend/credentials.ignore.md +0 -34
  253. package/docs/guides/no-cost-backend-implementation-plan.md +0 -77
  254. package/docs/guides/no-cost-firestore-google-drive-backend.md +0 -60
  255. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-16.md +0 -454
  256. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-24.md +0 -66
  257. package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-25.md +0 -67
  258. /package/docs/{MARKETING_WEBSITE_PLAN.md → archive/MARKETING_WEBSITE_PLAN.md} +0 -0
@@ -134,44 +134,58 @@ class LiveUpdatePlugin {
134
134
  }
135
135
 
136
136
  Task {
137
+ let bundleId = "bundle-\(Date().timeIntervalSince1970)"
138
+ let downloadDir = getUpdatesDirectory().appendingPathComponent(bundleId)
139
+ var downloadSucceeded = false
140
+ defer {
141
+ // Remove the download directory if anything in download/
142
+ // verify/extract failed. Without this, every failed
143
+ // download leaks an empty bundle-<ts>/ directory that
144
+ // never gets cleaned up.
145
+ if !downloadSucceeded {
146
+ try? FileManager.default.removeItem(at: downloadDir)
147
+ }
148
+ }
137
149
  do {
138
- let bundleId = "bundle-\(Date().timeIntervalSince1970)"
139
- let downloadDir = getUpdatesDirectory().appendingPathComponent(bundleId)
140
150
  try FileManager.default.createDirectory(at: downloadDir, withIntermediateDirectories: true)
141
-
142
- // Start download
151
+
143
152
  let downloadedFile = try await downloadBundle(from: url, to: downloadDir, bundleId: bundleId)
144
-
145
- // Verify checksum
153
+
146
154
  let calculatedChecksum = try calculateChecksum(for: downloadedFile)
147
155
  if calculatedChecksum != checksum {
148
- try FileManager.default.removeItem(at: downloadedFile)
149
156
  call.reject("CHECKSUM_ERROR", "Bundle checksum validation failed")
150
157
  return
151
158
  }
152
-
153
- // Verify signature if provided
159
+
154
160
  if let signature = call.getString("signature"),
155
161
  let publicKey = (config?["security"] as? [String: Any])?["publicKey"] as? String,
156
162
  (config?["security"] as? [String: Any])?["enableSignatureValidation"] as? Bool == true {
157
-
163
+
158
164
  let fileData = try Data(contentsOf: downloadedFile)
159
165
  let securityManager = SecurityManager()
160
-
166
+
161
167
  if !securityManager.verifySignature(data: fileData, signature: signature, publicKeyString: publicKey) {
162
- try FileManager.default.removeItem(at: downloadedFile)
163
168
  call.reject("SIGNATURE_ERROR", "Bundle signature validation failed")
164
169
  return
165
170
  }
166
171
  }
167
-
168
- // Create bundle info. Persist the signature so the
169
- // boot-time re-verify (verifyActiveBundleOnBoot) can run
170
- // without needing to re-download.
172
+
173
+ // Extract immediately so the bundle is bootable, but DO
174
+ // NOT swap the WebView's serverBasePath here. set() does
175
+ // that. This matches Android's contract — download stages
176
+ // a verified bundle, set() activates it.
177
+ try extractZipBundleForBundle(bundleId: bundleId, zipUrl: downloadedFile)
178
+
179
+ let extractedPath = getUpdatesDirectory()
180
+ .appendingPathComponent(bundleId)
181
+ .appendingPathComponent("www")
182
+ .path
183
+
171
184
  var bundleInfo: [String: Any] = [
172
185
  "bundleId": bundleId,
173
186
  "version": version,
174
187
  "path": downloadedFile.path,
188
+ "extractedPath": extractedPath,
175
189
  "downloadTime": Date().timeIntervalSince1970 * 1000,
176
190
  "size": try FileManager.default.attributesOfItem(atPath: downloadedFile.path)[.size] ?? 0,
177
191
  "status": "READY",
@@ -181,34 +195,42 @@ class LiveUpdatePlugin {
181
195
  if let signature = call.getString("signature") {
182
196
  bundleInfo["signature"] = signature
183
197
  }
184
-
185
- // Save bundle info
186
198
  saveBundleInfo(bundleInfo)
187
-
188
- // Extract the bundle
189
- try extractAndApplyBundle(downloadedFile, bundleId: bundleId)
190
-
191
- // Notify state change
199
+
192
200
  stateChangeListener?([
193
201
  "status": "READY",
194
202
  "bundleId": bundleId,
195
203
  "version": version
196
204
  ])
197
-
205
+
206
+ downloadSucceeded = true
198
207
  call.resolve(bundleInfo)
199
208
  } catch {
200
209
  call.reject("DOWNLOAD_ERROR", error.localizedDescription)
201
210
  }
202
211
  }
203
212
  }
204
-
213
+
205
214
  func set(_ call: CAPPluginCall) {
206
215
  guard let bundleId = call.getString("bundleId") else {
207
216
  call.reject("Bundle ID is required")
208
217
  return
209
218
  }
210
-
219
+
220
+ // Activation = update the active-bundle pointer AND swap the
221
+ // WebView's serverBasePath. Previously the swap happened in
222
+ // download(), which auto-activated bundles before the host app
223
+ // had a chance to call set(). That broke parity with Android
224
+ // and meant a partially-completed download could end up live.
225
+ let bundles = UserDefaults.standard.dictionary(forKey: "native_update_bundles") ?? [:]
226
+ guard let bundleInfo = bundles[bundleId] as? [String: Any],
227
+ let extractedPath = bundleInfo["extractedPath"] as? String else {
228
+ call.reject("Bundle not found or not extracted: \(bundleId)")
229
+ return
230
+ }
231
+
211
232
  setActiveBundle(bundleId)
233
+ configureWebViewPath(extractedPath)
212
234
  call.resolve()
213
235
  }
214
236
 
@@ -711,32 +733,34 @@ class LiveUpdatePlugin {
711
733
 
712
734
  // MARK: - Bundle Extraction and WebView Configuration
713
735
 
714
- private func extractAndApplyBundle(_ bundleUrl: URL, bundleId: String) throws {
715
- let extractedPath = getUpdatesDirectory().appendingPathComponent(bundleId).appendingPathComponent("www")
716
-
736
+ /// Extract a downloaded zip into `bundles/{bundleId}/www/`. Does NOT
737
+ /// touch `setServerBasePath` — activation is owned by set().
738
+ private func extractZipBundleForBundle(bundleId: String, zipUrl: URL) throws {
739
+ let extractedPath = getUpdatesDirectory()
740
+ .appendingPathComponent(bundleId)
741
+ .appendingPathComponent("www")
717
742
  do {
718
- // Extract the zip bundle
719
- try extractZipBundle(from: bundleUrl, to: extractedPath)
720
-
721
- // Update bundle info with extracted path
722
- var bundleInfo = getAllBundles().first { $0["bundleId"] as? String == bundleId } ?? [:]
723
- bundleInfo["extractedPath"] = extractedPath.path
724
- bundleInfo["status"] = "READY"
725
- saveBundleInfo(bundleInfo)
726
-
727
- // Configure WebView to use new path
728
- configureWebViewPath(extractedPath.path)
743
+ try extractZipBundle(from: zipUrl, to: extractedPath)
729
744
  } catch {
730
- // Get the safe bundle path (current working bundle)
731
- let safePath = UserDefaults.standard.string(forKey: "native_update_webview_path") ?? "/"
732
-
733
- // Rollback to safe bundle
734
- try? rollbackToSafeBundle(currentPath: extractedPath.path, safePath: safePath)
735
-
736
- // Re-throw the error
745
+ // Roll back the partial extraction so a re-download is clean.
746
+ try? FileManager.default.removeItem(at: extractedPath)
737
747
  throw error
738
748
  }
739
749
  }
750
+
751
+ private func extractAndApplyBundle(_ bundleUrl: URL, bundleId: String) throws {
752
+ // Legacy path retained for any caller still using it. Extracts
753
+ // and immediately activates — equivalent to the old behavior.
754
+ try extractZipBundleForBundle(bundleId: bundleId, zipUrl: bundleUrl)
755
+ let extractedPath = getUpdatesDirectory()
756
+ .appendingPathComponent(bundleId)
757
+ .appendingPathComponent("www")
758
+ var bundleInfo = getAllBundles().first { $0["bundleId"] as? String == bundleId } ?? [:]
759
+ bundleInfo["extractedPath"] = extractedPath.path
760
+ bundleInfo["status"] = "READY"
761
+ saveBundleInfo(bundleInfo)
762
+ configureWebViewPath(extractedPath.path)
763
+ }
740
764
 
741
765
  /// Hard cap on total uncompressed size of an OTA bundle. Protects
742
766
  /// against zip-bombs (a small zip that expands to gigabytes and fills
@@ -68,16 +68,21 @@ public class NativeUpdatePlugin: CAPPlugin {
68
68
  }
69
69
 
70
70
  @objc func cleanup(_ call: CAPPluginCall) {
71
- // Clean up any resources
72
71
  liveUpdatePlugin.cleanup()
73
- // Disable background updates through the plugin method
74
- let disableCall = CAPPluginCall(
75
- callbackId: "cleanup_disable",
76
- options: [:],
77
- success: { _ in },
78
- error: { _ in }
79
- )
80
- backgroundUpdatePlugin.disableBackgroundUpdates(disableCall)
72
+ // CAPACITOR-SDK-WORKAROUND (assumes Capacitor 8.x):
73
+ // We cannot manufacture a synthetic CAPPluginCall to forward into
74
+ // backgroundUpdatePlugin.disableBackgroundUpdates(_:) because
75
+ // CAPPluginCall(callbackId:options:success:error:) is `internal`
76
+ // in the public Capacitor SDK — referencing it produces a
77
+ // compile error against the shipped framework. The internal
78
+ // `disableBackgroundUpdatesInternal()` shim wraps the same
79
+ // teardown logic and is the ONLY entry point that doesn't
80
+ // require a CAPPluginCall.
81
+ //
82
+ // Revisit on every Capacitor major bump: if the constructor
83
+ // becomes public, replace the shim with a real synthetic call.
84
+ // Tracked in docs/project-audit/PRODUCTION-READINESS-AUDIT-2026-05-08.md (item I2).
85
+ backgroundUpdatePlugin.disableBackgroundUpdatesInternal()
81
86
  call.resolve()
82
87
  }
83
88
 
package/package.json CHANGED
@@ -1,16 +1,26 @@
1
1
  {
2
2
  "name": "native-update",
3
- "version": "2.0.0",
3
+ "version": "3.1.0",
4
4
  "engines": {
5
- "node": ">=18.0.0"
5
+ "node": ">=24.16.0"
6
6
  },
7
- "description": "Capacitor update plugin with live updates, app update checks, app reviews, and support for HTTP or Firestore-backed release delivery.",
7
+ "description": "Capacitor update plugin with live updates, app update checks, and app reviews. v3 ships an HTTP-only backend contract (Laravel + Nova reference implementation) and is paired with the hosted Native Update SaaS for release delivery.",
8
8
  "type": "module",
9
9
  "main": "dist/plugin.cjs.js",
10
10
  "module": "dist/esm/index.js",
11
11
  "types": "dist/esm/index.d.ts",
12
12
  "unpkg": "dist/plugin.js",
13
- "bin": "./cli/index.js",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/esm/index.d.ts",
16
+ "import": "./dist/plugin.esm.js",
17
+ "require": "./dist/plugin.cjs.js"
18
+ },
19
+ "./package.json": "./package.json",
20
+ "./dist/*": "./dist/*",
21
+ "./cli/*": "./cli/*"
22
+ },
23
+ "bin": "cli/index.js",
14
24
  "files": [
15
25
  "android/src/main/",
16
26
  "android/build.gradle",
@@ -19,6 +29,7 @@
19
29
  "android/gradle/",
20
30
  "android/settings.gradle",
21
31
  "android/proguard-rules.pro",
32
+ "android/manifest-additions.xml",
22
33
  "dist/",
23
34
  "ios/Plugin/",
24
35
  "NativeUpdate.podspec",
@@ -57,52 +68,41 @@
57
68
  "android",
58
69
  "hybrid"
59
70
  ],
60
- "packageManager": "yarn@4.10.3",
61
71
  "scripts": {
62
72
  "build": "rimraf ./dist && tsc && rollup -c rollup.config.js",
63
73
  "build:prod": "rimraf ./dist && tsc && NODE_ENV=production rollup -c rollup.config.js",
64
74
  "clean": "rimraf ./dist",
65
75
  "tsc": "tsc",
66
76
  "watch": "tsc --watch",
67
- "lint": "eslint . --ext ts",
77
+ "lint": "eslint .",
68
78
  "prettier": "prettier --write .",
69
79
  "prepublishOnly": "yarn build:prod",
70
- "swiftlint": "cd ios && swiftlint lint --fix --format --path Plugin --verbose",
71
- "test": "vitest",
72
- "test:run": "vitest --run",
73
- "test:ui": "vitest --ui",
74
- "test:coverage": "vitest --coverage"
80
+ "swiftlint": "cd ios && swiftlint lint --fix --format --path Plugin --verbose"
75
81
  },
76
82
  "dependencies": {
77
- "archiver": "^7.0.1",
83
+ "archiver": "^8.0.0",
78
84
  "chalk": "^5.6.2",
79
- "commander": "^14.0.3",
80
- "ora": "^9.3.0",
85
+ "commander": "^15.0.0",
86
+ "express": "^5.2.1",
87
+ "ora": "^9.4.0",
81
88
  "prompts": "^2.4.2"
82
89
  },
83
90
  "devDependencies": {
84
- "@capacitor/android": "^8.3.0",
85
91
  "@capacitor/app": "^8.1.0",
86
- "@capacitor/core": "^8.3.0",
92
+ "@capacitor/core": "^8.4.1",
87
93
  "@capacitor/device": "^8.0.2",
88
94
  "@capacitor/filesystem": "^8.1.2",
89
- "@capacitor/ios": "^8.3.0",
90
95
  "@capacitor/preferences": "^8.0.1",
91
- "@rollup/plugin-json": "^6.1.0",
92
96
  "@rollup/plugin-node-resolve": "^16.0.3",
93
97
  "@rollup/plugin-terser": "^1.0.0",
94
- "@types/node": "^25.6.0",
95
- "@typescript-eslint/eslint-plugin": "^8.58.2",
96
- "@typescript-eslint/parser": "^8.58.2",
97
- "@vitest/ui": "^4.1.4",
98
- "eslint": "^10.2.0",
99
- "express": "^5.2.1",
100
- "happy-dom": "^20.9.0",
101
- "prettier": "^3.8.3",
98
+ "@types/node": "^26.0.0",
99
+ "@typescript-eslint/eslint-plugin": "^8.61.1",
100
+ "@typescript-eslint/parser": "^8.61.1",
101
+ "eslint": "^10.5.0",
102
+ "prettier": "^3.8.4",
102
103
  "rimraf": "^6.1.3",
103
- "rollup": "^4.60.1",
104
- "typescript": "^6.0.2",
105
- "vitest": "^4.1.4"
104
+ "rollup": "^4.62.0",
105
+ "typescript": "^6.0.3"
106
106
  },
107
107
  "peerDependencies": {
108
108
  "@capacitor/core": "^8.0.1"
@@ -1,16 +0,0 @@
1
- {
2
- "systemParams": "linux-x64-137",
3
- "modulesFolders": [
4
- "node_modules"
5
- ],
6
- "flags": [],
7
- "linkedModules": [],
8
- "topLevelPatterns": [
9
- "commander@^11.0.0"
10
- ],
11
- "lockfileEntries": {
12
- "commander@^11.0.0": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906"
13
- },
14
- "files": [],
15
- "artifacts": {}
16
- }
@@ -1,22 +0,0 @@
1
- (The MIT License)
2
-
3
- Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- 'Software'), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.