cordova-plugin-hot-updates 2.1.2 → 2.2.1

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.
@@ -0,0 +1,51 @@
1
+ /*!
2
+ * @file HotUpdatesConstants.h
3
+ * @brief Constants for Hot Updates Plugin
4
+ * @details Contains error codes, storage keys, and directory names used by the plugin
5
+ * @version 2.1.0
6
+ * @date 2025-11-13
7
+ * @author Mustafin Vladimir
8
+ * @copyright Copyright (c) 2025. All rights reserved.
9
+ */
10
+
11
+ #ifndef HotUpdatesConstants_h
12
+ #define HotUpdatesConstants_h
13
+
14
+ #pragma mark - Error Codes
15
+
16
+ // Error codes returned to JavaScript
17
+ extern NSString * const kErrorUpdateDataRequired;
18
+ extern NSString * const kErrorURLRequired;
19
+ extern NSString * const kErrorDownloadInProgress;
20
+ extern NSString * const kErrorDownloadFailed;
21
+ extern NSString * const kErrorHTTPError;
22
+ extern NSString * const kErrorTempDirError;
23
+ extern NSString * const kErrorExtractionFailed;
24
+ extern NSString * const kErrorWWWNotFound;
25
+ extern NSString * const kErrorNoUpdateReady;
26
+ extern NSString * const kErrorUpdateFilesNotFound;
27
+ extern NSString * const kErrorInstallFailed;
28
+ extern NSString * const kErrorVersionRequired;
29
+
30
+ #pragma mark - Storage Keys
31
+
32
+ // NSUserDefaults keys
33
+ extern NSString * const kInstalledVersion;
34
+ extern NSString * const kPendingVersion;
35
+ extern NSString * const kHasPending;
36
+ extern NSString * const kPreviousVersion;
37
+ extern NSString * const kIgnoreList;
38
+ extern NSString * const kCanaryVersion;
39
+ extern NSString * const kDownloadInProgress;
40
+ extern NSString * const kPendingUpdateURL;
41
+ extern NSString * const kPendingUpdateReady;
42
+
43
+ #pragma mark - Directory Names
44
+
45
+ // Directory names
46
+ extern NSString * const kWWWDirName;
47
+ extern NSString * const kPreviousWWWDirName;
48
+ extern NSString * const kBackupWWWDirName;
49
+ extern NSString * const kPendingUpdateDirName;
50
+
51
+ #endif /* HotUpdatesConstants_h */
@@ -0,0 +1,46 @@
1
+ /*!
2
+ * @file HotUpdatesConstants.m
3
+ * @brief Implementation of constants for Hot Updates Plugin
4
+ * @details Defines all constant values used throughout the plugin
5
+ * @version 2.1.0
6
+ * @date 2025-11-13
7
+ * @author Mustafin Vladimir
8
+ * @copyright Copyright (c) 2025. All rights reserved.
9
+ */
10
+
11
+ #import <Foundation/Foundation.h>
12
+ #import "HotUpdatesConstants.h"
13
+
14
+ #pragma mark - Error Codes
15
+
16
+ NSString * const kErrorUpdateDataRequired = @"UPDATE_DATA_REQUIRED";
17
+ NSString * const kErrorURLRequired = @"URL_REQUIRED";
18
+ NSString * const kErrorDownloadInProgress = @"DOWNLOAD_IN_PROGRESS";
19
+ NSString * const kErrorDownloadFailed = @"DOWNLOAD_FAILED";
20
+ NSString * const kErrorHTTPError = @"HTTP_ERROR";
21
+ NSString * const kErrorTempDirError = @"TEMP_DIR_ERROR";
22
+ NSString * const kErrorExtractionFailed = @"EXTRACTION_FAILED";
23
+ NSString * const kErrorWWWNotFound = @"WWW_NOT_FOUND";
24
+ NSString * const kErrorNoUpdateReady = @"NO_UPDATE_READY";
25
+ NSString * const kErrorUpdateFilesNotFound = @"UPDATE_FILES_NOT_FOUND";
26
+ NSString * const kErrorInstallFailed = @"INSTALL_FAILED";
27
+ NSString * const kErrorVersionRequired = @"VERSION_REQUIRED";
28
+
29
+ #pragma mark - Storage Keys
30
+
31
+ NSString * const kInstalledVersion = @"hot_updates_installed_version";
32
+ NSString * const kPendingVersion = @"hot_updates_pending_version";
33
+ NSString * const kHasPending = @"hot_updates_has_pending";
34
+ NSString * const kPreviousVersion = @"hot_updates_previous_version";
35
+ NSString * const kIgnoreList = @"hot_updates_ignore_list";
36
+ NSString * const kCanaryVersion = @"hot_updates_canary_version";
37
+ NSString * const kDownloadInProgress = @"hot_updates_download_in_progress";
38
+ NSString * const kPendingUpdateURL = @"hot_updates_pending_update_url";
39
+ NSString * const kPendingUpdateReady = @"hot_updates_pending_ready";
40
+
41
+ #pragma mark - Directory Names
42
+
43
+ NSString * const kWWWDirName = @"www";
44
+ NSString * const kPreviousWWWDirName = @"www_previous";
45
+ NSString * const kBackupWWWDirName = @"www_backup";
46
+ NSString * const kPendingUpdateDirName = @"pending_update";
package/www/HotUpdates.js CHANGED
@@ -1,73 +1,80 @@
1
1
  var exec = require('cordova/exec');
2
2
 
3
3
  /**
4
- * Cordova Hot Updates Plugin v2.1.2
4
+ * Cordova Hot Updates Plugin v2.2.1
5
5
  * Frontend-controlled manual hot updates for iOS
6
6
  *
7
- * Provides manual over-the-air (OTA) updates for Cordova applications
8
- * using the WebView Reload approach. All update decisions are controlled
9
- * by JavaScript - the native plugin only executes commands.
10
- *
11
- * Features:
12
- * - Frontend-controlled manual updates (no automatic checking)
13
- * - Two-step update flow: getUpdate() downloads, forceUpdate() installs
14
- * - Automatic rollback with 20-second canary timer
15
- * - IgnoreList system for tracking problematic versions (information only)
16
- * - Auto-install pending updates on next app launch
17
- * - WebView reload approach for instant updates without app restart
18
- * - No App Store approval required for web content updates
19
- *
20
- * @version 2.1.2
7
+ * @version 2.2.1
21
8
  * @author Mustafin Vladimir
22
9
  */
10
+
11
+ /**
12
+ * Error codes returned by the plugin
13
+ * @readonly
14
+ * @enum {string}
15
+ */
16
+ var ErrorCodes = {
17
+ // getUpdate errors
18
+ UPDATE_DATA_REQUIRED: 'UPDATE_DATA_REQUIRED',
19
+ URL_REQUIRED: 'URL_REQUIRED',
20
+ DOWNLOAD_IN_PROGRESS: 'DOWNLOAD_IN_PROGRESS',
21
+ DOWNLOAD_FAILED: 'DOWNLOAD_FAILED',
22
+ HTTP_ERROR: 'HTTP_ERROR',
23
+ TEMP_DIR_ERROR: 'TEMP_DIR_ERROR',
24
+ EXTRACTION_FAILED: 'EXTRACTION_FAILED',
25
+ WWW_NOT_FOUND: 'WWW_NOT_FOUND',
26
+ // forceUpdate errors
27
+ NO_UPDATE_READY: 'NO_UPDATE_READY',
28
+ UPDATE_FILES_NOT_FOUND: 'UPDATE_FILES_NOT_FOUND',
29
+ INSTALL_FAILED: 'INSTALL_FAILED',
30
+ // canary errors
31
+ VERSION_REQUIRED: 'VERSION_REQUIRED'
32
+ };
33
+
23
34
  var HotUpdates = {
24
35
 
36
+ /**
37
+ * Error codes enum
38
+ * @type {Object}
39
+ */
40
+ ErrorCodes: ErrorCodes,
41
+
25
42
  /**
26
43
  * Download update from server
27
44
  *
28
- * Downloads update ZIP archive from the provided URL and saves to two locations:
29
- * - temp_downloaded_update (for immediate installation via forceUpdate)
30
- * - pending_update (for auto-installation on next app launch)
31
- *
32
- * If the specified version is already downloaded, returns success without re-downloading.
33
- * Does NOT check ignoreList - JavaScript controls all installation decisions.
34
- *
35
45
  * @param {Object} options - Update options
36
46
  * @param {string} options.url - URL to download ZIP archive (required)
37
47
  * @param {string} [options.version] - Version string (optional)
38
- * @param {Function} callback - Callback function
39
- * - Called with null on success
40
- * - Called with {error: {message?: string}} on error
48
+ * @param {Function} callback - Callback(error)
49
+ * - null on success
50
+ * - {error: {code: string, message: string}} on error
41
51
  *
42
52
  * @example
43
- * window.hotUpdate.getUpdate({
44
- * url: 'https://your-server.com/updates/2.0.0.zip',
45
- * version: '2.0.0'
46
- * }, function(error) {
47
- * if (error) {
48
- * console.error('Download failed:', error);
49
- * } else {
50
- * console.log('Update downloaded successfully');
51
- * // Can now call forceUpdate() to install immediately
52
- * // Or user can ignore and it will auto-install on next launch
53
- * }
53
+ * hotUpdate.getUpdate({url: 'https://server.com/update.zip', version: '2.0.0'}, function(err) {
54
+ * if (err) console.error(err.error.code, err.error.message);
55
+ * else console.log('Downloaded');
54
56
  * });
55
57
  */
56
58
  getUpdate: function(options, callback) {
57
- if (!options || !options.url) {
59
+ if (!options) {
60
+ if (callback) {
61
+ callback({error: {code: ErrorCodes.UPDATE_DATA_REQUIRED, message: 'Update data required'}});
62
+ }
63
+ return;
64
+ }
65
+
66
+ if (!options.url) {
58
67
  if (callback) {
59
- callback({error: {message: 'URL is required'}});
68
+ callback({error: {code: ErrorCodes.URL_REQUIRED, message: 'URL is required'}});
60
69
  }
61
70
  return;
62
71
  }
63
72
 
64
73
  exec(
65
74
  function() {
66
- // Success
67
75
  if (callback) callback(null);
68
76
  },
69
77
  function(error) {
70
- // Error
71
78
  if (callback) callback({error: error});
72
79
  },
73
80
  'HotUpdates',
@@ -79,42 +86,22 @@ var HotUpdates = {
79
86
  /**
80
87
  * Install downloaded update immediately
81
88
  *
82
- * Installs the update that was downloaded via getUpdate().
83
- * This will:
84
- * 1. Backup current version to www_previous
85
- * 2. Copy downloaded update to Documents/www
86
- * 3. Clear WebView cache (disk, memory, Service Worker)
87
- * 4. Reload WebView
88
- * 5. Start 20-second canary timer
89
- *
90
- * IMPORTANT: JavaScript MUST call canary(version) within 20 seconds
91
- * after reload to confirm successful bundle load. Otherwise automatic
92
- * rollback will occur.
93
- *
94
- * Does NOT check ignoreList - JavaScript decides what to install.
95
- *
96
- * @param {Function} callback - Callback function
97
- * - Called with null on success (before WebView reload)
98
- * - Called with {error: {message?: string}} on error
89
+ * @param {Function} callback - Callback(error)
90
+ * - null on success (WebView will reload)
91
+ * - {error: {code: string, message: string}} on error
99
92
  *
100
93
  * @example
101
- * window.hotUpdate.forceUpdate(function(error) {
102
- * if (error) {
103
- * console.error('Install failed:', error);
104
- * } else {
105
- * console.log('Update installing, WebView will reload...');
106
- * // After reload, MUST call canary() within 20 seconds!
107
- * }
94
+ * hotUpdate.forceUpdate(function(err) {
95
+ * if (err) console.error(err.error.code);
96
+ * // WebView reloads, call canary() within 20 sec
108
97
  * });
109
98
  */
110
99
  forceUpdate: function(callback) {
111
100
  exec(
112
101
  function() {
113
- // Success
114
102
  if (callback) callback(null);
115
103
  },
116
104
  function(error) {
117
- // Error
118
105
  if (callback) callback({error: error});
119
106
  },
120
107
  'HotUpdates',
@@ -124,36 +111,30 @@ var HotUpdates = {
124
111
  },
125
112
 
126
113
  /**
127
- * Confirm successful bundle load (canary check)
128
- *
129
- * MUST be called within 20 seconds after forceUpdate() to confirm
130
- * that the new bundle loaded successfully. This stops the canary timer
131
- * and prevents automatic rollback.
132
- *
133
- * If not called within 20 seconds:
134
- * - Automatic rollback to previous version
135
- * - Failed version added to ignoreList
136
- * - WebView reloaded with previous version
137
- *
138
- * Call this immediately after your app initialization completes.
114
+ * Confirm successful bundle load (MUST call within 20 sec after forceUpdate)
139
115
  *
140
- * @param {string} version - Version that loaded successfully
141
- * @param {Function} [callback] - Optional callback (not used, method is synchronous)
116
+ * @param {string} version - Current version
117
+ * @param {Function} [callback] - Optional callback
142
118
  *
143
119
  * @example
144
- * // Call as early as possible after app loads
145
120
  * document.addEventListener('deviceready', function() {
146
- * window.hotUpdate.canary('2.0.0');
147
- * console.log('Canary confirmed, update successful');
148
- * }, false);
121
+ * hotUpdate.canary('2.0.0');
122
+ * });
149
123
  */
150
124
  canary: function(version, callback) {
125
+ if (!version) {
126
+ if (callback) {
127
+ callback({error: {code: ErrorCodes.VERSION_REQUIRED, message: 'Version is required'}});
128
+ }
129
+ return;
130
+ }
131
+
151
132
  exec(
152
133
  function() {
153
- if (callback) callback();
134
+ if (callback) callback(null);
154
135
  },
155
- function() {
156
- if (callback) callback();
136
+ function(error) {
137
+ if (callback) callback({error: error});
157
138
  },
158
139
  'HotUpdates',
159
140
  'canary',
@@ -162,50 +143,62 @@ var HotUpdates = {
162
143
  },
163
144
 
164
145
  /**
165
- * Get list of problematic versions (information only)
146
+ * Get list of problematic versions
166
147
  *
167
- * Returns array of version strings that failed to load (triggered rollback).
168
- * This is an INFORMATION-ONLY system - native does NOT block installation
169
- * of versions in this list.
170
- *
171
- * JavaScript should read this list and decide whether to skip downloading/
172
- * installing these versions. If JS decides to install a version from the
173
- * ignoreList, that's allowed (per TS requirements).
174
- *
175
- * Native automatically adds versions to this list when rollback occurs.
176
- * JavaScript cannot modify the list (no add/remove/clear methods per TS v2.1.0).
177
- *
178
- * @param {Function} callback - Callback function
179
- * - Called with {versions: string[]} - Array of problematic version strings
148
+ * @param {Function} callback - Callback({versions: string[]})
180
149
  *
181
150
  * @example
182
- * window.hotUpdate.getIgnoreList(function(result) {
183
- * console.log('Problematic versions:', result.versions);
184
- * // Example: {versions: ['1.9.0', '2.0.1']}
185
- *
186
- * // JavaScript decides what to do with this information
187
- * var shouldSkip = result.versions.includes(availableVersion);
188
- * if (shouldSkip) {
189
- * console.log('Skipping known problematic version');
190
- * } else {
191
- * // Download and install
151
+ * hotUpdate.getIgnoreList(function(result) {
152
+ * if (result.versions.includes(newVersion)) {
153
+ * console.log('Version is blacklisted');
192
154
  * }
193
155
  * });
194
156
  */
195
157
  getIgnoreList: function(callback) {
196
158
  exec(
197
- function(versions) {
198
- // Success - native returns array of version strings
199
- if (callback) callback({versions: versions || []});
159
+ function(result) {
160
+ if (callback) callback(result || {versions: []});
200
161
  },
201
- function(error) {
202
- // Error - return empty list
162
+ function() {
203
163
  if (callback) callback({versions: []});
204
164
  },
205
165
  'HotUpdates',
206
166
  'getIgnoreList',
207
167
  []
208
168
  );
169
+ },
170
+
171
+ /**
172
+ * Get version info (debug method)
173
+ *
174
+ * @param {Function} callback - Callback with version info
175
+ * {
176
+ * appBundleVersion: string,
177
+ * installedVersion: string|null,
178
+ * previousVersion: string|null,
179
+ * canaryVersion: string|null,
180
+ * pendingVersion: string|null,
181
+ * hasPendingUpdate: boolean,
182
+ * ignoreList: string[]
183
+ * }
184
+ *
185
+ * @example
186
+ * hotUpdate.getVersionInfo(function(info) {
187
+ * console.log('Current:', info.installedVersion || info.appBundleVersion);
188
+ * });
189
+ */
190
+ getVersionInfo: function(callback) {
191
+ exec(
192
+ function(info) {
193
+ if (callback) callback(info);
194
+ },
195
+ function(error) {
196
+ if (callback) callback({error: error});
197
+ },
198
+ 'HotUpdates',
199
+ 'getVersionInfo',
200
+ []
201
+ );
209
202
  }
210
203
  };
211
204