cordova-plugin-hot-updates 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,31 +1,23 @@
1
- # Cordova Hot Updates Plugin
1
+ # Cordova Hot Updates Plugin v2.2.0
2
2
 
3
- 🔥 **Frontend-controlled over-the-air (OTA) hot updates for Cordova iOS applications**
3
+ Frontend-controlled manual hot updates for Cordova iOS applications using WebView Reload approach.
4
4
 
5
5
  [![npm version](https://badge.fury.io/js/cordova-plugin-hot-updates.svg)](https://badge.fury.io/js/cordova-plugin-hot-updates)
6
6
  [![License](https://img.shields.io/badge/License-Custom%20Non--Commercial-blue.svg)](#license)
7
7
 
8
8
  This plugin enables **manual, JavaScript-controlled** web content updates for your Cordova iOS applications without requiring App Store approval. Your frontend code decides when to check, download, and install updates.
9
9
 
10
- ## ✨ What's New in v2.1.0
10
+ ## Features
11
11
 
12
- - **Smart Download**: `getUpdate()` won't re-download already installed versions
13
- - **Cleaner Native Code**: Removed debug logs and emojis for production
14
- - **Better Documentation**: Complete API docs in `docs/` folder
15
- - **Bug Fixes**: Fixed duplicate download issues and code cleanup
12
+ - **Frontend Control**: JavaScript decides when to update (no automatic background checking)
13
+ - **Two-Step Updates**: Separate download (`getUpdate`) and install (`forceUpdate`) for better UX
14
+ - **Auto-Install on Launch**: If user ignores update prompt, it installs on next app launch
15
+ - **Canary System**: Automatic rollback if update fails to load (20-second timeout)
16
+ - **IgnoreList**: Tracks problematic versions (information only, does NOT block installation)
17
+ - **Instant Effect**: WebView Reload approach - no app restart needed
18
+ - **Cache Management**: Clears WKWebView cache (disk, memory, Service Worker) before reload
16
19
 
17
- [See full changelog](CHANGELOG.md)
18
-
19
- ## 🎯 Key Features
20
-
21
- - **🎮 Frontend Control**: Your JavaScript decides when to update (no automatic background checks)
22
- - **⚡ Two-Step Updates**: Separate download and install for better UX
23
- - **🔄 Auto-Install**: If user ignores popup, update installs on next app launch
24
- - **🐦 Canary System**: Automatic rollback if update fails to load (20-second timeout)
25
- - **📋 IgnoreList**: Tracks problematic versions (informational only)
26
- - **🚀 Instant Effect**: WebView Reload approach - no app restart needed
27
-
28
- ## 📦 Installation
20
+ ## Installation
29
21
 
30
22
  ```bash
31
23
  # Install from npm
@@ -36,166 +28,358 @@ cd platforms/ios
36
28
  pod install
37
29
  ```
38
30
 
31
+ Or install from local directory:
32
+
33
+ ```bash
34
+ cordova plugin add /path/to/cordova-plugin-hot-updates
35
+ ```
36
+
37
+ Or install from GitHub:
38
+
39
+ ```bash
40
+ cordova plugin add https://github.com/vladimirDarksy/Cordova_hot_update.git
41
+ ```
42
+
39
43
  **Requirements:**
40
44
  - Cordova >= 7.0.0
41
45
  - cordova-ios >= 4.4.0
42
- - iOS >= 11.0
46
+ - iOS >= 11.2
43
47
  - CocoaPods (for SSZipArchive dependency)
44
48
 
45
- ## 🚀 Quick Start
49
+ ## Quick Start
46
50
 
47
51
  ### 1. Minimal Integration
48
52
 
49
53
  ```javascript
50
54
  document.addEventListener('deviceready', function() {
51
- // STEP 1: Confirm app loaded successfully (REQUIRED on every start!)
52
- cordova.exec(
53
- function(info) {
54
- const currentVersion = info.installedVersion || info.appBundleVersion;
55
-
56
- // This MUST be called within 20 seconds or automatic rollback occurs
57
- window.HotUpdates.canary(currentVersion, function() {
58
- console.log('✅ Canary confirmed');
59
- });
60
-
61
- // STEP 2: Check for updates on YOUR server
62
- fetch('https://your-api.com/updates/check?version=' + currentVersion)
63
- .then(r => r.json())
64
- .then(data => {
65
- if (data.hasUpdate) {
66
- // STEP 3: Download update
67
- window.HotUpdates.getUpdate({
68
- url: data.downloadURL,
69
- version: data.newVersion
70
- }, function(error) {
71
- if (error) {
72
- console.error('Download failed:', error.error.message);
73
- return;
74
- }
55
+ // CRITICAL: Confirm successful bundle load within 20 seconds
56
+ var currentVersion = localStorage.getItem('app_version') || '1.0.0';
57
+ window.hotUpdate.canary(currentVersion);
58
+
59
+ // Check for updates
60
+ checkForUpdates();
61
+ }, false);
62
+
63
+ function checkForUpdates() {
64
+ fetch('https://your-server.com/api/check-update?version=1.0.0')
65
+ .then(response => response.json())
66
+ .then(data => {
67
+ if (data.hasUpdate) {
68
+ downloadAndInstall(data.downloadUrl, data.version);
69
+ }
70
+ });
71
+ }
75
72
 
76
- // STEP 4: Show popup
77
- if (confirm('Update to ' + data.newVersion + '?')) {
78
- // STEP 5: Install immediately
79
- window.HotUpdates.forceUpdate(function(error) {
80
- if (error) {
81
- console.error('Install failed:', error.error.message);
82
- }
83
- // WebView reloads automatically
84
- });
85
- }
86
- // If user cancels: update installs automatically on next launch
87
- });
88
- }
73
+ function downloadAndInstall(url, version) {
74
+ window.hotUpdate.getUpdate({url: url, version: version}, function(error) {
75
+ if (!error) {
76
+ if (confirm('Update available. Install now?')) {
77
+ localStorage.setItem('app_version', version);
78
+ window.hotUpdate.forceUpdate(function(error) {
79
+ // WebView will reload, canary() will be called in deviceready
89
80
  });
90
- },
91
- function(error) {
92
- console.error('Failed to get version:', error);
93
- },
94
- 'HotUpdates',
95
- 'getVersionInfo',
96
- []
97
- );
81
+ }
82
+ // If user declines, update auto-installs on next launch
83
+ }
84
+ });
85
+ }
86
+ ```
87
+
88
+ ## Error Handling
89
+
90
+ All errors are returned in a unified format for programmatic handling:
91
+
92
+ ```javascript
93
+ // Error format
94
+ callback({
95
+ error: {
96
+ code: "ERROR_CODE", // Code for programmatic handling
97
+ message: "Detailed message" // Detailed message for logs
98
+ }
99
+ })
100
+
101
+ // Success result
102
+ callback(null)
103
+ ```
104
+
105
+ ### Error Codes
106
+
107
+ #### getUpdate() errors:
108
+ - `UPDATE_DATA_REQUIRED` - Missing updateData parameter
109
+ - `URL_REQUIRED` - Missing url parameter
110
+ - `DOWNLOAD_IN_PROGRESS` - Download already in progress
111
+ - `DOWNLOAD_FAILED` - Network download error (message contains details)
112
+ - `HTTP_ERROR` - HTTP status != 200 (message contains status code)
113
+ - `TEMP_DIR_ERROR` - Error creating temporary directory
114
+ - `EXTRACTION_FAILED` - Error extracting ZIP archive
115
+ - `WWW_NOT_FOUND` - www folder not found in archive
116
+
117
+ #### forceUpdate() errors:
118
+ - `NO_UPDATE_READY` - getUpdate() not called first
119
+ - `UPDATE_FILES_NOT_FOUND` - Downloaded update files not found
120
+ - `INSTALL_FAILED` - Error copying files (message contains details)
121
+
122
+ #### canary() errors:
123
+ - `VERSION_REQUIRED` - Missing version parameter
124
+
125
+ ### Error Handling Example
126
+
127
+ ```javascript
128
+ window.hotUpdate.getUpdate({url: 'http://...'}, function(error) {
129
+ if (error) {
130
+ console.error('[HotUpdates]', error.code, ':', error.message);
131
+
132
+ switch(error.code) {
133
+ case 'HTTP_ERROR':
134
+ // Handle HTTP errors
135
+ break;
136
+ case 'DOWNLOAD_FAILED':
137
+ // Handle network errors
138
+ break;
139
+ default:
140
+ console.error('Unknown error:', error);
141
+ }
142
+ } else {
143
+ console.log('Update downloaded successfully');
144
+ }
98
145
  });
99
146
  ```
100
147
 
101
- ## 📚 API Reference
148
+ ## API Reference
149
+
150
+ All API methods are available via `window.hotUpdate` after the `deviceready` event.
151
+
152
+ ### window.hotUpdate.getUpdate(options, callback)
102
153
 
103
- ### Core Methods (v2.1.0)
154
+ Downloads update from server.
104
155
 
105
- #### 1. `getUpdate({url, version?}, callback)`
156
+ Downloads ZIP from provided URL and saves to two locations:
157
+ - `temp_downloaded_update` (for immediate installation via `forceUpdate()`)
158
+ - `pending_update` (for auto-installation on next app launch)
106
159
 
107
- Downloads update in background. **Does NOT install!**
160
+ If version already downloaded, returns success without re-downloading.
108
161
 
162
+ **Does NOT check ignoreList** - JavaScript controls all installation decisions.
163
+
164
+ **Parameters:**
165
+ - `options` (Object):
166
+ - `url` (string, required) - URL to download ZIP archive
167
+ - `version` (string, optional) - Version string
168
+ - `callback` (Function) - `callback(error)`
169
+ - `null` on success
170
+ - `{error: {message?: string}}` on error
171
+
172
+ **Example:**
109
173
  ```javascript
110
- window.HotUpdates.getUpdate({
111
- url: 'https://server.com/updates/2.7.8.zip',
112
- version: '2.7.8' // Optional
174
+ window.hotUpdate.getUpdate({
175
+ url: 'https://your-server.com/updates/2.0.0.zip',
176
+ version: '2.0.0'
113
177
  }, function(error) {
114
178
  if (error) {
115
- console.error('Download failed:', error.error.message);
179
+ console.error('Download failed:', error);
116
180
  } else {
117
- console.log(' Download complete');
181
+ console.log('Update downloaded successfully');
118
182
  }
119
183
  });
120
184
  ```
121
185
 
122
- **Features:**
123
- - Returns success if version already installed (won't re-download)
124
- - Saves to two locations: immediate install + auto-install on next launch
125
- - Callback format: `null` on success, `{error: {message}}` on error
186
+ ---
187
+
188
+ ### window.hotUpdate.forceUpdate(callback)
189
+
190
+ Installs downloaded update immediately and reloads WebView.
191
+
192
+ **Process:**
193
+ 1. Backup current version to `www_previous`
194
+ 2. Copy downloaded update to `Documents/www`
195
+ 3. Clear WebView cache (disk, memory, Service Worker)
196
+ 4. Reload WebView
197
+ 5. Start 20-second canary timer
198
+
199
+ **IMPORTANT:** JavaScript MUST call `canary(version)` within 20 seconds after reload to confirm successful bundle load. Otherwise automatic rollback occurs.
126
200
 
127
- #### 2. `forceUpdate(callback)`
201
+ **Does NOT check ignoreList** - JavaScript decides what to install.
128
202
 
129
- Installs downloaded update and reloads WebView. **No parameters needed!**
203
+ **Parameters:**
204
+ - `callback` (Function) - `callback(error)`
205
+ - `null` on success (before WebView reload)
206
+ - `{error: {message?: string}}` on error
130
207
 
208
+ **Example:**
131
209
  ```javascript
132
- window.HotUpdates.forceUpdate(function(error) {
210
+ window.hotUpdate.forceUpdate(function(error) {
133
211
  if (error) {
134
- console.error('Install failed:', error.error.message);
212
+ console.error('Install failed:', error);
135
213
  } else {
136
- console.log(' Installed, reloading...');
214
+ console.log('Update installing, WebView will reload...');
137
215
  }
138
216
  });
139
217
  ```
140
218
 
141
- **Important:**
142
- - Must call `getUpdate()` first
143
- - WebView reloads automatically after ~1 second
144
- - Call `canary()` after reload to confirm success
219
+ ---
220
+
221
+ ### window.hotUpdate.canary(version, callback)
222
+
223
+ Confirms successful bundle load after update.
145
224
 
146
- #### 3. `canary(version, callback)`
225
+ **MUST be called within 20 seconds** after `forceUpdate()` to stop canary timer and prevent automatic rollback.
147
226
 
148
- Confirms bundle loaded successfully. **REQUIRED on every app start!**
227
+ **If not called within 20 seconds:**
228
+ - Automatic rollback to previous version
229
+ - Failed version added to ignoreList
230
+ - WebView reloaded with previous version
149
231
 
232
+ **Parameters:**
233
+ - `version` (string) - Version that loaded successfully
234
+ - `callback` (Function, optional) - Not used, method is synchronous
235
+
236
+ **Example:**
150
237
  ```javascript
151
- window.HotUpdates.canary('2.7.8', function() {
152
- console.log(' Canary confirmed');
153
- });
238
+ document.addEventListener('deviceready', function() {
239
+ var version = localStorage.getItem('app_version') || '1.0.0';
240
+ window.hotUpdate.canary(version);
241
+ }, false);
154
242
  ```
155
243
 
156
- **Critical:**
157
- - Must be called within 20 seconds after app start
158
- - If not called: automatic rollback to previous version
159
- - Failed version is added to ignore list
244
+ ---
245
+
246
+ ### window.hotUpdate.getIgnoreList(callback)
247
+
248
+ Returns list of problematic versions (information only).
249
+
250
+ **This is an INFORMATION-ONLY system** - native does NOT block installation. JavaScript should read this list and decide whether to skip these versions.
160
251
 
161
- #### 4. `getIgnoreList(callback)`
252
+ Native automatically adds versions to this list when rollback occurs.
162
253
 
163
- Returns list of versions that caused problems.
254
+ **Parameters:**
255
+ - `callback` (Function) - `callback(result)`
256
+ - `result`: `{versions: string[]}` - Array of problematic version strings
164
257
 
258
+ **Example:**
165
259
  ```javascript
166
- window.HotUpdates.getIgnoreList(function(result) {
167
- const badVersions = result.versions; // ["2.7.5", "2.7.6"]
260
+ window.hotUpdate.getIgnoreList(function(result) {
261
+ console.log('Problematic versions:', result.versions);
168
262
 
169
- // Check before downloading
170
- if (!badVersions.includes(newVersion)) {
171
- // Safe to download
263
+ if (result.versions.includes(newVersion)) {
264
+ console.log('Skipping known problematic version');
172
265
  }
173
266
  });
174
267
  ```
175
268
 
176
- **Note:** IgnoreList is informational only - you decide whether to skip versions.
269
+ ---
177
270
 
178
- ## 🖥️ Server Requirements
271
+ ## Complete Update Flow
179
272
 
180
- Your server should provide:
273
+ ```javascript
274
+ // Step 1: Check for updates on your server
275
+ function checkForUpdates() {
276
+ var currentVersion = localStorage.getItem('app_version') || '1.0.0';
277
+
278
+ fetch('https://your-server.com/api/check-update?version=' + currentVersion)
279
+ .then(response => response.json())
280
+ .then(data => {
281
+ if (data.hasUpdate) {
282
+ // Step 2: Check ignoreList
283
+ window.hotUpdate.getIgnoreList(function(ignoreList) {
284
+ if (ignoreList.versions.includes(data.version)) {
285
+ console.log('Skipping problematic version');
286
+ return;
287
+ }
288
+
289
+ // Step 3: Download
290
+ window.hotUpdate.getUpdate({
291
+ url: data.downloadUrl,
292
+ version: data.version
293
+ }, function(error) {
294
+ if (!error) {
295
+ // Step 4: Prompt user
296
+ if (confirm('Update available. Install now?')) {
297
+ // Save version for canary check
298
+ localStorage.setItem('app_version', data.version);
299
+
300
+ // Step 5: Install
301
+ window.hotUpdate.forceUpdate(function(error) {
302
+ // WebView will reload
303
+ });
304
+ }
305
+ // If declined, auto-installs on next launch
306
+ }
307
+ });
308
+ });
309
+ }
310
+ });
311
+ }
312
+
313
+ // Step 6: After reload, confirm success
314
+ document.addEventListener('deviceready', function() {
315
+ var version = localStorage.getItem('app_version') || '1.0.0';
316
+ window.hotUpdate.canary(version); // Must call within 20 seconds!
317
+
318
+ initApp();
319
+ }, false);
320
+ ```
321
+
322
+ ## How It Works
323
+
324
+ ### Update Flow
181
325
 
182
- ### Check Endpoint
326
+ 1. **Download** (`getUpdate()`):
327
+ - Downloads ZIP from URL
328
+ - Validates `www` folder structure
329
+ - Saves to TWO locations:
330
+ - `temp_downloaded_update` (for immediate install)
331
+ - `pending_update` (for auto-install on next launch)
183
332
 
184
- **GET** `/api/updates/check?version={current}&platform=ios`
333
+ 2. **Installation Options**:
334
+ - **Immediate**: User clicks "Update" → `forceUpdate()` installs now
335
+ - **Deferred**: User ignores → Auto-installs on next app launch
336
+
337
+ 3. **Rollback Protection**:
338
+ - Previous version backed up before installation
339
+ - 20-second canary timer starts after reload
340
+ - If `canary()` not called → automatic rollback
341
+ - Failed version added to ignoreList
342
+
343
+ 4. **IgnoreList System**:
344
+ - Native tracks failed versions
345
+ - JavaScript reads via `getIgnoreList()`
346
+ - **Does NOT block** - JS decides what to install
347
+
348
+ ### Storage Structure
349
+
350
+ ```
351
+ Documents/
352
+ ├── www/ // Active version
353
+ ├── www_previous/ // Previous version (rollback)
354
+ ├── pending_update/ // Next launch auto-install
355
+ └── temp_downloaded_update/ // Immediate install
356
+ ```
185
357
 
186
- ```json
358
+ ### Version Management
359
+
360
+ - **appBundleVersion** - Native app version from Info.plist
361
+ - **installedVersion** - Current hot update version
362
+ - **previousVersion** - Last working version (rollback)
363
+
364
+ ## Update Server API
365
+
366
+ Your server should provide:
367
+
368
+ **Check API:**
369
+ ```
370
+ GET https://your-server.com/api/check-update?version=1.0.0&platform=ios
371
+
372
+ Response:
187
373
  {
188
374
  "hasUpdate": true,
189
- "newVersion": "2.7.8",
190
- "downloadURL": "https://server.com/updates/2.7.8.zip",
191
- "minAppVersion": "2.7.0"
375
+ "version": "2.0.0",
376
+ "downloadUrl": "https://your-server.com/updates/2.0.0.zip",
377
+ "minAppVersion": "2.7.0",
378
+ "releaseNotes": "Bug fixes"
192
379
  }
193
380
  ```
194
381
 
195
- ### Update Package
196
-
197
- ZIP file containing `www` folder:
198
-
382
+ **Update ZIP Structure:**
199
383
  ```
200
384
  update.zip
201
385
  └── www/
@@ -205,105 +389,90 @@ update.zip
205
389
  └── ...
206
390
  ```
207
391
 
208
- ## 🔧 How It Works
392
+ ## Best Practices
209
393
 
210
- ### Two-Step Update Flow
394
+ ### 1. Always Call Canary
211
395
 
396
+ ```javascript
397
+ document.addEventListener('deviceready', function() {
398
+ var version = localStorage.getItem('app_version');
399
+ window.hotUpdate.canary(version); // Within 20 seconds!
400
+ }, false);
212
401
  ```
213
- 1. JS checks YOUR server for updates
214
- 2. getUpdate() downloads ZIP in background
215
- 3. Show popup to user
216
- 4. User clicks "Update": forceUpdate() installs immediately
217
- 5. User ignores: update auto-installs on next app launch
218
- 6. WebView reloads with new content
219
- 7. JS calls canary() to confirm success
220
- ```
221
-
222
- ### Rollback Protection
223
-
224
- - 20-second canary timer starts after update
225
- - If `canary()` not called → automatic rollback
226
- - Failed version added to ignore list
227
- - App continues working on previous version
228
402
 
229
- ### File Structure
403
+ ### 2. Check IgnoreList
230
404
 
405
+ ```javascript
406
+ window.hotUpdate.getIgnoreList(function(result) {
407
+ if (result.versions.includes(newVersion)) {
408
+ console.log('Known problematic version');
409
+ }
410
+ });
231
411
  ```
232
- Documents/
233
- ├── www/ # Active version
234
- ├── www_previous/ # Backup (for rollback)
235
- ├── pending_update/ # Next launch auto-install
236
- └── temp_downloaded_update/ # Immediate install
237
- ```
238
-
239
- ## 📖 Full Documentation
240
-
241
- - **[docs/README.md](docs/README.md)** - Quick start guide
242
- - **[docs/API.md](docs/API.md)** - Complete API reference
243
- - **[docs/hot-updates-admin.html](docs/hot-updates-admin.html)** - Testing interface
244
- - **[CHANGELOG.md](CHANGELOG.md)** - Version history
245
412
 
246
- ## 🐛 Troubleshooting
413
+ ### 3. Handle Errors
247
414
 
248
- ### Common Issues
249
-
250
- **Updates not working**
251
- - Check `canary()` is called on every app start
252
- - Verify server URL returns correct JSON
253
- - Check iOS device logs for errors
415
+ ```javascript
416
+ window.hotUpdate.getUpdate(options, function(error) {
417
+ if (error) {
418
+ analytics.track('update_failed', {error: error.message});
419
+ showUserMessage('Update failed');
420
+ }
421
+ });
422
+ ```
254
423
 
255
- **Duplicate downloads**
256
- - ✅ Fixed in v2.1.0! `getUpdate()` now checks installed version
424
+ ### 4. Store Version
257
425
 
258
- **WebView shows old content**
259
- - Fixed in v2.1.0! Cache is cleared before reload
426
+ ```javascript
427
+ // Before forceUpdate
428
+ localStorage.setItem('app_version', newVersion);
260
429
 
261
- **CocoaPods errors**
262
- ```bash
263
- cd platforms/ios
264
- pod install
265
- cordova clean ios && cordova build ios
430
+ // After reload
431
+ var version = localStorage.getItem('app_version');
432
+ window.hotUpdate.canary(version);
266
433
  ```
267
434
 
268
- ### Debug Logs
269
-
270
- All plugin actions are logged with `[HotUpdates]` prefix:
435
+ ## Troubleshooting
271
436
 
272
- ```bash
273
- # iOS Simulator
274
- cordova run ios --debug
275
-
276
- # iOS Device
277
- # Use Xcode console or Safari Web Inspector
278
- ```
437
+ ### Update doesn't install
279
438
 
280
- ## ⚠️ Important Notes
439
+ - Check ZIP structure (must have `www/` folder)
440
+ - Check URL accessibility
441
+ - Check Xcode console: `[HotUpdates] ...`
281
442
 
282
- - **iOS Only**: Currently supports iOS platform only
283
- - **Manual Updates Only**: No automatic background checking (you control everything)
284
- - **App Store Compliance**: Only update web content, not native code
285
- - **HTTPS Required**: Update server should use HTTPS in production
286
- - **Testing**: Test rollback mechanism thoroughly
443
+ ### Automatic rollback
287
444
 
288
- ## 🤝 Contributing
445
+ **Cause:** `canary()` not called within 20 seconds
289
446
 
290
- Contributions are welcome! Please submit a Pull Request.
447
+ **Solution:** Call immediately in `deviceready`:
448
+ ```javascript
449
+ document.addEventListener('deviceready', function() {
450
+ window.hotUpdate.canary(version); // First thing!
451
+ }, false);
452
+ ```
291
453
 
292
- ## 📝 License
454
+ ### window.hotUpdate is undefined
293
455
 
294
- This project is licensed under the Custom Non-Commercial License - see the [LICENSE](LICENSE) file for details.
456
+ **Cause:** Called before `deviceready`
295
457
 
296
- **⚠️ Commercial use is strictly prohibited without explicit written permission from the copyright holder.**
458
+ **Solution:**
459
+ ```javascript
460
+ document.addEventListener('deviceready', function() {
461
+ console.log(window.hotUpdate); // Now available
462
+ }, false);
463
+ ```
297
464
 
298
- For commercial licensing inquiries, please contact: **Mustafin Vladimir** <outvova.gor@gmail.com>
465
+ ## License
299
466
 
300
- ## 🙋‍♂️ Support
467
+ Custom Non-Commercial License - See [LICENSE](LICENSE) file
301
468
 
302
- - **Issues**: [GitHub Issues](https://github.com/vladimirDarksy/Cordova_hot_update/issues)
303
- - **npm**: [cordova-plugin-hot-updates](https://www.npmjs.com/package/cordova-plugin-hot-updates)
469
+ ## Author
304
470
 
305
- ---
471
+ **Mustafin Vladimir**
472
+ - GitHub: [@vladimirDarksy](https://github.com/vladimirDarksy)
473
+ - Email: outvova.gor@gmail.com
306
474
 
307
- **Made with ❤️ by [Mustafin Vladimir](https://github.com/vladimirDarksy)**
475
+ ## Support
308
476
 
309
- **Version:** 2.1.0 | **Last Updated:** 2025-11-04
477
+ - Issues: https://github.com/vladimirDarksy/Cordova_hot_update/issues
478
+ - Repository: https://github.com/vladimirDarksy/Cordova_hot_update