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
@@ -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":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C,qBAAqB;AACrB,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAC3B,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE;IACtC,KAAK,EAAE;QACL,MAAM,EAAE;YACN,MAAM,EAAE,UAAU;SACnB;QACD,UAAU,EAAE,GAAG,EAAE,CAAC,gBAAgB;KACnC;CACF,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,cAA8B,CAAC;IACnC,IAAI,aAA4B,CAAC;IAEjC,MAAM,cAAc,GAAe;QACjC,QAAQ,EAAE,YAAY;QACtB,QAAQ,EAAE,KAAK;QACf,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,OAAO;QACtB,SAAS,EAAE,MAAM;QACjB,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,IAAI;KACb,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,IAAU,EAAsB,EAAE,CAAC,CAAC;QAC3D,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC;QAC1C,WAAW,EAAE,CAAC;KACf,CAAC,CAAC;IAEH,UAAU,CAAC,GAAG,EAAE;QACd,gCAAgC;QAChC,8DAA8D;QAC9D,aAAa,CAAC,UAAU,CAAC,GAAG,SAAgB,CAAC;QAC7C,aAAa,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;QAC5C,aAAa,CAAC,SAAS,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC;QAExD,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;QAEtC,uDAAuD;QACvD,UAAU,CAAC,iBAAiB,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB;IACnG,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC3E,aAAa,CAAC,SAAS,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC,CAAC;YACzD,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;YAEtC,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,EAAE;gBACd,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAClE,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,KAAK;gBACd,UAAU,EAAE,EAAE;gBACd,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,WAAW;gBACxE,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW;gBAC5E,OAAO,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,YAAY;aACxE,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;YAC1F,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,EAAE,EAAE,WAAW;gBAC3B,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;YAC1F,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,EAAE,EAAE,0CAA0C;gBAC1D,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;aACd,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;gBACb,cAAc,EAAE;oBACd,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,gCAAgC;iBACzD;aACF,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;gBACb,cAAc,EAAE;oBACd,aAAa,EAAE,OAAO,EAAE,mBAAmB;iBAC5C;aACF,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;gBACb,cAAc,EAAE;oBACd,aAAa,EAAE,OAAO,EAAE,mBAAmB;iBAC5C;aACF,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;gBACb,cAAc,EAAE;oBACd,SAAS,EAAE,CAAC,cAAc,EAAE,gBAAgB,CAAC;iBAC9C;aACF,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,OAAO,GAAkB;gBAC7B,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,GAAG;gBACf,SAAS,EAAE,eAAe,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC;gBAC3D,OAAO,EAAE,IAAI;gBACb,cAAc,EAAE;oBACd,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,kBAAkB;iBAC1C;aACF,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAE9E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;YACtE,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;YAC3E,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;YAE3E,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;YAE1E,MAAM,CAAC,UAAU,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YAC7C,MAAM,CAAC,UAAU,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;YAElD,cAAc,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC;YAE7C,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,aAAa,CAAC,SAAS,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;YACtC,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE9C,aAAa,CAAC,SAAS,CAAC,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC,CAAC;YACzD,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;YACtC,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,95 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { SecurityValidator } from '../core/security';
3
- import { ConfigManager } from '../core/config';
4
- import { ErrorCode } from '../core/errors';
5
- // We assert on shape (name + code + message) rather than `instanceof`
6
- // because NativeUpdateError pins its prototype in the constructor, which
7
- // breaks cross-subclass `instanceof` checks in certain transpilation modes.
8
- /**
9
- * Regression tests for the signature/checksum fail-closed contract.
10
- *
11
- * Prior to v2, verifySignature returned `true` when a signature was missing
12
- * but a public key was configured, and verifyChecksum returned `true` for
13
- * any empty checksum. Both were silent-pass gaps that let an attacker ship
14
- * a manifest with the fields stripped out and bypass all integrity checks.
15
- *
16
- * These tests lock the new contract in place:
17
- * - empty checksum → throws (always required in OTA paths)
18
- * - empty signature with publicKey/requireSignature → throws
19
- * - empty signature with neither configured → returns true (opt-out)
20
- */
21
- describe('SecurityValidator — fail-closed enforcement', () => {
22
- const validator = SecurityValidator.getInstance();
23
- const config = ConfigManager.getInstance();
24
- const sampleData = new TextEncoder().encode('hello world').buffer;
25
- // Test-only RSA public key (real format, fake material).
26
- const SAMPLE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\n` +
27
- `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxxxxxxxxxxxxxxxxxxxx\n` +
28
- `-----END PUBLIC KEY-----`;
29
- beforeEach(() => {
30
- // Reset to defaults before every test.
31
- config.configure({
32
- publicKey: '',
33
- enableSignatureValidation: false,
34
- requireSignature: false,
35
- });
36
- });
37
- describe('verifyChecksum', () => {
38
- it('throws when checksum is missing', async () => {
39
- await expect(validator.verifyChecksum(sampleData, '')).rejects.toMatchObject({
40
- name: 'ValidationError',
41
- code: ErrorCode.CHECKSUM_MISMATCH,
42
- });
43
- });
44
- it('returns true on matching checksum', async () => {
45
- // SHA-256("hello world")
46
- const expected = 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9';
47
- const ok = await validator.verifyChecksum(sampleData, expected);
48
- expect(ok).toBe(true);
49
- });
50
- it('returns false on mismatched checksum', async () => {
51
- const ok = await validator.verifyChecksum(sampleData, '0000000000000000000000000000000000000000000000000000000000000000');
52
- expect(ok).toBe(false);
53
- });
54
- });
55
- describe('verifySignature', () => {
56
- it('throws when signature missing and publicKey is configured', async () => {
57
- config.set('publicKey', SAMPLE_PUBLIC_KEY_PEM);
58
- await expect(validator.verifySignature(sampleData, '')).rejects.toMatchObject({
59
- name: 'ValidationError',
60
- code: ErrorCode.SIGNATURE_INVALID,
61
- });
62
- });
63
- it('throws when signature missing and requireSignature=true', async () => {
64
- config.set('requireSignature', true);
65
- await expect(validator.verifySignature(sampleData, undefined)).rejects.toMatchObject({
66
- name: 'ValidationError',
67
- code: ErrorCode.SIGNATURE_INVALID,
68
- });
69
- });
70
- it('throws when signature missing and enableSignatureValidation=true', async () => {
71
- config.set('enableSignatureValidation', true);
72
- await expect(validator.verifySignature(sampleData, null)).rejects.toMatchObject({
73
- name: 'ValidationError',
74
- code: ErrorCode.SIGNATURE_INVALID,
75
- });
76
- });
77
- it('returns true when signature AND signature-enforcement are both unset', async () => {
78
- // Opt-out path: host app passed no publicKey and disabled both flags.
79
- config.set('enableSignatureValidation', false);
80
- config.set('requireSignature', false);
81
- const ok = await validator.verifySignature(sampleData, '');
82
- expect(ok).toBe(true);
83
- });
84
- it('throws when signature is provided but publicKey is not configured', async () => {
85
- config.set('enableSignatureValidation', false);
86
- config.set('requireSignature', false);
87
- config.set('publicKey', '');
88
- await expect(validator.verifySignature(sampleData, 'AAAAAA==')).rejects.toMatchObject({
89
- name: 'ValidationError',
90
- code: ErrorCode.SIGNATURE_INVALID,
91
- });
92
- });
93
- });
94
- });
95
- //# sourceMappingURL=security-enforcement.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"security-enforcement.test.js","sourceRoot":"","sources":["../../../src/__tests__/security-enforcement.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};