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.
Files changed (36) hide show
  1. package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +41 -0
  2. package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +12 -0
  3. package/android/src/main/java/com/aoneahsan/nativeupdate/NativeUpdatePlugin.kt +52 -1
  4. package/backend-template/README.md +56 -0
  5. package/backend-template/package.json +20 -0
  6. package/backend-template/server.js +121 -0
  7. package/cli/index.js +22 -14
  8. package/dist/esm/core/event-emitter.d.ts +33 -0
  9. package/dist/esm/core/event-emitter.js +75 -0
  10. package/dist/esm/core/event-emitter.js.map +1 -0
  11. package/dist/esm/core/plugin-manager.d.ts +16 -0
  12. package/dist/esm/core/plugin-manager.js +50 -0
  13. package/dist/esm/core/plugin-manager.js.map +1 -1
  14. package/dist/esm/definitions.d.ts +59 -0
  15. package/dist/esm/index.d.ts +1 -1
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/plugin.js +43 -15
  18. package/dist/esm/plugin.js.map +1 -1
  19. package/dist/plugin.cjs.js +1 -1
  20. package/dist/plugin.cjs.js.map +1 -1
  21. package/dist/plugin.esm.js +1 -1
  22. package/dist/plugin.esm.js.map +1 -1
  23. package/dist/plugin.js +2 -2
  24. package/dist/plugin.js.map +1 -1
  25. package/docs/NATIVE_UPDATES_GUIDE.md +1 -1
  26. package/docs/QUICK_START.md +1 -1
  27. package/docs/api/app-update-api.md +9 -1
  28. package/docs/api/background-update-api.md +157 -0
  29. package/docs/api/events-api.md +123 -0
  30. package/docs/api/live-update-api.md +16 -0
  31. package/docs/features/app-updates.md +4 -4
  32. package/docs/getting-started/quick-start.md +1 -1
  33. package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +15 -0
  34. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +6 -0
  35. package/ios/Plugin/NativeUpdatePlugin.swift +45 -0
  36. package/package.json +24 -14
@@ -24,6 +24,7 @@ class AppUpdatePlugin(
24
24
  private val activity: Activity,
25
25
  private val context: Context
26
26
  ) {
27
+ private var eventListener: ((String, JSObject) -> Unit)? = null
27
28
  private val appUpdateManager: AppUpdateManager = AppUpdateManagerFactory.create(context)
28
29
  private var config: JSObject? = null
29
30
  private var updateInfo: AppUpdateInfo? = null
@@ -44,6 +45,10 @@ class AppUpdatePlugin(
44
45
  this.config = config
45
46
  }
46
47
 
48
+ fun setEventListener(listener: (String, JSObject) -> Unit) {
49
+ this.eventListener = listener
50
+ }
51
+
47
52
  fun getAppUpdateInfo(call: PluginCall) {
48
53
  val appUpdateInfoTask = appUpdateManager.appUpdateInfo
49
54
 
@@ -66,6 +71,15 @@ class AppUpdatePlugin(
66
71
  result.put("totalBytesToDownload", appUpdateInfo.totalBytesToDownload())
67
72
  }
68
73
 
74
+ // Emit available event if update is available
75
+ if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
76
+ val availableData = JSObject()
77
+ availableData.put("currentVersion", getCurrentAppVersion())
78
+ availableData.put("availableVersion", appUpdateInfo.availableVersionCode().toString())
79
+ availableData.put("updatePriority", appUpdateInfo.updatePriority())
80
+ eventListener?.invoke("appUpdateAvailable", availableData)
81
+ }
82
+
69
83
  call.resolve(result)
70
84
  }.addOnFailureListener { e ->
71
85
  call.reject("UPDATE_CHECK_FAILED", e.message)
@@ -174,10 +188,33 @@ class AppUpdatePlugin(
174
188
  }
175
189
 
176
190
  private fun handleInstallState(state: InstallState) {
191
+ // Emit state change event
192
+ val eventData = JSObject()
193
+ eventData.put("status", getInstallStatusString(state.installStatus()))
194
+ if (state.installError() != 0) {
195
+ eventData.put("installErrorCode", state.installError())
196
+ }
197
+ eventListener?.invoke("appUpdateStateChanged", eventData)
198
+
199
+ // Emit progress event for downloads
200
+ if (state.installStatus() == InstallStatus.DOWNLOADING) {
201
+ val progressData = JSObject()
202
+ progressData.put("percent", if (state.totalBytesToDownload() > 0)
203
+ ((state.bytesDownloaded() * 100) / state.totalBytesToDownload()).toInt() else 0)
204
+ progressData.put("bytesDownloaded", state.bytesDownloaded())
205
+ progressData.put("totalBytes", state.totalBytesToDownload())
206
+ eventListener?.invoke("appUpdateProgress", progressData)
207
+ }
208
+
177
209
  when (state.installStatus()) {
178
210
  InstallStatus.DOWNLOADED -> {
179
211
  // Update has been downloaded, prompt user to restart
180
212
  popupSnackbarForCompleteUpdate()
213
+
214
+ // Emit ready event
215
+ val readyData = JSObject()
216
+ readyData.put("message", "Update downloaded and ready to install")
217
+ eventListener?.invoke("appUpdateReady", readyData)
181
218
  }
182
219
  InstallStatus.INSTALLED -> {
183
220
  // Update installed, cleanup
@@ -185,6 +222,10 @@ class AppUpdatePlugin(
185
222
  }
186
223
  InstallStatus.FAILED -> {
187
224
  // Update failed
225
+ val failedData = JSObject()
226
+ failedData.put("error", "Update installation failed")
227
+ failedData.put("code", "INSTALL_FAILED")
228
+ eventListener?.invoke("appUpdateFailed", failedData)
188
229
  }
189
230
  else -> {
190
231
  // Handle other states
@@ -23,10 +23,13 @@ class LiveUpdatePlugin(
23
23
  private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
24
24
  private lateinit var okHttpClient: OkHttpClient
25
25
  private val securityManager = SecurityManager(context)
26
+ private val activeDownloads = mutableMapOf<String, Long>()
27
+ private var downloadManager: android.app.DownloadManager? = null
26
28
 
27
29
  init {
28
30
  // Initialize OkHttp with default settings
29
31
  okHttpClient = createOkHttpClient()
32
+ downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as? android.app.DownloadManager
30
33
  }
31
34
 
32
35
  private fun createOkHttpClient(): OkHttpClient {
@@ -495,6 +498,15 @@ class LiveUpdatePlugin(
495
498
  }
496
499
  }
497
500
 
501
+ fun cleanup() {
502
+ // Clean up any resources
503
+ // Cancel any ongoing downloads
504
+ activeDownloads.values.forEach { downloadId ->
505
+ downloadManager?.remove(downloadId)
506
+ }
507
+ activeDownloads.clear()
508
+ }
509
+
498
510
  private fun markBundleAsVerified() {
499
511
  val prefs = context.getSharedPreferences("native_update", Context.MODE_PRIVATE)
500
512
  prefs.edit().putBoolean("current_bundle_verified", true).apply()
@@ -23,6 +23,7 @@ class NativeUpdatePlugin : Plugin() {
23
23
  private lateinit var appReviewPlugin: AppReviewPlugin
24
24
  private lateinit var backgroundUpdatePlugin: BackgroundUpdatePlugin
25
25
  private lateinit var securityManager: SecurityManager
26
+ private var isInitialized = false
26
27
 
27
28
  override fun load() {
28
29
  super.load()
@@ -34,6 +35,11 @@ class NativeUpdatePlugin : Plugin() {
34
35
  backgroundUpdatePlugin = BackgroundUpdatePlugin()
35
36
  securityManager = SecurityManager(context)
36
37
 
38
+ // Set up app update event listener
39
+ appUpdatePlugin.setEventListener { eventName, data ->
40
+ notifyListeners(eventName, data)
41
+ }
42
+
37
43
  // Register plugins with manager for background access
38
44
  BackgroundUpdateManager.registerLiveUpdatePlugin(liveUpdatePlugin)
39
45
  BackgroundUpdateManager.registerAppUpdatePlugin(appUpdatePlugin)
@@ -48,6 +54,45 @@ class NativeUpdatePlugin : Plugin() {
48
54
  }
49
55
  }
50
56
 
57
+ @PluginMethod
58
+ fun initialize(call: PluginCall) {
59
+ val config = call.getObject("config")
60
+ if (config == null) {
61
+ call.reject("Configuration object is required")
62
+ return
63
+ }
64
+
65
+ try {
66
+ // Initialize with filesystem and preferences if provided
67
+ // In Android, we typically don't need these as we use native APIs
68
+
69
+ // Apply configuration
70
+ configure(call)
71
+
72
+ isInitialized = true
73
+ call.resolve()
74
+ } catch (e: Exception) {
75
+ call.reject("Initialization failed", e)
76
+ }
77
+ }
78
+
79
+ @PluginMethod
80
+ fun isInitialized(call: PluginCall) {
81
+ call.resolve(JSObject().put("initialized", isInitialized))
82
+ }
83
+
84
+ @PluginMethod
85
+ fun cleanup(call: PluginCall) {
86
+ try {
87
+ // Clean up any resources
88
+ liveUpdatePlugin.cleanup()
89
+ backgroundUpdatePlugin.disableBackgroundUpdates()
90
+ call.resolve()
91
+ } catch (e: Exception) {
92
+ call.reject("Cleanup failed", e)
93
+ }
94
+ }
95
+
51
96
  @PluginMethod
52
97
  fun configure(call: PluginCall) {
53
98
  val config = call.getObject("config")
@@ -118,7 +163,13 @@ class NativeUpdatePlugin : Plugin() {
118
163
 
119
164
  @PluginMethod
120
165
  fun reset(call: PluginCall) {
121
- liveUpdatePlugin.reset(call)
166
+ try {
167
+ // Reset plugin state
168
+ liveUpdatePlugin.reset(call)
169
+ isInitialized = false
170
+ } catch (e: Exception) {
171
+ call.reject("Reset failed", e)
172
+ }
122
173
  }
123
174
 
124
175
  @PluginMethod
@@ -0,0 +1,56 @@
1
+ # Minimal Backend Server Template
2
+
3
+ This is a minimal backend server for testing Capacitor Native Update plugin.
4
+
5
+ ⚠️ **NOT FOR PRODUCTION USE** - This is only for development and testing!
6
+
7
+ ## Quick Start
8
+
9
+ 1. Install dependencies:
10
+ ```bash
11
+ npm install
12
+ ```
13
+
14
+ 2. Start server:
15
+ ```bash
16
+ npm start
17
+ ```
18
+
19
+ Server runs on http://localhost:3000
20
+
21
+ ## API Endpoints
22
+
23
+ ### Check for Updates
24
+ ```
25
+ GET /api/v1/check?version=1.0.0&channel=production&appId=com.example.app
26
+ ```
27
+
28
+ ### Upload Bundle
29
+ ```
30
+ POST /api/v1/bundles
31
+ Content-Type: multipart/form-data
32
+ Fields:
33
+ - bundle: ZIP file
34
+ - version: 1.0.1
35
+ - appId: com.example.app
36
+ - channel: production
37
+ - mandatory: false
38
+ - releaseNotes: Bug fixes
39
+ ```
40
+
41
+ ### Download Bundle
42
+ ```
43
+ GET /api/v1/bundles/bundle-1.0.1.zip
44
+ ```
45
+
46
+ ## Production Requirements
47
+
48
+ For production, you need:
49
+ - Real database (PostgreSQL, MongoDB, etc.)
50
+ - Authentication & authorization
51
+ - CDN for bundle distribution
52
+ - Rate limiting
53
+ - Monitoring & logging
54
+ - SSL/TLS certificates
55
+ - Load balancing
56
+ - Backup strategy
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "capacitor-update-server",
3
+ "version": "1.0.0",
4
+ "description": "Minimal backend server for Capacitor Native Update",
5
+ "type": "module",
6
+ "main": "server.js",
7
+ "scripts": {
8
+ "start": "node server.js",
9
+ "dev": "node --watch server.js"
10
+ },
11
+ "dependencies": {
12
+ "express": "^4.18.2",
13
+ "cors": "^2.8.5",
14
+ "multer": "^1.4.5-lts.1",
15
+ "crypto": "^1.0.1"
16
+ },
17
+ "engines": {
18
+ "node": ">=18.0.0"
19
+ }
20
+ }
@@ -0,0 +1,121 @@
1
+ import express from 'express';
2
+ import cors from 'cors';
3
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
4
+ import { join } from 'path';
5
+ import multer from 'multer';
6
+ import crypto from 'crypto';
7
+
8
+ const app = express();
9
+ const PORT = process.env.PORT || 3000;
10
+
11
+ // Ensure directories exist
12
+ if (!existsSync('./bundles')) mkdirSync('./bundles');
13
+ if (!existsSync('./data')) mkdirSync('./data');
14
+
15
+ // Middleware
16
+ app.use(cors());
17
+ app.use(express.json());
18
+
19
+ // Storage for bundles
20
+ const storage = multer.diskStorage({
21
+ destination: './bundles',
22
+ filename: (req, file, cb) => {
23
+ const version = req.body.version || Date.now();
24
+ cb(null, `bundle-${version}.zip`);
25
+ }
26
+ });
27
+
28
+ const upload = multer({ storage });
29
+
30
+ // In-memory database (use real DB in production)
31
+ let versions = {};
32
+ const versionsFile = './data/versions.json';
33
+
34
+ // Load existing versions
35
+ if (existsSync(versionsFile)) {
36
+ versions = JSON.parse(readFileSync(versionsFile, 'utf8'));
37
+ }
38
+
39
+ // Save versions
40
+ function saveVersions() {
41
+ writeFileSync(versionsFile, JSON.stringify(versions, null, 2));
42
+ }
43
+
44
+ // Routes
45
+ app.get('/api/v1/check', (req, res) => {
46
+ const { version, channel = 'production', appId } = req.query;
47
+
48
+ const key = `${appId}-${channel}`;
49
+ const latest = versions[key];
50
+
51
+ if (!latest) {
52
+ return res.json({ updateAvailable: false });
53
+ }
54
+
55
+ res.json({
56
+ updateAvailable: latest.version !== version,
57
+ version: latest.version,
58
+ downloadUrl: `${req.protocol}://${req.get('host')}/api/v1/bundles/${latest.bundleId}`,
59
+ checksum: latest.checksum,
60
+ size: latest.size,
61
+ mandatory: latest.mandatory || false,
62
+ releaseNotes: latest.releaseNotes || 'Bug fixes and improvements'
63
+ });
64
+ });
65
+
66
+ app.post('/api/v1/bundles', upload.single('bundle'), (req, res) => {
67
+ const { version, channel = 'production', appId, mandatory, releaseNotes } = req.body;
68
+
69
+ if (!req.file) {
70
+ return res.status(400).json({ error: 'No bundle file provided' });
71
+ }
72
+
73
+ // Calculate checksum
74
+ const bundleData = readFileSync(req.file.path);
75
+ const checksum = crypto.createHash('sha256').update(bundleData).digest('hex');
76
+
77
+ const bundleId = req.file.filename;
78
+ const key = `${appId}-${channel}`;
79
+
80
+ versions[key] = {
81
+ version,
82
+ bundleId,
83
+ checksum,
84
+ size: req.file.size,
85
+ mandatory: mandatory === 'true',
86
+ releaseNotes,
87
+ uploadedAt: new Date().toISOString()
88
+ };
89
+
90
+ saveVersions();
91
+
92
+ res.json({
93
+ success: true,
94
+ version,
95
+ bundleId,
96
+ checksum
97
+ });
98
+ });
99
+
100
+ app.get('/api/v1/bundles/:bundleId', (req, res) => {
101
+ const bundlePath = join('./bundles', req.params.bundleId);
102
+
103
+ if (!existsSync(bundlePath)) {
104
+ return res.status(404).json({ error: 'Bundle not found' });
105
+ }
106
+
107
+ res.sendFile(bundlePath, { root: '.' });
108
+ });
109
+
110
+ app.get('/health', (req, res) => {
111
+ res.json({ status: 'ok', timestamp: new Date().toISOString() });
112
+ });
113
+
114
+ app.listen(PORT, () => {
115
+ console.log(`Update server running on http://localhost:${PORT}`);
116
+ console.log('\nEndpoints:');
117
+ console.log(`- GET /api/v1/check`);
118
+ console.log(`- POST /api/v1/bundles`);
119
+ console.log(`- GET /api/v1/bundles/:bundleId`);
120
+ console.log(`- GET /health`);
121
+ });
package/cli/index.js CHANGED
@@ -38,9 +38,11 @@ ${chalk.bold('Documentation:')}
38
38
  });
39
39
 
40
40
  // Bundle Management Commands
41
- program
41
+ const bundleCmd = program
42
42
  .command('bundle')
43
- .description('Bundle management commands')
43
+ .description('Bundle management commands');
44
+
45
+ bundleCmd
44
46
  .command('create <webDir>')
45
47
  .alias('create-bundle')
46
48
  .description(`Create an update bundle from your web directory
@@ -63,8 +65,7 @@ ${chalk.bold('Examples:')}
63
65
  await createBundle(webDir, options);
64
66
  });
65
67
 
66
- program
67
- .command('bundle')
68
+ bundleCmd
68
69
  .command('sign <bundlePath>')
69
70
  .alias('sign-bundle')
70
71
  .description(`Sign an update bundle with your private key
@@ -82,8 +83,7 @@ ${chalk.bold('Examples:')}
82
83
  await signBundle(bundlePath, options);
83
84
  });
84
85
 
85
- program
86
- .command('bundle')
86
+ bundleCmd
87
87
  .command('verify <bundlePath>')
88
88
  .alias('verify-bundle')
89
89
  .description(`Verify a signed bundle with public key
@@ -97,9 +97,11 @@ ${chalk.bold('Example:')}
97
97
  });
98
98
 
99
99
  // Key Management Commands
100
- program
100
+ const keysCmd = program
101
101
  .command('keys')
102
- .description('Key management commands')
102
+ .description('Key management commands');
103
+
104
+ keysCmd
103
105
  .command('generate')
104
106
  .alias('generate-keys')
105
107
  .description(`Generate a new key pair for bundle signing
@@ -122,9 +124,11 @@ ${chalk.bold('Examples:')}
122
124
  });
123
125
 
124
126
  // Server Commands
125
- program
127
+ const serverCmd = program
126
128
  .command('server')
127
- .description('Development server commands')
129
+ .description('Development server commands');
130
+
131
+ serverCmd
128
132
  .command('start')
129
133
  .alias('start-server')
130
134
  .description('Start a local update server for testing')
@@ -158,9 +162,11 @@ ${chalk.bold('Examples:')}
158
162
  });
159
163
 
160
164
  // Backend Commands
161
- program
165
+ const backendCmd = program
162
166
  .command('backend')
163
- .description('Backend template commands')
167
+ .description('Backend template commands');
168
+
169
+ backendCmd
164
170
  .command('create <type>')
165
171
  .alias('create-backend')
166
172
  .description(`Create a backend template (express, firebase, vercel)
@@ -183,9 +189,11 @@ ${chalk.bold('Examples:')}
183
189
  });
184
190
 
185
191
  // Config Commands
186
- program
192
+ const configCmd = program
187
193
  .command('config')
188
- .description('Configuration commands')
194
+ .description('Configuration commands');
195
+
196
+ configCmd
189
197
  .command('check')
190
198
  .description('Validate your native-update configuration')
191
199
  .action(async () => {
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Centralized event emitter for the Native Update plugin
3
+ */
4
+ export declare class EventEmitter {
5
+ private static instance;
6
+ private listeners;
7
+ private constructor();
8
+ static getInstance(): EventEmitter;
9
+ /**
10
+ * Add a listener for an event
11
+ */
12
+ addListener(eventName: string, listener: (data: unknown) => void): () => void;
13
+ /**
14
+ * Emit an event to all listeners
15
+ */
16
+ emit(eventName: string, data: unknown): void;
17
+ /**
18
+ * Remove all listeners for a specific event
19
+ */
20
+ removeListeners(eventName: string): void;
21
+ /**
22
+ * Remove all listeners
23
+ */
24
+ removeAllListeners(): void;
25
+ /**
26
+ * Get the number of listeners for an event
27
+ */
28
+ listenerCount(eventName: string): number;
29
+ /**
30
+ * Get all event names that have listeners
31
+ */
32
+ eventNames(): string[];
33
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Centralized event emitter for the Native Update plugin
3
+ */
4
+ export class EventEmitter {
5
+ constructor() {
6
+ this.listeners = new Map();
7
+ }
8
+ static getInstance() {
9
+ if (!EventEmitter.instance) {
10
+ EventEmitter.instance = new EventEmitter();
11
+ }
12
+ return EventEmitter.instance;
13
+ }
14
+ /**
15
+ * Add a listener for an event
16
+ */
17
+ addListener(eventName, listener) {
18
+ if (!this.listeners.has(eventName)) {
19
+ this.listeners.set(eventName, new Set());
20
+ }
21
+ this.listeners.get(eventName).add(listener);
22
+ // Return remove function
23
+ return () => {
24
+ const listeners = this.listeners.get(eventName);
25
+ if (listeners) {
26
+ listeners.delete(listener);
27
+ if (listeners.size === 0) {
28
+ this.listeners.delete(eventName);
29
+ }
30
+ }
31
+ };
32
+ }
33
+ /**
34
+ * Emit an event to all listeners
35
+ */
36
+ emit(eventName, data) {
37
+ const listeners = this.listeners.get(eventName);
38
+ if (listeners) {
39
+ listeners.forEach(listener => {
40
+ try {
41
+ listener(data);
42
+ }
43
+ catch (error) {
44
+ console.error(`Error in event listener for ${eventName}:`, error);
45
+ }
46
+ });
47
+ }
48
+ }
49
+ /**
50
+ * Remove all listeners for a specific event
51
+ */
52
+ removeListeners(eventName) {
53
+ this.listeners.delete(eventName);
54
+ }
55
+ /**
56
+ * Remove all listeners
57
+ */
58
+ removeAllListeners() {
59
+ this.listeners.clear();
60
+ }
61
+ /**
62
+ * Get the number of listeners for an event
63
+ */
64
+ listenerCount(eventName) {
65
+ var _a;
66
+ return ((_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.size) || 0;
67
+ }
68
+ /**
69
+ * Get all event names that have listeners
70
+ */
71
+ eventNames() {
72
+ return Array.from(this.listeners.keys());
73
+ }
74
+ }
75
+ //# sourceMappingURL=event-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitter.js","sourceRoot":"","sources":["../../../src/core/event-emitter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,YAAY;IAIvB;QAFQ,cAAS,GAA8C,IAAI,GAAG,EAAE,CAAC;IAElD,CAAC;IAExB,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;YAC3B,YAAY,CAAC,QAAQ,GAAG,IAAI,YAAY,EAAE,CAAC;QAC7C,CAAC;QACD,OAAO,YAAY,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,WAAW,CACT,SAAiB,EACjB,QAAiC;QAEjC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE7C,yBAAyB;QACzB,OAAO,GAAG,EAAE;YACV,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAChD,IAAI,SAAS,EAAE,CAAC;gBACd,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC3B,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBACzB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,SAAiB,EAAE,IAAa;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,SAAS,EAAE,CAAC;YACd,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAC3B,IAAI,CAAC;oBACH,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACjB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,SAAS,GAAG,EAAE,KAAK,CAAC,CAAC;gBACpE,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,SAAiB;QAC/B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,SAAiB;;QAC7B,OAAO,CAAA,MAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,0CAAE,IAAI,KAAI,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -4,6 +4,8 @@ import { SecurityValidator } from './security';
4
4
  import { BundleManager } from '../live-update/bundle-manager';
5
5
  import { DownloadManager } from '../live-update/download-manager';
6
6
  import { VersionManager } from '../live-update/version-manager';
7
+ import { AppUpdateManager } from '../app-update/app-update-manager';
8
+ import { EventEmitter } from './event-emitter';
7
9
  import { PluginInitConfig } from '../definitions';
8
10
  /**
9
11
  * Central manager for all plugin components
@@ -13,9 +15,11 @@ export declare class PluginManager {
13
15
  private readonly configManager;
14
16
  private readonly logger;
15
17
  private readonly securityValidator;
18
+ private readonly eventEmitter;
16
19
  private bundleManager;
17
20
  private downloadManager;
18
21
  private versionManager;
22
+ private appUpdateManager;
19
23
  private initialized;
20
24
  private constructor();
21
25
  static getInstance(): PluginManager;
@@ -55,6 +59,14 @@ export declare class PluginManager {
55
59
  * Get security validator
56
60
  */
57
61
  getSecurityValidator(): SecurityValidator;
62
+ /**
63
+ * Get app update manager
64
+ */
65
+ getAppUpdateManager(): AppUpdateManager;
66
+ /**
67
+ * Get event emitter
68
+ */
69
+ getEventEmitter(): EventEmitter;
58
70
  /**
59
71
  * Reset plugin state
60
72
  */
@@ -63,4 +75,8 @@ export declare class PluginManager {
63
75
  * Clean up resources
64
76
  */
65
77
  cleanup(): Promise<void>;
78
+ /**
79
+ * Setup event bridge between AppUpdateManager and central EventEmitter
80
+ */
81
+ private setupAppUpdateEventBridge;
66
82
  }