native-update 1.1.3 → 1.1.6
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/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +41 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +12 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +52 -1
- package/backend-template/README.md +56 -0
- package/backend-template/package.json +20 -0
- package/backend-template/server.js +121 -0
- package/cli/index.js +22 -14
- package/dist/esm/core/event-emitter.d.ts +33 -0
- package/dist/esm/core/event-emitter.js +75 -0
- package/dist/esm/core/event-emitter.js.map +1 -0
- package/dist/esm/core/plugin-manager.d.ts +16 -0
- package/dist/esm/core/plugin-manager.js +50 -0
- package/dist/esm/core/plugin-manager.js.map +1 -1
- package/dist/esm/definitions.d.ts +59 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/plugin.js +43 -15
- package/dist/esm/plugin.js.map +1 -1
- package/dist/plugin.cjs.js +1 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.esm.js +1 -1
- package/dist/plugin.esm.js.map +1 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin.js.map +1 -1
- package/docs/NATIVE_UPDATES_GUIDE.md +1 -1
- package/docs/QUICK_START.md +1 -1
- package/docs/api/app-update-api.md +9 -1
- package/docs/api/background-update-api.md +157 -0
- package/docs/api/events-api.md +123 -0
- package/docs/api/live-update-api.md +16 -0
- package/docs/features/app-updates.md +4 -4
- package/docs/getting-started/quick-start.md +1 -1
- package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +15 -0
- package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +6 -0
- package/ios/Plugin/NativeUpdatePlugin.swift +45 -0
- package/package.json +24 -14
|
@@ -6,6 +6,8 @@ import { SecurityValidator } from './security';
|
|
|
6
6
|
import { BundleManager } from '../live-update/bundle-manager';
|
|
7
7
|
import { DownloadManager } from '../live-update/download-manager';
|
|
8
8
|
import { VersionManager } from '../live-update/version-manager';
|
|
9
|
+
import { AppUpdateManager } from '../app-update/app-update-manager';
|
|
10
|
+
import { EventEmitter } from './event-emitter';
|
|
9
11
|
import { NativeUpdateError, ErrorCode } from './errors';
|
|
10
12
|
/**
|
|
11
13
|
* Central manager for all plugin components
|
|
@@ -15,10 +17,12 @@ export class PluginManager {
|
|
|
15
17
|
this.bundleManager = null;
|
|
16
18
|
this.downloadManager = null;
|
|
17
19
|
this.versionManager = null;
|
|
20
|
+
this.appUpdateManager = null;
|
|
18
21
|
this.initialized = false;
|
|
19
22
|
this.configManager = ConfigManager.getInstance();
|
|
20
23
|
this.logger = Logger.getInstance();
|
|
21
24
|
this.securityValidator = SecurityValidator.getInstance();
|
|
25
|
+
this.eventEmitter = EventEmitter.getInstance();
|
|
22
26
|
}
|
|
23
27
|
static getInstance() {
|
|
24
28
|
if (!PluginManager.instance) {
|
|
@@ -30,6 +34,7 @@ export class PluginManager {
|
|
|
30
34
|
* Initialize the plugin with configuration
|
|
31
35
|
*/
|
|
32
36
|
async initialize(config) {
|
|
37
|
+
var _a, _b;
|
|
33
38
|
if (this.initialized) {
|
|
34
39
|
this.logger.warn('Plugin already initialized');
|
|
35
40
|
return;
|
|
@@ -51,6 +56,20 @@ export class PluginManager {
|
|
|
51
56
|
await this.downloadManager.initialize();
|
|
52
57
|
this.versionManager = new VersionManager();
|
|
53
58
|
await this.versionManager.initialize();
|
|
59
|
+
this.appUpdateManager = new AppUpdateManager({
|
|
60
|
+
serverUrl: config.serverUrl || config.baseUrl || '',
|
|
61
|
+
channel: config.channel || 'production',
|
|
62
|
+
autoCheck: (_a = config.autoCheck) !== null && _a !== void 0 ? _a : true,
|
|
63
|
+
autoUpdate: (_b = config.autoUpdate) !== null && _b !== void 0 ? _b : false,
|
|
64
|
+
updateStrategy: config.updateStrategy,
|
|
65
|
+
publicKey: config.publicKey,
|
|
66
|
+
requireSignature: config.requireSignature,
|
|
67
|
+
checksumAlgorithm: config.checksumAlgorithm,
|
|
68
|
+
checkInterval: config.checkInterval,
|
|
69
|
+
security: config.security,
|
|
70
|
+
});
|
|
71
|
+
// Wire up app update manager events to central event emitter
|
|
72
|
+
this.setupAppUpdateEventBridge();
|
|
54
73
|
this.initialized = true;
|
|
55
74
|
this.logger.info('Plugin initialized successfully');
|
|
56
75
|
}
|
|
@@ -112,6 +131,19 @@ export class PluginManager {
|
|
|
112
131
|
getSecurityValidator() {
|
|
113
132
|
return this.securityValidator;
|
|
114
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Get app update manager
|
|
136
|
+
*/
|
|
137
|
+
getAppUpdateManager() {
|
|
138
|
+
this.ensureInitialized();
|
|
139
|
+
return this.appUpdateManager;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get event emitter
|
|
143
|
+
*/
|
|
144
|
+
getEventEmitter() {
|
|
145
|
+
return this.eventEmitter;
|
|
146
|
+
}
|
|
115
147
|
/**
|
|
116
148
|
* Reset plugin state
|
|
117
149
|
*/
|
|
@@ -131,7 +163,10 @@ export class PluginManager {
|
|
|
131
163
|
this.bundleManager = null;
|
|
132
164
|
this.downloadManager = null;
|
|
133
165
|
this.versionManager = null;
|
|
166
|
+
this.appUpdateManager = null;
|
|
134
167
|
this.initialized = false;
|
|
168
|
+
// Clear all event listeners
|
|
169
|
+
this.eventEmitter.removeAllListeners();
|
|
135
170
|
this.logger.info('Plugin reset complete');
|
|
136
171
|
}
|
|
137
172
|
/**
|
|
@@ -149,5 +184,20 @@ export class PluginManager {
|
|
|
149
184
|
}
|
|
150
185
|
this.logger.info('Cleanup complete');
|
|
151
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Setup event bridge between AppUpdateManager and central EventEmitter
|
|
189
|
+
*/
|
|
190
|
+
setupAppUpdateEventBridge() {
|
|
191
|
+
if (!this.appUpdateManager)
|
|
192
|
+
return;
|
|
193
|
+
// Bridge appUpdateStateChanged events
|
|
194
|
+
this.appUpdateManager.addListener('appUpdateStateChanged', (event) => {
|
|
195
|
+
this.eventEmitter.emit('appUpdateStateChanged', event);
|
|
196
|
+
});
|
|
197
|
+
// Bridge appUpdateProgress events
|
|
198
|
+
this.appUpdateManager.addListener('appUpdateProgress', (event) => {
|
|
199
|
+
this.eventEmitter.emit('appUpdateProgress', event);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
152
202
|
}
|
|
153
203
|
//# sourceMappingURL=plugin-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-manager.js","sourceRoot":"","sources":["../../../src/core/plugin-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGxD;;GAEG;AACH,MAAM,OAAO,aAAa;
|
|
1
|
+
{"version":3,"file":"plugin-manager.js","sourceRoot":"","sources":["../../../src/core/plugin-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -497,6 +497,37 @@ export interface BackgroundUpdateNotificationEvent {
|
|
|
497
497
|
version?: string;
|
|
498
498
|
action?: 'shown' | 'tapped' | 'dismissed';
|
|
499
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* App Update Events
|
|
502
|
+
*/
|
|
503
|
+
export interface AppUpdateStateChangedEvent {
|
|
504
|
+
status: InstallStatus;
|
|
505
|
+
installErrorCode?: number;
|
|
506
|
+
}
|
|
507
|
+
export interface AppUpdateProgressEvent {
|
|
508
|
+
percent: number;
|
|
509
|
+
bytesDownloaded: number;
|
|
510
|
+
totalBytes: number;
|
|
511
|
+
}
|
|
512
|
+
export interface AppUpdateAvailableEvent {
|
|
513
|
+
currentVersion: string;
|
|
514
|
+
availableVersion: string;
|
|
515
|
+
updatePriority: number;
|
|
516
|
+
updateSize?: number;
|
|
517
|
+
releaseNotes?: string[];
|
|
518
|
+
storeUrl?: string;
|
|
519
|
+
}
|
|
520
|
+
export interface AppUpdateReadyEvent {
|
|
521
|
+
message: string;
|
|
522
|
+
}
|
|
523
|
+
export interface AppUpdateFailedEvent {
|
|
524
|
+
error: string;
|
|
525
|
+
code: string;
|
|
526
|
+
}
|
|
527
|
+
export interface AppUpdateNotificationClickedEvent {
|
|
528
|
+
}
|
|
529
|
+
export interface AppUpdateInstallClickedEvent {
|
|
530
|
+
}
|
|
500
531
|
/**
|
|
501
532
|
* Plugin Events
|
|
502
533
|
*/
|
|
@@ -520,6 +551,34 @@ export interface NativeUpdateListeners {
|
|
|
520
551
|
* Listen for background update notifications
|
|
521
552
|
*/
|
|
522
553
|
addListener(eventName: 'backgroundUpdateNotification', listenerFunc: (event: BackgroundUpdateNotificationEvent) => void): Promise<PluginListenerHandle>;
|
|
554
|
+
/**
|
|
555
|
+
* Listen for app update state changes
|
|
556
|
+
*/
|
|
557
|
+
addListener(eventName: 'appUpdateStateChanged', listenerFunc: (event: AppUpdateStateChangedEvent) => void): Promise<PluginListenerHandle>;
|
|
558
|
+
/**
|
|
559
|
+
* Listen for app update progress
|
|
560
|
+
*/
|
|
561
|
+
addListener(eventName: 'appUpdateProgress', listenerFunc: (event: AppUpdateProgressEvent) => void): Promise<PluginListenerHandle>;
|
|
562
|
+
/**
|
|
563
|
+
* Listen for app update available
|
|
564
|
+
*/
|
|
565
|
+
addListener(eventName: 'appUpdateAvailable', listenerFunc: (event: AppUpdateAvailableEvent) => void): Promise<PluginListenerHandle>;
|
|
566
|
+
/**
|
|
567
|
+
* Listen for app update ready
|
|
568
|
+
*/
|
|
569
|
+
addListener(eventName: 'appUpdateReady', listenerFunc: (event: AppUpdateReadyEvent) => void): Promise<PluginListenerHandle>;
|
|
570
|
+
/**
|
|
571
|
+
* Listen for app update failed
|
|
572
|
+
*/
|
|
573
|
+
addListener(eventName: 'appUpdateFailed', listenerFunc: (event: AppUpdateFailedEvent) => void): Promise<PluginListenerHandle>;
|
|
574
|
+
/**
|
|
575
|
+
* Listen for app update notification clicked
|
|
576
|
+
*/
|
|
577
|
+
addListener(eventName: 'appUpdateNotificationClicked', listenerFunc: (event: AppUpdateNotificationClickedEvent) => void): Promise<PluginListenerHandle>;
|
|
578
|
+
/**
|
|
579
|
+
* Listen for app update install clicked
|
|
580
|
+
*/
|
|
581
|
+
addListener(eventName: 'appUpdateInstallClicked', listenerFunc: (event: AppUpdateInstallClickedEvent) => void): Promise<PluginListenerHandle>;
|
|
523
582
|
/**
|
|
524
583
|
* Remove all listeners
|
|
525
584
|
*/
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { NativeUpdate } from './plugin';
|
|
2
|
-
export type { NativeUpdatePlugin, NativeUpdateCombinedPlugin, NativeUpdateListeners, LiveUpdatePlugin, AppUpdatePlugin, AppReviewPlugin, PluginConfig, UpdateConfig, LiveUpdateConfig, AppUpdateConfig, AppReviewConfig, BundleInfo, BundleStatus, UpdateStrategy, InstallMode, DownloadOptions, DownloadProgressEvent, SyncOptions, SyncResult, DeleteOptions, LatestVersion, ValidateOptions, ValidationResult, AppUpdateInfo, OpenAppStoreOptions, ReviewResult, CanRequestReviewResult, UpdateStateChangedEvent, UpdateError, UpdateErrorCode, } from './definitions';
|
|
2
|
+
export type { NativeUpdatePlugin, NativeUpdateCombinedPlugin, NativeUpdateListeners, LiveUpdatePlugin, AppUpdatePlugin, AppReviewPlugin, PluginConfig, UpdateConfig, LiveUpdateConfig, AppUpdateConfig, AppReviewConfig, BundleInfo, BundleStatus, UpdateStrategy, InstallMode, DownloadOptions, DownloadProgressEvent, SyncOptions, SyncResult, DeleteOptions, LatestVersion, ValidateOptions, ValidationResult, AppUpdateInfo, OpenAppStoreOptions, ReviewResult, CanRequestReviewResult, UpdateStateChangedEvent, AppUpdateStateChangedEvent, AppUpdateProgressEvent, AppUpdateAvailableEvent, AppUpdateReadyEvent, AppUpdateFailedEvent, AppUpdateNotificationClickedEvent, AppUpdateInstallClickedEvent, BackgroundUpdateProgressEvent, BackgroundUpdateNotificationEvent, UpdateError, UpdateErrorCode, BackgroundUpdatePlugin, BackgroundUpdateConfig, BackgroundUpdateStatus, BackgroundCheckResult, BackgroundUpdateType, NotificationPreferences, NotificationPermissionStatus, NotificationPriority, SecurityConfig, SecurityInfo, CertificatePinning, CertificatePin, PluginInitConfig, PluginListenerHandle, SyncStatus, InstallStatus, UpdateMode, ChecksumAlgorithm, } from './definitions';
|
|
3
3
|
export { ErrorCode, NativeUpdateError, ConfigurationError, DownloadError, ValidationError, StorageError, UpdateError as UpdateErrorClass, } from './core/errors';
|
|
4
4
|
export { ConfigManager } from './core/config';
|
|
5
5
|
export { Logger, LogLevel } from './core/logger';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAoFxC,gBAAgB;AAChB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,WAAW,IAAI,gBAAgB,GAChC,MAAM,eAAe,CAAC;AAEvB,kCAAkC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,qCAAqC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC"}
|
package/dist/esm/plugin.js
CHANGED
|
@@ -8,12 +8,15 @@ import { NativeUpdateError, ErrorCode } from './core/errors';
|
|
|
8
8
|
class NativeUpdatePluginWeb {
|
|
9
9
|
constructor() {
|
|
10
10
|
this.initialized = false;
|
|
11
|
+
this.windowEventListeners = new Map();
|
|
11
12
|
this.pluginManager = PluginManager.getInstance();
|
|
12
13
|
}
|
|
13
14
|
// Main plugin methods
|
|
14
15
|
async initialize(config) {
|
|
15
16
|
await this.pluginManager.initialize(config);
|
|
16
17
|
this.initialized = true;
|
|
18
|
+
// Setup window event bridge for AppUpdateNotifier events
|
|
19
|
+
this.setupWindowEventBridge();
|
|
17
20
|
}
|
|
18
21
|
isInitialized() {
|
|
19
22
|
return this.initialized && this.pluginManager.isInitialized();
|
|
@@ -195,23 +198,24 @@ class NativeUpdatePluginWeb {
|
|
|
195
198
|
}
|
|
196
199
|
// AppUpdatePlugin methods
|
|
197
200
|
async getAppUpdateInfo() {
|
|
198
|
-
|
|
199
|
-
return
|
|
200
|
-
updateAvailable: false,
|
|
201
|
-
currentVersion: '1.0.0',
|
|
202
|
-
};
|
|
201
|
+
const appUpdateManager = this.pluginManager.getAppUpdateManager();
|
|
202
|
+
return appUpdateManager.getAppUpdateInfo();
|
|
203
203
|
}
|
|
204
204
|
async performImmediateUpdate() {
|
|
205
|
-
|
|
205
|
+
const appUpdateManager = this.pluginManager.getAppUpdateManager();
|
|
206
|
+
return appUpdateManager.performImmediateUpdate();
|
|
206
207
|
}
|
|
207
208
|
async startFlexibleUpdate() {
|
|
208
|
-
|
|
209
|
+
const appUpdateManager = this.pluginManager.getAppUpdateManager();
|
|
210
|
+
return appUpdateManager.startFlexibleUpdate();
|
|
209
211
|
}
|
|
210
212
|
async completeFlexibleUpdate() {
|
|
211
|
-
|
|
213
|
+
const appUpdateManager = this.pluginManager.getAppUpdateManager();
|
|
214
|
+
return appUpdateManager.completeFlexibleUpdate();
|
|
212
215
|
}
|
|
213
|
-
async openAppStore(
|
|
214
|
-
|
|
216
|
+
async openAppStore(options) {
|
|
217
|
+
const appUpdateManager = this.pluginManager.getAppUpdateManager();
|
|
218
|
+
return appUpdateManager.openAppStore(options);
|
|
215
219
|
}
|
|
216
220
|
// AppReviewPlugin methods
|
|
217
221
|
async requestReview() {
|
|
@@ -290,17 +294,41 @@ class NativeUpdatePluginWeb {
|
|
|
290
294
|
return false;
|
|
291
295
|
}
|
|
292
296
|
// Event listener methods
|
|
293
|
-
async addListener(
|
|
294
|
-
|
|
295
|
-
//
|
|
297
|
+
async addListener(eventName, listenerFunc) {
|
|
298
|
+
const eventEmitter = this.pluginManager.getEventEmitter();
|
|
299
|
+
// Add listener to central event emitter
|
|
300
|
+
const removeListener = eventEmitter.addListener(eventName, listenerFunc);
|
|
296
301
|
return {
|
|
297
302
|
remove: async () => {
|
|
298
|
-
|
|
303
|
+
removeListener();
|
|
299
304
|
},
|
|
300
305
|
};
|
|
301
306
|
}
|
|
302
307
|
async removeAllListeners() {
|
|
303
|
-
|
|
308
|
+
const eventEmitter = this.pluginManager.getEventEmitter();
|
|
309
|
+
eventEmitter.removeAllListeners();
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Setup bridge between window custom events and central event emitter
|
|
313
|
+
*/
|
|
314
|
+
setupWindowEventBridge() {
|
|
315
|
+
const eventEmitter = this.pluginManager.getEventEmitter();
|
|
316
|
+
// List of events emitted by AppUpdateNotifier via window
|
|
317
|
+
const windowEvents = [
|
|
318
|
+
'appUpdateAvailable',
|
|
319
|
+
'appUpdateProgress',
|
|
320
|
+
'appUpdateReady',
|
|
321
|
+
'appUpdateFailed',
|
|
322
|
+
'appUpdateNotificationClicked',
|
|
323
|
+
'appUpdateInstallClicked'
|
|
324
|
+
];
|
|
325
|
+
windowEvents.forEach(eventName => {
|
|
326
|
+
const listener = (event) => {
|
|
327
|
+
eventEmitter.emit(eventName, event.detail);
|
|
328
|
+
};
|
|
329
|
+
window.addEventListener(eventName, listener);
|
|
330
|
+
this.windowEventListeners.set(eventName, listener);
|
|
331
|
+
});
|
|
304
332
|
}
|
|
305
333
|
}
|
|
306
334
|
/**
|
package/dist/esm/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA6BjD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE7D;;GAEG;AACH,MAAM,qBAAqB;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e,t,r,a,i,n,s,o,l,c,d,u,h=require("@capacitor/core"),g=require("@capacitor/filesystem"),p=require("@capacitor/preferences");!function(e){e.APP_UPDATE="app_update",e.LIVE_UPDATE="live_update",e.BOTH="both"}(e||(e={})),function(e){e.MIN="min",e.LOW="low",e.DEFAULT="default",e.HIGH="high",e.MAX="max"}(t||(t={})),function(e){e.IMMEDIATE="immediate",e.BACKGROUND="background",e.MANUAL="manual"}(r||(r={})),function(e){e.IMMEDIATE="immediate",e.ON_NEXT_RESTART="on_next_restart",e.ON_NEXT_RESUME="on_next_resume"}(a||(a={})),function(e){e.IMMEDIATE="immediate",e.ON_NEXT_RESTART="on_next_restart",e.ON_NEXT_RESUME="on_next_resume"}(i||(i={})),function(e){e.SHA256="SHA-256",e.SHA512="SHA-512"}(n||(n={})),function(e){e.UP_TO_DATE="UP_TO_DATE",e.UPDATE_AVAILABLE="UPDATE_AVAILABLE",e.UPDATE_INSTALLED="UPDATE_INSTALLED",e.ERROR="ERROR"}(s||(s={})),function(e){e.PENDING="PENDING",e.DOWNLOADING="DOWNLOADING",e.READY="READY",e.ACTIVE="ACTIVE",e.FAILED="FAILED"}(o||(o={})),function(e){e.UNKNOWN="UNKNOWN",e.PENDING="PENDING",e.DOWNLOADING="DOWNLOADING",e.DOWNLOADED="DOWNLOADED",e.INSTALLING="INSTALLING",e.INSTALLED="INSTALLED",e.FAILED="FAILED",e.CANCELED="CANCELED"}(l||(l={})),function(e){e.NETWORK_ERROR="NETWORK_ERROR",e.SERVER_ERROR="SERVER_ERROR",e.TIMEOUT_ERROR="TIMEOUT_ERROR",e.DOWNLOAD_ERROR="DOWNLOAD_ERROR",e.STORAGE_ERROR="STORAGE_ERROR",e.SIZE_LIMIT_EXCEEDED="SIZE_LIMIT_EXCEEDED",e.VERIFICATION_ERROR="VERIFICATION_ERROR",e.CHECKSUM_ERROR="CHECKSUM_ERROR",e.SIGNATURE_ERROR="SIGNATURE_ERROR",e.INSECURE_URL="INSECURE_URL",e.INVALID_CERTIFICATE="INVALID_CERTIFICATE",e.PATH_TRAVERSAL="PATH_TRAVERSAL",e.INSTALL_ERROR="INSTALL_ERROR",e.ROLLBACK_ERROR="ROLLBACK_ERROR",e.VERSION_MISMATCH="VERSION_MISMATCH",e.PERMISSION_DENIED="PERMISSION_DENIED",e.UPDATE_NOT_AVAILABLE="UPDATE_NOT_AVAILABLE",e.UPDATE_IN_PROGRESS="UPDATE_IN_PROGRESS",e.UPDATE_CANCELLED="UPDATE_CANCELLED",e.PLATFORM_NOT_SUPPORTED="PLATFORM_NOT_SUPPORTED",e.REVIEW_NOT_SUPPORTED="REVIEW_NOT_SUPPORTED",e.QUOTA_EXCEEDED="QUOTA_EXCEEDED",e.CONDITIONS_NOT_MET="CONDITIONS_NOT_MET",e.INVALID_CONFIG="INVALID_CONFIG",e.UNKNOWN_ERROR="UNKNOWN_ERROR"}(c||(c={}));class f{constructor(){this.config=this.getDefaultConfig()}static getInstance(){return f.instance||(f.instance=new f),f.instance}getDefaultConfig(){return{filesystem:null,preferences:null,baseUrl:"",allowedHosts:[],maxBundleSize:104857600,downloadTimeout:3e4,retryAttempts:3,retryDelay:1e3,enableSignatureValidation:!0,publicKey:"",cacheExpiration:864e5,enableLogging:!1,serverUrl:"",channel:"production",autoCheck:!0,autoUpdate:!1,updateStrategy:"background",requireSignature:!0,checksumAlgorithm:"SHA-256",checkInterval:864e5,security:{enforceHttps:!0,validateInputs:!0,secureStorage:!0,logSecurityEvents:!1},promptAfterPositiveEvents:!1,maxPromptsPerVersion:1,minimumDaysSinceLastPrompt:7,isPremiumUser:!1,appStoreId:"",iosAppId:"",packageName:"",webReviewUrl:"",minimumVersion:"1.0.0"}}configure(e){this.config=Object.assign(Object.assign({},this.config),e),this.validateConfig()}validateConfig(){if(this.config.maxBundleSize<=0)throw new Error("maxBundleSize must be greater than 0");if(this.config.downloadTimeout<=0)throw new Error("downloadTimeout must be greater than 0");if(this.config.retryAttempts<0)throw new Error("retryAttempts must be non-negative");if(this.config.retryDelay<0)throw new Error("retryDelay must be non-negative")}get(e){return this.config[e]}set(e,t){this.config[e]=t}getAll(){return Object.assign({},this.config)}isConfigured(){return!(!this.config.filesystem||!this.config.preferences)}}exports.LogLevel=void 0,(d=exports.LogLevel||(exports.LogLevel={}))[d.DEBUG=0]="DEBUG",d[d.INFO=1]="INFO",d[d.WARN=2]="WARN",d[d.ERROR=3]="ERROR";class E{constructor(e){this.configManager=f.getInstance(),this.context=e||"NativeUpdate"}static getInstance(){return E.instance||(E.instance=new E),E.instance}shouldLog(){return this.configManager.get("enableLogging")}sanitize(e){if("string"==typeof e){let t=e;return t=t.replace(/\/[^\s]+\/([\w.-]+)$/g,"/<path>/$1"),t=t.replace(/https?:\/\/[^:]+:[^@]+@/g,"https://***:***@"),t=t.replace(/[a-zA-Z0-9]{32,}/g,"<redacted>"),t}if("object"==typeof e&&null!==e){if(Array.isArray(e))return e.map(e=>this.sanitize(e));{const t={},r=e;for(const e in r)t[e]=e.toLowerCase().includes("key")||e.toLowerCase().includes("secret")||e.toLowerCase().includes("password")||e.toLowerCase().includes("token")?"<redacted>":this.sanitize(r[e]);return t}}return e}log(e,t){this.logWithLevel(exports.LogLevel.INFO,e,t)}logWithLevel(e,t,r){if(!this.shouldLog())return;const a=(new Date).toISOString(),i=r?this.sanitize(r):void 0,n={timestamp:a,level:exports.LogLevel[e],context:this.context,message:t};switch(void 0!==i&&(n.data=i),e){case exports.LogLevel.DEBUG:console.debug(`[${this.context}]`,n);break;case exports.LogLevel.INFO:console.info(`[${this.context}]`,n);break;case exports.LogLevel.WARN:console.warn(`[${this.context}]`,n);break;case exports.LogLevel.ERROR:console.error(`[${this.context}]`,n)}}debug(e,t){this.logWithLevel(exports.LogLevel.DEBUG,e,t)}info(e,t){this.logWithLevel(exports.LogLevel.INFO,e,t)}warn(e,t){this.logWithLevel(exports.LogLevel.WARN,e,t)}error(e,t){const r=t instanceof Error?{name:t.name,message:t.message,stack:t.stack}:t;this.logWithLevel(exports.LogLevel.ERROR,e,r)}}exports.ErrorCode=void 0,(u=exports.ErrorCode||(exports.ErrorCode={})).NOT_CONFIGURED="NOT_CONFIGURED",u.INVALID_CONFIG="INVALID_CONFIG",u.MISSING_DEPENDENCY="MISSING_DEPENDENCY",u.DOWNLOAD_FAILED="DOWNLOAD_FAILED",u.DOWNLOAD_TIMEOUT="DOWNLOAD_TIMEOUT",u.INVALID_URL="INVALID_URL",u.UNAUTHORIZED_HOST="UNAUTHORIZED_HOST",u.BUNDLE_TOO_LARGE="BUNDLE_TOO_LARGE",u.CHECKSUM_MISMATCH="CHECKSUM_MISMATCH",u.SIGNATURE_INVALID="SIGNATURE_INVALID",u.VERSION_DOWNGRADE="VERSION_DOWNGRADE",u.INVALID_BUNDLE_FORMAT="INVALID_BUNDLE_FORMAT",u.STORAGE_FULL="STORAGE_FULL",u.FILE_NOT_FOUND="FILE_NOT_FOUND",u.PERMISSION_DENIED="PERMISSION_DENIED",u.UPDATE_FAILED="UPDATE_FAILED",u.ROLLBACK_FAILED="ROLLBACK_FAILED",u.BUNDLE_NOT_READY="BUNDLE_NOT_READY",u.PLATFORM_NOT_SUPPORTED="PLATFORM_NOT_SUPPORTED",u.NATIVE_ERROR="NATIVE_ERROR";class w extends Error{constructor(e,t,r,a){super(t),this.code=e,this.message=t,this.details=r,this.originalError=a,this.name="NativeUpdateError",Object.setPrototypeOf(this,w.prototype)}toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,stack:this.stack}}}class I extends w{constructor(e,t,r,a){super(e,t,r,a),this.name="DownloadError"}}class y extends w{constructor(e,t,r){super(e,t,r),this.name="ValidationError"}}class D extends w{constructor(e,t,r,a){super(e,t,r,a),this.name="StorageError"}}class A extends w{constructor(e,t,r,a){super(e,t,r,a),this.name="UpdateError"}}class m{constructor(){this.configManager=f.getInstance(),this.logger=E.getInstance()}static getInstance(){return m.instance||(m.instance=new m),m.instance}static validateUrl(e){try{return"https:"===new URL(e).protocol}catch(e){return!1}}static validateChecksum(e){return/^[a-f0-9]{64}$/i.test(e)}static sanitizeInput(e){return e?e.replace(/<[^>]*>/g,"").replace(/[^\w\s/.-]/g,""):""}static validateBundleSize(e){return e>0&&e<=104857600}async calculateChecksum(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(e=>e.toString(16).padStart(2,"0")).join("")}async verifyChecksum(e,t){if(!t)return this.logger.warn("No checksum provided for verification"),!0;const r=await this.calculateChecksum(e),a=r===t.toLowerCase();return a||this.logger.error("Checksum verification failed",{expected:t,actual:r}),a}async validateChecksum(e,t){return this.verifyChecksum(e,t)}async verifySignature(e,t){if(!this.configManager.get("enableSignatureValidation"))return!0;const r=this.configManager.get("publicKey");if(!r)throw new y(exports.ErrorCode.SIGNATURE_INVALID,"Public key not configured for signature validation");try{const a=await crypto.subtle.importKey("spki",this.pemToArrayBuffer(r),{name:"RSA-PSS",hash:"SHA-256"},!1,["verify"]),i=await crypto.subtle.verify({name:"RSA-PSS",saltLength:32},a,this.base64ToArrayBuffer(t),e);return i||this.logger.error("Signature verification failed"),i}catch(e){return this.logger.error("Signature verification error",e),!1}}pemToArrayBuffer(e){const t=e.replace(/-----BEGIN PUBLIC KEY-----/g,"").replace(/-----END PUBLIC KEY-----/g,"").replace(/\s/g,"");return this.base64ToArrayBuffer(t)}base64ToArrayBuffer(e){const t=atob(e),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r.buffer}sanitizePath(e){return e.split("/").filter(e=>".."!==e&&"."!==e).join("/").replace(/^\/+/,"")}validateBundleId(e){if(!e||"string"!=typeof e)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID must be a non-empty string");if(!/^[a-zA-Z0-9\-_.]+$/.test(e))throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID contains invalid characters");if(e.length>100)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is too long (max 100 characters)")}validateVersion(e){if(!e||"string"!=typeof e)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Version must be a non-empty string");if(!/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(e))throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Version must follow semantic versioning format (e.g., 1.2.3)")}isVersionDowngrade(e,t){const r=this.parseVersion(e),a=this.parseVersion(t);return a.major<r.major||!(a.major>r.major)&&(a.minor<r.minor||!(a.minor>r.minor)&&a.patch<r.patch)}parseVersion(e){const t=e.split("-")[0].split(".");return{major:parseInt(t[0],10)||0,minor:parseInt(t[1],10)||0,patch:parseInt(t[2],10)||0}}validateUrl(e){if(!e||"string"!=typeof e)throw new y(exports.ErrorCode.INVALID_URL,"URL must be a non-empty string");let t;try{t=new URL(e)}catch(e){throw new y(exports.ErrorCode.INVALID_URL,"Invalid URL format")}if("https:"!==t.protocol)throw new y(exports.ErrorCode.INVALID_URL,"Only HTTPS URLs are allowed");const r=this.configManager.get("allowedHosts");if(r.length>0&&!r.includes(t.hostname))throw new y(exports.ErrorCode.UNAUTHORIZED_HOST,`Host ${t.hostname} is not in the allowed hosts list`);if([/^localhost$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2[0-9]|3[0-1])\./,/^192\.168\./,/^::1$/,/^fc00:/i,/^fe80:/i].some(e=>e.test(t.hostname)))throw new y(exports.ErrorCode.UNAUTHORIZED_HOST,"Private/local addresses are not allowed")}validateFileSize(e){if("number"!=typeof e||e<0)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"File size must be a non-negative number");const t=this.configManager.get("maxBundleSize");if(e>t)throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,`File size ${e} exceeds maximum allowed size of ${t} bytes`)}generateSecureId(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}async validateCertificatePin(e,t){const r=this.configManager.certificatePins;if(!r||!Array.isArray(r)||0===r.length)return!0;const a=r.filter(t=>t.hostname===e);if(0===a.length)return!0;const i=await this.calculateCertificateHash(t),n=a.some(e=>e.sha256===i);return n||this.logger.error("Certificate pinning validation failed",{hostname:e,expectedPins:a.map(e=>e.sha256),actualHash:i}),n}async calculateCertificateHash(e){const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t),a=Array.from(new Uint8Array(r));return"sha256/"+btoa(String.fromCharCode(...a))}validateMetadata(e){if(e&&"object"!=typeof e)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Metadata must be an object");if(JSON.stringify(e||{}).length>10240)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Metadata is too large (max 10KB)")}}class N{constructor(){this.STORAGE_KEY="capacitor_native_update_bundles",this.ACTIVE_BUNDLE_KEY="capacitor_native_update_active",this.preferences=null,this.cache=new Map,this.cacheExpiry=0,this.logger=E.getInstance(),this.configManager=f.getInstance()}async initialize(){if(this.preferences=this.configManager.get("preferences"),!this.preferences)throw new D(exports.ErrorCode.MISSING_DEPENDENCY,"Preferences not configured. Please configure the plugin first.");await this.loadCache()}async loadCache(){if(!(Date.now()<this.cacheExpiry))try{const{value:e}=await this.preferences.get({key:this.STORAGE_KEY});if(e){const t=JSON.parse(e);this.cache.clear(),t.forEach(e=>this.cache.set(e.bundleId,e))}this.cacheExpiry=Date.now()+5e3}catch(e){this.logger.error("Failed to load bundles from storage",e),this.cache.clear()}}async saveCache(){try{const e=Array.from(this.cache.values());await this.preferences.set({key:this.STORAGE_KEY,value:JSON.stringify(e)}),this.logger.debug("Saved bundles to storage",{count:e.length})}catch(e){throw new D(exports.ErrorCode.STORAGE_FULL,"Failed to save bundles to storage",void 0,e)}}async saveBundleInfo(e){this.validateBundleInfo(e),this.cache.set(e.bundleId,e),await this.saveCache(),this.logger.info("Bundle saved",{bundleId:e.bundleId,version:e.version})}validateBundleInfo(e){if(!e.bundleId||"string"!=typeof e.bundleId)throw new D(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle ID");if(!e.version||"string"!=typeof e.version)throw new D(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle version");if(!e.path||"string"!=typeof e.path)throw new D(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle path");if("number"!=typeof e.size||e.size<0)throw new D(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle size")}async getAllBundles(){return await this.loadCache(),Array.from(this.cache.values())}async getBundle(e){if(!e)throw new D(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");return await this.loadCache(),this.cache.get(e)||null}async deleteBundle(e){if(!e)throw new D(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");await this.loadCache(),this.cache.get(e)?(this.cache.delete(e),await this.saveCache(),await this.getActiveBundleId()===e&&await this.clearActiveBundle(),this.logger.info("Bundle deleted",{bundleId:e})):this.logger.warn("Attempted to delete non-existent bundle",{bundleId:e})}async getActiveBundle(){const e=await this.getActiveBundleId();return e?this.getBundle(e):null}async setActiveBundle(e){if(!e)throw new D(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");const t=await this.getBundle(e);if(!t)throw new D(exports.ErrorCode.FILE_NOT_FOUND,`Bundle ${e} not found`);const r=await this.getActiveBundle();r&&r.bundleId!==e&&(r.status="READY",await this.saveBundleInfo(r)),t.status="ACTIVE",await this.saveBundleInfo(t),await this.preferences.set({key:this.ACTIVE_BUNDLE_KEY,value:e}),this.logger.info("Active bundle set",{bundleId:e,version:t.version})}async getActiveBundleId(){try{const{value:e}=await this.preferences.get({key:this.ACTIVE_BUNDLE_KEY});return e}catch(e){return this.logger.error("Failed to get active bundle ID",e),null}}async clearActiveBundle(){await this.preferences.remove({key:this.ACTIVE_BUNDLE_KEY}),this.logger.info("Active bundle cleared")}async clearAllBundles(){await this.preferences.remove({key:this.STORAGE_KEY}),await this.preferences.remove({key:this.ACTIVE_BUNDLE_KEY}),this.cache.clear(),this.cacheExpiry=0,this.logger.info("All bundles cleared")}async cleanupOldBundles(e){if(e<1)throw new D(exports.ErrorCode.INVALID_CONFIG,"Keep count must be at least 1");const t=await this.getAllBundles(),r=await this.getActiveBundleId(),a=t.sort((e,t)=>t.downloadTime-e.downloadTime),i=new Set;r&&i.add(r);let n=i.size;for(const t of a){if(n>=e)break;i.has(t.bundleId)||(i.add(t.bundleId),n++)}let s=0;for(const e of t)i.has(e.bundleId)||(await this.deleteBundle(e.bundleId),s++);s>0&&this.logger.info("Cleaned up old bundles",{deleted:s,kept:n})}async getBundlesOlderThan(e){if(e<0)throw new D(exports.ErrorCode.INVALID_CONFIG,"Timestamp must be non-negative");return(await this.getAllBundles()).filter(t=>t.downloadTime<e)}async markBundleAsVerified(e){const t=await this.getBundle(e);if(!t)throw new D(exports.ErrorCode.FILE_NOT_FOUND,`Bundle ${e} not found`);t.verified=!0,await this.saveBundleInfo(t),this.logger.info("Bundle marked as verified",{bundleId:e})}async getTotalStorageUsed(){return(await this.getAllBundles()).reduce((e,t)=>e+t.size,0)}async isStorageLimitExceeded(e=0){return await this.getTotalStorageUsed()+e>3*this.configManager.get("maxBundleSize")}createDefaultBundle(){return{bundleId:"default",version:"1.0.0",path:"/",downloadTime:Date.now(),size:0,status:"ACTIVE",checksum:"",verified:!0}}async cleanExpiredBundles(){const e=this.configManager.get("cacheExpiration"),t=Date.now()-e,r=await this.getBundlesOlderThan(t);for(const e of r){const t=await this.getActiveBundleId();e.bundleId!==t&&await this.deleteBundle(e.bundleId)}}}class _{constructor(){this.activeDownloads=new Map,this.filesystem=null,this.logger=E.getInstance(),this.configManager=f.getInstance()}async initialize(){if(this.filesystem=this.configManager.get("filesystem"),!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not configured. Please configure the plugin first.")}validateUrl(e){try{const t=new URL(e);if("https:"!==t.protocol)throw new y(exports.ErrorCode.INVALID_URL,"Only HTTPS URLs are allowed for security reasons");const r=this.configManager.get("allowedHosts");if(r.length>0&&!r.includes(t.hostname))throw new y(exports.ErrorCode.UNAUTHORIZED_HOST,`Host ${t.hostname} is not in the allowed hosts list`)}catch(e){if(e instanceof y)throw e;throw new y(exports.ErrorCode.INVALID_URL,"Invalid URL format")}}async download(e,t,r){if(this.validateUrl(e),!t)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");if(this.activeDownloads.has(t))throw new I(exports.ErrorCode.DOWNLOAD_FAILED,`Download already in progress for bundle ${t}`);const a=new AbortController,i={controller:a,startTime:Date.now()};this.activeDownloads.set(t,i);try{const n=this.configManager.get("downloadTimeout"),s=setTimeout(()=>a.abort(),n),o=await fetch(e,{signal:a.signal,headers:{"Cache-Control":"no-cache",Accept:"application/octet-stream, application/zip"}});if(clearTimeout(s),!o.ok)throw new I(exports.ErrorCode.DOWNLOAD_FAILED,`Download failed: ${o.status} ${o.statusText}`,{status:o.status,statusText:o.statusText});const l=o.headers.get("content-type");if(l&&!this.isValidContentType(l))throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,`Invalid content type: ${l}`);const c=o.headers.get("content-length"),d=c?parseInt(c,10):0;if(d>this.configManager.get("maxBundleSize"))throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,`Bundle size ${d} exceeds maximum allowed size`);if(!d||!o.body){const e=await o.blob();return this.validateBlobSize(e),e}const u=o.body.getReader(),h=[];let g=0;for(;;){const{done:e,value:a}=await u.read();if(e)break;if(h.push(a),g+=a.length,g>this.configManager.get("maxBundleSize"))throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,"Download size exceeds maximum allowed size");r&&r({percent:Math.round(g/d*100),bytesDownloaded:g,totalBytes:d,bundleId:t})}const p=new Blob(h);return this.validateBlobSize(p),this.logger.info("Download completed",{bundleId:t,size:p.size,duration:Date.now()-i.startTime}),p}catch(e){if(e instanceof Error&&"AbortError"===e.name){const t=Date.now()-i.startTime>=this.configManager.get("downloadTimeout");throw new I(t?exports.ErrorCode.DOWNLOAD_TIMEOUT:exports.ErrorCode.DOWNLOAD_FAILED,t?"Download timed out":"Download cancelled",void 0,e)}throw e}finally{this.activeDownloads.delete(t)}}isValidContentType(e){return["application/octet-stream","application/zip","application/x-zip-compressed","application/x-zip"].some(t=>e.includes(t))}validateBlobSize(e){if(0===e.size)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Downloaded file is empty");if(e.size>this.configManager.get("maxBundleSize"))throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,`File size ${e.size} exceeds maximum allowed size`)}cancelDownload(e){const t=this.activeDownloads.get(e);t&&(t.controller.abort(),this.activeDownloads.delete(e),this.logger.info("Download cancelled",{bundleId:e}))}cancelAllDownloads(){for(const e of this.activeDownloads.values())e.controller.abort();const e=this.activeDownloads.size;this.activeDownloads.clear(),e>0&&this.logger.info("All downloads cancelled",{count:e})}isDownloading(e){return this.activeDownloads.has(e)}getActiveDownloadCount(){return this.activeDownloads.size}async downloadWithRetry(e,t,r){const a=this.configManager.get("retryAttempts"),i=this.configManager.get("retryDelay");let n=null;for(let s=0;s<a;s++)try{if(s>0){const e=Math.min(i*Math.pow(2,s-1),3e4);await new Promise(t=>setTimeout(t,e)),this.logger.debug("Retrying download",{bundleId:t,attempt:s,delay:e})}return await this.download(e,t,r)}catch(e){if(n=e,e instanceof y||e instanceof Error&&"AbortError"===e.name)throw e;this.logger.warn(`Download attempt ${s+1} failed`,{bundleId:t,error:e})}throw new I(exports.ErrorCode.DOWNLOAD_FAILED,"Download failed after all retries",{attempts:a},n||void 0)}async blobToArrayBuffer(e){return e.arrayBuffer()}async saveBlob(e,t){if(!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");const r=await this.blobToArrayBuffer(t),a=btoa(String.fromCharCode(...new Uint8Array(r))),i=`bundles/${e}/bundle.zip`;return await this.filesystem.writeFile({path:i,data:a,directory:g.Directory.Data,recursive:!0}),this.logger.debug("Bundle saved to filesystem",{bundleId:e,path:i,size:t.size}),i}async loadBlob(e){if(!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");try{const t=`bundles/${e}/bundle.zip`,r=await this.filesystem.readFile({path:t,directory:g.Directory.Data}),a=atob(r.data),i=new Uint8Array(a.length);for(let e=0;e<a.length;e++)i[e]=a.charCodeAt(e);return new Blob([i],{type:"application/zip"})}catch(t){return this.logger.debug("Failed to load bundle from filesystem",{bundleId:e,error:t}),null}}async deleteBlob(e){if(!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");try{const t=`bundles/${e}`;await this.filesystem.rmdir({path:t,directory:g.Directory.Data,recursive:!0}),this.logger.debug("Bundle deleted from filesystem",{bundleId:e})}catch(t){this.logger.warn("Failed to delete bundle from filesystem",{bundleId:e,error:t})}}}class C{constructor(){this.VERSION_CHECK_CACHE_KEY="capacitor_native_update_version_cache",this.CACHE_DURATION=3e5,this.preferences=null,this.memoryCache=new Map,this.logger=E.getInstance(),this.configManager=f.getInstance(),this.securityValidator=m.getInstance()}static compareVersions(e,t){try{const[r,a]=e.split("-"),[i,n]=t.split("-"),s=r.split(".").map(Number),o=i.split(".").map(Number);for(let e=0;e<3;e++){const t=s[e]||0,r=o[e]||0;if(t>r)return 1;if(t<r)return-1}return a&&!n?-1:!a&&n?1:a&&n?a.localeCompare(n):0}catch(r){return e===t?0:e>t?1:-1}}static isValidVersion(e){return/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/.test(e)}static shouldUpdate(e,t,r){return!(r&&C.compareVersions(e,r)<0)&&C.compareVersions(e,t)<0}async initialize(){if(this.preferences=this.configManager.get("preferences"),!this.preferences)throw new y(exports.ErrorCode.MISSING_DEPENDENCY,"Preferences not configured. Please configure the plugin first.")}async checkForUpdates(e,t,r,a){if(this.securityValidator.validateUrl(e),this.securityValidator.validateVersion(r),!t||!a)throw new y(exports.ErrorCode.INVALID_CONFIG,"Channel and appId are required");const i=`${t}-${a}`,n=await this.getCachedVersionInfo(i);if(n&&n.channel===t&&Date.now()-n.timestamp<this.CACHE_DURATION)return this.logger.debug("Returning cached version info",{channel:t,version:n.data.version}),n.data;try{const n=new URL(`${e}/check`);n.searchParams.append("channel",t),n.searchParams.append("version",r),n.searchParams.append("appId",a),n.searchParams.append("platform","web");const s=await fetch(n.toString(),{method:"GET",headers:{"Content-Type":"application/json","X-App-Version":r,"X-App-Id":a},signal:AbortSignal.timeout(this.configManager.get("downloadTimeout"))});if(!s.ok)throw new Error(`Version check failed: ${s.status}`);const o=await s.json();if(!o.version)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"No version in server response");return this.securityValidator.validateVersion(o.version),o.bundleUrl&&this.securityValidator.validateUrl(o.bundleUrl),o.minAppVersion&&this.securityValidator.validateVersion(o.minAppVersion),await this.cacheVersionInfo(i,t,o),this.logger.info("Version check completed",{channel:t,currentVersion:r,latestVersion:o.version,updateAvailable:this.isNewerVersion(o.version,r)}),o}catch(e){return this.logger.error("Failed to check for updates",e),null}}isNewerVersion(e,t){try{const r=this.parseVersion(e),a=this.parseVersion(t);return r.major!==a.major?r.major>a.major:r.minor!==a.minor?r.minor>a.minor:r.patch!==a.patch?r.patch>a.patch:!(r.prerelease&&!a.prerelease||(r.prerelease||!a.prerelease)&&(!r.prerelease||!a.prerelease||!(r.prerelease>a.prerelease)))}catch(r){return this.logger.error("Failed to compare versions",{version1:e,version2:t,error:r}),!1}}isUpdateMandatory(e,t){if(!t)return!1;try{return this.securityValidator.validateVersion(e),this.securityValidator.validateVersion(t),!this.isNewerVersion(e,t)&&e!==t}catch(e){return this.logger.error("Failed to check mandatory update",e),!1}}parseVersion(e){const t=e.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/);if(!t)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid version format");return{major:parseInt(t[1],10),minor:parseInt(t[2],10),patch:parseInt(t[3],10),prerelease:t[4],build:t[5]}}buildVersionString(e){let t=`${e.major}.${e.minor}.${e.patch}`;return e.prerelease&&(t+=`-${e.prerelease}`),e.build&&(t+=`+${e.build}`),t}isCompatibleWithNativeVersion(e,t,r){if(!r)return!0;try{const a=r[e];return!a||(this.securityValidator.validateVersion(t),this.securityValidator.validateVersion(a),!this.isNewerVersion(a,t))}catch(e){return this.logger.error("Failed to check compatibility",e),!1}}async getCachedVersionInfo(e){const t=this.memoryCache.get(e);if(t&&Date.now()-t.timestamp<this.CACHE_DURATION)return t;try{const{value:t}=await this.preferences.get({key:this.VERSION_CHECK_CACHE_KEY});if(!t)return null;const r=JSON.parse(t)[e];if(r&&Date.now()-r.timestamp<this.CACHE_DURATION)return this.memoryCache.set(e,r),r}catch(e){this.logger.debug("Failed to load cached version info",e)}return null}async cacheVersionInfo(e,t,r){const a={channel:t,data:r,timestamp:Date.now()};this.memoryCache.set(e,a);try{const{value:t}=await this.preferences.get({key:this.VERSION_CHECK_CACHE_KEY}),r=t?JSON.parse(t):{},i=Date.now();for(const e in r)i-r[e].timestamp>2*this.CACHE_DURATION&&delete r[e];r[e]=a,await this.preferences.set({key:this.VERSION_CHECK_CACHE_KEY,value:JSON.stringify(r)})}catch(e){this.logger.warn("Failed to cache version info",e)}}async clearVersionCache(){this.memoryCache.clear();try{await this.preferences.remove({key:this.VERSION_CHECK_CACHE_KEY})}catch(e){this.logger.warn("Failed to clear version cache",e)}}shouldBlockDowngrade(e,t){try{return this.securityValidator.isVersionDowngrade(e,t)}catch(e){return this.logger.error("Failed to check downgrade",e),!0}}}class v{constructor(){this.bundleManager=null,this.downloadManager=null,this.versionManager=null,this.initialized=!1,this.configManager=f.getInstance(),this.logger=E.getInstance(),this.securityValidator=m.getInstance()}static getInstance(){return v.instance||(v.instance=new v),v.instance}async initialize(e){if(this.initialized)this.logger.warn("Plugin already initialized");else try{this.configManager.configure(e),e.filesystem||(e.filesystem=g.Filesystem),e.preferences||(e.preferences=p.Preferences),this.bundleManager=new N,await this.bundleManager.initialize(),this.downloadManager=new _,await this.downloadManager.initialize(),this.versionManager=new C,await this.versionManager.initialize(),this.initialized=!0,this.logger.info("Plugin initialized successfully")}catch(e){throw this.logger.error("Failed to initialize plugin",e),e}}isInitialized(){return this.initialized&&this.configManager.isConfigured()}ensureInitialized(){if(!this.isInitialized())throw new w(exports.ErrorCode.NOT_CONFIGURED,"Plugin not initialized. Please call initialize() first.")}getBundleManager(){return this.ensureInitialized(),this.bundleManager}getDownloadManager(){return this.ensureInitialized(),this.downloadManager}getVersionManager(){return this.ensureInitialized(),this.versionManager}getConfigManager(){return this.configManager}getLogger(){return this.logger}getSecurityValidator(){return this.securityValidator}async reset(){this.logger.info("Resetting plugin state"),this.bundleManager&&await this.bundleManager.clearAllBundles(),this.versionManager&&await this.versionManager.clearVersionCache(),this.downloadManager&&this.downloadManager.cancelAllDownloads(),this.bundleManager=null,this.downloadManager=null,this.versionManager=null,this.initialized=!1,this.logger.info("Plugin reset complete")}async cleanup(){this.logger.info("Cleaning up plugin resources"),this.downloadManager&&this.downloadManager.cancelAllDownloads(),this.bundleManager&&await this.bundleManager.cleanExpiredBundles(),this.logger.info("Cleanup complete")}}class R{constructor(){this.initialized=!1,this.pluginManager=v.getInstance()}async initialize(e){await this.pluginManager.initialize(e),this.initialized=!0}isInitialized(){return this.initialized&&this.pluginManager.isInitialized()}async reset(){await this.pluginManager.reset()}async cleanup(){await this.pluginManager.cleanup()}async configure(e){var t;let r;r="config"in e&&"object"==typeof e.config?e.config:{baseUrl:null===(t=e.liveUpdate)||void 0===t?void 0:t.serverUrl},this.initialized?this.pluginManager.getConfigManager().configure(r):await this.initialize(r)}async getSecurityInfo(){return{enforceHttps:!0,certificatePinning:{enabled:!1,pins:[]},validateInputs:!0,secureStorage:!0}}async sync(e){const t=this.pluginManager.getBundleManager();try{const e=await t.getActiveBundle();return{status:s.UP_TO_DATE,version:(null==e?void 0:e.version)||"1.0.0"}}catch(e){return{status:s.ERROR,error:{code:c.UNKNOWN_ERROR,message:e instanceof Error?e.message:"Sync failed"}}}}async download(e){const t=this.pluginManager.getDownloadManager(),r=this.pluginManager.getBundleManager(),a=await t.downloadWithRetry(e.url,e.version),i=await t.saveBlob(e.version,a),n={bundleId:e.version,version:e.version,path:i,downloadTime:Date.now(),size:a.size,status:o.READY,checksum:e.checksum,signature:e.signature,verified:!1};return await r.saveBundleInfo(n),n}async set(e){const t=this.pluginManager.getBundleManager();await t.setActiveBundle(e.bundleId)}async reload(){"undefined"!=typeof window&&window.location.reload()}async current(){const e=this.pluginManager.getBundleManager(),t=await e.getActiveBundle();if(!t)throw new w(exports.ErrorCode.FILE_NOT_FOUND,"No active bundle found");return t}async list(){return this.pluginManager.getBundleManager().getAllBundles()}async delete(e){const t=this.pluginManager.getBundleManager();if(e.bundleId)await t.deleteBundle(e.bundleId);else if(void 0!==e.keepVersions){const r=(await t.getAllBundles()).sort((e,t)=>t.downloadTime-e.downloadTime);for(let a=e.keepVersions;a<r.length;a++)await t.deleteBundle(r[a].bundleId)}}async notifyAppReady(){const e=this.pluginManager.getBundleManager(),t=await e.getActiveBundle();t&&(t.status=o.ACTIVE,await e.saveBundleInfo(t))}async getLatest(){return{available:!1}}async setChannel(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"update_channel",value:e})}async setUpdateUrl(e){this.pluginManager.getConfigManager().configure({baseUrl:e})}async validateUpdate(e){const t=this.pluginManager.getSecurityValidator();try{const r=await t.validateChecksum(new ArrayBuffer(0),e.checksum);return{isValid:r,details:{checksumValid:r,signatureValid:!0,sizeValid:!0,versionValid:!0}}}catch(e){return{isValid:!1,error:e instanceof Error?e.message:"Validation failed"}}}async getAppUpdateInfo(){return{updateAvailable:!1,currentVersion:"1.0.0"}}async performImmediateUpdate(){throw new w(exports.ErrorCode.PLATFORM_NOT_SUPPORTED,"Native app updates are not supported on web")}async startFlexibleUpdate(){throw new w(exports.ErrorCode.PLATFORM_NOT_SUPPORTED,"Native app updates are not supported on web")}async completeFlexibleUpdate(){throw new w(exports.ErrorCode.PLATFORM_NOT_SUPPORTED,"Native app updates are not supported on web")}async openAppStore(e){throw new w(exports.ErrorCode.PLATFORM_NOT_SUPPORTED,"App store is not available on web")}async requestReview(){return{displayed:!1,error:"Reviews are not supported on web"}}async canRequestReview(){return{canRequest:!1,reason:"Reviews are not supported on web"}}async enableBackgroundUpdates(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"background_update_config",value:JSON.stringify(e)})}async disableBackgroundUpdates(){const e=this.pluginManager.getConfigManager().get("preferences");e&&await e.remove({key:"background_update_config"})}async getBackgroundUpdateStatus(){return{enabled:!1,isRunning:!1,checkCount:0,failureCount:0}}async scheduleBackgroundCheck(e){throw new w(exports.ErrorCode.PLATFORM_NOT_SUPPORTED,"Background updates are not supported on web")}async triggerBackgroundCheck(){return{success:!1,updatesFound:!1,notificationSent:!1,error:{code:c.PLATFORM_NOT_SUPPORTED,message:"Background updates are not supported on web"}}}async setNotificationPreferences(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"notification_preferences",value:JSON.stringify(e)})}async getNotificationPermissions(){return{granted:!1,canRequest:!1}}async requestNotificationPermissions(){return!1}async addListener(e,t){return{remove:async()=>{}}}async removeAllListeners(){}}const O=h.registerPlugin("NativeUpdate",{web:()=>new R});exports.BundleManager=N,exports.CacheManager=class{constructor(){this.filesystem=null,this.memoryCache=new Map,this.CACHE_DIR="cache",this.logger=E.getInstance(),this.configManager=f.getInstance()}async initialize(){if(this.filesystem=this.configManager.get("filesystem"),!this.filesystem)throw new Error("Filesystem not configured");try{await this.filesystem.mkdir({path:this.CACHE_DIR,directory:g.Directory.Data,recursive:!0})}catch(e){this.logger.debug("Cache directory may already exist",e)}await this.cleanExpiredCache()}async set(e,t,r){const a=Date.now()+(r||this.configManager.get("cacheExpiration")),i={data:t,timestamp:Date.now(),expiry:a};this.memoryCache.set(e,i),this.shouldPersist(t)&&await this.persistToFile(e,i),this.logger.debug("Cache entry set",{key:e,expiry:new Date(a)})}async get(e){const t=this.memoryCache.get(e);if(t){if(Date.now()<t.expiry)return t.data;this.memoryCache.delete(e)}const r=await this.loadFromFile(e);if(r){if(Date.now()<r.expiry)return this.memoryCache.set(e,r),r.data;await this.removeFile(e)}return null}async has(e){return null!==await this.get(e)}async remove(e){this.memoryCache.delete(e),await this.removeFile(e),this.logger.debug("Cache entry removed",{key:e})}async clear(){this.memoryCache.clear();try{await this.filesystem.rmdir({path:this.CACHE_DIR,directory:g.Directory.Data,recursive:!0}),await this.filesystem.mkdir({path:this.CACHE_DIR,directory:g.Directory.Data,recursive:!0})}catch(e){this.logger.warn("Failed to clear cache directory",e)}this.logger.info("Cache cleared")}async cleanExpiredCache(){const e=Date.now();let t=0;for(const[r,a]of this.memoryCache)e>=a.expiry&&(this.memoryCache.delete(r),t++);try{const r=await this.filesystem.readdir({path:this.CACHE_DIR,directory:g.Directory.Data});for(const a of r.files){const r=a.name.replace(".json",""),i=await this.loadFromFile(r);(!i||e>=i.expiry)&&(await this.removeFile(r),t++)}}catch(e){this.logger.debug("Failed to clean filesystem cache",e)}t>0&&this.logger.info("Cleaned expired cache entries",{count:t})}async getStats(){let e=0,t=0;try{const r=await this.filesystem.readdir({path:this.CACHE_DIR,directory:g.Directory.Data});e=r.files.length;for(const e of r.files)t+=(await this.filesystem.stat({path:`${this.CACHE_DIR}/${e.name}`,directory:g.Directory.Data})).size||0}catch(e){this.logger.debug("Failed to get cache stats",e)}return{memoryEntries:this.memoryCache.size,fileEntries:e,totalSize:t}}async cacheBundleMetadata(e){const t=`bundle_meta_${e.bundleId}`;await this.set(t,e,864e5)}async getCachedBundleMetadata(e){return this.get(`bundle_meta_${e}`)}shouldPersist(e){return"object"==typeof e||"string"==typeof e&&e.length>1024}async persistToFile(e,t){if(this.filesystem)try{const r=`${this.CACHE_DIR}/${e}.json`,a=JSON.stringify(t);await this.filesystem.writeFile({path:r,data:a,directory:g.Directory.Data,encoding:g.Encoding.UTF8})}catch(t){this.logger.warn("Failed to persist cache to file",{key:e,error:t})}}async loadFromFile(e){if(!this.filesystem)return null;try{const t=`${this.CACHE_DIR}/${e}.json`,r=await this.filesystem.readFile({path:t,directory:g.Directory.Data,encoding:g.Encoding.UTF8});return JSON.parse(r.data)}catch(e){return null}}async removeFile(e){if(this.filesystem)try{const t=`${this.CACHE_DIR}/${e}.json`;await this.filesystem.deleteFile({path:t,directory:g.Directory.Data})}catch(t){this.logger.debug("Failed to remove cache file",{key:e,error:t})}}},exports.ConfigManager=f,exports.ConfigurationError=class extends w{constructor(e,t){super(exports.ErrorCode.INVALID_CONFIG,e,t),this.name="ConfigurationError"}},exports.DownloadError=I,exports.DownloadManager=_,exports.Logger=E,exports.NativeUpdate=O,exports.NativeUpdateError=w,exports.PluginManager=v,exports.SecurityValidator=m,exports.StorageError=D,exports.UpdateErrorClass=A,exports.UpdateManager=class{constructor(){this.filesystem=null,this.updateInProgress=!1,this.currentState=null,this.pluginManager=v.getInstance(),this.securityValidator=m.getInstance()}async initialize(){if(this.filesystem=this.pluginManager.getConfigManager().get("filesystem"),!this.filesystem)throw new A(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not configured")}async applyUpdate(e,t){if(this.updateInProgress)throw new A(exports.ErrorCode.UPDATE_FAILED,"Another update is already in progress");const r=this.pluginManager.getLogger(),a=this.pluginManager.getBundleManager();try{this.updateInProgress=!0,r.info("Starting bundle update",{bundleId:e});const i=await a.getBundle(e);if(!i)throw new A(exports.ErrorCode.FILE_NOT_FOUND,`Bundle ${e} not found`);if("READY"!==i.status&&"ACTIVE"!==i.status)throw new A(exports.ErrorCode.BUNDLE_NOT_READY,`Bundle ${e} is not ready for installation`);const n=await a.getActiveBundle();this.currentState={currentBundle:n,newBundle:i,backupPath:null,startTime:Date.now()},await this.validateUpdate(n,i,t),n&&"default"!==n.bundleId&&(this.currentState.backupPath=await this.createBackup(n)),await this.performUpdate(i),await this.verifyUpdate(i),await a.setActiveBundle(e),(null==t?void 0:t.cleanupOldBundles)&&await a.cleanupOldBundles(t.keepBundleCount||3),r.info("Bundle update completed successfully",{bundleId:e,version:i.version,duration:Date.now()-this.currentState.startTime}),this.currentState=null}catch(e){throw r.error("Bundle update failed",e),this.currentState&&await this.rollback(),e}finally{this.updateInProgress=!1}}async validateUpdate(e,t,r){const a=this.pluginManager.getLogger(),i=this.pluginManager.getVersionManager();if(e&&!(null==r?void 0:r.allowDowngrade)&&i.shouldBlockDowngrade(e.version,t.version))throw new y(exports.ErrorCode.VERSION_DOWNGRADE,`Cannot downgrade from ${e.version} to ${t.version}`);if(!t.verified){a.warn("Bundle not verified, verifying now",{bundleId:t.bundleId});const e=this.pluginManager.getDownloadManager(),r=await e.loadBlob(t.bundleId);if(!r)throw new A(exports.ErrorCode.FILE_NOT_FOUND,"Bundle data not found");const i=await r.arrayBuffer();if(!await this.securityValidator.verifyChecksum(i,t.checksum))throw new y(exports.ErrorCode.CHECKSUM_MISMATCH,"Bundle checksum verification failed");if(t.signature&&!await this.securityValidator.verifySignature(i,t.signature))throw new y(exports.ErrorCode.SIGNATURE_INVALID,"Bundle signature verification failed");await this.pluginManager.getBundleManager().markBundleAsVerified(t.bundleId)}a.debug("Bundle validation passed",{bundleId:t.bundleId})}async createBackup(e){const t=`backups/${e.bundleId}_${Date.now()}`,r=this.pluginManager.getLogger();try{return await this.filesystem.mkdir({path:t,directory:g.Directory.Data,recursive:!0}),await this.filesystem.copy({from:e.path,to:t,directory:g.Directory.Data}),r.info("Backup created",{bundleId:e.bundleId,backupPath:t}),t}catch(e){throw r.error("Failed to create backup",e),new A(exports.ErrorCode.UPDATE_FAILED,"Failed to create backup",void 0,e)}}async performUpdate(e){const t=this.pluginManager.getLogger();try{const r=`active/${e.bundleId}`;await this.filesystem.mkdir({path:r,directory:g.Directory.Data,recursive:!0}),await this.filesystem.copy({from:e.path,to:r,directory:g.Directory.Data}),e.path=r,t.debug("Bundle files installed",{bundleId:e.bundleId,targetPath:r})}catch(e){throw new A(exports.ErrorCode.UPDATE_FAILED,"Failed to install bundle files",void 0,e)}}async verifyUpdate(e){try{const t=`${e.path}/index.html`;await this.filesystem.stat({path:t,directory:g.Directory.Data})}catch(e){throw new A(exports.ErrorCode.UPDATE_FAILED,"Bundle verification failed after installation",void 0,e)}}async rollback(){var e;if(!this.currentState)throw new A(exports.ErrorCode.ROLLBACK_FAILED,"No update state to rollback");const t=this.pluginManager.getLogger();t.warn("Starting rollback",{from:this.currentState.newBundle.bundleId,to:(null===(e=this.currentState.currentBundle)||void 0===e?void 0:e.bundleId)||"default"});try{const e=this.pluginManager.getBundleManager();if(this.currentState.backupPath&&this.currentState.currentBundle){const t=`active/${this.currentState.currentBundle.bundleId}`;await this.filesystem.copy({from:this.currentState.backupPath,to:t,directory:g.Directory.Data}),this.currentState.currentBundle.path=t,await e.saveBundleInfo(this.currentState.currentBundle)}this.currentState.currentBundle?await e.setActiveBundle(this.currentState.currentBundle.bundleId):await e.clearActiveBundle(),t.info("Rollback completed successfully")}catch(e){throw t.error("Rollback failed",e),new A(exports.ErrorCode.ROLLBACK_FAILED,"Failed to rollback update",void 0,e)}finally{if(this.currentState.backupPath)try{await this.filesystem.rmdir({path:this.currentState.backupPath,directory:g.Directory.Data,recursive:!0})}catch(e){t.warn("Failed to clean up backup",e)}}}getUpdateProgress(){var e,t;return{inProgress:this.updateInProgress,bundleId:null===(e=this.currentState)||void 0===e?void 0:e.newBundle.bundleId,startTime:null===(t=this.currentState)||void 0===t?void 0:t.startTime}}async cancelUpdate(){this.updateInProgress&&this.currentState&&(this.pluginManager.getLogger().warn("Cancelling update",{bundleId:this.currentState.newBundle.bundleId}),await this.rollback(),this.updateInProgress=!1,this.currentState=null)}},exports.ValidationError=y,exports.VersionManager=C;
|
|
1
|
+
var e,t,r,a,i,n,s,o,l,c,d,h,u,g=require("@capacitor/core"),p=require("@capacitor/filesystem"),f=require("@capacitor/preferences");!function(e){e.APP_UPDATE="app_update",e.LIVE_UPDATE="live_update",e.BOTH="both"}(e||(e={})),function(e){e.MIN="min",e.LOW="low",e.DEFAULT="default",e.HIGH="high",e.MAX="max"}(t||(t={})),function(e){e.IMMEDIATE="immediate",e.BACKGROUND="background",e.MANUAL="manual"}(r||(r={})),function(e){e.IMMEDIATE="immediate",e.ON_NEXT_RESTART="on_next_restart",e.ON_NEXT_RESUME="on_next_resume"}(a||(a={})),function(e){e.IMMEDIATE="immediate",e.ON_NEXT_RESTART="on_next_restart",e.ON_NEXT_RESUME="on_next_resume"}(i||(i={})),function(e){e.SHA256="SHA-256",e.SHA512="SHA-512"}(n||(n={})),function(e){e.UP_TO_DATE="UP_TO_DATE",e.UPDATE_AVAILABLE="UPDATE_AVAILABLE",e.UPDATE_INSTALLED="UPDATE_INSTALLED",e.ERROR="ERROR"}(s||(s={})),function(e){e.PENDING="PENDING",e.DOWNLOADING="DOWNLOADING",e.READY="READY",e.ACTIVE="ACTIVE",e.FAILED="FAILED"}(o||(o={})),function(e){e.UNKNOWN="UNKNOWN",e.PENDING="PENDING",e.DOWNLOADING="DOWNLOADING",e.DOWNLOADED="DOWNLOADED",e.INSTALLING="INSTALLING",e.INSTALLED="INSTALLED",e.FAILED="FAILED",e.CANCELED="CANCELED"}(l||(l={})),function(e){e.NETWORK_ERROR="NETWORK_ERROR",e.SERVER_ERROR="SERVER_ERROR",e.TIMEOUT_ERROR="TIMEOUT_ERROR",e.DOWNLOAD_ERROR="DOWNLOAD_ERROR",e.STORAGE_ERROR="STORAGE_ERROR",e.SIZE_LIMIT_EXCEEDED="SIZE_LIMIT_EXCEEDED",e.VERIFICATION_ERROR="VERIFICATION_ERROR",e.CHECKSUM_ERROR="CHECKSUM_ERROR",e.SIGNATURE_ERROR="SIGNATURE_ERROR",e.INSECURE_URL="INSECURE_URL",e.INVALID_CERTIFICATE="INVALID_CERTIFICATE",e.PATH_TRAVERSAL="PATH_TRAVERSAL",e.INSTALL_ERROR="INSTALL_ERROR",e.ROLLBACK_ERROR="ROLLBACK_ERROR",e.VERSION_MISMATCH="VERSION_MISMATCH",e.PERMISSION_DENIED="PERMISSION_DENIED",e.UPDATE_NOT_AVAILABLE="UPDATE_NOT_AVAILABLE",e.UPDATE_IN_PROGRESS="UPDATE_IN_PROGRESS",e.UPDATE_CANCELLED="UPDATE_CANCELLED",e.PLATFORM_NOT_SUPPORTED="PLATFORM_NOT_SUPPORTED",e.REVIEW_NOT_SUPPORTED="REVIEW_NOT_SUPPORTED",e.QUOTA_EXCEEDED="QUOTA_EXCEEDED",e.CONDITIONS_NOT_MET="CONDITIONS_NOT_MET",e.INVALID_CONFIG="INVALID_CONFIG",e.UNKNOWN_ERROR="UNKNOWN_ERROR"}(c||(c={}));class w{constructor(){this.config=this.getDefaultConfig()}static getInstance(){return w.instance||(w.instance=new w),w.instance}getDefaultConfig(){return{filesystem:null,preferences:null,baseUrl:"",allowedHosts:[],maxBundleSize:104857600,downloadTimeout:3e4,retryAttempts:3,retryDelay:1e3,enableSignatureValidation:!0,publicKey:"",cacheExpiration:864e5,enableLogging:!1,serverUrl:"",channel:"production",autoCheck:!0,autoUpdate:!1,updateStrategy:"background",requireSignature:!0,checksumAlgorithm:"SHA-256",checkInterval:864e5,security:{enforceHttps:!0,validateInputs:!0,secureStorage:!0,logSecurityEvents:!1},promptAfterPositiveEvents:!1,maxPromptsPerVersion:1,minimumDaysSinceLastPrompt:7,isPremiumUser:!1,appStoreId:"",iosAppId:"",packageName:"",webReviewUrl:"",minimumVersion:"1.0.0"}}configure(e){this.config=Object.assign(Object.assign({},this.config),e),this.validateConfig()}validateConfig(){if(this.config.maxBundleSize<=0)throw new Error("maxBundleSize must be greater than 0");if(this.config.downloadTimeout<=0)throw new Error("downloadTimeout must be greater than 0");if(this.config.retryAttempts<0)throw new Error("retryAttempts must be non-negative");if(this.config.retryDelay<0)throw new Error("retryDelay must be non-negative")}get(e){return this.config[e]}set(e,t){this.config[e]=t}getAll(){return Object.assign({},this.config)}isConfigured(){return!(!this.config.filesystem||!this.config.preferences)}}exports.LogLevel=void 0,(d=exports.LogLevel||(exports.LogLevel={}))[d.DEBUG=0]="DEBUG",d[d.INFO=1]="INFO",d[d.WARN=2]="WARN",d[d.ERROR=3]="ERROR";class E{constructor(e){this.configManager=w.getInstance(),this.context=e||"NativeUpdate"}static getInstance(){return E.instance||(E.instance=new E),E.instance}shouldLog(){return this.configManager.get("enableLogging")}sanitize(e){if("string"==typeof e){let t=e;return t=t.replace(/\/[^\s]+\/([\w.-]+)$/g,"/<path>/$1"),t=t.replace(/https?:\/\/[^:]+:[^@]+@/g,"https://***:***@"),t=t.replace(/[a-zA-Z0-9]{32,}/g,"<redacted>"),t}if("object"==typeof e&&null!==e){if(Array.isArray(e))return e.map(e=>this.sanitize(e));{const t={},r=e;for(const e in r)t[e]=e.toLowerCase().includes("key")||e.toLowerCase().includes("secret")||e.toLowerCase().includes("password")||e.toLowerCase().includes("token")?"<redacted>":this.sanitize(r[e]);return t}}return e}log(e,t){this.logWithLevel(exports.LogLevel.INFO,e,t)}logWithLevel(e,t,r){if(!this.shouldLog())return;const a=(new Date).toISOString(),i=r?this.sanitize(r):void 0,n={timestamp:a,level:exports.LogLevel[e],context:this.context,message:t};switch(void 0!==i&&(n.data=i),e){case exports.LogLevel.DEBUG:console.debug(`[${this.context}]`,n);break;case exports.LogLevel.INFO:console.info(`[${this.context}]`,n);break;case exports.LogLevel.WARN:console.warn(`[${this.context}]`,n);break;case exports.LogLevel.ERROR:console.error(`[${this.context}]`,n)}}debug(e,t){this.logWithLevel(exports.LogLevel.DEBUG,e,t)}info(e,t){this.logWithLevel(exports.LogLevel.INFO,e,t)}warn(e,t){this.logWithLevel(exports.LogLevel.WARN,e,t)}error(e,t){const r=t instanceof Error?{name:t.name,message:t.message,stack:t.stack}:t;this.logWithLevel(exports.LogLevel.ERROR,e,r)}}exports.ErrorCode=void 0,(h=exports.ErrorCode||(exports.ErrorCode={})).NOT_CONFIGURED="NOT_CONFIGURED",h.INVALID_CONFIG="INVALID_CONFIG",h.MISSING_DEPENDENCY="MISSING_DEPENDENCY",h.DOWNLOAD_FAILED="DOWNLOAD_FAILED",h.DOWNLOAD_TIMEOUT="DOWNLOAD_TIMEOUT",h.INVALID_URL="INVALID_URL",h.UNAUTHORIZED_HOST="UNAUTHORIZED_HOST",h.BUNDLE_TOO_LARGE="BUNDLE_TOO_LARGE",h.CHECKSUM_MISMATCH="CHECKSUM_MISMATCH",h.SIGNATURE_INVALID="SIGNATURE_INVALID",h.VERSION_DOWNGRADE="VERSION_DOWNGRADE",h.INVALID_BUNDLE_FORMAT="INVALID_BUNDLE_FORMAT",h.STORAGE_FULL="STORAGE_FULL",h.FILE_NOT_FOUND="FILE_NOT_FOUND",h.PERMISSION_DENIED="PERMISSION_DENIED",h.UPDATE_FAILED="UPDATE_FAILED",h.ROLLBACK_FAILED="ROLLBACK_FAILED",h.BUNDLE_NOT_READY="BUNDLE_NOT_READY",h.PLATFORM_NOT_SUPPORTED="PLATFORM_NOT_SUPPORTED",h.NATIVE_ERROR="NATIVE_ERROR";class m extends Error{constructor(e,t,r,a){super(t),this.code=e,this.message=t,this.details=r,this.originalError=a,this.name="NativeUpdateError",Object.setPrototypeOf(this,m.prototype)}toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,stack:this.stack}}}class I extends m{constructor(e,t,r,a){super(e,t,r,a),this.name="DownloadError"}}class y extends m{constructor(e,t,r){super(e,t,r),this.name="ValidationError"}}class A extends m{constructor(e,t,r,a){super(e,t,r,a),this.name="StorageError"}}class D extends m{constructor(e,t,r,a){super(e,t,r,a),this.name="UpdateError"}}class N{constructor(){this.configManager=w.getInstance(),this.logger=E.getInstance()}static getInstance(){return N.instance||(N.instance=new N),N.instance}static validateUrl(e){try{return"https:"===new URL(e).protocol}catch(e){return!1}}static validateChecksum(e){return/^[a-f0-9]{64}$/i.test(e)}static sanitizeInput(e){return e?e.replace(/<[^>]*>/g,"").replace(/[^\w\s/.-]/g,""):""}static validateBundleSize(e){return e>0&&e<=104857600}async calculateChecksum(e){const t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(e=>e.toString(16).padStart(2,"0")).join("")}async verifyChecksum(e,t){if(!t)return this.logger.warn("No checksum provided for verification"),!0;const r=await this.calculateChecksum(e),a=r===t.toLowerCase();return a||this.logger.error("Checksum verification failed",{expected:t,actual:r}),a}async validateChecksum(e,t){return this.verifyChecksum(e,t)}async verifySignature(e,t){if(!this.configManager.get("enableSignatureValidation"))return!0;const r=this.configManager.get("publicKey");if(!r)throw new y(exports.ErrorCode.SIGNATURE_INVALID,"Public key not configured for signature validation");try{const a=await crypto.subtle.importKey("spki",this.pemToArrayBuffer(r),{name:"RSA-PSS",hash:"SHA-256"},!1,["verify"]),i=await crypto.subtle.verify({name:"RSA-PSS",saltLength:32},a,this.base64ToArrayBuffer(t),e);return i||this.logger.error("Signature verification failed"),i}catch(e){return this.logger.error("Signature verification error",e),!1}}pemToArrayBuffer(e){const t=e.replace(/-----BEGIN PUBLIC KEY-----/g,"").replace(/-----END PUBLIC KEY-----/g,"").replace(/\s/g,"");return this.base64ToArrayBuffer(t)}base64ToArrayBuffer(e){const t=atob(e),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r.buffer}sanitizePath(e){return e.split("/").filter(e=>".."!==e&&"."!==e).join("/").replace(/^\/+/,"")}validateBundleId(e){if(!e||"string"!=typeof e)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID must be a non-empty string");if(!/^[a-zA-Z0-9\-_.]+$/.test(e))throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID contains invalid characters");if(e.length>100)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is too long (max 100 characters)")}validateVersion(e){if(!e||"string"!=typeof e)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Version must be a non-empty string");if(!/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(e))throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Version must follow semantic versioning format (e.g., 1.2.3)")}isVersionDowngrade(e,t){const r=this.parseVersion(e),a=this.parseVersion(t);return a.major<r.major||!(a.major>r.major)&&(a.minor<r.minor||!(a.minor>r.minor)&&a.patch<r.patch)}parseVersion(e){const t=e.split("-")[0].split(".");return{major:parseInt(t[0],10)||0,minor:parseInt(t[1],10)||0,patch:parseInt(t[2],10)||0}}validateUrl(e){if(!e||"string"!=typeof e)throw new y(exports.ErrorCode.INVALID_URL,"URL must be a non-empty string");let t;try{t=new URL(e)}catch(e){throw new y(exports.ErrorCode.INVALID_URL,"Invalid URL format")}if("https:"!==t.protocol)throw new y(exports.ErrorCode.INVALID_URL,"Only HTTPS URLs are allowed");const r=this.configManager.get("allowedHosts");if(r.length>0&&!r.includes(t.hostname))throw new y(exports.ErrorCode.UNAUTHORIZED_HOST,`Host ${t.hostname} is not in the allowed hosts list`);if([/^localhost$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2[0-9]|3[0-1])\./,/^192\.168\./,/^::1$/,/^fc00:/i,/^fe80:/i].some(e=>e.test(t.hostname)))throw new y(exports.ErrorCode.UNAUTHORIZED_HOST,"Private/local addresses are not allowed")}validateFileSize(e){if("number"!=typeof e||e<0)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"File size must be a non-negative number");const t=this.configManager.get("maxBundleSize");if(e>t)throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,`File size ${e} exceeds maximum allowed size of ${t} bytes`)}generateSecureId(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}async validateCertificatePin(e,t){const r=this.configManager.certificatePins;if(!r||!Array.isArray(r)||0===r.length)return!0;const a=r.filter(t=>t.hostname===e);if(0===a.length)return!0;const i=await this.calculateCertificateHash(t),n=a.some(e=>e.sha256===i);return n||this.logger.error("Certificate pinning validation failed",{hostname:e,expectedPins:a.map(e=>e.sha256),actualHash:i}),n}async calculateCertificateHash(e){const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t),a=Array.from(new Uint8Array(r));return"sha256/"+btoa(String.fromCharCode(...a))}validateMetadata(e){if(e&&"object"!=typeof e)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Metadata must be an object");if(JSON.stringify(e||{}).length>10240)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Metadata is too large (max 10KB)")}}class v{constructor(){this.STORAGE_KEY="capacitor_native_update_bundles",this.ACTIVE_BUNDLE_KEY="capacitor_native_update_active",this.preferences=null,this.cache=new Map,this.cacheExpiry=0,this.logger=E.getInstance(),this.configManager=w.getInstance()}async initialize(){if(this.preferences=this.configManager.get("preferences"),!this.preferences)throw new A(exports.ErrorCode.MISSING_DEPENDENCY,"Preferences not configured. Please configure the plugin first.");await this.loadCache()}async loadCache(){if(!(Date.now()<this.cacheExpiry))try{const{value:e}=await this.preferences.get({key:this.STORAGE_KEY});if(e){const t=JSON.parse(e);this.cache.clear(),t.forEach(e=>this.cache.set(e.bundleId,e))}this.cacheExpiry=Date.now()+5e3}catch(e){this.logger.error("Failed to load bundles from storage",e),this.cache.clear()}}async saveCache(){try{const e=Array.from(this.cache.values());await this.preferences.set({key:this.STORAGE_KEY,value:JSON.stringify(e)}),this.logger.debug("Saved bundles to storage",{count:e.length})}catch(e){throw new A(exports.ErrorCode.STORAGE_FULL,"Failed to save bundles to storage",void 0,e)}}async saveBundleInfo(e){this.validateBundleInfo(e),this.cache.set(e.bundleId,e),await this.saveCache(),this.logger.info("Bundle saved",{bundleId:e.bundleId,version:e.version})}validateBundleInfo(e){if(!e.bundleId||"string"!=typeof e.bundleId)throw new A(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle ID");if(!e.version||"string"!=typeof e.version)throw new A(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle version");if(!e.path||"string"!=typeof e.path)throw new A(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle path");if("number"!=typeof e.size||e.size<0)throw new A(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid bundle size")}async getAllBundles(){return await this.loadCache(),Array.from(this.cache.values())}async getBundle(e){if(!e)throw new A(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");return await this.loadCache(),this.cache.get(e)||null}async deleteBundle(e){if(!e)throw new A(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");await this.loadCache(),this.cache.get(e)?(this.cache.delete(e),await this.saveCache(),await this.getActiveBundleId()===e&&await this.clearActiveBundle(),this.logger.info("Bundle deleted",{bundleId:e})):this.logger.warn("Attempted to delete non-existent bundle",{bundleId:e})}async getActiveBundle(){const e=await this.getActiveBundleId();return e?this.getBundle(e):null}async setActiveBundle(e){if(!e)throw new A(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");const t=await this.getBundle(e);if(!t)throw new A(exports.ErrorCode.FILE_NOT_FOUND,`Bundle ${e} not found`);const r=await this.getActiveBundle();r&&r.bundleId!==e&&(r.status="READY",await this.saveBundleInfo(r)),t.status="ACTIVE",await this.saveBundleInfo(t),await this.preferences.set({key:this.ACTIVE_BUNDLE_KEY,value:e}),this.logger.info("Active bundle set",{bundleId:e,version:t.version})}async getActiveBundleId(){try{const{value:e}=await this.preferences.get({key:this.ACTIVE_BUNDLE_KEY});return e}catch(e){return this.logger.error("Failed to get active bundle ID",e),null}}async clearActiveBundle(){await this.preferences.remove({key:this.ACTIVE_BUNDLE_KEY}),this.logger.info("Active bundle cleared")}async clearAllBundles(){await this.preferences.remove({key:this.STORAGE_KEY}),await this.preferences.remove({key:this.ACTIVE_BUNDLE_KEY}),this.cache.clear(),this.cacheExpiry=0,this.logger.info("All bundles cleared")}async cleanupOldBundles(e){if(e<1)throw new A(exports.ErrorCode.INVALID_CONFIG,"Keep count must be at least 1");const t=await this.getAllBundles(),r=await this.getActiveBundleId(),a=t.sort((e,t)=>t.downloadTime-e.downloadTime),i=new Set;r&&i.add(r);let n=i.size;for(const t of a){if(n>=e)break;i.has(t.bundleId)||(i.add(t.bundleId),n++)}let s=0;for(const e of t)i.has(e.bundleId)||(await this.deleteBundle(e.bundleId),s++);s>0&&this.logger.info("Cleaned up old bundles",{deleted:s,kept:n})}async getBundlesOlderThan(e){if(e<0)throw new A(exports.ErrorCode.INVALID_CONFIG,"Timestamp must be non-negative");return(await this.getAllBundles()).filter(t=>t.downloadTime<e)}async markBundleAsVerified(e){const t=await this.getBundle(e);if(!t)throw new A(exports.ErrorCode.FILE_NOT_FOUND,`Bundle ${e} not found`);t.verified=!0,await this.saveBundleInfo(t),this.logger.info("Bundle marked as verified",{bundleId:e})}async getTotalStorageUsed(){return(await this.getAllBundles()).reduce((e,t)=>e+t.size,0)}async isStorageLimitExceeded(e=0){return await this.getTotalStorageUsed()+e>3*this.configManager.get("maxBundleSize")}createDefaultBundle(){return{bundleId:"default",version:"1.0.0",path:"/",downloadTime:Date.now(),size:0,status:"ACTIVE",checksum:"",verified:!0}}async cleanExpiredBundles(){const e=this.configManager.get("cacheExpiration"),t=Date.now()-e,r=await this.getBundlesOlderThan(t);for(const e of r){const t=await this.getActiveBundleId();e.bundleId!==t&&await this.deleteBundle(e.bundleId)}}}class C{constructor(){this.activeDownloads=new Map,this.filesystem=null,this.logger=E.getInstance(),this.configManager=w.getInstance()}async initialize(){if(this.filesystem=this.configManager.get("filesystem"),!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not configured. Please configure the plugin first.")}validateUrl(e){try{const t=new URL(e);if("https:"!==t.protocol)throw new y(exports.ErrorCode.INVALID_URL,"Only HTTPS URLs are allowed for security reasons");const r=this.configManager.get("allowedHosts");if(r.length>0&&!r.includes(t.hostname))throw new y(exports.ErrorCode.UNAUTHORIZED_HOST,`Host ${t.hostname} is not in the allowed hosts list`)}catch(e){if(e instanceof y)throw e;throw new y(exports.ErrorCode.INVALID_URL,"Invalid URL format")}}async download(e,t,r){if(this.validateUrl(e),!t)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Bundle ID is required");if(this.activeDownloads.has(t))throw new I(exports.ErrorCode.DOWNLOAD_FAILED,`Download already in progress for bundle ${t}`);const a=new AbortController,i={controller:a,startTime:Date.now()};this.activeDownloads.set(t,i);try{const n=this.configManager.get("downloadTimeout"),s=setTimeout(()=>a.abort(),n),o=await fetch(e,{signal:a.signal,headers:{"Cache-Control":"no-cache",Accept:"application/octet-stream, application/zip"}});if(clearTimeout(s),!o.ok)throw new I(exports.ErrorCode.DOWNLOAD_FAILED,`Download failed: ${o.status} ${o.statusText}`,{status:o.status,statusText:o.statusText});const l=o.headers.get("content-type");if(l&&!this.isValidContentType(l))throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,`Invalid content type: ${l}`);const c=o.headers.get("content-length"),d=c?parseInt(c,10):0;if(d>this.configManager.get("maxBundleSize"))throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,`Bundle size ${d} exceeds maximum allowed size`);if(!d||!o.body){const e=await o.blob();return this.validateBlobSize(e),e}const h=o.body.getReader(),u=[];let g=0;for(;;){const{done:e,value:a}=await h.read();if(e)break;if(u.push(a),g+=a.length,g>this.configManager.get("maxBundleSize"))throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,"Download size exceeds maximum allowed size");r&&r({percent:Math.round(g/d*100),bytesDownloaded:g,totalBytes:d,bundleId:t})}const p=new Blob(u);return this.validateBlobSize(p),this.logger.info("Download completed",{bundleId:t,size:p.size,duration:Date.now()-i.startTime}),p}catch(e){if(e instanceof Error&&"AbortError"===e.name){const t=Date.now()-i.startTime>=this.configManager.get("downloadTimeout");throw new I(t?exports.ErrorCode.DOWNLOAD_TIMEOUT:exports.ErrorCode.DOWNLOAD_FAILED,t?"Download timed out":"Download cancelled",void 0,e)}throw e}finally{this.activeDownloads.delete(t)}}isValidContentType(e){return["application/octet-stream","application/zip","application/x-zip-compressed","application/x-zip"].some(t=>e.includes(t))}validateBlobSize(e){if(0===e.size)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Downloaded file is empty");if(e.size>this.configManager.get("maxBundleSize"))throw new y(exports.ErrorCode.BUNDLE_TOO_LARGE,`File size ${e.size} exceeds maximum allowed size`)}cancelDownload(e){const t=this.activeDownloads.get(e);t&&(t.controller.abort(),this.activeDownloads.delete(e),this.logger.info("Download cancelled",{bundleId:e}))}cancelAllDownloads(){for(const e of this.activeDownloads.values())e.controller.abort();const e=this.activeDownloads.size;this.activeDownloads.clear(),e>0&&this.logger.info("All downloads cancelled",{count:e})}isDownloading(e){return this.activeDownloads.has(e)}getActiveDownloadCount(){return this.activeDownloads.size}async downloadWithRetry(e,t,r){const a=this.configManager.get("retryAttempts"),i=this.configManager.get("retryDelay");let n=null;for(let s=0;s<a;s++)try{if(s>0){const e=Math.min(i*Math.pow(2,s-1),3e4);await new Promise(t=>setTimeout(t,e)),this.logger.debug("Retrying download",{bundleId:t,attempt:s,delay:e})}return await this.download(e,t,r)}catch(e){if(n=e,e instanceof y||e instanceof Error&&"AbortError"===e.name)throw e;this.logger.warn(`Download attempt ${s+1} failed`,{bundleId:t,error:e})}throw new I(exports.ErrorCode.DOWNLOAD_FAILED,"Download failed after all retries",{attempts:a},n||void 0)}async blobToArrayBuffer(e){return e.arrayBuffer()}async saveBlob(e,t){if(!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");const r=await this.blobToArrayBuffer(t),a=btoa(String.fromCharCode(...new Uint8Array(r))),i=`bundles/${e}/bundle.zip`;return await this.filesystem.writeFile({path:i,data:a,directory:p.Directory.Data,recursive:!0}),this.logger.debug("Bundle saved to filesystem",{bundleId:e,path:i,size:t.size}),i}async loadBlob(e){if(!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");try{const t=`bundles/${e}/bundle.zip`,r=await this.filesystem.readFile({path:t,directory:p.Directory.Data}),a=atob(r.data),i=new Uint8Array(a.length);for(let e=0;e<a.length;e++)i[e]=a.charCodeAt(e);return new Blob([i],{type:"application/zip"})}catch(t){return this.logger.debug("Failed to load bundle from filesystem",{bundleId:e,error:t}),null}}async deleteBlob(e){if(!this.filesystem)throw new I(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not initialized");try{const t=`bundles/${e}`;await this.filesystem.rmdir({path:t,directory:p.Directory.Data,recursive:!0}),this.logger.debug("Bundle deleted from filesystem",{bundleId:e})}catch(t){this.logger.warn("Failed to delete bundle from filesystem",{bundleId:e,error:t})}}}class U{constructor(){this.VERSION_CHECK_CACHE_KEY="capacitor_native_update_version_cache",this.CACHE_DURATION=3e5,this.preferences=null,this.memoryCache=new Map,this.logger=E.getInstance(),this.configManager=w.getInstance(),this.securityValidator=N.getInstance()}static compareVersions(e,t){try{const[r,a]=e.split("-"),[i,n]=t.split("-"),s=r.split(".").map(Number),o=i.split(".").map(Number);for(let e=0;e<3;e++){const t=s[e]||0,r=o[e]||0;if(t>r)return 1;if(t<r)return-1}return a&&!n?-1:!a&&n?1:a&&n?a.localeCompare(n):0}catch(r){return e===t?0:e>t?1:-1}}static isValidVersion(e){return/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/.test(e)}static shouldUpdate(e,t,r){return!(r&&U.compareVersions(e,r)<0)&&U.compareVersions(e,t)<0}async initialize(){if(this.preferences=this.configManager.get("preferences"),!this.preferences)throw new y(exports.ErrorCode.MISSING_DEPENDENCY,"Preferences not configured. Please configure the plugin first.")}async checkForUpdates(e,t,r,a){if(this.securityValidator.validateUrl(e),this.securityValidator.validateVersion(r),!t||!a)throw new y(exports.ErrorCode.INVALID_CONFIG,"Channel and appId are required");const i=`${t}-${a}`,n=await this.getCachedVersionInfo(i);if(n&&n.channel===t&&Date.now()-n.timestamp<this.CACHE_DURATION)return this.logger.debug("Returning cached version info",{channel:t,version:n.data.version}),n.data;try{const n=new URL(`${e}/check`);n.searchParams.append("channel",t),n.searchParams.append("version",r),n.searchParams.append("appId",a),n.searchParams.append("platform","web");const s=await fetch(n.toString(),{method:"GET",headers:{"Content-Type":"application/json","X-App-Version":r,"X-App-Id":a},signal:AbortSignal.timeout(this.configManager.get("downloadTimeout"))});if(!s.ok)throw new Error(`Version check failed: ${s.status}`);const o=await s.json();if(!o.version)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"No version in server response");return this.securityValidator.validateVersion(o.version),o.bundleUrl&&this.securityValidator.validateUrl(o.bundleUrl),o.minAppVersion&&this.securityValidator.validateVersion(o.minAppVersion),await this.cacheVersionInfo(i,t,o),this.logger.info("Version check completed",{channel:t,currentVersion:r,latestVersion:o.version,updateAvailable:this.isNewerVersion(o.version,r)}),o}catch(e){return this.logger.error("Failed to check for updates",e),null}}isNewerVersion(e,t){try{const r=this.parseVersion(e),a=this.parseVersion(t);return r.major!==a.major?r.major>a.major:r.minor!==a.minor?r.minor>a.minor:r.patch!==a.patch?r.patch>a.patch:!(r.prerelease&&!a.prerelease||(r.prerelease||!a.prerelease)&&(!r.prerelease||!a.prerelease||!(r.prerelease>a.prerelease)))}catch(r){return this.logger.error("Failed to compare versions",{version1:e,version2:t,error:r}),!1}}isUpdateMandatory(e,t){if(!t)return!1;try{return this.securityValidator.validateVersion(e),this.securityValidator.validateVersion(t),!this.isNewerVersion(e,t)&&e!==t}catch(e){return this.logger.error("Failed to check mandatory update",e),!1}}parseVersion(e){const t=e.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/);if(!t)throw new y(exports.ErrorCode.INVALID_BUNDLE_FORMAT,"Invalid version format");return{major:parseInt(t[1],10),minor:parseInt(t[2],10),patch:parseInt(t[3],10),prerelease:t[4],build:t[5]}}buildVersionString(e){let t=`${e.major}.${e.minor}.${e.patch}`;return e.prerelease&&(t+=`-${e.prerelease}`),e.build&&(t+=`+${e.build}`),t}isCompatibleWithNativeVersion(e,t,r){if(!r)return!0;try{const a=r[e];return!a||(this.securityValidator.validateVersion(t),this.securityValidator.validateVersion(a),!this.isNewerVersion(a,t))}catch(e){return this.logger.error("Failed to check compatibility",e),!1}}async getCachedVersionInfo(e){const t=this.memoryCache.get(e);if(t&&Date.now()-t.timestamp<this.CACHE_DURATION)return t;try{const{value:t}=await this.preferences.get({key:this.VERSION_CHECK_CACHE_KEY});if(!t)return null;const r=JSON.parse(t)[e];if(r&&Date.now()-r.timestamp<this.CACHE_DURATION)return this.memoryCache.set(e,r),r}catch(e){this.logger.debug("Failed to load cached version info",e)}return null}async cacheVersionInfo(e,t,r){const a={channel:t,data:r,timestamp:Date.now()};this.memoryCache.set(e,a);try{const{value:t}=await this.preferences.get({key:this.VERSION_CHECK_CACHE_KEY}),r=t?JSON.parse(t):{},i=Date.now();for(const e in r)i-r[e].timestamp>2*this.CACHE_DURATION&&delete r[e];r[e]=a,await this.preferences.set({key:this.VERSION_CHECK_CACHE_KEY,value:JSON.stringify(r)})}catch(e){this.logger.warn("Failed to cache version info",e)}}async clearVersionCache(){this.memoryCache.clear();try{await this.preferences.remove({key:this.VERSION_CHECK_CACHE_KEY})}catch(e){this.logger.warn("Failed to clear version cache",e)}}shouldBlockDowngrade(e,t){try{return this.securityValidator.isVersionDowngrade(e,t)}catch(e){return this.logger.error("Failed to check downgrade",e),!0}}}class L{constructor(e){this.config=e,this.logger=new E("AppUpdateChecker")}async checkServerVersion(e){if(!this.config.updateUrl)return{};try{const e=new URL(`${this.config.updateUrl}/app-version`);e.searchParams.append("platform",this.getPlatform()),e.searchParams.append("current",await this.getCurrentVersion()),this.config.channel&&e.searchParams.append("channel",this.config.channel);const t=await fetch(e.toString(),{method:"GET",headers:{Accept:"application/json","X-App-Version":await this.getCurrentVersion(),"X-App-Platform":this.getPlatform()}});if(!t.ok)throw new Error(`Server returned ${t.status}`);const r=await t.json();return{availableVersion:r.version,updatePriority:r.priority,releaseNotes:r.releaseNotes,updateSize:r.size,updateURL:r.downloadUrl}}catch(e){return this.logger.error("Failed to check server version",e),{}}}compareVersions(e,t){const r=e.split(".").map(Number),a=t.split(".").map(Number);for(let e=0;e<Math.max(r.length,a.length);e++){const t=r[e]||0,i=a[e]||0;if(t>i)return 1;if(t<i)return-1}return 0}isUpdateRequired(e,t,r){return this.compareVersions(e,t)<0||!!(r&&this.compareVersions(e,r)<0)}determineUpdatePriority(e,t){const[r,a]=e.split(".").map(Number);return r>0?5:a>0&&t&&t>30?4:a>0?3:1}async getCurrentVersion(){return"1.0.0"}getPlatform(){if("undefined"!=typeof window){const e=window.navigator.userAgent;if(/android/i.test(e))return"android";if(/iPad|iPhone|iPod/.test(e))return"ios"}return"web"}}!function(e){e[e.UNKNOWN=0]="UNKNOWN",e[e.PENDING=1]="PENDING",e[e.DOWNLOADING=2]="DOWNLOADING",e[e.INSTALLING=3]="INSTALLING",e[e.INSTALLED=4]="INSTALLED",e[e.FAILED=5]="FAILED",e[e.CANCELED=6]="CANCELED",e[e.DOWNLOADED=11]="DOWNLOADED"}(u||(u={}));class _{constructor(e){this.logger=new E("AppUpdateInstaller"),this.currentState={installStatus:u.UNKNOWN,packageName:"",availableVersion:""}}async startImmediateUpdate(){if(this.logger.log("Starting immediate update installation"),this.updateState(u.PENDING),this.isAndroid())this.logger.log("Triggering Android immediate update");else{if(!this.isIOS())throw new Error("Immediate updates not supported on web platform");this.logger.log("Opening iOS App Store for update")}}async startFlexibleUpdate(){if(this.logger.log("Starting flexible update download"),this.updateState(u.DOWNLOADING),this.isWeb())this.simulateFlexibleUpdate();else{if(!this.isAndroid())throw new Error("Flexible updates not supported on iOS");this.logger.log("Starting Android flexible update")}}async completeFlexibleUpdate(){if(this.logger.log("Completing flexible update installation"),this.currentState.installStatus!==u.DOWNLOADED)throw new Error("Update not ready for installation");this.updateState(u.INSTALLING),this.isAndroid()?this.logger.log("Completing Android update installation"):setTimeout(()=>{this.updateState(u.INSTALLED)},1e3)}async cancelUpdate(){this.logger.log("Cancelling update"),this.currentState.installStatus===u.DOWNLOADING&&this.updateState(u.CANCELED)}async getInstallState(){return Object.assign({},this.currentState)}onProgress(e){this.progressCallback=e}updateState(e,t){this.currentState.installStatus=e,void 0!==t&&(this.currentState.installErrorCode=t),this.logger.log("Update state changed",this.currentState)}simulateFlexibleUpdate(){let e=0;const t=52428800,r=1048576,a=setInterval(()=>{e+=r,e>=t&&(e=t,clearInterval(a),this.updateState(u.DOWNLOADED));const i={bytesDownloaded:e,totalBytesToDownload:t,percentComplete:Math.round(e/t*100),downloadSpeed:r,estimatedTime:Math.ceil((t-e)/r)};this.progressCallback&&this.progressCallback(i)},1e3)}isAndroid(){return"undefined"!=typeof window&&/android/i.test(window.navigator.userAgent)}isIOS(){return"undefined"!=typeof window&&/iPad|iPhone|iPod/.test(window.navigator.userAgent)}isWeb(){return!this.isAndroid()&&!this.isIOS()}}class b{constructor(e){this.config=e,this.logger=new E("PlatformAppUpdate"),this.platform=g.Capacitor.getPlatform()}async checkForUpdate(e){this.logger.log("Checking for platform update: "+this.platform);const t=await this.getVersionInfo(),r={updateAvailable:!1,currentVersion:t.currentVersion,availableVersion:t.currentVersion};if("android"===this.platform)return r;if("ios"===this.platform)return r;if(this.config.webUpdateUrl)try{const e=await fetch(this.config.webUpdateUrl),a=await e.json();a.version&&a.version!==t.currentVersion&&(r.updateAvailable=!0,r.availableVersion=a.version,r.releaseNotes=a.releaseNotes,r.updateURL=a.downloadUrl)}catch(e){this.logger.error("Failed to check web update",e)}return r}async getVersionInfo(){return{currentVersion:"1.0.0",buildNumber:"1",packageName:"com.example.app",platform:this.platform,minimumVersion:this.config.minimumVersion}}async getAppStoreUrl(){const e=this.platform;let t="";if("ios"===e){const e=this.config.appStoreId||this.config.iosAppId;if(!e)throw new Error("App Store ID not configured");t=`https://apps.apple.com/app/id${e}`}else t="android"===e?`https://play.google.com/store/apps/details?id=${this.config.packageName||(await this.getVersionInfo()).packageName}`:this.config.webUpdateUrl||window.location.origin;return{url:t,platform:e}}async openUrl(e){if("undefined"==typeof window||!window.open)throw new Error("Cannot open URL on this platform");window.open(e,"_blank")}isUpdateSupported(){return"android"===this.platform||"ios"!==this.platform}getUpdateCapabilities(){const e={immediateUpdate:!1,flexibleUpdate:!1,backgroundDownload:!1,inAppReview:!1};return"android"===this.platform?(e.immediateUpdate=!0,e.flexibleUpdate=!0,e.backgroundDownload=!0,e.inAppReview=!0):"ios"===this.platform&&(e.inAppReview=!0),e}}class O{constructor(e){this.listeners=new Map,this.config=e,this.logger=new E("AppUpdateManager"),this.checker=new L(e),this.installer=new _(e),this.platformUpdate=new b(e)}async checkAppUpdate(e){try{this.logger.log("Checking for app updates",e);const t=await this.platformUpdate.checkForUpdate(e);if(!t.updateAvailable&&this.config.updateUrl){const r=await this.checker.checkServerVersion(e);return this.mergeUpdateInfo(t,r)}return t}catch(e){throw this.logger.error("Failed to check app update",e),e}}async startImmediateUpdate(){try{this.logger.log("Starting immediate update");const e=await this.checkAppUpdate();if(!e.immediateUpdateAllowed)throw new Error("Immediate update not allowed");await this.installer.startImmediateUpdate(),this.emit("appUpdateStateChanged",{installStatus:1,packageName:this.config.packageName||"",availableVersion:e.availableVersion||""})}catch(e){throw this.logger.error("Failed to start immediate update",e),e}}async startFlexibleUpdate(){try{this.logger.log("Starting flexible update");const e=await this.checkAppUpdate();if(!e.flexibleUpdateAllowed)throw new Error("Flexible update not allowed");await this.installer.startFlexibleUpdate(),this.installer.onProgress(e=>{this.emit("appUpdateProgress",e)}),this.emit("appUpdateStateChanged",{installStatus:2,packageName:this.config.packageName||"",availableVersion:e.availableVersion||""})}catch(e){throw this.logger.error("Failed to start flexible update",e),e}}async completeFlexibleUpdate(){try{this.logger.log("Completing flexible update"),await this.installer.completeFlexibleUpdate(),this.emit("appUpdateStateChanged",{installStatus:3,packageName:this.config.packageName||"",availableVersion:""})}catch(e){throw this.logger.error("Failed to complete flexible update",e),e}}async getVersionInfo(){try{return this.logger.log("Getting version info"),await this.platformUpdate.getVersionInfo()}catch(e){throw this.logger.error("Failed to get version info",e),e}}async isMinimumVersionMet(){try{this.logger.log("Checking minimum version");const e=await this.getVersionInfo(),t=this.config.minimumVersion||"0.0.0",r=this.checker.compareVersions(e.currentVersion,t)>=0;return{isMet:r,currentVersion:e.currentVersion,minimumVersion:t,updateRequired:!r&&!0===this.config.enforceMinVersion}}catch(e){throw this.logger.error("Failed to check minimum version",e),e}}async getAppUpdateInfo(){return this.checkAppUpdate()}async performImmediateUpdate(){return this.startImmediateUpdate()}async openAppStore(e){try{this.logger.log("Opening app store");const e=await this.getAppStoreUrl();await this.platformUpdate.openUrl(e.url)}catch(e){throw this.logger.error("Failed to open app store",e),e}}async getAppStoreUrl(){try{return this.logger.log("Getting app store URL"),await this.platformUpdate.getAppStoreUrl()}catch(e){throw this.logger.error("Failed to get app store URL",e),e}}async getUpdateInstallState(){try{return this.logger.log("Getting update install state"),await this.installer.getInstallState()}catch(e){throw this.logger.error("Failed to get update install state",e),e}}addListener(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),{remove:async()=>{const r=this.listeners.get(e);r&&r.delete(t)}}}async removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}emit(e,t){const r=this.listeners.get(e);r&&r.forEach(r=>{try{r(t)}catch(t){this.logger.error(`Error in ${e} listener`,t)}})}mergeUpdateInfo(e,t){return Object.assign(Object.assign(Object.assign({},e),t),{updateAvailable:e.updateAvailable||!!t.availableVersion,availableVersion:t.availableVersion||e.availableVersion})}}class R{constructor(){this.listeners=new Map}static getInstance(){return R.instance||(R.instance=new R),R.instance}addListener(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{const r=this.listeners.get(e);r&&(r.delete(t),0===r.size&&this.listeners.delete(e))}}emit(e,t){const r=this.listeners.get(e);r&&r.forEach(r=>{try{r(t)}catch(t){console.error(`Error in event listener for ${e}:`,t)}})}removeListeners(e){this.listeners.delete(e)}removeAllListeners(){this.listeners.clear()}listenerCount(e){var t;return(null===(t=this.listeners.get(e))||void 0===t?void 0:t.size)||0}eventNames(){return Array.from(this.listeners.keys())}}class S{constructor(){this.bundleManager=null,this.downloadManager=null,this.versionManager=null,this.appUpdateManager=null,this.initialized=!1,this.configManager=w.getInstance(),this.logger=E.getInstance(),this.securityValidator=N.getInstance(),this.eventEmitter=R.getInstance()}static getInstance(){return S.instance||(S.instance=new S),S.instance}async initialize(e){var t,r;if(this.initialized)this.logger.warn("Plugin already initialized");else try{this.configManager.configure(e),e.filesystem||(e.filesystem=p.Filesystem),e.preferences||(e.preferences=f.Preferences),this.bundleManager=new v,await this.bundleManager.initialize(),this.downloadManager=new C,await this.downloadManager.initialize(),this.versionManager=new U,await this.versionManager.initialize(),this.appUpdateManager=new O({serverUrl:e.serverUrl||e.baseUrl||"",channel:e.channel||"production",autoCheck:null===(t=e.autoCheck)||void 0===t||t,autoUpdate:null!==(r=e.autoUpdate)&&void 0!==r&&r,updateStrategy:e.updateStrategy,publicKey:e.publicKey,requireSignature:e.requireSignature,checksumAlgorithm:e.checksumAlgorithm,checkInterval:e.checkInterval,security:e.security}),this.setupAppUpdateEventBridge(),this.initialized=!0,this.logger.info("Plugin initialized successfully")}catch(e){throw this.logger.error("Failed to initialize plugin",e),e}}isInitialized(){return this.initialized&&this.configManager.isConfigured()}ensureInitialized(){if(!this.isInitialized())throw new m(exports.ErrorCode.NOT_CONFIGURED,"Plugin not initialized. Please call initialize() first.")}getBundleManager(){return this.ensureInitialized(),this.bundleManager}getDownloadManager(){return this.ensureInitialized(),this.downloadManager}getVersionManager(){return this.ensureInitialized(),this.versionManager}getConfigManager(){return this.configManager}getLogger(){return this.logger}getSecurityValidator(){return this.securityValidator}getAppUpdateManager(){return this.ensureInitialized(),this.appUpdateManager}getEventEmitter(){return this.eventEmitter}async reset(){this.logger.info("Resetting plugin state"),this.bundleManager&&await this.bundleManager.clearAllBundles(),this.versionManager&&await this.versionManager.clearVersionCache(),this.downloadManager&&this.downloadManager.cancelAllDownloads(),this.bundleManager=null,this.downloadManager=null,this.versionManager=null,this.appUpdateManager=null,this.initialized=!1,this.eventEmitter.removeAllListeners(),this.logger.info("Plugin reset complete")}async cleanup(){this.logger.info("Cleaning up plugin resources"),this.downloadManager&&this.downloadManager.cancelAllDownloads(),this.bundleManager&&await this.bundleManager.cleanExpiredBundles(),this.logger.info("Cleanup complete")}setupAppUpdateEventBridge(){this.appUpdateManager&&(this.appUpdateManager.addListener("appUpdateStateChanged",e=>{this.eventEmitter.emit("appUpdateStateChanged",e)}),this.appUpdateManager.addListener("appUpdateProgress",e=>{this.eventEmitter.emit("appUpdateProgress",e)}))}}class T{constructor(){this.initialized=!1,this.windowEventListeners=new Map,this.pluginManager=S.getInstance()}async initialize(e){await this.pluginManager.initialize(e),this.initialized=!0,this.setupWindowEventBridge()}isInitialized(){return this.initialized&&this.pluginManager.isInitialized()}async reset(){await this.pluginManager.reset()}async cleanup(){await this.pluginManager.cleanup()}async configure(e){var t;let r;r="config"in e&&"object"==typeof e.config?e.config:{baseUrl:null===(t=e.liveUpdate)||void 0===t?void 0:t.serverUrl},this.initialized?this.pluginManager.getConfigManager().configure(r):await this.initialize(r)}async getSecurityInfo(){return{enforceHttps:!0,certificatePinning:{enabled:!1,pins:[]},validateInputs:!0,secureStorage:!0}}async sync(e){const t=this.pluginManager.getBundleManager();try{const e=await t.getActiveBundle();return{status:s.UP_TO_DATE,version:(null==e?void 0:e.version)||"1.0.0"}}catch(e){return{status:s.ERROR,error:{code:c.UNKNOWN_ERROR,message:e instanceof Error?e.message:"Sync failed"}}}}async download(e){const t=this.pluginManager.getDownloadManager(),r=this.pluginManager.getBundleManager(),a=await t.downloadWithRetry(e.url,e.version),i=await t.saveBlob(e.version,a),n={bundleId:e.version,version:e.version,path:i,downloadTime:Date.now(),size:a.size,status:o.READY,checksum:e.checksum,signature:e.signature,verified:!1};return await r.saveBundleInfo(n),n}async set(e){const t=this.pluginManager.getBundleManager();await t.setActiveBundle(e.bundleId)}async reload(){"undefined"!=typeof window&&window.location.reload()}async current(){const e=this.pluginManager.getBundleManager(),t=await e.getActiveBundle();if(!t)throw new m(exports.ErrorCode.FILE_NOT_FOUND,"No active bundle found");return t}async list(){return this.pluginManager.getBundleManager().getAllBundles()}async delete(e){const t=this.pluginManager.getBundleManager();if(e.bundleId)await t.deleteBundle(e.bundleId);else if(void 0!==e.keepVersions){const r=(await t.getAllBundles()).sort((e,t)=>t.downloadTime-e.downloadTime);for(let a=e.keepVersions;a<r.length;a++)await t.deleteBundle(r[a].bundleId)}}async notifyAppReady(){const e=this.pluginManager.getBundleManager(),t=await e.getActiveBundle();t&&(t.status=o.ACTIVE,await e.saveBundleInfo(t))}async getLatest(){return{available:!1}}async setChannel(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"update_channel",value:e})}async setUpdateUrl(e){this.pluginManager.getConfigManager().configure({baseUrl:e})}async validateUpdate(e){const t=this.pluginManager.getSecurityValidator();try{const r=await t.validateChecksum(new ArrayBuffer(0),e.checksum);return{isValid:r,details:{checksumValid:r,signatureValid:!0,sizeValid:!0,versionValid:!0}}}catch(e){return{isValid:!1,error:e instanceof Error?e.message:"Validation failed"}}}async getAppUpdateInfo(){return this.pluginManager.getAppUpdateManager().getAppUpdateInfo()}async performImmediateUpdate(){return this.pluginManager.getAppUpdateManager().performImmediateUpdate()}async startFlexibleUpdate(){return this.pluginManager.getAppUpdateManager().startFlexibleUpdate()}async completeFlexibleUpdate(){return this.pluginManager.getAppUpdateManager().completeFlexibleUpdate()}async openAppStore(e){return this.pluginManager.getAppUpdateManager().openAppStore(e)}async requestReview(){return{displayed:!1,error:"Reviews are not supported on web"}}async canRequestReview(){return{canRequest:!1,reason:"Reviews are not supported on web"}}async enableBackgroundUpdates(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"background_update_config",value:JSON.stringify(e)})}async disableBackgroundUpdates(){const e=this.pluginManager.getConfigManager().get("preferences");e&&await e.remove({key:"background_update_config"})}async getBackgroundUpdateStatus(){return{enabled:!1,isRunning:!1,checkCount:0,failureCount:0}}async scheduleBackgroundCheck(e){throw new m(exports.ErrorCode.PLATFORM_NOT_SUPPORTED,"Background updates are not supported on web")}async triggerBackgroundCheck(){return{success:!1,updatesFound:!1,notificationSent:!1,error:{code:c.PLATFORM_NOT_SUPPORTED,message:"Background updates are not supported on web"}}}async setNotificationPreferences(e){const t=this.pluginManager.getConfigManager().get("preferences");t&&await t.set({key:"notification_preferences",value:JSON.stringify(e)})}async getNotificationPermissions(){return{granted:!1,canRequest:!1}}async requestNotificationPermissions(){return!1}async addListener(e,t){const r=this.pluginManager.getEventEmitter().addListener(e,t);return{remove:async()=>{r()}}}async removeAllListeners(){this.pluginManager.getEventEmitter().removeAllListeners()}setupWindowEventBridge(){const e=this.pluginManager.getEventEmitter();["appUpdateAvailable","appUpdateProgress","appUpdateReady","appUpdateFailed","appUpdateNotificationClicked","appUpdateInstallClicked"].forEach(t=>{const r=r=>{e.emit(t,r.detail)};window.addEventListener(t,r),this.windowEventListeners.set(t,r)})}}const M=g.registerPlugin("NativeUpdate",{web:()=>new T});exports.BundleManager=v,exports.CacheManager=class{constructor(){this.filesystem=null,this.memoryCache=new Map,this.CACHE_DIR="cache",this.logger=E.getInstance(),this.configManager=w.getInstance()}async initialize(){if(this.filesystem=this.configManager.get("filesystem"),!this.filesystem)throw new Error("Filesystem not configured");try{await this.filesystem.mkdir({path:this.CACHE_DIR,directory:p.Directory.Data,recursive:!0})}catch(e){this.logger.debug("Cache directory may already exist",e)}await this.cleanExpiredCache()}async set(e,t,r){const a=Date.now()+(r||this.configManager.get("cacheExpiration")),i={data:t,timestamp:Date.now(),expiry:a};this.memoryCache.set(e,i),this.shouldPersist(t)&&await this.persistToFile(e,i),this.logger.debug("Cache entry set",{key:e,expiry:new Date(a)})}async get(e){const t=this.memoryCache.get(e);if(t){if(Date.now()<t.expiry)return t.data;this.memoryCache.delete(e)}const r=await this.loadFromFile(e);if(r){if(Date.now()<r.expiry)return this.memoryCache.set(e,r),r.data;await this.removeFile(e)}return null}async has(e){return null!==await this.get(e)}async remove(e){this.memoryCache.delete(e),await this.removeFile(e),this.logger.debug("Cache entry removed",{key:e})}async clear(){this.memoryCache.clear();try{await this.filesystem.rmdir({path:this.CACHE_DIR,directory:p.Directory.Data,recursive:!0}),await this.filesystem.mkdir({path:this.CACHE_DIR,directory:p.Directory.Data,recursive:!0})}catch(e){this.logger.warn("Failed to clear cache directory",e)}this.logger.info("Cache cleared")}async cleanExpiredCache(){const e=Date.now();let t=0;for(const[r,a]of this.memoryCache)e>=a.expiry&&(this.memoryCache.delete(r),t++);try{const r=await this.filesystem.readdir({path:this.CACHE_DIR,directory:p.Directory.Data});for(const a of r.files){const r=a.name.replace(".json",""),i=await this.loadFromFile(r);(!i||e>=i.expiry)&&(await this.removeFile(r),t++)}}catch(e){this.logger.debug("Failed to clean filesystem cache",e)}t>0&&this.logger.info("Cleaned expired cache entries",{count:t})}async getStats(){let e=0,t=0;try{const r=await this.filesystem.readdir({path:this.CACHE_DIR,directory:p.Directory.Data});e=r.files.length;for(const e of r.files)t+=(await this.filesystem.stat({path:`${this.CACHE_DIR}/${e.name}`,directory:p.Directory.Data})).size||0}catch(e){this.logger.debug("Failed to get cache stats",e)}return{memoryEntries:this.memoryCache.size,fileEntries:e,totalSize:t}}async cacheBundleMetadata(e){const t=`bundle_meta_${e.bundleId}`;await this.set(t,e,864e5)}async getCachedBundleMetadata(e){return this.get(`bundle_meta_${e}`)}shouldPersist(e){return"object"==typeof e||"string"==typeof e&&e.length>1024}async persistToFile(e,t){if(this.filesystem)try{const r=`${this.CACHE_DIR}/${e}.json`,a=JSON.stringify(t);await this.filesystem.writeFile({path:r,data:a,directory:p.Directory.Data,encoding:p.Encoding.UTF8})}catch(t){this.logger.warn("Failed to persist cache to file",{key:e,error:t})}}async loadFromFile(e){if(!this.filesystem)return null;try{const t=`${this.CACHE_DIR}/${e}.json`,r=await this.filesystem.readFile({path:t,directory:p.Directory.Data,encoding:p.Encoding.UTF8});return JSON.parse(r.data)}catch(e){return null}}async removeFile(e){if(this.filesystem)try{const t=`${this.CACHE_DIR}/${e}.json`;await this.filesystem.deleteFile({path:t,directory:p.Directory.Data})}catch(t){this.logger.debug("Failed to remove cache file",{key:e,error:t})}}},exports.ConfigManager=w,exports.ConfigurationError=class extends m{constructor(e,t){super(exports.ErrorCode.INVALID_CONFIG,e,t),this.name="ConfigurationError"}},exports.DownloadError=I,exports.DownloadManager=C,exports.Logger=E,exports.NativeUpdate=M,exports.NativeUpdateError=m,exports.PluginManager=S,exports.SecurityValidator=N,exports.StorageError=A,exports.UpdateErrorClass=D,exports.UpdateManager=class{constructor(){this.filesystem=null,this.updateInProgress=!1,this.currentState=null,this.pluginManager=S.getInstance(),this.securityValidator=N.getInstance()}async initialize(){if(this.filesystem=this.pluginManager.getConfigManager().get("filesystem"),!this.filesystem)throw new D(exports.ErrorCode.MISSING_DEPENDENCY,"Filesystem not configured")}async applyUpdate(e,t){if(this.updateInProgress)throw new D(exports.ErrorCode.UPDATE_FAILED,"Another update is already in progress");const r=this.pluginManager.getLogger(),a=this.pluginManager.getBundleManager();try{this.updateInProgress=!0,r.info("Starting bundle update",{bundleId:e});const i=await a.getBundle(e);if(!i)throw new D(exports.ErrorCode.FILE_NOT_FOUND,`Bundle ${e} not found`);if("READY"!==i.status&&"ACTIVE"!==i.status)throw new D(exports.ErrorCode.BUNDLE_NOT_READY,`Bundle ${e} is not ready for installation`);const n=await a.getActiveBundle();this.currentState={currentBundle:n,newBundle:i,backupPath:null,startTime:Date.now()},await this.validateUpdate(n,i,t),n&&"default"!==n.bundleId&&(this.currentState.backupPath=await this.createBackup(n)),await this.performUpdate(i),await this.verifyUpdate(i),await a.setActiveBundle(e),(null==t?void 0:t.cleanupOldBundles)&&await a.cleanupOldBundles(t.keepBundleCount||3),r.info("Bundle update completed successfully",{bundleId:e,version:i.version,duration:Date.now()-this.currentState.startTime}),this.currentState=null}catch(e){throw r.error("Bundle update failed",e),this.currentState&&await this.rollback(),e}finally{this.updateInProgress=!1}}async validateUpdate(e,t,r){const a=this.pluginManager.getLogger(),i=this.pluginManager.getVersionManager();if(e&&!(null==r?void 0:r.allowDowngrade)&&i.shouldBlockDowngrade(e.version,t.version))throw new y(exports.ErrorCode.VERSION_DOWNGRADE,`Cannot downgrade from ${e.version} to ${t.version}`);if(!t.verified){a.warn("Bundle not verified, verifying now",{bundleId:t.bundleId});const e=this.pluginManager.getDownloadManager(),r=await e.loadBlob(t.bundleId);if(!r)throw new D(exports.ErrorCode.FILE_NOT_FOUND,"Bundle data not found");const i=await r.arrayBuffer();if(!await this.securityValidator.verifyChecksum(i,t.checksum))throw new y(exports.ErrorCode.CHECKSUM_MISMATCH,"Bundle checksum verification failed");if(t.signature&&!await this.securityValidator.verifySignature(i,t.signature))throw new y(exports.ErrorCode.SIGNATURE_INVALID,"Bundle signature verification failed");await this.pluginManager.getBundleManager().markBundleAsVerified(t.bundleId)}a.debug("Bundle validation passed",{bundleId:t.bundleId})}async createBackup(e){const t=`backups/${e.bundleId}_${Date.now()}`,r=this.pluginManager.getLogger();try{return await this.filesystem.mkdir({path:t,directory:p.Directory.Data,recursive:!0}),await this.filesystem.copy({from:e.path,to:t,directory:p.Directory.Data}),r.info("Backup created",{bundleId:e.bundleId,backupPath:t}),t}catch(e){throw r.error("Failed to create backup",e),new D(exports.ErrorCode.UPDATE_FAILED,"Failed to create backup",void 0,e)}}async performUpdate(e){const t=this.pluginManager.getLogger();try{const r=`active/${e.bundleId}`;await this.filesystem.mkdir({path:r,directory:p.Directory.Data,recursive:!0}),await this.filesystem.copy({from:e.path,to:r,directory:p.Directory.Data}),e.path=r,t.debug("Bundle files installed",{bundleId:e.bundleId,targetPath:r})}catch(e){throw new D(exports.ErrorCode.UPDATE_FAILED,"Failed to install bundle files",void 0,e)}}async verifyUpdate(e){try{const t=`${e.path}/index.html`;await this.filesystem.stat({path:t,directory:p.Directory.Data})}catch(e){throw new D(exports.ErrorCode.UPDATE_FAILED,"Bundle verification failed after installation",void 0,e)}}async rollback(){var e;if(!this.currentState)throw new D(exports.ErrorCode.ROLLBACK_FAILED,"No update state to rollback");const t=this.pluginManager.getLogger();t.warn("Starting rollback",{from:this.currentState.newBundle.bundleId,to:(null===(e=this.currentState.currentBundle)||void 0===e?void 0:e.bundleId)||"default"});try{const e=this.pluginManager.getBundleManager();if(this.currentState.backupPath&&this.currentState.currentBundle){const t=`active/${this.currentState.currentBundle.bundleId}`;await this.filesystem.copy({from:this.currentState.backupPath,to:t,directory:p.Directory.Data}),this.currentState.currentBundle.path=t,await e.saveBundleInfo(this.currentState.currentBundle)}this.currentState.currentBundle?await e.setActiveBundle(this.currentState.currentBundle.bundleId):await e.clearActiveBundle(),t.info("Rollback completed successfully")}catch(e){throw t.error("Rollback failed",e),new D(exports.ErrorCode.ROLLBACK_FAILED,"Failed to rollback update",void 0,e)}finally{if(this.currentState.backupPath)try{await this.filesystem.rmdir({path:this.currentState.backupPath,directory:p.Directory.Data,recursive:!0})}catch(e){t.warn("Failed to clean up backup",e)}}}getUpdateProgress(){var e,t;return{inProgress:this.updateInProgress,bundleId:null===(e=this.currentState)||void 0===e?void 0:e.newBundle.bundleId,startTime:null===(t=this.currentState)||void 0===t?void 0:t.startTime}}async cancelUpdate(){this.updateInProgress&&this.currentState&&(this.pluginManager.getLogger().warn("Cancelling update",{bundleId:this.currentState.newBundle.bundleId}),await this.rollback(),this.updateInProgress=!1,this.currentState=null)}},exports.ValidationError=y,exports.VersionManager=U;
|
|
2
2
|
//# sourceMappingURL=plugin.cjs.js.map
|