mirror of
				https://github.com/steveiliop56/tinyauth.git
				synced 2025-10-30 21:55:43 +00:00 
			
		
		
		
	feat: app context
This commit is contained in:
		| @@ -10,6 +10,8 @@ | ||||
|         "@radix-ui/react-separator": "^1.1.4", | ||||
|         "@radix-ui/react-slot": "^1.2.2", | ||||
|         "@tailwindcss/vite": "^4.1.4", | ||||
|         "@tanstack/react-query": "^5.75.6", | ||||
|         "axios": "^1.9.0", | ||||
|         "class-variance-authority": "^0.7.1", | ||||
|         "clsx": "^2.1.1", | ||||
|         "i18next": "^25.0.2", | ||||
| @@ -29,6 +31,7 @@ | ||||
|       }, | ||||
|       "devDependencies": { | ||||
|         "@eslint/js": "^9.22.0", | ||||
|         "@tanstack/eslint-plugin-query": "^5.74.7", | ||||
|         "@types/node": "^22.15.3", | ||||
|         "@types/react": "^19.0.10", | ||||
|         "@types/react-dom": "^19.0.4", | ||||
| @@ -318,6 +321,12 @@ | ||||
|  | ||||
|     "@tailwindcss/vite": ["@tailwindcss/vite@4.1.5", "", { "dependencies": { "@tailwindcss/node": "4.1.5", "@tailwindcss/oxide": "4.1.5", "tailwindcss": "4.1.5" }, "peerDependencies": { "vite": "^5.2.0 || ^6" } }, "sha512-FE1stRoqdHSb7RxesMfCXE8icwI1W6zGE/512ae3ZDrpkQYTTYeSyUJPRCjZd8CwVAhpDUbi1YR8pcZioFJQ/w=="], | ||||
|  | ||||
|     "@tanstack/eslint-plugin-query": ["@tanstack/eslint-plugin-query@5.74.7", "", { "dependencies": { "@typescript-eslint/utils": "^8.18.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" } }, "sha512-EeHuaaYiCOD+XOGyB7LMNEx9OEByAa5lkgP+S3ZggjKJpmIO6iRWeoIYYDKo2F8uc3qXcVhTfC7pn7NddQiNtA=="], | ||||
|  | ||||
|     "@tanstack/query-core": ["@tanstack/query-core@5.75.6", "", {}, "sha512-r+WQ/z30KZF0TFkzCT7C8gWgrLuv7/t+gEjqeEp69JAIUS/omuieaHeIkoscjEcT6yaWebXGTyjdiIxJkYzEXg=="], | ||||
|  | ||||
|     "@tanstack/react-query": ["@tanstack/react-query@5.75.6", "", { "dependencies": { "@tanstack/query-core": "5.75.6" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-0d97uvpeHUNN5eTEsJzYgxLgAEyUM+XaJAWFFAaXH+dQgDN//TTDNbei/YVzN5BUJcWcnQ7YaQDtLLzSe+IvTg=="], | ||||
|  | ||||
|     "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], | ||||
|  | ||||
|     "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], | ||||
| @@ -382,6 +391,10 @@ | ||||
|  | ||||
|     "aria-hidden": ["aria-hidden@1.2.4", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A=="], | ||||
|  | ||||
|     "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], | ||||
|  | ||||
|     "axios": ["axios@1.9.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg=="], | ||||
|  | ||||
|     "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], | ||||
|  | ||||
|     "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], | ||||
| @@ -424,6 +437,8 @@ | ||||
|  | ||||
|     "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=="], | ||||
|  | ||||
|     "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], | ||||
| @@ -450,6 +465,8 @@ | ||||
|  | ||||
|     "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], | ||||
|  | ||||
|     "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], | ||||
|  | ||||
|     "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], | ||||
|  | ||||
|     "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], | ||||
| @@ -476,6 +493,8 @@ | ||||
|  | ||||
|     "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.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], | ||||
|  | ||||
|     "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], | ||||
| @@ -542,6 +561,10 @@ | ||||
|  | ||||
|     "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], | ||||
|  | ||||
|     "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=="], | ||||
|  | ||||
|     "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], | ||||
|  | ||||
|     "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], | ||||
| @@ -572,6 +595,8 @@ | ||||
|  | ||||
|     "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-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], | ||||
| @@ -746,9 +771,9 @@ | ||||
|  | ||||
|     "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], | ||||
|  | ||||
|     "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], | ||||
|     "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], | ||||
|  | ||||
|     "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], | ||||
|     "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], | ||||
|  | ||||
|     "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], | ||||
|  | ||||
| @@ -804,6 +829,8 @@ | ||||
|  | ||||
|     "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], | ||||
|  | ||||
|     "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], | ||||
|  | ||||
|     "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], | ||||
|  | ||||
|     "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], | ||||
| @@ -998,14 +1025,22 @@ | ||||
|  | ||||
|     "@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], | ||||
|  | ||||
|     "accepts/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], | ||||
|  | ||||
|     "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], | ||||
|  | ||||
|     "express/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], | ||||
|  | ||||
|     "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], | ||||
|  | ||||
|     "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], | ||||
|  | ||||
|     "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], | ||||
|  | ||||
|     "send/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], | ||||
|  | ||||
|     "type-is/mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], | ||||
|  | ||||
|     "@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], | ||||
|  | ||||
|     "@tailwindcss/oxide-wasm32-wasi/@emnapi/core/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], | ||||
| @@ -1024,6 +1059,14 @@ | ||||
|  | ||||
|     "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], | ||||
|  | ||||
|     "accepts/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], | ||||
|  | ||||
|     "express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], | ||||
|  | ||||
|     "send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], | ||||
|  | ||||
|     "type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], | ||||
|  | ||||
|     "@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], | ||||
|  | ||||
|     "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], | ||||
|   | ||||
| @@ -1,28 +1,31 @@ | ||||
| import js from '@eslint/js' | ||||
| import globals from 'globals' | ||||
| import reactHooks from 'eslint-plugin-react-hooks' | ||||
| import reactRefresh from 'eslint-plugin-react-refresh' | ||||
| import tseslint from 'typescript-eslint' | ||||
| import js from "@eslint/js"; | ||||
| import globals from "globals"; | ||||
| import reactHooks from "eslint-plugin-react-hooks"; | ||||
| import reactRefresh from "eslint-plugin-react-refresh"; | ||||
| import tseslint from "typescript-eslint"; | ||||
| import pluginQuery from "@tanstack/eslint-plugin-query"; | ||||
|  | ||||
| export default tseslint.config( | ||||
|   { ignores: ['dist'] }, | ||||
|   { ignores: ["dist"] }, | ||||
|   { | ||||
|     extends: [js.configs.recommended, ...tseslint.configs.recommended], | ||||
|     files: ['**/*.{ts,tsx}'], | ||||
|     files: ["**/*.{ts,tsx}"], | ||||
|     languageOptions: { | ||||
|       ecmaVersion: 2020, | ||||
|       globals: globals.browser, | ||||
|     }, | ||||
|     plugins: { | ||||
|       'react-hooks': reactHooks, | ||||
|       'react-refresh': reactRefresh, | ||||
|       "react-hooks": reactHooks, | ||||
|       "react-refresh": reactRefresh, | ||||
|       "@tanstack/query": pluginQuery, | ||||
|     }, | ||||
|     rules: { | ||||
|       ...reactHooks.configs.recommended.rules, | ||||
|       'react-refresh/only-export-components': [ | ||||
|         'warn', | ||||
|       "react-refresh/only-export-components": [ | ||||
|         "warn", | ||||
|         { allowConstantExport: true }, | ||||
|       ], | ||||
|       "@tanstack/query/exhaustive-deps": "error", | ||||
|     }, | ||||
|   }, | ||||
| ) | ||||
| ); | ||||
|   | ||||
| @@ -16,6 +16,8 @@ | ||||
|     "@radix-ui/react-separator": "^1.1.4", | ||||
|     "@radix-ui/react-slot": "^1.2.2", | ||||
|     "@tailwindcss/vite": "^4.1.4", | ||||
|     "@tanstack/react-query": "^5.75.6", | ||||
|     "axios": "^1.9.0", | ||||
|     "class-variance-authority": "^0.7.1", | ||||
|     "clsx": "^2.1.1", | ||||
|     "i18next": "^25.0.2", | ||||
| @@ -35,6 +37,7 @@ | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@eslint/js": "^9.22.0", | ||||
|     "@tanstack/eslint-plugin-query": "^5.74.7", | ||||
|     "@types/node": "^22.15.3", | ||||
|     "@types/react": "^19.0.10", | ||||
|     "@types/react-dom": "^19.0.4", | ||||
|   | ||||
							
								
								
									
										37
									
								
								frontend/src/context/app-context.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/src/context/app-context.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| import { AppContextSchema } from "@/schemas/app-context-schema"; | ||||
| import { createContext, useContext } from "react"; | ||||
| import { useQuery } from "@tanstack/react-query"; | ||||
| import axios from "axios"; | ||||
|  | ||||
| const AppContext = createContext<AppContextSchema | null>(null); | ||||
|  | ||||
| export const AppContextProvider = ({ | ||||
|   children, | ||||
| }: { | ||||
|   children: React.ReactNode; | ||||
| }) => { | ||||
|   const { isPending, isError, data, error } = useQuery({ | ||||
|     queryKey: ["status"], | ||||
|     queryFn: () => axios.get("/api/app").then((res) => res.data), | ||||
|   }); | ||||
|  | ||||
|   if (isPending) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (isError) { | ||||
|     throw error; | ||||
|   } | ||||
|  | ||||
|   return <AppContext.Provider value={data}>{children}</AppContext.Provider>; | ||||
| }; | ||||
|  | ||||
| export const useAppContext = () => { | ||||
|   const context = useContext(AppContext); | ||||
|  | ||||
|   if (!context) { | ||||
|     throw new Error("useAppContext must be used within an AppContextProvider"); | ||||
|   } | ||||
|  | ||||
|   return context; | ||||
| }; | ||||
| @@ -13,3 +13,7 @@ export const isValidUrl = (url: string) => { | ||||
|     return false | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const capitalize = (str: string) => { | ||||
|   return str.charAt(0).toUpperCase() + str.slice(1); | ||||
| } | ||||
| @@ -12,6 +12,8 @@ import { TotpPage } from "./pages/totp-page.tsx"; | ||||
| import { ForgotPasswordPage } from "./pages/forgot-password-page.tsx"; | ||||
| import { LogoutPage } from "./pages/logout-page.tsx"; | ||||
| import { UnauthorizedPage } from "./pages/unauthorized-page.tsx"; | ||||
| import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; | ||||
| import { AppContextProvider } from "./context/app-context.tsx"; | ||||
|  | ||||
| const router = createBrowserRouter([ | ||||
|   { | ||||
| @@ -56,10 +58,16 @@ const router = createBrowserRouter([ | ||||
|   }, | ||||
| ]); | ||||
|  | ||||
| const queryClient = new QueryClient(); | ||||
|  | ||||
| createRoot(document.getElementById("root")!).render( | ||||
|   <StrictMode> | ||||
|     <QueryClientProvider client={queryClient}> | ||||
|       <AppContextProvider> | ||||
|         <Layout> | ||||
|           <RouterProvider router={router} /> | ||||
|         </Layout> | ||||
|       </AppContextProvider> | ||||
|     </QueryClientProvider> | ||||
|   </StrictMode>, | ||||
| ); | ||||
|   | ||||
| @@ -7,22 +7,21 @@ import { | ||||
|   CardTitle, | ||||
| } from "@/components/ui/card"; | ||||
| import { Code } from "@/components/ui/code"; | ||||
| import { useAppContext } from "@/context/app-context"; | ||||
| import { isValidUrl } from "@/lib/utils"; | ||||
| import { Trans, useTranslation } from "react-i18next"; | ||||
| import { Navigate, useNavigate } from "react-router"; | ||||
|  | ||||
| export const ContinuePage = () => { | ||||
|   const { t } = useTranslation(); | ||||
|   const navigate = useNavigate(); | ||||
|   const params = new URLSearchParams(window.location.search); | ||||
|   const redirectURI = params.get("redirect_uri"); | ||||
|  | ||||
|   const redirectURI = params.get("redirect_uri") ?? ""; | ||||
|   const { domain, disableContinue } = useAppContext(); | ||||
|   const { t } = useTranslation(); | ||||
|  | ||||
|   //psuedo | ||||
|   const domain = "127.0.0.1"; | ||||
|   const disableContinue = false; | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
|   if (redirectURI === "") { | ||||
|   if (!redirectURI) { | ||||
|     return <Navigate to="/" />; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -4,10 +4,12 @@ import { | ||||
|   CardHeader, | ||||
|   CardTitle, | ||||
| } from "@/components/ui/card"; | ||||
| import { useAppContext } from "@/context/app-context"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
| import Markdown from "react-markdown"; | ||||
|  | ||||
| export const ForgotPasswordPage = () => { | ||||
|   const { forgotPasswordMessage } = useAppContext(); | ||||
|   const { t } = useTranslation(); | ||||
|  | ||||
|   return ( | ||||
| @@ -15,10 +17,7 @@ export const ForgotPasswordPage = () => { | ||||
|       <CardHeader> | ||||
|         <CardTitle className="text-3xl">{t("forgotPasswordTitle")}</CardTitle> | ||||
|         <CardDescription> | ||||
|           <Markdown> | ||||
|             You can reset your password by changing the `USERS` environment | ||||
|             variable. | ||||
|           </Markdown> | ||||
|           <Markdown>{forgotPasswordMessage}</Markdown> | ||||
|         </CardDescription> | ||||
|       </CardHeader> | ||||
|     </Card> | ||||
|   | ||||
| @@ -11,12 +11,12 @@ import { | ||||
| } from "@/components/ui/card"; | ||||
| import { OAuthButton } from "@/components/ui/oauth-button"; | ||||
| import { SeperatorWithChildren } from "@/components/ui/separator"; | ||||
| import { useAppContext } from "@/context/app-context"; | ||||
| import { useTranslation } from "react-i18next"; | ||||
|  | ||||
| export const LoginPage = () => { | ||||
|   const { configuredProviders, title } = useAppContext(); | ||||
|   const { t } = useTranslation(); | ||||
|   const configuredProviders = ["google", "github", "generic", "username"]; | ||||
|   const title = "Tinyauth"; | ||||
|  | ||||
|   const oauthConfigured = | ||||
|     configuredProviders.filter((provider) => provider !== "username").length > | ||||
|   | ||||
| @@ -7,14 +7,15 @@ import { | ||||
|   CardTitle, | ||||
| } from "@/components/ui/card"; | ||||
| import { Code } from "@/components/ui/code"; | ||||
| import { capitalize } from "@/utils/utils"; | ||||
| import { useAppContext } from "@/context/app-context"; | ||||
| import { capitalize } from "@/lib/utils"; | ||||
| import { Trans, useTranslation } from "react-i18next"; | ||||
|  | ||||
| export const LogoutPage = () => { | ||||
|   const { genericName } = useAppContext(); | ||||
|   const { t } = useTranslation(); | ||||
|  | ||||
|   const provider = "google"; | ||||
|   const genericName = "generic"; | ||||
|   const username = "username"; | ||||
|   const email = "smbd@example.com"; | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import { | ||||
| } from "@/components/ui/card"; | ||||
| import { Code } from "@/components/ui/code"; | ||||
| import { Trans, useTranslation } from "react-i18next"; | ||||
| import { Navigate } from "react-router"; | ||||
| import { Navigate, useNavigate } from "react-router"; | ||||
|  | ||||
| export const UnauthorizedPage = () => { | ||||
|   const searchParams = new URLSearchParams(window.location.search); | ||||
| @@ -17,6 +17,7 @@ export const UnauthorizedPage = () => { | ||||
|   const groupErr = searchParams.get("groupErr"); | ||||
|  | ||||
|   const { t } = useTranslation(); | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
|   if (!username) { | ||||
|     return <Navigate to="/" />; | ||||
| @@ -51,7 +52,7 @@ export const UnauthorizedPage = () => { | ||||
|         </CardDescription> | ||||
|       </CardHeader> | ||||
|       <CardFooter className="flex flex-col items-stretch"> | ||||
|         <Button onClick={() => window.location.replace("/")}> | ||||
|         <Button onClick={() => navigate("/login")}> | ||||
|           {t("unauthorizedButton")} | ||||
|         </Button> | ||||
|       </CardFooter> | ||||
|   | ||||
							
								
								
									
										13
									
								
								frontend/src/schemas/app-context-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								frontend/src/schemas/app-context-schema.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import { z } from "zod"; | ||||
|  | ||||
| export const appContextSchema = z.object({ | ||||
|     configuredProviders: z.array(z.string()), | ||||
|     disableContinue: z.boolean(), | ||||
|     title: z.string(), | ||||
|     genericName: z.string(), | ||||
|     domain: z.string(), | ||||
|     forgotPasswordMessage: z.string(), | ||||
|     oauthAutoRedirect: z.string(), | ||||
| }) | ||||
|  | ||||
| export type AppContextSchema = z.infer<typeof appContextSchema>; | ||||
							
								
								
									
										13
									
								
								frontend/src/schemas/user-context-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								frontend/src/schemas/user-context-schema.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import { z } from "zod"; | ||||
|  | ||||
| export const userContextSchema = z.object({ | ||||
|     isLoggedIn: z.boolean(), | ||||
|     username: z.string(), | ||||
|     name: z.string(), | ||||
|     email: z.string(), | ||||
|     provider: z.string(), | ||||
|     oauth: z.boolean(), | ||||
|     totpPending: z.boolean(),     | ||||
| }) | ||||
|  | ||||
| export type UserContextSchema = z.infer<typeof userContextSchema>; | ||||
| @@ -1,3 +0,0 @@ | ||||
| export const capitalize = (str: string) => { | ||||
|   return str.charAt(0).toUpperCase() + str.slice(1); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Stavros
					Stavros