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
@@ -1,271 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { ManifestReader } from '../firestore/manifest-reader';
3
- // Mock crypto.subtle
4
- const mockDigest = vi.fn();
5
- Object.defineProperty(global, 'crypto', {
6
- value: {
7
- subtle: {
8
- digest: mockDigest,
9
- },
10
- },
11
- });
12
- // Mock FirestoreClient
13
- vi.mock('../firestore/firestore-client', () => ({
14
- FirestoreClient: vi.fn().mockImplementation(() => ({
15
- getManifest: vi.fn(),
16
- getManifestFor: vi.fn(),
17
- clearCache: vi.fn(),
18
- })),
19
- }));
20
- describe('ManifestReader', () => {
21
- let manifestReader;
22
- let mockFirestoreClient;
23
- const createTimestamp = (date) => ({
24
- seconds: Math.floor(date.getTime() / 1000),
25
- nanoseconds: 0,
26
- });
27
- const mockDeviceInfo = {
28
- deviceId: 'device-123',
29
- platform: 'ios',
30
- appVersion: '1.5.0',
31
- bundleVersion: '1.0.0',
32
- osVersion: '17.0',
33
- locale: 'en-US',
34
- };
35
- const mockManifest = {
36
- appId: 'com.example.app',
37
- channel: 'production',
38
- current: {
39
- version: '2.0.0',
40
- bundleId: 'build-123',
41
- bundleUrl: 'https://example.com/bundle.zip',
42
- manifestUrl: 'https://example.com/manifest.json',
43
- checksum: 'abc123',
44
- size: 1000000,
45
- releaseNotes: 'New features',
46
- releaseDate: createTimestamp(new Date()),
47
- mandatory: false,
48
- minNativeVersion: '1.0.0',
49
- },
50
- deltas: {
51
- '1.5.0': {
52
- patchUrl: 'https://example.com/patch-1.5.0.bin',
53
- patchSize: 50000,
54
- patchChecksum: 'patch123',
55
- targetChecksum: 'abc123',
56
- },
57
- },
58
- rollout: {
59
- enabled: false,
60
- percentage: 100,
61
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
62
- endTime: null,
63
- },
64
- previousVersions: [],
65
- updatedAt: createTimestamp(new Date()),
66
- updatedBy: 'user-123',
67
- };
68
- beforeEach(() => {
69
- mockFirestoreClient = {
70
- getManifest: vi.fn(),
71
- getManifestFor: vi.fn(),
72
- clearCache: vi.fn(),
73
- };
74
- manifestReader = new ManifestReader(mockFirestoreClient);
75
- // Mock crypto for device percentile calculation
76
- mockDigest.mockResolvedValue(new Uint8Array([0x10, 0x00, 0x00, 0x00]).buffer); // ~6% percentile
77
- });
78
- describe('checkForUpdates', () => {
79
- it('should return updateAvailable: false when no manifest found', async () => {
80
- mockFirestoreClient.getManifest.mockResolvedValue(null);
81
- const result = await manifestReader.checkForUpdates({
82
- currentVersion: '1.0.0',
83
- deviceInfo: mockDeviceInfo,
84
- });
85
- expect(result.updateAvailable).toBe(false);
86
- });
87
- it('should return updateAvailable: false when current version is latest', async () => {
88
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
89
- const result = await manifestReader.checkForUpdates({
90
- currentVersion: '2.0.0',
91
- deviceInfo: mockDeviceInfo,
92
- });
93
- expect(result.updateAvailable).toBe(false);
94
- expect(result.version).toBe('2.0.0');
95
- });
96
- it('should return updateAvailable: true when update is available', async () => {
97
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
98
- const result = await manifestReader.checkForUpdates({
99
- currentVersion: '1.5.0',
100
- deviceInfo: mockDeviceInfo,
101
- });
102
- expect(result.updateAvailable).toBe(true);
103
- expect(result.version).toBe('2.0.0');
104
- expect(result.bundleUrl).toBe('https://example.com/bundle.zip');
105
- expect(result.checksum).toBe('abc123');
106
- });
107
- it('should include delta info when available for current version', async () => {
108
- var _a, _b, _c;
109
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
110
- const result = await manifestReader.checkForUpdates({
111
- currentVersion: '1.5.0',
112
- deviceInfo: mockDeviceInfo,
113
- checkDeltas: true,
114
- });
115
- expect(result.delta).toBeDefined();
116
- expect((_a = result.delta) === null || _a === void 0 ? void 0 : _a.available).toBe(true);
117
- expect((_b = result.delta) === null || _b === void 0 ? void 0 : _b.patchUrl).toBe('https://example.com/patch-1.5.0.bin');
118
- expect((_c = result.delta) === null || _c === void 0 ? void 0 : _c.patchSize).toBe(50000);
119
- });
120
- it('should not include delta when checkDeltas is false', async () => {
121
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
122
- const result = await manifestReader.checkForUpdates({
123
- currentVersion: '1.5.0',
124
- deviceInfo: mockDeviceInfo,
125
- checkDeltas: false,
126
- });
127
- expect(result.delta).toBeUndefined();
128
- });
129
- it('should indicate delta not available when no delta for current version', async () => {
130
- var _a;
131
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
132
- const result = await manifestReader.checkForUpdates({
133
- currentVersion: '1.0.0', // No delta for this version
134
- deviceInfo: mockDeviceInfo,
135
- checkDeltas: true,
136
- });
137
- expect(result.delta).toBeDefined();
138
- expect((_a = result.delta) === null || _a === void 0 ? void 0 : _a.available).toBe(false);
139
- });
140
- it('should clear cache when forceRefresh is true', async () => {
141
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
142
- await manifestReader.checkForUpdates({
143
- currentVersion: '1.5.0',
144
- deviceInfo: mockDeviceInfo,
145
- forceRefresh: true,
146
- });
147
- expect(mockFirestoreClient.clearCache).toHaveBeenCalled();
148
- });
149
- });
150
- describe('checkRolloutEligibility', () => {
151
- it('should return eligible when rollout is not enabled', async () => {
152
- const rollout = {
153
- enabled: false,
154
- percentage: 10,
155
- startTime: createTimestamp(new Date()),
156
- endTime: null,
157
- };
158
- const result = await manifestReader.checkRolloutEligibility(rollout, mockDeviceInfo);
159
- expect(result.eligible).toBe(true);
160
- expect(result.reason).toBe('Rollout not enabled, all devices eligible');
161
- });
162
- it('should return ineligible when rollout not started', async () => {
163
- const rollout = {
164
- enabled: true,
165
- percentage: 100,
166
- startTime: createTimestamp(new Date(Date.now() + 86400000)),
167
- endTime: null,
168
- };
169
- const result = await manifestReader.checkRolloutEligibility(rollout, mockDeviceInfo);
170
- expect(result.eligible).toBe(false);
171
- expect(result.reason).toBe('Rollout not started yet');
172
- });
173
- it('should return ineligible when rollout ended', async () => {
174
- const rollout = {
175
- enabled: true,
176
- percentage: 100,
177
- startTime: createTimestamp(new Date(Date.now() - 86400000 * 7)),
178
- endTime: createTimestamp(new Date(Date.now() - 86400000)),
179
- };
180
- const result = await manifestReader.checkRolloutEligibility(rollout, mockDeviceInfo);
181
- expect(result.eligible).toBe(false);
182
- expect(result.reason).toBe('Rollout ended');
183
- });
184
- it('should check scheduled rollout time', async () => {
185
- const rollout = {
186
- enabled: true,
187
- percentage: 100,
188
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
189
- endTime: null,
190
- schedule: {
191
- type: 'scheduled',
192
- scheduledTime: createTimestamp(new Date(Date.now() + 86400000)),
193
- },
194
- };
195
- const result = await manifestReader.checkRolloutEligibility(rollout, mockDeviceInfo);
196
- expect(result.eligible).toBe(false);
197
- expect(result.reason).toBe('Scheduled for later');
198
- });
199
- it('should calculate gradual rollout percentage', async () => {
200
- const rollout = {
201
- enabled: true,
202
- percentage: 100,
203
- startTime: createTimestamp(new Date(Date.now() - 3600000)), // 1 hour ago
204
- endTime: null,
205
- schedule: {
206
- type: 'gradual',
207
- gradualSteps: [10, 25, 50, 100],
208
- gradualInterval: 24, // 24 hours per step
209
- },
210
- };
211
- // Device is at ~6% percentile, first step is 10%, should be eligible
212
- const result = await manifestReader.checkRolloutEligibility(rollout, mockDeviceInfo);
213
- expect(result.eligible).toBe(true);
214
- });
215
- });
216
- describe('version comparison', () => {
217
- it('should correctly compare versions', async () => {
218
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
219
- // 1.5.0 < 2.0.0 - update available
220
- let result = await manifestReader.checkForUpdates({
221
- currentVersion: '1.5.0',
222
- deviceInfo: mockDeviceInfo,
223
- });
224
- expect(result.updateAvailable).toBe(true);
225
- // 2.0.0 = 2.0.0 - no update
226
- result = await manifestReader.checkForUpdates({
227
- currentVersion: '2.0.0',
228
- deviceInfo: mockDeviceInfo,
229
- });
230
- expect(result.updateAvailable).toBe(false);
231
- // 3.0.0 > 2.0.0 - no update (already ahead)
232
- result = await manifestReader.checkForUpdates({
233
- currentVersion: '3.0.0',
234
- deviceInfo: mockDeviceInfo,
235
- });
236
- expect(result.updateAvailable).toBe(false);
237
- });
238
- it('should handle pre-release versions', async () => {
239
- const manifestWithPreRelease = Object.assign(Object.assign({}, mockManifest), { current: Object.assign(Object.assign({}, mockManifest.current), { version: '2.0.0' }) });
240
- mockFirestoreClient.getManifest.mockResolvedValue(manifestWithPreRelease);
241
- // 2.0.0-beta < 2.0.0 - update available
242
- const result = await manifestReader.checkForUpdates({
243
- currentVersion: '2.0.0-beta',
244
- deviceInfo: mockDeviceInfo,
245
- });
246
- expect(result.updateAvailable).toBe(true);
247
- });
248
- });
249
- describe('getManifest', () => {
250
- it('should return raw manifest', async () => {
251
- mockFirestoreClient.getManifest.mockResolvedValue(mockManifest);
252
- const result = await manifestReader.getManifest();
253
- expect(result).toEqual(mockManifest);
254
- });
255
- });
256
- describe('getManifestFor', () => {
257
- it('should get manifest for specific app and channel', async () => {
258
- mockFirestoreClient.getManifestFor.mockResolvedValue(mockManifest);
259
- const result = await manifestReader.getManifestFor('com.example.app', 'production');
260
- expect(mockFirestoreClient.getManifestFor).toHaveBeenCalledWith('com.example.app', 'production');
261
- expect(result).toEqual(mockManifest);
262
- });
263
- });
264
- describe('clearCache', () => {
265
- it('should clear firestore client cache', () => {
266
- manifestReader.clearCache();
267
- expect(mockFirestoreClient.clearCache).toHaveBeenCalled();
268
- });
269
- });
270
- });
271
- //# sourceMappingURL=manifest-reader.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"manifest-reader.test.js","sourceRoot":"","sources":["../../../src/__tests__/manifest-reader.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,210 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { RolloutChecker } from '../live-update/rollout-checker';
3
- import { ConfigManager } from '../core/config';
4
- // Mock crypto.subtle
5
- const mockDigest = vi.fn();
6
- Object.defineProperty(global, 'crypto', {
7
- value: {
8
- subtle: {
9
- digest: mockDigest,
10
- },
11
- randomUUID: () => 'test-uuid-1234',
12
- },
13
- });
14
- describe('RolloutChecker', () => {
15
- let rolloutChecker;
16
- let configManager;
17
- const mockDeviceInfo = {
18
- deviceId: 'device-123',
19
- platform: 'ios',
20
- appVersion: '1.5.0',
21
- bundleVersion: '1.0.0',
22
- osVersion: '17.0',
23
- locale: 'en-US',
24
- region: 'US',
25
- };
26
- const createTimestamp = (date) => ({
27
- seconds: Math.floor(date.getTime() / 1000),
28
- nanoseconds: 0,
29
- });
30
- beforeEach(() => {
31
- // Reset ConfigManager singleton
32
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
- ConfigManager['instance'] = undefined;
34
- configManager = ConfigManager.getInstance();
35
- configManager.configure({ enableStagedRollouts: true });
36
- rolloutChecker = new RolloutChecker();
37
- // Mock crypto.subtle.digest to return predictable hash
38
- mockDigest.mockResolvedValue(new Uint8Array([0x50, 0x00, 0x00, 0x00]).buffer); // ~31% percentile
39
- });
40
- describe('checkEligibility', () => {
41
- it('should return eligible when rollouts are disabled in config', async () => {
42
- configManager.configure({ enableStagedRollouts: false });
43
- rolloutChecker = new RolloutChecker();
44
- const rollout = {
45
- enabled: true,
46
- percentage: 10,
47
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
48
- endTime: null,
49
- };
50
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
51
- expect(result.eligible).toBe(true);
52
- expect(result.reason).toBe('Staged rollouts disabled in config');
53
- });
54
- it('should return eligible when rollout is not enabled', async () => {
55
- const rollout = {
56
- enabled: false,
57
- percentage: 10,
58
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
59
- endTime: null,
60
- };
61
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
62
- expect(result.eligible).toBe(true);
63
- expect(result.reason).toBe('Rollout not enabled, all devices eligible');
64
- });
65
- it('should return ineligible when rollout has not started', async () => {
66
- const rollout = {
67
- enabled: true,
68
- percentage: 100,
69
- startTime: createTimestamp(new Date(Date.now() + 86400000)), // Tomorrow
70
- endTime: null,
71
- };
72
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
73
- expect(result.eligible).toBe(false);
74
- expect(result.reason).toContain('Rollout not started yet');
75
- });
76
- it('should return ineligible when rollout has ended', async () => {
77
- const rollout = {
78
- enabled: true,
79
- percentage: 100,
80
- startTime: createTimestamp(new Date(Date.now() - 86400000 * 7)), // Week ago
81
- endTime: createTimestamp(new Date(Date.now() - 86400000)), // Yesterday
82
- };
83
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
84
- expect(result.eligible).toBe(false);
85
- expect(result.reason).toContain('Rollout ended');
86
- });
87
- it('should return ineligible when device percentile exceeds rollout percentage', async () => {
88
- const rollout = {
89
- enabled: true,
90
- percentage: 10, // Only 10%
91
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
92
- endTime: null,
93
- };
94
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
95
- expect(result.eligible).toBe(false);
96
- expect(result.reason).toContain('exceeds rollout');
97
- });
98
- it('should return eligible when device percentile is within rollout percentage', async () => {
99
- const rollout = {
100
- enabled: true,
101
- percentage: 50, // 50% - device at ~31% should be eligible
102
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
103
- endTime: null,
104
- };
105
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
106
- expect(result.eligible).toBe(true);
107
- expect(result.reason).toBe('Device eligible for update');
108
- });
109
- it('should check platform segments', async () => {
110
- const rollout = {
111
- enabled: true,
112
- percentage: 100,
113
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
114
- endTime: null,
115
- targetSegments: {
116
- platforms: ['android'], // iOS device should be excluded
117
- },
118
- };
119
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
120
- expect(result.eligible).toBe(false);
121
- expect(result.reason).toContain('Platform ios not in target list');
122
- });
123
- it('should check minimum app version', async () => {
124
- const rollout = {
125
- enabled: true,
126
- percentage: 100,
127
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
128
- endTime: null,
129
- targetSegments: {
130
- minAppVersion: '2.0.0', // Device has 1.5.0
131
- },
132
- };
133
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
134
- expect(result.eligible).toBe(false);
135
- expect(result.reason).toContain('below minimum');
136
- });
137
- it('should check maximum app version', async () => {
138
- const rollout = {
139
- enabled: true,
140
- percentage: 100,
141
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
142
- endTime: null,
143
- targetSegments: {
144
- maxAppVersion: '1.0.0', // Device has 1.5.0
145
- },
146
- };
147
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
148
- expect(result.eligible).toBe(false);
149
- expect(result.reason).toContain('above maximum');
150
- });
151
- it('should check device ID whitelist', async () => {
152
- const rollout = {
153
- enabled: true,
154
- percentage: 100,
155
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
156
- endTime: null,
157
- targetSegments: {
158
- deviceIds: ['other-device', 'another-device'],
159
- },
160
- };
161
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
162
- expect(result.eligible).toBe(false);
163
- expect(result.reason).toBe('Device not in whitelist');
164
- });
165
- it('should check region targeting', async () => {
166
- const rollout = {
167
- enabled: true,
168
- percentage: 100,
169
- startTime: createTimestamp(new Date(Date.now() - 86400000)),
170
- endTime: null,
171
- targetSegments: {
172
- regions: ['CA', 'UK'], // Device is in US
173
- },
174
- };
175
- const result = await rolloutChecker.checkEligibility(rollout, mockDeviceInfo);
176
- expect(result.eligible).toBe(false);
177
- expect(result.reason).toContain('Region US not in target list');
178
- });
179
- });
180
- describe('getDevicePercentile', () => {
181
- it('should return consistent percentile for same device ID', async () => {
182
- const percentile1 = await rolloutChecker.getDevicePercentile('device-123');
183
- const percentile2 = await rolloutChecker.getDevicePercentile('device-123');
184
- expect(percentile1).toBe(percentile2);
185
- });
186
- it('should return value between 0 and 100', async () => {
187
- const percentile = await rolloutChecker.getDevicePercentile('device-123');
188
- expect(percentile).toBeGreaterThanOrEqual(0);
189
- expect(percentile).toBeLessThanOrEqual(100);
190
- });
191
- });
192
- describe('device info caching', () => {
193
- it('should cache and retrieve device info', () => {
194
- expect(rolloutChecker.getDeviceInfo()).toBeNull();
195
- rolloutChecker.setDeviceInfo(mockDeviceInfo);
196
- expect(rolloutChecker.getDeviceInfo()).toEqual(mockDeviceInfo);
197
- });
198
- });
199
- describe('isEnabled', () => {
200
- it('should return config value for enableStagedRollouts', () => {
201
- configManager.configure({ enableStagedRollouts: true });
202
- rolloutChecker = new RolloutChecker();
203
- expect(rolloutChecker.isEnabled()).toBe(true);
204
- configManager.configure({ enableStagedRollouts: false });
205
- rolloutChecker = new RolloutChecker();
206
- expect(rolloutChecker.isEnabled()).toBe(false);
207
- });
208
- });
209
- });
210
- //# sourceMappingURL=rollout-checker.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rollout-checker.test.js","sourceRoot":"","sources":["../../../src/__tests__/rollout-checker.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,54 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { SecurityValidator } from '../core/security';
3
- describe('SecurityValidator', () => {
4
- describe('validateUrl', () => {
5
- it('should accept HTTPS URLs', () => {
6
- expect(SecurityValidator.validateUrl('https://example.com')).toBe(true);
7
- expect(SecurityValidator.validateUrl('https://sub.example.com/path')).toBe(true);
8
- expect(SecurityValidator.validateUrl('https://example.com:8443')).toBe(true);
9
- });
10
- it('should reject HTTP URLs', () => {
11
- expect(SecurityValidator.validateUrl('http://example.com')).toBe(false);
12
- expect(SecurityValidator.validateUrl('http://localhost')).toBe(false);
13
- });
14
- it('should reject invalid URLs', () => {
15
- expect(SecurityValidator.validateUrl('not-a-url')).toBe(false);
16
- expect(SecurityValidator.validateUrl('')).toBe(false);
17
- expect(SecurityValidator.validateUrl('javascript:alert(1)')).toBe(false);
18
- });
19
- });
20
- describe('validateChecksum', () => {
21
- it('should validate SHA-256 checksums', () => {
22
- const validChecksum = 'a'.repeat(64);
23
- expect(SecurityValidator.validateChecksum(validChecksum)).toBe(true);
24
- });
25
- it('should reject invalid checksums', () => {
26
- expect(SecurityValidator.validateChecksum('too-short')).toBe(false);
27
- expect(SecurityValidator.validateChecksum('invalid@chars')).toBe(false);
28
- expect(SecurityValidator.validateChecksum('')).toBe(false);
29
- });
30
- });
31
- describe('sanitizeInput', () => {
32
- it('should sanitize dangerous input', () => {
33
- expect(SecurityValidator.sanitizeInput('<script>alert(1)</script>')).toBe('alert1');
34
- expect(SecurityValidator.sanitizeInput('normal text')).toBe('normal text');
35
- expect(SecurityValidator.sanitizeInput('path/to/file')).toBe('path/to/file');
36
- });
37
- it('should handle null and undefined', () => {
38
- expect(SecurityValidator.sanitizeInput(null)).toBe('');
39
- expect(SecurityValidator.sanitizeInput(undefined)).toBe('');
40
- });
41
- });
42
- describe('validateBundleSize', () => {
43
- it('should accept reasonable bundle sizes', () => {
44
- expect(SecurityValidator.validateBundleSize(1024 * 1024)).toBe(true); // 1MB
45
- expect(SecurityValidator.validateBundleSize(50 * 1024 * 1024)).toBe(true); // 50MB
46
- });
47
- it('should reject excessive sizes', () => {
48
- expect(SecurityValidator.validateBundleSize(200 * 1024 * 1024)).toBe(false); // 200MB
49
- expect(SecurityValidator.validateBundleSize(-1)).toBe(false);
50
- expect(SecurityValidator.validateBundleSize(0)).toBe(false);
51
- });
52
- });
53
- });
54
- //# sourceMappingURL=security.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"security.test.js","sourceRoot":"","sources":["../../../src/__tests__/security.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,45 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { VersionManager } from '../live-update/version-manager';
3
- describe('VersionManager', () => {
4
- describe('compareVersions', () => {
5
- it('should correctly compare semantic versions', () => {
6
- expect(VersionManager.compareVersions('1.0.0', '1.0.0')).toBe(0);
7
- expect(VersionManager.compareVersions('1.0.0', '1.0.1')).toBe(-1);
8
- expect(VersionManager.compareVersions('1.0.1', '1.0.0')).toBe(1);
9
- expect(VersionManager.compareVersions('2.0.0', '1.9.9')).toBe(1);
10
- expect(VersionManager.compareVersions('1.0.0-alpha', '1.0.0')).toBe(-1);
11
- });
12
- it('should handle invalid versions', () => {
13
- expect(VersionManager.compareVersions('invalid', '1.0.0')).toBe(-1);
14
- expect(VersionManager.compareVersions('1.0.0', 'invalid')).toBe(1);
15
- expect(VersionManager.compareVersions('invalid', 'invalid')).toBe(0);
16
- });
17
- });
18
- describe('isValidVersion', () => {
19
- it('should validate semantic versions', () => {
20
- expect(VersionManager.isValidVersion('1.0.0')).toBe(true);
21
- expect(VersionManager.isValidVersion('1.2.3')).toBe(true);
22
- expect(VersionManager.isValidVersion('1.0.0-alpha')).toBe(true);
23
- expect(VersionManager.isValidVersion('1.0.0+build123')).toBe(true);
24
- });
25
- it('should reject invalid versions', () => {
26
- expect(VersionManager.isValidVersion('1.0')).toBe(false);
27
- expect(VersionManager.isValidVersion('invalid')).toBe(false);
28
- expect(VersionManager.isValidVersion('')).toBe(false);
29
- expect(VersionManager.isValidVersion('v1.0.0')).toBe(false);
30
- });
31
- });
32
- describe('shouldUpdate', () => {
33
- it('should determine if update is needed', () => {
34
- expect(VersionManager.shouldUpdate('1.0.0', '1.0.1')).toBe(true);
35
- expect(VersionManager.shouldUpdate('1.0.0', '2.0.0')).toBe(true);
36
- expect(VersionManager.shouldUpdate('1.0.1', '1.0.0')).toBe(false);
37
- expect(VersionManager.shouldUpdate('1.0.0', '1.0.0')).toBe(false);
38
- });
39
- it('should respect minimum app version', () => {
40
- expect(VersionManager.shouldUpdate('1.0.0', '1.0.1', '1.0.0')).toBe(true);
41
- expect(VersionManager.shouldUpdate('1.0.0', '1.0.1', '2.0.0')).toBe(false);
42
- });
43
- });
44
- });
45
- //# sourceMappingURL=version-manager.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"version-manager.test.js","sourceRoot":"","sources":["../../../src/__tests__/version-manager.test.ts"],"names":[],"mappings":"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"}