generated from thegrind/laravel-dockerized
Got claude started on the docs. Will have to update them heavily
This commit is contained in:
parent
92164921a5
commit
9db9b0f6b3
1
.gitignore
vendored
1
.gitignore
vendored
@ -27,3 +27,4 @@ yarn-error.log
|
||||
**/caddy
|
||||
frankenphp
|
||||
frankenphp-worker.php
|
||||
/docs/.vitepress/cache
|
||||
|
603
bun.lock
Normal file
603
bun.lock
Normal 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=="],
|
||||
}
|
||||
}
|
89
docs/.vitepress/config.mjs
Normal file
89
docs/.vitepress/config.mjs
Normal 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'
|
||||
}
|
||||
}
|
||||
})
|
@ -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
360
docs/config/email.md
Normal 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
402
docs/config/environment.md
Normal 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
188
docs/guide/applications.md
Normal 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
202
docs/guide/first-setup.md
Normal 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
259
docs/guide/installation.md
Normal 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
159
docs/guide/quick-start.md
Normal 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
75
docs/index.md
Normal 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)
|
||||
|
322
docs/integrations/grafana.md
Normal file
322
docs/integrations/grafana.md
Normal 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.
|
370
docs/integrations/nextcloud.md
Normal file
370
docs/integrations/nextcloud.md
Normal 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.
|
324
docs/integrations/overview.md
Normal file
324
docs/integrations/overview.md
Normal 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
10
docs/package.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev",
|
||||
"docs:build": "vitepress build",
|
||||
"docs:preview": "vitepress preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.6.3"
|
||||
}
|
||||
}
|
@ -19,4 +19,4 @@
|
||||
"@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
|
||||
"lightningcss-linux-x64-gnu": "^1.29.1"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user