tiny-essentials 1.28.0 → 1.28.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.
- package/changelog/1/28/1.md +23 -0
- package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
- package/dist/v1/TinyAfterScrollWatcher.min.js +1 -1
- package/dist/v1/TinyAnalogClock.min.js +1 -1
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyDayNightCycle.min.js +1 -1
- package/dist/v1/TinyDragDropDetector.min.js +1 -1
- package/dist/v1/TinyDragger.min.js +1 -1
- package/dist/v1/TinyElementObserver.min.js +1 -1
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyGamepad.min.js +1 -1
- package/dist/v1/TinyHtml.min.js +1 -1
- package/dist/v1/TinyI18.min.js +1 -1
- package/dist/v1/TinyIframeEvents.min.js +1 -1
- package/dist/v1/TinyLocalStorage.min.js +1 -1
- package/dist/v1/TinyMediaPlayer.min.js +1 -1
- package/dist/v1/TinyNewWinEvents.min.js +1 -1
- package/dist/v1/TinyNotifyCenter.min.js +1 -1
- package/dist/v1/TinyRadioFm.min.js +1 -1
- package/dist/v1/TinyRateLimiter.min.js +1 -1
- package/dist/v1/TinySmartScroller.min.js +1 -1
- package/dist/v1/TinyTextDiffer.min.js +1 -1
- package/dist/v1/TinyTextarea.min.js +1 -1
- package/dist/v1/TinyTimeout.min.js +1 -1
- package/dist/v1/TinyToastNotify.min.js +1 -1
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/UltraRandomMsgGen.min.js +1 -1
- package/dist/v1/basics/array.cjs +57 -9
- package/dist/v1/basics/array.d.mts +27 -11
- package/dist/v1/basics/array.mjs +51 -9
- package/dist/v1/basics/clock.cjs +94 -42
- package/dist/v1/basics/clock.d.mts +10 -10
- package/dist/v1/basics/clock.mjs +91 -54
- package/dist/v1/basics/deprecated/html.cjs +246 -0
- package/dist/v1/basics/deprecated/html.d.mts +63 -0
- package/dist/v1/basics/deprecated/html.mjs +190 -0
- package/dist/v1/basics/html.cjs +149 -130
- package/dist/v1/basics/html.d.mts +26 -61
- package/dist/v1/basics/html.mjs +113 -105
- package/dist/v1/basics/index.cjs +2 -0
- package/dist/v1/basics/index.d.mts +3 -1
- package/dist/v1/basics/index.mjs +3 -3
- package/dist/v1/basics/mediaContent.cjs +51 -9
- package/dist/v1/basics/mediaContent.d.mts +0 -87
- package/dist/v1/basics/mediaContent.mjs +40 -10
- package/dist/v1/basics/objChecker.cjs +7 -5
- package/dist/v1/basics/objChecker.d.mts +3 -2
- package/dist/v1/basics/objChecker.mjs +6 -6
- package/dist/v1/basics/objFilter.cjs +40 -7
- package/dist/v1/basics/objFilter.d.mts +6 -6
- package/dist/v1/basics/objFilter.mjs +32 -7
- package/dist/v1/basics/simpleMath.cjs +81 -25
- package/dist/v1/basics/simpleMath.d.mts +2 -2
- package/dist/v1/basics/simpleMath.mjs +70 -27
- package/dist/v1/basics/text.cjs +76 -31
- package/dist/v1/basics/text.d.mts +69 -7
- package/dist/v1/basics/text.mjs +62 -31
- package/dist/v1/index.cjs +4 -0
- package/dist/v1/index.d.mts +4 -1
- package/dist/v1/index.mjs +4 -3
- package/dist/v1/libs/TinyAdvancedRaffle.cjs +64 -50
- package/dist/v1/libs/TinyAdvancedRaffle.d.mts +4 -13
- package/dist/v1/libs/TinyAdvancedRaffle.mjs +62 -49
- package/dist/v1/libs/TinyAfterScrollWatcher.cjs +17 -1
- package/dist/v1/libs/TinyAfterScrollWatcher.d.mts +4 -1
- package/dist/v1/libs/TinyAfterScrollWatcher.mjs +15 -1
- package/dist/v1/libs/TinyAnalogClock.cjs +60 -0
- package/dist/v1/libs/TinyAnalogClock.d.mts +6 -0
- package/dist/v1/libs/TinyAnalogClock.mjs +57 -0
- package/dist/v1/libs/TinyClipboard.cjs +2 -0
- package/dist/v1/libs/TinyClipboard.d.mts +4 -2
- package/dist/v1/libs/TinyClipboard.mjs +2 -0
- package/dist/v1/libs/TinyColorConverter.cjs +1 -0
- package/dist/v1/libs/TinyColorConverter.d.mts +2 -1
- package/dist/v1/libs/TinyColorConverter.mjs +1 -0
- package/dist/v1/libs/TinyDayNightCycle.cjs +67 -42
- package/dist/v1/libs/TinyDayNightCycle.d.mts +2 -7
- package/dist/v1/libs/TinyDayNightCycle.mjs +65 -41
- package/dist/v1/libs/TinyDragDropDetector.cjs +25 -0
- package/dist/v1/libs/TinyDragDropDetector.d.mts +6 -0
- package/dist/v1/libs/TinyDragDropDetector.mjs +22 -0
- package/dist/v1/libs/TinyDragger.cjs +46 -19
- package/dist/v1/libs/TinyDragger.mjs +45 -18
- package/dist/v1/libs/TinyElementObserver.cjs +39 -0
- package/dist/v1/libs/TinyElementObserver.d.mts +6 -0
- package/dist/v1/libs/TinyElementObserver.mjs +36 -0
- package/dist/v1/libs/TinyGamepad.cjs +131 -1
- package/dist/v1/libs/TinyGamepad.mjs +129 -1
- package/dist/v1/libs/TinyHtml.cjs +1 -1
- package/dist/v1/libs/TinyHtml.mjs +2 -2
- package/dist/v1/libs/TinyI18.cjs +61 -0
- package/dist/v1/libs/TinyI18.d.mts +14 -0
- package/dist/v1/libs/TinyI18.mjs +55 -0
- package/dist/v1/libs/TinyIframeEvents.cjs +18 -1
- package/dist/v1/libs/TinyIframeEvents.mjs +18 -1
- package/dist/v1/libs/TinyLocalStorage.cjs +48 -0
- package/dist/v1/libs/TinyLocalStorage.d.mts +6 -0
- package/dist/v1/libs/TinyLocalStorage.mjs +45 -0
- package/dist/v1/libs/TinyMediaPlayer.cjs +72 -0
- package/dist/v1/libs/TinyMediaPlayer.d.mts +10 -0
- package/dist/v1/libs/TinyMediaPlayer.mjs +66 -0
- package/dist/v1/libs/TinyNewWinEvents.cjs +29 -0
- package/dist/v1/libs/TinyNewWinEvents.d.mts +6 -0
- package/dist/v1/libs/TinyNewWinEvents.mjs +26 -0
- package/dist/v1/libs/TinyNotifyCenter.cjs +36 -0
- package/dist/v1/libs/TinyNotifyCenter.d.mts +6 -0
- package/dist/v1/libs/TinyNotifyCenter.mjs +32 -0
- package/dist/v1/libs/TinyRadioFm.cjs +38 -0
- package/dist/v1/libs/TinyRadioFm.d.mts +1 -0
- package/dist/v1/libs/TinyRadioFm.mjs +35 -0
- package/dist/v1/libs/TinyRateLimiter.cjs +52 -0
- package/dist/v1/libs/TinyRateLimiter.d.mts +6 -0
- package/dist/v1/libs/TinyRateLimiter.mjs +48 -0
- package/dist/v1/libs/TinySmartScroller.cjs +52 -3
- package/dist/v1/libs/TinySmartScroller.d.mts +17 -15
- package/dist/v1/libs/TinySmartScroller.mjs +51 -5
- package/dist/v1/libs/TinyTextDiffer.cjs +19 -18
- package/dist/v1/libs/TinyTextDiffer.d.mts +1 -0
- package/dist/v1/libs/TinyTextDiffer.mjs +16 -17
- package/dist/v1/libs/TinyTextarea.cjs +19 -0
- package/dist/v1/libs/TinyTextarea.d.mts +6 -0
- package/dist/v1/libs/TinyTextarea.mjs +17 -0
- package/dist/v1/libs/TinyTimeout.cjs +11 -1
- package/dist/v1/libs/TinyTimeout.mjs +9 -1
- package/dist/v1/libs/TinyToastNotify.cjs +35 -0
- package/dist/v1/libs/TinyToastNotify.d.mts +6 -0
- package/dist/v1/libs/TinyToastNotify.mjs +31 -0
- package/dist/v1/libs/TinyUploadClicker.cjs +19 -0
- package/dist/v1/libs/TinyUploadClicker.d.mts +6 -0
- package/dist/v1/libs/TinyUploadClicker.mjs +17 -0
- package/dist/v1/libs/UltraRandomMsgGen.cjs +148 -35
- package/dist/v1/libs/UltraRandomMsgGen.d.mts +17 -3
- package/dist/v1/libs/UltraRandomMsgGen.mjs +133 -34
- package/dist/v1/libs/utils.cjs +21 -0
- package/dist/v1/libs/utils.d.mts +2 -0
- package/dist/v1/libs/utils.mjs +16 -0
- package/docs/v1/README.md +1 -0
- package/docs/v1/basics/array.md +2 -2
- package/docs/v1/basics/deprecated/html.md +17 -0
- package/docs/v1/basics/fullScreen.md +1 -1
- package/docs/v1/basics/html.md +12 -26
- package/docs/v1/basics/mediaContent.md +1 -1
- package/docs/v1/basics/objChecker.md +1 -1
- package/docs/v1/basics/text.md +2 -2
- package/docs/v1/fileManager/main.md +1 -1
- package/docs/v1/libs/ColorSafeStringify.md +1 -1
- package/docs/v1/libs/TinyAfterScrollWatcher.md +1 -1
- package/docs/v1/libs/TinyAnalogClock.md +1 -1
- package/docs/v1/libs/TinyArrayComparator.md +1 -1
- package/docs/v1/libs/TinyArrayPaginator.md +1 -1
- package/docs/v1/libs/TinyClassManager/TinyPluginInliner.md +2 -2
- package/docs/v1/libs/TinyClassManager.md +1 -1
- package/docs/v1/libs/TinyClipboard.md +1 -1
- package/docs/v1/libs/TinyCookieConsent.md +1 -1
- package/docs/v1/libs/TinyDomReadyManager.md +1 -1
- package/docs/v1/libs/TinyDragDropDetector.md +1 -1
- package/docs/v1/libs/TinyDragger.md +1 -1
- package/docs/v1/libs/TinyElementObserver.md +1 -1
- package/docs/v1/libs/TinyHtml.md +1 -1
- package/docs/v1/libs/TinyIframeEvents.md +2 -2
- package/docs/v1/libs/TinyLevelUp.md +1 -1
- package/docs/v1/libs/TinyLoadingScreen.md +1 -1
- package/docs/v1/libs/TinyNewWinEvents.md +2 -2
- package/docs/v1/libs/TinyNotifications.md +1 -1
- package/docs/v1/libs/TinyPromiseQueue.md +2 -2
- package/docs/v1/libs/TinyTextDiffer.md +1 -1
- package/docs/v1/libs/TinyTextarea.md +1 -1
- package/package.json +10 -1
package/dist/v1/basics/clock.mjs
CHANGED
|
@@ -2,31 +2,41 @@
|
|
|
2
2
|
* Calculates the time duration between the current time and a given time offset.
|
|
3
3
|
*
|
|
4
4
|
* @param {Date} timeData - The target time as a Date object.
|
|
5
|
-
* @param {
|
|
5
|
+
* @param {'asMilliseconds'|'asSeconds'|'asMinutes'|'asHours'|'asDays'} [durationType='asSeconds'] - The type of duration to return.
|
|
6
6
|
* @param {Date|null} [now=null] - The current time as a Date object. Defaults to the current date and time if not provided.
|
|
7
7
|
* @returns {number|null} The calculated duration in the specified unit, or `null` if `timeData` is not provided.
|
|
8
8
|
*/
|
|
9
9
|
export function getTimeDuration(timeData = new Date(), durationType = 'asSeconds', now = null) {
|
|
10
|
-
if (timeData instanceof Date) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
10
|
+
if (!(timeData instanceof Date)) {
|
|
11
|
+
throw new TypeError("The 'timeData' argument must be an instance of Date.");
|
|
12
|
+
}
|
|
13
|
+
if (typeof durationType !== 'string') {
|
|
14
|
+
throw new TypeError("The 'durationType' argument must be a string.");
|
|
15
|
+
}
|
|
16
|
+
const validDurationTypes = ['asMilliseconds', 'asSeconds', 'asMinutes', 'asHours', 'asDays'];
|
|
17
|
+
if (!validDurationTypes.includes(durationType)) {
|
|
18
|
+
throw new RangeError(`The 'durationType' must be one of: ${validDurationTypes.join(', ')}.`);
|
|
19
|
+
}
|
|
20
|
+
if (now !== null && !(now instanceof Date)) {
|
|
21
|
+
throw new TypeError("The 'now' argument must be an instance of Date or null.");
|
|
22
|
+
}
|
|
23
|
+
const currentTime = now instanceof Date ? now : new Date();
|
|
24
|
+
/** @type {number} */
|
|
25
|
+
const diffMs = timeData.getTime() - currentTime.getTime();
|
|
26
|
+
switch (durationType) {
|
|
27
|
+
case 'asMilliseconds':
|
|
28
|
+
return diffMs;
|
|
29
|
+
case 'asSeconds':
|
|
30
|
+
return diffMs / 1000;
|
|
31
|
+
case 'asMinutes':
|
|
32
|
+
return diffMs / (1000 * 60);
|
|
33
|
+
case 'asHours':
|
|
34
|
+
return diffMs / (1000 * 60 * 60);
|
|
35
|
+
case 'asDays':
|
|
36
|
+
return diffMs / (1000 * 60 * 60 * 24);
|
|
37
|
+
default:
|
|
38
|
+
return diffMs / 1000; // default to seconds
|
|
28
39
|
}
|
|
29
|
-
return null;
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
42
|
* Formats a custom timer string based on total seconds and a detail level.
|
|
@@ -38,8 +48,20 @@ export function getTimeDuration(timeData = new Date(), durationType = 'asSeconds
|
|
|
38
48
|
* @returns {string} The formatted timer string.
|
|
39
49
|
*/
|
|
40
50
|
export function formatCustomTimer(totalSeconds, level = 'seconds', format = '{time}') {
|
|
41
|
-
totalSeconds
|
|
51
|
+
if (typeof totalSeconds !== 'number' || Number.isNaN(totalSeconds)) {
|
|
52
|
+
throw new TypeError("The 'totalSeconds' argument must be a valid number.");
|
|
53
|
+
}
|
|
54
|
+
if (typeof level !== 'string') {
|
|
55
|
+
throw new TypeError("The 'level' argument must be a string.");
|
|
56
|
+
}
|
|
42
57
|
const levels = ['seconds', 'minutes', 'hours', 'days', 'months', 'years'];
|
|
58
|
+
if (!levels.includes(level)) {
|
|
59
|
+
throw new RangeError(`The 'level' must be one of: ${levels.join(', ')}.`);
|
|
60
|
+
}
|
|
61
|
+
if (typeof format !== 'string') {
|
|
62
|
+
throw new TypeError("The 'format' argument must be a string.");
|
|
63
|
+
}
|
|
64
|
+
totalSeconds = Math.max(0, Math.floor(totalSeconds));
|
|
43
65
|
const index = levels.indexOf(level);
|
|
44
66
|
const include = {
|
|
45
67
|
years: index >= 5,
|
|
@@ -51,13 +73,13 @@ export function formatCustomTimer(totalSeconds, level = 'seconds', format = '{ti
|
|
|
51
73
|
};
|
|
52
74
|
/**
|
|
53
75
|
* @type {{
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
76
|
+
* years: number|NaN,
|
|
77
|
+
* months: number|NaN,
|
|
78
|
+
* days: number|NaN,
|
|
79
|
+
* hours: number|NaN,
|
|
80
|
+
* minutes: number|NaN,
|
|
81
|
+
* seconds: number|NaN,
|
|
82
|
+
* total: number|NaN
|
|
61
83
|
* }}
|
|
62
84
|
*/
|
|
63
85
|
const parts = {
|
|
@@ -109,14 +131,14 @@ export function formatCustomTimer(totalSeconds, level = 'seconds', format = '{ti
|
|
|
109
131
|
parts.seconds = remaining;
|
|
110
132
|
}
|
|
111
133
|
// Calculate total
|
|
112
|
-
const totalMap = {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
};
|
|
134
|
+
/** const totalMap = {
|
|
135
|
+
seconds: include.seconds ? totalSeconds : NaN,
|
|
136
|
+
minutes: include.minutes ? totalSeconds / 60 : NaN,
|
|
137
|
+
hours: include.hours ? totalSeconds / 3600 : NaN,
|
|
138
|
+
days: include.days ? totalSeconds / 86400 : NaN,
|
|
139
|
+
months: include.months ? parts.years * 12 + parts.months + (parts.days || 0) / 30 : NaN,
|
|
140
|
+
years: include.years ? parts.years + (parts.months || 0) / 12 + (parts.days || 0) / 365 : NaN,
|
|
141
|
+
}; */
|
|
120
142
|
parts.total = +totalSeconds.toFixed(2).replace(/\.00$/, '');
|
|
121
143
|
/**
|
|
122
144
|
* Pads a number to ensure it is at least two digits long, using leading zeros if necessary.
|
|
@@ -155,6 +177,9 @@ export function formatCustomTimer(totalSeconds, level = 'seconds', format = '{ti
|
|
|
155
177
|
* @returns {string} The formatted timer string in "HH:MM:SS" format.
|
|
156
178
|
*/
|
|
157
179
|
export function formatTimer(seconds) {
|
|
180
|
+
if (typeof seconds !== 'number' || Number.isNaN(seconds)) {
|
|
181
|
+
throw new TypeError("The 'seconds' argument must be a valid number.");
|
|
182
|
+
}
|
|
158
183
|
return formatCustomTimer(seconds, 'hours', '{hours}:{minutes}:{seconds}');
|
|
159
184
|
}
|
|
160
185
|
/**
|
|
@@ -166,6 +191,9 @@ export function formatTimer(seconds) {
|
|
|
166
191
|
* @returns {string} The formatted timer string in "Xd HH:MM:SS" format.
|
|
167
192
|
*/
|
|
168
193
|
export function formatDayTimer(seconds) {
|
|
194
|
+
if (typeof seconds !== 'number' || Number.isNaN(seconds)) {
|
|
195
|
+
throw new TypeError("The 'seconds' argument must be a valid number.");
|
|
196
|
+
}
|
|
169
197
|
return formatCustomTimer(seconds, 'days', '{days}d {hours}:{minutes}:{seconds}');
|
|
170
198
|
}
|
|
171
199
|
/**
|
|
@@ -174,19 +202,28 @@ export function formatDayTimer(seconds) {
|
|
|
174
202
|
* @param {number} totalMs - The total duration in milliseconds.
|
|
175
203
|
* @param {'milliseconds'|'seconds'|'minutes'|'hours'|'days'|'months'|'years'} [level='milliseconds'] - The highest level to calculate and display.
|
|
176
204
|
* @returns {{
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
205
|
+
* years: number|NaN,
|
|
206
|
+
* months: number|NaN,
|
|
207
|
+
* days: number|NaN,
|
|
208
|
+
* hours: number|NaN,
|
|
209
|
+
* minutes: number|NaN,
|
|
210
|
+
* seconds: number|NaN,
|
|
211
|
+
* milliseconds: number|NaN,
|
|
212
|
+
* total: number|NaN
|
|
185
213
|
* }}
|
|
186
214
|
*/
|
|
187
215
|
export function breakdownDuration(totalMs, level = 'milliseconds') {
|
|
188
|
-
totalMs
|
|
216
|
+
if (typeof totalMs !== 'number' || Number.isNaN(totalMs)) {
|
|
217
|
+
throw new TypeError("The 'totalMs' argument must be a valid number.");
|
|
218
|
+
}
|
|
219
|
+
if (typeof level !== 'string') {
|
|
220
|
+
throw new TypeError("The 'level' argument must be a string.");
|
|
221
|
+
}
|
|
189
222
|
const levels = ['milliseconds', 'seconds', 'minutes', 'hours', 'days', 'months', 'years'];
|
|
223
|
+
if (!levels.includes(level)) {
|
|
224
|
+
throw new RangeError(`The 'level' must be one of: ${levels.join(', ')}.`);
|
|
225
|
+
}
|
|
226
|
+
totalMs = Math.max(0, Math.floor(totalMs));
|
|
190
227
|
const index = levels.indexOf(level);
|
|
191
228
|
const include = {
|
|
192
229
|
years: index >= 6,
|
|
@@ -251,15 +288,15 @@ export function breakdownDuration(totalMs, level = 'milliseconds') {
|
|
|
251
288
|
parts.milliseconds = remaining;
|
|
252
289
|
}
|
|
253
290
|
// Totals
|
|
254
|
-
const totalMap = {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
};
|
|
291
|
+
/** const totalMap = {
|
|
292
|
+
milliseconds: include.milliseconds ? totalMs : NaN,
|
|
293
|
+
seconds: include.seconds ? totalMs / 1000 : NaN,
|
|
294
|
+
minutes: include.minutes ? totalMs / 60000 : NaN,
|
|
295
|
+
hours: include.hours ? totalMs / 3600000 : NaN,
|
|
296
|
+
days: include.days ? totalMs / 86400000 : NaN,
|
|
297
|
+
months: include.months ? parts.years * 12 + parts.months + (parts.days || 0) / 30 : NaN,
|
|
298
|
+
years: include.years ? parts.years + (parts.months || 0) / 12 + (parts.days || 0) / 365 : NaN,
|
|
299
|
+
}; */
|
|
263
300
|
parts.total = +totalMs;
|
|
264
301
|
return parts;
|
|
265
302
|
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var html = require('../html.cjs');
|
|
4
|
+
var objChecker = require('../objChecker.cjs');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} FetchTemplateOptions
|
|
8
|
+
* @property {string} [method="GET"] - HTTP method to use (GET, POST, etc.).
|
|
9
|
+
* @property {any} [body] - Request body (only for methods like POST, PUT).
|
|
10
|
+
* @property {number} [timeout=0] - Timeout in milliseconds (ignored if signal is provided).
|
|
11
|
+
* @property {number} [retries=0] - Number of retry attempts (ignored if signal is provided).
|
|
12
|
+
* @property {Headers|Record<string, *>} [headers={}] - Additional headers.
|
|
13
|
+
* @property {AbortSignal|null} [signal] - External AbortSignal; disables timeout and retries.
|
|
14
|
+
* @property {import('../html.mjs').FetchOnProgressResult} [onProgress] - Track the load progress.
|
|
15
|
+
* @deprecated
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} url - The full URL to fetch data from.
|
|
20
|
+
* @param {FetchTemplateOptions} [options] - Optional settings.
|
|
21
|
+
* @returns {Promise<Response>} Result data.
|
|
22
|
+
* @throws {Error} Throws if fetch fails, times out.
|
|
23
|
+
*/
|
|
24
|
+
async function fetchTemplate(url, options = {}) {
|
|
25
|
+
if (options !== null && typeof options !== 'object') {
|
|
26
|
+
throw new TypeError('The "options" argument must be an object.');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
method = 'GET',
|
|
31
|
+
body,
|
|
32
|
+
timeout = 0,
|
|
33
|
+
retries = 0,
|
|
34
|
+
headers = {},
|
|
35
|
+
signal = null,
|
|
36
|
+
onProgress,
|
|
37
|
+
} = options;
|
|
38
|
+
|
|
39
|
+
if (
|
|
40
|
+
typeof url !== 'string' ||
|
|
41
|
+
(!url.startsWith('../') &&
|
|
42
|
+
!url.startsWith('./') &&
|
|
43
|
+
!url.startsWith('/') &&
|
|
44
|
+
!url.startsWith('https://') &&
|
|
45
|
+
!url.startsWith('http://'))
|
|
46
|
+
)
|
|
47
|
+
throw new Error('Invalid URL: must be a valid http or https address.');
|
|
48
|
+
|
|
49
|
+
if (typeof method !== 'string' || !method.trim())
|
|
50
|
+
throw new Error('Invalid method: must be a non-empty string.');
|
|
51
|
+
|
|
52
|
+
if (headers !== null && typeof headers !== 'object') {
|
|
53
|
+
throw new TypeError('The "headers" option must be an object.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (signal !== null && !(signal instanceof AbortSignal)) {
|
|
57
|
+
throw new TypeError('The "signal" option must be an instance of AbortSignal.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (onProgress !== undefined && typeof onProgress !== 'function') {
|
|
61
|
+
throw new TypeError('The "onProgress" option must be a function.');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!signal) {
|
|
65
|
+
if (
|
|
66
|
+
typeof timeout !== 'number' ||
|
|
67
|
+
!Number.isFinite(timeout) ||
|
|
68
|
+
Number.isNaN(timeout) ||
|
|
69
|
+
timeout < 0
|
|
70
|
+
)
|
|
71
|
+
throw new Error('Invalid timeout: must be a positive number.');
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
typeof retries !== 'number' ||
|
|
75
|
+
!Number.isFinite(retries) ||
|
|
76
|
+
Number.isNaN(retries) ||
|
|
77
|
+
retries < 0
|
|
78
|
+
)
|
|
79
|
+
throw new Error('Invalid retries: must be a positive number.');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const attempts = signal ? 1 : retries + 1;
|
|
83
|
+
/** @type {Error|null} */
|
|
84
|
+
let lastError = null;
|
|
85
|
+
|
|
86
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
87
|
+
const controller = signal ? null : new AbortController();
|
|
88
|
+
const localSignal = signal || (controller?.signal ?? null);
|
|
89
|
+
const timer =
|
|
90
|
+
!signal && timeout && controller ? setTimeout(() => controller.abort(), timeout) : null;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const response = await fetch(url, {
|
|
94
|
+
method: method.toUpperCase(),
|
|
95
|
+
headers: {
|
|
96
|
+
Accept: 'application/json',
|
|
97
|
+
...headers,
|
|
98
|
+
},
|
|
99
|
+
body: body !== undefined ? (objChecker.isJsonObject(body) ? JSON.stringify(body) : body) : undefined,
|
|
100
|
+
signal: localSignal,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (timer) clearTimeout(timer);
|
|
104
|
+
|
|
105
|
+
if (!response.ok) throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
106
|
+
|
|
107
|
+
// If onProgress is not provided or body is null, return original response
|
|
108
|
+
if (!onProgress) return response;
|
|
109
|
+
return html.trackFetchProgress(response, onProgress);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
lastError = /** @type {Error} */ (err);
|
|
112
|
+
if (signal) break; // if an external signal came, it does not retry
|
|
113
|
+
if (attempt < retries)
|
|
114
|
+
await new Promise((resolve) => setTimeout(resolve, 300 * (attempt + 1)));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Failed to fetch JSON from "${url}"${lastError ? `: ${lastError.message}` : '.'}`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Loads and parses a JSON from a remote URL using Fetch API.
|
|
125
|
+
*
|
|
126
|
+
* @param {string} url - The full URL to fetch JSON from.
|
|
127
|
+
* @param {FetchTemplateOptions} [options] - Optional settings.
|
|
128
|
+
* @returns {Promise<any[] | Record<string | number | symbol, unknown>>} Parsed JSON object.
|
|
129
|
+
* @throws {Error} Throws if fetch fails, times out, or returns invalid JSON.
|
|
130
|
+
* @deprecated
|
|
131
|
+
*/
|
|
132
|
+
async function fetchJson(url, options) {
|
|
133
|
+
if (typeof url !== 'string') {
|
|
134
|
+
return Promise.reject(new TypeError('The "url" argument must be a string.'));
|
|
135
|
+
}
|
|
136
|
+
if (options !== undefined && (options === null || typeof options !== 'object')) {
|
|
137
|
+
return Promise.reject(new TypeError('The "options" argument must be an object.'));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
fetchTemplate(url, options)
|
|
142
|
+
.then(async (res) => {
|
|
143
|
+
const contentType = res.headers.get('content-type') || '';
|
|
144
|
+
if (!contentType.includes('application/json'))
|
|
145
|
+
throw new Error(`Unexpected content-type: ${contentType}`);
|
|
146
|
+
|
|
147
|
+
const data = await res.json();
|
|
148
|
+
|
|
149
|
+
if (!Array.isArray(data) && !objChecker.isJsonObject(data))
|
|
150
|
+
throw new Error('Received invalid data instead of valid JSON.');
|
|
151
|
+
|
|
152
|
+
return resolve(data);
|
|
153
|
+
})
|
|
154
|
+
.catch(reject);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Loads a remote file as a Blob using Fetch API.
|
|
160
|
+
*
|
|
161
|
+
* @param {string} url - The full URL to fetch the file from.
|
|
162
|
+
* @param {string[]} [allowedMimeTypes] - Optional list of accepted MIME types (e.g., ['image/jpeg']).
|
|
163
|
+
* @param {FetchTemplateOptions} [options] - Optional fetch options.
|
|
164
|
+
* @returns {Promise<Blob>} - The fetched file as a Blob.
|
|
165
|
+
* @throws {Error} Throws if fetch fails, response is not ok, or MIME type is not allowed.
|
|
166
|
+
* @deprecated
|
|
167
|
+
*/
|
|
168
|
+
async function fetchBlob(url, allowedMimeTypes, options) {
|
|
169
|
+
if (typeof url !== 'string') {
|
|
170
|
+
return Promise.reject(new TypeError('The "url" argument must be a string.'));
|
|
171
|
+
}
|
|
172
|
+
if (allowedMimeTypes !== undefined && !Array.isArray(allowedMimeTypes)) {
|
|
173
|
+
return Promise.reject(
|
|
174
|
+
new TypeError('The "allowedMimeTypes" argument must be an array of strings.'),
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
if (options !== undefined && (options === null || typeof options !== 'object')) {
|
|
178
|
+
return Promise.reject(new TypeError('The "options" argument must be an object.'));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return new Promise((resolve, reject) => {
|
|
182
|
+
fetchTemplate(url, options)
|
|
183
|
+
.then(async (res) => {
|
|
184
|
+
const contentType = res.headers.get('content-type') || '';
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
Array.isArray(allowedMimeTypes) &&
|
|
188
|
+
allowedMimeTypes.length > 0 &&
|
|
189
|
+
!allowedMimeTypes.some((type) => contentType.includes(type))
|
|
190
|
+
) {
|
|
191
|
+
throw new Error(`Blocked MIME type: ${contentType}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const data = await res.blob();
|
|
195
|
+
return resolve(data);
|
|
196
|
+
})
|
|
197
|
+
.catch(reject);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Loads a remote file as a text using Fetch API.
|
|
203
|
+
*
|
|
204
|
+
* @param {string} url - The full URL to fetch the file from.
|
|
205
|
+
* @param {string[]} [allowedMimeTypes] - Optional list of accepted MIME types (e.g., ['image/jpeg']).
|
|
206
|
+
* @param {FetchTemplateOptions} [options] - Optional fetch options.
|
|
207
|
+
* @returns {Promise<string>} - The fetched file as a text.
|
|
208
|
+
* @throws {Error} Throws if fetch fails, response is not ok, or MIME type is not allowed.
|
|
209
|
+
* @deprecated
|
|
210
|
+
*/
|
|
211
|
+
async function fetchText(url, allowedMimeTypes, options) {
|
|
212
|
+
if (typeof url !== 'string') {
|
|
213
|
+
return Promise.reject(new TypeError('The "url" argument must be a string.'));
|
|
214
|
+
}
|
|
215
|
+
if (allowedMimeTypes !== undefined && !Array.isArray(allowedMimeTypes)) {
|
|
216
|
+
return Promise.reject(
|
|
217
|
+
new TypeError('The "allowedMimeTypes" argument must be an array of strings.'),
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
if (options !== undefined && (options === null || typeof options !== 'object')) {
|
|
221
|
+
return Promise.reject(new TypeError('The "options" argument must be an object.'));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return new Promise((resolve, reject) => {
|
|
225
|
+
fetchTemplate(url, options)
|
|
226
|
+
.then(async (res) => {
|
|
227
|
+
const contentType = res.headers.get('content-type') || '';
|
|
228
|
+
|
|
229
|
+
if (
|
|
230
|
+
Array.isArray(allowedMimeTypes) &&
|
|
231
|
+
allowedMimeTypes.length > 0 &&
|
|
232
|
+
!allowedMimeTypes.some((type) => contentType.includes(type))
|
|
233
|
+
) {
|
|
234
|
+
throw new Error(`Blocked MIME type: ${contentType}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const data = await res.text();
|
|
238
|
+
return resolve(data);
|
|
239
|
+
})
|
|
240
|
+
.catch(reject);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
exports.fetchBlob = fetchBlob;
|
|
245
|
+
exports.fetchJson = fetchJson;
|
|
246
|
+
exports.fetchText = fetchText;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads and parses a JSON from a remote URL using Fetch API.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} url - The full URL to fetch JSON from.
|
|
5
|
+
* @param {FetchTemplateOptions} [options] - Optional settings.
|
|
6
|
+
* @returns {Promise<any[] | Record<string | number | symbol, unknown>>} Parsed JSON object.
|
|
7
|
+
* @throws {Error} Throws if fetch fails, times out, or returns invalid JSON.
|
|
8
|
+
* @deprecated
|
|
9
|
+
*/
|
|
10
|
+
export function fetchJson(url: string, options?: FetchTemplateOptions): Promise<any[] | Record<string | number | symbol, unknown>>;
|
|
11
|
+
/**
|
|
12
|
+
* Loads a remote file as a Blob using Fetch API.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} url - The full URL to fetch the file from.
|
|
15
|
+
* @param {string[]} [allowedMimeTypes] - Optional list of accepted MIME types (e.g., ['image/jpeg']).
|
|
16
|
+
* @param {FetchTemplateOptions} [options] - Optional fetch options.
|
|
17
|
+
* @returns {Promise<Blob>} - The fetched file as a Blob.
|
|
18
|
+
* @throws {Error} Throws if fetch fails, response is not ok, or MIME type is not allowed.
|
|
19
|
+
* @deprecated
|
|
20
|
+
*/
|
|
21
|
+
export function fetchBlob(url: string, allowedMimeTypes?: string[], options?: FetchTemplateOptions): Promise<Blob>;
|
|
22
|
+
/**
|
|
23
|
+
* Loads a remote file as a text using Fetch API.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} url - The full URL to fetch the file from.
|
|
26
|
+
* @param {string[]} [allowedMimeTypes] - Optional list of accepted MIME types (e.g., ['image/jpeg']).
|
|
27
|
+
* @param {FetchTemplateOptions} [options] - Optional fetch options.
|
|
28
|
+
* @returns {Promise<string>} - The fetched file as a text.
|
|
29
|
+
* @throws {Error} Throws if fetch fails, response is not ok, or MIME type is not allowed.
|
|
30
|
+
* @deprecated
|
|
31
|
+
*/
|
|
32
|
+
export function fetchText(url: string, allowedMimeTypes?: string[], options?: FetchTemplateOptions): Promise<string>;
|
|
33
|
+
export type FetchTemplateOptions = {
|
|
34
|
+
/**
|
|
35
|
+
* - HTTP method to use (GET, POST, etc.).
|
|
36
|
+
*/
|
|
37
|
+
method?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* - Request body (only for methods like POST, PUT).
|
|
40
|
+
*/
|
|
41
|
+
body?: any;
|
|
42
|
+
/**
|
|
43
|
+
* - Timeout in milliseconds (ignored if signal is provided).
|
|
44
|
+
*/
|
|
45
|
+
timeout?: number | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* - Number of retry attempts (ignored if signal is provided).
|
|
48
|
+
*/
|
|
49
|
+
retries?: number | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* - Additional headers.
|
|
52
|
+
*/
|
|
53
|
+
headers?: Headers | Record<string, any> | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* - External AbortSignal; disables timeout and retries.
|
|
56
|
+
*/
|
|
57
|
+
signal?: AbortSignal | null | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* - Track the load progress.
|
|
60
|
+
*/
|
|
61
|
+
onProgress?: import("../html.mjs").FetchOnProgressResult | undefined;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=html.d.mts.map
|