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.
- package/Readme.md +28 -14
- package/android/manifest-additions.xml +28 -0
- package/android/src/main/AndroidManifest.xml +3 -7
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +21 -13
- package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +196 -29
- package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +21 -36
- package/cli/AGENTS.md +15 -1
- package/cli/CLAUDE.md +15 -1
- package/cli/commands/backend-create.js +56 -15
- package/cli/commands/bundle-create.js +39 -7
- package/cli/commands/monitor.js +72 -51
- package/cli/index.js +10 -24
- package/cli/package.json +11 -3
- package/dist/esm/app-review/app-review-manager.js +0 -1
- package/dist/esm/app-review/index.js +0 -1
- package/dist/esm/app-review/platform-review-handler.js +0 -1
- package/dist/esm/app-review/review-conditions-checker.js +0 -1
- package/dist/esm/app-review/review-rate-limiter.js +0 -1
- package/dist/esm/app-review/types.js +0 -1
- package/dist/esm/app-update/app-update-checker.js +0 -1
- package/dist/esm/app-update/app-update-installer.d.ts +1 -0
- package/dist/esm/app-update/app-update-installer.js +19 -8
- package/dist/esm/app-update/app-update-manager.js +0 -1
- package/dist/esm/app-update/app-update-notifier.js +0 -1
- package/dist/esm/app-update/index.js +0 -1
- package/dist/esm/app-update/platform-app-update.js +12 -3
- package/dist/esm/app-update/types.js +0 -1
- package/dist/esm/background-update/background-scheduler.js +0 -1
- package/dist/esm/background-update/index.js +0 -1
- package/dist/esm/background-update/notification-manager.js +0 -1
- package/dist/esm/config/support.js +0 -1
- package/dist/esm/core/analytics.d.ts +13 -0
- package/dist/esm/core/analytics.js +15 -1
- package/dist/esm/core/cache-manager.js +0 -1
- package/dist/esm/core/config.d.ts +0 -15
- package/dist/esm/core/config.js +0 -4
- package/dist/esm/core/errors.d.ts +1 -0
- package/dist/esm/core/errors.js +1 -1
- package/dist/esm/core/event-emitter.d.ts +0 -3
- package/dist/esm/core/event-emitter.js +8 -3
- package/dist/esm/core/logger.js +0 -1
- package/dist/esm/core/performance.js +0 -1
- package/dist/esm/core/plugin-manager.js +3 -1
- package/dist/esm/core/security.d.ts +11 -0
- package/dist/esm/core/security.js +27 -1
- package/dist/esm/definitions.d.ts +0 -11
- package/dist/esm/definitions.js +0 -1
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +3 -1
- package/dist/esm/live-update/bundle-manager.d.ts +8 -0
- package/dist/esm/live-update/bundle-manager.js +20 -1
- package/dist/esm/live-update/certificate-pinning.js +0 -1
- package/dist/esm/live-update/delta-processor.d.ts +1 -1
- package/dist/esm/live-update/delta-processor.js +3 -1
- package/dist/esm/live-update/download-manager.js +9 -2
- package/dist/esm/live-update/rollout-checker.d.ts +1 -1
- package/dist/esm/live-update/rollout-checker.js +5 -6
- package/dist/esm/live-update/update-manager.js +0 -1
- package/dist/esm/live-update/version-manager.d.ts +0 -12
- package/dist/esm/live-update/version-manager.js +0 -68
- package/dist/esm/plugin.js +69 -43
- package/dist/esm/security/crypto.js +11 -7
- package/dist/esm/security/validator.js +0 -1
- package/dist/esm/types/rollout.d.ts +85 -0
- package/dist/esm/types/rollout.js +25 -0
- package/dist/esm/web.d.ts +8 -0
- package/dist/esm/web.js +148 -54
- package/dist/plugin.cjs.js +1 -2
- package/dist/plugin.esm.js +1 -2
- package/dist/plugin.js +2 -3
- package/docs/CHANGELOG.md +124 -0
- package/docs/CLAUDE.md +1 -1
- package/docs/MANUAL-TASKS.md +17 -0
- package/docs/MARKETING_WEBSITE_TRACKER.md +18 -2
- package/docs/MIGRATION.md +83 -0
- package/docs/PACKAGES.md +167 -0
- package/docs/PERFORMANCE.md +110 -0
- package/docs/PROJECT_COMPLETION_TRACKER.md +4 -35
- package/docs/README.md +0 -1
- package/docs/REMAINING_FEATURES.md +123 -76
- package/docs/ROADMAP.md +200 -120
- package/docs/SECURITY-IF-REPO-PUBLIC.md +232 -0
- package/docs/TESTING_REQUIREMENTS.md +1 -112
- package/docs/ai-knowledge-base/00-project-profile.md +38 -0
- package/docs/ai-knowledge-base/01-features.md +46 -0
- package/docs/ai-knowledge-base/02-routes.md +72 -0
- package/docs/ai-knowledge-base/03-tech-stack.md +57 -0
- package/docs/ai-knowledge-base/README.md +23 -0
- package/docs/analytics-tracking.md +37 -0
- package/docs/capacitor-official-plugins.md +46 -0
- package/docs/capawesome-plugins.md +29 -0
- package/docs/deployment/HOSTINGER_DEPLOY.md +75 -34
- package/docs/deployment/PRODUCTION-DEPLOY-CHECKLIST.md +184 -0
- package/docs/docs-site/plan.md +201 -0
- package/docs/docs-site/scope.md +127 -0
- package/docs/docs-site/tracker.json +235 -0
- package/docs/error-handling-tracking.md +37 -0
- package/docs/guides/testing-guide.md +15 -41
- package/docs/package-audit.md +41 -0
- package/docs/play-store/ASO-METADATA.md +5 -0
- package/docs/play-store/DATA-SAFETY.md +5 -0
- package/docs/play-store/DECLARATIONS.md +5 -0
- package/docs/play-store/README.md +27 -0
- package/docs/play-store/RELEASE-NOTES.md +99 -0
- package/docs/play-store/RELEASE-STEPS.md +6 -0
- package/docs/play-store/STORE-LISTING.md +7 -0
- package/docs/play-store/SUBMISSION-CHECKLIST.md +5 -0
- package/docs/production-readiness.md +1 -1
- package/docs/project-audit/2026-05-16/00-FINALIZATION-PLAN.md +123 -0
- package/docs/project-audit/2026-05-16/01-BATCH-PLAN.md +227 -0
- package/docs/project-audit/2026-05-16/02-AUDIT-FINDINGS.md +144 -0
- package/docs/project-audit/2026-05-16/sessions/batch-01.md +42 -0
- package/docs/project-audit/2026-05-16/sessions/batch-02.md +74 -0
- package/docs/project-audit/2026-05-16/sessions/batch-03.md +71 -0
- package/docs/project-audit/2026-05-16/sessions/batch-04.md +88 -0
- package/docs/project-audit/2026-05-16/sessions/batch-05.md +63 -0
- package/docs/project-audit/2026-05-16/sessions/batch-06.md +103 -0
- package/docs/project-audit/2026-05-16/sessions/batch-07.md +61 -0
- package/docs/project-audit/2026-05-16/sessions/batch-08.md +101 -0
- package/docs/project-audit/2026-05-16/sessions/batch-09.md +105 -0
- package/docs/project-audit/2026-05-16/sessions/batch-10.md +102 -0
- package/docs/project-audit/AUDIT-HISTORY.md +74 -0
- package/docs/project-audit/BATCH-PLAN.md +168 -0
- package/docs/project-audit/MARKETING-WEBSITE-FINDINGS-2026-05-11.md +73 -0
- package/docs/project-audit/PRODUCTION-READINESS-AUDIT-2026-05-08.md +275 -0
- package/docs/project-finalization/00-tracker.json +60 -0
- package/docs/project-knowledge-base/01-system-overview.md +39 -30
- package/docs/project-knowledge-base/02-routes-pages-forms-users.md +87 -81
- package/docs/project-knowledge-base/03-tech-stack-modules-services.md +140 -108
- package/docs/project-knowledge-base/04-data-models-integrations.md +191 -254
- package/docs/project-knowledge-base/05-docs-corpus-inventory.md +83 -20
- package/docs/project-knowledge-base/06-operations-testing-legal-content.md +67 -29
- package/docs/project-knowledge-base/README.md +27 -14
- package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-05-19.md +81 -0
- package/docs/rules-tracker.md +102 -0
- package/docs/security/PRE-LAUNCH-PENTEST-CHECKLIST.md +116 -0
- package/docs/social-media-marketing/README.md +81 -0
- package/docs/social-media-marketing/posts-batch-01.md +613 -0
- package/docs/social-media-marketing/posts-batch-02.md +528 -0
- package/docs/social-media-marketing/whatsapp-messages-batch-01.md +458 -0
- package/docs/social-media-marketing/whatsapp-status-batch-01.md +355 -0
- package/docs/tracking/finalization-2026-05-16-tracker.json +346 -0
- package/docs/tracking/full-audit-tracker.json +121 -0
- package/docs/tracking/production-readiness-audit-tracker.json +429 -0
- package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +16 -3
- package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +71 -47
- package/ios/Plugin/NativeUpdatePlugin.swift +14 -9
- package/package.json +29 -29
- package/cli/node_modules/.yarn-integrity +0 -16
- package/cli/node_modules/commander/LICENSE +0 -22
- package/cli/node_modules/commander/Readme.md +0 -1148
- package/cli/node_modules/commander/esm.mjs +0 -16
- package/cli/node_modules/commander/index.js +0 -26
- package/cli/node_modules/commander/lib/argument.js +0 -145
- package/cli/node_modules/commander/lib/command.js +0 -2179
- package/cli/node_modules/commander/lib/error.js +0 -43
- package/cli/node_modules/commander/lib/help.js +0 -462
- package/cli/node_modules/commander/lib/option.js +0 -329
- package/cli/node_modules/commander/lib/suggestSimilar.js +0 -100
- package/cli/node_modules/commander/package-support.json +0 -16
- package/cli/node_modules/commander/package.json +0 -80
- package/cli/node_modules/commander/typings/esm.d.mts +0 -3
- package/cli/node_modules/commander/typings/index.d.ts +0 -884
- package/cli/yarn.lock +0 -8
- package/dist/esm/__tests__/bundle-manager.test.d.ts +0 -1
- package/dist/esm/__tests__/bundle-manager.test.js +0 -151
- package/dist/esm/__tests__/bundle-manager.test.js.map +0 -1
- package/dist/esm/__tests__/config.test.d.ts +0 -1
- package/dist/esm/__tests__/config.test.js +0 -70
- package/dist/esm/__tests__/config.test.js.map +0 -1
- package/dist/esm/__tests__/delta-processor.test.d.ts +0 -1
- package/dist/esm/__tests__/delta-processor.test.js +0 -77
- package/dist/esm/__tests__/delta-processor.test.js.map +0 -1
- package/dist/esm/__tests__/firestore-schema.test.d.ts +0 -1
- package/dist/esm/__tests__/firestore-schema.test.js +0 -74
- package/dist/esm/__tests__/firestore-schema.test.js.map +0 -1
- package/dist/esm/__tests__/integration.test.d.ts +0 -1
- package/dist/esm/__tests__/integration.test.js +0 -78
- package/dist/esm/__tests__/integration.test.js.map +0 -1
- package/dist/esm/__tests__/manifest-reader.test.d.ts +0 -1
- package/dist/esm/__tests__/manifest-reader.test.js +0 -271
- package/dist/esm/__tests__/manifest-reader.test.js.map +0 -1
- package/dist/esm/__tests__/rollout-checker.test.d.ts +0 -1
- package/dist/esm/__tests__/rollout-checker.test.js +0 -210
- package/dist/esm/__tests__/rollout-checker.test.js.map +0 -1
- package/dist/esm/__tests__/security-enforcement.test.d.ts +0 -1
- package/dist/esm/__tests__/security-enforcement.test.js +0 -95
- package/dist/esm/__tests__/security-enforcement.test.js.map +0 -1
- package/dist/esm/__tests__/security.test.d.ts +0 -1
- package/dist/esm/__tests__/security.test.js +0 -54
- package/dist/esm/__tests__/security.test.js.map +0 -1
- package/dist/esm/__tests__/version-manager.test.d.ts +0 -1
- package/dist/esm/__tests__/version-manager.test.js +0 -45
- package/dist/esm/__tests__/version-manager.test.js.map +0 -1
- package/dist/esm/app-review/app-review-manager.js.map +0 -1
- package/dist/esm/app-review/index.js.map +0 -1
- package/dist/esm/app-review/platform-review-handler.js.map +0 -1
- package/dist/esm/app-review/review-conditions-checker.js.map +0 -1
- package/dist/esm/app-review/review-rate-limiter.js.map +0 -1
- package/dist/esm/app-review/types.js.map +0 -1
- package/dist/esm/app-update/app-update-checker.js.map +0 -1
- package/dist/esm/app-update/app-update-installer.js.map +0 -1
- package/dist/esm/app-update/app-update-manager.js.map +0 -1
- package/dist/esm/app-update/app-update-notifier.js.map +0 -1
- package/dist/esm/app-update/index.js.map +0 -1
- package/dist/esm/app-update/platform-app-update.js.map +0 -1
- package/dist/esm/app-update/types.js.map +0 -1
- package/dist/esm/background-update/background-scheduler.js.map +0 -1
- package/dist/esm/background-update/index.js.map +0 -1
- package/dist/esm/background-update/notification-manager.js.map +0 -1
- package/dist/esm/config/support.js.map +0 -1
- package/dist/esm/core/analytics.js.map +0 -1
- package/dist/esm/core/cache-manager.js.map +0 -1
- package/dist/esm/core/config.js.map +0 -1
- package/dist/esm/core/errors.js.map +0 -1
- package/dist/esm/core/event-emitter.js.map +0 -1
- package/dist/esm/core/logger.js.map +0 -1
- package/dist/esm/core/performance.js.map +0 -1
- package/dist/esm/core/plugin-manager.js.map +0 -1
- package/dist/esm/core/security.js.map +0 -1
- package/dist/esm/definitions.js.map +0 -1
- package/dist/esm/firestore/firestore-client.d.ts +0 -109
- package/dist/esm/firestore/firestore-client.js +0 -264
- package/dist/esm/firestore/firestore-client.js.map +0 -1
- package/dist/esm/firestore/index.d.ts +0 -11
- package/dist/esm/firestore/index.js +0 -11
- package/dist/esm/firestore/index.js.map +0 -1
- package/dist/esm/firestore/manifest-reader.d.ts +0 -87
- package/dist/esm/firestore/manifest-reader.js +0 -294
- package/dist/esm/firestore/manifest-reader.js.map +0 -1
- package/dist/esm/firestore/schema.d.ts +0 -507
- package/dist/esm/firestore/schema.js +0 -73
- package/dist/esm/firestore/schema.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/live-update/bundle-manager.js.map +0 -1
- package/dist/esm/live-update/certificate-pinning.js.map +0 -1
- package/dist/esm/live-update/delta-processor.js.map +0 -1
- package/dist/esm/live-update/download-manager.js.map +0 -1
- package/dist/esm/live-update/rollout-checker.js.map +0 -1
- package/dist/esm/live-update/update-manager.js.map +0 -1
- package/dist/esm/live-update/version-manager.js.map +0 -1
- package/dist/esm/plugin.js.map +0 -1
- package/dist/esm/security/crypto.js.map +0 -1
- package/dist/esm/security/validator.js.map +0 -1
- package/dist/esm/web.js.map +0 -1
- package/dist/plugin.cjs.js.map +0 -1
- package/dist/plugin.esm.js.map +0 -1
- package/dist/plugin.js.map +0 -1
- package/docs/FIREBASE_INTEGRATION_TRACKER.md +0 -321
- package/docs/FIREBASE_QUERIES_AND_INDEXES_AUDIT.md +0 -221
- package/docs/examples/firebase-backend-example.md +0 -27
- package/docs/features/laravel-nova-backend/credentials.ignore.md +0 -34
- package/docs/guides/no-cost-backend-implementation-plan.md +0 -77
- package/docs/guides/no-cost-firestore-google-drive-backend.md +0 -60
- package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-16.md +0 -454
- package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-24.md +0 -66
- package/docs/project-profiles/native-update-capacitor-update-platform-project-profile-last-updated-2026-03-25.md +0 -67
- /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,
|
|
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
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
117
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
240
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
798
|
+
logger.warn('Signature validation failed');
|
|
732
799
|
}
|
|
733
800
|
return isValid;
|
|
734
801
|
}
|
|
735
802
|
catch (error) {
|
|
736
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|