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
package/dist/esm/web.js CHANGED
@@ -1,6 +1,11 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
2
  import { SyncStatus, BundleStatus, UpdateErrorCode } from './definitions';
3
3
  import { ConfigManager } from './core/config';
4
+ import { Logger } from './core/logger';
5
+ // Module-level logger so we never leak sensitive headers / tokens
6
+ // through raw console.* calls. The Logger sanitises payloads (paths,
7
+ // keys, secrets) and respects the runtime log-level switch.
8
+ const logger = new Logger('NativeUpdateWeb');
4
9
  export class NativeUpdateWeb extends WebPlugin {
5
10
  constructor() {
6
11
  super();
@@ -17,6 +22,10 @@ export class NativeUpdateWeb extends WebPlugin {
17
22
  };
18
23
  this.backgroundCheckInterval = null;
19
24
  this.isConfigured = false;
25
+ // Single-slot cache of the most recently downloaded bundle's bytes so a
26
+ // follow-up validateUpdate() on the same URL doesn't re-download the
27
+ // whole bundle just to hash it. Overwritten on each download().
28
+ this.downloadedBundleBytes = null;
20
29
  this.configManager = ConfigManager.getInstance();
21
30
  this.loadStoredData();
22
31
  this.incrementLaunchCount();
@@ -84,8 +93,7 @@ export class NativeUpdateWeb extends WebPlugin {
84
93
  }
85
94
  }
86
95
  async download(options) {
87
- var _a;
88
- // Validate URL
96
+ var _a, _b;
89
97
  if (!options.url.startsWith('https://') &&
90
98
  ((_a = this.config.security) === null || _a === void 0 ? void 0 : _a.enforceHttps) !== false) {
91
99
  throw this.createError(UpdateErrorCode.INSECURE_URL, 'Download URL must use HTTPS');
@@ -96,44 +104,82 @@ export class NativeUpdateWeb extends WebPlugin {
96
104
  version: options.version,
97
105
  path: options.url,
98
106
  downloadTime: Date.now(),
99
- size: 0, // Would be calculated during actual download
107
+ size: 0,
100
108
  status: BundleStatus.DOWNLOADING,
101
109
  checksum: options.checksum,
102
110
  signature: options.signature,
103
111
  verified: false,
104
112
  };
105
113
  this.bundles.set(bundleId, bundle);
106
- // Simulate download progress
107
- for (let i = 0; i <= 100; i += 10) {
108
- await this.notifyListeners('downloadProgress', {
109
- percent: i,
110
- bytesDownloaded: i * 1000,
111
- totalBytes: 10000,
112
- bundleId,
113
- });
114
- await new Promise((resolve) => setTimeout(resolve, 100));
114
+ // Actually fetch the bundle so we hash REAL bytes, not the bundleId
115
+ // string. This was a P0: validateChecksum used to receive `bundleId`
116
+ // and silently fail (or pass) regardless of the bundle contents.
117
+ let bundleBytes;
118
+ try {
119
+ const response = await fetch(options.url);
120
+ if (!response.ok) {
121
+ throw new Error(`HTTP ${response.status}`);
122
+ }
123
+ const reader = (_b = response.body) === null || _b === void 0 ? void 0 : _b.getReader();
124
+ const contentLength = Number(response.headers.get('content-length') || 0);
125
+ if (reader) {
126
+ const chunks = [];
127
+ let received = 0;
128
+ while (true) {
129
+ const { done, value } = await reader.read();
130
+ if (done)
131
+ break;
132
+ chunks.push(value);
133
+ received += value.length;
134
+ if (contentLength > 0) {
135
+ await this.notifyListeners('downloadProgress', {
136
+ percent: Math.round((received / contentLength) * 100),
137
+ bytesDownloaded: received,
138
+ totalBytes: contentLength,
139
+ bundleId,
140
+ });
141
+ }
142
+ }
143
+ const combined = new Uint8Array(received);
144
+ let offset = 0;
145
+ for (const chunk of chunks) {
146
+ combined.set(chunk, offset);
147
+ offset += chunk.length;
148
+ }
149
+ bundleBytes = combined.buffer;
150
+ }
151
+ else {
152
+ bundleBytes = await response.arrayBuffer();
153
+ }
115
154
  }
116
- // Verify bundle integrity if checksum/signature provided
117
- let verified = true;
155
+ catch (error) {
156
+ bundle.status = BundleStatus.FAILED;
157
+ this.bundles.delete(bundleId);
158
+ throw this.createError(UpdateErrorCode.NETWORK_ERROR, `Failed to download bundle: ${error.message}`);
159
+ }
160
+ bundle.size = bundleBytes.byteLength;
161
+ let verified = false;
118
162
  if (options.checksum) {
119
- const checksumValid = await this.validateChecksum(bundleId, options.checksum);
163
+ const checksumValid = await this.validateChecksum(bundleBytes, options.checksum);
120
164
  if (!checksumValid) {
121
165
  bundle.status = BundleStatus.FAILED;
122
166
  this.bundles.delete(bundleId);
123
167
  throw this.createError(UpdateErrorCode.CHECKSUM_ERROR, 'Bundle checksum verification failed');
124
168
  }
169
+ verified = true;
125
170
  }
126
171
  if (options.signature) {
127
- const signatureValid = await this.validateSignature(bundleId, options.signature);
172
+ const signatureValid = await this.validateSignature(bundleBytes, options.signature);
128
173
  if (!signatureValid) {
129
174
  bundle.status = BundleStatus.FAILED;
130
175
  this.bundles.delete(bundleId);
131
176
  throw this.createError(UpdateErrorCode.SIGNATURE_ERROR, 'Bundle signature verification failed');
132
177
  }
178
+ verified = true;
133
179
  }
134
- // Update bundle status
135
180
  bundle.status = BundleStatus.READY;
136
181
  bundle.verified = verified;
182
+ this.downloadedBundleBytes = { path: options.url, bytes: bundleBytes };
137
183
  this.saveStoredData();
138
184
  await this.notifyListeners('updateStateChanged', {
139
185
  status: bundle.status,
@@ -146,24 +192,25 @@ export class NativeUpdateWeb extends WebPlugin {
146
192
  if (!this.bundles.has(bundle.bundleId)) {
147
193
  throw this.createError(UpdateErrorCode.UNKNOWN_ERROR, 'Bundle not found');
148
194
  }
195
+ const stored = this.bundles.get(bundle.bundleId);
196
+ if (!stored.verified) {
197
+ throw this.createError(UpdateErrorCode.SIGNATURE_ERROR, `Refusing to activate unverified bundle ${bundle.bundleId}`);
198
+ }
149
199
  const previousBundle = this.currentBundle;
150
- this.currentBundle = bundle;
200
+ this.currentBundle = stored;
151
201
  this.currentBundle.status = BundleStatus.ACTIVE;
152
- // Update previous bundle status
153
202
  if (previousBundle) {
154
203
  previousBundle.status = BundleStatus.READY;
155
204
  }
156
205
  this.saveStoredData();
157
206
  }
158
207
  async reload() {
159
- // console.log('Web: Reloading application...');
160
208
  // In web, we can reload the page
161
209
  if (typeof window !== 'undefined') {
162
210
  window.location.reload();
163
211
  }
164
212
  }
165
213
  async reset() {
166
- // console.log('Web: Resetting to original bundle...');
167
214
  this.currentBundle = null;
168
215
  this.bundles.clear();
169
216
  this.saveStoredData();
@@ -197,7 +244,6 @@ export class NativeUpdateWeb extends WebPlugin {
197
244
  this.saveStoredData();
198
245
  }
199
246
  async notifyAppReady() {
200
- // console.log('Web: App ready notification received');
201
247
  if (this.currentBundle) {
202
248
  this.currentBundle.verified = true;
203
249
  this.saveStoredData();
@@ -232,16 +278,43 @@ export class NativeUpdateWeb extends WebPlugin {
232
278
  */
233
279
  async setUpdateUrl(url) {
234
280
  void url;
235
- console.warn('[native-update] setUpdateUrl() is deprecated and ignored. Update URL is locked after initialize().');
281
+ logger.warn('setUpdateUrl() is deprecated and ignored. Update URL is locked after initialize().');
236
282
  return;
237
283
  }
238
284
  async validateUpdate(options) {
239
- // Simulate validation
240
- const checksumValid = await this.validateChecksum(options.bundlePath, options.checksum);
285
+ var _a;
286
+ // bundlePath on web is the bundle URL (we don't persist bytes locally
287
+ // here). Reuse the bytes from the last download() when the URL matches;
288
+ // only re-fetch when validating a bundle we never downloaded.
289
+ let bundleBytes;
290
+ if (((_a = this.downloadedBundleBytes) === null || _a === void 0 ? void 0 : _a.path) === options.bundlePath) {
291
+ bundleBytes = this.downloadedBundleBytes.bytes;
292
+ }
293
+ else {
294
+ try {
295
+ const response = await fetch(options.bundlePath);
296
+ if (!response.ok) {
297
+ return {
298
+ isValid: false,
299
+ error: `Failed to fetch bundle for validation: HTTP ${response.status}`,
300
+ };
301
+ }
302
+ bundleBytes = await response.arrayBuffer();
303
+ }
304
+ catch (error) {
305
+ return {
306
+ isValid: false,
307
+ error: `Failed to fetch bundle for validation: ${error.message}`,
308
+ };
309
+ }
310
+ }
311
+ const checksumValid = await this.validateChecksum(bundleBytes, options.checksum);
241
312
  const signatureValid = options.signature
242
- ? await this.validateSignature(options.bundlePath, options.signature)
313
+ ? await this.validateSignature(bundleBytes, options.signature)
314
+ : true;
315
+ const sizeValid = options.maxSize
316
+ ? bundleBytes.byteLength <= options.maxSize
243
317
  : true;
244
- const sizeValid = options.maxSize ? true : true; // Would check actual size
245
318
  const isValid = checksumValid && signatureValid && sizeValid;
246
319
  return {
247
320
  isValid,
@@ -346,7 +419,6 @@ export class NativeUpdateWeb extends WebPlugin {
346
419
  * App Update Methods
347
420
  */
348
421
  async getAppUpdateInfo() {
349
- // console.log('Web: App updates not supported on web platform');
350
422
  return {
351
423
  updateAvailable: false,
352
424
  currentVersion: '1.0.0',
@@ -378,6 +450,7 @@ export class NativeUpdateWeb extends WebPlugin {
378
450
  * App Review Methods
379
451
  */
380
452
  async requestReview() {
453
+ var _a;
381
454
  const canRequest = await this.canRequestReview();
382
455
  if (!canRequest.canRequest) {
383
456
  return {
@@ -385,10 +458,9 @@ export class NativeUpdateWeb extends WebPlugin {
385
458
  error: canRequest.reason,
386
459
  };
387
460
  }
388
- // console.log('Web: Showing review request fallback');
389
461
  // Update last request time
390
462
  this.lastReviewRequest = Date.now();
391
- localStorage.setItem('native-update-last-review', this.lastReviewRequest.toString());
463
+ (_a = this.getLocalStorage()) === null || _a === void 0 ? void 0 : _a.setItem('native-update-last-review', this.lastReviewRequest.toString());
392
464
  // In web, we could show a custom modal or redirect to a review page
393
465
  // Note: Web platform cannot display native in-app review dialogs
394
466
  // We can offer a fallback redirect, but `displayed` reflects native capability
@@ -444,7 +516,6 @@ export class NativeUpdateWeb extends WebPlugin {
444
516
  * Background Update Methods
445
517
  */
446
518
  async enableBackgroundUpdates(config) {
447
- // console.log('Web: Enabling background updates', config);
448
519
  if (!this.config.backgroundUpdate) {
449
520
  this.config.backgroundUpdate = config;
450
521
  }
@@ -461,7 +532,6 @@ export class NativeUpdateWeb extends WebPlugin {
461
532
  this.saveConfiguration();
462
533
  }
463
534
  async disableBackgroundUpdates() {
464
- // console.log('Web: Disabling background updates');
465
535
  if (this.backgroundCheckInterval) {
466
536
  clearInterval(this.backgroundCheckInterval);
467
537
  this.backgroundCheckInterval = null;
@@ -478,7 +548,6 @@ export class NativeUpdateWeb extends WebPlugin {
478
548
  return Object.assign({}, this.backgroundUpdateStatus);
479
549
  }
480
550
  async scheduleBackgroundCheck(interval) {
481
- // console.log('Web: Scheduling background check with interval', interval);
482
551
  if (this.backgroundCheckInterval) {
483
552
  clearInterval(this.backgroundCheckInterval);
484
553
  }
@@ -491,7 +560,6 @@ export class NativeUpdateWeb extends WebPlugin {
491
560
  this.backgroundUpdateStatus.nextCheckTime = Date.now() + interval;
492
561
  }
493
562
  async triggerBackgroundCheck() {
494
- // console.log('Web: Triggering background check');
495
563
  if (!this.backgroundUpdateStatus.enabled) {
496
564
  return {
497
565
  success: false,
@@ -543,7 +611,6 @@ export class NativeUpdateWeb extends WebPlugin {
543
611
  }
544
612
  }
545
613
  async setNotificationPreferences(preferences) {
546
- // console.log('Web: Setting notification preferences', preferences);
547
614
  if (!this.config.backgroundUpdate) {
548
615
  this.config.backgroundUpdate = {};
549
616
  }
@@ -622,7 +689,7 @@ export class NativeUpdateWeb extends WebPlugin {
622
689
  return true;
623
690
  }
624
691
  catch (error) {
625
- console.error('Web: Failed to send notification', error);
692
+ logger.error('Failed to send notification', error);
626
693
  return false;
627
694
  }
628
695
  }
@@ -673,7 +740,7 @@ export class NativeUpdateWeb extends WebPlugin {
673
740
  // Compare checksums (case-insensitive)
674
741
  const isValid = hashHex.toLowerCase() === expectedChecksum.toLowerCase();
675
742
  if (!isValid) {
676
- console.warn('Checksum validation failed', {
743
+ logger.warn('Checksum validation failed', {
677
744
  expected: expectedChecksum.toLowerCase(),
678
745
  actual: hashHex.toLowerCase(),
679
746
  });
@@ -681,7 +748,7 @@ export class NativeUpdateWeb extends WebPlugin {
681
748
  return isValid;
682
749
  }
683
750
  catch (error) {
684
- console.error('Checksum validation error:', error);
751
+ logger.error('Checksum validation error', error);
685
752
  return false;
686
753
  }
687
754
  }
@@ -728,12 +795,12 @@ export class NativeUpdateWeb extends WebPlugin {
728
795
  saltLength: 32,
729
796
  }, publicKey, signatureBuffer, dataBuffer);
730
797
  if (!isValid) {
731
- console.warn('Signature validation failed');
798
+ logger.warn('Signature validation failed');
732
799
  }
733
800
  return isValid;
734
801
  }
735
802
  catch (error) {
736
- console.error('Signature validation error:', error);
803
+ logger.error('Signature validation error', error);
737
804
  // Try ECDSA as fallback
738
805
  return this.validateSignatureECDSA(data, signature);
739
806
  }
@@ -768,7 +835,7 @@ export class NativeUpdateWeb extends WebPlugin {
768
835
  return isValid;
769
836
  }
770
837
  catch (error) {
771
- console.error('ECDSA signature validation error:', error);
838
+ logger.error('ECDSA signature validation error', error);
772
839
  return false;
773
840
  }
774
841
  }
@@ -801,41 +868,66 @@ export class NativeUpdateWeb extends WebPlugin {
801
868
  namedCurve: 'P-256',
802
869
  }, false, ['verify']);
803
870
  }
871
+ /**
872
+ * Safe localStorage accessor. Returns `null` in environments where
873
+ * `localStorage` isn't available — SSR, Node-only test runners that
874
+ * stub `window` without storage, or sandboxed iframes. All callers
875
+ * MUST tolerate a `null` return and skip persistence.
876
+ */
877
+ getLocalStorage() {
878
+ try {
879
+ if (typeof window === 'undefined')
880
+ return null;
881
+ if (typeof window.localStorage === 'undefined')
882
+ return null;
883
+ return window.localStorage;
884
+ }
885
+ catch (_a) {
886
+ // Some browsers throw on localStorage access in private mode.
887
+ return null;
888
+ }
889
+ }
804
890
  loadStoredData() {
891
+ const storage = this.getLocalStorage();
892
+ if (!storage)
893
+ return;
805
894
  // Load configuration — note that any previously-persisted copy was
806
895
  // pre-v2 and may contain an apiKey/publicKey in plaintext. We still
807
896
  // read it to preserve non-sensitive state (channel, etc.) but secrets
808
897
  // are stripped on save; an old cache wipes itself on first save.
809
- const storedConfig = localStorage.getItem('native-update-config');
898
+ const storedConfig = storage.getItem('native-update-config');
810
899
  if (storedConfig) {
811
900
  this.config = JSON.parse(storedConfig);
812
901
  }
813
902
  // Load bundles
814
- const storedBundles = localStorage.getItem('native-update-bundles');
903
+ const storedBundles = storage.getItem('native-update-bundles');
815
904
  if (storedBundles) {
816
905
  const bundlesArray = JSON.parse(storedBundles);
817
906
  bundlesArray.forEach((bundle) => this.bundles.set(bundle.bundleId, bundle));
818
907
  }
819
908
  // Load current bundle
820
- const storedCurrent = localStorage.getItem('native-update-current');
909
+ const storedCurrent = storage.getItem('native-update-current');
821
910
  if (storedCurrent) {
822
911
  this.currentBundle = JSON.parse(storedCurrent);
823
912
  }
824
913
  // Load last review request time
825
- const storedLastReview = localStorage.getItem('native-update-last-review');
914
+ const storedLastReview = storage.getItem('native-update-last-review');
826
915
  if (storedLastReview) {
827
916
  this.lastReviewRequest = parseInt(storedLastReview, 10);
828
917
  }
829
918
  // Load launch count
830
- const storedLaunchCount = localStorage.getItem('native-update-launch-count');
919
+ const storedLaunchCount = storage.getItem('native-update-launch-count');
831
920
  if (storedLaunchCount) {
832
921
  this.launchCount = parseInt(storedLaunchCount, 10);
833
922
  }
834
923
  }
835
924
  saveStoredData() {
836
- localStorage.setItem('native-update-bundles', JSON.stringify(Array.from(this.bundles.values())));
925
+ const storage = this.getLocalStorage();
926
+ if (!storage)
927
+ return;
928
+ storage.setItem('native-update-bundles', JSON.stringify(Array.from(this.bundles.values())));
837
929
  if (this.currentBundle) {
838
- localStorage.setItem('native-update-current', JSON.stringify(this.currentBundle));
930
+ storage.setItem('native-update-current', JSON.stringify(this.currentBundle));
839
931
  }
840
932
  }
841
933
  sanitizeConfigForPersistence(raw) {
@@ -862,20 +954,23 @@ export class NativeUpdateWeb extends WebPlugin {
862
954
  return clone;
863
955
  }
864
956
  saveConfiguration() {
865
- localStorage.setItem('native-update-config', JSON.stringify(this.sanitizeConfigForPersistence(this.config)));
957
+ var _a;
958
+ (_a = this.getLocalStorage()) === null || _a === void 0 ? void 0 : _a.setItem('native-update-config', JSON.stringify(this.sanitizeConfigForPersistence(this.config)));
866
959
  }
867
960
  getInstallDate() {
868
- const stored = localStorage.getItem('native-update-install-date');
961
+ const storage = this.getLocalStorage();
962
+ const stored = storage === null || storage === void 0 ? void 0 : storage.getItem('native-update-install-date');
869
963
  if (stored) {
870
964
  return parseInt(stored, 10);
871
965
  }
872
966
  const now = Date.now();
873
- localStorage.setItem('native-update-install-date', now.toString());
967
+ storage === null || storage === void 0 ? void 0 : storage.setItem('native-update-install-date', now.toString());
874
968
  return now;
875
969
  }
876
970
  incrementLaunchCount() {
971
+ var _a;
877
972
  this.launchCount++;
878
- localStorage.setItem('native-update-launch-count', this.launchCount.toString());
973
+ (_a = this.getLocalStorage()) === null || _a === void 0 ? void 0 : _a.setItem('native-update-launch-count', this.launchCount.toString());
879
974
  }
880
975
  /**
881
976
  * Get configured review URL from plugin config
@@ -910,7 +1005,7 @@ export class NativeUpdateWeb extends WebPlugin {
910
1005
  return `https://play.google.com/store/apps/details?id=${packageName}&showAllReviews=true`;
911
1006
  }
912
1007
  // No review URL configured - return null to indicate review not available
913
- console.warn('No review URL configured. Set appUpdate.storeUrl.ios, appUpdate.storeUrl.android, ' +
1008
+ logger.warn('No review URL configured. Set appUpdate.storeUrl.ios, appUpdate.storeUrl.android, ' +
914
1009
  'appReview.webReviewUrl, appStoreId, or packageName in plugin config.');
915
1010
  return null;
916
1011
  }
@@ -931,4 +1026,3 @@ NativeUpdateWeb.SENSITIVE_CONFIG_PATHS = [
931
1026
  ];
932
1027
  // Alias for backward compatibility with tests
933
1028
  // Already exported above
934
- //# sourceMappingURL=web.js.map