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.
@@ -1,180 +1,6 @@
1
- function log(message = "", options = {}) {
2
- let {
3
- color = null,
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;">&times;</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" ? (_a = window == null ? void 0 : window.grab) == null ? void 0 : _a.defaults : ((_c = (_b = global || globalThis) == null ? void 0 : _b.grab) == null ? void 0 : _c.defaults) || {},
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
- if (debounce > 0)
243
- return await debouncer(async () => {
244
- await grab$1(path, { ...options, debounce: 0 });
245
- }, debounce * 1e3);
246
- if (repeat > 1) {
247
- for (let i = 0; i < repeat; i++) {
248
- await grab$1(path, { ...options, repeat: 0 });
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
- return response;
251
- }
252
- if (repeatEvery) {
253
- setInterval(async () => {
254
- await grab$1(path, { ...options, repeat: 0, repeatEvery: null });
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
- let resFunction = typeof response === "function" ? response : null;
280
- if (!response || resFunction) response = {};
281
- var [paginateKey, paginateResult, paginateElement] = infiniteScroll || [];
282
- if ((infiniteScroll == null ? void 0 : infiniteScroll.length) && typeof paginateElement !== "undefined" && typeof window !== "undefined") {
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
- cache: false,
297
- [paginateKey]: (priorRequest == null ? void 0 : priorRequest.currentPage) + 1
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
- } else {
318
- let pageNumber = (priorRequest == null ? void 0 : priorRequest.currentPage) + 1 || (params == null ? void 0 : params[paginateKey]) || 1;
319
- if (!priorRequest) {
320
- response[paginateResult] = [];
321
- pageNumber = 1;
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
- if (priorRequest) priorRequest.currentPage = pageNumber;
324
- params[paginateKey] = pageNumber;
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
- let res = null, startTime = /* @__PURE__ */ new Date(), mockHandler = (_h = grab$1.mock) == null ? void 0 : _h[path];
368
- let wait = (s2) => new Promise((res2) => setTimeout(res2, s2 * 1e3 || 0));
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 (!res.ok)
379
- throw new Error(`HTTP error: ${res.status} ${res.statusText}`);
380
- let type = res.headers.get("content-type");
381
- if (onStream) await onStream(res.body);
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
- 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) => {
384
- throw new Error("Error parsing response: " + e);
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$1.instance = (defaults = {}) => (path, options = {}) => grab$1(path, { ...defaults, ...options });
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$1;
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$1.log = [];
446
- grab$1.mock = {};
447
- grab$1.defaults = {};
298
+ grab.log = [];
299
+ grab.mock = {};
300
+ grab.defaults = {};
448
301
  global.log = log;
449
- global.grab = grab$1.instance();
302
+ global.grab = grab.instance();
450
303
  } else if (typeof globalThis !== "undefined") {
451
- grab$1.log = [];
452
- grab$1.mock = {};
453
- grab$1.defaults = {};
304
+ grab.log = [];
305
+ grab.mock = {};
306
+ grab.defaults = {};
454
307
  globalThis.log = log;
455
- globalThis.grab = grab$1.instance();
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;">&times;</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$1 as default,
459
- grab$1 as 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