vasuzex 2.1.26 → 2.1.29
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.
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const CACHE_KEY = 'app-config';
|
|
15
15
|
const CACHE_EXPIRY_KEY = 'app-config-expiry';
|
|
16
|
+
const CACHE_VERSION_KEY = 'app-config-version';
|
|
16
17
|
const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours
|
|
17
18
|
const BACKGROUND_REFRESH_KEY = 'app-config-last-background-refresh';
|
|
18
19
|
const BACKGROUND_REFRESH_INTERVAL = 60 * 60 * 1000; // 1 hour - only refresh once per hour
|
|
@@ -25,18 +26,33 @@ const BACKGROUND_REFRESH_INTERVAL = 60 * 60 * 1000; // 1 hour - only refresh onc
|
|
|
25
26
|
* @param {boolean} options.forceRefresh - Skip cache and fetch fresh
|
|
26
27
|
* @param {number} options.cacheDuration - Cache duration in milliseconds
|
|
27
28
|
* @param {string} options.configUrl - Custom config endpoint path (default: '/config/app-settings')
|
|
29
|
+
* @param {boolean} options.versionCheck - Enable version-based cache invalidation (default: false)
|
|
30
|
+
* @param {string} options.versionUrl - Custom version endpoint path (default: '/config/version')
|
|
28
31
|
* @returns {Promise<Object>} Configuration object
|
|
29
32
|
*/
|
|
30
33
|
export async function loadAppConfig(apiBaseUrl, options = {}) {
|
|
31
34
|
const {
|
|
32
35
|
forceRefresh = false,
|
|
33
36
|
cacheDuration = DEFAULT_CACHE_DURATION,
|
|
34
|
-
configUrl = '/config/app-settings'
|
|
37
|
+
configUrl = '/config/app-settings',
|
|
38
|
+
versionCheck = false,
|
|
39
|
+
versionUrl = '/config/version'
|
|
35
40
|
} = options;
|
|
36
41
|
|
|
37
42
|
try {
|
|
43
|
+
let shouldForceRefresh = forceRefresh;
|
|
44
|
+
|
|
45
|
+
// Check version if enabled
|
|
46
|
+
if (versionCheck && !forceRefresh) {
|
|
47
|
+
const versionChanged = await checkConfigVersion(apiBaseUrl, versionUrl);
|
|
48
|
+
if (versionChanged) {
|
|
49
|
+
console.log('🔄 Config version changed, clearing cache');
|
|
50
|
+
shouldForceRefresh = true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
// Check cache first (unless force refresh)
|
|
39
|
-
if (!
|
|
55
|
+
if (!shouldForceRefresh) {
|
|
40
56
|
const cached = getCachedConfig();
|
|
41
57
|
if (cached) {
|
|
42
58
|
console.log('📦 Using cached app config');
|
|
@@ -52,6 +68,11 @@ export async function loadAppConfig(apiBaseUrl, options = {}) {
|
|
|
52
68
|
console.log('🌐 Fetching app config from API...');
|
|
53
69
|
const config = await fetchConfigFromAPI(apiBaseUrl, configUrl);
|
|
54
70
|
|
|
71
|
+
// Extract and store version from response if present
|
|
72
|
+
if (versionCheck && config._meta?.version) {
|
|
73
|
+
localStorage.setItem(CACHE_VERSION_KEY, config._meta.version);
|
|
74
|
+
}
|
|
75
|
+
|
|
55
76
|
// Cache the result
|
|
56
77
|
cacheConfig(config, cacheDuration);
|
|
57
78
|
|
|
@@ -196,6 +217,69 @@ async function refreshConfigInBackground(apiBaseUrl, cacheDuration, configUrl =
|
|
|
196
217
|
}
|
|
197
218
|
}
|
|
198
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Check if config version has changed on server
|
|
222
|
+
* @param {string} apiBaseUrl - API base URL
|
|
223
|
+
* @param {string} versionUrl - Version endpoint path
|
|
224
|
+
* @returns {Promise<boolean>} True if version changed, false otherwise
|
|
225
|
+
*/
|
|
226
|
+
async function checkConfigVersion(apiBaseUrl, versionUrl) {
|
|
227
|
+
try {
|
|
228
|
+
const baseUrl = apiBaseUrl.replace(/\/$/, '');
|
|
229
|
+
const path = versionUrl.startsWith('/') ? versionUrl : `/${versionUrl}`;
|
|
230
|
+
const url = `${baseUrl}${path}`;
|
|
231
|
+
|
|
232
|
+
// Fetch version from server
|
|
233
|
+
const response = await fetch(url, {
|
|
234
|
+
method: 'GET',
|
|
235
|
+
headers: { 'Content-Type': 'application/json' },
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// If endpoint doesn't exist, silently continue (backward compatible)
|
|
239
|
+
if (response.status === 404) {
|
|
240
|
+
console.debug('[ConfigLoader] Version endpoint not found (backward compatible mode)');
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
throw new Error(`Version check failed: ${response.status}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const result = await response.json();
|
|
249
|
+
|
|
250
|
+
// Extract version from standardized response: { success, data: { version } }
|
|
251
|
+
const serverVersion = result.data?.version || result.version;
|
|
252
|
+
|
|
253
|
+
if (!serverVersion) {
|
|
254
|
+
console.warn('[ConfigLoader] No version found in response');
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Get cached version
|
|
259
|
+
const cachedVersion = localStorage.getItem(CACHE_VERSION_KEY);
|
|
260
|
+
|
|
261
|
+
// First time - store version
|
|
262
|
+
if (!cachedVersion) {
|
|
263
|
+
localStorage.setItem(CACHE_VERSION_KEY, serverVersion);
|
|
264
|
+
return false; // Don't force refresh on first load
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Compare versions
|
|
268
|
+
if (cachedVersion !== serverVersion) {
|
|
269
|
+
console.log(`[ConfigLoader] Version changed: ${cachedVersion} → ${serverVersion}`);
|
|
270
|
+
localStorage.setItem(CACHE_VERSION_KEY, serverVersion);
|
|
271
|
+
clearConfigCache(); // Clear cache to force fresh fetch
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return false; // Version unchanged
|
|
276
|
+
} catch (error) {
|
|
277
|
+
// Non-critical error - don't break the app
|
|
278
|
+
console.debug('[ConfigLoader] Version check failed (non-critical):', error.message);
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
199
283
|
/**
|
|
200
284
|
* Clear cached configuration
|
|
201
285
|
*/
|
|
@@ -203,6 +287,7 @@ export function clearConfigCache() {
|
|
|
203
287
|
localStorage.removeItem(CACHE_KEY);
|
|
204
288
|
localStorage.removeItem(CACHE_EXPIRY_KEY);
|
|
205
289
|
localStorage.removeItem(BACKGROUND_REFRESH_KEY);
|
|
290
|
+
// Note: We don't clear CACHE_VERSION_KEY - it's needed for next comparison
|
|
206
291
|
console.log('🗑️ Config cache cleared');
|
|
207
292
|
}
|
|
208
293
|
|
|
@@ -62,7 +62,9 @@ export function AppConfigProvider({
|
|
|
62
62
|
errorComponent,
|
|
63
63
|
showLoadingScreen = true,
|
|
64
64
|
showErrorScreen = true,
|
|
65
|
-
cacheDuration
|
|
65
|
+
cacheDuration,
|
|
66
|
+
versionCheck = false,
|
|
67
|
+
versionUrl
|
|
66
68
|
}) {
|
|
67
69
|
const [config, setConfig] = useState(defaultConfig);
|
|
68
70
|
const [loading, setLoading] = useState(true);
|
|
@@ -108,6 +110,8 @@ export function AppConfigProvider({
|
|
|
108
110
|
forceRefresh,
|
|
109
111
|
cacheDuration,
|
|
110
112
|
configUrl,
|
|
113
|
+
versionCheck,
|
|
114
|
+
versionUrl,
|
|
111
115
|
});
|
|
112
116
|
|
|
113
117
|
setConfig(fetchedConfig);
|
|
@@ -119,7 +123,7 @@ export function AppConfigProvider({
|
|
|
119
123
|
} finally {
|
|
120
124
|
setLoading(false);
|
|
121
125
|
}
|
|
122
|
-
}, [getApiBaseUrl, cacheDuration, configUrl]); // Removed defaultConfig from deps
|
|
126
|
+
}, [getApiBaseUrl, cacheDuration, configUrl, versionCheck, versionUrl]); // Removed defaultConfig from deps
|
|
123
127
|
|
|
124
128
|
// Load config only once on mount
|
|
125
129
|
useEffect(() => {
|
|
@@ -255,6 +259,8 @@ AppConfigProvider.propTypes = {
|
|
|
255
259
|
showLoadingScreen: PropTypes.bool,
|
|
256
260
|
showErrorScreen: PropTypes.bool,
|
|
257
261
|
cacheDuration: PropTypes.number,
|
|
262
|
+
versionCheck: PropTypes.bool,
|
|
263
|
+
versionUrl: PropTypes.string,
|
|
258
264
|
};
|
|
259
265
|
|
|
260
266
|
/**
|