@contentstorage/core 1.2.0 → 1.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.
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { CONTENTSTORAGE_CONFIG } from '../../contentstorage-config.js';
|
|
3
3
|
import { appConfig, setContentLanguage } from '../contentManagement.js';
|
|
4
|
+
// Map of request keys to their debounce timers
|
|
5
|
+
const debounceTimers = new Map();
|
|
6
|
+
// Map of request keys to their cancel token sources
|
|
7
|
+
const cancelTokenSources = new Map();
|
|
8
|
+
// Fixed debounce delay in milliseconds
|
|
9
|
+
const DEBOUNCE_MS = 200;
|
|
4
10
|
export async function fetchContent(language, options = {}) {
|
|
5
11
|
const { withPendingChanges, contentKey } = options;
|
|
6
12
|
const languageToFetch = language || appConfig?.languageCodes?.[0];
|
|
@@ -23,12 +29,82 @@ export async function fetchContent(language, options = {}) {
|
|
|
23
29
|
requestConfig.headers = {
|
|
24
30
|
'X-Content-Key': effectiveContentKey,
|
|
25
31
|
};
|
|
32
|
+
// Apply debouncing and cancellation only for pending-changes API endpoint
|
|
33
|
+
const requestKey = `${languageToFetch}:${effectiveContentKey}`;
|
|
34
|
+
// Cancel any existing in-flight request for the same parameters
|
|
35
|
+
const existingCancelSource = cancelTokenSources.get(requestKey);
|
|
36
|
+
if (existingCancelSource) {
|
|
37
|
+
existingCancelSource.cancel('Request cancelled due to new request');
|
|
38
|
+
cancelTokenSources.delete(requestKey);
|
|
39
|
+
}
|
|
40
|
+
// Clear any existing debounce timer for the same parameters
|
|
41
|
+
const existingTimer = debounceTimers.get(requestKey);
|
|
42
|
+
if (existingTimer) {
|
|
43
|
+
clearTimeout(existingTimer);
|
|
44
|
+
debounceTimers.delete(requestKey);
|
|
45
|
+
}
|
|
46
|
+
// Return a promise that will resolve after debouncing
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const timer = setTimeout(async () => {
|
|
49
|
+
debounceTimers.delete(requestKey);
|
|
50
|
+
// Create a cancel token for this request
|
|
51
|
+
const cancelTokenSource = axios.CancelToken.source();
|
|
52
|
+
requestConfig.cancelToken = cancelTokenSource.token;
|
|
53
|
+
cancelTokenSources.set(requestKey, cancelTokenSource);
|
|
54
|
+
try {
|
|
55
|
+
// Fetch data for the current language
|
|
56
|
+
const response = await axios.get(fileUrl, requestConfig);
|
|
57
|
+
let jsonData = response.data;
|
|
58
|
+
// Handle API response structure - only for pending changes API
|
|
59
|
+
if (jsonData && typeof jsonData === 'object' && 'data' in jsonData) {
|
|
60
|
+
jsonData = jsonData.data;
|
|
61
|
+
}
|
|
62
|
+
if (jsonData === undefined || jsonData === null) {
|
|
63
|
+
throw new Error(`No data received from ${fileUrl} for language ${languageToFetch}.`);
|
|
64
|
+
}
|
|
65
|
+
// Validate that jsonData is a single, non-null JSON object (not an array)
|
|
66
|
+
if (typeof jsonData !== 'object') {
|
|
67
|
+
throw new Error(`Expected a single JSON object from ${fileUrl} for language ${languageToFetch}, but received type ${typeof jsonData}. Cannot proceed.`);
|
|
68
|
+
}
|
|
69
|
+
console.log(`Received JSON for ${languageToFetch}`);
|
|
70
|
+
setContentLanguage({
|
|
71
|
+
languageCode: languageToFetch,
|
|
72
|
+
contentJson: jsonData,
|
|
73
|
+
});
|
|
74
|
+
// Clean up cancel token source
|
|
75
|
+
cancelTokenSources.delete(requestKey);
|
|
76
|
+
resolve();
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
// Clean up cancel token source
|
|
80
|
+
cancelTokenSources.delete(requestKey);
|
|
81
|
+
// Don't log cancelled requests as errors
|
|
82
|
+
if (axios.isCancel(error)) {
|
|
83
|
+
console.log(`Request cancelled for language ${languageToFetch}`);
|
|
84
|
+
resolve();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Catch errors related to fetching or saving a single language file
|
|
88
|
+
console.error(`\nError processing language ${languageToFetch} from ${fileUrl}:`);
|
|
89
|
+
if (axios.isAxiosError(error)) {
|
|
90
|
+
console.error(` Status: ${error.response?.status}`);
|
|
91
|
+
console.error(`Response Data: ${error.response?.data ? JSON.stringify(error.response.data) : 'N/A'}`);
|
|
92
|
+
console.error(` Message: ${error.message}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.error(` Error: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
reject(error);
|
|
98
|
+
}
|
|
99
|
+
}, DEBOUNCE_MS);
|
|
100
|
+
debounceTimers.set(requestKey, timer);
|
|
101
|
+
});
|
|
26
102
|
}
|
|
27
103
|
else {
|
|
28
104
|
fileUrl = `${CONTENTSTORAGE_CONFIG.BASE_URL}/${effectiveContentKey}/content/${languageToFetch}.json`;
|
|
29
105
|
}
|
|
30
106
|
try {
|
|
31
|
-
// Fetch data for the current language
|
|
107
|
+
// Fetch data for the current language (CDN endpoint - no debouncing)
|
|
32
108
|
const response = await axios.get(fileUrl, requestConfig);
|
|
33
109
|
let jsonData = response.data;
|
|
34
110
|
// Handle API response structure - only for pending changes API
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@contentstorage/core",
|
|
3
3
|
"author": "Kaido Hussar <kaidohus@gmail.com>",
|
|
4
4
|
"homepage": "https://contentstorage.app",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"description": "Fetch content from contentstorage and generate TypeScript types",
|
|
8
8
|
"license": "MIT",
|