fix: ws, wip: animations

This commit is contained in:
Derock 2023-11-10 22:41:50 -05:00
parent e151a91290
commit a7fb919cda
No known key found for this signature in database
12 changed files with 216 additions and 180 deletions

View file

@ -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": {

View file

@ -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

View file

@ -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<T extends Record<string, number>>(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<T extends Record<string, number>>(props: {
</ResponsiveContainer>
</div>
<div className={`relative z-10 ${/*styles["stat-card"]*/ "asdf"}`}>
<p className="stroke stroke-card text-2xl font-bold">{props.value}</p>
<div className={`relative z-10 ${styles["stat-card"]}`}>
<p className="stroke stroke-card text-2xl font-bold">
<AnimatedNumber
animateToNumber={128391}
includeComma
fontStyle={{
fontSize: 24,
// fontWeight: "inherit",
}}
/>
{props.unit}
</p>
<p className="stroke stroke-card text-sm text-muted-foreground">
{props.subvalue}
</p>

View file

@ -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<StatData>(props.initialData);
api.system.liveStats.useSubscription(undefined, {
onData: (data) => {
setData(data);
},
});
return (
<div className="m-8 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-4">
<StatCard
title="CPU Usage"
value={`${data.cpu.usage ?? 0}%`}
// value={`${data.cpu.usage ?? 0}%`}
value={data.cpu.usage}
unit="%"
subvalue={`of ${data.cpu.cores} CPUs`}
icon={RiPulseFill}
data={TEST_DATA}
@ -58,9 +64,6 @@ export function SystemStatistics(props: {
data={TEST_DATA}
dataKey="cpu"
/>
{/* <StatCard />
<StatCard />
<StatCard /> */}
</div>
);
}

View file

@ -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 (
<div className="mx-auto max-w-[1500px]">

View file

@ -1,9 +1,9 @@
import { authenticatedProcedure, createTRPCRouter } from "../../trpc";
import os from "os";
import osu from "node-os-utils";
import { observable } from "@trpc/server/observable";
export const systemRouter = createTRPCRouter({
current: authenticatedProcedure.query(async ({ ctx }) => {
async function fetchSystemInfo() {
const [cpuUsage, storage, memory] = await Promise.all([
osu.cpu.usage(),
osu.drive.info("/"),
@ -26,5 +26,27 @@ export const systemRouter = createTRPCRouter({
total: memory.totalMemMb / 1024,
},
};
}
export const systemRouter = createTRPCRouter({
currentStats: authenticatedProcedure.query(async ({ ctx }) => {
return fetchSystemInfo();
}),
liveStats: authenticatedProcedure.subscription(async ({ ctx }) => {
return observable<Awaited<ReturnType<typeof fetchSystemInfo>>>(
(observer) => {
console.log("subscription got");
fetchSystemInfo().then(observer.next.bind(observer));
const interval = setInterval(async () => {
observer.next(await fetchSystemInfo());
}, 1000);
return () => {
clearInterval(interval);
};
},
);
}),
});

View file

@ -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");

View file

@ -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);
}
});

View file

@ -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,

View file

@ -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<AppRouter>();
@ -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)),
],
}),
);

View file

@ -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";
}