From a7fb919cda02185d158fe735841eba585b2ffc72 Mon Sep 17 00:00:00 2001 From: Derock Date: Fri, 10 Nov 2023 22:41:50 -0500 Subject: [PATCH] fix: ws, wip: animations --- package.json | 7 +- pnpm-lock.yaml | 211 ++++++++++--------------- src/app/home/StatCard.tsx | 25 ++- src/app/home/SystemStatistics.tsx | 23 +-- src/app/home/page.tsx | 2 +- src/server/api/routers/system/index.ts | 60 ++++--- src/server/api/trpc.ts | 2 + src/server/server.ts | 19 ++- src/server/utils/serverUtils.ts | 9 +- src/trpc/{auth.ts => links.ts} | 0 src/trpc/react.tsx | 34 +++- src/trpc/shared.ts | 4 +- 12 files changed, 216 insertions(+), 180 deletions(-) rename src/trpc/{auth.ts => links.ts} (100%) diff --git a/package.json b/package.json index 0aa5ffc..8bf7cc9 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "build:server": "tsup", "clean": "rm -rf .next dist", "db:push": "drizzle-kit push:sqlite", - "dev": "npm-run-all build:server dev:run", + "dev": "tsup --watch --onSuccess \"npm run dev:run\" --clean", "dev:run": "node --enable-source-maps dist/server.js", "lint": "next lint", "start": "node -r tsconfig" @@ -43,6 +43,7 @@ "next-themes": "^0.2.1", "node-os-utils": "^1.3.7", "react": "18.2.0", + "react-animated-numbers": "^0.16.0", "react-dom": "18.2.0", "react-icons": "^4.11.0", "recharts": "^2.9.3", @@ -51,7 +52,6 @@ "tailwind-merge": "^2.0.0", "tailwindcss-animate": "^1.0.7", "ts-permissions": "^1.0.0", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.33.0", "ua-parser-js": "^1.0.37", "ws": "^8.14.2", "zod": "^3.22.4" @@ -78,11 +78,8 @@ "prettier": "^3.0.3", "prettier-plugin-tailwindcss": "^0.5.6", "tailwindcss": "^3.3.5", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.2.0", "tscpaths": "^0.0.9", "tsup": "^7.2.0", - "tsx": "^3.14.0", "typescript": "^5.2.2" }, "ct3aMetadata": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d7fa82..77292ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,9 @@ dependencies: react: specifier: 18.2.0 version: 18.2.0 + react-animated-numbers: + specifier: ^0.16.0 + version: 0.16.0(react-dom@18.2.0)(react@18.2.0) react-dom: specifier: 18.2.0 version: 18.2.0(react@18.2.0) @@ -113,9 +116,6 @@ dependencies: ts-permissions: specifier: ^1.0.0 version: 1.0.0 - uWebSockets.js: - specifier: github:uNetworking/uWebSockets.js#v20.33.0 - version: github.com/uNetworking/uWebSockets.js/c10b47c350cc97c299c6b4a07a98abb628704c71 ua-parser-js: specifier: ^1.0.37 version: 1.0.37 @@ -189,22 +189,13 @@ devDependencies: version: 0.5.6(prettier@3.0.3) tailwindcss: specifier: ^3.3.5 - version: 3.3.5(ts-node@10.9.1) - ts-node: - specifier: ^10.9.1 - version: 10.9.1(@types/node@20.9.0)(typescript@5.2.2) - tsconfig-paths: - specifier: ^4.2.0 - version: 4.2.0 + version: 3.3.5 tscpaths: specifier: ^0.0.9 version: 0.0.9 tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.31)(ts-node@10.9.1)(typescript@5.2.2) - tsx: - specifier: ^3.14.0 - version: 3.14.0 + version: 7.2.0(postcss@8.4.31)(typescript@5.2.2) typescript: specifier: ^5.2.2 version: 5.2.2 @@ -422,12 +413,6 @@ packages: dependencies: regenerator-runtime: 0.14.0 - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - /@drizzle-team/studio@0.0.5: resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==} dev: true @@ -726,12 +711,6 @@ packages: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - /@js-joda/core@5.6.1: resolution: {integrity: sha512-Xla/d7ZMMR6+zRd6lTio0wRZECfcfFJP7GGe9A9L4tDOlD5CX4YcZ4YZle9w58bBYzssojVapI84RraKWDQZRg==} dev: false @@ -1165,6 +1144,54 @@ packages: react: 18.2.0 dev: false + /@react-spring/animated@9.7.3(react@18.2.0): + resolution: {integrity: sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/shared': 9.7.3(react@18.2.0) + '@react-spring/types': 9.7.3 + react: 18.2.0 + dev: false + + /@react-spring/core@9.7.3(react@18.2.0): + resolution: {integrity: sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/animated': 9.7.3(react@18.2.0) + '@react-spring/shared': 9.7.3(react@18.2.0) + '@react-spring/types': 9.7.3 + react: 18.2.0 + dev: false + + /@react-spring/shared@9.7.3(react@18.2.0): + resolution: {integrity: sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/types': 9.7.3 + react: 18.2.0 + dev: false + + /@react-spring/types@9.7.3: + resolution: {integrity: sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==} + dev: false + + /@react-spring/web@9.7.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/animated': 9.7.3(react@18.2.0) + '@react-spring/core': 9.7.3(react@18.2.0) + '@react-spring/shared': 9.7.3(react@18.2.0) + '@react-spring/types': 9.7.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@rushstack/eslint-patch@1.5.1: resolution: {integrity: sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==} dev: true @@ -1299,18 +1326,6 @@ packages: engines: {node: '>=18.0.0'} dev: false - /@tsconfig/node10@1.0.9: - resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - /@types/better-sqlite3@7.6.7: resolution: {integrity: sha512-+c2YGPWY5831v3uj2/X0HRTK94u1GXU3sCnLqu7AKlxlSfawswnAiJR//TFzSL5azWsLQkG/uS+YnnqHtuZxPw==} dependencies: @@ -1638,14 +1653,11 @@ packages: acorn: 8.11.2 dev: true - /acorn-walk@8.3.0: - resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} - engines: {node: '>=0.4.0'} - /acorn@8.11.2: resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} @@ -1760,9 +1772,6 @@ packages: readable-stream: 3.6.2 dev: false - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -2433,9 +2442,6 @@ packages: readable-stream: 3.6.2 dev: false - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - /cross-spawn@6.0.5: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} @@ -2705,10 +2711,6 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - /difflib@0.2.4: resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} dependencies: @@ -4451,12 +4453,6 @@ packages: minimist: 1.2.8 dev: true - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true - /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -4738,9 +4734,6 @@ packages: semver: 7.5.4 dev: false - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - /map-cache@0.2.2: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} engines: {node: '>=0.10.0'} @@ -5701,7 +5694,7 @@ packages: camelcase-css: 2.0.1 postcss: 8.4.31 - /postcss-load-config@4.0.1(postcss@8.4.31)(ts-node@10.9.1): + /postcss-load-config@4.0.1(postcss@8.4.31): resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} engines: {node: '>= 14'} peerDependencies: @@ -5715,7 +5708,6 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.31 - ts-node: 10.9.1(@types/node@20.9.0)(typescript@5.2.2) yaml: 2.3.4 /postcss-nested@6.0.1(postcss@8.4.31): @@ -5909,6 +5901,18 @@ packages: strip-json-comments: 2.0.1 dev: false + /react-animated-numbers@0.16.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-MUoOsf8fLzwyUL9l6NEMma+29QtfbeYmt8x2LLt4IeLHQWJQfGa4WIUXB/VDVBXEhg74BhCRytdyvhHR3IiHsw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@react-spring/web': 9.7.3(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-intersection-observer: 8.34.0(react@18.2.0) + dev: false + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -5927,6 +5931,14 @@ packages: react: 18.2.0 dev: false + /react-intersection-observer@8.34.0(react@18.2.0): + resolution: {integrity: sha512-TYKh52Zc0Uptp5/b4N91XydfSGKubEhgZRtcg1rhTKABXijc4Sdr1uTp5lJ8TN27jwUsdXxjHXtHa0kPj704sw==} + peerDependencies: + react: ^15.0.0 || ^16.0.0 || ^17.0.0|| ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -6748,10 +6760,10 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders' dependencies: - tailwindcss: 3.3.5(ts-node@10.9.1) + tailwindcss: 3.3.5 dev: false - /tailwindcss@3.3.5(ts-node@10.9.1): + /tailwindcss@3.3.5: resolution: {integrity: sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==} engines: {node: '>=14.0.0'} hasBin: true @@ -6773,7 +6785,7 @@ packages: postcss: 8.4.31 postcss-import: 15.1.0(postcss@8.4.31) postcss-js: 4.0.1(postcss@8.4.31) - postcss-load-config: 4.0.1(postcss@8.4.31)(ts-node@10.9.1) + postcss-load-config: 4.0.1(postcss@8.4.31) postcss-nested: 6.0.1(postcss@8.4.31) postcss-selector-parser: 6.0.13 resolve: 1.22.8 @@ -6973,36 +6985,6 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - /ts-node@10.9.1(@types/node@20.9.0)(typescript@5.2.2): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.9.0 - acorn: 8.11.2 - acorn-walk: 8.3.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.2.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - /ts-pattern@4.3.0: resolution: {integrity: sha512-pefrkcd4lmIVR0LA49Imjf9DYLK8vtWhqBPA3Ya1ir8xCW0O2yjL9dsCVvI7pCodLC5q7smNpEtDR2yVulQxOg==} dev: false @@ -7020,15 +7002,6 @@ packages: strip-bom: 3.0.0 dev: true - /tsconfig-paths@4.2.0: - resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} - engines: {node: '>=6'} - dependencies: - json5: 2.2.3 - minimist: 1.2.8 - strip-bom: 3.0.0 - dev: true - /tscpaths@0.0.9: resolution: {integrity: sha512-tz4qimSJTCjYtHVsoY7pvxLcxhmhgmwzm7fyMEiL3/kPFFVyUuZOwuwcWwjkAsIrSUKJK22A7fNuJUwxzQ+H+w==} hasBin: true @@ -7043,7 +7016,7 @@ packages: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: false - /tsup@7.2.0(postcss@8.4.31)(ts-node@10.9.1)(typescript@5.2.2): + /tsup@7.2.0(postcss@8.4.31)(typescript@5.2.2): resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==} engines: {node: '>=16.14'} hasBin: true @@ -7068,7 +7041,7 @@ packages: globby: 11.1.0 joycon: 3.1.1 postcss: 8.4.31 - postcss-load-config: 4.0.1(postcss@8.4.31)(ts-node@10.9.1) + postcss-load-config: 4.0.1(postcss@8.4.31) resolve-from: 5.0.0 rollup: 3.29.4 source-map: 0.8.0-beta.0 @@ -7080,17 +7053,6 @@ packages: - ts-node dev: true - /tsx@3.14.0: - resolution: {integrity: sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==} - hasBin: true - dependencies: - esbuild: 0.18.20 - get-tsconfig: 4.7.2 - source-map-support: 0.5.21 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: @@ -7269,9 +7231,6 @@ packages: hasBin: true dev: false - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -7463,10 +7422,6 @@ packages: resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} engines: {node: '>= 14'} - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -7482,9 +7437,3 @@ packages: /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - - github.com/uNetworking/uWebSockets.js/c10b47c350cc97c299c6b4a07a98abb628704c71: - resolution: {tarball: https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/c10b47c350cc97c299c6b4a07a98abb628704c71} - name: uWebSockets.js - version: 20.33.0 - dev: false diff --git a/src/app/home/StatCard.tsx b/src/app/home/StatCard.tsx index 599fe14..2d0552c 100644 --- a/src/app/home/StatCard.tsx +++ b/src/app/home/StatCard.tsx @@ -2,11 +2,18 @@ import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { ResponsiveContainer, AreaChart, Area } from "recharts"; -// import styles from "./StatCard.module.css"; +import styles from "./StatCard.module.css"; +// import AnimatedNumber from "react-animated-numbers"; + +import dynamic from "next/dynamic"; +const AnimatedNumber = dynamic(() => import("react-animated-numbers"), { + ssr: false, +}); export function StatCard>(props: { title: string; - value: string; + value: number; + unit: string; subvalue: string; icon: React.FC<{ className: string }>; data: T[]; @@ -72,8 +79,18 @@ export function StatCard>(props: { -
-

{props.value}

+
+

+ + {props.unit} +

{props.subvalue}

diff --git a/src/app/home/SystemStatistics.tsx b/src/app/home/SystemStatistics.tsx index 02b29c9..2bf903e 100644 --- a/src/app/home/SystemStatistics.tsx +++ b/src/app/home/SystemStatistics.tsx @@ -4,6 +4,7 @@ import { api } from "~/trpc/react"; import { StatCard } from "./StatCard"; import { RouterOutputs } from "~/trpc/shared"; import { RiPulseFill } from "react-icons/ri"; +import { useState } from "react"; const TEST_DATA = [ { cpu: 0.05 }, @@ -16,19 +17,24 @@ const TEST_DATA = [ { cpu: 0.3 }, ]; -export function SystemStatistics(props: { - initialData: RouterOutputs["system"]["current"]; -}) { - const { data } = api.system.current.useQuery(undefined, { - initialData: props.initialData, - refetchInterval: 5_000, +type StatData = RouterOutputs["system"]["currentStats"]; + +export function SystemStatistics(props: { initialData: StatData }) { + const [data, setData] = useState(props.initialData); + + api.system.liveStats.useSubscription(undefined, { + onData: (data) => { + setData(data); + }, }); return (
- {/* - - */}
); } diff --git a/src/app/home/page.tsx b/src/app/home/page.tsx index 19792ee..1c63e6b 100644 --- a/src/app/home/page.tsx +++ b/src/app/home/page.tsx @@ -4,7 +4,7 @@ import { StatCard } from "./StatCard"; import { SystemStatistics } from "./SystemStatistics"; export default async function DashboardHome() { - const initialStats = await api.system.current.query(); + const initialStats = await api.system.currentStats.query(); return (
diff --git a/src/server/api/routers/system/index.ts b/src/server/api/routers/system/index.ts index 7225524..6a6e123 100644 --- a/src/server/api/routers/system/index.ts +++ b/src/server/api/routers/system/index.ts @@ -1,30 +1,52 @@ import { authenticatedProcedure, createTRPCRouter } from "../../trpc"; import os from "os"; import osu from "node-os-utils"; +import { observable } from "@trpc/server/observable"; + +async function fetchSystemInfo() { + const [cpuUsage, storage, memory] = await Promise.all([ + osu.cpu.usage(), + osu.drive.info("/"), + osu.mem.info(), + ]); + + return { + cpu: { + usage: cpuUsage, + cores: os.cpus().length, + }, + + storage: { + used: parseInt(storage.usedGb), + total: parseInt(storage.totalGb), + }, + + memory: { + used: memory.usedMemMb / 1024, + total: memory.totalMemMb / 1024, + }, + }; +} export const systemRouter = createTRPCRouter({ - current: authenticatedProcedure.query(async ({ ctx }) => { - const [cpuUsage, storage, memory] = await Promise.all([ - osu.cpu.usage(), - osu.drive.info("/"), - osu.mem.info(), - ]); + currentStats: authenticatedProcedure.query(async ({ ctx }) => { + return fetchSystemInfo(); + }), - return { - cpu: { - usage: cpuUsage, - cores: os.cpus().length, - }, + liveStats: authenticatedProcedure.subscription(async ({ ctx }) => { + return observable>>( + (observer) => { + console.log("subscription got"); + fetchSystemInfo().then(observer.next.bind(observer)); - storage: { - used: parseInt(storage.usedGb), - total: parseInt(storage.totalGb), - }, + const interval = setInterval(async () => { + observer.next(await fetchSystemInfo()); + }, 1000); - memory: { - used: memory.usedMemMb / 1024, - total: memory.totalMemMb / 1024, + return () => { + clearInterval(interval); + }; }, - }; + ); }), }); diff --git a/src/server/api/trpc.ts b/src/server/api/trpc.ts index 2c6c73a..c6244dd 100644 --- a/src/server/api/trpc.ts +++ b/src/server/api/trpc.ts @@ -56,6 +56,8 @@ export const createTRPCContext = async (opts: { req: NextRequest; resHeaders: Headers; }) => { + console.log("contexting ", opts.req.url); + // disable caching opts.resHeaders.set("Cache-Control", "no-store"); diff --git a/src/server/server.ts b/src/server/server.ts index 0f90d36..9c6ef8b 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -31,6 +31,8 @@ async function startApp() { // create the http server const server = createServer((req, res) => { + console.log("req", req.url); + getHandler(req, res).catch((error) => { logger.error(error); res.statusCode = 500; @@ -43,11 +45,14 @@ async function startApp() { const trpcHandler = applyWSSHandler({ wss, router: appRouter, - createContext: ({ req }) => - createTRPCContext({ + createContext: ({ req }) => { + console.log("createContext", req.url); + + return createTRPCContext({ req: incomingRequestToNextRequest(req), resHeaders: new Headers(), - }), + }); + }, }); process.on("SIGTERM", () => { @@ -60,10 +65,16 @@ async function startApp() { // handle the upgrade server.on("upgrade", (req, socket, head) => { + console.log("upgrade", req.url); + // send trpc requests to the trpc server if (req.url?.startsWith("/api/trpc")) { - wss.handleUpgrade(req, socket, head, () => undefined); + console.log("🚚 passing upgrade to tRPC"); + wss.handleUpgrade(req, socket, head, (ws) => { + wss.emit("connection", ws, req); + }); } else { + console.log("🆙 ws for next.js recieved"); void upgradeHandler(req, socket, head); } }); diff --git a/src/server/utils/serverUtils.ts b/src/server/utils/serverUtils.ts index 7a6fb11..1f85442 100644 --- a/src/server/utils/serverUtils.ts +++ b/src/server/utils/serverUtils.ts @@ -1,6 +1,7 @@ import assert from "assert"; import { type IncomingMessage } from "http"; import { NextRequest } from "next/server.js"; +import { getUrl } from "~/trpc/shared"; /** * Turns an node:http IncomingMessage into a next.js request @@ -29,9 +30,13 @@ export function incomingRequestToNextRequest(req: IncomingMessage) { }); } - // create the web request + // resolve URL assert(req.url, "req.url is undefined"); - return new NextRequest(req.url, { + const url = new URL(req.url, getUrl()); + + // create the web request + + return new NextRequest(url.toString(), { method: req.method, body, headers, diff --git a/src/trpc/auth.ts b/src/trpc/links.ts similarity index 100% rename from src/trpc/auth.ts rename to src/trpc/links.ts diff --git a/src/trpc/react.tsx b/src/trpc/react.tsx index 8622385..1797f8d 100644 --- a/src/trpc/react.tsx +++ b/src/trpc/react.tsx @@ -5,13 +5,17 @@ import { type HTTPBatchStreamLinkOptions, loggerLink, unstable_httpBatchStreamLink, + wsLink, + createWSClient, + splitLink, + httpLink, } from "@trpc/client"; import { createTRPCReact } from "@trpc/react-query"; import { useState } from "react"; import { type AppRouter } from "~/server/api/root"; import { getUrl, transformer } from "./shared"; -import { authLink } from "./auth"; +import { authLink } from "./links"; export const api = createTRPCReact(); @@ -48,8 +52,34 @@ export function TRPCReactProvider(props: { process.env.NODE_ENV === "development" || (op.direction === "down" && op.result instanceof Error), }), + authLink(sharedLinkOptions(props.cookies)), - unstable_httpBatchStreamLink(sharedLinkOptions(props.cookies)), + + splitLink({ + condition(op) { + return op.type === "subscription"; + }, + + // true: httpLink(sharedLinkOptions(props.cookies)), + // false: unstable_httpBatchStreamLink(sharedLinkOptions(props.cookies)), + + true: wsLink({ + client: createWSClient({ + url: getUrl().replace("http", "ws"), + }), + }), + + false: unstable_httpBatchStreamLink(sharedLinkOptions(props.cookies)), + }), + + // authLink(sharedLinkOptions(props.cookies)), + // wsLink({ + // client: createWSClient({ + // url: getUrl().replace("http", "ws"), + // }), + // }), + // wsLink(sharedLinkOptions(props.cookies)), + // unstable_httpBatchStreamLink(sharedLinkOptions(props.cookies)), ], }), ); diff --git a/src/trpc/shared.ts b/src/trpc/shared.ts index 955d9fb..b9375c7 100644 --- a/src/trpc/shared.ts +++ b/src/trpc/shared.ts @@ -6,9 +6,9 @@ import { type AppRouter } from "~/server/api/root"; export const transformer = superjson; function getBaseUrl() { - if (typeof window !== "undefined") return ""; + if (typeof window !== "undefined") return window.location.origin; const vc = process.env.VERCEL_URL; - if (vc) return "https://" + vc; + if (vc !== undefined && vc !== "") return "https://" + vc; return "http://localhost:3000"; }