grab-url 1.0.7 → 1.0.8
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/dist/download.cjs.js +3 -0
- package/dist/download.cjs.js.map +1 -0
- package/dist/download.d.ts +1 -0
- package/dist/download.es.js +3715 -0
- package/dist/download.es.js.map +1 -0
- package/dist/grab-api.cjs.js +1 -1
- package/dist/grab-api.cjs.js.map +1 -1
- package/dist/grab-api.d.ts +63 -54
- package/dist/grab-api.es.js +244 -354
- package/dist/grab-api.es.js.map +1 -1
- package/dist/grab-api.umd.js +2 -0
- package/dist/grab-api.umd.js.map +1 -0
- package/dist/icons.cjs.js +1 -1
- package/dist/icons.cjs.js.map +1 -1
- package/dist/icons.es.js +3 -3
- package/dist/icons.es.js.map +1 -1
- package/dist/log.cjs.js +2 -0
- package/dist/log.cjs.js.map +1 -0
- package/dist/log.d.ts +123 -0
- package/dist/log.es.js +299 -0
- package/dist/log.es.js.map +1 -0
- package/package.json +17 -13
- package/readme.md +7 -7
- package/src/grab-api.ts +150 -112
- package/src/grab-url.js +9 -40
- package/src/icons/cli/spinners.js +818 -0
- package/src/{log.ts → log-json.ts} +128 -129
- package/src/icons/cli/spinners.json +0 -1074
package/dist/grab-api.es.js
CHANGED
|
@@ -1,180 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
style = "color: #66ccff; font-size: 10pt;",
|
|
5
|
-
hideInProduction = void 0,
|
|
6
|
-
startSpinner = false,
|
|
7
|
-
stopSpinner = false
|
|
8
|
-
} = options;
|
|
9
|
-
if (typeof hideInProduction === "undefined")
|
|
10
|
-
hideInProduction = typeof window !== "undefined" && (window == null ? void 0 : window.location.hostname.includes("localhost"));
|
|
11
|
-
if (typeof message === "object")
|
|
12
|
-
message = printJSONStructure(message) + "\n\n" + JSON.stringify(message, null, 2);
|
|
13
|
-
if (color && typeof process !== void 0)
|
|
14
|
-
message = (colors[color] || "") + message + colors.reset;
|
|
15
|
-
var i = 0;
|
|
16
|
-
if (startSpinner)
|
|
17
|
-
(global || globalThis).interval = setInterval(() => {
|
|
18
|
-
process.stdout.write(
|
|
19
|
-
(colors[color] || "") + "\r" + "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏".split("")[i = ++i % 10] + " " + message + colors.reset
|
|
20
|
-
);
|
|
21
|
-
}, 50);
|
|
22
|
-
else if (stopSpinner) {
|
|
23
|
-
clearInterval((global || globalThis).interval);
|
|
24
|
-
process.stdout.write(
|
|
25
|
-
"\r" + (message || "✔ Done") + " ".repeat(message.length + 20) + "\n"
|
|
26
|
-
);
|
|
27
|
-
} else if (typeof style === "string") {
|
|
28
|
-
if (style.split(" ").length == 1 || color) {
|
|
29
|
-
style = `color: ${color || style}; font-size: 11pt;`;
|
|
30
|
-
} else {
|
|
31
|
-
if (style.match(/^#[0-9a-fA-F]{6}$/)) {
|
|
32
|
-
style = `color: ${style}; font-size: 11pt;`;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
if (hideInProduction)
|
|
36
|
-
console.debug((style ? "%c" : "") + (message || ""), style);
|
|
37
|
-
else console.log((style ? "%c" : "") + (message || ""), style);
|
|
38
|
-
} else if (typeof style === "object") console.log(message, ...style);
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
const colors = {
|
|
42
|
-
reset: "\x1B[0m",
|
|
43
|
-
// Reset to default color
|
|
44
|
-
black: "\x1B[30m",
|
|
45
|
-
red: "\x1B[31m",
|
|
46
|
-
// Functions, errors
|
|
47
|
-
green: "\x1B[32m",
|
|
48
|
-
// Object braces, success
|
|
49
|
-
yellow: "\x1B[33m",
|
|
50
|
-
// Strings, warnings
|
|
51
|
-
blue: "\x1B[34m",
|
|
52
|
-
// Array brackets, info
|
|
53
|
-
magenta: "\x1B[35m",
|
|
54
|
-
// Booleans
|
|
55
|
-
cyan: "\x1B[36m",
|
|
56
|
-
// Numbers
|
|
57
|
-
white: "\x1B[37m",
|
|
58
|
-
// Default color, plain text
|
|
59
|
-
gray: "\x1B[90m",
|
|
60
|
-
// Null, undefined, subtle
|
|
61
|
-
// Bright variants
|
|
62
|
-
brightRed: "\x1B[91m",
|
|
63
|
-
brightGreen: "\x1B[92m",
|
|
64
|
-
brightYellow: "\x1B[93m",
|
|
65
|
-
brightBlue: "\x1B[94m",
|
|
66
|
-
brightMagenta: "\x1B[95m",
|
|
67
|
-
brightCyan: "\x1B[96m",
|
|
68
|
-
brightWhite: "\x1B[97m",
|
|
69
|
-
// Background colors (optional)
|
|
70
|
-
bgRed: "\x1B[41m",
|
|
71
|
-
bgGreen: "\x1B[42m",
|
|
72
|
-
bgYellow: "\x1B[43m",
|
|
73
|
-
bgBlue: "\x1B[44m",
|
|
74
|
-
bgMagenta: "\x1B[45m",
|
|
75
|
-
bgCyan: "\x1B[46m",
|
|
76
|
-
bgWhite: "\x1B[47m",
|
|
77
|
-
bgGray: "\x1B[100m"
|
|
78
|
-
};
|
|
79
|
-
function getColorForType(value) {
|
|
80
|
-
if (typeof value === "string") return colors.yellow;
|
|
81
|
-
if (typeof value === "number") return colors.cyan;
|
|
82
|
-
if (typeof value === "boolean") return colors.magenta;
|
|
83
|
-
if (typeof value === "function") return colors.red;
|
|
84
|
-
if (value === null) return colors.gray;
|
|
85
|
-
if (Array.isArray(value)) return colors.blue;
|
|
86
|
-
if (typeof value === "object") return colors.green;
|
|
87
|
-
return colors.white;
|
|
88
|
-
}
|
|
89
|
-
function getTypeString(value) {
|
|
90
|
-
if (typeof value === "string") return '""';
|
|
91
|
-
if (typeof value === "number") return "number";
|
|
92
|
-
if (typeof value === "boolean") return "bool";
|
|
93
|
-
if (typeof value === "function") return "function";
|
|
94
|
-
if (value === null) return "null";
|
|
95
|
-
if (Array.isArray(value)) {
|
|
96
|
-
if (value.length) return "[" + getTypeString(value[0]) + "]";
|
|
97
|
-
else return "[]";
|
|
98
|
-
}
|
|
99
|
-
if (typeof value === "object") return "{...}";
|
|
100
|
-
return typeof value;
|
|
101
|
-
}
|
|
102
|
-
function printJSONStructure(obj, indent = 0) {
|
|
103
|
-
const pad = " ".repeat(indent);
|
|
104
|
-
if (typeof obj !== "object" || obj === null) {
|
|
105
|
-
const color = getColorForType(obj);
|
|
106
|
-
return color + getTypeString(obj) + colors.reset;
|
|
107
|
-
}
|
|
108
|
-
if (Array.isArray(obj)) {
|
|
109
|
-
let result2 = colors.blue + "[" + colors.reset;
|
|
110
|
-
if (obj.length) result2 += "\n";
|
|
111
|
-
obj.forEach((item, idx) => {
|
|
112
|
-
result2 += pad + " " + printJSONStructure(item, indent + 1);
|
|
113
|
-
if (idx < obj.length - 1) result2 += ",";
|
|
114
|
-
result2 += "\n";
|
|
115
|
-
});
|
|
116
|
-
result2 += pad + colors.blue + "]" + colors.reset;
|
|
117
|
-
return result2;
|
|
118
|
-
}
|
|
119
|
-
let result = colors.green + "{" + colors.reset;
|
|
120
|
-
const keys = Object.keys(obj);
|
|
121
|
-
if (keys.length) result += "\n";
|
|
122
|
-
keys.forEach((key, index) => {
|
|
123
|
-
const value = obj[key];
|
|
124
|
-
const color = getColorForType(value);
|
|
125
|
-
result += pad + " ";
|
|
126
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
127
|
-
result += color + key + colors.reset + ": " + printJSONStructure(value, indent + 1);
|
|
128
|
-
} else if (Array.isArray(value)) {
|
|
129
|
-
result += color + key + colors.reset + ": " + printJSONStructure(value, indent + 1);
|
|
130
|
-
} else {
|
|
131
|
-
result += color + key + ": " + getTypeString(value) + colors.reset;
|
|
132
|
-
}
|
|
133
|
-
if (index < keys.length - 1) result += ",";
|
|
134
|
-
result += "\n";
|
|
135
|
-
});
|
|
136
|
-
result += pad + colors.green + "}" + colors.reset;
|
|
137
|
-
return result;
|
|
138
|
-
}
|
|
139
|
-
function showAlert(msg) {
|
|
140
|
-
if (typeof document === "undefined") return;
|
|
141
|
-
let o = document.getElementById("alert-overlay"), list;
|
|
142
|
-
if (!o) {
|
|
143
|
-
o = document.body.appendChild(document.createElement("div"));
|
|
144
|
-
o.id = "alert-overlay";
|
|
145
|
-
o.setAttribute(
|
|
146
|
-
"style",
|
|
147
|
-
"position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center"
|
|
148
|
-
);
|
|
149
|
-
o.innerHTML = `<div id="alert-box" style="background:#fff;padding:1.5em 2em;border-radius:8px;box-shadow:0 2px 16px #0003;min-width:220px;max-height:80vh;position:relative;display:flex;flex-direction:column;">
|
|
150
|
-
<button id="close-alert" style="position:absolute;top:12px;right:20px;font-size:1.5em;background:none;border:none;cursor:pointer;color:black;">×</button>
|
|
151
|
-
<div id="alert-list" style="overflow:auto;flex:1;"></div>
|
|
152
|
-
</div>`;
|
|
153
|
-
o.addEventListener("click", (e) => e.target == o && o.remove());
|
|
154
|
-
document.getElementById("close-alert").onclick = () => o.remove();
|
|
155
|
-
}
|
|
156
|
-
list = o.querySelector("#alert-list");
|
|
157
|
-
list.innerHTML += `<div style="border-bottom:1px solid #333; font-size:1.2em;margin:0.5em 0;">${msg}</div>`;
|
|
158
|
-
}
|
|
159
|
-
function setupDevTools() {
|
|
160
|
-
document.addEventListener("keydown", (e) => {
|
|
161
|
-
if (e.key === "i" && e.ctrlKey) {
|
|
162
|
-
let html = " ";
|
|
163
|
-
for (let request of grab.log) {
|
|
164
|
-
html += `<div style="margin-bottom:1em; border-bottom:1px solid #ccc; padding-bottom:1em;">
|
|
165
|
-
<b>Path:</b> ${request.path}<br>
|
|
166
|
-
<b>Request:</b> ${request.request}<br>
|
|
167
|
-
<b>Response:</b> ${JSON.stringify(request.response, null, 2)}<br>
|
|
168
|
-
<b>Time:</b> ${new Date(request.lastFetchTime).toLocaleString()}
|
|
169
|
-
</div>`;
|
|
170
|
-
}
|
|
171
|
-
showAlert(html);
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
async function grab$1(path, options) {
|
|
176
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
177
|
-
let {
|
|
1
|
+
import { log, printJSONStructure } from "./log.es.js";
|
|
2
|
+
async function grab(path, options) {
|
|
3
|
+
var {
|
|
178
4
|
headers,
|
|
179
5
|
response = {},
|
|
180
6
|
// Pre-initialized object to set the response in. isLoading and error are also set on this object.
|
|
@@ -232,191 +58,218 @@ async function grab$1(path, options) {
|
|
|
232
58
|
// All other params become request params/query
|
|
233
59
|
} = {
|
|
234
60
|
// Destructure options with defaults, merging with any globally set defaults
|
|
235
|
-
...typeof window !== "undefined" ?
|
|
61
|
+
...typeof window !== "undefined" ? window?.grab?.defaults : (global || globalThis)?.grab?.defaults || {},
|
|
236
62
|
...options
|
|
237
63
|
};
|
|
238
64
|
let s = (t) => path.startsWith(t);
|
|
239
65
|
if (s("http:") || s("https:")) baseURL = "";
|
|
240
66
|
else if (!s("/") && !baseURL.endsWith("/")) path = "/" + path;
|
|
241
67
|
else if (s("/") && baseURL.endsWith("/")) path = path.slice(1);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
await
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
68
|
+
try {
|
|
69
|
+
if (debounce > 0)
|
|
70
|
+
return await debouncer(async () => {
|
|
71
|
+
await grab(path, { ...options, debounce: 0 });
|
|
72
|
+
}, debounce * 1e3);
|
|
73
|
+
if (repeat > 1) {
|
|
74
|
+
for (let i = 0; i < repeat; i++) {
|
|
75
|
+
await grab(path, { ...options, repeat: 0 });
|
|
76
|
+
}
|
|
77
|
+
return response;
|
|
249
78
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}, repeatEvery * 1e3);
|
|
256
|
-
return response;
|
|
257
|
-
}
|
|
258
|
-
if (options == null ? void 0 : options.setDefaults) {
|
|
259
|
-
if (typeof window !== "undefined")
|
|
260
|
-
window.grab.defaults = { ...options, setDefaults: void 0 };
|
|
261
|
-
else if (typeof (global || globalThis).grab !== "undefined")
|
|
262
|
-
(global || globalThis).grab.defaults = {
|
|
263
|
-
...options,
|
|
264
|
-
setDefaults: void 0
|
|
265
|
-
};
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
if (typeof window !== void 0) {
|
|
269
|
-
const regrab = async () => await grab$1(path, { ...options, cache: false });
|
|
270
|
-
if (regrabOnStale && cache) setTimeout(regrab, 1e3 * cacheForTime);
|
|
271
|
-
if (regrabOnNetwork) window.addEventListener("online", regrab);
|
|
272
|
-
if (regrabOnFocus) {
|
|
273
|
-
window.addEventListener("focus", regrab);
|
|
274
|
-
document.addEventListener("visibilitychange", async () => {
|
|
275
|
-
if (document.visibilityState === "visible") await regrab();
|
|
276
|
-
});
|
|
79
|
+
if (repeatEvery) {
|
|
80
|
+
setInterval(async () => {
|
|
81
|
+
await grab(path, { ...options, repeat: 0, repeatEvery: null });
|
|
82
|
+
}, repeatEvery * 1e3);
|
|
83
|
+
return response;
|
|
277
84
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
let paginateDOM = typeof paginateElement === "string" ? document.querySelector(paginateElement) : paginateElement;
|
|
284
|
-
if (!paginateDOM) log("paginateDOM not found", { color: "red" });
|
|
285
|
-
if (window.scrollListener)
|
|
286
|
-
paginateDOM.removeEventListener("scroll", window.scrollListener);
|
|
287
|
-
window.scrollListener = async (event) => {
|
|
288
|
-
const t = event.target;
|
|
289
|
-
localStorage.setItem(
|
|
290
|
-
"scroll",
|
|
291
|
-
JSON.stringify([t.scrollTop, t.scrollLeft, paginateElement])
|
|
292
|
-
);
|
|
293
|
-
if (t.scrollHeight - t.scrollTop <= t.clientHeight + 200) {
|
|
294
|
-
await grab$1(path, {
|
|
85
|
+
if (options?.setDefaults) {
|
|
86
|
+
if (typeof window !== "undefined")
|
|
87
|
+
window.grab.defaults = { ...options, setDefaults: void 0 };
|
|
88
|
+
else if (typeof (global || globalThis).grab !== "undefined")
|
|
89
|
+
(global || globalThis).grab.defaults = {
|
|
295
90
|
...options,
|
|
296
|
-
|
|
297
|
-
|
|
91
|
+
setDefaults: void 0
|
|
92
|
+
};
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (typeof window !== "undefined") {
|
|
96
|
+
const regrab = async () => await grab(path, { ...options, cache: false });
|
|
97
|
+
if (regrabOnStale && cache) setTimeout(regrab, 1e3 * cacheForTime);
|
|
98
|
+
if (regrabOnNetwork) window.addEventListener("online", regrab);
|
|
99
|
+
if (regrabOnFocus) {
|
|
100
|
+
window.addEventListener("focus", regrab);
|
|
101
|
+
document.addEventListener("visibilitychange", async () => {
|
|
102
|
+
if (document.visibilityState === "visible") await regrab();
|
|
298
103
|
});
|
|
299
104
|
}
|
|
300
|
-
};
|
|
301
|
-
if (paginateDOM)
|
|
302
|
-
paginateDOM.addEventListener("scroll", window.scrollListener);
|
|
303
|
-
}
|
|
304
|
-
let paramsAsText = JSON.stringify(
|
|
305
|
-
paginateKey ? { ...params, [paginateKey]: void 0 } : params
|
|
306
|
-
);
|
|
307
|
-
let priorRequest = (_d = grab$1 == null ? void 0 : grab$1.log) == null ? void 0 : _d.find(
|
|
308
|
-
(e) => e.request == paramsAsText && e.path == path
|
|
309
|
-
);
|
|
310
|
-
if (!paginateKey) {
|
|
311
|
-
for (let key of Object.keys(response)) response[key] = void 0;
|
|
312
|
-
if (cache && (!cacheForTime || (priorRequest == null ? void 0 : priorRequest.lastFetchTime) > Date.now() - 1e3 * cacheForTime)) {
|
|
313
|
-
for (let key of Object.keys(priorRequest.res))
|
|
314
|
-
response[key] = priorRequest.res[key];
|
|
315
|
-
if (resFunction) response = resFunction(response);
|
|
316
105
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
106
|
+
let resFunction = typeof response === "function" ? response : null;
|
|
107
|
+
if (!response || resFunction) response = {};
|
|
108
|
+
var [paginateKey, paginateResult, paginateElement] = infiniteScroll || [];
|
|
109
|
+
if (infiniteScroll?.length && typeof paginateElement !== "undefined" && typeof window !== "undefined") {
|
|
110
|
+
let paginateDOM = typeof paginateElement === "string" ? document.querySelector(paginateElement) : paginateElement;
|
|
111
|
+
if (!paginateDOM) log("paginateDOM not found", { color: "red" });
|
|
112
|
+
else if (window.scrollListener && typeof paginateDOM !== "undefined" && typeof paginateDOM.removeEventListener === "function")
|
|
113
|
+
paginateDOM.removeEventListener("scroll", window.scrollListener);
|
|
114
|
+
window.scrollListener = async (event) => {
|
|
115
|
+
const t = event.target;
|
|
116
|
+
localStorage.setItem(
|
|
117
|
+
"scroll",
|
|
118
|
+
JSON.stringify([t.scrollTop, t.scrollLeft, paginateElement])
|
|
119
|
+
);
|
|
120
|
+
if (t.scrollHeight - t.scrollTop <= t.clientHeight + 200) {
|
|
121
|
+
await grab(path, {
|
|
122
|
+
...options,
|
|
123
|
+
cache: false,
|
|
124
|
+
[paginateKey]: priorRequest?.currentPage + 1
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
if (paginateDOM)
|
|
129
|
+
paginateDOM.addEventListener("scroll", window.scrollListener);
|
|
322
130
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
if (resFunction) resFunction({ isLoading: true });
|
|
327
|
-
else if (typeof response === "object") response.isLoading = true;
|
|
328
|
-
if (resFunction) response = resFunction(response);
|
|
329
|
-
if (rateLimit > 0 && (priorRequest == null ? void 0 : priorRequest.lastFetchTime) && priorRequest.lastFetchTime > Date.now() - 1e3 * rateLimit)
|
|
330
|
-
throw new Error(`Fetch rate limit exceeded for ${path}.
|
|
331
|
-
Wait ${rateLimit}s between requests.`);
|
|
332
|
-
if (priorRequest == null ? void 0 : priorRequest.controller) {
|
|
333
|
-
if (cancelOngoingIfNew) priorRequest.controller.abort();
|
|
334
|
-
else if (cancelNewIfOngoing) return { isLoading: true };
|
|
335
|
-
}
|
|
336
|
-
if (typeof grab$1.log != "undefined")
|
|
337
|
-
(_e = grab$1.log) == null ? void 0 : _e.unshift({
|
|
338
|
-
path,
|
|
339
|
-
request: paramsAsText,
|
|
340
|
-
lastFetchTime: Date.now(),
|
|
341
|
-
controller: new AbortController()
|
|
342
|
-
});
|
|
343
|
-
let fetchParams = {
|
|
344
|
-
method,
|
|
345
|
-
headers: {
|
|
346
|
-
"Content-Type": "application/json",
|
|
347
|
-
Accept: "application/json",
|
|
348
|
-
...headers
|
|
349
|
-
},
|
|
350
|
-
body: params.body,
|
|
351
|
-
redirect: "follow",
|
|
352
|
-
cache: cache ? "force-cache" : "no-store",
|
|
353
|
-
signal: cancelOngoingIfNew ? (_g = (_f = grab$1.log[0]) == null ? void 0 : _f.controller) == null ? void 0 : _g.signal : AbortSignal.timeout(timeout * 1e3)
|
|
354
|
-
};
|
|
355
|
-
let paramsGETRequest = "";
|
|
356
|
-
if (["POST", "PUT", "PATCH"].includes(method))
|
|
357
|
-
fetchParams.body = params.body || JSON.stringify(params);
|
|
358
|
-
else
|
|
359
|
-
paramsGETRequest = (Object.keys(params).length ? "?" : "") + new URLSearchParams(params).toString();
|
|
360
|
-
if (typeof onRequest === "function")
|
|
361
|
-
[path, response, params, fetchParams] = onRequest(
|
|
362
|
-
path,
|
|
363
|
-
response,
|
|
364
|
-
params,
|
|
365
|
-
fetchParams
|
|
131
|
+
let paramsAsText = JSON.stringify(
|
|
132
|
+
paginateKey ? { ...params, [paginateKey]: void 0 } : params
|
|
366
133
|
);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if (mockHandler && (!mockHandler.params || mockHandler.method == method) && (!mockHandler.params || paramsAsText == JSON.stringify(mockHandler.params))) {
|
|
370
|
-
await wait(mockHandler.delay);
|
|
371
|
-
res = typeof mockHandler.response === "function" ? mockHandler.response(params) : mockHandler.response;
|
|
372
|
-
} else {
|
|
373
|
-
res = await fetch(baseURL + path + paramsGETRequest, fetchParams).catch(
|
|
374
|
-
(e) => {
|
|
375
|
-
throw new Error(e);
|
|
376
|
-
}
|
|
134
|
+
let priorRequest = grab?.log?.find(
|
|
135
|
+
(e) => e.request == paramsAsText && e.path == path
|
|
377
136
|
);
|
|
378
|
-
if (!
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
137
|
+
if (!paginateKey) {
|
|
138
|
+
for (let key of Object.keys(response)) response[key] = void 0;
|
|
139
|
+
if (cache && (!cacheForTime || priorRequest?.lastFetchTime > Date.now() - 1e3 * cacheForTime)) {
|
|
140
|
+
for (let key of Object.keys(priorRequest.res))
|
|
141
|
+
response[key] = priorRequest.res[key];
|
|
142
|
+
if (resFunction) response = resFunction(response);
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
let pageNumber = priorRequest?.currentPage + 1 || params?.[paginateKey] || 1;
|
|
146
|
+
if (!priorRequest) {
|
|
147
|
+
response[paginateResult] = [];
|
|
148
|
+
pageNumber = 1;
|
|
149
|
+
}
|
|
150
|
+
if (priorRequest) priorRequest.currentPage = pageNumber;
|
|
151
|
+
params = { ...params, [paginateKey]: pageNumber };
|
|
152
|
+
}
|
|
153
|
+
if (resFunction) resFunction({ isLoading: true });
|
|
154
|
+
else if (typeof response === "object") response.isLoading = true;
|
|
155
|
+
if (resFunction) response = resFunction(response);
|
|
156
|
+
if (rateLimit > 0 && priorRequest?.lastFetchTime && priorRequest.lastFetchTime > Date.now() - 1e3 * rateLimit)
|
|
157
|
+
throw new Error(`Fetch rate limit exceeded for ${path}.
|
|
158
|
+
Wait ${rateLimit}s between requests.`);
|
|
159
|
+
if (priorRequest?.controller) {
|
|
160
|
+
if (cancelOngoingIfNew) priorRequest.controller.abort();
|
|
161
|
+
else if (cancelNewIfOngoing) return { isLoading: true };
|
|
162
|
+
}
|
|
163
|
+
if (typeof grab.log != "undefined")
|
|
164
|
+
grab.log?.unshift({
|
|
165
|
+
path,
|
|
166
|
+
request: paramsAsText,
|
|
167
|
+
lastFetchTime: Date.now(),
|
|
168
|
+
controller: new AbortController()
|
|
169
|
+
});
|
|
170
|
+
let fetchParams = {
|
|
171
|
+
method,
|
|
172
|
+
headers: {
|
|
173
|
+
"Content-Type": "application/json",
|
|
174
|
+
Accept: "application/json",
|
|
175
|
+
...headers
|
|
176
|
+
},
|
|
177
|
+
body: params.body,
|
|
178
|
+
redirect: "follow",
|
|
179
|
+
cache: cache ? "force-cache" : "no-store",
|
|
180
|
+
signal: cancelOngoingIfNew ? grab.log[0]?.controller?.signal : AbortSignal.timeout(timeout * 1e3)
|
|
181
|
+
};
|
|
182
|
+
let paramsGETRequest = "";
|
|
183
|
+
if (["POST", "PUT", "PATCH"].includes(method))
|
|
184
|
+
fetchParams.body = params.body || JSON.stringify(params);
|
|
382
185
|
else
|
|
383
|
-
|
|
384
|
-
|
|
186
|
+
paramsGETRequest = (Object.keys(params).length ? "?" : "") + new URLSearchParams(params).toString();
|
|
187
|
+
if (typeof onRequest === "function")
|
|
188
|
+
[path, response, params, fetchParams] = onRequest(
|
|
189
|
+
path,
|
|
190
|
+
response,
|
|
191
|
+
params,
|
|
192
|
+
fetchParams
|
|
193
|
+
);
|
|
194
|
+
let res = null, startTime = /* @__PURE__ */ new Date(), mockHandler = grab.mock?.[path];
|
|
195
|
+
let wait = (s2) => new Promise((res2) => setTimeout(res2, s2 * 1e3 || 0));
|
|
196
|
+
if (mockHandler && (!mockHandler.params || mockHandler.method == method) && (!mockHandler.params || paramsAsText == JSON.stringify(mockHandler.params))) {
|
|
197
|
+
await wait(mockHandler.delay);
|
|
198
|
+
res = typeof mockHandler.response === "function" ? mockHandler.response(params) : mockHandler.response;
|
|
199
|
+
} else {
|
|
200
|
+
res = await fetch(baseURL + path + paramsGETRequest, fetchParams).catch(
|
|
201
|
+
(e) => {
|
|
202
|
+
throw new Error(e.message);
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
if (!res.ok)
|
|
206
|
+
throw new Error(`HTTP error: ${res.status} ${res.statusText}`);
|
|
207
|
+
let type = res.headers.get("content-type");
|
|
208
|
+
if (onStream) await onStream(res.body);
|
|
209
|
+
else
|
|
210
|
+
res = await (type ? type.includes("application/json") ? res && res.json() : type.includes("application/pdf") || type.includes("application/octet-stream") ? res.blob() : res.text() : res.json()).catch((e) => {
|
|
211
|
+
throw new Error("Error parsing response: " + e);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
if (typeof onResponse === "function")
|
|
215
|
+
[path, response, params, fetchParams] = onResponse(
|
|
216
|
+
path,
|
|
217
|
+
response,
|
|
218
|
+
params,
|
|
219
|
+
fetchParams
|
|
220
|
+
);
|
|
221
|
+
if (resFunction) resFunction({ isLoading: void 0 });
|
|
222
|
+
else if (typeof response === "object") delete response?.isLoading;
|
|
223
|
+
delete priorRequest?.controller;
|
|
224
|
+
const elapsedTime = ((Number(/* @__PURE__ */ new Date()) - Number(startTime)) / 1e3).toFixed(1);
|
|
225
|
+
if (debug) {
|
|
226
|
+
logger(
|
|
227
|
+
"Path:" + baseURL + path + paramsGETRequest + "\n" + JSON.stringify(options, null, 2) + "\nTime: " + elapsedTime + "s\nResponse: " + printJSONStructure(res)
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
if (typeof res === "object") {
|
|
231
|
+
for (let key of Object.keys(res))
|
|
232
|
+
response[key] = paginateResult == key && response[key]?.length ? [...response[key], ...res[key]] : res[key];
|
|
233
|
+
if (typeof response !== "undefined") response.data = res;
|
|
234
|
+
} else if (resFunction) resFunction({ data: res, ...res });
|
|
235
|
+
else if (typeof response === "object") response.data = res;
|
|
236
|
+
if (typeof grab.log != "undefined")
|
|
237
|
+
grab.log?.unshift({
|
|
238
|
+
path,
|
|
239
|
+
request: JSON.stringify({ ...params, paginateKey: void 0 }),
|
|
240
|
+
response,
|
|
241
|
+
lastFetchTime: Date.now()
|
|
385
242
|
});
|
|
243
|
+
if (resFunction) response = resFunction(response);
|
|
244
|
+
return response;
|
|
245
|
+
} catch (error) {
|
|
246
|
+
let errorMessage = "Error: " + error.message + "\nPath:" + baseURL + path + "\n";
|
|
247
|
+
if (typeof onError === "function")
|
|
248
|
+
onError(error.message, baseURL + path, params);
|
|
249
|
+
if (options.retryAttempts > 0)
|
|
250
|
+
return await grab(path, {
|
|
251
|
+
...options,
|
|
252
|
+
retryAttempts: --options.retryAttempts
|
|
253
|
+
});
|
|
254
|
+
if (!error.message.includes("signal") && options.debug) {
|
|
255
|
+
logger(errorMessage, { color: "red" });
|
|
256
|
+
if (debug && typeof document !== "undefined") showAlert(errorMessage);
|
|
257
|
+
}
|
|
258
|
+
response.error = error.message;
|
|
259
|
+
if (typeof response === "function") {
|
|
260
|
+
response.data = response({ isLoading: void 0, error: error.message });
|
|
261
|
+
response = response.data;
|
|
262
|
+
} else delete response?.isLoading;
|
|
263
|
+
if (typeof grab.log != "undefined")
|
|
264
|
+
grab.log?.unshift({
|
|
265
|
+
path,
|
|
266
|
+
request: JSON.stringify(params),
|
|
267
|
+
error: error.message
|
|
268
|
+
});
|
|
269
|
+
return response;
|
|
386
270
|
}
|
|
387
|
-
if (typeof onResponse === "function")
|
|
388
|
-
[path, response, params, fetchParams] = onResponse(
|
|
389
|
-
path,
|
|
390
|
-
response,
|
|
391
|
-
params,
|
|
392
|
-
fetchParams
|
|
393
|
-
);
|
|
394
|
-
if (resFunction) resFunction({ isLoading: void 0 });
|
|
395
|
-
else if (typeof response === "object") response == null ? true : delete response.isLoading;
|
|
396
|
-
priorRequest == null ? true : delete priorRequest.controller;
|
|
397
|
-
const elapsedTime = ((Number(/* @__PURE__ */ new Date()) - Number(startTime)) / 1e3).toFixed(1);
|
|
398
|
-
if (debug) {
|
|
399
|
-
logger(
|
|
400
|
-
"Path:" + baseURL + path + paramsGETRequest + "\n" + JSON.stringify(options, null, 2) + "\nTime: " + elapsedTime + "s\nResponse: " + printJSONStructure(res)
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
if (typeof res === "object") {
|
|
404
|
-
for (let key of Object.keys(res))
|
|
405
|
-
response[key] = paginateResult == key && ((_i = response[key]) == null ? void 0 : _i.length) ? [...response[key], ...res[key]] : res[key];
|
|
406
|
-
if (typeof response !== "undefined") response.data = res;
|
|
407
|
-
} else if (resFunction) resFunction({ data: res, ...res });
|
|
408
|
-
else if (typeof response === "object") response.data = res;
|
|
409
|
-
if (typeof grab$1.log != "undefined")
|
|
410
|
-
(_j = grab$1.log) == null ? void 0 : _j.unshift({
|
|
411
|
-
path,
|
|
412
|
-
request: JSON.stringify({ ...params, paginateKey: void 0 }),
|
|
413
|
-
response,
|
|
414
|
-
lastFetchTime: Date.now()
|
|
415
|
-
});
|
|
416
|
-
if (resFunction) response = resFunction(response);
|
|
417
|
-
return response;
|
|
418
271
|
}
|
|
419
|
-
grab
|
|
272
|
+
grab.instance = (defaults = {}) => (path, options = {}) => grab(path, { ...defaults, ...options });
|
|
420
273
|
const debouncer = async (func, wait) => {
|
|
421
274
|
let timeout;
|
|
422
275
|
return async function executedFunction(...args) {
|
|
@@ -430,7 +283,7 @@ const debouncer = async (func, wait) => {
|
|
|
430
283
|
};
|
|
431
284
|
if (typeof window !== "undefined") {
|
|
432
285
|
window.log = log;
|
|
433
|
-
window.grab = grab
|
|
286
|
+
window.grab = grab;
|
|
434
287
|
window.grab.log = [];
|
|
435
288
|
window.grab.mock = {};
|
|
436
289
|
window.grab.defaults = {};
|
|
@@ -442,23 +295,60 @@ if (typeof window !== "undefined") {
|
|
|
442
295
|
document.querySelector(paginateElement).scrollLeft = scrollLeft;
|
|
443
296
|
});
|
|
444
297
|
} else if (typeof global !== "undefined") {
|
|
445
|
-
grab
|
|
446
|
-
grab
|
|
447
|
-
grab
|
|
298
|
+
grab.log = [];
|
|
299
|
+
grab.mock = {};
|
|
300
|
+
grab.defaults = {};
|
|
448
301
|
global.log = log;
|
|
449
|
-
global.grab = grab
|
|
302
|
+
global.grab = grab.instance();
|
|
450
303
|
} else if (typeof globalThis !== "undefined") {
|
|
451
|
-
grab
|
|
452
|
-
grab
|
|
453
|
-
grab
|
|
304
|
+
grab.log = [];
|
|
305
|
+
grab.mock = {};
|
|
306
|
+
grab.defaults = {};
|
|
454
307
|
globalThis.log = log;
|
|
455
|
-
globalThis.grab = grab
|
|
308
|
+
globalThis.grab = grab.instance();
|
|
309
|
+
}
|
|
310
|
+
function showAlert(msg) {
|
|
311
|
+
if (typeof document === "undefined") return;
|
|
312
|
+
let o = document.getElementById("alert-overlay"), list;
|
|
313
|
+
if (!o) {
|
|
314
|
+
o = document.body.appendChild(document.createElement("div"));
|
|
315
|
+
o.id = "alert-overlay";
|
|
316
|
+
o.setAttribute(
|
|
317
|
+
"style",
|
|
318
|
+
"position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center"
|
|
319
|
+
);
|
|
320
|
+
o.innerHTML = `<div id="alert-box" style="background:#fff;padding:1.5em 2em;border-radius:8px;box-shadow:0 2px 16px #0003;min-width:220px;max-height:80vh;position:relative;display:flex;flex-direction:column;">
|
|
321
|
+
<button id="close-alert" style="position:absolute;top:12px;right:20px;font-size:1.5em;background:none;border:none;cursor:pointer;color:black;">×</button>
|
|
322
|
+
<div id="alert-list" style="overflow:auto;flex:1;"></div>
|
|
323
|
+
</div>`;
|
|
324
|
+
o.addEventListener("click", (e) => e.target == o && o.remove());
|
|
325
|
+
document.getElementById("close-alert").onclick = () => o.remove();
|
|
326
|
+
}
|
|
327
|
+
list = o.querySelector("#alert-list");
|
|
328
|
+
list.innerHTML += `<div style="border-bottom:1px solid #333; font-size:1.2em;margin:0.5em 0;">${msg}</div>`;
|
|
329
|
+
}
|
|
330
|
+
function setupDevTools() {
|
|
331
|
+
document.addEventListener("keydown", (e) => {
|
|
332
|
+
if (e.key === "i" && e.ctrlKey && e.altKey) {
|
|
333
|
+
let html = " ";
|
|
334
|
+
for (let request of grab.log) {
|
|
335
|
+
html += `<div style="margin-bottom:1em; border-bottom:1px solid #ccc; padding-bottom:1em;">
|
|
336
|
+
<b>Path:</b> ${request.path}<br>
|
|
337
|
+
<b>Request:</b> ${printJSONStructure(request.request, 0, "html")}<br>
|
|
338
|
+
<b>Response:</b> ${printJSONStructure(request.response, 0, "html")}<br>
|
|
339
|
+
<b>Time:</b> ${new Date(request.lastFetchTime).toLocaleString()}
|
|
340
|
+
</div>`;
|
|
341
|
+
}
|
|
342
|
+
showAlert(html);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
456
345
|
}
|
|
457
346
|
export {
|
|
458
|
-
grab
|
|
459
|
-
grab
|
|
347
|
+
grab as default,
|
|
348
|
+
grab,
|
|
460
349
|
log,
|
|
461
350
|
printJSONStructure,
|
|
351
|
+
setupDevTools,
|
|
462
352
|
showAlert
|
|
463
353
|
};
|
|
464
354
|
//# sourceMappingURL=grab-api.es.js.map
|