this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

reorder some things

+1087 -521
+6
package.json
··· 35 35 "postgres": "^3.4.9", 36 36 "react": "^19.2.5", 37 37 "react-dom": "^19.2.5", 38 + "rehype-raw": "^7.0.0", 39 + "rehype-react": "^8.0.0", 40 + "remark-gfm": "^4.0.1", 41 + "remark-parse": "^11.0.0", 42 + "remark-rehype": "^11.1.2", 38 43 "tailwind-merge": "^3.5.0", 39 44 "tailwindcss": "^4.2.4", 40 45 "tailwindcss-animate": "^1.0.7", 41 46 "tsx": "^4.21.0", 47 + "unified": "^11.0.5", 42 48 "valibot": "^1.3.1" 43 49 }, 44 50 "devDependencies": {
+947
pnpm-lock.yaml
··· 78 78 react-dom: 79 79 specifier: ^19.2.5 80 80 version: 19.2.5(react@19.2.5) 81 + rehype-raw: 82 + specifier: ^7.0.0 83 + version: 7.0.0 84 + rehype-react: 85 + specifier: ^8.0.0 86 + version: 8.0.0 87 + remark-gfm: 88 + specifier: ^4.0.1 89 + version: 4.0.1 90 + remark-parse: 91 + specifier: ^11.0.0 92 + version: 11.0.0 93 + remark-rehype: 94 + specifier: ^11.1.2 95 + version: 11.1.2 81 96 tailwind-merge: 82 97 specifier: ^3.5.0 83 98 version: 3.5.0 ··· 90 105 tsx: 91 106 specifier: ^4.21.0 92 107 version: 4.21.0 108 + unified: 109 + specifier: ^11.0.5 110 + version: 11.0.5 93 111 valibot: 94 112 specifier: ^1.3.1 95 113 version: 1.3.1(typescript@6.0.3) ··· 2271 2289 '@types/chai@5.2.3': 2272 2290 resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} 2273 2291 2292 + '@types/debug@4.1.13': 2293 + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} 2294 + 2274 2295 '@types/deep-eql@4.0.2': 2275 2296 resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 2297 + 2298 + '@types/estree-jsx@1.0.5': 2299 + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} 2276 2300 2277 2301 '@types/estree@1.0.8': 2278 2302 resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 2279 2303 2304 + '@types/hast@3.0.4': 2305 + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} 2306 + 2307 + '@types/mdast@4.0.4': 2308 + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} 2309 + 2310 + '@types/ms@2.1.0': 2311 + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} 2312 + 2280 2313 '@types/node@25.6.0': 2281 2314 resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} 2282 2315 ··· 2296 2329 2297 2330 '@types/triple-beam@1.3.5': 2298 2331 resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} 2332 + 2333 + '@types/unist@2.0.11': 2334 + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} 2335 + 2336 + '@types/unist@3.0.3': 2337 + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} 2299 2338 2300 2339 '@types/yauzl@2.10.3': 2301 2340 resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} ··· 2364 2403 '@typescript/native-preview@7.0.0-dev.20260421.2': 2365 2404 resolution: {integrity: sha512-CmajHI25HpVWE9R1XFoxr+cphJPxoYD3eFioQtAvXYkMFKnLdICMS9pXre9Pybizb75ejRxjKD5/CVG055rEIg==} 2366 2405 hasBin: true 2406 + 2407 + '@ungap/structured-clone@1.3.0': 2408 + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} 2367 2409 2368 2410 '@vercel/nft@0.29.4': 2369 2411 resolution: {integrity: sha512-6lLqMNX3TuycBPABycx7A9F1bHQR7kiQln6abjFbPrf5C/05qHM9M5E4PeTE59c7z8g6vHnx1Ioihb2AQl7BTA==} ··· 2682 2724 babel-dead-code-elimination@1.0.12: 2683 2725 resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} 2684 2726 2727 + bail@2.0.2: 2728 + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} 2729 + 2685 2730 balanced-match@1.0.2: 2686 2731 resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 2687 2732 ··· 2804 2849 caniuse-lite@1.0.30001791: 2805 2850 resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==} 2806 2851 2852 + ccount@2.0.1: 2853 + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} 2854 + 2807 2855 chalk@4.1.2: 2808 2856 resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 2809 2857 engines: {node: '>=10'} ··· 2811 2859 chalk@5.6.2: 2812 2860 resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} 2813 2861 engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 2862 + 2863 + character-entities-html4@2.1.0: 2864 + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} 2865 + 2866 + character-entities-legacy@3.0.0: 2867 + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} 2868 + 2869 + character-entities@2.0.2: 2870 + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} 2871 + 2872 + character-reference-invalid@2.0.1: 2873 + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} 2814 2874 2815 2875 cheerio-select@2.1.0: 2816 2876 resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} ··· 2878 2938 resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} 2879 2939 engines: {node: '>=18'} 2880 2940 2941 + comma-separated-tokens@2.0.3: 2942 + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} 2943 + 2881 2944 commander@10.0.1: 2882 2945 resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} 2883 2946 engines: {node: '>=14'} ··· 3011 3074 decache@4.6.2: 3012 3075 resolution: {integrity: sha512-2LPqkLeu8XWHU8qNCS3kcF6sCcb5zIzvWaAHYSvPfwhdd7mHuah29NssMzrTYyHN4F5oFy2ko9OBYxegtU0FEw==} 3013 3076 3077 + decode-named-character-reference@1.3.0: 3078 + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} 3079 + 3014 3080 dedent@1.7.2: 3015 3081 resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} 3016 3082 peerDependencies: ··· 3033 3099 3034 3100 defu@6.1.7: 3035 3101 resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} 3102 + 3103 + dequal@2.0.3: 3104 + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 3105 + engines: {node: '>=6'} 3036 3106 3037 3107 destr@2.0.5: 3038 3108 resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} ··· 3086 3156 3087 3157 dettle@1.0.5: 3088 3158 resolution: {integrity: sha512-ZVyjhAJ7sCe1PNXEGveObOH9AC8QvMga3HJIghHawtG7mE4K5pW9nz/vDGAr/U7a3LWgdOzEE7ac9MURnyfaTA==} 3159 + 3160 + devlop@1.1.0: 3161 + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} 3089 3162 3090 3163 diff@8.0.4: 3091 3164 resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} ··· 3362 3435 resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 3363 3436 engines: {node: '>=4.0'} 3364 3437 3438 + estree-util-is-identifier-name@3.0.0: 3439 + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} 3440 + 3365 3441 estree-walker@2.0.2: 3366 3442 resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 3367 3443 ··· 3393 3469 3394 3470 exsolve@1.0.8: 3395 3471 resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} 3472 + 3473 + extend@3.0.2: 3474 + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} 3396 3475 3397 3476 extract-zip@2.0.1: 3398 3477 resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} ··· 3618 3697 resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} 3619 3698 engines: {node: '>= 0.4'} 3620 3699 3700 + hast-util-from-parse5@8.0.3: 3701 + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} 3702 + 3703 + hast-util-parse-selector@4.0.0: 3704 + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} 3705 + 3706 + hast-util-raw@9.1.0: 3707 + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} 3708 + 3709 + hast-util-to-jsx-runtime@2.3.6: 3710 + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} 3711 + 3712 + hast-util-to-parse5@8.0.1: 3713 + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} 3714 + 3715 + hast-util-whitespace@3.0.0: 3716 + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} 3717 + 3718 + hastscript@9.0.1: 3719 + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} 3720 + 3621 3721 hosted-git-info@7.0.2: 3622 3722 resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} 3623 3723 engines: {node: ^16.14.0 || >=18.0.0} 3624 3724 3725 + html-void-elements@3.0.0: 3726 + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} 3727 + 3625 3728 htmlparser2@10.1.0: 3626 3729 resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} 3627 3730 ··· 3670 3773 inherits@2.0.4: 3671 3774 resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 3672 3775 3776 + inline-style-parser@0.2.7: 3777 + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} 3778 + 3673 3779 internal-slot@1.1.0: 3674 3780 resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} 3675 3781 engines: {node: '>= 0.4'} ··· 3681 3787 iron-webcrypto@1.2.1: 3682 3788 resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} 3683 3789 3790 + is-alphabetical@2.0.1: 3791 + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} 3792 + 3793 + is-alphanumerical@2.0.1: 3794 + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} 3795 + 3684 3796 is-array-buffer@3.0.5: 3685 3797 resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} 3686 3798 engines: {node: '>= 0.4'} ··· 3717 3829 resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} 3718 3830 engines: {node: '>= 0.4'} 3719 3831 3832 + is-decimal@2.0.1: 3833 + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} 3834 + 3720 3835 is-extglob@2.1.1: 3721 3836 resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 3722 3837 engines: {node: '>=0.10.0'} ··· 3736 3851 is-glob@4.0.3: 3737 3852 resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 3738 3853 engines: {node: '>=0.10.0'} 3854 + 3855 + is-hexadecimal@2.0.1: 3856 + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} 3739 3857 3740 3858 is-map@2.0.3: 3741 3859 resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} ··· 4036 4154 resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} 4037 4155 engines: {node: '>= 12.0.0'} 4038 4156 4157 + longest-streak@3.1.0: 4158 + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} 4159 + 4039 4160 lru-cache@10.4.3: 4040 4161 resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 4041 4162 ··· 4057 4178 resolution: {integrity: sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==} 4058 4179 engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 4059 4180 4181 + markdown-table@3.0.4: 4182 + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} 4183 + 4060 4184 math-intrinsics@1.1.0: 4061 4185 resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 4062 4186 engines: {node: '>= 0.4'} 4063 4187 4188 + mdast-util-find-and-replace@3.0.2: 4189 + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} 4190 + 4191 + mdast-util-from-markdown@2.0.3: 4192 + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} 4193 + 4194 + mdast-util-gfm-autolink-literal@2.0.1: 4195 + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} 4196 + 4197 + mdast-util-gfm-footnote@2.1.0: 4198 + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} 4199 + 4200 + mdast-util-gfm-strikethrough@2.0.0: 4201 + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} 4202 + 4203 + mdast-util-gfm-table@2.0.0: 4204 + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} 4205 + 4206 + mdast-util-gfm-task-list-item@2.0.0: 4207 + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} 4208 + 4209 + mdast-util-gfm@3.1.0: 4210 + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} 4211 + 4212 + mdast-util-mdx-expression@2.0.1: 4213 + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} 4214 + 4215 + mdast-util-mdx-jsx@3.2.0: 4216 + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} 4217 + 4218 + mdast-util-mdxjs-esm@2.0.1: 4219 + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} 4220 + 4221 + mdast-util-phrasing@4.1.0: 4222 + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} 4223 + 4224 + mdast-util-to-hast@13.2.1: 4225 + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} 4226 + 4227 + mdast-util-to-markdown@2.1.2: 4228 + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} 4229 + 4230 + mdast-util-to-string@4.0.0: 4231 + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} 4232 + 4064 4233 mdn-data@2.0.28: 4065 4234 resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} 4066 4235 ··· 4078 4247 resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 4079 4248 engines: {node: '>= 8'} 4080 4249 4250 + micromark-core-commonmark@2.0.3: 4251 + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} 4252 + 4253 + micromark-extension-gfm-autolink-literal@2.1.0: 4254 + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} 4255 + 4256 + micromark-extension-gfm-footnote@2.1.0: 4257 + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} 4258 + 4259 + micromark-extension-gfm-strikethrough@2.1.0: 4260 + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} 4261 + 4262 + micromark-extension-gfm-table@2.1.1: 4263 + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} 4264 + 4265 + micromark-extension-gfm-tagfilter@2.0.0: 4266 + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} 4267 + 4268 + micromark-extension-gfm-task-list-item@2.1.0: 4269 + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} 4270 + 4271 + micromark-extension-gfm@3.0.0: 4272 + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} 4273 + 4274 + micromark-factory-destination@2.0.1: 4275 + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} 4276 + 4277 + micromark-factory-label@2.0.1: 4278 + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} 4279 + 4280 + micromark-factory-space@2.0.1: 4281 + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} 4282 + 4283 + micromark-factory-title@2.0.1: 4284 + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} 4285 + 4286 + micromark-factory-whitespace@2.0.1: 4287 + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} 4288 + 4289 + micromark-util-character@2.1.1: 4290 + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} 4291 + 4292 + micromark-util-chunked@2.0.1: 4293 + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} 4294 + 4295 + micromark-util-classify-character@2.0.1: 4296 + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} 4297 + 4298 + micromark-util-combine-extensions@2.0.1: 4299 + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} 4300 + 4301 + micromark-util-decode-numeric-character-reference@2.0.2: 4302 + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} 4303 + 4304 + micromark-util-decode-string@2.0.1: 4305 + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} 4306 + 4307 + micromark-util-encode@2.0.1: 4308 + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} 4309 + 4310 + micromark-util-html-tag-name@2.0.1: 4311 + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} 4312 + 4313 + micromark-util-normalize-identifier@2.0.1: 4314 + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} 4315 + 4316 + micromark-util-resolve-all@2.0.1: 4317 + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} 4318 + 4319 + micromark-util-sanitize-uri@2.0.1: 4320 + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} 4321 + 4322 + micromark-util-subtokenize@2.1.0: 4323 + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} 4324 + 4325 + micromark-util-symbol@2.0.1: 4326 + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} 4327 + 4328 + micromark-util-types@2.0.2: 4329 + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} 4330 + 4331 + micromark@4.0.2: 4332 + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} 4333 + 4081 4334 micromatch@4.0.8: 4082 4335 resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 4083 4336 engines: {node: '>=8.6'} ··· 4313 4566 package-json-from-dist@1.0.1: 4314 4567 resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 4315 4568 4569 + parse-entities@4.0.2: 4570 + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} 4571 + 4316 4572 parse-gitignore@2.0.0: 4317 4573 resolution: {integrity: sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==} 4318 4574 engines: {node: '>=14'} ··· 4429 4685 resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} 4430 4686 engines: {node: '>= 0.6.0'} 4431 4687 4688 + property-information@7.1.0: 4689 + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} 4690 + 4432 4691 pump@3.0.4: 4433 4692 resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} 4434 4693 ··· 4492 4751 resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} 4493 4752 engines: {node: '>= 0.4'} 4494 4753 4754 + rehype-raw@7.0.0: 4755 + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} 4756 + 4757 + rehype-react@8.0.0: 4758 + resolution: {integrity: sha512-vzo0YxYbB2HE+36+9HWXVdxNoNDubx63r5LBzpxBGVWM8s9mdnMdbmuJBAX6TTyuGdZjZix6qU3GcSuKCIWivw==} 4759 + 4760 + remark-gfm@4.0.1: 4761 + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} 4762 + 4763 + remark-parse@11.0.0: 4764 + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} 4765 + 4766 + remark-rehype@11.1.2: 4767 + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} 4768 + 4769 + remark-stringify@11.0.0: 4770 + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} 4771 + 4495 4772 remove-trailing-separator@1.1.0: 4496 4773 resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} 4497 4774 ··· 4675 4952 resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} 4676 4953 engines: {node: '>= 12'} 4677 4954 4955 + space-separated-tokens@2.0.2: 4956 + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} 4957 + 4678 4958 spdx-correct@3.2.0: 4679 4959 resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} 4680 4960 ··· 4730 5010 4731 5011 string_decoder@1.3.0: 4732 5012 resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 5013 + 5014 + stringify-entities@4.0.4: 5015 + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} 4733 5016 4734 5017 strip-ansi@6.0.1: 4735 5018 resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} ··· 4750 5033 strip-literal@3.1.0: 4751 5034 resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} 4752 5035 5036 + style-to-js@1.1.21: 5037 + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} 5038 + 5039 + style-to-object@1.0.14: 5040 + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} 5041 + 4753 5042 supports-color@7.2.0: 4754 5043 resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 4755 5044 engines: {node: '>=8'} ··· 4837 5126 tr46@0.0.3: 4838 5127 resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 4839 5128 5129 + trim-lines@3.0.1: 5130 + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} 5131 + 4840 5132 triple-beam@1.4.1: 4841 5133 resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} 4842 5134 engines: {node: '>= 14.0.0'} 5135 + 5136 + trough@2.2.0: 5137 + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} 4843 5138 4844 5139 ts-api-utils@2.5.0: 4845 5140 resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} ··· 4917 5212 resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} 4918 5213 engines: {node: '>=18'} 4919 5214 5215 + unified@11.0.5: 5216 + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} 5217 + 5218 + unist-util-is@6.0.1: 5219 + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} 5220 + 5221 + unist-util-position@5.0.0: 5222 + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} 5223 + 5224 + unist-util-stringify-position@4.0.0: 5225 + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} 5226 + 5227 + unist-util-visit-parents@6.0.2: 5228 + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} 5229 + 5230 + unist-util-visit@5.1.0: 5231 + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} 5232 + 4920 5233 unixify@1.0.0: 4921 5234 resolution: {integrity: sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==} 4922 5235 engines: {node: '>=0.10.0'} ··· 5037 5350 resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} 5038 5351 engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 5039 5352 5353 + vfile-location@5.0.3: 5354 + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} 5355 + 5356 + vfile-message@4.0.3: 5357 + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} 5358 + 5359 + vfile@6.0.3: 5360 + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} 5361 + 5040 5362 vite-plus@0.1.19: 5041 5363 resolution: {integrity: sha512-QWuTqkO/a8Q7I3hHnYdvwlJa7mcc6hgh99/8CHoRb27pgo+z1ux+NGYYCZPJHKVtatAtVRaQQvy4cEQBHyB87A==} 5042 5364 engines: {node: ^20.19.0 || >=22.12.0} ··· 5053 5375 walk-up-path@4.0.0: 5054 5376 resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} 5055 5377 engines: {node: 20 || >=22} 5378 + 5379 + web-namespaces@2.0.1: 5380 + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} 5056 5381 5057 5382 web-streams-polyfill@3.3.3: 5058 5383 resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} ··· 5181 5506 5182 5507 zod@4.3.6: 5183 5508 resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} 5509 + 5510 + zwitch@2.0.4: 5511 + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} 5184 5512 5185 5513 snapshots: 5186 5514 ··· 7117 7445 '@types/deep-eql': 4.0.2 7118 7446 assertion-error: 2.0.1 7119 7447 7448 + '@types/debug@4.1.13': 7449 + dependencies: 7450 + '@types/ms': 2.1.0 7451 + 7120 7452 '@types/deep-eql@4.0.2': {} 7121 7453 7454 + '@types/estree-jsx@1.0.5': 7455 + dependencies: 7456 + '@types/estree': 1.0.8 7457 + 7122 7458 '@types/estree@1.0.8': {} 7123 7459 7460 + '@types/hast@3.0.4': 7461 + dependencies: 7462 + '@types/unist': 3.0.3 7463 + 7464 + '@types/mdast@4.0.4': 7465 + dependencies: 7466 + '@types/unist': 3.0.3 7467 + 7468 + '@types/ms@2.1.0': {} 7469 + 7124 7470 '@types/node@25.6.0': 7125 7471 dependencies: 7126 7472 undici-types: 7.19.2 ··· 7138 7484 '@types/retry@0.12.2': {} 7139 7485 7140 7486 '@types/triple-beam@1.3.5': {} 7487 + 7488 + '@types/unist@2.0.11': {} 7489 + 7490 + '@types/unist@3.0.3': {} 7141 7491 7142 7492 '@types/yauzl@2.10.3': 7143 7493 dependencies: ··· 7209 7559 '@typescript/native-preview-linux-x64': 7.0.0-dev.20260421.2 7210 7560 '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260421.2 7211 7561 '@typescript/native-preview-win32-x64': 7.0.0-dev.20260421.2 7562 + 7563 + '@ungap/structured-clone@1.3.0': {} 7212 7564 7213 7565 '@vercel/nft@0.29.4': 7214 7566 dependencies: ··· 7503 7855 transitivePeerDependencies: 7504 7856 - supports-color 7505 7857 7858 + bail@2.0.2: {} 7859 + 7506 7860 balanced-match@1.0.2: {} 7507 7861 7508 7862 balanced-match@4.0.4: {} ··· 7613 7967 callsite@1.0.0: {} 7614 7968 7615 7969 caniuse-lite@1.0.30001791: {} 7970 + 7971 + ccount@2.0.1: {} 7616 7972 7617 7973 chalk@4.1.2: 7618 7974 dependencies: ··· 7621 7977 7622 7978 chalk@5.6.2: {} 7623 7979 7980 + character-entities-html4@2.1.0: {} 7981 + 7982 + character-entities-legacy@3.0.0: {} 7983 + 7984 + character-entities@2.0.2: {} 7985 + 7986 + character-reference-invalid@2.0.1: {} 7987 + 7624 7988 cheerio-select@2.1.0: 7625 7989 dependencies: 7626 7990 boolbase: 1.0.0 ··· 7706 8070 dependencies: 7707 8071 color-convert: 3.1.3 7708 8072 color-string: 2.1.4 8073 + 8074 + comma-separated-tokens@2.0.3: {} 7709 8075 7710 8076 commander@10.0.1: {} 7711 8077 ··· 7827 8193 dependencies: 7828 8194 callsite: 1.0.0 7829 8195 8196 + decode-named-character-reference@1.3.0: 8197 + dependencies: 8198 + character-entities: 2.0.2 8199 + 7830 8200 dedent@1.7.2: {} 7831 8201 7832 8202 deepmerge@4.3.1: {} ··· 7845 8215 7846 8216 defu@6.1.7: {} 7847 8217 8218 + dequal@2.0.3: {} 8219 + 7848 8220 destr@2.0.5: {} 7849 8221 7850 8222 detect-libc@2.1.2: {} ··· 7906 8278 - supports-color 7907 8279 7908 8280 dettle@1.0.5: {} 8281 + 8282 + devlop@1.1.0: 8283 + dependencies: 8284 + dequal: 2.0.3 7909 8285 7910 8286 diff@8.0.4: {} 7911 8287 ··· 8184 8560 8185 8561 estraverse@5.3.0: {} 8186 8562 8563 + estree-util-is-identifier-name@3.0.0: {} 8564 + 8187 8565 estree-walker@2.0.2: {} 8188 8566 8189 8567 estree-walker@3.0.3: ··· 8218 8596 8219 8597 exsolve@1.0.8: {} 8220 8598 8599 + extend@3.0.2: {} 8600 + 8221 8601 extract-zip@2.0.1: 8222 8602 dependencies: 8223 8603 debug: 4.4.3 ··· 8444 8824 dependencies: 8445 8825 function-bind: 1.1.2 8446 8826 8827 + hast-util-from-parse5@8.0.3: 8828 + dependencies: 8829 + '@types/hast': 3.0.4 8830 + '@types/unist': 3.0.3 8831 + devlop: 1.1.0 8832 + hastscript: 9.0.1 8833 + property-information: 7.1.0 8834 + vfile: 6.0.3 8835 + vfile-location: 5.0.3 8836 + web-namespaces: 2.0.1 8837 + 8838 + hast-util-parse-selector@4.0.0: 8839 + dependencies: 8840 + '@types/hast': 3.0.4 8841 + 8842 + hast-util-raw@9.1.0: 8843 + dependencies: 8844 + '@types/hast': 3.0.4 8845 + '@types/unist': 3.0.3 8846 + '@ungap/structured-clone': 1.3.0 8847 + hast-util-from-parse5: 8.0.3 8848 + hast-util-to-parse5: 8.0.1 8849 + html-void-elements: 3.0.0 8850 + mdast-util-to-hast: 13.2.1 8851 + parse5: 7.3.0 8852 + unist-util-position: 5.0.0 8853 + unist-util-visit: 5.1.0 8854 + vfile: 6.0.3 8855 + web-namespaces: 2.0.1 8856 + zwitch: 2.0.4 8857 + 8858 + hast-util-to-jsx-runtime@2.3.6: 8859 + dependencies: 8860 + '@types/estree': 1.0.8 8861 + '@types/hast': 3.0.4 8862 + '@types/unist': 3.0.3 8863 + comma-separated-tokens: 2.0.3 8864 + devlop: 1.1.0 8865 + estree-util-is-identifier-name: 3.0.0 8866 + hast-util-whitespace: 3.0.0 8867 + mdast-util-mdx-expression: 2.0.1 8868 + mdast-util-mdx-jsx: 3.2.0 8869 + mdast-util-mdxjs-esm: 2.0.1 8870 + property-information: 7.1.0 8871 + space-separated-tokens: 2.0.2 8872 + style-to-js: 1.1.21 8873 + unist-util-position: 5.0.0 8874 + vfile-message: 4.0.3 8875 + transitivePeerDependencies: 8876 + - supports-color 8877 + 8878 + hast-util-to-parse5@8.0.1: 8879 + dependencies: 8880 + '@types/hast': 3.0.4 8881 + comma-separated-tokens: 2.0.3 8882 + devlop: 1.1.0 8883 + property-information: 7.1.0 8884 + space-separated-tokens: 2.0.2 8885 + web-namespaces: 2.0.1 8886 + zwitch: 2.0.4 8887 + 8888 + hast-util-whitespace@3.0.0: 8889 + dependencies: 8890 + '@types/hast': 3.0.4 8891 + 8892 + hastscript@9.0.1: 8893 + dependencies: 8894 + '@types/hast': 3.0.4 8895 + comma-separated-tokens: 2.0.3 8896 + hast-util-parse-selector: 4.0.0 8897 + property-information: 7.1.0 8898 + space-separated-tokens: 2.0.2 8899 + 8447 8900 hosted-git-info@7.0.2: 8448 8901 dependencies: 8449 8902 lru-cache: 10.4.3 8903 + 8904 + html-void-elements@3.0.0: {} 8450 8905 8451 8906 htmlparser2@10.1.0: 8452 8907 dependencies: ··· 8491 8946 8492 8947 inherits@2.0.4: {} 8493 8948 8949 + inline-style-parser@0.2.7: {} 8950 + 8494 8951 internal-slot@1.1.0: 8495 8952 dependencies: 8496 8953 es-errors: 1.3.0 ··· 8539 8996 8540 8997 iron-webcrypto@1.2.1: {} 8541 8998 8999 + is-alphabetical@2.0.1: {} 9000 + 9001 + is-alphanumerical@2.0.1: 9002 + dependencies: 9003 + is-alphabetical: 2.0.1 9004 + is-decimal: 2.0.1 9005 + 8542 9006 is-array-buffer@3.0.5: 8543 9007 dependencies: 8544 9008 call-bind: 1.0.9 ··· 8583 9047 call-bound: 1.0.4 8584 9048 has-tostringtag: 1.0.2 8585 9049 9050 + is-decimal@2.0.1: {} 9051 + 8586 9052 is-extglob@2.1.1: {} 8587 9053 8588 9054 is-finalizationregistry@1.1.1: ··· 8602 9068 is-glob@4.0.3: 8603 9069 dependencies: 8604 9070 is-extglob: 2.1.1 9071 + 9072 + is-hexadecimal@2.0.1: {} 8605 9073 8606 9074 is-map@2.0.3: {} 8607 9075 ··· 8881 9349 safe-stable-stringify: 2.5.0 8882 9350 triple-beam: 1.4.1 8883 9351 9352 + longest-streak@3.1.0: {} 9353 + 8884 9354 lru-cache@10.4.3: {} 8885 9355 8886 9356 lru-cache@11.3.5: {} ··· 8897 9367 8898 9368 map-obj@5.0.2: {} 8899 9369 9370 + markdown-table@3.0.4: {} 9371 + 8900 9372 math-intrinsics@1.1.0: {} 8901 9373 9374 + mdast-util-find-and-replace@3.0.2: 9375 + dependencies: 9376 + '@types/mdast': 4.0.4 9377 + escape-string-regexp: 5.0.0 9378 + unist-util-is: 6.0.1 9379 + unist-util-visit-parents: 6.0.2 9380 + 9381 + mdast-util-from-markdown@2.0.3: 9382 + dependencies: 9383 + '@types/mdast': 4.0.4 9384 + '@types/unist': 3.0.3 9385 + decode-named-character-reference: 1.3.0 9386 + devlop: 1.1.0 9387 + mdast-util-to-string: 4.0.0 9388 + micromark: 4.0.2 9389 + micromark-util-decode-numeric-character-reference: 2.0.2 9390 + micromark-util-decode-string: 2.0.1 9391 + micromark-util-normalize-identifier: 2.0.1 9392 + micromark-util-symbol: 2.0.1 9393 + micromark-util-types: 2.0.2 9394 + unist-util-stringify-position: 4.0.0 9395 + transitivePeerDependencies: 9396 + - supports-color 9397 + 9398 + mdast-util-gfm-autolink-literal@2.0.1: 9399 + dependencies: 9400 + '@types/mdast': 4.0.4 9401 + ccount: 2.0.1 9402 + devlop: 1.1.0 9403 + mdast-util-find-and-replace: 3.0.2 9404 + micromark-util-character: 2.1.1 9405 + 9406 + mdast-util-gfm-footnote@2.1.0: 9407 + dependencies: 9408 + '@types/mdast': 4.0.4 9409 + devlop: 1.1.0 9410 + mdast-util-from-markdown: 2.0.3 9411 + mdast-util-to-markdown: 2.1.2 9412 + micromark-util-normalize-identifier: 2.0.1 9413 + transitivePeerDependencies: 9414 + - supports-color 9415 + 9416 + mdast-util-gfm-strikethrough@2.0.0: 9417 + dependencies: 9418 + '@types/mdast': 4.0.4 9419 + mdast-util-from-markdown: 2.0.3 9420 + mdast-util-to-markdown: 2.1.2 9421 + transitivePeerDependencies: 9422 + - supports-color 9423 + 9424 + mdast-util-gfm-table@2.0.0: 9425 + dependencies: 9426 + '@types/mdast': 4.0.4 9427 + devlop: 1.1.0 9428 + markdown-table: 3.0.4 9429 + mdast-util-from-markdown: 2.0.3 9430 + mdast-util-to-markdown: 2.1.2 9431 + transitivePeerDependencies: 9432 + - supports-color 9433 + 9434 + mdast-util-gfm-task-list-item@2.0.0: 9435 + dependencies: 9436 + '@types/mdast': 4.0.4 9437 + devlop: 1.1.0 9438 + mdast-util-from-markdown: 2.0.3 9439 + mdast-util-to-markdown: 2.1.2 9440 + transitivePeerDependencies: 9441 + - supports-color 9442 + 9443 + mdast-util-gfm@3.1.0: 9444 + dependencies: 9445 + mdast-util-from-markdown: 2.0.3 9446 + mdast-util-gfm-autolink-literal: 2.0.1 9447 + mdast-util-gfm-footnote: 2.1.0 9448 + mdast-util-gfm-strikethrough: 2.0.0 9449 + mdast-util-gfm-table: 2.0.0 9450 + mdast-util-gfm-task-list-item: 2.0.0 9451 + mdast-util-to-markdown: 2.1.2 9452 + transitivePeerDependencies: 9453 + - supports-color 9454 + 9455 + mdast-util-mdx-expression@2.0.1: 9456 + dependencies: 9457 + '@types/estree-jsx': 1.0.5 9458 + '@types/hast': 3.0.4 9459 + '@types/mdast': 4.0.4 9460 + devlop: 1.1.0 9461 + mdast-util-from-markdown: 2.0.3 9462 + mdast-util-to-markdown: 2.1.2 9463 + transitivePeerDependencies: 9464 + - supports-color 9465 + 9466 + mdast-util-mdx-jsx@3.2.0: 9467 + dependencies: 9468 + '@types/estree-jsx': 1.0.5 9469 + '@types/hast': 3.0.4 9470 + '@types/mdast': 4.0.4 9471 + '@types/unist': 3.0.3 9472 + ccount: 2.0.1 9473 + devlop: 1.1.0 9474 + mdast-util-from-markdown: 2.0.3 9475 + mdast-util-to-markdown: 2.1.2 9476 + parse-entities: 4.0.2 9477 + stringify-entities: 4.0.4 9478 + unist-util-stringify-position: 4.0.0 9479 + vfile-message: 4.0.3 9480 + transitivePeerDependencies: 9481 + - supports-color 9482 + 9483 + mdast-util-mdxjs-esm@2.0.1: 9484 + dependencies: 9485 + '@types/estree-jsx': 1.0.5 9486 + '@types/hast': 3.0.4 9487 + '@types/mdast': 4.0.4 9488 + devlop: 1.1.0 9489 + mdast-util-from-markdown: 2.0.3 9490 + mdast-util-to-markdown: 2.1.2 9491 + transitivePeerDependencies: 9492 + - supports-color 9493 + 9494 + mdast-util-phrasing@4.1.0: 9495 + dependencies: 9496 + '@types/mdast': 4.0.4 9497 + unist-util-is: 6.0.1 9498 + 9499 + mdast-util-to-hast@13.2.1: 9500 + dependencies: 9501 + '@types/hast': 3.0.4 9502 + '@types/mdast': 4.0.4 9503 + '@ungap/structured-clone': 1.3.0 9504 + devlop: 1.1.0 9505 + micromark-util-sanitize-uri: 2.0.1 9506 + trim-lines: 3.0.1 9507 + unist-util-position: 5.0.0 9508 + unist-util-visit: 5.1.0 9509 + vfile: 6.0.3 9510 + 9511 + mdast-util-to-markdown@2.1.2: 9512 + dependencies: 9513 + '@types/mdast': 4.0.4 9514 + '@types/unist': 3.0.3 9515 + longest-streak: 3.1.0 9516 + mdast-util-phrasing: 4.1.0 9517 + mdast-util-to-string: 4.0.0 9518 + micromark-util-classify-character: 2.0.1 9519 + micromark-util-decode-string: 2.0.1 9520 + unist-util-visit: 5.1.0 9521 + zwitch: 2.0.4 9522 + 9523 + mdast-util-to-string@4.0.0: 9524 + dependencies: 9525 + '@types/mdast': 4.0.4 9526 + 8902 9527 mdn-data@2.0.28: {} 8903 9528 8904 9529 mdn-data@2.27.1: {} ··· 8911 9536 8912 9537 merge2@1.4.1: {} 8913 9538 9539 + micromark-core-commonmark@2.0.3: 9540 + dependencies: 9541 + decode-named-character-reference: 1.3.0 9542 + devlop: 1.1.0 9543 + micromark-factory-destination: 2.0.1 9544 + micromark-factory-label: 2.0.1 9545 + micromark-factory-space: 2.0.1 9546 + micromark-factory-title: 2.0.1 9547 + micromark-factory-whitespace: 2.0.1 9548 + micromark-util-character: 2.1.1 9549 + micromark-util-chunked: 2.0.1 9550 + micromark-util-classify-character: 2.0.1 9551 + micromark-util-html-tag-name: 2.0.1 9552 + micromark-util-normalize-identifier: 2.0.1 9553 + micromark-util-resolve-all: 2.0.1 9554 + micromark-util-subtokenize: 2.1.0 9555 + micromark-util-symbol: 2.0.1 9556 + micromark-util-types: 2.0.2 9557 + 9558 + micromark-extension-gfm-autolink-literal@2.1.0: 9559 + dependencies: 9560 + micromark-util-character: 2.1.1 9561 + micromark-util-sanitize-uri: 2.0.1 9562 + micromark-util-symbol: 2.0.1 9563 + micromark-util-types: 2.0.2 9564 + 9565 + micromark-extension-gfm-footnote@2.1.0: 9566 + dependencies: 9567 + devlop: 1.1.0 9568 + micromark-core-commonmark: 2.0.3 9569 + micromark-factory-space: 2.0.1 9570 + micromark-util-character: 2.1.1 9571 + micromark-util-normalize-identifier: 2.0.1 9572 + micromark-util-sanitize-uri: 2.0.1 9573 + micromark-util-symbol: 2.0.1 9574 + micromark-util-types: 2.0.2 9575 + 9576 + micromark-extension-gfm-strikethrough@2.1.0: 9577 + dependencies: 9578 + devlop: 1.1.0 9579 + micromark-util-chunked: 2.0.1 9580 + micromark-util-classify-character: 2.0.1 9581 + micromark-util-resolve-all: 2.0.1 9582 + micromark-util-symbol: 2.0.1 9583 + micromark-util-types: 2.0.2 9584 + 9585 + micromark-extension-gfm-table@2.1.1: 9586 + dependencies: 9587 + devlop: 1.1.0 9588 + micromark-factory-space: 2.0.1 9589 + micromark-util-character: 2.1.1 9590 + micromark-util-symbol: 2.0.1 9591 + micromark-util-types: 2.0.2 9592 + 9593 + micromark-extension-gfm-tagfilter@2.0.0: 9594 + dependencies: 9595 + micromark-util-types: 2.0.2 9596 + 9597 + micromark-extension-gfm-task-list-item@2.1.0: 9598 + dependencies: 9599 + devlop: 1.1.0 9600 + micromark-factory-space: 2.0.1 9601 + micromark-util-character: 2.1.1 9602 + micromark-util-symbol: 2.0.1 9603 + micromark-util-types: 2.0.2 9604 + 9605 + micromark-extension-gfm@3.0.0: 9606 + dependencies: 9607 + micromark-extension-gfm-autolink-literal: 2.1.0 9608 + micromark-extension-gfm-footnote: 2.1.0 9609 + micromark-extension-gfm-strikethrough: 2.1.0 9610 + micromark-extension-gfm-table: 2.1.1 9611 + micromark-extension-gfm-tagfilter: 2.0.0 9612 + micromark-extension-gfm-task-list-item: 2.1.0 9613 + micromark-util-combine-extensions: 2.0.1 9614 + micromark-util-types: 2.0.2 9615 + 9616 + micromark-factory-destination@2.0.1: 9617 + dependencies: 9618 + micromark-util-character: 2.1.1 9619 + micromark-util-symbol: 2.0.1 9620 + micromark-util-types: 2.0.2 9621 + 9622 + micromark-factory-label@2.0.1: 9623 + dependencies: 9624 + devlop: 1.1.0 9625 + micromark-util-character: 2.1.1 9626 + micromark-util-symbol: 2.0.1 9627 + micromark-util-types: 2.0.2 9628 + 9629 + micromark-factory-space@2.0.1: 9630 + dependencies: 9631 + micromark-util-character: 2.1.1 9632 + micromark-util-types: 2.0.2 9633 + 9634 + micromark-factory-title@2.0.1: 9635 + dependencies: 9636 + micromark-factory-space: 2.0.1 9637 + micromark-util-character: 2.1.1 9638 + micromark-util-symbol: 2.0.1 9639 + micromark-util-types: 2.0.2 9640 + 9641 + micromark-factory-whitespace@2.0.1: 9642 + dependencies: 9643 + micromark-factory-space: 2.0.1 9644 + micromark-util-character: 2.1.1 9645 + micromark-util-symbol: 2.0.1 9646 + micromark-util-types: 2.0.2 9647 + 9648 + micromark-util-character@2.1.1: 9649 + dependencies: 9650 + micromark-util-symbol: 2.0.1 9651 + micromark-util-types: 2.0.2 9652 + 9653 + micromark-util-chunked@2.0.1: 9654 + dependencies: 9655 + micromark-util-symbol: 2.0.1 9656 + 9657 + micromark-util-classify-character@2.0.1: 9658 + dependencies: 9659 + micromark-util-character: 2.1.1 9660 + micromark-util-symbol: 2.0.1 9661 + micromark-util-types: 2.0.2 9662 + 9663 + micromark-util-combine-extensions@2.0.1: 9664 + dependencies: 9665 + micromark-util-chunked: 2.0.1 9666 + micromark-util-types: 2.0.2 9667 + 9668 + micromark-util-decode-numeric-character-reference@2.0.2: 9669 + dependencies: 9670 + micromark-util-symbol: 2.0.1 9671 + 9672 + micromark-util-decode-string@2.0.1: 9673 + dependencies: 9674 + decode-named-character-reference: 1.3.0 9675 + micromark-util-character: 2.1.1 9676 + micromark-util-decode-numeric-character-reference: 2.0.2 9677 + micromark-util-symbol: 2.0.1 9678 + 9679 + micromark-util-encode@2.0.1: {} 9680 + 9681 + micromark-util-html-tag-name@2.0.1: {} 9682 + 9683 + micromark-util-normalize-identifier@2.0.1: 9684 + dependencies: 9685 + micromark-util-symbol: 2.0.1 9686 + 9687 + micromark-util-resolve-all@2.0.1: 9688 + dependencies: 9689 + micromark-util-types: 2.0.2 9690 + 9691 + micromark-util-sanitize-uri@2.0.1: 9692 + dependencies: 9693 + micromark-util-character: 2.1.1 9694 + micromark-util-encode: 2.0.1 9695 + micromark-util-symbol: 2.0.1 9696 + 9697 + micromark-util-subtokenize@2.1.0: 9698 + dependencies: 9699 + devlop: 1.1.0 9700 + micromark-util-chunked: 2.0.1 9701 + micromark-util-symbol: 2.0.1 9702 + micromark-util-types: 2.0.2 9703 + 9704 + micromark-util-symbol@2.0.1: {} 9705 + 9706 + micromark-util-types@2.0.2: {} 9707 + 9708 + micromark@4.0.2: 9709 + dependencies: 9710 + '@types/debug': 4.1.13 9711 + debug: 4.4.3 9712 + decode-named-character-reference: 1.3.0 9713 + devlop: 1.1.0 9714 + micromark-core-commonmark: 2.0.3 9715 + micromark-factory-space: 2.0.1 9716 + micromark-util-character: 2.1.1 9717 + micromark-util-chunked: 2.0.1 9718 + micromark-util-combine-extensions: 2.0.1 9719 + micromark-util-decode-numeric-character-reference: 2.0.2 9720 + micromark-util-encode: 2.0.1 9721 + micromark-util-normalize-identifier: 2.0.1 9722 + micromark-util-resolve-all: 2.0.1 9723 + micromark-util-sanitize-uri: 2.0.1 9724 + micromark-util-subtokenize: 2.1.0 9725 + micromark-util-symbol: 2.0.1 9726 + micromark-util-types: 2.0.2 9727 + transitivePeerDependencies: 9728 + - supports-color 9729 + 8914 9730 micromatch@4.0.8: 8915 9731 dependencies: 8916 9732 braces: 3.0.3 ··· 9210 10026 9211 10027 package-json-from-dist@1.0.1: {} 9212 10028 10029 + parse-entities@4.0.2: 10030 + dependencies: 10031 + '@types/unist': 2.0.11 10032 + character-entities-legacy: 3.0.0 10033 + character-reference-invalid: 2.0.1 10034 + decode-named-character-reference: 1.3.0 10035 + is-alphanumerical: 2.0.1 10036 + is-decimal: 2.0.1 10037 + is-hexadecimal: 2.0.1 10038 + 9213 10039 parse-gitignore@2.0.0: {} 9214 10040 9215 10041 parse-imports@2.2.1: ··· 9322 10148 9323 10149 process@0.11.10: {} 9324 10150 10151 + property-information@7.1.0: {} 10152 + 9325 10153 pump@3.0.4: 9326 10154 dependencies: 9327 10155 end-of-stream: 1.4.5 ··· 9410 10238 gopd: 1.2.0 9411 10239 set-function-name: 2.0.2 9412 10240 10241 + rehype-raw@7.0.0: 10242 + dependencies: 10243 + '@types/hast': 3.0.4 10244 + hast-util-raw: 9.1.0 10245 + vfile: 6.0.3 10246 + 10247 + rehype-react@8.0.0: 10248 + dependencies: 10249 + '@types/hast': 3.0.4 10250 + hast-util-to-jsx-runtime: 2.3.6 10251 + unified: 11.0.5 10252 + transitivePeerDependencies: 10253 + - supports-color 10254 + 10255 + remark-gfm@4.0.1: 10256 + dependencies: 10257 + '@types/mdast': 4.0.4 10258 + mdast-util-gfm: 3.1.0 10259 + micromark-extension-gfm: 3.0.0 10260 + remark-parse: 11.0.0 10261 + remark-stringify: 11.0.0 10262 + unified: 11.0.5 10263 + transitivePeerDependencies: 10264 + - supports-color 10265 + 10266 + remark-parse@11.0.0: 10267 + dependencies: 10268 + '@types/mdast': 4.0.4 10269 + mdast-util-from-markdown: 2.0.3 10270 + micromark-util-types: 2.0.2 10271 + unified: 11.0.5 10272 + transitivePeerDependencies: 10273 + - supports-color 10274 + 10275 + remark-rehype@11.1.2: 10276 + dependencies: 10277 + '@types/hast': 3.0.4 10278 + '@types/mdast': 4.0.4 10279 + mdast-util-to-hast: 13.2.1 10280 + unified: 11.0.5 10281 + vfile: 6.0.3 10282 + 10283 + remark-stringify@11.0.0: 10284 + dependencies: 10285 + '@types/mdast': 4.0.4 10286 + mdast-util-to-markdown: 2.1.2 10287 + unified: 11.0.5 10288 + 9413 10289 remove-trailing-separator@1.1.0: {} 9414 10290 9415 10291 require-directory@2.1.1: {} ··· 9619 10495 9620 10496 source-map@0.7.6: {} 9621 10497 10498 + space-separated-tokens@2.0.2: {} 10499 + 9622 10500 spdx-correct@3.2.0: 9623 10501 dependencies: 9624 10502 spdx-expression-parse: 3.0.1 ··· 9696 10574 dependencies: 9697 10575 safe-buffer: 5.2.1 9698 10576 10577 + stringify-entities@4.0.4: 10578 + dependencies: 10579 + character-entities-html4: 2.1.0 10580 + character-entities-legacy: 3.0.0 10581 + 9699 10582 strip-ansi@6.0.1: 9700 10583 dependencies: 9701 10584 ansi-regex: 5.0.1 ··· 9712 10595 dependencies: 9713 10596 js-tokens: 9.0.1 9714 10597 10598 + style-to-js@1.1.21: 10599 + dependencies: 10600 + style-to-object: 1.0.14 10601 + 10602 + style-to-object@1.0.14: 10603 + dependencies: 10604 + inline-style-parser: 0.2.7 10605 + 9715 10606 supports-color@7.2.0: 9716 10607 dependencies: 9717 10608 has-flag: 4.0.0 ··· 9803 10694 9804 10695 tr46@0.0.3: {} 9805 10696 10697 + trim-lines@3.0.1: {} 10698 + 9806 10699 triple-beam@1.4.1: {} 10700 + 10701 + trough@2.2.0: {} 9807 10702 9808 10703 ts-api-utils@2.5.0(typescript@5.9.3): 9809 10704 dependencies: ··· 9880 10775 9881 10776 unicorn-magic@0.1.0: {} 9882 10777 10778 + unified@11.0.5: 10779 + dependencies: 10780 + '@types/unist': 3.0.3 10781 + bail: 2.0.2 10782 + devlop: 1.1.0 10783 + extend: 3.0.2 10784 + is-plain-obj: 4.1.0 10785 + trough: 2.2.0 10786 + vfile: 6.0.3 10787 + 10788 + unist-util-is@6.0.1: 10789 + dependencies: 10790 + '@types/unist': 3.0.3 10791 + 10792 + unist-util-position@5.0.0: 10793 + dependencies: 10794 + '@types/unist': 3.0.3 10795 + 10796 + unist-util-stringify-position@4.0.0: 10797 + dependencies: 10798 + '@types/unist': 3.0.3 10799 + 10800 + unist-util-visit-parents@6.0.2: 10801 + dependencies: 10802 + '@types/unist': 3.0.3 10803 + unist-util-is: 6.0.1 10804 + 10805 + unist-util-visit@5.1.0: 10806 + dependencies: 10807 + '@types/unist': 3.0.3 10808 + unist-util-is: 6.0.1 10809 + unist-util-visit-parents: 6.0.2 10810 + 9883 10811 unixify@1.0.0: 9884 10812 dependencies: 9885 10813 normalize-path: 2.1.1 ··· 9942 10870 9943 10871 validate-npm-package-name@5.0.1: {} 9944 10872 10873 + vfile-location@5.0.3: 10874 + dependencies: 10875 + '@types/unist': 3.0.3 10876 + vfile: 6.0.3 10877 + 10878 + vfile-message@4.0.3: 10879 + dependencies: 10880 + '@types/unist': 3.0.3 10881 + unist-util-stringify-position: 4.0.0 10882 + 10883 + vfile@6.0.3: 10884 + dependencies: 10885 + '@types/unist': 3.0.3 10886 + vfile-message: 4.0.3 10887 + 9945 10888 vite-plus@0.1.19(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3): 9946 10889 dependencies: 9947 10890 '@oxc-project/types': 0.126.0 ··· 9994 10937 vite: '@voidzero-dev/vite-plus-core@0.1.19(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' 9995 10938 9996 10939 walk-up-path@4.0.0: {} 10940 + 10941 + web-namespaces@2.0.1: {} 9997 10942 9998 10943 web-streams-polyfill@3.3.3: {} 9999 10944 ··· 10146 11091 zod@3.25.76: {} 10147 11092 10148 11093 zod@4.3.6: {} 11094 + 11095 + zwitch@2.0.4: {}
-132
src/components/console/pokemon-table-skeleton.tsx
··· 1 - import { Suspense, type ReactNode } from "react"; 2 - import { 3 - Table, 4 - TableBody, 5 - TableCell, 6 - TableHead, 7 - TableHeader, 8 - TableRow, 9 - } from "~/components/ui/table"; 10 - import { cn } from "~/lib/utils"; 11 - 12 - interface PokemonTableSkeletonProps { 13 - /** 14 - * Number of skeleton rows to render (defaults to 10 for POKEMON_LIMIT) 15 - */ 16 - rowCount?: number; 17 - className?: string; 18 - } 19 - 20 - /** 21 - * Skeleton loading state for the Pokemon table. 22 - * 23 - * Renders skeleton rows that exactly match the height of real table rows 24 - * to prevent layout shift when data loads. Uses the same padding and 25 - * structure as the actual PokemonTable component. 26 - * 27 - * @example 28 - * <PokemonTableSkeleton rowCount={10} /> 29 - */ 30 - export function PokemonTableSkeleton({ rowCount = 10, className }: PokemonTableSkeletonProps) { 31 - return ( 32 - <Table className={cn("w-full border-collapse", "text-sm", "font-mono", className)}> 33 - <TableHeader> 34 - <TableRow className="border-b border-(--border-strong)"> 35 - <TableHead 36 - className={cn( 37 - "text-left py-3 px-3", 38 - "font-semibold text-(--text-secondary)", 39 - "uppercase text-xs tracking-wider", 40 - )} 41 - > 42 - # 43 - </TableHead> 44 - <TableHead 45 - className={cn( 46 - "text-left py-3 px-3", 47 - "font-semibold text-(--text-secondary)", 48 - "uppercase text-xs tracking-wider", 49 - )} 50 - > 51 - Name 52 - </TableHead> 53 - <TableHead 54 - className={cn( 55 - "text-left py-3 px-3", 56 - "font-semibold text-(--text-secondary)", 57 - "uppercase text-xs tracking-wider", 58 - )} 59 - > 60 - Details 61 - </TableHead> 62 - </TableRow> 63 - </TableHeader> 64 - <TableBody> 65 - {Array.from({ length: rowCount }).map((_, index) => ( 66 - <SkeletonRow key={index} /> 67 - ))} 68 - </TableBody> 69 - </Table> 70 - ); 71 - } 72 - 73 - /** 74 - * Skeleton row that exactly matches the height of a real table row. 75 - * 76 - * Real rows have py-3 (12px) padding + content. This skeleton uses 77 - * identical padding to ensure zero layout shift when data loads. 78 - */ 79 - function SkeletonRow() { 80 - return ( 81 - <TableRow className="border-b border-(--border-default)"> 82 - <TableCell className="py-3 px-3"> 83 - <div className="h-4 w-8 bg-(--bg-secondary) animate-pulse" /> 84 - </TableCell> 85 - <TableCell className="py-3 px-3"> 86 - <div className="h-4 w-32 bg-(--bg-secondary) animate-pulse" /> 87 - </TableCell> 88 - <TableCell className="py-3 px-3"> 89 - <div className="flex gap-2"> 90 - <div className="h-5 w-16 bg-(--bg-secondary) animate-pulse" /> 91 - <div className="h-5 w-16 bg-(--bg-secondary) animate-pulse" /> 92 - </div> 93 - </TableCell> 94 - </TableRow> 95 - ); 96 - } 97 - 98 - interface PokemonTableContainerProps { 99 - /** 100 - * The actual PokemonTable component with data 101 - */ 102 - children: ReactNode; 103 - /** 104 - * Number of rows expected (for skeleton sizing) 105 - */ 106 - rowCount?: number; 107 - className?: string; 108 - } 109 - 110 - /** 111 - * Suspense-wrapped container for Pokemon tables. 112 - * 113 - * Provides a consistent loading state across all routes while 114 - * maintaining the console aesthetic. The table header is shown 115 - * immediately to set expectations for the data structure. 116 - * 117 - * @example 118 - * <PokemonTableContainer rowCount={10}> 119 - * <PokemonTable pokemon={data.pokemon} /> 120 - * </PokemonTableContainer> 121 - */ 122 - export function PokemonTableContainer({ 123 - children, 124 - rowCount, 125 - className, 126 - }: PokemonTableContainerProps) { 127 - return ( 128 - <Suspense fallback={<PokemonTableSkeleton rowCount={rowCount} className={className} />}> 129 - {children} 130 - </Suspense> 131 - ); 132 - }
-88
src/components/console/pokemon-table.tsx
··· 1 - import { 2 - Table, 3 - TableBody, 4 - TableCell, 5 - TableHead, 6 - TableHeader, 7 - TableRow, 8 - } from "~/components/ui/table"; 9 - import { TypeBadge } from "./type-badge"; 10 - import { cn } from "~/lib/utils"; 11 - 12 - interface Pokemon { 13 - id: number; 14 - name: string; 15 - types: Array<{ name: string }>; 16 - } 17 - 18 - interface PokemonTableProps { 19 - pokemon: Pokemon[]; 20 - className?: string; 21 - } 22 - 23 - /** 24 - * Pokemon data table with console styling. 25 - * 26 - * Displays Pokemon ID, name, and types in a monospace-styled table. 27 - * Used consistently across all example routes. 28 - * 29 - * @example 30 - * <PokemonTable pokemon={data.pokemon} /> 31 - */ 32 - export function PokemonTable({ pokemon, className }: PokemonTableProps) { 33 - return ( 34 - <Table className={cn("w-full border-collapse", "text-sm", "font-mono", className)}> 35 - <TableHeader> 36 - <TableRow className="border-b border-(--border-strong)"> 37 - <TableHead 38 - className={cn( 39 - "text-left py-3 px-3", 40 - "font-semibold text-(--text-secondary)", 41 - "uppercase text-xs tracking-wider", 42 - )} 43 - > 44 - # 45 - </TableHead> 46 - <TableHead 47 - className={cn( 48 - "text-left py-3 px-3", 49 - "font-semibold text-(--text-secondary)", 50 - "uppercase text-xs tracking-wider", 51 - )} 52 - > 53 - Name 54 - </TableHead> 55 - <TableHead 56 - className={cn( 57 - "text-left py-3 px-3", 58 - "font-semibold text-(--text-secondary)", 59 - "uppercase text-xs tracking-wider", 60 - )} 61 - > 62 - Types 63 - </TableHead> 64 - </TableRow> 65 - </TableHeader> 66 - <TableBody> 67 - {pokemon.map((p) => ( 68 - <TableRow 69 - key={p.name} 70 - className={cn( 71 - "border-b border-(--border-default)", 72 - "transition-colors duration-fast ease-default", 73 - "hover:bg-(--bg-secondary)", 74 - )} 75 - > 76 - <TableCell className="py-3 px-3 font-mono text-(--text-muted)">{p.id}</TableCell> 77 - <TableCell className="py-3 px-3 capitalize text-(--text-primary)">{p.name}</TableCell> 78 - <TableCell className="py-3 px-3"> 79 - {p.types.map((type) => ( 80 - <TypeBadge key={type.name} type={type.name} /> 81 - ))} 82 - </TableCell> 83 - </TableRow> 84 - ))} 85 - </TableBody> 86 - </Table> 87 - ); 88 - }
-36
src/components/console/type-badge.tsx
··· 1 - import { cn } from "~/lib/utils"; 2 - 3 - interface TypeBadgeProps { 4 - type: string; 5 - className?: string; 6 - } 7 - 8 - /** 9 - * Badge for displaying Pokemon types. 10 - * 11 - * Simple bordered label that fits the console aesthetic. 12 - * Multiple badges can be displayed inline for dual-type Pokemon. 13 - * 14 - * @example 15 - * <TypeBadge type="fire" /> 16 - * <TypeBadge type="flying" /> 17 - */ 18 - export function TypeBadge({ type, className }: TypeBadgeProps) { 19 - return ( 20 - <span 21 - className={cn( 22 - "inline-block", 23 - "px-2 py-0.5", 24 - "text-xs font-mono", 25 - "border border-(--border-default)", 26 - "bg-(--bg-secondary)", 27 - "text-(--text-secondary)", 28 - "capitalize", 29 - "mr-1", 30 - className, 31 - )} 32 - > 33 - {type} 34 - </span> 35 - ); 36 - }
-3
src/components/header.tsx
··· 16 16 <span className="hidden font-display text-lg font-semibold leading-none sm:inline"> 17 17 Prefetching Patterns 18 18 </span> 19 - <span className="hidden text-xs font-mono uppercase text-(--text-muted) sm:inline"> 20 - Contents 21 - </span> 22 19 </Link> 23 20 24 21 <nav className="flex shrink-0 items-center gap-2" aria-label="Reader navigation">
+23 -8
src/components/strategy-article.tsx
··· 1 + import { renderMarkdown } from "~/utils/markdown"; 2 + 1 3 interface StrategyArticleProps { 2 - eyebrow: string; 3 4 title: string; 5 + markdown: string; 4 6 } 5 7 6 - const loremIpsum = 7 - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 8 + export async function StrategyArticle({ title, markdown }: StrategyArticleProps) { 9 + const content = await renderMarkdown(markdown); 8 10 9 - export function StrategyArticle({ eyebrow, title }: StrategyArticleProps) { 10 11 return ( 11 12 <article className="border border-(--border-default) bg-(--bg-secondary) p-6 md:p-8 xl:sticky xl:top-20"> 12 - <p className="mb-5 font-mono text-xs uppercase text-(--accent-default)">{eyebrow}</p> 13 13 <h2 className="mb-6 text-3xl font-semibold uppercase leading-tight text-(--text-primary) md:text-4xl"> 14 14 {title} 15 15 </h2> 16 - <div className="space-y-5 text-sm leading-7 text-(--text-secondary)"> 17 - <p>{loremIpsum}</p> 18 - <p>{loremIpsum}</p> 16 + <div 17 + className={[ 18 + "space-y-5 text-sm leading-7 text-(--text-secondary)", 19 + "[&_h2]:mb-4 [&_h2]:mt-8 [&_h2]:text-xl [&_h2]:font-semibold [&_h2]:text-(--text-primary) [&_h2]:first:mt-0", 20 + "[&_h3]:mb-3 [&_h3]:mt-6 [&_h3]:text-lg [&_h3]:font-semibold [&_h3]:text-(--text-primary) first:[&_h3]:mt-0", 21 + "[&_p]:mb-5", 22 + "[&_ul]:mb-5 [&_ul]:list-disc [&_ul]:space-y-2 [&_ul]:pl-5", 23 + "[&_ol]:mb-5 [&_ol]:list-decimal [&_ol]:space-y-2 [&_ol]:pl-5", 24 + "[&_li]:text-(--text-secondary)", 25 + "[&_strong]:font-semibold [&_strong]:text-(--text-primary)", 26 + "[&_code]:rounded [&_code]:bg-(--bg-primary) [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-xs", 27 + "[&_pre]:mb-5 [&_pre]:overflow-x-auto [&_pre]:rounded [&_pre]:bg-(--bg-primary) [&_pre]:p-4 [&_pre]:font-mono [&_pre]:text-xs", 28 + "[&_a]:text-(--accent-default) [&_a]:underline [&_a]:decoration-(--accent-default)/30 [&_a]:underline-offset-2 hover:[&_a]:decoration-(--accent-default)", 29 + "[&_blockquote]:mb-5 [&_blockquote]:border-l-2 [&_blockquote]:border-(--accent-default) [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:text-(--text-muted)", 30 + "[&_hr]:my-8 [&_hr]:border-(--border-default)", 31 + ].join(" ")} 32 + > 33 + {content} 19 34 </div> 20 35 <div className="mt-8 border-t border-(--border-default) pt-5 font-mono text-xs uppercase text-(--text-muted)"> 21 36 Strategy notes / walkthrough
+3 -9
src/components/strategy-page-layout.tsx
··· 1 1 import { ChapterPager } from "~/components/chapter-navigation"; 2 - import { StrategyArticle } from "~/components/strategy-article"; 3 2 4 3 interface StrategyPageLayoutProps { 5 - articleEyebrow: string; 6 - articleTitle: string; 4 + sidebar?: React.ReactNode; 7 5 children: React.ReactNode; 8 6 } 9 7 10 - export function StrategyPageLayout({ 11 - articleEyebrow, 12 - articleTitle, 13 - children, 14 - }: StrategyPageLayoutProps) { 8 + export function StrategyPageLayout({ sidebar, children }: StrategyPageLayoutProps) { 15 9 return ( 16 10 <> 17 11 <div className="grid gap-8 xl:grid-cols-[minmax(0,0.9fr)_minmax(34rem,1.1fr)] xl:items-start"> 18 - <StrategyArticle eyebrow={articleEyebrow} title={articleTitle} /> 12 + {sidebar} 19 13 <div className="min-w-0">{children}</div> 20 14 </div> 21 15 <ChapterPager />
-44
src/lib/collections.ts
··· 1 - import { BasicIndex, createCollection } from "@tanstack/react-db"; 2 - import { electricCollectionOptions } from "@tanstack/electric-db-collection"; 3 - import { snakeCamelMapper } from "@electric-sql/client"; 4 - 5 - import { pokemonSelectSchema, typesSelectSchema, pokemonTypesSelectSchema } from "~/data/schema"; 6 - 7 - export const pokemonCollection = createCollection( 8 - electricCollectionOptions({ 9 - shapeOptions: { 10 - url: "http://localhost:3000/api/shapes/pokemon", 11 - columnMapper: snakeCamelMapper(), 12 - }, 13 - getKey: (item) => item.id, 14 - schema: pokemonSelectSchema, 15 - }), 16 - ); 17 - pokemonCollection.createIndex((row) => row.id, { indexType: BasicIndex }); 18 - pokemonCollection.createIndex((row) => row.dexId, { indexType: BasicIndex }); 19 - 20 - export const typesCollection = createCollection( 21 - electricCollectionOptions({ 22 - shapeOptions: { 23 - url: "http://localhost:3000/api/shapes/types", 24 - columnMapper: snakeCamelMapper(), 25 - }, 26 - getKey: (item) => item.id, 27 - schema: typesSelectSchema, 28 - }), 29 - ); 30 - typesCollection.createIndex((row) => row.id, { indexType: BasicIndex }); 31 - 32 - export const pokemonTypesCollection = createCollection( 33 - electricCollectionOptions({ 34 - shapeOptions: { 35 - url: "http://localhost:3000/api/shapes/pokemon-types", 36 - columnMapper: snakeCamelMapper(), 37 - }, 38 - getKey: (item) => item.id, 39 - schema: pokemonTypesSelectSchema, 40 - }), 41 - ); 42 - pokemonTypesCollection.createIndex((row) => row.id, { indexType: BasicIndex }); 43 - pokemonTypesCollection.createIndex((row) => row.pokemonId, { indexType: BasicIndex }); 44 - pokemonTypesCollection.createIndex((row) => row.typeId, { indexType: BasicIndex });
+1 -1
src/routes/__root.tsx
··· 85 85 Skip to main content 86 86 </a> 87 87 <Header /> 88 - <div id="main-content">{props.children}</div> 88 + {props.children} 89 89 90 90 <TanStackDevtools 91 91 plugins={[
+13 -5
src/routes/basic.tsx
··· 6 6 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 7 7 import { ConsoleCard } from "~/components/console/console-card"; 8 8 import { SectionHeader } from "~/components/console/section-header"; 9 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 9 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 10 10 import { POKEMON_LIMIT } from "~/constants"; 11 - import { getPokemonListQueryFn, getPokemonListQueryKey } from "~/util/pokemon"; 12 - import { lazily } from "~/util/lazily"; 11 + import { getPokemonListQueryFn, getPokemonListQueryKey } from "~/utils/pokemon"; 12 + import { lazily } from "~/lib/lazily"; 13 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 13 14 14 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 15 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 15 16 16 17 const searchParamsSchema = v.object({ 17 18 offset: v.optional(v.number(), 0), ··· 19 20 20 21 export const Route = createFileRoute("/basic")({ 21 22 validateSearch: searchParamsSchema, 23 + loader: async () => { 24 + const { Renderable: Article } = await getStrategyArticle({ 25 + data: { title: "No prefetching", slug: "basic" }, 26 + }); 27 + return { Article }; 28 + }, 22 29 component: RouteComponent, 23 30 }); 24 31 25 32 function RouteComponent() { 26 33 const { offset: currentOffset } = Route.useSearch(); 34 + const { Article } = Route.useLoaderData(); 27 35 28 36 return ( 29 37 <main className="min-h-screen bg-(--bg-primary) p-6"> 30 38 <div className="max-w-7xl mx-auto"> 31 39 <SectionHeader title="01_basic" subtitle="// No prefetching (baseline)" /> 32 40 33 - <StrategyPageLayout articleEyebrow="Baseline" articleTitle="No prefetching"> 41 + <StrategyPageLayout sidebar={Article}> 34 42 <ConsoleCard className="mb-6"> 35 43 <h1 className="text-lg font-mono text-(--text-primary) mb-4"> 36 44 National Pokédex: Pokémon {currentOffset + 1}-{currentOffset + POKEMON_LIMIT}
+12 -9
src/routes/debounced-preload-filters.tsx
··· 8 8 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 9 9 import { ConsoleCard } from "~/components/console/console-card"; 10 10 import { SectionHeader } from "~/components/console/section-header"; 11 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 11 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 12 12 import { POKEMON_LIMIT } from "~/constants"; 13 - import { getFilteredPokemonListQueryKey, getFilteredPokemonListQueryFn } from "~/util/pokemon"; 14 - import { lazily } from "~/util/lazily"; 13 + import { getFilteredPokemonListQueryKey, getFilteredPokemonListQueryFn } from "~/utils/pokemon"; 14 + import { lazily } from "~/lib/lazily"; 15 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 15 16 16 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 17 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 17 18 18 19 const searchParamsSchema = v.object({ 19 20 offset: v.optional(v.number(), 0), ··· 42 43 pokemonListOptions, 43 44 }; 44 45 }, 45 - loader: ({ context }) => { 46 + loader: async ({ context }) => { 46 47 void context.queryClient.prefetchQuery(context.pokemonListOptions); 48 + const { Renderable: Article } = await getStrategyArticle({ 49 + data: { title: "Debounced filter prefetch", slug: "debounced-preload-filters" }, 50 + }); 51 + return { Article }; 47 52 }, 48 53 component: RouteComponent, 49 54 }); ··· 94 99 95 100 function RouteComponent() { 96 101 const { offset: currentOffset, name: nameFilter } = Route.useSearch(); 102 + const { Article } = Route.useLoaderData(); 97 103 const navigate = Route.useNavigate(); 98 104 99 105 return ( ··· 101 107 <div className="max-w-7xl mx-auto"> 102 108 <SectionHeader title="06_debounced" subtitle="// Advanced filter prefetch" /> 103 109 104 - <StrategyPageLayout 105 - articleEyebrow="Debounced search" 106 - articleTitle="Debounced filter prefetch" 107 - > 110 + <StrategyPageLayout sidebar={Article}> 108 111 {/* Filter UI */} 109 112 <ConsoleCard className="mb-6"> 110 113 <h2 className="text-sm font-semibold mb-4 text-(--text-primary) uppercase tracking-wider">
+12 -6
src/routes/filters.tsx
··· 7 7 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 8 8 import { ConsoleCard } from "~/components/console/console-card"; 9 9 import { SectionHeader } from "~/components/console/section-header"; 10 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 10 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 11 11 import { POKEMON_LIMIT } from "~/constants"; 12 - import { getFilteredPokemonListQueryKey, getFilteredPokemonListQueryFn } from "~/util/pokemon"; 13 - import { lazily } from "~/util/lazily"; 12 + import { getFilteredPokemonListQueryKey, getFilteredPokemonListQueryFn } from "~/utils/pokemon"; 13 + import { lazily } from "~/lib/lazily"; 14 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 14 15 15 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 16 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 16 17 17 18 const searchParamsSchema = v.object({ 18 19 offset: v.optional(v.number(), 0), ··· 57 58 pokemonListOptions, 58 59 }; 59 60 }, 60 - loader: ({ context }) => { 61 + loader: async ({ context }) => { 61 62 void context.queryClient.prefetchQuery(context.pokemonListOptions); 63 + const { Renderable: Article } = await getStrategyArticle({ 64 + data: { title: "Submitted filter prefetch", slug: "filters" }, 65 + }); 66 + return { Article }; 62 67 }, 63 68 component: RouteComponent, 64 69 }); 65 70 66 71 function RouteComponent() { 67 72 const { offset: currentOffset, name: nameFilter } = Route.useSearch(); 73 + const { Article } = Route.useLoaderData(); 68 74 const navigate = Route.useNavigate(); 69 75 70 76 return ( ··· 72 78 <div className="max-w-7xl mx-auto"> 73 79 <SectionHeader title="05_filters" subtitle="// Search with prefetch" /> 74 80 75 - <StrategyPageLayout articleEyebrow="Search" articleTitle="Submitted filter prefetch"> 81 + <StrategyPageLayout sidebar={Article}> 76 82 {/* Filter UI */} 77 83 <ConsoleCard className="mb-6"> 78 84 <h2 className="text-sm font-semibold mb-4 text-(--text-primary) uppercase tracking-wider">
+12 -6
src/routes/intent-preloading.tsx
··· 6 6 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 7 7 import { ConsoleCard } from "~/components/console/console-card"; 8 8 import { SectionHeader } from "~/components/console/section-header"; 9 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 9 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 10 10 import { POKEMON_LIMIT } from "~/constants"; 11 - import { getPokemonListQueryKey, getPokemonListQueryFn } from "~/util/pokemon"; 12 - import { lazily } from "~/util/lazily"; 11 + import { getPokemonListQueryKey, getPokemonListQueryFn } from "~/utils/pokemon"; 12 + import { lazily } from "~/lib/lazily"; 13 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 13 14 14 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 15 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 15 16 16 17 const searchParamsSchema = v.object({ 17 18 offset: v.optional(v.number(), 0), ··· 34 35 pokemonListOptions, 35 36 }; 36 37 }, 37 - loader: ({ context }) => { 38 + loader: async ({ context }) => { 38 39 void context.queryClient.prefetchQuery(context.pokemonListOptions); 40 + const { Renderable: Article } = await getStrategyArticle({ 41 + data: { title: "Hover and focus preloading", slug: "intent-preloading" }, 42 + }); 43 + return { Article }; 39 44 }, 40 45 component: RouteComponent, 41 46 }); 42 47 43 48 function RouteComponent() { 44 49 const { offset: currentOffset } = Route.useSearch(); 50 + const { Article } = Route.useLoaderData(); 45 51 46 52 return ( 47 53 <main className="min-h-screen bg-(--bg-primary) p-6"> 48 54 <div className="max-w-7xl mx-auto"> 49 55 <SectionHeader title="03_intent-preloading" subtitle="// Hover-based prefetch" /> 50 56 51 - <StrategyPageLayout articleEyebrow="Intent" articleTitle="Hover and focus preloading"> 57 + <StrategyPageLayout sidebar={Article}> 52 58 <ConsoleCard className="mb-6"> 53 59 <h1 className="text-lg font-mono text-(--text-primary) mb-4"> 54 60 National Pokédex: Pokémon {currentOffset + 1}-{currentOffset + POKEMON_LIMIT}
+17 -5
src/routes/live-query-filters.tsx
··· 4 4 import * as v from "valibot"; 5 5 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 6 6 import { ConsoleCard } from "~/components/console/console-card"; 7 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 7 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 8 8 import { SectionHeader } from "~/components/console/section-header"; 9 9 import { FilterForm, FilterSubmitContext } from "~/components/filter-form"; 10 - import { pokemonCollection, pokemonTypesCollection, typesCollection } from "~/lib/collections"; 10 + import { 11 + pokemonCollection, 12 + pokemonTypesCollection, 13 + typesCollection, 14 + } from "~/data/local/collections"; 11 15 import { cn } from "~/lib/utils"; 12 16 import { POKEMON_LIMIT } from "~/constants"; 13 - import { lazily } from "~/util/lazily"; 17 + import { lazily } from "~/lib/lazily"; 18 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 14 19 15 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 20 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 16 21 17 22 const searchParamsSchema = v.object({ 18 23 offset: v.optional(v.number(), 0), ··· 42 47 export const Route = createFileRoute("/live-query-filters")({ 43 48 ssr: false, 44 49 validateSearch: searchParamsSchema, 50 + loader: async () => { 51 + const { Renderable: Article } = await getStrategyArticle({ 52 + data: { title: "Reactive filtered data", slug: "live-query-filters" }, 53 + }); 54 + return { Article }; 55 + }, 45 56 component: RouteComponent, 46 57 }); 47 58 48 59 function RouteComponent() { 49 60 const { offset: currentOffset, name: nameFilter } = Route.useSearch(); 61 + const { Article } = Route.useLoaderData(); 50 62 const navigate = Route.useNavigate(); 51 63 52 64 return ( ··· 54 66 <div className="max-w-7xl mx-auto"> 55 67 <SectionHeader title="08_live-query-filters" subtitle="// Electric SQL live search" /> 56 68 57 - <StrategyPageLayout articleEyebrow="Live search" articleTitle="Reactive filtered data"> 69 + <StrategyPageLayout sidebar={Article}> 58 70 <div> 59 71 <ConsoleCard className="mb-6"> 60 72 <h2 className="text-sm font-semibold mb-4 text-(--text-primary) uppercase tracking-wider">
+17 -5
src/routes/live-query.tsx
··· 6 6 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 7 7 import { ConsoleCard } from "~/components/console/console-card"; 8 8 import { SectionHeader } from "~/components/console/section-header"; 9 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 9 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 10 10 import { POKEMON_LIMIT } from "~/constants"; 11 - import { lazily } from "~/util/lazily"; 12 - import { pokemonCollection, typesCollection, pokemonTypesCollection } from "~/lib/collections"; 11 + import { lazily } from "~/lib/lazily"; 12 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 13 + import { 14 + pokemonCollection, 15 + typesCollection, 16 + pokemonTypesCollection, 17 + } from "~/data/local/collections"; 13 18 14 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 19 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 15 20 16 21 const searchParamsSchema = v.object({ 17 22 offset: v.optional(v.number(), 0), ··· 20 25 export const Route = createFileRoute("/live-query")({ 21 26 ssr: false, 22 27 validateSearch: searchParamsSchema, 28 + loader: async () => { 29 + const { Renderable: Article } = await getStrategyArticle({ 30 + data: { title: "Synced collection", slug: "live-query" }, 31 + }); 32 + return { Article }; 33 + }, 23 34 component: RouteComponent, 24 35 }); 25 36 26 37 function RouteComponent() { 27 38 const { offset: currentOffset } = Route.useSearch(); 39 + const { Article } = Route.useLoaderData(); 28 40 29 41 return ( 30 42 <main className="min-h-screen bg-(--bg-primary) p-6"> 31 43 <div className="max-w-7xl mx-auto"> 32 44 <SectionHeader title="07_live-query" subtitle="// Electric SQL synced collection" /> 33 45 34 - <StrategyPageLayout articleEyebrow="Live query" articleTitle="Synced collection"> 46 + <StrategyPageLayout sidebar={Article}> 35 47 <ConsoleCard className="mb-6"> 36 48 <h1 className="text-lg font-mono text-(--text-primary) mb-4"> 37 49 National Pokédex: Pokémon {currentOffset + 1}-{currentOffset + POKEMON_LIMIT}
+12 -6
src/routes/pagination.tsx
··· 6 6 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 7 7 import { ConsoleCard } from "~/components/console/console-card"; 8 8 import { SectionHeader } from "~/components/console/section-header"; 9 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 9 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 10 10 import { POKEMON_LIMIT } from "~/constants"; 11 - import { getPokemonListQueryKey, getPokemonListQueryFn } from "~/util/pokemon"; 12 - import { lazily } from "~/util/lazily"; 11 + import { getPokemonListQueryKey, getPokemonListQueryFn } from "~/utils/pokemon"; 12 + import { lazily } from "~/lib/lazily"; 13 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 13 14 14 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 15 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 15 16 16 17 const searchParamsSchema = v.object({ 17 18 offset: v.optional(v.number(), 0), ··· 34 35 pokemonListOptions, 35 36 }; 36 37 }, 37 - loader: ({ context }) => { 38 + loader: async ({ context }) => { 38 39 void context.queryClient.prefetchQuery(context.pokemonListOptions); 40 + const { Renderable: Article } = await getStrategyArticle({ 41 + data: { title: "Viewport pagination preload", slug: "pagination" }, 42 + }); 43 + return { Article }; 39 44 }, 40 45 component: RouteComponent, 41 46 }); 42 47 43 48 function RouteComponent() { 44 49 const { offset: currentOffset } = Route.useSearch(); 50 + const { Article } = Route.useLoaderData(); 45 51 46 52 return ( 47 53 <main className="min-h-screen bg-(--bg-primary) p-6"> 48 54 <div className="max-w-7xl mx-auto"> 49 55 <SectionHeader title="04_pagination" subtitle="// Preloading next/prev pages" /> 50 56 51 - <StrategyPageLayout articleEyebrow="Pagination" articleTitle="Viewport pagination preload"> 57 + <StrategyPageLayout sidebar={Article}> 52 58 <ConsoleCard className="mb-6"> 53 59 <h1 className="text-lg font-mono text-(--text-primary) mb-4"> 54 60 National Pokédex: Pokémon {currentOffset + 1}-{currentOffset + POKEMON_LIMIT}
+12 -6
src/routes/preloading.tsx
··· 6 6 import { StrategyPageLayout } from "~/components/strategy-page-layout"; 7 7 import { ConsoleCard } from "~/components/console/console-card"; 8 8 import { SectionHeader } from "~/components/console/section-header"; 9 - import { PokemonTableSkeleton } from "~/components/console/pokemon-table-skeleton"; 9 + import { PokemonTableSkeleton } from "~/components/tables/pokemon-table-skeleton"; 10 10 import { POKEMON_LIMIT } from "~/constants"; 11 - import { getPokemonListQueryKey, getPokemonListQueryFn } from "~/util/pokemon"; 12 - import { lazily } from "~/util/lazily"; 11 + import { getPokemonListQueryKey, getPokemonListQueryFn } from "~/utils/pokemon"; 12 + import { lazily } from "~/lib/lazily"; 13 + import { getStrategyArticle } from "~/server/strategy-article.functions"; 13 14 14 - const { PokemonTable } = lazily(() => import("~/components/console/pokemon-table")); 15 + const { PokemonTable } = lazily(() => import("~/components/tables/pokemon-table")); 15 16 16 17 const searchParamsSchema = v.object({ 17 18 offset: v.optional(v.number(), 0), ··· 34 35 pokemonListOptions, 35 36 }; 36 37 }, 37 - loader: ({ context }) => { 38 + loader: async ({ context }) => { 38 39 void context.queryClient.prefetchQuery(context.pokemonListOptions); 40 + const { Renderable: Article } = await getStrategyArticle({ 41 + data: { title: "Route-level prefetch", slug: "preloading" }, 42 + }); 43 + return { Article }; 39 44 }, 40 45 component: RouteComponent, 41 46 }); 42 47 43 48 function RouteComponent() { 44 49 const { offset: currentOffset } = Route.useSearch(); 50 + const { Article } = Route.useLoaderData(); 45 51 46 52 return ( 47 53 <main className="min-h-screen bg-(--bg-primary) p-6"> 48 54 <div className="max-w-7xl mx-auto"> 49 55 <SectionHeader title="02_preloading" subtitle="// Route-level prefetch" /> 50 56 51 - <StrategyPageLayout articleEyebrow="Route loader" articleTitle="Route-level prefetch"> 57 + <StrategyPageLayout sidebar={Article}> 52 58 <ConsoleCard className="mb-6"> 53 59 <h1 className="text-lg font-mono text-(--text-primary) mb-4"> 54 60 National Pokédex: Pokémon {currentOffset + 1}-{currentOffset + POKEMON_LIMIT}
-84
src/server/pokemon.ts
··· 1 - import { createServerFn } from "@tanstack/react-start"; 2 - import * as v from "valibot"; 3 - import { DB } from "~/data/db"; 4 - import { POKEMON_LIMIT } from "~/constants"; 5 - 6 - const PokemonListParamsSchema = v.object({ 7 - offset: v.optional(v.number()), 8 - }); 9 - 10 - const FilteredPokemonListParamsSchema = v.object({ 11 - offset: v.optional(v.number()), 12 - nameFilter: v.optional(v.string()), 13 - }); 14 - 15 - const innerGetPokemonList = async (offset: number) => { 16 - // Fetch one extra item to check if there are more results 17 - const pokemon = await DB.queries.getPokemonAtOffset(offset, POKEMON_LIMIT + 1); 18 - 19 - // Check if there are more results by looking at the extra item 20 - const hasMore = pokemon.length > POKEMON_LIMIT; 21 - 22 - // Remove the extra item if it exists 23 - const results = hasMore ? pokemon.slice(0, -1) : pokemon; 24 - 25 - return { 26 - pokemon: results, 27 - nextOffset: hasMore ? offset + POKEMON_LIMIT : null, 28 - prevOffset: offset > 0 ? Math.max(0, offset - POKEMON_LIMIT) : null, 29 - }; 30 - }; 31 - 32 - const innerGetFilteredPokemonList = async (offset: number, nameFilter: string) => { 33 - // If no filter is provided, fall back to regular query 34 - if (!nameFilter.trim()) { 35 - return await innerGetPokemonList(offset); 36 - } 37 - 38 - // Fetch one extra item to check if there are more results 39 - const pokemon = await DB.queries.getFilteredPokemonAtOffset( 40 - offset, 41 - POKEMON_LIMIT + 1, 42 - `%${nameFilter.trim()}%`, 43 - ); 44 - 45 - // Check if there are more results by looking at the extra item 46 - const hasMore = pokemon.length > POKEMON_LIMIT; 47 - 48 - // Remove the extra item if it exists 49 - const results = hasMore ? pokemon.slice(0, -1) : pokemon; 50 - 51 - return { 52 - pokemon: results, 53 - nextOffset: hasMore ? offset + POKEMON_LIMIT : null, 54 - prevOffset: offset > 0 ? Math.max(0, offset - POKEMON_LIMIT) : null, 55 - appliedFilter: nameFilter.trim(), 56 - }; 57 - }; 58 - 59 - export const getServerPokemonList = createServerFn({ method: "GET" }) 60 - .inputValidator((params) => { 61 - const validated = v.parse(PokemonListParamsSchema, params); 62 - const offset = validated.offset ?? 0; 63 - 64 - if (offset < 0) throw new Error("Offset must be greater than or equal to 0"); 65 - 66 - return { offset }; 67 - }) 68 - .handler(async ({ data }) => { 69 - return await innerGetPokemonList(data.offset); 70 - }); 71 - 72 - export const getServerFilteredPokemonList = createServerFn({ method: "GET" }) 73 - .inputValidator((params) => { 74 - const validated = v.parse(FilteredPokemonListParamsSchema, params); 75 - const offset = validated.offset ?? 0; 76 - const nameFilter = validated.nameFilter ?? ""; 77 - 78 - if (offset < 0) throw new Error("Offset must be greater than or equal to 0"); 79 - 80 - return { offset, nameFilter }; 81 - }) 82 - .handler(async ({ data }) => { 83 - return await innerGetFilteredPokemonList(data.offset, data.nameFilter); 84 - });
-40
src/util/lazily.ts
··· 1 - /* 2 - * src: github.com/JLarky/react-lazily/blob/main/src/core/lazily.ts 3 - * 4 - * MIT License 5 - * Copyright (c) 2020 JLarky 6 - * 7 - * Permission is hereby granted, free of charge, to any person obtaining a copy 8 - * of this software and associated documentation files (the "Software"), to deal 9 - * in the Software without restriction, including without limitation the rights 10 - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 - * copies of the Software, and to permit persons to whom the Software is 12 - * furnished to do so, subject to the following conditions: 13 - * 14 - * The above copyright notice and this permission notice shall be included in all 15 - * copies or substantial portions of the Software. 16 - * 17 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 - SOFTWARE. 24 - * 25 - */ 26 - 27 - import { lazy } from "react"; 28 - 29 - export const lazily = <T extends {}, U extends keyof T>(loader: (x?: string) => Promise<T>) => 30 - new Proxy({} as unknown as T, { 31 - get: (_target, componentName: string | symbol) => { 32 - if (typeof componentName === "string") { 33 - return lazy(() => 34 - loader(componentName).then((x) => ({ 35 - default: x[componentName as U] as any as React.ComponentType<any>, 36 - })), 37 - ); 38 - } 39 - }, 40 - });
-28
src/util/pokemon.ts
··· 1 - import type { QueryFunctionContext } from "@tanstack/react-query"; 2 - import { getServerPokemonList, getServerFilteredPokemonList } from "~/server/pokemon"; 3 - 4 - export const getPokemonListQueryKey = (location: string, offset: number) => { 5 - return ["pokemon-list", location, { offset }] as const; 6 - }; 7 - 8 - export const getFilteredPokemonListQueryKey = ( 9 - location: string, 10 - offset: number, 11 - nameFilter: string, 12 - ) => { 13 - return ["pokemon-list", location, { offset, nameFilter }] as const; 14 - }; 15 - 16 - export const getPokemonListQueryFn = async ({ 17 - queryKey, 18 - }: QueryFunctionContext<ReturnType<typeof getPokemonListQueryKey>>) => { 19 - const { offset } = queryKey[2]; 20 - return getServerPokemonList({ data: { offset } }); 21 - }; 22 - 23 - export const getFilteredPokemonListQueryFn = async ({ 24 - queryKey, 25 - }: QueryFunctionContext<ReturnType<typeof getFilteredPokemonListQueryKey>>) => { 26 - const { offset, nameFilter } = queryKey[2]; 27 - return getServerFilteredPokemonList({ data: { offset, nameFilter } }); 28 - };