A simple SEO inspecter Tool, to get social media card previews

Add API and documentation

+1007 -6
+3
.env
··· 1 + VITE_SUPABASE_PROJECT_ID="gjhfnqiknusundbktwxs" 2 + VITE_SUPABASE_PUBLISHABLE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdqaGZucWlrbnVzdW5kYmt0d3hzIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjAxMzI1NjgsImV4cCI6MjA3NTcwODU2OH0.zNRPupvAPnzJsTvXkg8tm0nycVKzc6dSG_2RRQZKKv0" 3 + VITE_SUPABASE_URL="https://gjhfnqiknusundbktwxs.supabase.co"
+248 -5
package-lock.json
··· 36 36 "@radix-ui/react-toggle": "^1.1.9", 37 37 "@radix-ui/react-toggle-group": "^1.1.10", 38 38 "@radix-ui/react-tooltip": "^1.2.7", 39 + "@supabase/supabase-js": "^2.75.0", 39 40 "@tanstack/react-query": "^5.83.0", 40 41 "class-variance-authority": "^0.7.1", 41 42 "clsx": "^2.1.1", ··· 82 83 "version": "5.2.0", 83 84 "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", 84 85 "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", 86 + "dev": true, 85 87 "license": "MIT", 86 88 "engines": { 87 89 "node": ">=10" ··· 845 847 "version": "8.0.2", 846 848 "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", 847 849 "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", 850 + "dev": true, 848 851 "license": "ISC", 849 852 "dependencies": { 850 853 "string-width": "^5.1.2", ··· 862 865 "version": "0.3.5", 863 866 "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", 864 867 "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", 868 + "dev": true, 865 869 "license": "MIT", 866 870 "dependencies": { 867 871 "@jridgewell/set-array": "^1.2.1", ··· 876 880 "version": "3.1.2", 877 881 "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 878 882 "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 883 + "dev": true, 879 884 "license": "MIT", 880 885 "engines": { 881 886 "node": ">=6.0.0" ··· 885 890 "version": "1.2.1", 886 891 "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 887 892 "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 893 + "dev": true, 888 894 "license": "MIT", 889 895 "engines": { 890 896 "node": ">=6.0.0" ··· 894 900 "version": "1.5.0", 895 901 "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 896 902 "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 903 + "dev": true, 897 904 "license": "MIT" 898 905 }, 899 906 "node_modules/@jridgewell/trace-mapping": { 900 907 "version": "0.3.25", 901 908 "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 902 909 "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 910 + "dev": true, 903 911 "license": "MIT", 904 912 "dependencies": { 905 913 "@jridgewell/resolve-uri": "^3.1.0", ··· 910 918 "version": "2.1.5", 911 919 "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 912 920 "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 921 + "dev": true, 913 922 "license": "MIT", 914 923 "dependencies": { 915 924 "@nodelib/fs.stat": "2.0.5", ··· 923 932 "version": "2.0.5", 924 933 "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 925 934 "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 935 + "dev": true, 926 936 "license": "MIT", 927 937 "engines": { 928 938 "node": ">= 8" ··· 932 942 "version": "1.2.8", 933 943 "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 934 944 "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 945 + "dev": true, 935 946 "license": "MIT", 936 947 "dependencies": { 937 948 "@nodelib/fs.scandir": "2.1.5", ··· 945 956 "version": "0.11.0", 946 957 "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 947 958 "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 959 + "dev": true, 948 960 "license": "MIT", 949 961 "optional": true, 950 962 "engines": { ··· 2545 2557 "win32" 2546 2558 ] 2547 2559 }, 2560 + "node_modules/@supabase/auth-js": { 2561 + "version": "2.75.0", 2562 + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.75.0.tgz", 2563 + "integrity": "sha512-J8TkeqCOMCV4KwGKVoxmEBuDdHRwoInML2vJilthOo7awVCro2SM+tOcpljORwuBQ1vHUtV62Leit+5wlxrNtw==", 2564 + "license": "MIT", 2565 + "dependencies": { 2566 + "@supabase/node-fetch": "2.6.15" 2567 + } 2568 + }, 2569 + "node_modules/@supabase/functions-js": { 2570 + "version": "2.75.0", 2571 + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.75.0.tgz", 2572 + "integrity": "sha512-18yk07Moj/xtQ28zkqswxDavXC3vbOwt1hDuYM3/7xPnwwpKnsmPyZ7bQ5th4uqiJzQ135t74La9tuaxBR6e7w==", 2573 + "license": "MIT", 2574 + "dependencies": { 2575 + "@supabase/node-fetch": "2.6.15" 2576 + } 2577 + }, 2578 + "node_modules/@supabase/node-fetch": { 2579 + "version": "2.6.15", 2580 + "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz", 2581 + "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==", 2582 + "license": "MIT", 2583 + "dependencies": { 2584 + "whatwg-url": "^5.0.0" 2585 + }, 2586 + "engines": { 2587 + "node": "4.x || >=6.0.0" 2588 + } 2589 + }, 2590 + "node_modules/@supabase/postgrest-js": { 2591 + "version": "2.75.0", 2592 + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.75.0.tgz", 2593 + "integrity": "sha512-YfBz4W/z7eYCFyuvHhfjOTTzRrQIvsMG2bVwJAKEVVUqGdzqfvyidXssLBG0Fqlql1zJFgtsPpK1n4meHrI7tg==", 2594 + "license": "MIT", 2595 + "dependencies": { 2596 + "@supabase/node-fetch": "2.6.15" 2597 + } 2598 + }, 2599 + "node_modules/@supabase/realtime-js": { 2600 + "version": "2.75.0", 2601 + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.75.0.tgz", 2602 + "integrity": "sha512-B4Xxsf2NHd5cEnM6MGswOSPSsZKljkYXpvzKKmNxoUmNQOfB7D8HOa6NwHcUBSlxcjV+vIrYKcYXtavGJqeGrw==", 2603 + "license": "MIT", 2604 + "dependencies": { 2605 + "@supabase/node-fetch": "2.6.15", 2606 + "@types/phoenix": "^1.6.6", 2607 + "@types/ws": "^8.18.1", 2608 + "ws": "^8.18.2" 2609 + } 2610 + }, 2611 + "node_modules/@supabase/storage-js": { 2612 + "version": "2.75.0", 2613 + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.75.0.tgz", 2614 + "integrity": "sha512-wpJMYdfFDckDiHQaTpK+Ib14N/O2o0AAWWhguKvmmMurB6Unx17GGmYp5rrrqCTf8S1qq4IfIxTXxS4hzrUySg==", 2615 + "license": "MIT", 2616 + "dependencies": { 2617 + "@supabase/node-fetch": "2.6.15" 2618 + } 2619 + }, 2620 + "node_modules/@supabase/supabase-js": { 2621 + "version": "2.75.0", 2622 + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.75.0.tgz", 2623 + "integrity": "sha512-8UN/vATSgS2JFuJlMVr51L3eUDz+j1m7Ww63wlvHLKULzCDaVWYzvacCjBTLW/lX/vedI2LBI4Vg+01G9ufsJQ==", 2624 + "license": "MIT", 2625 + "dependencies": { 2626 + "@supabase/auth-js": "2.75.0", 2627 + "@supabase/functions-js": "2.75.0", 2628 + "@supabase/node-fetch": "2.6.15", 2629 + "@supabase/postgrest-js": "2.75.0", 2630 + "@supabase/realtime-js": "2.75.0", 2631 + "@supabase/storage-js": "2.75.0" 2632 + } 2633 + }, 2548 2634 "node_modules/@swc/core": { 2549 2635 "version": "1.13.2", 2550 2636 "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.2.tgz", ··· 2907 2993 "version": "22.16.5", 2908 2994 "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", 2909 2995 "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", 2910 - "dev": true, 2911 2996 "license": "MIT", 2912 2997 "dependencies": { 2913 2998 "undici-types": "~6.21.0" 2914 2999 } 2915 3000 }, 3001 + "node_modules/@types/phoenix": { 3002 + "version": "1.6.6", 3003 + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz", 3004 + "integrity": "sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==", 3005 + "license": "MIT" 3006 + }, 2916 3007 "node_modules/@types/prop-types": { 2917 3008 "version": "15.7.13", 2918 3009 "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", 2919 3010 "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", 2920 - "devOptional": true, 3011 + "dev": true, 2921 3012 "license": "MIT" 2922 3013 }, 2923 3014 "node_modules/@types/react": { 2924 3015 "version": "18.3.23", 2925 3016 "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", 2926 3017 "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", 2927 - "devOptional": true, 3018 + "dev": true, 2928 3019 "license": "MIT", 2929 3020 "dependencies": { 2930 3021 "@types/prop-types": "*", ··· 2935 3026 "version": "18.3.7", 2936 3027 "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", 2937 3028 "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", 2938 - "devOptional": true, 3029 + "dev": true, 2939 3030 "license": "MIT", 2940 3031 "peerDependencies": { 2941 3032 "@types/react": "^18.0.0" 3033 + } 3034 + }, 3035 + "node_modules/@types/ws": { 3036 + "version": "8.18.1", 3037 + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", 3038 + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", 3039 + "license": "MIT", 3040 + "dependencies": { 3041 + "@types/node": "*" 2942 3042 } 2943 3043 }, 2944 3044 "node_modules/@typescript-eslint/eslint-plugin": { ··· 3257 3357 "version": "6.1.0", 3258 3358 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", 3259 3359 "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", 3360 + "dev": true, 3260 3361 "license": "MIT", 3261 3362 "engines": { 3262 3363 "node": ">=12" ··· 3269 3370 "version": "4.3.0", 3270 3371 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 3271 3372 "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 3373 + "dev": true, 3272 3374 "license": "MIT", 3273 3375 "dependencies": { 3274 3376 "color-convert": "^2.0.1" ··· 3284 3386 "version": "1.3.0", 3285 3387 "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 3286 3388 "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", 3389 + "dev": true, 3287 3390 "license": "MIT" 3288 3391 }, 3289 3392 "node_modules/anymatch": { 3290 3393 "version": "3.1.3", 3291 3394 "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 3292 3395 "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 3396 + "dev": true, 3293 3397 "license": "ISC", 3294 3398 "dependencies": { 3295 3399 "normalize-path": "^3.0.0", ··· 3303 3407 "version": "5.0.2", 3304 3408 "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 3305 3409 "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", 3410 + "dev": true, 3306 3411 "license": "MIT" 3307 3412 }, 3308 3413 "node_modules/argparse": { ··· 3366 3471 "version": "1.0.2", 3367 3472 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 3368 3473 "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 3474 + "dev": true, 3369 3475 "license": "MIT" 3370 3476 }, 3371 3477 "node_modules/binary-extensions": { 3372 3478 "version": "2.3.0", 3373 3479 "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 3374 3480 "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 3481 + "dev": true, 3375 3482 "license": "MIT", 3376 3483 "engines": { 3377 3484 "node": ">=8" ··· 3395 3502 "version": "3.0.3", 3396 3503 "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 3397 3504 "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 3505 + "dev": true, 3398 3506 "license": "MIT", 3399 3507 "dependencies": { 3400 3508 "fill-range": "^7.1.1" ··· 3450 3558 "version": "2.0.1", 3451 3559 "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", 3452 3560 "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", 3561 + "dev": true, 3453 3562 "license": "MIT", 3454 3563 "engines": { 3455 3564 "node": ">= 6" ··· 3497 3606 "version": "3.6.0", 3498 3607 "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 3499 3608 "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 3609 + "dev": true, 3500 3610 "license": "MIT", 3501 3611 "dependencies": { 3502 3612 "anymatch": "~3.1.2", ··· 3521 3631 "version": "5.1.2", 3522 3632 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 3523 3633 "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 3634 + "dev": true, 3524 3635 "license": "ISC", 3525 3636 "dependencies": { 3526 3637 "is-glob": "^4.0.1" ··· 3569 3680 "version": "2.0.1", 3570 3681 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 3571 3682 "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 3683 + "dev": true, 3572 3684 "license": "MIT", 3573 3685 "dependencies": { 3574 3686 "color-name": "~1.1.4" ··· 3581 3693 "version": "1.1.4", 3582 3694 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 3583 3695 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 3696 + "dev": true, 3584 3697 "license": "MIT" 3585 3698 }, 3586 3699 "node_modules/commander": { 3587 3700 "version": "4.1.1", 3588 3701 "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", 3589 3702 "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", 3703 + "dev": true, 3590 3704 "license": "MIT", 3591 3705 "engines": { 3592 3706 "node": ">= 6" ··· 3603 3717 "version": "7.0.6", 3604 3718 "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 3605 3719 "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 3720 + "dev": true, 3606 3721 "dependencies": { 3607 3722 "path-key": "^3.1.0", 3608 3723 "shebang-command": "^2.0.0", ··· 3616 3731 "version": "3.0.0", 3617 3732 "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 3618 3733 "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 3734 + "dev": true, 3619 3735 "license": "MIT", 3620 3736 "bin": { 3621 3737 "cssesc": "bin/cssesc" ··· 3802 3918 "version": "1.2.2", 3803 3919 "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 3804 3920 "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", 3921 + "dev": true, 3805 3922 "license": "Apache-2.0" 3806 3923 }, 3807 3924 "node_modules/dlv": { 3808 3925 "version": "1.1.3", 3809 3926 "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", 3810 3927 "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 3928 + "dev": true, 3811 3929 "license": "MIT" 3812 3930 }, 3813 3931 "node_modules/dom-helpers": { ··· 3824 3942 "version": "0.2.0", 3825 3943 "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 3826 3944 "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 3945 + "dev": true, 3827 3946 "license": "MIT" 3828 3947 }, 3829 3948 "node_modules/electron-to-chromium": { ··· 3865 3984 "version": "9.2.2", 3866 3985 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 3867 3986 "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 3987 + "dev": true, 3868 3988 "license": "MIT" 3869 3989 }, 3870 3990 "node_modules/esbuild": { ··· 4143 4263 "version": "3.3.2", 4144 4264 "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", 4145 4265 "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", 4266 + "dev": true, 4146 4267 "license": "MIT", 4147 4268 "dependencies": { 4148 4269 "@nodelib/fs.stat": "^2.0.2", ··· 4159 4280 "version": "5.1.2", 4160 4281 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 4161 4282 "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 4283 + "dev": true, 4162 4284 "license": "ISC", 4163 4285 "dependencies": { 4164 4286 "is-glob": "^4.0.1" ··· 4185 4307 "version": "1.17.1", 4186 4308 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", 4187 4309 "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", 4310 + "dev": true, 4188 4311 "license": "ISC", 4189 4312 "dependencies": { 4190 4313 "reusify": "^1.0.4" ··· 4207 4330 "version": "7.1.1", 4208 4331 "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 4209 4332 "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 4333 + "dev": true, 4210 4334 "license": "MIT", 4211 4335 "dependencies": { 4212 4336 "to-regex-range": "^5.0.1" ··· 4257 4381 "version": "3.3.0", 4258 4382 "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", 4259 4383 "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", 4384 + "dev": true, 4260 4385 "license": "ISC", 4261 4386 "dependencies": { 4262 4387 "cross-spawn": "^7.0.0", ··· 4287 4412 "version": "2.3.3", 4288 4413 "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 4289 4414 "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 4415 + "dev": true, 4290 4416 "hasInstallScript": true, 4291 4417 "license": "MIT", 4292 4418 "optional": true, ··· 4301 4427 "version": "1.1.2", 4302 4428 "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 4303 4429 "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 4430 + "dev": true, 4304 4431 "license": "MIT", 4305 4432 "funding": { 4306 4433 "url": "https://github.com/sponsors/ljharb" ··· 4319 4446 "version": "10.4.5", 4320 4447 "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", 4321 4448 "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", 4449 + "dev": true, 4322 4450 "license": "ISC", 4323 4451 "dependencies": { 4324 4452 "foreground-child": "^3.1.0", ··· 4339 4467 "version": "6.0.2", 4340 4468 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 4341 4469 "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 4470 + "dev": true, 4342 4471 "license": "ISC", 4343 4472 "dependencies": { 4344 4473 "is-glob": "^4.0.3" ··· 4351 4480 "version": "2.0.2", 4352 4481 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", 4353 4482 "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", 4483 + "dev": true, 4354 4484 "license": "MIT", 4355 4485 "dependencies": { 4356 4486 "balanced-match": "^1.0.0" ··· 4360 4490 "version": "9.0.5", 4361 4491 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 4362 4492 "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 4493 + "dev": true, 4363 4494 "license": "ISC", 4364 4495 "dependencies": { 4365 4496 "brace-expansion": "^2.0.1" ··· 4405 4536 "version": "2.0.2", 4406 4537 "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 4407 4538 "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 4539 + "dev": true, 4408 4540 "license": "MIT", 4409 4541 "dependencies": { 4410 4542 "function-bind": "^1.1.2" ··· 4473 4605 "version": "2.1.0", 4474 4606 "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 4475 4607 "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 4608 + "dev": true, 4476 4609 "license": "MIT", 4477 4610 "dependencies": { 4478 4611 "binary-extensions": "^2.0.0" ··· 4485 4618 "version": "2.15.1", 4486 4619 "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", 4487 4620 "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", 4621 + "dev": true, 4488 4622 "license": "MIT", 4489 4623 "dependencies": { 4490 4624 "hasown": "^2.0.2" ··· 4500 4634 "version": "2.1.1", 4501 4635 "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 4502 4636 "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 4637 + "dev": true, 4503 4638 "license": "MIT", 4504 4639 "engines": { 4505 4640 "node": ">=0.10.0" ··· 4509 4644 "version": "3.0.0", 4510 4645 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 4511 4646 "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 4647 + "dev": true, 4512 4648 "license": "MIT", 4513 4649 "engines": { 4514 4650 "node": ">=8" ··· 4518 4654 "version": "4.0.3", 4519 4655 "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 4520 4656 "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 4657 + "dev": true, 4521 4658 "license": "MIT", 4522 4659 "dependencies": { 4523 4660 "is-extglob": "^2.1.1" ··· 4530 4667 "version": "7.0.0", 4531 4668 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 4532 4669 "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 4670 + "dev": true, 4533 4671 "license": "MIT", 4534 4672 "engines": { 4535 4673 "node": ">=0.12.0" ··· 4539 4677 "version": "2.0.0", 4540 4678 "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 4541 4679 "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 4680 + "dev": true, 4542 4681 "license": "ISC" 4543 4682 }, 4544 4683 "node_modules/jackspeak": { 4545 4684 "version": "3.4.3", 4546 4685 "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", 4547 4686 "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", 4687 + "dev": true, 4548 4688 "license": "BlueOak-1.0.0", 4549 4689 "dependencies": { 4550 4690 "@isaacs/cliui": "^8.0.2" ··· 4560 4700 "version": "1.21.6", 4561 4701 "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", 4562 4702 "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", 4703 + "dev": true, 4563 4704 "license": "MIT", 4564 4705 "bin": { 4565 4706 "jiti": "bin/jiti.js" ··· 4633 4774 "version": "3.1.3", 4634 4775 "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", 4635 4776 "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", 4777 + "dev": true, 4636 4778 "license": "MIT", 4637 4779 "engines": { 4638 4780 "node": ">=14" ··· 4645 4787 "version": "1.2.4", 4646 4788 "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 4647 4789 "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 4790 + "dev": true, 4648 4791 "license": "MIT" 4649 4792 }, 4650 4793 "node_modules/locate-path": { ··· 5154 5297 "version": "10.4.3", 5155 5298 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 5156 5299 "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 5300 + "dev": true, 5157 5301 "license": "ISC" 5158 5302 }, 5159 5303 "node_modules/lucide-react": { ··· 5178 5322 "version": "1.4.1", 5179 5323 "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 5180 5324 "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 5325 + "dev": true, 5181 5326 "license": "MIT", 5182 5327 "engines": { 5183 5328 "node": ">= 8" ··· 5187 5332 "version": "4.0.8", 5188 5333 "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 5189 5334 "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 5335 + "dev": true, 5190 5336 "license": "MIT", 5191 5337 "dependencies": { 5192 5338 "braces": "^3.0.3", ··· 5213 5359 "version": "7.1.2", 5214 5360 "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", 5215 5361 "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", 5362 + "dev": true, 5216 5363 "license": "ISC", 5217 5364 "engines": { 5218 5365 "node": ">=16 || 14 >=14.17" ··· 5229 5376 "version": "2.7.0", 5230 5377 "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", 5231 5378 "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", 5379 + "dev": true, 5232 5380 "license": "MIT", 5233 5381 "dependencies": { 5234 5382 "any-promise": "^1.0.0", ··· 5240 5388 "version": "3.3.11", 5241 5389 "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", 5242 5390 "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 5391 + "dev": true, 5243 5392 "funding": [ 5244 5393 { 5245 5394 "type": "github", ··· 5282 5431 "version": "3.0.0", 5283 5432 "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 5284 5433 "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 5434 + "dev": true, 5285 5435 "license": "MIT", 5286 5436 "engines": { 5287 5437 "node": ">=0.10.0" ··· 5310 5460 "version": "3.0.0", 5311 5461 "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", 5312 5462 "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", 5463 + "dev": true, 5313 5464 "license": "MIT", 5314 5465 "engines": { 5315 5466 "node": ">= 6" ··· 5369 5520 "version": "1.0.1", 5370 5521 "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", 5371 5522 "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", 5523 + "dev": true, 5372 5524 "license": "BlueOak-1.0.0" 5373 5525 }, 5374 5526 "node_modules/parent-module": { ··· 5398 5550 "version": "3.1.1", 5399 5551 "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 5400 5552 "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 5553 + "dev": true, 5401 5554 "license": "MIT", 5402 5555 "engines": { 5403 5556 "node": ">=8" ··· 5407 5560 "version": "1.0.7", 5408 5561 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 5409 5562 "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 5563 + "dev": true, 5410 5564 "license": "MIT" 5411 5565 }, 5412 5566 "node_modules/path-scurry": { 5413 5567 "version": "1.11.1", 5414 5568 "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 5415 5569 "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 5570 + "dev": true, 5416 5571 "license": "BlueOak-1.0.0", 5417 5572 "dependencies": { 5418 5573 "lru-cache": "^10.2.0", ··· 5429 5584 "version": "1.1.1", 5430 5585 "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 5431 5586 "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 5587 + "dev": true, 5432 5588 "license": "ISC" 5433 5589 }, 5434 5590 "node_modules/picomatch": { 5435 5591 "version": "2.3.1", 5436 5592 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 5437 5593 "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 5594 + "dev": true, 5438 5595 "license": "MIT", 5439 5596 "engines": { 5440 5597 "node": ">=8.6" ··· 5447 5604 "version": "2.3.0", 5448 5605 "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 5449 5606 "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 5607 + "dev": true, 5450 5608 "license": "MIT", 5451 5609 "engines": { 5452 5610 "node": ">=0.10.0" ··· 5456 5614 "version": "4.0.6", 5457 5615 "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", 5458 5616 "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", 5617 + "dev": true, 5459 5618 "license": "MIT", 5460 5619 "engines": { 5461 5620 "node": ">= 6" ··· 5465 5624 "version": "8.5.6", 5466 5625 "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", 5467 5626 "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", 5627 + "dev": true, 5468 5628 "funding": [ 5469 5629 { 5470 5630 "type": "opencollective", ··· 5493 5653 "version": "15.1.0", 5494 5654 "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", 5495 5655 "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", 5656 + "dev": true, 5496 5657 "license": "MIT", 5497 5658 "dependencies": { 5498 5659 "postcss-value-parser": "^4.0.0", ··· 5510 5671 "version": "4.0.1", 5511 5672 "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", 5512 5673 "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", 5674 + "dev": true, 5513 5675 "license": "MIT", 5514 5676 "dependencies": { 5515 5677 "camelcase-css": "^2.0.1" ··· 5529 5691 "version": "4.0.2", 5530 5692 "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", 5531 5693 "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", 5694 + "dev": true, 5532 5695 "funding": [ 5533 5696 { 5534 5697 "type": "opencollective", ··· 5564 5727 "version": "6.2.0", 5565 5728 "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", 5566 5729 "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", 5730 + "dev": true, 5567 5731 "funding": [ 5568 5732 { 5569 5733 "type": "opencollective", ··· 5589 5753 "version": "6.1.2", 5590 5754 "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", 5591 5755 "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", 5756 + "dev": true, 5592 5757 "license": "MIT", 5593 5758 "dependencies": { 5594 5759 "cssesc": "^3.0.0", ··· 5602 5767 "version": "4.2.0", 5603 5768 "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 5604 5769 "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 5770 + "dev": true, 5605 5771 "license": "MIT" 5606 5772 }, 5607 5773 "node_modules/prelude-ls": { ··· 5645 5811 "version": "1.2.3", 5646 5812 "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 5647 5813 "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 5814 + "dev": true, 5648 5815 "funding": [ 5649 5816 { 5650 5817 "type": "github", ··· 5868 6035 "version": "1.0.0", 5869 6036 "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 5870 6037 "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 6038 + "dev": true, 5871 6039 "license": "MIT", 5872 6040 "dependencies": { 5873 6041 "pify": "^2.3.0" ··· 5877 6045 "version": "3.6.0", 5878 6046 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 5879 6047 "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 6048 + "dev": true, 5880 6049 "license": "MIT", 5881 6050 "dependencies": { 5882 6051 "picomatch": "^2.2.1" ··· 5921 6090 "version": "1.22.8", 5922 6091 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 5923 6092 "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 6093 + "dev": true, 5924 6094 "license": "MIT", 5925 6095 "dependencies": { 5926 6096 "is-core-module": "^2.13.0", ··· 5948 6118 "version": "1.0.4", 5949 6119 "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 5950 6120 "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 6121 + "dev": true, 5951 6122 "license": "MIT", 5952 6123 "engines": { 5953 6124 "iojs": ">=1.0.0", ··· 5994 6165 "version": "1.2.0", 5995 6166 "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 5996 6167 "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 6168 + "dev": true, 5997 6169 "funding": [ 5998 6170 { 5999 6171 "type": "github", ··· 6039 6211 "version": "2.0.0", 6040 6212 "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 6041 6213 "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 6214 + "dev": true, 6042 6215 "license": "MIT", 6043 6216 "dependencies": { 6044 6217 "shebang-regex": "^3.0.0" ··· 6051 6224 "version": "3.0.0", 6052 6225 "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 6053 6226 "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 6227 + "dev": true, 6054 6228 "license": "MIT", 6055 6229 "engines": { 6056 6230 "node": ">=8" ··· 6060 6234 "version": "4.1.0", 6061 6235 "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 6062 6236 "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 6237 + "dev": true, 6063 6238 "license": "ISC", 6064 6239 "engines": { 6065 6240 "node": ">=14" ··· 6082 6257 "version": "1.2.1", 6083 6258 "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 6084 6259 "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 6260 + "dev": true, 6085 6261 "license": "BSD-3-Clause", 6086 6262 "engines": { 6087 6263 "node": ">=0.10.0" ··· 6091 6267 "version": "5.1.2", 6092 6268 "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 6093 6269 "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 6270 + "dev": true, 6094 6271 "license": "MIT", 6095 6272 "dependencies": { 6096 6273 "eastasianwidth": "^0.2.0", ··· 6109 6286 "version": "4.2.3", 6110 6287 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 6111 6288 "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 6289 + "dev": true, 6112 6290 "license": "MIT", 6113 6291 "dependencies": { 6114 6292 "emoji-regex": "^8.0.0", ··· 6123 6301 "version": "5.0.1", 6124 6302 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 6125 6303 "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 6304 + "dev": true, 6126 6305 "license": "MIT", 6127 6306 "engines": { 6128 6307 "node": ">=8" ··· 6132 6311 "version": "8.0.0", 6133 6312 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 6134 6313 "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 6314 + "dev": true, 6135 6315 "license": "MIT" 6136 6316 }, 6137 6317 "node_modules/string-width-cjs/node_modules/strip-ansi": { 6138 6318 "version": "6.0.1", 6139 6319 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 6140 6320 "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 6321 + "dev": true, 6141 6322 "license": "MIT", 6142 6323 "dependencies": { 6143 6324 "ansi-regex": "^5.0.1" ··· 6150 6331 "version": "7.1.0", 6151 6332 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 6152 6333 "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 6334 + "dev": true, 6153 6335 "license": "MIT", 6154 6336 "dependencies": { 6155 6337 "ansi-regex": "^6.0.1" ··· 6166 6348 "version": "6.0.1", 6167 6349 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 6168 6350 "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 6351 + "dev": true, 6169 6352 "license": "MIT", 6170 6353 "dependencies": { 6171 6354 "ansi-regex": "^5.0.1" ··· 6178 6361 "version": "5.0.1", 6179 6362 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 6180 6363 "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 6364 + "dev": true, 6181 6365 "license": "MIT", 6182 6366 "engines": { 6183 6367 "node": ">=8" ··· 6200 6384 "version": "3.35.0", 6201 6385 "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", 6202 6386 "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", 6387 + "dev": true, 6203 6388 "license": "MIT", 6204 6389 "dependencies": { 6205 6390 "@jridgewell/gen-mapping": "^0.3.2", ··· 6235 6420 "version": "1.0.0", 6236 6421 "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 6237 6422 "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 6423 + "dev": true, 6238 6424 "license": "MIT", 6239 6425 "engines": { 6240 6426 "node": ">= 0.4" ··· 6257 6443 "version": "3.4.17", 6258 6444 "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", 6259 6445 "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", 6446 + "dev": true, 6260 6447 "license": "MIT", 6261 6448 "dependencies": { 6262 6449 "@alloc/quick-lru": "^5.2.0", ··· 6303 6490 "version": "3.3.1", 6304 6491 "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", 6305 6492 "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", 6493 + "dev": true, 6306 6494 "license": "MIT", 6307 6495 "dependencies": { 6308 6496 "any-promise": "^1.0.0" ··· 6312 6500 "version": "1.6.0", 6313 6501 "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", 6314 6502 "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", 6503 + "dev": true, 6315 6504 "license": "MIT", 6316 6505 "dependencies": { 6317 6506 "thenify": ">= 3.1.0 < 4" ··· 6330 6519 "version": "5.0.1", 6331 6520 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 6332 6521 "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 6522 + "dev": true, 6333 6523 "license": "MIT", 6334 6524 "dependencies": { 6335 6525 "is-number": "^7.0.0" ··· 6338 6528 "node": ">=8.0" 6339 6529 } 6340 6530 }, 6531 + "node_modules/tr46": { 6532 + "version": "0.0.3", 6533 + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 6534 + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 6535 + "license": "MIT" 6536 + }, 6341 6537 "node_modules/ts-api-utils": { 6342 6538 "version": "2.1.0", 6343 6539 "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", ··· 6355 6551 "version": "0.1.13", 6356 6552 "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", 6357 6553 "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", 6554 + "dev": true, 6358 6555 "license": "Apache-2.0" 6359 6556 }, 6360 6557 "node_modules/tslib": { ··· 6418 6615 "version": "6.21.0", 6419 6616 "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", 6420 6617 "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", 6421 - "dev": true, 6422 6618 "license": "MIT" 6423 6619 }, 6424 6620 "node_modules/update-browserslist-db": { ··· 6518 6714 "version": "1.0.2", 6519 6715 "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 6520 6716 "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 6717 + "dev": true, 6521 6718 "license": "MIT" 6522 6719 }, 6523 6720 "node_modules/vaul": { ··· 6615 6812 } 6616 6813 } 6617 6814 }, 6815 + "node_modules/webidl-conversions": { 6816 + "version": "3.0.1", 6817 + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 6818 + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 6819 + "license": "BSD-2-Clause" 6820 + }, 6821 + "node_modules/whatwg-url": { 6822 + "version": "5.0.0", 6823 + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 6824 + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 6825 + "license": "MIT", 6826 + "dependencies": { 6827 + "tr46": "~0.0.3", 6828 + "webidl-conversions": "^3.0.0" 6829 + } 6830 + }, 6618 6831 "node_modules/which": { 6619 6832 "version": "2.0.2", 6620 6833 "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 6621 6834 "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 6835 + "dev": true, 6622 6836 "license": "ISC", 6623 6837 "dependencies": { 6624 6838 "isexe": "^2.0.0" ··· 6644 6858 "version": "8.1.0", 6645 6859 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", 6646 6860 "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", 6861 + "dev": true, 6647 6862 "license": "MIT", 6648 6863 "dependencies": { 6649 6864 "ansi-styles": "^6.1.0", ··· 6662 6877 "version": "7.0.0", 6663 6878 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 6664 6879 "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 6880 + "dev": true, 6665 6881 "license": "MIT", 6666 6882 "dependencies": { 6667 6883 "ansi-styles": "^4.0.0", ··· 6679 6895 "version": "5.0.1", 6680 6896 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 6681 6897 "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 6898 + "dev": true, 6682 6899 "license": "MIT", 6683 6900 "engines": { 6684 6901 "node": ">=8" ··· 6688 6905 "version": "8.0.0", 6689 6906 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 6690 6907 "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 6908 + "dev": true, 6691 6909 "license": "MIT" 6692 6910 }, 6693 6911 "node_modules/wrap-ansi-cjs/node_modules/string-width": { 6694 6912 "version": "4.2.3", 6695 6913 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 6696 6914 "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 6915 + "dev": true, 6697 6916 "license": "MIT", 6698 6917 "dependencies": { 6699 6918 "emoji-regex": "^8.0.0", ··· 6708 6927 "version": "6.0.1", 6709 6928 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 6710 6929 "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 6930 + "dev": true, 6711 6931 "license": "MIT", 6712 6932 "dependencies": { 6713 6933 "ansi-regex": "^5.0.1" ··· 6720 6940 "version": "6.2.1", 6721 6941 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 6722 6942 "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 6943 + "dev": true, 6723 6944 "license": "MIT", 6724 6945 "engines": { 6725 6946 "node": ">=12" ··· 6728 6949 "url": "https://github.com/chalk/ansi-styles?sponsor=1" 6729 6950 } 6730 6951 }, 6952 + "node_modules/ws": { 6953 + "version": "8.18.3", 6954 + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", 6955 + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", 6956 + "license": "MIT", 6957 + "engines": { 6958 + "node": ">=10.0.0" 6959 + }, 6960 + "peerDependencies": { 6961 + "bufferutil": "^4.0.1", 6962 + "utf-8-validate": ">=5.0.2" 6963 + }, 6964 + "peerDependenciesMeta": { 6965 + "bufferutil": { 6966 + "optional": true 6967 + }, 6968 + "utf-8-validate": { 6969 + "optional": true 6970 + } 6971 + } 6972 + }, 6731 6973 "node_modules/yaml": { 6732 6974 "version": "2.6.0", 6733 6975 "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", 6734 6976 "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", 6977 + "dev": true, 6735 6978 "license": "ISC", 6736 6979 "bin": { 6737 6980 "yaml": "bin.mjs"
+1
package.json
··· 39 39 "@radix-ui/react-toggle": "^1.1.9", 40 40 "@radix-ui/react-toggle-group": "^1.1.10", 41 41 "@radix-ui/react-tooltip": "^1.2.7", 42 + "@supabase/supabase-js": "^2.75.0", 42 43 "@tanstack/react-query": "^5.83.0", 43 44 "class-variance-authority": "^0.7.1", 44 45 "clsx": "^2.1.1",
+2
src/App.tsx
··· 4 4 import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 5 5 import { BrowserRouter, Routes, Route } from "react-router-dom"; 6 6 import Index from "./pages/Index"; 7 + import Docs from "./pages/Docs"; 7 8 import NotFound from "./pages/NotFound"; 8 9 9 10 const queryClient = new QueryClient(); ··· 16 17 <BrowserRouter> 17 18 <Routes> 18 19 <Route path="/" element={<Index />} /> 20 + <Route path="/docs" element={<Docs />} /> 19 21 {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} 20 22 <Route path="*" element={<NotFound />} /> 21 23 </Routes>
+9 -1
src/components/SEOTester.tsx
··· 1 1 import React, { useState, useEffect } from 'react'; 2 + import { Link } from 'react-router-dom'; 2 3 import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; 3 4 import { Button } from '@/components/ui/button'; 4 5 import { Input } from '@/components/ui/input'; ··· 6 7 import { Separator } from '@/components/ui/separator'; 7 8 import { Progress } from '@/components/ui/progress'; 8 9 import { useToast } from '@/hooks/use-toast'; 9 - import { Search, ExternalLink, Image, FileText, Tag, Globe, AlertCircle, CheckCircle, Zap, TrendingUp, Eye, Share2, Target, Terminal, Code, Bug, Cpu, Database, Monitor, Server } from 'lucide-react'; 10 + import { Search, ExternalLink, Image, FileText, Tag, Globe, AlertCircle, CheckCircle, Zap, TrendingUp, Eye, Share2, Target, Terminal, Code, Bug, Cpu, Database, Monitor, Server, Book } from 'lucide-react'; 10 11 11 12 interface SEOData { 12 13 title?: string; ··· 285 286 <div className="w-2 h-2 rounded-full bg-success animate-pulse"></div> 286 287 <span className="text-muted-foreground font-mono">dev-tools</span> 287 288 </div> 289 + <Separator orientation="vertical" className="h-4" /> 290 + <Link to="/docs"> 291 + <Button variant="ghost" size="sm" className="text-xs font-mono"> 292 + <Book className="h-3 w-3 mr-1" /> 293 + API Docs 294 + </Button> 295 + </Link> 288 296 </div> 289 297 290 298 <div className="text-left">
+17
src/integrations/supabase/client.ts
··· 1 + // This file is automatically generated. Do not edit it directly. 2 + import { createClient } from '@supabase/supabase-js'; 3 + import type { Database } from './types'; 4 + 5 + const SUPABASE_URL = import.meta.env.VITE_SUPABASE_URL; 6 + const SUPABASE_PUBLISHABLE_KEY = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY; 7 + 8 + // Import the supabase client like this: 9 + // import { supabase } from "@/integrations/supabase/client"; 10 + 11 + export const supabase = createClient<Database>(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, { 12 + auth: { 13 + storage: localStorage, 14 + persistSession: true, 15 + autoRefreshToken: true, 16 + } 17 + });
+155
src/integrations/supabase/types.ts
··· 1 + export type Json = 2 + | string 3 + | number 4 + | boolean 5 + | null 6 + | { [key: string]: Json | undefined } 7 + | Json[] 8 + 9 + export type Database = { 10 + // Allows to automatically instantiate createClient with right options 11 + // instead of createClient<Database, { PostgrestVersion: 'XX' }>(URL, KEY) 12 + __InternalSupabase: { 13 + PostgrestVersion: "13.0.5" 14 + } 15 + public: { 16 + Tables: { 17 + [_ in never]: never 18 + } 19 + Views: { 20 + [_ in never]: never 21 + } 22 + Functions: { 23 + [_ in never]: never 24 + } 25 + Enums: { 26 + [_ in never]: never 27 + } 28 + CompositeTypes: { 29 + [_ in never]: never 30 + } 31 + } 32 + } 33 + 34 + type DatabaseWithoutInternals = Omit<Database, "__InternalSupabase"> 35 + 36 + type DefaultSchema = DatabaseWithoutInternals[Extract<keyof Database, "public">] 37 + 38 + export type Tables< 39 + DefaultSchemaTableNameOrOptions extends 40 + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) 41 + | { schema: keyof DatabaseWithoutInternals }, 42 + TableName extends DefaultSchemaTableNameOrOptions extends { 43 + schema: keyof DatabaseWithoutInternals 44 + } 45 + ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & 46 + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) 47 + : never = never, 48 + > = DefaultSchemaTableNameOrOptions extends { 49 + schema: keyof DatabaseWithoutInternals 50 + } 51 + ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & 52 + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { 53 + Row: infer R 54 + } 55 + ? R 56 + : never 57 + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & 58 + DefaultSchema["Views"]) 59 + ? (DefaultSchema["Tables"] & 60 + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { 61 + Row: infer R 62 + } 63 + ? R 64 + : never 65 + : never 66 + 67 + export type TablesInsert< 68 + DefaultSchemaTableNameOrOptions extends 69 + | keyof DefaultSchema["Tables"] 70 + | { schema: keyof DatabaseWithoutInternals }, 71 + TableName extends DefaultSchemaTableNameOrOptions extends { 72 + schema: keyof DatabaseWithoutInternals 73 + } 74 + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] 75 + : never = never, 76 + > = DefaultSchemaTableNameOrOptions extends { 77 + schema: keyof DatabaseWithoutInternals 78 + } 79 + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { 80 + Insert: infer I 81 + } 82 + ? I 83 + : never 84 + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] 85 + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { 86 + Insert: infer I 87 + } 88 + ? I 89 + : never 90 + : never 91 + 92 + export type TablesUpdate< 93 + DefaultSchemaTableNameOrOptions extends 94 + | keyof DefaultSchema["Tables"] 95 + | { schema: keyof DatabaseWithoutInternals }, 96 + TableName extends DefaultSchemaTableNameOrOptions extends { 97 + schema: keyof DatabaseWithoutInternals 98 + } 99 + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] 100 + : never = never, 101 + > = DefaultSchemaTableNameOrOptions extends { 102 + schema: keyof DatabaseWithoutInternals 103 + } 104 + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { 105 + Update: infer U 106 + } 107 + ? U 108 + : never 109 + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] 110 + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { 111 + Update: infer U 112 + } 113 + ? U 114 + : never 115 + : never 116 + 117 + export type Enums< 118 + DefaultSchemaEnumNameOrOptions extends 119 + | keyof DefaultSchema["Enums"] 120 + | { schema: keyof DatabaseWithoutInternals }, 121 + EnumName extends DefaultSchemaEnumNameOrOptions extends { 122 + schema: keyof DatabaseWithoutInternals 123 + } 124 + ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] 125 + : never = never, 126 + > = DefaultSchemaEnumNameOrOptions extends { 127 + schema: keyof DatabaseWithoutInternals 128 + } 129 + ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] 130 + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] 131 + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] 132 + : never 133 + 134 + export type CompositeTypes< 135 + PublicCompositeTypeNameOrOptions extends 136 + | keyof DefaultSchema["CompositeTypes"] 137 + | { schema: keyof DatabaseWithoutInternals }, 138 + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { 139 + schema: keyof DatabaseWithoutInternals 140 + } 141 + ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] 142 + : never = never, 143 + > = PublicCompositeTypeNameOrOptions extends { 144 + schema: keyof DatabaseWithoutInternals 145 + } 146 + ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] 147 + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] 148 + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] 149 + : never 150 + 151 + export const Constants = { 152 + public: { 153 + Enums: {}, 154 + }, 155 + } as const
+380
src/pages/Docs.tsx
··· 1 + import React, { useState } from 'react'; 2 + import { Card, CardContent, CardHeader } from '@/components/ui/card'; 3 + import { Button } from '@/components/ui/button'; 4 + import { Separator } from '@/components/ui/separator'; 5 + import { Badge } from '@/components/ui/badge'; 6 + import { Code, Terminal, Book, ChevronRight, Copy, Check, Home } from 'lucide-react'; 7 + import { useToast } from '@/hooks/use-toast'; 8 + import { Link } from 'react-router-dom'; 9 + 10 + const Docs = () => { 11 + const [copiedSection, setCopiedSection] = useState<string | null>(null); 12 + const { toast } = useToast(); 13 + 14 + const copyToClipboard = (text: string, section: string) => { 15 + navigator.clipboard.writeText(text); 16 + setCopiedSection(section); 17 + setTimeout(() => setCopiedSection(null), 2000); 18 + toast({ 19 + title: "Copied!", 20 + description: "Code copied to clipboard", 21 + }); 22 + }; 23 + 24 + const apiUrl = 'https://gjhfnqiknusundbktwxs.supabase.co/functions/v1/analyze-seo'; 25 + 26 + return ( 27 + <div className="min-h-screen bg-background"> 28 + <div className="absolute inset-0 opacity-5"> 29 + <div className="absolute inset-0" style={{ 30 + backgroundImage: `radial-gradient(circle at 1px 1px, rgb(255,255,255) 1px, transparent 0)`, 31 + backgroundSize: '20px 20px' 32 + }}></div> 33 + </div> 34 + 35 + <div className="container mx-auto px-4 py-8 relative z-10"> 36 + <div className="max-w-4xl mx-auto"> 37 + {/* Header */} 38 + <div className="mb-8 animate-fade-in"> 39 + <Link to="/" className="inline-flex items-center gap-2 text-sm font-mono text-muted-foreground hover:text-foreground mb-4"> 40 + <Home className="h-4 w-4" /> 41 + Back to SEO Tester 42 + </Link> 43 + 44 + <div className="flex items-center gap-3 mb-4 p-4 bg-muted/50 rounded-lg border border-border/50"> 45 + <Terminal className="h-5 w-5 text-primary" /> 46 + <div className="flex items-center gap-1 text-xs font-mono"> 47 + <span className="text-primary">$</span> 48 + <span className="text-muted-foreground">api-documentation</span> 49 + </div> 50 + </div> 51 + 52 + <h1 className="text-3xl font-bold text-foreground font-mono flex items-center gap-2"> 53 + <Book className="h-8 w-8 text-primary" /> 54 + SEO Analyzer API 55 + </h1> 56 + <p className="text-sm text-muted-foreground font-mono mt-2"> 57 + → RESTful API for programmatic SEO analysis 58 + </p> 59 + </div> 60 + 61 + {/* Quick Start */} 62 + <Card className="mb-6 border border-border bg-card"> 63 + <CardHeader className="pb-3"> 64 + <div className="flex items-center justify-between"> 65 + <div className="flex items-center gap-2"> 66 + <Code className="h-4 w-4 text-primary" /> 67 + <span className="font-mono text-sm">Quick Start</span> 68 + </div> 69 + <Badge variant="outline" className="font-mono text-xs">GET STARTED</Badge> 70 + </div> 71 + </CardHeader> 72 + <CardContent className="space-y-4"> 73 + <div> 74 + <div className="flex items-center justify-between mb-2"> 75 + <span className="text-xs font-mono text-muted-foreground">ENDPOINT</span> 76 + </div> 77 + <div className="bg-muted/30 p-3 rounded font-mono text-sm border border-border/50 flex items-center justify-between"> 78 + <code className="text-primary break-all">{apiUrl}</code> 79 + <Button 80 + size="sm" 81 + variant="ghost" 82 + onClick={() => copyToClipboard(apiUrl, 'endpoint')} 83 + className="ml-2" 84 + > 85 + {copiedSection === 'endpoint' ? ( 86 + <Check className="h-4 w-4 text-green-500" /> 87 + ) : ( 88 + <Copy className="h-4 w-4" /> 89 + )} 90 + </Button> 91 + </div> 92 + </div> 93 + 94 + <div> 95 + <div className="flex items-center gap-2 mb-2"> 96 + <Badge variant="default" className="bg-green-600 text-xs">POST</Badge> 97 + <span className="text-xs font-mono text-muted-foreground">METHOD</span> 98 + </div> 99 + </div> 100 + </CardContent> 101 + </Card> 102 + 103 + {/* Request Format */} 104 + <Card className="mb-6 border border-border bg-card"> 105 + <CardHeader className="pb-3"> 106 + <div className="flex items-center gap-2"> 107 + <ChevronRight className="h-4 w-4 text-primary" /> 108 + <span className="font-mono text-sm">Request Format</span> 109 + </div> 110 + </CardHeader> 111 + <CardContent className="space-y-4"> 112 + <div> 113 + <div className="text-xs font-mono text-muted-foreground mb-2">HEADERS</div> 114 + <div className="bg-muted/30 p-3 rounded font-mono text-sm border border-border/50"> 115 + <div className="text-muted-foreground">Content-Type: <span className="text-foreground">application/json</span></div> 116 + </div> 117 + </div> 118 + 119 + <div> 120 + <div className="flex items-center justify-between mb-2"> 121 + <span className="text-xs font-mono text-muted-foreground">REQUEST BODY</span> 122 + <Button 123 + size="sm" 124 + variant="ghost" 125 + onClick={() => copyToClipboard('{\n "url": "https://example.com"\n}', 'request')} 126 + > 127 + {copiedSection === 'request' ? ( 128 + <Check className="h-4 w-4 text-green-500" /> 129 + ) : ( 130 + <Copy className="h-4 w-4" /> 131 + )} 132 + </Button> 133 + </div> 134 + <pre className="bg-muted/30 p-4 rounded font-mono text-sm border border-border/50 overflow-x-auto"> 135 + {`{ 136 + "url": "https://example.com" 137 + }`} 138 + </pre> 139 + </div> 140 + </CardContent> 141 + </Card> 142 + 143 + {/* Response Format */} 144 + <Card className="mb-6 border border-border bg-card"> 145 + <CardHeader className="pb-3"> 146 + <div className="flex items-center gap-2"> 147 + <ChevronRight className="h-4 w-4 text-primary" /> 148 + <span className="font-mono text-sm">Response Format</span> 149 + </div> 150 + </CardHeader> 151 + <CardContent> 152 + <div className="flex items-center justify-between mb-2"> 153 + <span className="text-xs font-mono text-muted-foreground">SUCCESS RESPONSE (200)</span> 154 + <Button 155 + size="sm" 156 + variant="ghost" 157 + onClick={() => copyToClipboard(`{ 158 + "success": true, 159 + "data": { 160 + "title": "Page Title", 161 + "description": "Meta description", 162 + "ogTitle": "OG Title", 163 + "ogDescription": "OG Description", 164 + "ogImage": "https://example.com/image.jpg", 165 + "ogType": "website", 166 + "twitterCard": "summary_large_image", 167 + "h1": "Main Heading", 168 + "canonical": "https://example.com", 169 + "lang": "en", 170 + "viewport": "width=device-width, initial-scale=1", 171 + "charset": "UTF-8", 172 + "metaRobots": "index,follow" 173 + }, 174 + "score": { 175 + "total": 85, 176 + "breakdown": { 177 + "basic": 35, 178 + "social": 30, 179 + "technical": 20 180 + } 181 + } 182 + }`, 'response')} 183 + > 184 + {copiedSection === 'response' ? ( 185 + <Check className="h-4 w-4 text-green-500" /> 186 + ) : ( 187 + <Copy className="h-4 w-4" /> 188 + )} 189 + </Button> 190 + </div> 191 + <pre className="bg-muted/30 p-4 rounded font-mono text-xs border border-border/50 overflow-x-auto max-h-96"> 192 + {`{ 193 + "success": true, 194 + "data": { 195 + "title": "Page Title", 196 + "description": "Meta description", 197 + "ogTitle": "OG Title", 198 + "ogDescription": "OG Description", 199 + "ogImage": "https://example.com/image.jpg", 200 + "ogType": "website", 201 + "twitterCard": "summary_large_image", 202 + "twitterTitle": "Twitter Title", 203 + "twitterDescription": "Twitter Description", 204 + "twitterImage": "https://example.com/image.jpg", 205 + "h1": "Main Heading", 206 + "canonical": "https://example.com", 207 + "keywords": "keyword1, keyword2", 208 + "lang": "en", 209 + "viewport": "width=device-width, initial-scale=1", 210 + "charset": "UTF-8", 211 + "metaRobots": "index,follow", 212 + "url": "https://example.com" 213 + }, 214 + "score": { 215 + "total": 85, 216 + "breakdown": { 217 + "basic": 35, 218 + "social": 30, 219 + "technical": 20 220 + } 221 + } 222 + }`} 223 + </pre> 224 + </CardContent> 225 + </Card> 226 + 227 + {/* Code Examples */} 228 + <Card className="mb-6 border border-border bg-card"> 229 + <CardHeader className="pb-3"> 230 + <div className="flex items-center gap-2"> 231 + <Code className="h-4 w-4 text-primary" /> 232 + <span className="font-mono text-sm">Code Examples</span> 233 + </div> 234 + </CardHeader> 235 + <CardContent className="space-y-6"> 236 + {/* JavaScript/Fetch */} 237 + <div> 238 + <div className="flex items-center justify-between mb-2"> 239 + <span className="text-xs font-mono text-muted-foreground">JAVASCRIPT (FETCH)</span> 240 + <Button 241 + size="sm" 242 + variant="ghost" 243 + onClick={() => copyToClipboard(`fetch('${apiUrl}', { 244 + method: 'POST', 245 + headers: { 246 + 'Content-Type': 'application/json', 247 + }, 248 + body: JSON.stringify({ 249 + url: 'https://example.com' 250 + }) 251 + }) 252 + .then(response => response.json()) 253 + .then(data => console.log(data)) 254 + .catch(error => console.error('Error:', error));`, 'js-fetch')} 255 + > 256 + {copiedSection === 'js-fetch' ? ( 257 + <Check className="h-4 w-4 text-green-500" /> 258 + ) : ( 259 + <Copy className="h-4 w-4" /> 260 + )} 261 + </Button> 262 + </div> 263 + <pre className="bg-muted/30 p-4 rounded font-mono text-xs border border-border/50 overflow-x-auto"> 264 + {`fetch('${apiUrl}', { 265 + method: 'POST', 266 + headers: { 267 + 'Content-Type': 'application/json', 268 + }, 269 + body: JSON.stringify({ 270 + url: 'https://example.com' 271 + }) 272 + }) 273 + .then(response => response.json()) 274 + .then(data => console.log(data)) 275 + .catch(error => console.error('Error:', error));`} 276 + </pre> 277 + </div> 278 + 279 + <Separator /> 280 + 281 + {/* cURL */} 282 + <div> 283 + <div className="flex items-center justify-between mb-2"> 284 + <span className="text-xs font-mono text-muted-foreground">CURL</span> 285 + <Button 286 + size="sm" 287 + variant="ghost" 288 + onClick={() => copyToClipboard(`curl -X POST '${apiUrl}' \\ 289 + -H 'Content-Type: application/json' \\ 290 + -d '{"url": "https://example.com"}'`, 'curl')} 291 + > 292 + {copiedSection === 'curl' ? ( 293 + <Check className="h-4 w-4 text-green-500" /> 294 + ) : ( 295 + <Copy className="h-4 w-4" /> 296 + )} 297 + </Button> 298 + </div> 299 + <pre className="bg-muted/30 p-4 rounded font-mono text-xs border border-border/50 overflow-x-auto"> 300 + {`curl -X POST '${apiUrl}' \\ 301 + -H 'Content-Type: application/json' \\ 302 + -d '{"url": "https://example.com"}'`} 303 + </pre> 304 + </div> 305 + 306 + <Separator /> 307 + 308 + {/* Python */} 309 + <div> 310 + <div className="flex items-center justify-between mb-2"> 311 + <span className="text-xs font-mono text-muted-foreground">PYTHON</span> 312 + <Button 313 + size="sm" 314 + variant="ghost" 315 + onClick={() => copyToClipboard(`import requests 316 + 317 + url = "${apiUrl}" 318 + payload = {"url": "https://example.com"} 319 + headers = {"Content-Type": "application/json"} 320 + 321 + response = requests.post(url, json=payload, headers=headers) 322 + print(response.json())`, 'python')} 323 + > 324 + {copiedSection === 'python' ? ( 325 + <Check className="h-4 w-4 text-green-500" /> 326 + ) : ( 327 + <Copy className="h-4 w-4" /> 328 + )} 329 + </Button> 330 + </div> 331 + <pre className="bg-muted/30 p-4 rounded font-mono text-xs border border-border/50 overflow-x-auto"> 332 + {`import requests 333 + 334 + url = "${apiUrl}" 335 + payload = {"url": "https://example.com"} 336 + headers = {"Content-Type": "application/json"} 337 + 338 + response = requests.post(url, json=payload, headers=headers) 339 + print(response.json())`} 340 + </pre> 341 + </div> 342 + </CardContent> 343 + </Card> 344 + 345 + {/* Error Responses */} 346 + <Card className="border border-border bg-card"> 347 + <CardHeader className="pb-3"> 348 + <div className="flex items-center gap-2"> 349 + <Terminal className="h-4 w-4 text-destructive" /> 350 + <span className="font-mono text-sm">Error Responses</span> 351 + </div> 352 + </CardHeader> 353 + <CardContent className="space-y-4"> 354 + <div> 355 + <Badge variant="destructive" className="text-xs mb-2">400 BAD REQUEST</Badge> 356 + <pre className="bg-muted/30 p-3 rounded font-mono text-xs border border-border/50"> 357 + {`{ 358 + "error": "URL parameter is required" 359 + }`} 360 + </pre> 361 + </div> 362 + 363 + <div> 364 + <Badge variant="destructive" className="text-xs mb-2">500 INTERNAL ERROR</Badge> 365 + <pre className="bg-muted/30 p-3 rounded font-mono text-xs border border-border/50"> 366 + {`{ 367 + "success": false, 368 + "error": "Failed to fetch website" 369 + }`} 370 + </pre> 371 + </div> 372 + </CardContent> 373 + </Card> 374 + </div> 375 + </div> 376 + </div> 377 + ); 378 + }; 379 + 380 + export default Docs;
+1
supabase/config.toml
··· 1 + project_id = "gjhfnqiknusundbktwxs"
+191
supabase/functions/analyze-seo/index.ts
··· 1 + import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; 2 + 3 + const corsHeaders = { 4 + 'Access-Control-Allow-Origin': '*', 5 + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', 6 + }; 7 + 8 + interface SEOData { 9 + title?: string; 10 + description?: string; 11 + ogTitle?: string; 12 + ogDescription?: string; 13 + ogImage?: string; 14 + ogType?: string; 15 + twitterCard?: string; 16 + twitterTitle?: string; 17 + twitterDescription?: string; 18 + twitterImage?: string; 19 + canonical?: string; 20 + keywords?: string; 21 + url: string; 22 + h1?: string; 23 + metaRobots?: string; 24 + lang?: string; 25 + viewport?: string; 26 + charset?: string; 27 + } 28 + 29 + interface SEOScore { 30 + total: number; 31 + breakdown: { 32 + basic: number; 33 + social: number; 34 + technical: number; 35 + }; 36 + } 37 + 38 + const extractMetaData = (html: string, url: string): SEOData => { 39 + const parser = new DOMParser(); 40 + const doc = parser.parseFromString(html, 'text/html'); 41 + 42 + const getMetaContent = (name: string, property?: string) => { 43 + if (property) { 44 + const element = doc.querySelector(`meta[property="${property}"]`); 45 + return element?.getAttribute('content') || ''; 46 + } 47 + const element = doc.querySelector(`meta[name="${name}"]`) || 48 + doc.querySelector(`meta[property="${name}"]`); 49 + return element?.getAttribute('content') || ''; 50 + }; 51 + 52 + const title = doc.querySelector('title')?.textContent || ''; 53 + const canonical = doc.querySelector('link[rel="canonical"]')?.getAttribute('href') || ''; 54 + const h1 = doc.querySelector('h1')?.textContent || ''; 55 + const htmlElement = doc.querySelector('html'); 56 + const lang = htmlElement?.getAttribute('lang') || ''; 57 + 58 + return { 59 + title, 60 + description: getMetaContent('description'), 61 + ogTitle: getMetaContent('', 'og:title'), 62 + ogDescription: getMetaContent('', 'og:description'), 63 + ogImage: getMetaContent('', 'og:image'), 64 + ogType: getMetaContent('', 'og:type'), 65 + twitterCard: getMetaContent('twitter:card'), 66 + twitterTitle: getMetaContent('twitter:title'), 67 + twitterDescription: getMetaContent('twitter:description'), 68 + twitterImage: getMetaContent('twitter:image'), 69 + canonical, 70 + keywords: getMetaContent('keywords'), 71 + h1, 72 + metaRobots: getMetaContent('robots'), 73 + lang, 74 + viewport: getMetaContent('viewport'), 75 + charset: doc.querySelector('meta[charset]')?.getAttribute('charset') || '', 76 + url 77 + }; 78 + }; 79 + 80 + const calculateSEOScore = (data: SEOData): SEOScore => { 81 + let basicScore = 0; 82 + let socialScore = 0; 83 + let technicalScore = 0; 84 + 85 + // Basic SEO (40 points max) 86 + if (data.title) basicScore += 15; 87 + if (data.description) basicScore += 15; 88 + if (data.h1) basicScore += 10; 89 + 90 + // Social Media (30 points max) 91 + if (data.ogTitle || data.title) socialScore += 8; 92 + if (data.ogDescription || data.description) socialScore += 8; 93 + if (data.ogImage) socialScore += 14; 94 + 95 + // Technical SEO (30 points max) 96 + if (data.canonical) technicalScore += 10; 97 + if (data.lang) technicalScore += 5; 98 + if (data.viewport) technicalScore += 5; 99 + if (data.charset) technicalScore += 5; 100 + if (!data.metaRobots || !data.metaRobots.includes('noindex')) technicalScore += 5; 101 + 102 + const total = basicScore + socialScore + technicalScore; 103 + 104 + return { 105 + total, 106 + breakdown: { 107 + basic: basicScore, 108 + social: socialScore, 109 + technical: technicalScore 110 + } 111 + }; 112 + }; 113 + 114 + serve(async (req) => { 115 + // Handle CORS preflight requests 116 + if (req.method === 'OPTIONS') { 117 + return new Response(null, { headers: corsHeaders }); 118 + } 119 + 120 + try { 121 + const { url } = await req.json(); 122 + 123 + if (!url) { 124 + return new Response( 125 + JSON.stringify({ error: 'URL parameter is required' }), 126 + { 127 + status: 400, 128 + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, 129 + } 130 + ); 131 + } 132 + 133 + console.log('Analyzing SEO for URL:', url); 134 + 135 + // Validate URL 136 + try { 137 + new URL(url); 138 + } catch { 139 + return new Response( 140 + JSON.stringify({ error: 'Invalid URL format' }), 141 + { 142 + status: 400, 143 + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, 144 + } 145 + ); 146 + } 147 + 148 + // Fetch website content 149 + const proxyUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(url)}`; 150 + const response = await fetch(proxyUrl); 151 + 152 + if (!response.ok) { 153 + throw new Error(`Failed to fetch website: ${response.status}`); 154 + } 155 + 156 + const data = await response.json(); 157 + 158 + if (!data.contents) { 159 + throw new Error('No content received from the website'); 160 + } 161 + 162 + // Extract and analyze SEO data 163 + const seoData = extractMetaData(data.contents, url); 164 + const seoScore = calculateSEOScore(seoData); 165 + 166 + console.log('SEO analysis completed successfully'); 167 + 168 + return new Response( 169 + JSON.stringify({ 170 + success: true, 171 + data: seoData, 172 + score: seoScore, 173 + }), 174 + { 175 + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, 176 + } 177 + ); 178 + } catch (error) { 179 + console.error('Error in analyze-seo function:', error); 180 + return new Response( 181 + JSON.stringify({ 182 + success: false, 183 + error: error instanceof Error ? error.message : 'Internal server error', 184 + }), 185 + { 186 + status: 500, 187 + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, 188 + } 189 + ); 190 + } 191 + });