@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.0",
5
+ "version": "1.2.1",
6
6
  "type": "module",
7
7
  "description": "Fetch content from contentstorage and generate TypeScript types",
8
8
  "license": "MIT",