Got claude started on the docs. Will have to update them heavily
All checks were successful
linter / quality (push) Successful in 3m34s
tests / ci (push) Successful in 7m10s

This commit is contained in:
Javier Feliz 2025-08-03 00:23:06 -04:00
parent 92164921a5
commit 9db9b0f6b3
16 changed files with 3365 additions and 172 deletions

1
.gitignore vendored
View File

@ -27,3 +27,4 @@ yarn-error.log
**/caddy
frankenphp
frankenphp-worker.php
/docs/.vitepress/cache

603
bun.lock Normal file
View File

@ -0,0 +1,603 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {
"@tailwindcss/vite": "^4.0.7",
"autoprefixer": "^10.4.20",
"axios": "^1.7.4",
"concurrently": "^9.0.1",
"laravel-vite-plugin": "^1.0",
"tailwindcss": "^4.0.7",
"vite": "^6.0",
},
"devDependencies": {
"vitepress": "^1.6.3",
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.9.5",
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
"lightningcss-linux-x64-gnu": "^1.29.1",
},
},
},
"packages": {
"@algolia/abtesting": ["@algolia/abtesting@1.1.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow=="],
"@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.17.7", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", "@algolia/autocomplete-shared": "1.17.7" } }, "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q=="],
"@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.17.7", "", { "dependencies": { "@algolia/autocomplete-shared": "1.17.7" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A=="],
"@algolia/autocomplete-preset-algolia": ["@algolia/autocomplete-preset-algolia@1.17.7", "", { "dependencies": { "@algolia/autocomplete-shared": "1.17.7" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA=="],
"@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.17.7", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg=="],
"@algolia/client-abtesting": ["@algolia/client-abtesting@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ=="],
"@algolia/client-analytics": ["@algolia/client-analytics@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw=="],
"@algolia/client-common": ["@algolia/client-common@5.35.0", "", {}, "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w=="],
"@algolia/client-insights": ["@algolia/client-insights@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA=="],
"@algolia/client-personalization": ["@algolia/client-personalization@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA=="],
"@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w=="],
"@algolia/client-search": ["@algolia/client-search@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg=="],
"@algolia/ingestion": ["@algolia/ingestion@1.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA=="],
"@algolia/monitoring": ["@algolia/monitoring@1.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw=="],
"@algolia/recommend": ["@algolia/recommend@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ=="],
"@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0" } }, "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw=="],
"@algolia/requester-fetch": ["@algolia/requester-fetch@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0" } }, "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ=="],
"@algolia/requester-node-http": ["@algolia/requester-node-http@5.35.0", "", { "dependencies": { "@algolia/client-common": "5.35.0" } }, "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
"@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": "./bin/babel-parser.js" }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="],
"@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
"@docsearch/css": ["@docsearch/css@3.8.2", "", {}, "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ=="],
"@docsearch/js": ["@docsearch/js@3.8.2", "", { "dependencies": { "@docsearch/react": "3.8.2", "preact": "^10.0.0" } }, "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ=="],
"@docsearch/react": ["@docsearch/react@3.8.2", "", { "dependencies": { "@algolia/autocomplete-core": "1.17.7", "@algolia/autocomplete-preset-algolia": "1.17.7", "@docsearch/css": "3.8.2", "algoliasearch": "^5.14.2" }, "peerDependencies": { "@types/react": ">= 16.8.0 < 19.0.0", "react": ">= 16.8.0 < 19.0.0", "react-dom": ">= 16.8.0 < 19.0.0", "search-insights": ">= 1 < 3" }, "optionalPeers": ["@types/react", "react", "react-dom", "search-insights"] }, "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.0", "", { "os": "android", "cpu": "arm" }, "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.0", "", { "os": "android", "cpu": "arm64" }, "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.0", "", { "os": "android", "cpu": "x64" }, "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.0", "", { "os": "linux", "cpu": "arm" }, "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.0", "", { "os": "linux", "cpu": "none" }, "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.0", "", { "os": "none", "cpu": "arm64" }, "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.0", "", { "os": "none", "cpu": "x64" }, "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ=="],
"@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.45", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-POOz+NjYQDy2fy1u+sIZi05N6r6oSooIGBaBcZLh7w8QOmLgJAZ6mBt+7Messp7ku9ucRua61if33BPoOZCwRQ=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.4", "", {}, "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q=="],
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ=="],
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.9.5", "", { "os": "linux", "cpu": "x64" }, "sha512-Dq1bqBdLaZ1Gb/l2e5/+o3B18+8TI9ANlA1SkejZqDgdU/jK/ThYaMPMJpVMMXy2uRHvGKbkz9vheVGdq3cJfA=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.8", "", { "os": "win32", "cpu": "x64" }, "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g=="],
"@shikijs/core": ["@shikijs/core@2.5.0", "", { "dependencies": { "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg=="],
"@shikijs/engine-javascript": ["@shikijs/engine-javascript@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^3.1.0" } }, "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w=="],
"@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw=="],
"@shikijs/langs": ["@shikijs/langs@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0" } }, "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w=="],
"@shikijs/themes": ["@shikijs/themes@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0" } }, "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw=="],
"@shikijs/transformers": ["@shikijs/transformers@2.5.0", "", { "dependencies": { "@shikijs/core": "2.5.0", "@shikijs/types": "2.5.0" } }, "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg=="],
"@shikijs/types": ["@shikijs/types@2.5.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw=="],
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
"@tailwindcss/node": ["@tailwindcss/node@4.0.8", "", { "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "tailwindcss": "4.0.8" } }, "sha512-FKArQpbrbwv08TNT0k7ejYXpF+R8knZFAatNc0acOxbgeqLzwb86r+P3LGOjIeI3Idqe9CVkZrh4GlsJLJKkkw=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.0.8", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.0.8", "@tailwindcss/oxide-darwin-arm64": "4.0.8", "@tailwindcss/oxide-darwin-x64": "4.0.8", "@tailwindcss/oxide-freebsd-x64": "4.0.8", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.8", "@tailwindcss/oxide-linux-arm64-gnu": "4.0.8", "@tailwindcss/oxide-linux-arm64-musl": "4.0.8", "@tailwindcss/oxide-linux-x64-gnu": "4.0.8", "@tailwindcss/oxide-linux-x64-musl": "4.0.8", "@tailwindcss/oxide-win32-arm64-msvc": "4.0.8", "@tailwindcss/oxide-win32-x64-msvc": "4.0.8" } }, "sha512-KfMcuAu/Iw+DcV1e8twrFyr2yN8/ZDC/odIGta4wuuJOGkrkHZbvJvRNIbQNhGh7erZTYV6Ie0IeD6WC9Y8Hcw=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.0.8", "", { "os": "android", "cpu": "arm64" }, "sha512-We7K79+Sm4mwJHk26Yzu/GAj7C7myemm7PeXvpgMxyxO70SSFSL3uCcqFbz9JA5M5UPkrl7N9fkBe/Y0iazqpA=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.0.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Lv9Isi2EwkCTG1sRHNDi0uRNN1UGFdEThUAGFrydRmQZnraGLMjN8gahzg2FFnOizDl7LB2TykLUuiw833DSNg=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.0.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-fWfywfYIlSWtKoqWTjukTHLWV3ARaBRjXCC2Eo0l6KVpaqGY4c2y8snUjp1xpxUtpqwMvCvFWFaleMoz1Vhzlw=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.0.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SO+dyvjJV9G94bnmq2288Ke0BIdvrbSbvtPLaQdqjqHR83v5L2fWADyFO+1oecHo9Owsk8MxcXh1agGVPIKIqw=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.0.8", "", { "os": "linux", "cpu": "arm" }, "sha512-ZSHggWiEblQNV69V0qUK5vuAtHP+I+S2eGrKGJ5lPgwgJeAd6GjLsVBN+Mqn2SPVfYM3BOpS9jX/zVg9RWQVDQ=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.0.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-xWpr6M0OZLDNsr7+bQz+3X7zcnDJZJ1N9gtBWCtfhkEtDjjxYEp+Lr5L5nc/yXlL4MyCHnn0uonGVXy3fhxaVA=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.0.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-5tz2IL7LN58ssGEq7h/staD7pu/izF/KeMWdlJ86WDe2Ah46LF3ET6ZGKTr5eZMrnEA0M9cVFuSPprKRHNgjeg=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.0.8", "", { "os": "linux", "cpu": "x64" }, "sha512-KSzMkhyrxAQyY2o194NKVKU9j/c+NFSoMvnHWFaNHKi3P1lb+Vq1UC19tLHrmxSkKapcMMu69D7+G1+FVGNDXQ=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.0.8", "", { "os": "linux", "cpu": "x64" }, "sha512-yFYKG5UtHTRimjtqxUWXBgI4Tc6NJe3USjRIVdlTczpLRxq/SFwgzGl5JbatCxgSRDPBFwRrNPxq+ukfQFGdrw=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.0.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-tndGujmCSba85cRCnQzXgpA2jx5gXimyspsUYae5jlPyLRG0RjXbDshFKOheVXU4TLflo7FSG8EHCBJ0EHTKdQ=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.0.8", "", { "os": "win32", "cpu": "x64" }, "sha512-T77jroAc0p4EHVVgTUiNeFn6Nj3jtD3IeNId2X+0k+N1XxfNipy81BEkYErpKLiOkNhpNFjPee8/ZVas29b2OQ=="],
"@tailwindcss/vite": ["@tailwindcss/vite@4.0.8", "", { "dependencies": { "@tailwindcss/node": "4.0.8", "@tailwindcss/oxide": "4.0.8", "lightningcss": "^1.29.1", "tailwindcss": "4.0.8" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-+SAq44yLzYlzyrb7QTcFCdU8Xa7FOA0jp+Xby7fPMUie+MY9HhJysM7Vp+vL8qIp8ceQJfLD+FjgJuJ4lL6nyg=="],
"@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="],
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
"@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="],
"@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="],
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
"@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="],
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="],
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
"@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="],
"@vue/compiler-core": ["@vue/compiler-core@3.5.18", "", { "dependencies": { "@babel/parser": "^7.28.0", "@vue/shared": "3.5.18", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw=="],
"@vue/compiler-dom": ["@vue/compiler-dom@3.5.18", "", { "dependencies": { "@vue/compiler-core": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A=="],
"@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.18", "", { "dependencies": { "@babel/parser": "^7.28.0", "@vue/compiler-core": "3.5.18", "@vue/compiler-dom": "3.5.18", "@vue/compiler-ssr": "3.5.18", "@vue/shared": "3.5.18", "estree-walker": "^2.0.2", "magic-string": "^0.30.17", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA=="],
"@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.18", "", { "dependencies": { "@vue/compiler-dom": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g=="],
"@vue/devtools-api": ["@vue/devtools-api@7.7.7", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="],
"@vue/devtools-kit": ["@vue/devtools-kit@7.7.7", "", { "dependencies": { "@vue/devtools-shared": "^7.7.7", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA=="],
"@vue/devtools-shared": ["@vue/devtools-shared@7.7.7", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw=="],
"@vue/reactivity": ["@vue/reactivity@3.5.18", "", { "dependencies": { "@vue/shared": "3.5.18" } }, "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg=="],
"@vue/runtime-core": ["@vue/runtime-core@3.5.18", "", { "dependencies": { "@vue/reactivity": "3.5.18", "@vue/shared": "3.5.18" } }, "sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w=="],
"@vue/runtime-dom": ["@vue/runtime-dom@3.5.18", "", { "dependencies": { "@vue/reactivity": "3.5.18", "@vue/runtime-core": "3.5.18", "@vue/shared": "3.5.18", "csstype": "^3.1.3" } }, "sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw=="],
"@vue/server-renderer": ["@vue/server-renderer@3.5.18", "", { "dependencies": { "@vue/compiler-ssr": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "vue": "3.5.18" } }, "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA=="],
"@vue/shared": ["@vue/shared@3.5.18", "", {}, "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA=="],
"@vueuse/core": ["@vueuse/core@12.8.2", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "12.8.2", "@vueuse/shared": "12.8.2", "vue": "^3.5.13" } }, "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ=="],
"@vueuse/integrations": ["@vueuse/integrations@12.8.2", "", { "dependencies": { "@vueuse/core": "12.8.2", "@vueuse/shared": "12.8.2", "vue": "^3.5.13" }, "peerDependencies": { "async-validator": "^4", "axios": "^1", "change-case": "^5", "drauu": "^0.4", "focus-trap": "^7", "fuse.js": "^7", "idb-keyval": "^6", "jwt-decode": "^4", "nprogress": "^0.2", "qrcode": "^1.5", "sortablejs": "^1", "universal-cookie": "^7" }, "optionalPeers": ["async-validator", "axios", "change-case", "drauu", "focus-trap", "fuse.js", "idb-keyval", "jwt-decode", "nprogress", "qrcode", "sortablejs", "universal-cookie"] }, "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g=="],
"@vueuse/metadata": ["@vueuse/metadata@12.8.2", "", {}, "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A=="],
"@vueuse/shared": ["@vueuse/shared@12.8.2", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w=="],
"algoliasearch": ["algoliasearch@5.35.0", "", { "dependencies": { "@algolia/abtesting": "1.1.0", "@algolia/client-abtesting": "5.35.0", "@algolia/client-analytics": "5.35.0", "@algolia/client-common": "5.35.0", "@algolia/client-insights": "5.35.0", "@algolia/client-personalization": "5.35.0", "@algolia/client-query-suggestions": "5.35.0", "@algolia/client-search": "5.35.0", "@algolia/ingestion": "1.35.0", "@algolia/monitoring": "1.35.0", "@algolia/recommend": "5.35.0", "@algolia/requester-browser-xhr": "5.35.0", "@algolia/requester-fetch": "5.35.0", "@algolia/requester-node-http": "5.35.0" } }, "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg=="],
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
"autoprefixer": ["autoprefixer@10.4.20", "", { "dependencies": { "browserslist": "^4.23.3", "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": "bin/autoprefixer" }, "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g=="],
"axios": ["axios@1.7.9", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw=="],
"birpc": ["birpc@2.5.0", "", {}, "sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ=="],
"browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": "cli.js" }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001700", "", {}, "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="],
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
"concurrently": ["concurrently@9.1.2", "", { "dependencies": { "chalk": "^4.1.2", "lodash": "^4.17.21", "rxjs": "^7.8.1", "shell-quote": "^1.8.1", "supports-color": "^8.1.1", "tree-kill": "^1.2.2", "yargs": "^17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ=="],
"copy-anything": ["copy-anything@3.0.5", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
"detect-libc": ["detect-libc@1.0.3", "", { "bin": "bin/detect-libc.js" }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"electron-to-chromium": ["electron-to-chromium@1.5.103", "", {}, "sha512-P6+XzIkfndgsrjROJWfSvVEgNHtPgbhVyTkwLjUM2HU/h7pZRORgaTlHqfAikqxKmdJMLW8fftrdGWbd/Ds0FA=="],
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="],
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
"esbuild": ["esbuild@0.25.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.0", "@esbuild/android-arm": "0.25.0", "@esbuild/android-arm64": "0.25.0", "@esbuild/android-x64": "0.25.0", "@esbuild/darwin-arm64": "0.25.0", "@esbuild/darwin-x64": "0.25.0", "@esbuild/freebsd-arm64": "0.25.0", "@esbuild/freebsd-x64": "0.25.0", "@esbuild/linux-arm": "0.25.0", "@esbuild/linux-arm64": "0.25.0", "@esbuild/linux-ia32": "0.25.0", "@esbuild/linux-loong64": "0.25.0", "@esbuild/linux-mips64el": "0.25.0", "@esbuild/linux-ppc64": "0.25.0", "@esbuild/linux-riscv64": "0.25.0", "@esbuild/linux-s390x": "0.25.0", "@esbuild/linux-x64": "0.25.0", "@esbuild/netbsd-arm64": "0.25.0", "@esbuild/netbsd-x64": "0.25.0", "@esbuild/openbsd-arm64": "0.25.0", "@esbuild/openbsd-x64": "0.25.0", "@esbuild/sunos-x64": "0.25.0", "@esbuild/win32-arm64": "0.25.0", "@esbuild/win32-ia32": "0.25.0", "@esbuild/win32-x64": "0.25.0" }, "bin": "bin/esbuild" }, "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"focus-trap": ["focus-trap@7.6.5", "", { "dependencies": { "tabbable": "^6.2.0" } }, "sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg=="],
"follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="],
"form-data": ["form-data@4.0.2", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" } }, "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w=="],
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="],
"hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="],
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="],
"jiti": ["jiti@2.4.2", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"laravel-vite-plugin": ["laravel-vite-plugin@1.2.0", "", { "dependencies": { "picocolors": "^1.0.0", "vite-plugin-full-reload": "^1.1.0" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0" }, "bin": { "clean-orphaned-assets": "bin/clean.js" } }, "sha512-R0pJ+IcTVeqEMoKz/B2Ij57QVq3sFTABiFmb06gAwFdivbOgsUtuhX6N2MGLEArajrS3U5JbberzwOe7uXHMHQ=="],
"lightningcss": ["lightningcss@1.29.1", "", { "dependencies": { "detect-libc": "^1.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.1", "lightningcss-darwin-x64": "1.29.1", "lightningcss-freebsd-x64": "1.29.1", "lightningcss-linux-arm-gnueabihf": "1.29.1", "lightningcss-linux-arm64-gnu": "1.29.1", "lightningcss-linux-arm64-musl": "1.29.1", "lightningcss-linux-x64-gnu": "1.29.1", "lightningcss-linux-x64-musl": "1.29.1", "lightningcss-win32-arm64-msvc": "1.29.1", "lightningcss-win32-x64-msvc": "1.29.1" } }, "sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.1", "", { "os": "linux", "cpu": "arm" }, "sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.1", "", { "os": "linux", "cpu": "x64" }, "sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.1", "", { "os": "win32", "cpu": "x64" }, "sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q=="],
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
"mark.js": ["mark.js@8.11.1", "", {}, "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"mdast-util-to-hast": ["mdast-util-to-hast@13.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA=="],
"micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="],
"micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="],
"micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="],
"micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="],
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"minisearch": ["minisearch@7.1.2", "", {}, "sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA=="],
"mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
"nanoid": ["nanoid@3.3.8", "", { "bin": "bin/nanoid.cjs" }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
"normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="],
"oniguruma-to-es": ["oniguruma-to-es@3.1.1", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ=="],
"perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
"preact": ["preact@10.27.0", "", {}, "sha512-/DTYoB6mwwgPytiqQTh/7SFRL98ZdiD8Sk8zIUVOxtwq4oWcwrcd1uno9fE/zZmUaUrFNYzbH14CPebOz9tZQw=="],
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
"regex": ["regex@6.0.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA=="],
"regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="],
"regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="],
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
"rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
"rollup": ["rollup@4.34.8", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.8", "@rollup/rollup-android-arm64": "4.34.8", "@rollup/rollup-darwin-arm64": "4.34.8", "@rollup/rollup-darwin-x64": "4.34.8", "@rollup/rollup-freebsd-arm64": "4.34.8", "@rollup/rollup-freebsd-x64": "4.34.8", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", "@rollup/rollup-linux-arm-musleabihf": "4.34.8", "@rollup/rollup-linux-arm64-gnu": "4.34.8", "@rollup/rollup-linux-arm64-musl": "4.34.8", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", "@rollup/rollup-linux-riscv64-gnu": "4.34.8", "@rollup/rollup-linux-s390x-gnu": "4.34.8", "@rollup/rollup-linux-x64-gnu": "4.34.8", "@rollup/rollup-linux-x64-musl": "4.34.8", "@rollup/rollup-win32-arm64-msvc": "4.34.8", "@rollup/rollup-win32-ia32-msvc": "4.34.8", "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ=="],
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
"search-insights": ["search-insights@2.17.3", "", {}, "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ=="],
"shell-quote": ["shell-quote@1.8.2", "", {}, "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA=="],
"shiki": ["shiki@2.5.0", "", { "dependencies": { "@shikijs/core": "2.5.0", "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/langs": "2.5.0", "@shikijs/themes": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
"speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="],
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"superjson": ["superjson@2.2.2", "", { "dependencies": { "copy-anything": "^3.0.2" } }, "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q=="],
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
"tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="],
"tailwindcss": ["tailwindcss@4.0.8", "", {}, "sha512-Me7N5CKR+D2A1xdWA5t5+kjjT7bwnxZOE6/yDI/ixJdJokszsn2n++mdU5yJwrsTpqFX2B9ZNMBJDwcqk9C9lw=="],
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
"tree-kill": ["tree-kill@1.2.2", "", { "bin": "cli.js" }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
"unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="],
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
"unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
"unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
"update-browserslist-db": ["update-browserslist-db@1.1.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg=="],
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
"vite": ["vite@6.2.0", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": "bin/vite.js" }, "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ=="],
"vite-plugin-full-reload": ["vite-plugin-full-reload@1.2.0", "", { "dependencies": { "picocolors": "^1.0.0", "picomatch": "^2.3.1" } }, "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA=="],
"vitepress": ["vitepress@1.6.3", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw=="],
"vue": ["vue@3.5.18", "", { "dependencies": { "@vue/compiler-dom": "3.5.18", "@vue/compiler-sfc": "3.5.18", "@vue/runtime-dom": "3.5.18", "@vue/server-renderer": "3.5.18", "@vue/shared": "3.5.18" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA=="],
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
"@vue/compiler-sfc/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"rollup/@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA=="],
"vitepress/vite": ["vite@5.4.19", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA=="],
"@vue/compiler-sfc/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"vitepress/vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
"vitepress/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
"vitepress/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
"vitepress/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="],
"vitepress/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="],
"vitepress/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="],
"vitepress/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="],
"vitepress/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="],
"vitepress/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="],
"vitepress/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="],
"vitepress/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="],
"vitepress/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="],
"vitepress/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="],
"vitepress/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="],
"vitepress/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="],
"vitepress/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="],
"vitepress/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="],
"vitepress/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="],
"vitepress/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="],
"vitepress/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="],
"vitepress/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="],
"vitepress/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="],
"vitepress/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="],
"vitepress/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
}
}

View File

@ -0,0 +1,89 @@
import { defineConfig } from 'vitepress'
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "AuthentiKate",
description: "A lightweight SSO/OIDC solution built for homelabbers",
head: [
['meta', { name: 'theme-color', content: '#3b82f6' }],
],
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: '/logo.svg',
nav: [
{ text: 'Home', link: '/' },
{ text: 'Guide', link: '/guide/installation' },
{ text: 'Configuration', link: '/config/environment' },
{ text: 'Integrations', link: '/integrations/overview' }
],
sidebar: {
'/guide/': [
{
text: 'Getting Started',
items: [
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Quick Start', link: '/guide/quick-start' },
{ text: 'First Setup', link: '/guide/first-setup' }
]
},
{
text: 'User Management',
items: [
{ text: 'Creating Users', link: '/guide/users' },
{ text: 'Invitations', link: '/guide/invitations' },
{ text: 'User Profiles', link: '/guide/profiles' }
]
},
{
text: 'Applications',
items: [
{ text: 'Managing Apps', link: '/guide/applications' },
{ text: 'OAuth Configuration', link: '/guide/oauth' }
]
}
],
'/config/': [
{
text: 'Configuration',
items: [
{ text: 'Environment Variables', link: '/config/environment' },
{ text: 'Database Setup', link: '/config/database' },
{ text: 'Security Settings', link: '/config/security' },
{ text: 'Email Configuration', link: '/config/email' }
]
}
],
'/integrations/': [
{
text: 'Integrations',
items: [
{ text: 'Overview', link: '/integrations/overview' },
{ text: 'Grafana', link: '/integrations/grafana' },
{ text: 'Nextcloud', link: '/integrations/nextcloud' },
{ text: 'Traefik', link: '/integrations/traefik' },
{ text: 'Other Applications', link: '/integrations/generic' }
]
}
]
},
socialLinks: [
{ icon: 'github', link: 'https://github.com/jdubpark/authentikate' }
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2024-present AuthentiKate'
},
editLink: {
pattern: 'https://github.com/jdubpark/authentikate/edit/main/docs/:path'
},
search: {
provider: 'local'
}
}
})

View File

@ -1,171 +0,0 @@
# Testing RSA Keys Management
This document explains how RSA keys are managed during testing to ensure that running tests doesn't interfere with production keys.
## Overview
The application uses RSA keys for OIDC (OpenID Connect) JWT token signing. To prevent tests from deleting or overwriting production keys, we've implemented a separate key management system for testing environments.
## Key Features
### 1. Environment-Aware Key Paths
- **Production**: `storage/oauth/`
- **Testing**: `storage/testing/oauth/`
### 2. Enhanced Generate Keys Command
The `app:generate-keys` command now supports:
```bash
# Generate keys in default location (environment-dependent)
php artisan app:generate-keys
# Generate keys in custom location
php artisan app:generate-keys --path=/custom/path
```
**Environment Behavior:**
- Production: Uses `storage/oauth/`
- Testing: Uses `storage/testing/oauth/`
### 3. Test Key Management Trait
The `ManagesTestKeys` trait provides methods for managing test keys:
```php
// Set up test keys before test suite
ManagesTestKeys::setUpTestKeys()
// Clean up test keys after test suite
ManagesTestKeys::tearDownTestKeys()
// Ensure test keys exist for current test
$this->ensureTestKeysExist()
```
### 4. CI/CD Script
The `scripts/setup-test-keys.sh` script provides commands for CI/CD environments:
```bash
# Set up test keys
./scripts/setup-test-keys.sh setup
# Clean up test keys
./scripts/setup-test-keys.sh cleanup
# Reset (cleanup and regenerate) test keys
./scripts/setup-test-keys.sh reset
```
## Implementation Details
### Files Modified
1. **`app/Console/Commands/GenerateKeys.php`**
- Added `--path` option
- Environment-aware default paths
- Uses `storage/testing/oauth/` in testing environment
2. **`app/Http/Controllers/OIDCController.php`**
- Added helper methods `getPrivateKeyPath()` and `getPublicKeyPath()`
- Uses test keys in testing environment
3. **`tests/Feature/GenerateKeysCommandTest.php`**
- Updated to use test directory
- Added test for custom path option
4. **`tests/Feature/OIDCControllerTest.php`**
- Uses `ManagesTestKeys` trait
- Automatically generates test keys before tests
5. **`.gitignore`**
- Added `/storage/testing/*` to ignore test files
### Test Key Management
#### Automatic Generation
Test keys are automatically generated when needed:
1. When running `OIDCControllerTest`, keys are generated in `beforeEach`
2. Keys are only generated if they don't already exist
3. Uses the same RSA 2048-bit specification as production
#### Cleanup
Test keys are cleaned up:
1. After each test in `GenerateKeysCommandTest`
2. Can be manually cleaned using the script
3. Not committed to version control (ignored in `.gitignore`)
## GitHub Actions Integration
Example workflow configuration:
```yaml
- name: Set up test RSA keys
run: ./scripts/setup-test-keys.sh setup
- name: Run tests
run: php artisan test --coverage
- name: Clean up test RSA keys
run: ./scripts/setup-test-keys.sh cleanup
if: always()
```
## Benefits
1. **Safety**: Production keys are never affected by tests
2. **Isolation**: Each test environment has its own keys
3. **Consistency**: Same key generation process for all environments
4. **CI/CD Ready**: Works seamlessly in automated environments
5. **Flexibility**: Custom paths supported for advanced use cases
## Usage Examples
### Local Development
```bash
# Run tests (keys automatically managed)
php artisan test
# Manually generate test keys
php artisan app:generate-keys --path=storage/testing/oauth
```
### CI/CD Environment
```bash
# Set up environment
./scripts/setup-test-keys.sh setup
# Run tests
php artisan test
# Clean up
./scripts/setup-test-keys.sh cleanup
```
### Custom Testing Setup
```php
// In a test file
use Tests\Support\ManagesTestKeys;
uses(ManagesTestKeys::class);
beforeEach(function () {
$this->ensureTestKeysExist();
});
```
## Security Considerations
1. Test keys are generated with the same security parameters as production
2. Test keys are temporary and not persisted
3. Test directories are excluded from version control
4. No hardcoded keys in test files

360
docs/config/email.md Normal file
View File

@ -0,0 +1,360 @@
# Email Configuration
Email is essential for user invitations, password resets, and account verification. This guide covers how to configure email in AuthentiKate.
## Why Email Matters
Email is used for:
- **User Invitations**: Send registration links to new users
- **Password Resets**: Allow users to reset forgotten passwords
- **Email Verification**: Verify user email addresses
- **Account Notifications**: Security alerts and updates
## Basic SMTP Configuration
Set these environment variables for SMTP email:
```bash
MAIL_MAILER=smtp
MAIL_HOST=your-smtp-server.com
MAIL_PORT=587
MAIL_USERNAME=your-email@domain.com
MAIL_PASSWORD=your-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
```
## Provider-Specific Configurations
### Gmail
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password # Not your regular Gmail password!
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=your-email@gmail.com
MAIL_FROM_NAME="Your Name"
```
**Important**: Use an [App Password](https://support.google.com/accounts/answer/185833), not your regular Gmail password.
#### Creating Gmail App Password
1. Enable 2-Factor Authentication on your Google account
2. Go to **Google Account****Security** → **App passwords**
3. Generate a new app password for "Mail"
4. Use this 16-character password in `MAIL_PASSWORD`
### Outlook/Hotmail
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp-mail.outlook.com
MAIL_PORT=587
MAIL_USERNAME=your-email@outlook.com
MAIL_PASSWORD=your-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=your-email@outlook.com
MAIL_FROM_NAME="Your Name"
```
### Custom Domain Email
If you have your own domain with email hosting:
```bash
MAIL_MAILER=smtp
MAIL_HOST=mail.yourdomain.com
MAIL_PORT=587
MAIL_USERNAME=auth@yourdomain.com
MAIL_PASSWORD=your-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
```
## Email Service Providers
### SendGrid
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=your-sendgrid-api-key
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
```
### Mailgun
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=your-mailgun-username
MAIL_PASSWORD=your-mailgun-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
```
### Amazon SES
```bash
MAIL_MAILER=smtp
MAIL_HOST=email-smtp.us-east-1.amazonaws.com # Change region as needed
MAIL_PORT=587
MAIL_USERNAME=your-ses-smtp-username
MAIL_PASSWORD=your-ses-smtp-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
```
### Postmark
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.postmarkapp.com
MAIL_PORT=587
MAIL_USERNAME=your-postmark-token
MAIL_PASSWORD=your-postmark-token
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
```
## Docker Compose Configuration
### Environment Variables
```yaml
services:
authentikate:
image: authentikate/authentikate:latest
environment:
# Gmail example
MAIL_MAILER: smtp
MAIL_HOST: smtp.gmail.com
MAIL_PORT: 587
MAIL_USERNAME: your-email@gmail.com
MAIL_PASSWORD: your-app-password
MAIL_ENCRYPTION: tls
MAIL_FROM_ADDRESS: your-email@gmail.com
MAIL_FROM_NAME: "AuthentiKate"
```
### Environment File
Create a `.env` file:
```bash
# Email configuration
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=your-email@gmail.com
MAIL_FROM_NAME="AuthentiKate"
```
Reference it in docker-compose.yml:
```yaml
services:
authentikate:
image: authentikate/authentikate:latest
env_file: .env
```
## Testing Email Configuration
### Send Test Email
AuthentiKate includes a command to test email sending:
```bash
# Test email configuration
docker exec -it authentikate php artisan tinker
# In the tinker console:
Mail::raw('Test email from AuthentiKate', function($message) {
$message->to('test@example.com')->subject('Test Email');
});
```
### Check Logs
If emails aren't sending, check the logs:
```bash
# View container logs
docker logs authentikate
# Look for email-related errors
docker logs authentikate 2>&1 | grep -i mail
```
## Advanced Configuration
### Custom SMTP Port
Some providers use different ports:
```bash
# Standard ports
MAIL_PORT=25 # Unencrypted (not recommended)
MAIL_PORT=587 # STARTTLS (recommended)
MAIL_PORT=465 # SSL/TLS
# Custom port
MAIL_PORT=2525 # Some providers use alternate ports
```
### SSL/TLS Configuration
```bash
# Use TLS (recommended)
MAIL_ENCRYPTION=tls
# Use SSL (older, but still secure)
MAIL_ENCRYPTION=ssl
# No encryption (not recommended)
MAIL_ENCRYPTION=null
```
### Multiple From Addresses
Configure different senders for different email types:
```bash
# Default sender
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
# Admin notifications (configure in application)
ADMIN_EMAIL_FROM=admin@yourdomain.com
ADMIN_EMAIL_NAME="AuthentiKate Admin"
```
## Email Templates
AuthentiKate uses customizable email templates for different purposes:
### Invitation Email
- **Subject**: "You're invited to join AuthentiKate"
- **Content**: Welcome message with registration link
- **Action**: "Complete Registration" button
### Password Reset
- **Subject**: "Reset your AuthentiKate password"
- **Content**: Instructions for password reset
- **Action**: "Reset Password" button
### Email Verification
- **Subject**: "Verify your email address"
- **Content**: Verification instructions
- **Action**: "Verify Email" button
## Troubleshooting
### Common Issues
#### "Connection could not be established"
```
Swift_TransportException: Connection could not be established
```
**Solutions**:
- Check SMTP server address and port
- Verify firewall isn't blocking SMTP ports
- Try different encryption settings (TLS vs SSL)
#### "Authentication failed"
```
Swift_TransportException: Expected response code 235 but got code "535"
```
**Solutions**:
- Verify username and password
- Use App Password for Gmail
- Check if 2FA is enabled and requires app password
#### "From address not allowed"
```
Message: From address not allowed
```
**Solutions**:
- Ensure `MAIL_FROM_ADDRESS` matches authenticated user
- Configure your email provider to allow sending from this address
- Use provider's verified domain
### Debug Mode
Enable email debugging:
```bash
# Add to environment
LOG_LEVEL=debug
MAIL_LOG_CHANNEL=single
# Check detailed logs
docker logs authentikate | grep -i mail
```
### Test with Different Providers
If one provider doesn't work, try another:
```bash
# Try Gmail first (easiest to set up)
MAIL_HOST=smtp.gmail.com
# Then try SendGrid (good for production)
MAIL_HOST=smtp.sendgrid.net
# Or use a transactional service
MAIL_HOST=smtp.mailgun.org
```
## Production Recommendations
### Dedicated Email Service
For production, use a dedicated email service:
- **SendGrid**: Easy setup, good deliverability
- **Mailgun**: Reliable, detailed analytics
- **Amazon SES**: Cost-effective, AWS integration
- **Postmark**: Fast delivery, great for transactional emails
### Domain Authentication
Set up SPF, DKIM, and DMARC records:
```dns
# SPF record
yourdomain.com. TXT "v=spf1 include:_spf.google.com ~all"
# DKIM (provided by email service)
default._domainkey.yourdomain.com. TXT "v=DKIM1; k=rsa; p=..."
# DMARC
_dmarc.yourdomain.com. TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com"
```
### Monitoring
Monitor email delivery:
- Track bounce rates
- Monitor spam complaints
- Watch delivery statistics
- Set up alerts for failures
Your email configuration is now ready! Users will receive professional-looking emails for invitations, password resets, and other notifications.

402
docs/config/environment.md Normal file
View File

@ -0,0 +1,402 @@
# Environment Variables
AuthentiKate is configured through environment variables. This page covers all available configuration options.
## Core Application Settings
### APP_URL
**Required** - The URL where AuthentiKate is accessible.
```bash
APP_URL=https://auth.yourdomain.com
```
::: warning
This URL must match exactly how users access AuthentiKate. OAuth redirects and JWT tokens depend on this value.
:::
### APP_ENV
**Default**: `production`
```bash
APP_ENV=production # or 'local' for development
```
### APP_DEBUG
**Default**: `false`
```bash
APP_DEBUG=false # Set to 'true' only for debugging
```
::: danger
Never set `APP_DEBUG=true` in production as it exposes sensitive information.
:::
### APP_KEY
**Auto-generated** - Laravel application key for encryption.
```bash
APP_KEY=base64:generated-key-here
```
The key is automatically generated on first run. Do not change this after deployment as it will invalidate existing sessions and tokens.
## Database Configuration
### SQLite (Default)
```bash
DB_CONNECTION=sqlite
DB_DATABASE=/var/www/html/storage/database/database.sqlite
```
### PostgreSQL
```bash
DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=authentikate
DB_USERNAME=authentikate
DB_PASSWORD=secure_password
```
### MySQL/MariaDB
```bash
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=authentikate
DB_USERNAME=authentikate
DB_PASSWORD=secure_password
```
## Email Configuration
Email is used for user invitations, password resets, and verification.
### SMTP
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="AuthentiKate"
```
### Common SMTP Providers
#### Gmail
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password # Use App Password, not regular password
MAIL_ENCRYPTION=tls
```
#### Outlook/Hotmail
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp-mail.outlook.com
MAIL_PORT=587
MAIL_USERNAME=your-email@outlook.com
MAIL_PASSWORD=your-password
MAIL_ENCRYPTION=tls
```
#### SendGrid
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=your-sendgrid-api-key
MAIL_ENCRYPTION=tls
```
#### Mailgun
```bash
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=your-mailgun-username
MAIL_PASSWORD=your-mailgun-password
MAIL_ENCRYPTION=tls
```
### Disable Email
```bash
MAIL_MAILER=log # Emails will be written to logs instead of sent
```
## Cache Configuration
### Redis (Recommended for Production)
```bash
CACHE_DRIVER=redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=your-redis-password
```
### File Cache (Default)
```bash
CACHE_DRIVER=file
```
### Database Cache
```bash
CACHE_DRIVER=database
```
## Session Configuration
### Redis Sessions (Recommended for Production)
```bash
SESSION_DRIVER=redis
SESSION_LIFETIME=120 # Minutes
```
### File Sessions (Default)
```bash
SESSION_DRIVER=file
SESSION_LIFETIME=120
```
### Database Sessions
```bash
SESSION_DRIVER=database
```
## Security Settings
### SSL/HTTPS
```bash
# Force HTTPS redirects
FORCE_HTTPS=true
# Set secure cookie settings
SESSION_SECURE_COOKIE=true
SANCTUM_STATEFUL_DOMAINS=auth.yourdomain.com
```
### CORS Configuration
```bash
# Allow CORS for your domains
CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
```
## Logging
### Log Level
```bash
LOG_LEVEL=info # debug, info, notice, warning, error, critical, alert, emergency
```
### Log Channel
```bash
LOG_CHANNEL=stack # single, daily, slack, syslog, errorlog
```
### Daily Log Rotation
```bash
LOG_CHANNEL=daily
LOG_DAILY_DAYS=14 # Keep logs for 14 days
```
## Queue Configuration
For background job processing:
### Redis Queue
```bash
QUEUE_CONNECTION=redis
```
### Database Queue
```bash
QUEUE_CONNECTION=database
```
### Sync Queue (Default)
```bash
QUEUE_CONNECTION=sync # Process jobs immediately
```
## OAuth/OIDC Settings
### Token Lifetimes
```bash
# Access token lifetime (in minutes)
OAUTH_ACCESS_TOKEN_LIFETIME=60
# Refresh token lifetime (in days)
OAUTH_REFRESH_TOKEN_LIFETIME=30
# Authorization code lifetime (in minutes)
OAUTH_AUTHORIZATION_CODE_LIFETIME=10
```
### JWT Configuration
```bash
# JWT algorithm (default: RS256)
JWT_ALGORITHM=RS256
# Key paths (automatically set)
OAUTH_PRIVATE_KEY_PATH=storage/oauth/private.pem
OAUTH_PUBLIC_KEY_PATH=storage/oauth/public.pem
```
## Performance Settings
### PHP Configuration
```bash
# Memory limit
PHP_MEMORY_LIMIT=256M
# Upload limits
PHP_UPLOAD_MAX_FILESIZE=10M
PHP_POST_MAX_SIZE=10M
# Execution time
PHP_MAX_EXECUTION_TIME=300
```
### Application Optimization
```bash
# Enable optimizations for production
APP_OPTIMIZE=true
# Cache configuration
CONFIG_CACHE=true
ROUTE_CACHE=true
VIEW_CACHE=true
```
## Development Settings
These should only be used in development environments:
```bash
APP_ENV=local
APP_DEBUG=true
LOG_LEVEL=debug
# Disable HTTPS for local development
FORCE_HTTPS=false
SESSION_SECURE_COOKIE=false
```
## Complete Production Example
Here's a complete environment configuration for production:
```bash
# Application
APP_ENV=production
APP_DEBUG=false
APP_URL=https://auth.yourdomain.com
FORCE_HTTPS=true
# Database
DB_CONNECTION=pgsql
DB_HOST=postgres
DB_DATABASE=authentikate
DB_USERNAME=authentikate
DB_PASSWORD=secure_database_password
# Email
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=auth@yourdomain.com
MAIL_PASSWORD=gmail_app_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=auth@yourdomain.com
MAIL_FROM_NAME="Your Company Auth"
# Cache & Sessions
CACHE_DRIVER=redis
SESSION_DRIVER=redis
REDIS_HOST=redis
REDIS_PASSWORD=secure_redis_password
# Security
SESSION_SECURE_COOKIE=true
SESSION_LIFETIME=120
SANCTUM_STATEFUL_DOMAINS=yourdomain.com
# Performance
LOG_LEVEL=warning
LOG_CHANNEL=daily
LOG_DAILY_DAYS=30
```
## Docker Compose Integration
Add environment variables to your `docker-compose.yml`:
```yaml
services:
authentikate:
image: authentikate/authentikate:latest
environment:
- APP_URL=https://auth.yourdomain.com
- APP_ENV=production
- DB_CONNECTION=pgsql
- DB_HOST=postgres
- MAIL_MAILER=smtp
- MAIL_HOST=smtp.gmail.com
# ... other variables
env_file:
- .env # Or load from file
```
## Environment File
Create a `.env` file for easier management:
```bash
# Create environment file
cat > .env << 'EOF'
APP_URL=https://auth.yourdomain.com
APP_ENV=production
DB_CONNECTION=pgsql
# ... other settings
EOF
# Reference in docker-compose.yml
services:
authentikate:
env_file: .env
```
::: tip
Keep your `.env` file secure and never commit it to version control.
:::

188
docs/guide/applications.md Normal file
View File

@ -0,0 +1,188 @@
# Managing Applications
Learn how to create and manage OAuth applications in AuthentiKate.
## Creating Applications
### Via Web Interface
1. **Navigate** to **Applications** in the admin panel
2. **Click** "Create Application"
3. **Fill in** the application details:
- **Name**: Display name for your application
- **Redirect URI**: OAuth callback URL
- **Icon**: Optional icon URL for the application
4. **Save** the application
### Application Details
Each application gets:
- **Unique Client ID**: Public identifier for your application
- **Client Secret**: Private key for token exchange
- **Redirect URI**: Where users return after authentication
::: warning
Keep your Client Secret secure! It should never be exposed in client-side code.
:::
## Application Templates
AuthentiKate includes templates for popular applications:
### Available Templates
- **Grafana**: Analytics and monitoring
- **Nextcloud**: File sharing and collaboration
- **Proxmox**: Virtualization management
- **Portainer**: Docker container management
- **GitLab**: Git repository hosting
Templates automatically configure:
- Correct redirect URI patterns
- Appropriate application icons
- Common configuration settings
## OAuth Configuration
### Client Credentials
```yaml
Client ID: f47ac10b-58cc-4372-a567-0e02b2c3d479
Client Secret: 40-character-random-string
```
### Endpoints
Your applications will use these endpoints:
- **Authorization**: `/oauth/authorize`
- **Token**: `/oauth/token`
- **User Info**: `/oauth/userinfo`
- **JWKS**: `/.well-known/jwks.json`
### Supported Features
- **Authorization Code Flow**: Standard OAuth2 flow
- **PKCE**: Enhanced security for public clients
- **JWT Tokens**: Signed with RSA256
- **Refresh Tokens**: Long-lived token renewal
## Security Best Practices
### Redirect URI Validation
- Use exact URI matching
- Always use HTTPS in production
- Avoid wildcard redirects
### Client Secret Management
- Store secrets securely
- Rotate secrets regularly
- Use different secrets per environment
### Token Handling
- Validate token signatures
- Respect token expiration
- Implement proper logout
## Common Integration Patterns
### Server-Side Applications
Best for applications that can securely store client secrets:
```javascript
// Example: Node.js application
const config = {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
authorizationURL: 'https://auth.yourdomain.com/oauth/authorize',
tokenURL: 'https://auth.yourdomain.com/oauth/token',
callbackURL: 'https://yourapp.com/auth/callback'
};
```
### Single Page Applications (SPA)
For client-side applications using PKCE:
```javascript
// Example: React application with PKCE
const config = {
clientId: 'your-client-id',
// No client secret for public clients
authorizationURL: 'https://auth.yourdomain.com/oauth/authorize',
tokenURL: 'https://auth.yourdomain.com/oauth/token',
redirectUri: 'https://yourapp.com/callback',
usePKCE: true
};
```
### Mobile Applications
Similar to SPAs, always use PKCE:
```swift
// Example: iOS Swift
let config = OIDServiceConfiguration(
authorizationEndpoint: URL(string: "https://auth.yourdomain.com/oauth/authorize")!,
tokenEndpoint: URL(string: "https://auth.yourdomain.com/oauth/token")!
)
```
## Testing Applications
### Manual Testing
1. **Start OAuth flow** from your application
2. **Verify redirect** to AuthentiKate
3. **Complete authentication**
4. **Confirm successful** return to your app
5. **Check user data** is populated correctly
### Automated Testing
```bash
# Test authorization endpoint
curl "https://auth.yourdomain.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=openid"
# Test token exchange (after getting auth code)
curl -X POST https://auth.yourdomain.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=AUTH_CODE&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=REDIRECT_URI"
```
## Troubleshooting
### Invalid Redirect URI
**Error**: `The redirect URI is invalid`
**Solutions**:
- Verify exact URL match in application settings
- Check for trailing slashes
- Ensure HTTPS is used
### Invalid Client
**Error**: `Client authentication failed`
**Solutions**:
- Verify Client ID and Secret
- Check that application exists and is active
- Ensure secrets haven't been regenerated
### Token Validation Issues
**Error**: `Invalid token signature`
**Solutions**:
- Use JWKS endpoint for signature validation
- Verify token hasn't expired
- Check token issuer matches AuthentiKate URL
## Application Management
### Updating Applications
- **Edit** application details anytime
- **Regenerate** client secrets if compromised
- **Update** redirect URIs for new environments
### Deactivating Applications
- **Disable** applications to prevent new logins
- Existing tokens remain valid until expiration
- **Re-enable** anytime to restore access
### Monitoring Usage
View application usage in the admin panel:
- **Active tokens** per application
- **Recent authentications**
- **User access patterns**
Your applications are now ready for OAuth integration with AuthentiKate!

202
docs/guide/first-setup.md Normal file
View File

@ -0,0 +1,202 @@
# First Setup
After installing AuthentiKate, you'll want to complete the initial configuration to make it ready for production use.
## Initial Login
When you first start AuthentiKate, it automatically creates an admin user. The credentials are shown in the container logs:
```bash
docker logs authentikate
```
Look for:
```
✅ Initial admin user created:
Email: admin@authentikate.local
Password: randomly-generated-password
```
::: tip
Save these credentials securely! You'll need them to access the admin interface.
:::
## Admin Dashboard
After logging in, you'll see the AuthentiKate dashboard with:
- **Applications**: Manage OAuth applications
- **Users**: User management and invitations
- **Tokens**: View active authentication tokens
- **Profile**: Your user profile settings
## Essential Configuration Steps
### 1. Update Your Profile
1. Click your avatar in the top right
2. Select **"Profile"**
3. Update your information:
- Change the email from `admin@authentikate.local` to your real email
- Set a preferred username
- Upload an avatar (optional)
- **Change your password** to something secure
### 2. Configure Email (Recommended)
Email is used for:
- User invitations
- Password resets
- Account verification
Set up email by updating your environment variables:
```yaml
environment:
MAIL_MAILER: smtp
MAIL_HOST: smtp.gmail.com
MAIL_PORT: 587
MAIL_USERNAME: your-email@gmail.com
MAIL_PASSWORD: your-app-password
MAIL_ENCRYPTION: tls
MAIL_FROM_ADDRESS: auth@yourdomain.com
MAIL_FROM_NAME: "AuthentiKate"
```
[→ See full email configuration guide](/config/email)
### 3. Set Your Domain
Update the `APP_URL` to match your actual domain:
```yaml
environment:
APP_URL: https://auth.yourdomain.com
```
This ensures:
- Correct OAuth redirect URLs
- Proper JWT issuer claims
- Working email links
### 4. Create Your First Application
1. Go to **Applications** → **Create Application**
2. Fill in the basic information:
- **Name**: Your application name (e.g., "Grafana")
- **Redirect URI**: Where users return after authentication
- **Icon**: Optional app icon URL
3. Note the generated **Client ID** and **Client Secret**
4. Use these in your application's OAuth configuration
## Security Checklist
Before going to production, verify these security settings:
### ✅ Admin Account
- [ ] Changed default admin email
- [ ] Set a strong, unique password
- [ ] Enabled email verification (if email is configured)
### ✅ Environment
- [ ] Set `APP_ENV=production`
- [ ] Set `APP_DEBUG=false`
- [ ] Using HTTPS with valid SSL certificate
- [ ] `APP_URL` matches your actual domain
### ✅ Database
- [ ] Using persistent volume for data
- [ ] Consider using PostgreSQL/MySQL for production
- [ ] Regular backups configured
### ✅ Reverse Proxy
- [ ] Proper SSL termination
- [ ] Security headers configured
- [ ] Rate limiting in place
## Application Integration
### OIDC Endpoints
Your applications will need these endpoints:
| Endpoint | URL |
|----------|-----|
| Authorization | `https://auth.yourdomain.com/oauth/authorize` |
| Token | `https://auth.yourdomain.com/oauth/token` |
| User Info | `https://auth.yourdomain.com/oauth/userinfo` |
| JWKS | `https://auth.yourdomain.com/.well-known/jwks.json` |
| Discovery | `https://auth.yourdomain.com/.well-known/openid_configuration` |
### OAuth Flow
1. **User clicks login** in your application
2. **Redirect to AuthentiKate** with authorization request
3. **User authenticates** (if not already logged in)
4. **User consents** to application access (if required)
5. **Redirect back** to your application with authorization code
6. **Exchange code** for access token and ID token
7. **Access user info** using the access token
## User Management
### Invitation System
AuthentiKate uses an invitation-based registration system:
1. **Admin creates invitation** with user's email
2. **Invitation email sent** with registration link
3. **User completes registration** using the invitation
4. **User can access applications** they're authorized for
### User Permissions
- **Admin users**: Full access to manage applications and users
- **Regular users**: Can only access authorized applications and manage their own profile
## Backup Strategy
Set up regular backups of your AuthentiKate data:
### SQLite (Default)
```bash
# Daily backup script
#!/bin/bash
docker exec authentikate cp /var/www/html/storage/database/database.sqlite /tmp/backup.sqlite
docker cp authentikate:/tmp/backup.sqlite ./backups/authentikate-$(date +%Y%m%d).sqlite
```
### Full Volume Backup
```bash
# Backup all persistent data
docker run --rm -v authentikate_data:/data -v $(pwd)/backups:/backup alpine tar czf /backup/authentikate-full-$(date +%Y%m%d).tar.gz -C /data .
```
## Common Next Steps
### Popular Integrations
- [Set up Grafana SSO](/integrations/grafana)
- [Configure Nextcloud authentication](/integrations/nextcloud)
- [Integrate with Traefik forward auth](/integrations/traefik)
### Advanced Configuration
- [Environment variables reference](/config/environment)
- [Database configuration](/config/database)
- [Security settings](/config/security)
### User Management
- [Create user invitations](/guide/invitations)
- [Manage user profiles](/guide/profiles)
- [Handle user permissions](/guide/users)
## Getting Help
If you run into issues:
1. **Check the logs**: `docker logs authentikate`
2. **Verify configuration**: Compare with working examples
3. **Test endpoints**: Use curl or Postman to test OIDC endpoints
4. **Community support**: Check GitHub issues and discussions
Your AuthentiKate instance is now ready for production use! 🎉

259
docs/guide/installation.md Normal file
View File

@ -0,0 +1,259 @@
# Installation
AuthentiKate is designed to be deployed easily with Docker, making it perfect for homelab environments. This guide will walk you through different installation methods.
## Quick Start with Docker
The fastest way to get AuthentiKate running is with Docker:
```bash
docker run -d \
--name authentikate \
-p 8080:8080 \
-e APP_URL=http://localhost:8080 \
-v authentikate_data:/var/www/html/storage \
authentikate/authentikate:latest
```
AuthentiKate will be available at `http://localhost:8080` with automatic setup completing in the background.
## Docker Compose (Recommended)
For production use, we recommend using Docker Compose for better configuration management:
```yaml
version: '3.8'
services:
authentikate:
image: authentikate/authentikate:latest
container_name: authentikate
restart: unless-stopped
ports:
- "8080:8080"
environment:
# Required
APP_URL: https://auth.yourdomain.com
APP_ENV: production
# Database (SQLite by default)
DB_CONNECTION: sqlite
# Email (optional but recommended)
MAIL_MAILER: smtp
MAIL_HOST: your-smtp-server.com
MAIL_PORT: 587
MAIL_USERNAME: your-email@domain.com
MAIL_PASSWORD: your-password
MAIL_ENCRYPTION: tls
MAIL_FROM_ADDRESS: auth@yourdomain.com
MAIL_FROM_NAME: "AuthentiKate"
volumes:
- authentikate_data:/var/www/html/storage
- authentikate_logs:/var/www/html/storage/logs
# Optional: Use external database
# depends_on:
# - postgres
labels:
# Traefik labels (if using Traefik)
- "traefik.enable=true"
- "traefik.http.routers.authentikate.rule=Host(`auth.yourdomain.com`)"
- "traefik.http.routers.authentikate.entrypoints=websecure"
- "traefik.http.routers.authentikate.tls.certresolver=letsencrypt"
- "traefik.http.services.authentikate.loadbalancer.server.port=8080"
volumes:
authentikate_data:
authentikate_logs:
```
## Environment Variables
### Required Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `APP_URL` | The URL where AuthentiKate will be accessible | `https://auth.yourdomain.com` |
### Optional Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `APP_ENV` | `production` | Application environment |
| `APP_DEBUG` | `false` | Enable debug mode |
| `DB_CONNECTION` | `sqlite` | Database type (`sqlite`, `mysql`, `postgres`) |
| `DB_DATABASE` | `/var/www/html/storage/database/database.sqlite` | Database path/name |
## Database Options
### SQLite (Default)
Perfect for most homelab setups. No additional configuration required.
### PostgreSQL
For larger installations:
```yaml
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: authentikate
POSTGRES_USER: authentikate
POSTGRES_PASSWORD: secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
authentikate:
# ... other config
environment:
DB_CONNECTION: pgsql
DB_HOST: postgres
DB_DATABASE: authentikate
DB_USERNAME: authentikate
DB_PASSWORD: secure_password
depends_on:
- postgres
volumes:
postgres_data:
```
### MySQL/MariaDB
```yaml
services:
mysql:
image: mariadb:10
environment:
MYSQL_DATABASE: authentikate
MYSQL_USER: authentikate
MYSQL_PASSWORD: secure_password
MYSQL_ROOT_PASSWORD: root_password
volumes:
- mysql_data:/var/lib/mysql
authentikate:
# ... other config
environment:
DB_CONNECTION: mysql
DB_HOST: mysql
DB_DATABASE: authentikate
DB_USERNAME: authentikate
DB_PASSWORD: secure_password
depends_on:
- mysql
volumes:
mysql_data:
```
## Reverse Proxy Setup
### Traefik
AuthentiKate works perfectly with Traefik. Add these labels to your Docker Compose:
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.authentikate.rule=Host(`auth.yourdomain.com`)"
- "traefik.http.routers.authentikate.entrypoints=websecure"
- "traefik.http.routers.authentikate.tls.certresolver=letsencrypt"
- "traefik.http.services.authentikate.loadbalancer.server.port=8080"
```
### Nginx
```nginx
server {
listen 443 ssl http2;
server_name auth.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
### Caddy
```caddyfile
auth.yourdomain.com {
reverse_proxy localhost:8080
}
```
## First Run
When you first start AuthentiKate, it will automatically:
1. **Generate RSA Keys**: Creates public/private key pair for JWT signing
2. **Run Database Migrations**: Sets up all necessary database tables
3. **Create Admin User**: Generates an initial admin account
The initial admin credentials will be displayed in the container logs:
```bash
docker logs authentikate
```
Look for output like:
```
✅ Initial admin user created:
Email: admin@authentikate.local
Password: randomly-generated-password
```
## Updating
To update AuthentiKate:
```bash
# Pull the latest image
docker pull authentikate/authentikate:latest
# Stop and remove the old container
docker stop authentikate
docker rm authentikate
# Start with the new image
docker-compose up -d
```
Your data will be preserved in the Docker volumes.
## Backup
### Database Backup (SQLite)
```bash
# Create backup
docker exec authentikate cp /var/www/html/storage/database/database.sqlite /tmp/backup.sqlite
docker cp authentikate:/tmp/backup.sqlite ./authentikate-backup-$(date +%Y%m%d).sqlite
# Restore backup
docker cp ./authentikate-backup-20240101.sqlite authentikate:/tmp/restore.sqlite
docker exec authentikate cp /tmp/restore.sqlite /var/www/html/storage/database/database.sqlite
```
### Full Data Backup
```bash
# Backup all data
docker run --rm -v authentikate_data:/data -v $(pwd):/backup alpine tar czf /backup/authentikate-data-$(date +%Y%m%d).tar.gz -C /data .
# Restore data
docker run --rm -v authentikate_data:/data -v $(pwd):/backup alpine tar xzf /backup/authentikate-data-20240101.tar.gz -C /data
```
## Next Steps
Once AuthentiKate is running:
1. [Complete the first setup →](/guide/first-setup)
2. [Configure your first application →](/guide/applications)
3. [Set up email notifications →](/config/email)

159
docs/guide/quick-start.md Normal file
View File

@ -0,0 +1,159 @@
# Quick Start
This guide will get you up and running with AuthentiKate in under 5 minutes.
## Prerequisites
- Docker installed on your system
- A domain name (optional, can use localhost for testing)
## Step 1: Deploy AuthentiKate
Run the following command to start AuthentiKate:
```bash
docker run -d \
--name authentikate \
-p 8080:8080 \
-e APP_URL=http://localhost:8080 \
-v authentikate_data:/var/www/html/storage \
authentikate/authentikate:latest
```
## Step 2: Get Your Admin Credentials
AuthentiKate automatically creates an admin user on first run. Get the credentials from the logs:
```bash
docker logs authentikate
```
Look for output like:
```
✅ Initial admin user created:
Email: admin@authentikate.local
Password: Xy9#mK2$vB8nQ4!p
```
## Step 3: Access the Interface
1. Open your browser and go to `http://localhost:8080`
2. Log in with the admin credentials from Step 2
3. You'll be taken to the AuthentiKate dashboard
## Step 4: Create Your First Application
1. Click **"Applications"** in the navigation
2. Click **"Create Application"**
3. Fill in the details:
- **Name**: `Test App`
- **Redirect URI**: `http://localhost:3000/auth/callback`
- **Client ID**: (auto-generated)
- **Client Secret**: (auto-generated)
4. Click **"Save"**
## Step 5: Test the Integration
Your application is now configured! Here are the OIDC endpoints you'll need:
- **Authorization**: `http://localhost:8080/oauth/authorize`
- **Token**: `http://localhost:8080/oauth/token`
- **User Info**: `http://localhost:8080/oauth/userinfo`
- **JWKS**: `http://localhost:8080/.well-known/jwks.json`
- **Discovery**: `http://localhost:8080/.well-known/openid_configuration`
## Common Integration Examples
### Test with curl
```bash
# Get authorization URL (replace CLIENT_ID with your actual client ID)
CLIENT_ID="your-client-id"
REDIRECT_URI="http://localhost:3000/auth/callback"
echo "Visit this URL to authorize:"
echo "http://localhost:8080/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid profile email"
```
### Simple HTML Test Page
Create a simple test page to try the OAuth flow:
```html
<!DOCTYPE html>
<html>
<head>
<title>AuthentiKate Test</title>
</head>
<body>
<h1>AuthentiKate OAuth Test</h1>
<button onclick="authenticate()">Login with AuthentiKate</button>
<script>
function authenticate() {
const clientId = 'your-client-id'; // Replace with your actual client ID
const redirectUri = 'http://localhost:3000/auth/callback';
const authUrl = `http://localhost:8080/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=openid profile email`;
window.location.href = authUrl;
}
</script>
</body>
</html>
```
## What's Next?
Now that you have AuthentiKate running:
### Configure Your Environment
- [Set up email notifications](/config/email)
- [Configure a custom domain](/config/environment)
- [Set up reverse proxy](/guide/installation#reverse-proxy-setup)
### Add Real Applications
- [Integrate with Grafana](/integrations/grafana)
- [Set up Nextcloud SSO](/integrations/nextcloud)
- [Configure other applications](/integrations/generic)
### Manage Users
- [Create user invitations](/guide/invitations)
- [Set up user profiles](/guide/profiles)
- [Configure user permissions](/guide/users)
### Production Setup
- [Use PostgreSQL/MySQL](/guide/installation#database-options)
- [Set up proper email](/config/email)
- [Configure security settings](/config/security)
## Troubleshooting
### Can't access AuthentiKate?
- Make sure the container is running: `docker ps`
- Check the logs: `docker logs authentikate`
- Verify the port is accessible: `curl http://localhost:8080`
### Forgot admin password?
Reset it by running:
```bash
docker exec -it authentikate php artisan app:create-initial-admin --force
```
### Need to change the URL?
Update the `APP_URL` environment variable and restart:
```bash
docker stop authentikate
docker rm authentikate
# Run again with new APP_URL
```
### Container won't start?
Check for port conflicts:
```bash
# See what's using port 8080
sudo netstat -tulpn | grep 8080
# Use a different port
docker run -d --name authentikate -p 8081:8080 ...
```

75
docs/index.md Normal file
View File

@ -0,0 +1,75 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "AuthentiKate"
text: "SSO/OIDC for Homelabbers"
tagline: A lightweight, self-hosted authentication solution that just works
image:
src: /logo.svg
alt: AuthentiKate
actions:
- theme: brand
text: Get Started
link: /guide/installation
- theme: alt
text: View on GitHub
link: https://github.com/jdubpark/authentikate
features:
- icon: 🔐
title: OpenID Connect Ready
details: Full OIDC compliance with JWT tokens, PKCE support, and industry-standard security practices. Integrate with any OAuth2/OIDC compatible application.
- icon: 🐳
title: Docker First
details: Single container deployment with automatic setup. No complex configuration files or multi-service orchestration required.
- icon: ⚡
title: Built for Speed
details: Powered by Laravel and optimized for homelab environments. Fast authentication flows and minimal resource usage.
- icon: 🎨
title: Beautiful Interface
details: Clean, modern UI built with Livewire and Tailwind CSS. Intuitive user management and application configuration.
- icon: 🔄
title: Auto-Configuration
details: Automatic RSA key generation, database setup, and admin user creation. Zero manual configuration needed.
- icon: 🏠
title: Homelab Optimized
details: Perfect for self-hosters. Integrates seamlessly with Traefik, includes popular app presets, and supports local networks.
- icon: 👥
title: User Management
details: Invitation-based registration, user profiles with avatars, and granular permission controls. Keep your homelab secure.
- icon: 📱
title: Modern Features
details: JWT tokens with UUID-based user identification, token management, and comprehensive audit logging.
---
## Why AuthentiKate?
AuthentiKate is designed specifically for homelabbers who want enterprise-grade authentication without the enterprise complexity. Unlike heavyweight solutions that require extensive setup and maintenance, AuthentiKate gets you up and running in minutes.
### Perfect for Your Homelab
- **One Container**: Deploy with a single Docker command
- **Zero Config**: Automatic setup with sensible defaults
- **Popular Apps**: Pre-configured templates for Grafana, Nextcloud, and more
- **Reverse Proxy Ready**: Works seamlessly with Traefik and other proxies
### Enterprise Features, Homelab Simplicity
- Full OpenID Connect compliance
- JWT tokens with RSA256 signing
- PKCE support for mobile apps
- Invitation-based user registration
- Comprehensive token management
- Beautiful, responsive interface
Ready to secure your homelab? [Get started in minutes →](/guide/installation)

View File

@ -0,0 +1,322 @@
# Grafana Integration
This guide shows how to integrate Grafana with AuthentiKate for single sign-on authentication.
## Prerequisites
- AuthentiKate running and accessible
- Grafana instance (Docker or standalone)
- Admin access to both systems
## Step 1: Create Application in AuthentiKate
1. Log into your AuthentiKate admin panel
2. Navigate to **Applications** → **Create Application**
3. Fill in the application details:
```
Name: Grafana
Redirect URI: https://grafana.yourdomain.com/login/generic_oauth
Icon: https://cdn.jsdelivr.net/gh/selfhst/icons/webp/grafana.webp
```
4. Click **Save** and note the generated:
- **Client ID**
- **Client Secret**
## Step 2: Configure Grafana
### Environment Variables (Docker)
Add these environment variables to your Grafana container:
```yaml
services:
grafana:
image: grafana/grafana:latest
environment:
# OAuth Settings
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
GF_AUTH_GENERIC_OAUTH_NAME: "AuthentiKate"
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: "your-client-id"
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: "your-client-secret"
GF_AUTH_GENERIC_OAUTH_SCOPES: "openid profile email"
GF_AUTH_GENERIC_OAUTH_AUTH_URL: "https://auth.yourdomain.com/oauth/authorize"
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: "https://auth.yourdomain.com/oauth/token"
GF_AUTH_GENERIC_OAUTH_API_URL: "https://auth.yourdomain.com/oauth/userinfo"
# Auto-login (optional)
GF_AUTH_OAUTH_AUTO_LOGIN: "true"
GF_AUTH_DISABLE_LOGIN_FORM: "true"
# User mapping
GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH: "preferred_username"
GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH: "name"
GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH: "email"
# Role mapping (optional)
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: "contains(groups[*], 'admin') && 'Admin' || 'Viewer'"
```
### Configuration File
Alternatively, configure via `grafana.ini`:
```ini
[auth.generic_oauth]
enabled = true
name = AuthentiKate
client_id = your-client-id
client_secret = your-client-secret
scopes = openid profile email
auth_url = https://auth.yourdomain.com/oauth/authorize
token_url = https://auth.yourdomain.com/oauth/token
api_url = https://auth.yourdomain.com/oauth/userinfo
# Auto-login
auto_login = true
# User attribute mapping
login_attribute_path = preferred_username
name_attribute_path = name
email_attribute_path = email
# Role mapping (optional)
role_attribute_path = contains(groups[*], 'admin') && 'Admin' || 'Viewer'
[auth]
# Disable regular login form (optional)
disable_login_form = true
# Allow sign up
oauth_auto_login = true
```
## Step 3: Docker Compose Example
Complete Docker Compose configuration:
```yaml
version: '3.8'
services:
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
environment:
# Basic settings
GF_SECURITY_ADMIN_PASSWORD: admin
GF_INSTALL_PLUGINS: grafana-piechart-panel
# OAuth with AuthentiKate
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
GF_AUTH_GENERIC_OAUTH_NAME: "AuthentiKate"
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: "your-client-id-here"
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: "your-client-secret-here"
GF_AUTH_GENERIC_OAUTH_SCOPES: "openid profile email"
GF_AUTH_GENERIC_OAUTH_AUTH_URL: "https://auth.yourdomain.com/oauth/authorize"
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: "https://auth.yourdomain.com/oauth/token"
GF_AUTH_GENERIC_OAUTH_API_URL: "https://auth.yourdomain.com/oauth/userinfo"
# User mapping
GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH: "preferred_username"
GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH: "name"
GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH: "email"
# Auto-login
GF_AUTH_OAUTH_AUTO_LOGIN: "true"
GF_AUTH_DISABLE_LOGIN_FORM: "false" # Keep false for admin access
volumes:
- grafana_data:/var/lib/grafana
labels:
# Traefik labels (if using Traefik)
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.yourdomain.com`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
volumes:
grafana_data:
```
## Step 4: Advanced Configuration
### Role Mapping
Map AuthentiKate users to Grafana roles based on user attributes:
```ini
# Basic role mapping
role_attribute_path = preferred_username == 'admin' && 'Admin' || 'Viewer'
# Multiple admin users
role_attribute_path = contains(['admin', 'grafana-admin'], preferred_username) && 'Admin' || 'Editor'
# Default to Editor for all users
role_attribute_path = 'Editor'
```
### Team Mapping
Automatically assign users to Grafana teams:
```ini
# Team mapping (if you add groups to AuthentiKate in the future)
team_ids_attribute_path = groups
team_ids = 1,2,3
```
### Allow Sign-Up
Control whether new users can sign up automatically:
```ini
[users]
# Allow users to sign up
allow_sign_up = true
# Auto-assign organization
auto_assign_org = true
auto_assign_org_id = 1
# Default role for new users
auto_assign_org_role = Viewer
```
## Step 5: Testing
1. **Restart Grafana** after configuration changes
2. **Navigate to Grafana** in your browser
3. **Click "Sign in with AuthentiKate"** (or get redirected automatically)
4. **Authenticate with AuthentiKate** using your credentials
5. **Verify** you're logged into Grafana with the correct user info
## Troubleshooting
### Common Issues
#### "Invalid redirect URI" Error
Ensure the redirect URI in AuthentiKate exactly matches:
```
https://grafana.yourdomain.com/login/generic_oauth
```
#### Users Not Getting Correct Roles
Check the role mapping configuration:
```ini
# Debug role mapping
role_attribute_path = 'Admin' # Give everyone admin temporarily
```
#### OAuth Login Button Not Appearing
Verify these settings:
```ini
[auth.generic_oauth]
enabled = true
name = AuthentiKate # This shows as the button text
```
#### Auto-login Not Working
Check the auto-login settings:
```ini
[auth]
oauth_auto_login = true
disable_login_form = false # Keep false to allow admin login
```
### Debug Mode
Enable debug logging in Grafana:
```ini
[log]
level = debug
[log.console]
level = debug
```
Then check the Grafana logs:
```bash
docker logs grafana
```
### Testing OAuth Flow
Test the OAuth endpoints manually:
```bash
# Test AuthentiKate discovery
curl https://auth.yourdomain.com/.well-known/openid_configuration
# Test with specific parameters
curl "https://auth.yourdomain.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=https://grafana.yourdomain.com/login/generic_oauth&response_type=code&scope=openid+profile+email"
```
## Advanced Features
### Custom Login Page
Create a custom login experience:
```ini
[auth]
disable_login_form = true
oauth_auto_login = true
[server]
# Custom login logo
login_logo = https://yourdomain.com/logo.png
```
### Organization Management
Control organization assignment:
```ini
[users]
# Assign all OAuth users to specific org
auto_assign_org = true
auto_assign_org_id = 1
# Allow org admins to invite users
allow_org_create = false
```
### Session Management
Configure session settings:
```ini
[session]
# Session timeout
session_life_time = 86400 # 24 hours
# Cookie settings
cookie_secure = true
cookie_samesite = strict
```
## Production Considerations
### Security
- Use HTTPS for both AuthentiKate and Grafana
- Store client secrets securely
- Consider using environment files for secrets
- Set up proper SSL certificates
### Performance
- Enable caching in Grafana
- Use external databases for larger installations
- Monitor authentication latency
### Backup
- Backup Grafana configuration
- Include OAuth settings in your backup strategy
- Test authentication after restores
Your Grafana instance is now integrated with AuthentiKate! Users can sign in with their AuthentiKate credentials and access Grafana with appropriate roles and permissions.

View File

@ -0,0 +1,370 @@
# Nextcloud Integration
This guide shows how to integrate Nextcloud with AuthentiKate using the OpenID Connect app for seamless single sign-on.
## Prerequisites
- AuthentiKate running and accessible
- Nextcloud instance with admin access
- Nextcloud OpenID Connect app installed
## Step 1: Install OpenID Connect App
### Via Nextcloud App Store
1. Log into Nextcloud as an administrator
2. Go to **Apps** → **Authentication**
3. Find and install **"OpenID Connect user backend"**
4. Enable the app
### Via Command Line
```bash
# Install via occ command
sudo -u www-data php occ app:install user_oidc
sudo -u www-data php occ app:enable user_oidc
```
## Step 2: Create Application in AuthentiKate
1. Log into your AuthentiKate admin panel
2. Navigate to **Applications** → **Create Application**
3. Fill in the application details:
```
Name: Nextcloud
Redirect URI: https://cloud.yourdomain.com/apps/user_oidc/code
Icon: https://cdn.jsdelivr.net/gh/selfhst/icons/webp/nextcloud.webp
```
4. Click **Save** and note the generated:
- **Client ID**
- **Client Secret**
## Step 3: Configure Nextcloud OIDC
### Via Web Interface
1. Go to **Settings****Administration** → **OpenID Connect**
2. Configure the OIDC provider:
```
Provider Name: AuthentiKate
Identifier: authentikate
Client ID: your-client-id
Client Secret: your-client-secret
Discovery endpoint: https://auth.yourdomain.com/.well-known/openid_configuration
```
3. **Advanced Settings** (click to expand):
```
Scope: openid profile email
Unique user identifier: preferred_username
```
4. Click **Save**
### Via Command Line
```bash
# Set OIDC configuration
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-clientId --value="your-client-id"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-clientSecret --value="your-client-secret"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-discoveryUrl --value="https://auth.yourdomain.com/.well-known/openid_configuration"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-scope --value="openid profile email"
# Set unique identifier
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-uniqueUid --value="1"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-uniqueUidMapping --value="preferred_username"
```
## Step 4: User Attribute Mapping
Configure how AuthentiKate user attributes map to Nextcloud:
### Via Web Interface
In **Settings****Administration****OpenID Connect****Advanced**:
```
Display name mapping: name
Email mapping: email
Unique user identifier: preferred_username
```
### Via Command Line
```bash
# User attribute mapping
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-displayNameMapping --value="name"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-emailMapping --value="email"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-quotaMapping --value=""
```
## Step 5: Auto-Provisioning (Optional)
Enable automatic user creation on first login:
### Via Web Interface
In the OIDC settings, enable:
- **Auto provision users**
- **Respect email verified claim**
### Via Command Line
```bash
# Enable auto-provisioning
sudo -u www-data php occ config:app:set user_oidc auto-provision --value="1"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-provisioningEnabled --value="1"
# Respect email verification
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-checkEmailVerification --value="1"
```
## Step 6: Group Mapping (Optional)
If you plan to add groups to AuthentiKate in the future:
```bash
# Enable group provisioning
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-groupProvisioning --value="1"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-groupMapping --value="groups"
```
## Step 7: Login Button Customization
Customize the OAuth login button:
### Via Config
```bash
# Set custom button text
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-buttonText --value="Login with AuthentiKate"
# Hide default login form (optional)
sudo -u www-data php occ config:system:set hide_login_form --value=true
```
### Custom CSS (Optional)
Add custom styling in **Settings****Administration****Theming**:
```css
/* Style the OIDC login button */
.oidc-login-button {
background-color: #3b82f6 !important;
border-color: #3b82f6 !important;
}
.oidc-login-button:hover {
background-color: #2563eb !important;
border-color: #2563eb !important;
}
```
## Complete Configuration Example
Here's a complete command-line setup:
```bash
#!/bin/bash
# Install and enable OIDC app
sudo -u www-data php occ app:install user_oidc
sudo -u www-data php occ app:enable user_oidc
# Configure OIDC provider
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-clientId --value="your-client-id"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-clientSecret --value="your-client-secret"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-discoveryUrl --value="https://auth.yourdomain.com/.well-known/openid_configuration"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-scope --value="openid profile email"
# User mapping
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-uniqueUid --value="1"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-uniqueUidMapping --value="preferred_username"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-displayNameMapping --value="name"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-emailMapping --value="email"
# Auto-provisioning
sudo -u www-data php occ config:app:set user_oidc auto-provision --value="1"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-provisioningEnabled --value="1"
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-checkEmailVerification --value="1"
# Button customization
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-buttonText --value="Login with AuthentiKate"
echo "Nextcloud OIDC integration configured successfully!"
```
## Docker Compose Example
Complete Docker setup with Nextcloud and AuthentiKate:
```yaml
version: '3.8'
services:
nextcloud:
image: nextcloud:latest
container_name: nextcloud
restart: unless-stopped
ports:
- "80:80"
environment:
- NEXTCLOUD_ADMIN_USER=admin
- NEXTCLOUD_ADMIN_PASSWORD=secure_password
- NEXTCLOUD_TRUSTED_DOMAINS=cloud.yourdomain.com
- OVERWRITEPROTOCOL=https
- OVERWRITEHOST=cloud.yourdomain.com
volumes:
- nextcloud_data:/var/www/html
- ./setup-oidc.sh:/docker-entrypoint-hooks.d/pre-installation/setup-oidc.sh:ro
labels:
# Traefik labels
- "traefik.enable=true"
- "traefik.http.routers.nextcloud.rule=Host(`cloud.yourdomain.com`)"
- "traefik.http.routers.nextcloud.entrypoints=websecure"
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
volumes:
nextcloud_data:
```
## Testing the Integration
1. **Log out** of Nextcloud (if currently logged in)
2. **Navigate to** your Nextcloud login page
3. **Click "Login with AuthentiKate"** button
4. **Authenticate** with your AuthentiKate credentials
5. **Verify** you're logged into Nextcloud with correct user information
## Advanced Configuration
### Custom User Provisioning
Control how users are created:
```bash
# Set default quota for new users
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-defaultQuota --value="5GB"
# Set default group for new users
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-defaultGroup --value="users"
```
### Backup Users
Prevent deletion of users not found in OIDC:
```bash
# Enable soft delete (backup users)
sudo -u www-data php occ config:app:set user_oidc provider-authentikate-softAutoUpdate --value="1"
```
### Admin Users
Make specific users administrators:
```bash
# Add users to admin group (run after first login)
sudo -u www-data php occ group:adduser admin "admin_username"
```
## Troubleshooting
### Common Issues
#### "Invalid redirect URI" Error
Ensure the redirect URI in AuthentiKate exactly matches:
```
https://cloud.yourdomain.com/apps/user_oidc/code
```
#### OIDC Login Button Missing
Check that the app is enabled:
```bash
sudo -u www-data php occ app:list | grep user_oidc
```
#### Users Not Auto-Created
Verify auto-provisioning is enabled:
```bash
sudo -u www-data php occ config:app:get user_oidc auto-provision
sudo -u www-data php occ config:app:get user_oidc provider-authentikate-provisioningEnabled
```
#### Wrong User Information
Check the attribute mapping:
```bash
sudo -u www-data php occ config:app:get user_oidc provider-authentikate-displayNameMapping
sudo -u www-data php occ config:app:get user_oidc provider-authentikate-emailMapping
```
### Debug Mode
Enable debugging in Nextcloud:
```bash
# Enable debug mode
sudo -u www-data php occ config:system:set debug --value=true
# Check logs
sudo -u www-data php occ log:tail
```
### Configuration Check
Verify your OIDC configuration:
```bash
# List all OIDC settings
sudo -u www-data php occ config:list user_oidc
# Test OIDC discovery endpoint
curl https://auth.yourdomain.com/.well-known/openid_configuration
```
### Reset Configuration
If you need to start over:
```bash
# Remove OIDC configuration
sudo -u www-data php occ config:app:delete user_oidc provider-authentikate-clientId
sudo -u www-data php occ config:app:delete user_oidc provider-authentikate-clientSecret
sudo -u www-data php occ config:app:delete user_oidc provider-authentikate-discoveryUrl
# Disable auto-provisioning
sudo -u www-data php occ config:app:set user_oidc auto-provision --value="0"
```
## Security Considerations
### Trusted Domains
Ensure your domain is in Nextcloud's trusted domains:
```bash
sudo -u www-data php occ config:system:set trusted_domains 0 --value="cloud.yourdomain.com"
```
### HTTPS Configuration
Force HTTPS in Nextcloud:
```bash
sudo -u www-data php occ config:system:set overwriteprotocol --value="https"
sudo -u www-data php occ config:system:set overwrite.cli.url --value="https://cloud.yourdomain.com"
```
### Session Security
Configure secure sessions:
```bash
sudo -u www-data php occ config:system:set session_lifetime --value=3600
sudo -u www-data php occ config:system:set session_keepalive --value=false
```
Your Nextcloud instance is now integrated with AuthentiKate! Users can sign in with their AuthentiKate credentials and access their Nextcloud files and applications.

View File

@ -0,0 +1,324 @@
# Integration Overview
AuthentiKate supports OpenID Connect (OIDC) and OAuth 2.0, making it compatible with hundreds of applications. This section covers how to integrate AuthentiKate with popular homelab applications.
## OIDC Endpoints
All applications will need these AuthentiKate endpoints:
| Endpoint | URL | Description |
|----------|-----|-------------|
| **Discovery** | `/.well-known/openid_configuration` | Auto-configuration endpoint |
| **Authorization** | `/oauth/authorize` | User authorization endpoint |
| **Token** | `/oauth/token` | Token exchange endpoint |
| **User Info** | `/oauth/userinfo` | User profile endpoint |
| **JWKS** | `/.well-known/jwks.json` | JSON Web Key Set |
::: tip
Most modern applications can auto-configure using just the discovery endpoint. Use `https://auth.yourdomain.com/.well-known/openid_configuration` when possible.
:::
## Quick Integration Steps
### 1. Create Application in AuthentiKate
1. Log into AuthentiKate admin panel
2. Go to **Applications** → **Create Application**
3. Fill in the details:
- **Name**: Your application name
- **Redirect URI**: Your app's OAuth callback URL
- **Icon**: Optional icon URL
4. Save and note the **Client ID** and **Client Secret**
### 2. Configure Your Application
Use the generated credentials in your application's OAuth/OIDC settings:
- **Provider URL**: `https://auth.yourdomain.com`
- **Client ID**: (from step 1)
- **Client Secret**: (from step 1)
- **Scopes**: `openid profile email`
### 3. Test the Integration
1. Try logging into your application
2. You should be redirected to AuthentiKate
3. After authentication, you'll be returned to your app
## Supported Applications
### Ready-to-Use Guides
- [**Grafana**](/integrations/grafana) - Analytics and monitoring
- [**Nextcloud**](/integrations/nextcloud) - File sharing and collaboration
- [**Traefik Forward Auth**](/integrations/traefik) - Reverse proxy authentication
### Compatible Applications
AuthentiKate works with any application that supports OIDC/OAuth2:
#### **Monitoring & Analytics**
- Grafana ✅
- Prometheus
- Uptime Kuma
- Tautulli
- Zabbix
- LibreNMS
#### **Media & Entertainment**
- Jellyfin
- Plex (via Tautulli)
- Overseerr
- Sonarr/Radarr/Lidarr
- Ombi
#### **Productivity & Files**
- Nextcloud ✅
- BookStack
- Paperless-ngx
- Standard Notes
- Joplin Server
- PhotoPrism
- Immich
#### **Development & Git**
- Gitea
- GitLab
- Forgejo
- Drone CI
- Jenkins
#### **Communication**
- Mattermost
- Rocket.Chat
- Element (Matrix)
#### **Infrastructure & Networking**
- Portainer
- Proxmox
- pfSense
- OPNsense
- Traefik ✅
#### **Finance & Business**
- Firefly III
- Invoice Ninja
- Crater
- Akaunting
## Application Templates
AuthentiKate includes templates for popular applications:
```javascript
// Example: Grafana template
{
name: "Grafana",
redirectUri: "https://grafana.yourdomain.com/login/generic_oauth",
icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/grafana.webp"
}
```
Available templates:
- Grafana
- Nextcloud
- Proxmox
- Portainer
- GitLab
- And many more...
## Integration Patterns
### Pattern 1: Direct OIDC Integration
Best for applications with built-in OIDC support:
```mermaid
graph LR
A[User] --> B[Application]
B --> C[AuthentiKate]
C --> B
B --> A
```
**Examples**: Grafana, Nextcloud, GitLab
### Pattern 2: Reverse Proxy Authentication
For applications without OIDC support:
```mermaid
graph LR
A[User] --> B[Reverse Proxy]
B --> C[AuthentiKate]
C --> B
B --> D[Application]
D --> B
B --> A
```
**Examples**: Traefik Forward Auth, nginx auth_request
### Pattern 3: Header-Based Authentication
Applications that accept authentication headers:
```mermaid
graph LR
A[User] --> B[Proxy + Headers]
B --> C[AuthentiKate]
C --> B
B --> D[Application]
```
**Examples**: Proxmox, Portainer (with middleware)
## Common Configuration Values
Most applications need these standard values:
### Basic OIDC Settings
```yaml
provider_url: https://auth.yourdomain.com
client_id: your-client-id
client_secret: your-client-secret
scopes: openid profile email
```
### Advanced Settings
```yaml
# Token validation
jwks_uri: https://auth.yourdomain.com/.well-known/jwks.json
issuer: https://auth.yourdomain.com
# User mapping
username_claim: preferred_username
email_claim: email
name_claim: name
# Security
require_https: true
verify_ssl: true
```
## User Attribute Mapping
AuthentiKate provides these user claims:
| Claim | Description | Example |
|-------|-------------|---------|
| `sub` | Unique user ID (UUID) | `f47ac10b-58cc-4372-a567-0e02b2c3d479` |
| `email` | User email address | `user@example.com` |
| `name` | Full display name | `John Doe` |
| `preferred_username` | Username | `john.doe` |
| `email_verified` | Email verification status | `true` |
| `picture` | Avatar URL | `https://auth.yourdomain.com/storage/avatars/...` |
### Custom User Mapping
Some applications need custom field mapping:
```yaml
# Grafana example
field_mapping:
login: preferred_username
email: email
name: name
# GitLab example
user_info_mapping:
username: preferred_username
email: email
name: name
```
## Troubleshooting Common Issues
### Invalid Redirect URI
```
Error: Invalid redirect URI
```
**Solution**: Ensure the redirect URI in AuthentiKate exactly matches your application's callback URL.
### Invalid Client
```
Error: Invalid client credentials
```
**Solution**: Double-check the Client ID and Client Secret in your application settings.
### SSL/HTTPS Issues
```
Error: SSL verification failed
```
**Solutions**:
- Ensure AuthentiKate is accessible via HTTPS
- Use valid SSL certificates
- Set `verify_ssl: false` only for testing
### Token Validation Errors
```
Error: Invalid token signature
```
**Solution**: Verify the JWKS endpoint is accessible and your application is using the correct validation method.
## Testing Your Integration
### 1. Manual Testing
1. Try logging into your application
2. Check that you're redirected to AuthentiKate
3. Verify successful authentication returns you to the app
4. Confirm user details are populated correctly
### 2. Token Validation
```bash
# Test the discovery endpoint
curl https://auth.yourdomain.com/.well-known/openid_configuration
# Test JWKS endpoint
curl https://auth.yourdomain.com/.well-known/jwks.json
# Test user info (requires valid token)
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
https://auth.yourdomain.com/oauth/userinfo
```
### 3. Debug Mode
Enable debug logging in your application to see:
- OAuth request/response details
- Token validation steps
- User claim mapping
## Security Best Practices
### Client Configuration
- Use strong, unique Client Secrets
- Implement proper redirect URI validation
- Use HTTPS for all communication
- Validate SSL certificates
### Scope Management
- Request minimal necessary scopes
- Use `openid` scope for OIDC compliance
- Add `profile` and `email` as needed
### Token Handling
- Store tokens securely
- Implement proper token refresh
- Validate token signatures
- Respect token expiration
## Getting Help
If you're having trouble integrating an application:
1. **Check the logs**: Both AuthentiKate and your application logs
2. **Verify endpoints**: Test OIDC endpoints with curl
3. **Compare settings**: Use working examples as reference
4. **Community help**: Check GitHub discussions for similar integrations
Ready to integrate your first application? Start with our [Grafana guide](/integrations/grafana) for a step-by-step walkthrough.

10
docs/package.json Normal file
View File

@ -0,0 +1,10 @@
{
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
},
"devDependencies": {
"vitepress": "^1.6.3"
}
}

View File

@ -19,4 +19,4 @@
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
"lightningcss-linux-x64-gnu": "^1.29.1"
}
}
}