grab-url 0.9.135 → 0.9.137
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/package.json +6 -2
- package/src/grab-api.ts +783 -0
- package/src/grab-url-cli.js +6 -6
- package/src/icons/index.ts +313 -0
- package/src/icons/loading-bouncy-ball.svg +3 -0
- package/src/icons/loading-double-ring.svg +6 -0
- package/src/icons/loading-eclipse.svg +3 -0
- package/src/icons/loading-ellipsis.svg +16 -0
- package/src/icons/loading-floating-search.svg +11 -0
- package/src/icons/loading-gears.svg +3 -0
- package/src/icons/loading-infinity.svg +3 -0
- package/src/icons/loading-orbital.svg +8 -0
- package/src/icons/loading-pacman.svg +22 -0
- package/src/icons/loading-pulse-bars.svg +12 -0
- package/src/icons/loading-red-blue-ball.svg +10 -0
- package/src/icons/loading-reload-arrow.svg +5 -0
- package/src/icons/loading-ring.svg +3 -0
- package/src/icons/loading-ripple.svg +7 -0
- package/src/icons/loading-spinner-oval.svg +49 -0
- package/src/icons/loading-spinner.svg +57 -0
- package/src/icons/loading-square-blocks.svg +17 -0
- package/src/log.ts +309 -0
- package/src/spinners.json +1555 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><circle r="20" fill="#e90c59" cy="50" cx="30">
|
|
2
|
+
<animate begin="-0.5s" values="30;70;30" keyTimes="0;0.5;1" dur="1s" repeatCount="indefinite" attributeName="cx"></animate>
|
|
3
|
+
</circle>
|
|
4
|
+
<circle r="20" fill="#0f3bc6" cy="50" cx="70">
|
|
5
|
+
<animate begin="0s" values="30;70;30" keyTimes="0;0.5;1" dur="1s" repeatCount="indefinite" attributeName="cx"></animate>
|
|
6
|
+
</circle>
|
|
7
|
+
<circle r="20" fill="#e90c59" cy="50" cx="30">
|
|
8
|
+
<animate begin="-0.5s" values="30;70;30" keyTimes="0;0.5;1" dur="1s" repeatCount="indefinite" attributeName="cx"></animate>
|
|
9
|
+
<animate repeatCount="indefinite" dur="1s" keyTimes="0;0.499;0.5;1" calcMode="discrete" values="0;0;1;1" attributeName="fill-opacity"></animate>
|
|
10
|
+
</circle><g></g></g></svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><g>
|
|
2
|
+
<path stroke-width="12" stroke="#e1945b" fill="none" d="M50 15A35 35 0 1 0 74.74873734152916 25.251262658470843"></path>
|
|
3
|
+
<path fill="#e1945b" d="M49 3L49 27L61 15L49 3"></path>
|
|
4
|
+
<animateTransform keyTimes="0;1" values="0 50 50;360 50 50" dur="1s" repeatCount="indefinite" type="rotate" attributeName="transform"></animateTransform>
|
|
5
|
+
</g><g></g></g></svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><circle stroke-linecap="round" fill="none" stroke-dasharray="50.26548245743669 50.26548245743669" stroke="#fe718d" stroke-width="8" r="32" cy="50" cx="50">
|
|
2
|
+
<animateTransform values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" repeatCount="indefinite" type="rotate" attributeName="transform"></animateTransform>
|
|
3
|
+
</circle><g></g></g></svg>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block" xmlns:xlink="http://www.w3.org/1999/xlink"><g><circle stroke-width="2" stroke="#cbb953" fill="none" r="0" cy="50" cx="50">
|
|
2
|
+
<animate begin="0s" calcMode="spline" keySplines="0 0.2 0.8 1" keyTimes="0;1" values="0;40" dur="1s" repeatCount="indefinite" attributeName="r"></animate>
|
|
3
|
+
<animate begin="0s" calcMode="spline" keySplines="0.2 0 0.8 1" keyTimes="0;1" values="1;0" dur="1s" repeatCount="indefinite" attributeName="opacity"></animate>
|
|
4
|
+
</circle><circle stroke-width="2" stroke="#cbb953" fill="none" r="0" cy="50" cx="50">
|
|
5
|
+
<animate begin="-0.5s" calcMode="spline" keySplines="0 0.2 0.8 1" keyTimes="0;1" values="0;40" dur="1s" repeatCount="indefinite" attributeName="r"></animate>
|
|
6
|
+
<animate begin="-0.5s" calcMode="spline" keySplines="0.2 0 0.8 1" keyTimes="0;1" values="1;0" dur="1s" repeatCount="indefinite" attributeName="opacity"></animate>
|
|
7
|
+
</circle><g></g></g></svg>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><g transform="rotate(0 50 50)">
|
|
2
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
3
|
+
<animate repeatCount="indefinite" begin="-0.9166666666666666s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
4
|
+
</rect>
|
|
5
|
+
</g><g transform="rotate(30 50 50)">
|
|
6
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
7
|
+
<animate repeatCount="indefinite" begin="-0.8333333333333334s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
8
|
+
</rect>
|
|
9
|
+
</g><g transform="rotate(60 50 50)">
|
|
10
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
11
|
+
<animate repeatCount="indefinite" begin="-0.75s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
12
|
+
</rect>
|
|
13
|
+
</g><g transform="rotate(90 50 50)">
|
|
14
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
15
|
+
<animate repeatCount="indefinite" begin="-0.6666666666666666s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
16
|
+
</rect>
|
|
17
|
+
</g><g transform="rotate(120 50 50)">
|
|
18
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
19
|
+
<animate repeatCount="indefinite" begin="-0.5833333333333334s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
20
|
+
</rect>
|
|
21
|
+
</g><g transform="rotate(150 50 50)">
|
|
22
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
23
|
+
<animate repeatCount="indefinite" begin="-0.5s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
24
|
+
</rect>
|
|
25
|
+
</g><g transform="rotate(180 50 50)">
|
|
26
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
27
|
+
<animate repeatCount="indefinite" begin="-0.4166666666666667s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
28
|
+
</rect>
|
|
29
|
+
</g><g transform="rotate(210 50 50)">
|
|
30
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
31
|
+
<animate repeatCount="indefinite" begin="-0.3333333333333333s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
32
|
+
</rect>
|
|
33
|
+
</g><g transform="rotate(240 50 50)">
|
|
34
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
35
|
+
<animate repeatCount="indefinite" begin="-0.25s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
36
|
+
</rect>
|
|
37
|
+
</g><g transform="rotate(270 50 50)">
|
|
38
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
39
|
+
<animate repeatCount="indefinite" begin="-0.16666666666666666s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
40
|
+
</rect>
|
|
41
|
+
</g><g transform="rotate(300 50 50)">
|
|
42
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
43
|
+
<animate repeatCount="indefinite" begin="-0.08333333333333333s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
44
|
+
</rect>
|
|
45
|
+
</g><g transform="rotate(330 50 50)">
|
|
46
|
+
<rect fill="#0099e5" height="12" width="6" ry="6" rx="3" y="24" x="47">
|
|
47
|
+
<animate repeatCount="indefinite" begin="0s" dur="1s" keyTimes="0;1" values="1;0" attributeName="opacity"></animate>
|
|
48
|
+
</rect>
|
|
49
|
+
</g><g></g></g></svg>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><g transform="translate(80,50)">
|
|
2
|
+
<g transform="rotate(0)">
|
|
3
|
+
<circle fill-opacity="1" fill="#0099e5" r="6" cy="0" cx="0">
|
|
4
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="-0.875s" type="scale" attributeName="transform"></animateTransform>
|
|
5
|
+
<animate begin="-0.875s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
6
|
+
</circle>
|
|
7
|
+
</g>
|
|
8
|
+
</g><g transform="translate(71.21320343559643,71.21320343559643)">
|
|
9
|
+
<g transform="rotate(45)">
|
|
10
|
+
<circle fill-opacity="0.875" fill="#0099e5" r="6" cy="0" cx="0">
|
|
11
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="-0.75s" type="scale" attributeName="transform"></animateTransform>
|
|
12
|
+
<animate begin="-0.75s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
13
|
+
</circle>
|
|
14
|
+
</g>
|
|
15
|
+
</g><g transform="translate(50,80)">
|
|
16
|
+
<g transform="rotate(90)">
|
|
17
|
+
<circle fill-opacity="0.75" fill="#0099e5" r="6" cy="0" cx="0">
|
|
18
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="-0.625s" type="scale" attributeName="transform"></animateTransform>
|
|
19
|
+
<animate begin="-0.625s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
20
|
+
</circle>
|
|
21
|
+
</g>
|
|
22
|
+
</g><g transform="translate(28.786796564403577,71.21320343559643)">
|
|
23
|
+
<g transform="rotate(135)">
|
|
24
|
+
<circle fill-opacity="0.625" fill="#0099e5" r="6" cy="0" cx="0">
|
|
25
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="-0.5s" type="scale" attributeName="transform"></animateTransform>
|
|
26
|
+
<animate begin="-0.5s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
27
|
+
</circle>
|
|
28
|
+
</g>
|
|
29
|
+
</g><g transform="translate(20,50.00000000000001)">
|
|
30
|
+
<g transform="rotate(180)">
|
|
31
|
+
<circle fill-opacity="0.5" fill="#0099e5" r="6" cy="0" cx="0">
|
|
32
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="-0.375s" type="scale" attributeName="transform"></animateTransform>
|
|
33
|
+
<animate begin="-0.375s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
34
|
+
</circle>
|
|
35
|
+
</g>
|
|
36
|
+
</g><g transform="translate(28.78679656440357,28.786796564403577)">
|
|
37
|
+
<g transform="rotate(225)">
|
|
38
|
+
<circle fill-opacity="0.375" fill="#0099e5" r="6" cy="0" cx="0">
|
|
39
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="-0.25s" type="scale" attributeName="transform"></animateTransform>
|
|
40
|
+
<animate begin="-0.25s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
41
|
+
</circle>
|
|
42
|
+
</g>
|
|
43
|
+
</g><g transform="translate(49.99999999999999,20)">
|
|
44
|
+
<g transform="rotate(270)">
|
|
45
|
+
<circle fill-opacity="0.25" fill="#0099e5" r="6" cy="0" cx="0">
|
|
46
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="-0.125s" type="scale" attributeName="transform"></animateTransform>
|
|
47
|
+
<animate begin="-0.125s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
48
|
+
</circle>
|
|
49
|
+
</g>
|
|
50
|
+
</g><g transform="translate(71.21320343559643,28.78679656440357)">
|
|
51
|
+
<g transform="rotate(315)">
|
|
52
|
+
<circle fill-opacity="0.125" fill="#0099e5" r="6" cy="0" cx="0">
|
|
53
|
+
<animateTransform repeatCount="indefinite" dur="1s" keyTimes="0;1" values="1.5 1.5;1 1" begin="0s" type="scale" attributeName="transform"></animateTransform>
|
|
54
|
+
<animate begin="0s" values="1;0" repeatCount="indefinite" dur="1s" keyTimes="0;1" attributeName="fill-opacity"></animate>
|
|
55
|
+
</circle>
|
|
56
|
+
</g>
|
|
57
|
+
</g><g></g></g></svg>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="200" height="200" style="shape-rendering: auto; display: block; " xmlns:xlink="http://www.w3.org/1999/xlink"><g><rect fill="#e15b64" height="20" width="20" y="19" x="19">
|
|
2
|
+
<animate calcMode="discrete" begin="0s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
3
|
+
</rect><rect fill="#e15b64" height="20" width="20" y="19" x="40">
|
|
4
|
+
<animate calcMode="discrete" begin="0.125s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
5
|
+
</rect><rect fill="#e15b64" height="20" width="20" y="19" x="61">
|
|
6
|
+
<animate calcMode="discrete" begin="0.25s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
7
|
+
</rect><rect fill="#e15b64" height="20" width="20" y="40" x="19">
|
|
8
|
+
<animate calcMode="discrete" begin="0.875s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
9
|
+
</rect><rect fill="#e15b64" height="20" width="20" y="40" x="61">
|
|
10
|
+
<animate calcMode="discrete" begin="0.375s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
11
|
+
</rect><rect fill="#e15b64" height="20" width="20" y="61" x="19">
|
|
12
|
+
<animate calcMode="discrete" begin="0.75s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
13
|
+
</rect><rect fill="#e15b64" height="20" width="20" y="61" x="40">
|
|
14
|
+
<animate calcMode="discrete" begin="0.625s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
15
|
+
</rect><rect fill="#e15b64" height="20" width="20" y="61" x="61">
|
|
16
|
+
<animate calcMode="discrete" begin="0.5s" repeatCount="indefinite" dur="1s" keyTimes="0;0.125;1" values="#f8b26a;#e15b64;#e15b64" attributeName="fill"></animate>
|
|
17
|
+
</rect><g></g></g></svg>
|
package/src/log.ts
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ### Colorized Log With JSON Structure
|
|
3
|
+
* 
|
|
4
|
+
* Logs messages to the console with custom styling,
|
|
5
|
+
* prints JSON with description of structure layout,
|
|
6
|
+
* and showing debug output in development only.
|
|
7
|
+
* @param {string|object} message - The message to log. If an object is provided, it will be stringified.
|
|
8
|
+
* @param {string|string[]} [options.style] default='color: blue; font-size: 11pt;' - CSS style string
|
|
9
|
+
* @param {boolean} [options.hideInProduction] - default = auto-detects based on hostname.
|
|
10
|
+
* If true, uses `console.debug` (hidden in production). If false, uses `console.log`.
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
export function log(message = "", options: LogOptions = {}) {
|
|
14
|
+
let {
|
|
15
|
+
color = null,
|
|
16
|
+
style = "color: blue; font-size: 11pt;",
|
|
17
|
+
hideInProduction = undefined,
|
|
18
|
+
startSpinner = false,
|
|
19
|
+
stopSpinner = false,
|
|
20
|
+
} = options;
|
|
21
|
+
|
|
22
|
+
// Auto-detect if we should hide logs in production based on hostname
|
|
23
|
+
if (typeof hideInProduction === "undefined")
|
|
24
|
+
hideInProduction =
|
|
25
|
+
typeof window !== "undefined" &&
|
|
26
|
+
window?.location.hostname.includes("localhost");
|
|
27
|
+
|
|
28
|
+
// For objects, print both the structure visualization and full JSON
|
|
29
|
+
if (typeof message === "object")
|
|
30
|
+
message =
|
|
31
|
+
printJSONStructure(message) + "\n\n" + JSON.stringify(message, null, 2);
|
|
32
|
+
|
|
33
|
+
//colorize in terminal (%c is only in browser)
|
|
34
|
+
if (color && typeof process !== undefined)
|
|
35
|
+
message = (colors[color] || "") + message + colors.reset;
|
|
36
|
+
|
|
37
|
+
// Displays an animated spinner in the terminal with the provided text.
|
|
38
|
+
var i = 0;
|
|
39
|
+
|
|
40
|
+
if (startSpinner)
|
|
41
|
+
(global || globalThis).interval = setInterval(() => {
|
|
42
|
+
process.stdout.write(
|
|
43
|
+
(colors[color] || "") +
|
|
44
|
+
"\r" +
|
|
45
|
+
"⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏".split("")[(i = ++i % 10)] +
|
|
46
|
+
" " +
|
|
47
|
+
message +
|
|
48
|
+
colors.reset
|
|
49
|
+
);
|
|
50
|
+
}, 50);
|
|
51
|
+
else if (stopSpinner) {
|
|
52
|
+
clearInterval((global || globalThis).interval);
|
|
53
|
+
process.stdout.write(
|
|
54
|
+
"\r" + (message || "✔ Done") + " ".repeat(message.length + 20) + "\n"
|
|
55
|
+
);
|
|
56
|
+
} else if (typeof style === "string") {
|
|
57
|
+
// check if style is a one word color code or named color
|
|
58
|
+
//test if style is valid as a CSS color name
|
|
59
|
+
if (style.split(" ").length == 1 || color) {
|
|
60
|
+
style = `color: ${color || style}; font-size: 11pt;`;
|
|
61
|
+
} else {
|
|
62
|
+
// check if style is valid as a CSS color code
|
|
63
|
+
if (style.match(/^#[0-9a-fA-F]{6}$/)) {
|
|
64
|
+
style = `color: ${style}; font-size: 11pt;`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Use console.debug for production-hidden logs, console.log otherwise
|
|
68
|
+
if (hideInProduction)
|
|
69
|
+
console.debug((style ? "%c" : "") + (message || ""), style);
|
|
70
|
+
else console.log((style ? "%c" : "") + (message || ""), style);
|
|
71
|
+
} else if (typeof style === "object") console.log(message, ...(style as any));
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface LogOptions {
|
|
76
|
+
/** CSS style string or array of CSS strings for browser console styling */
|
|
77
|
+
style?: string | string[];
|
|
78
|
+
/** Optional color name or code for terminal environments */
|
|
79
|
+
color?: keyof typeof colors | null;
|
|
80
|
+
/** If true, hides log in production (auto-detects by hostname if undefined) */
|
|
81
|
+
hideInProduction?: boolean;
|
|
82
|
+
/** Start a spinner (for CLI tools, optional) */
|
|
83
|
+
startSpinner?: boolean;
|
|
84
|
+
/** Stop a spinner (for CLI tools, optional) */
|
|
85
|
+
stopSpinner?: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ANSI escape codes for terminal colors when running in Node.js
|
|
89
|
+
export const colors = {
|
|
90
|
+
reset: "\x1b[0m", // Reset to default color
|
|
91
|
+
black: "\x1b[30m",
|
|
92
|
+
red: "\x1b[31m", // Functions, errors
|
|
93
|
+
green: "\x1b[32m", // Object braces, success
|
|
94
|
+
yellow: "\x1b[33m", // Strings, warnings
|
|
95
|
+
blue: "\x1b[34m", // Array brackets, info
|
|
96
|
+
magenta: "\x1b[35m", // Booleans
|
|
97
|
+
cyan: "\x1b[36m", // Numbers
|
|
98
|
+
white: "\x1b[37m", // Default color, plain text
|
|
99
|
+
gray: "\x1b[90m", // Null, undefined, subtle
|
|
100
|
+
// Bright variants
|
|
101
|
+
brightRed: "\x1b[91m",
|
|
102
|
+
brightGreen: "\x1b[92m",
|
|
103
|
+
brightYellow: "\x1b[93m",
|
|
104
|
+
brightBlue: "\x1b[94m",
|
|
105
|
+
brightMagenta: "\x1b[95m",
|
|
106
|
+
brightCyan: "\x1b[96m",
|
|
107
|
+
brightWhite: "\x1b[97m",
|
|
108
|
+
// Background colors (optional)
|
|
109
|
+
bgRed: "\x1b[41m",
|
|
110
|
+
bgGreen: "\x1b[42m",
|
|
111
|
+
bgYellow: "\x1b[43m",
|
|
112
|
+
bgBlue: "\x1b[44m",
|
|
113
|
+
bgMagenta: "\x1b[45m",
|
|
114
|
+
bgCyan: "\x1b[46m",
|
|
115
|
+
bgWhite: "\x1b[47m",
|
|
116
|
+
bgGray: "\x1b[100m",
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Determines the appropriate color code for a given value type
|
|
121
|
+
* Used for consistent color coding in the structure visualization
|
|
122
|
+
*/
|
|
123
|
+
function getColorForType(value) {
|
|
124
|
+
if (typeof value === "string") return colors.yellow;
|
|
125
|
+
if (typeof value === "number") return colors.cyan;
|
|
126
|
+
if (typeof value === "boolean") return colors.magenta;
|
|
127
|
+
if (typeof value === "function") return colors.red;
|
|
128
|
+
if (value === null) return colors.gray;
|
|
129
|
+
if (Array.isArray(value)) return colors.blue;
|
|
130
|
+
if (typeof value === "object") return colors.green;
|
|
131
|
+
return colors.white;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Returns a string representation of the value's type
|
|
136
|
+
* Used to show simplified type information in the structure visualization
|
|
137
|
+
*/
|
|
138
|
+
function getTypeString(value) {
|
|
139
|
+
if (typeof value === "string") return '""';
|
|
140
|
+
if (typeof value === "number") return "number";
|
|
141
|
+
if (typeof value === "boolean") return "bool";
|
|
142
|
+
if (typeof value === "function") return "function";
|
|
143
|
+
if (value === null) return "null";
|
|
144
|
+
if (Array.isArray(value)) {
|
|
145
|
+
if (value.length) return "[" + getTypeString(value[0]) + "]";
|
|
146
|
+
else return "[]";
|
|
147
|
+
}
|
|
148
|
+
if (typeof value === "object") return "{...}";
|
|
149
|
+
return typeof value;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Creates a colored visualization of a JSON object's structure
|
|
154
|
+
* Shows the shape and types of the data rather than actual values
|
|
155
|
+
* Recursively processes nested objects and arrays
|
|
156
|
+
*/
|
|
157
|
+
export function printJSONStructure(obj, indent = 0) {
|
|
158
|
+
const pad = " ".repeat(indent);
|
|
159
|
+
|
|
160
|
+
// Handle primitive values and null
|
|
161
|
+
if (typeof obj !== "object" || obj === null) {
|
|
162
|
+
const color = getColorForType(obj);
|
|
163
|
+
return color + getTypeString(obj) + colors.reset;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Handle arrays with special bracket formatting
|
|
167
|
+
if (Array.isArray(obj)) {
|
|
168
|
+
let result = colors.blue + "[" + colors.reset;
|
|
169
|
+
if (obj.length) result += "\n";
|
|
170
|
+
obj.forEach((item, idx) => {
|
|
171
|
+
result += pad + " " + printJSONStructure(item, indent + 1);
|
|
172
|
+
if (idx < obj.length - 1) result += ",";
|
|
173
|
+
result += "\n";
|
|
174
|
+
});
|
|
175
|
+
result += pad + colors.blue + "]" + colors.reset;
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Handle objects with special brace and property formatting
|
|
180
|
+
let result = colors.green + "{" + colors.reset;
|
|
181
|
+
const keys = Object.keys(obj);
|
|
182
|
+
if (keys.length) result += "\n";
|
|
183
|
+
keys.forEach((key, index) => {
|
|
184
|
+
const value = obj[key];
|
|
185
|
+
const color = getColorForType(value);
|
|
186
|
+
result += pad + " ";
|
|
187
|
+
|
|
188
|
+
// Handle nested objects recursively
|
|
189
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
190
|
+
result +=
|
|
191
|
+
color +
|
|
192
|
+
key +
|
|
193
|
+
colors.reset +
|
|
194
|
+
": " +
|
|
195
|
+
printJSONStructure(value, indent + 1);
|
|
196
|
+
}
|
|
197
|
+
// Handle nested arrays recursively
|
|
198
|
+
else if (Array.isArray(value)) {
|
|
199
|
+
result +=
|
|
200
|
+
color +
|
|
201
|
+
key +
|
|
202
|
+
colors.reset +
|
|
203
|
+
": " +
|
|
204
|
+
printJSONStructure(value, indent + 1);
|
|
205
|
+
}
|
|
206
|
+
// Handle primitive values
|
|
207
|
+
else {
|
|
208
|
+
result += color + key + ": " + getTypeString(value) + colors.reset;
|
|
209
|
+
}
|
|
210
|
+
if (index < keys.length - 1) result += ",";
|
|
211
|
+
result += "\n";
|
|
212
|
+
});
|
|
213
|
+
result += pad + colors.green + "}" + colors.reset;
|
|
214
|
+
|
|
215
|
+
// Only log at top level of recursion
|
|
216
|
+
if (indent === 0) {
|
|
217
|
+
// console.log(result);
|
|
218
|
+
}
|
|
219
|
+
return result;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Shows message in a modal overlay with scrollable message stack
|
|
224
|
+
* and is easier to dismiss unlike alert() which blocks window.
|
|
225
|
+
* Creates a semi-transparent overlay with a white box containing the message.
|
|
226
|
+
* @param {string} msg - The message to display
|
|
227
|
+
*/
|
|
228
|
+
export function showAlert(msg) {
|
|
229
|
+
if (typeof document === "undefined") return;
|
|
230
|
+
let o = document.getElementById("alert-overlay"),
|
|
231
|
+
list;
|
|
232
|
+
|
|
233
|
+
// Create overlay and alert box if they don't exist
|
|
234
|
+
if (!o) {
|
|
235
|
+
o = document.body.appendChild(document.createElement("div"));
|
|
236
|
+
o.id = "alert-overlay";
|
|
237
|
+
o.setAttribute(
|
|
238
|
+
"style",
|
|
239
|
+
"position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center"
|
|
240
|
+
);
|
|
241
|
+
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;">
|
|
242
|
+
<button id="close-alert" style="position:absolute;top:12px;right:20px;font-size:1.5em;background:none;border:none;cursor:pointer;color:black;">×</button>
|
|
243
|
+
<div id="alert-list" style="overflow:auto;flex:1;"></div>
|
|
244
|
+
</div>`;
|
|
245
|
+
|
|
246
|
+
// Add click handlers to close overlay
|
|
247
|
+
o.addEventListener("click", (e) => e.target == o && o.remove());
|
|
248
|
+
document.getElementById("close-alert").onclick = () => o.remove();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
list = o.querySelector("#alert-list");
|
|
252
|
+
|
|
253
|
+
// Add new message to list
|
|
254
|
+
list.innerHTML += `<div style="border-bottom:1px solid #333; font-size:1.2em;margin:0.5em 0;">${msg}</div>`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Sets up development tools for debugging API requests
|
|
259
|
+
* Adds a keyboard shortcut (Ctrl+I) that shows a modal with request history
|
|
260
|
+
* Each request entry shows:
|
|
261
|
+
* - Request path
|
|
262
|
+
* - Request details
|
|
263
|
+
* - Response data
|
|
264
|
+
* - Timestamp
|
|
265
|
+
*/
|
|
266
|
+
export function setupDevTools() {
|
|
267
|
+
// Keyboard shortcut (Ctrl+I) to toggle debug view
|
|
268
|
+
document.addEventListener("keydown", (e) => {
|
|
269
|
+
if (e.key === "i" && e.ctrlKey) {
|
|
270
|
+
// Create HTML of the grab.log requests
|
|
271
|
+
let html = " ";
|
|
272
|
+
for (let request of grab.log) {
|
|
273
|
+
html += `<div style="margin-bottom:1em; border-bottom:1px solid #ccc; padding-bottom:1em;">
|
|
274
|
+
<b>Path:</b> ${request.path}<br>
|
|
275
|
+
<b>Request:</b> ${request.request}<br>
|
|
276
|
+
<b>Response:</b> ${JSON.stringify(request.response, null, 2)}<br>
|
|
277
|
+
<b>Time:</b> ${new Date(request.lastFetchTime).toLocaleString()}
|
|
278
|
+
</div>`;
|
|
279
|
+
}
|
|
280
|
+
showAlert(html);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Displays an animated spinner in the terminal with the provided text.
|
|
287
|
+
* The spinner animates in-place until the returned function is called,
|
|
288
|
+
* which stops the spinner and prints a success message.
|
|
289
|
+
* @param {string} text - The text to display next to the spinner animation.
|
|
290
|
+
* @returns {(success?: string) => void} Stop function with optional message.
|
|
291
|
+
* @example
|
|
292
|
+
* const stopSpinner = showSpinnerInTerminal('Downloading...');
|
|
293
|
+
* setTimeout(() => {
|
|
294
|
+
* stopSpinner('Success!');
|
|
295
|
+
* }, 2000);
|
|
296
|
+
*/
|
|
297
|
+
export function showSpinnerInTerminal(text) {
|
|
298
|
+
let i = 0,
|
|
299
|
+
interval = setInterval(() => {
|
|
300
|
+
process.stdout.write(
|
|
301
|
+
"\r" + "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏".split("")[(i = ++i % 10)] + " " + text
|
|
302
|
+
);
|
|
303
|
+
}, 50);
|
|
304
|
+
|
|
305
|
+
return function (success = "✔ Done!") {
|
|
306
|
+
clearInterval(interval);
|
|
307
|
+
process.stdout.write("\r" + success + " ".repeat(text.length) + "\n");
|
|
308
|
+
};
|
|
309
|
+
}
|