Merge pull request #13 from orus-dev/simple-working-mvp
Simple working mvp
This commit is contained in:
Generated
+391
@@ -46,11 +46,13 @@
|
|||||||
"@supabase/supabase-js": "^2.94.1",
|
"@supabase/supabase-js": "^2.94.1",
|
||||||
"@uiw/codemirror-theme-vscode": "^4.25.4",
|
"@uiw/codemirror-theme-vscode": "^4.25.4",
|
||||||
"@uiw/react-codemirror": "^4.25.4",
|
"@uiw/react-codemirror": "^4.25.4",
|
||||||
|
"axios": "^1.13.5",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
|
"ioredis": "^5.9.2",
|
||||||
"lucide-react": "^0.563.0",
|
"lucide-react": "^0.563.0",
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
@@ -777,6 +779,12 @@
|
|||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ioredis/commands": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
@@ -3465,6 +3473,23 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.13.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
|
||||||
|
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.11",
|
||||||
|
"form-data": "^4.0.5",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.9.19",
|
"version": "2.9.19",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
|
||||||
@@ -3474,6 +3499,19 @@
|
|||||||
"baseline-browser-mapping": "dist/cli.js"
|
"baseline-browser-mapping": "dist/cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bind-apply-helpers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001766",
|
"version": "1.0.30001766",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
|
||||||
@@ -3521,6 +3559,15 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cluster-key-slot": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cmdk": {
|
"node_modules/cmdk": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz",
|
||||||
@@ -3552,6 +3599,18 @@
|
|||||||
"@codemirror/view": "^6.0.0"
|
"@codemirror/view": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cookie": {
|
"node_modules/cookie": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
|
||||||
@@ -3714,12 +3773,47 @@
|
|||||||
"integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==",
|
"integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/decimal.js-light": {
|
"node_modules/decimal.js-light": {
|
||||||
"version": "2.5.1",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||||
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
|
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||||
@@ -3746,6 +3840,20 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dunder-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/embla-carousel": {
|
"node_modules/embla-carousel": {
|
||||||
"version": "8.6.0",
|
"version": "8.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
|
||||||
@@ -3788,6 +3896,51 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-define-property": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-errors": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-object-atoms": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eventemitter3": {
|
"node_modules/eventemitter3": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
@@ -3803,6 +3956,75 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||||
|
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/function-bind": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-intrinsic": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-nonce": {
|
"node_modules/get-nonce": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||||
@@ -3812,6 +4034,31 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dunder-proto": "^1.0.1",
|
||||||
|
"es-object-atoms": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/gopd": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/graceful-fs": {
|
"node_modules/graceful-fs": {
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
@@ -3819,6 +4066,45 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/has-symbols": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/has-tostringtag": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-symbols": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hasown": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iceberg-js": {
|
"node_modules/iceberg-js": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
|
||||||
@@ -3837,6 +4123,30 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ioredis": {
|
||||||
|
"version": "5.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz",
|
||||||
|
"integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ioredis/commands": "1.5.0",
|
||||||
|
"cluster-key-slot": "^1.1.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"lodash.defaults": "^4.2.0",
|
||||||
|
"lodash.isarguments": "^3.1.0",
|
||||||
|
"redis-errors": "^1.2.0",
|
||||||
|
"redis-parser": "^3.0.0",
|
||||||
|
"standard-as-callback": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/ioredis"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "2.6.1",
|
"version": "2.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||||
@@ -4120,6 +4430,18 @@
|
|||||||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.defaults": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isarguments": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/loose-envify": {
|
"node_modules/loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
@@ -4151,6 +4473,42 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/math-intrinsics": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.11",
|
"version": "3.3.11",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||||
@@ -4311,6 +4669,12 @@
|
|||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/radix-ui": {
|
"node_modules/radix-ui": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz",
|
||||||
@@ -4706,6 +5070,27 @@
|
|||||||
"decimal.js-light": "^2.4.1"
|
"decimal.js-light": "^2.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redis-errors": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/redis-parser": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"redis-errors": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/scheduler": {
|
"node_modules/scheduler": {
|
||||||
"version": "0.27.0",
|
"version": "0.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||||
@@ -4779,6 +5164,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/standard-as-callback": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/style-mod": {
|
"node_modules/style-mod": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
|
||||||
|
|||||||
@@ -46,11 +46,13 @@
|
|||||||
"@supabase/supabase-js": "^2.94.1",
|
"@supabase/supabase-js": "^2.94.1",
|
||||||
"@uiw/codemirror-theme-vscode": "^4.25.4",
|
"@uiw/codemirror-theme-vscode": "^4.25.4",
|
||||||
"@uiw/react-codemirror": "^4.25.4",
|
"@uiw/react-codemirror": "^4.25.4",
|
||||||
|
"axios": "^1.13.5",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
|
"ioredis": "^5.9.2",
|
||||||
"lucide-react": "^0.563.0",
|
"lucide-react": "^0.563.0",
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import { createClient } from "@/lib/supabase/server";
|
||||||
|
import * as Core from "@/modules/live-run/core";
|
||||||
|
import { getSession } from "@/modules/account/core";
|
||||||
|
|
||||||
|
export async function POST(req: NextRequest) {
|
||||||
|
const { runId, moves } = await req.json();
|
||||||
|
|
||||||
|
if (!runId || !moves)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "body requires runId and moves" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
|
||||||
|
const supabase = await createClient();
|
||||||
|
|
||||||
|
const session = await getSession(supabase);
|
||||||
|
|
||||||
|
if (!session)
|
||||||
|
return NextResponse.json({ error: "Invalid session" }, { status: 401 });
|
||||||
|
|
||||||
|
const liveRun = await Core.getLiveRun(runId);
|
||||||
|
|
||||||
|
if (!liveRun)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Run is not live or does not exist" },
|
||||||
|
{ status: 401 },
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(moves);
|
||||||
|
|
||||||
|
const run = await Core.addLiveRunMoves(liveRun.id, moves);
|
||||||
|
|
||||||
|
return NextResponse.json({ ok: true, run });
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import { createClient } from "@/lib/supabase/server";
|
||||||
|
import * as Core from "@/modules/live-run/core";
|
||||||
|
import { getSession } from "@/modules/account/core";
|
||||||
|
import { randomUUID } from "crypto";
|
||||||
|
|
||||||
|
export async function PUT(req: NextRequest) {
|
||||||
|
const { problem, category } = await req.json();
|
||||||
|
|
||||||
|
if (!problem || !category)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "body requires problem and category" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
|
||||||
|
const supabase = await createClient();
|
||||||
|
|
||||||
|
const session = await getSession(supabase);
|
||||||
|
|
||||||
|
if (!session)
|
||||||
|
return NextResponse.json({ error: "Invalid session" }, { status: 401 });
|
||||||
|
|
||||||
|
const runId = randomUUID();
|
||||||
|
|
||||||
|
await Core.addLiveRun({
|
||||||
|
problem,
|
||||||
|
category,
|
||||||
|
id: runId,
|
||||||
|
username: session[1].username,
|
||||||
|
views: 0,
|
||||||
|
start: new Date().getTime(),
|
||||||
|
runsCount: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json({ ok: true, runId });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function POST(req: NextRequest) {
|
||||||
|
const { runId } = await req.json();
|
||||||
|
|
||||||
|
if (!runId)
|
||||||
|
return NextResponse.json({ error: "body requires runId" }, { status: 400 });
|
||||||
|
|
||||||
|
const supabase = await createClient();
|
||||||
|
|
||||||
|
const session = await getSession(supabase);
|
||||||
|
|
||||||
|
if (!session)
|
||||||
|
return NextResponse.json({ error: "Invalid session" }, { status: 401 });
|
||||||
|
|
||||||
|
const liveRun = await Core.getLiveRun(runId);
|
||||||
|
|
||||||
|
if (!liveRun)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Run is not live or does not exist" },
|
||||||
|
{ status: 401 },
|
||||||
|
);
|
||||||
|
|
||||||
|
const run = await Core.submitRun(supabase, liveRun, session[0].id);
|
||||||
|
|
||||||
|
return NextResponse.json({ ok: true, run });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function DELETE(req: NextRequest) {
|
||||||
|
const runId = req.nextUrl.searchParams.get("runId");
|
||||||
|
|
||||||
|
if (!runId)
|
||||||
|
return NextResponse.json({ error: "missing ?runId=" }, { status: 400 });
|
||||||
|
|
||||||
|
const supabase = await createClient();
|
||||||
|
|
||||||
|
const session = await getSession(supabase);
|
||||||
|
|
||||||
|
if (!session)
|
||||||
|
return NextResponse.json({ error: "Invalid session" }, { status: 401 });
|
||||||
|
|
||||||
|
const run = await Core.removeLiveRun(runId);
|
||||||
|
|
||||||
|
return NextResponse.json({ ok: true, run });
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import { Badge } from "@/components/ui/badge";
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Problem } from "@/modules/problems/types";
|
import { Problem } from "@/modules/problems/types";
|
||||||
import { Clock, Zap, Users, Code } from "lucide-react";
|
import { Clock, Zap, Users, Code } from "lucide-react";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
const ProblemCard = ({
|
const ProblemCard = ({
|
||||||
problem,
|
problem,
|
||||||
@@ -100,7 +101,7 @@ const ProblemCard = ({
|
|||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await fetch(`http://127.0.0.1:63780/start-run/${problem.id}`);
|
await axios.get(`http://127.0.0.1:63780/start-run/${problem.id}`);
|
||||||
window.open("vscode://", "_blank");
|
window.open("vscode://", "_blank");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Search, Grid, List } from "lucide-react";
|
import { Search, Grid, List } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import ProblemCard from "@/app/problems/components/ProblemCard";
|
import ProblemCard from "@/app/problems/components/ProblemCard";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||||
import useAction from "@/hook/use-action";
|
import useAction from "@/hook/use-action";
|
||||||
import { getProblems } from "@/modules/problems/actions";
|
import { getProblems } from "@/modules/problems/actions";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
export default function Problems() {
|
export default function Problems() {
|
||||||
const [problems, problemsLoaded, problemsError] = useAction(getProblems);
|
const [problems] = useAction(getProblems);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await axios.post("http://127.0.0.1:63780/auth", {
|
||||||
|
saveCookies: document.cookie,
|
||||||
|
});
|
||||||
|
})().catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
|
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { json } from "@codemirror/lang-json";
|
|||||||
import { python } from "@codemirror/lang-python";
|
import { python } from "@codemirror/lang-python";
|
||||||
import { java } from "@codemirror/lang-java";
|
import { java } from "@codemirror/lang-java";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import useAction, { useActionOnce } from "@/hook/use-action";
|
import useAction from "@/hook/use-action";
|
||||||
import { getLiveRunMoves } from "@/modules/live-run/actions";
|
import { getLiveRunMoves } from "@/modules/live-run/actions";
|
||||||
import { LiveRun, LiveRunMove } from "@/modules/live-run/types";
|
import { LiveRun, LiveRunMove } from "@/modules/live-run/types";
|
||||||
|
|
||||||
@@ -43,11 +43,29 @@ function getLanguageExtension(lang: Language) {
|
|||||||
|
|
||||||
export default function Editor({ run }: { run: LiveRun | null | undefined }) {
|
export default function Editor({ run }: { run: LiveRun | null | undefined }) {
|
||||||
const [editorView, setEditorView] = useState<EditorView>();
|
const [editorView, setEditorView] = useState<EditorView>();
|
||||||
const [moves] = useActionOnce<LiveRunMove[]>(
|
const [rawMoves] = useAction<LiveRunMove[]>(
|
||||||
async () => (run ? (await getLiveRunMoves(run.id)) || [] : []),
|
async () => (run ? await getLiveRunMoves(run.id) : []),
|
||||||
[run],
|
[run],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [_, setLastMoveId] = useState<number>(-1);
|
||||||
|
const [moves, setMoves] = useState<LiveRunMove[]>([]);
|
||||||
|
const [movesLoading, setMovesLoading] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!rawMoves || rawMoves.length === 0 || movesLoading) return;
|
||||||
|
|
||||||
|
setLastMoveId((prevLastMoveId) => {
|
||||||
|
const newMoves = rawMoves.filter((move) => move.moveId > prevLastMoveId);
|
||||||
|
|
||||||
|
if (newMoves.length === 0) return prevLastMoveId;
|
||||||
|
|
||||||
|
setMoves(newMoves);
|
||||||
|
|
||||||
|
return Math.max(...newMoves.map((m) => m.moveId));
|
||||||
|
});
|
||||||
|
}, [rawMoves, movesLoading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editorView || !moves) return;
|
if (!editorView || !moves) return;
|
||||||
|
|
||||||
@@ -73,16 +91,18 @@ export default function Editor({ run }: { run: LiveRun | null | undefined }) {
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!moves) return;
|
if (!moves) return;
|
||||||
|
setMovesLoading(true);
|
||||||
for (const move of moves) {
|
for (const move of moves) {
|
||||||
if (cancelled) break;
|
if (cancelled) break;
|
||||||
await executeMove(move);
|
await executeMove(move);
|
||||||
}
|
}
|
||||||
|
setMovesLoading(false);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [editorView, moves]);
|
}, [moves]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import {
|
|||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import LiveRunRow from "./components/LiveRunRow";
|
import LiveRunRow from "./components/LiveRunRow";
|
||||||
import useAction from "@/hook/use-action";
|
import useAction, { useActionInterval } from "@/hook/use-action";
|
||||||
import { getLiveRuns } from "@/modules/live-run/actions";
|
import { getLiveRuns } from "@/modules/live-run/actions";
|
||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||||
|
|
||||||
export default function LiveRuns() {
|
export default function LiveRuns() {
|
||||||
const [liveRuns] = useAction(getLiveRuns);
|
const [liveRuns] = useActionInterval(getLiveRuns, 1500);
|
||||||
|
|
||||||
// Sort top runners (status === 'pb') to the top
|
// Sort top runners (status === 'pb') to the top
|
||||||
const sortedRuns = [...(liveRuns || [])];
|
const sortedRuns = [...(liveRuns || [])];
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import "server-only";
|
||||||
|
import Redis from "ioredis";
|
||||||
|
|
||||||
|
export const redis = new Redis(process.env.REDIS_URL!);
|
||||||
@@ -25,11 +25,7 @@ export async function signInWithGitHub(origin: string) {
|
|||||||
export async function getSession() {
|
export async function getSession() {
|
||||||
const supabase = await createClient();
|
const supabase = await createClient();
|
||||||
|
|
||||||
try {
|
|
||||||
return await Core.getSession(supabase);
|
return await Core.getSession(supabase);
|
||||||
} catch {
|
|
||||||
return redirect("/login");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function signOut() {
|
export async function signOut() {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export async function getGithubProfile(
|
|||||||
|
|
||||||
export async function getSession(
|
export async function getSession(
|
||||||
supabase: SupabaseClient,
|
supabase: SupabaseClient,
|
||||||
): Promise<[User, UserProfile]> {
|
): Promise<[User, UserProfile] | null> {
|
||||||
const {
|
const {
|
||||||
data: { user },
|
data: { user },
|
||||||
error: sessionError,
|
error: sessionError,
|
||||||
@@ -79,16 +79,5 @@ export async function getSession(
|
|||||||
|
|
||||||
const profile = await getProfile(supabase, user);
|
const profile = await getProfile(supabase, user);
|
||||||
|
|
||||||
return [user, profile];
|
return user && profile ? [user, profile] : null;
|
||||||
}
|
|
||||||
|
|
||||||
export async function getSessionRedirect(
|
|
||||||
supabase: SupabaseClient,
|
|
||||||
redirect: (s: string) => void,
|
|
||||||
): Promise<[User, UserProfile] | undefined> {
|
|
||||||
try {
|
|
||||||
return await getSession(supabase);
|
|
||||||
} catch {
|
|
||||||
redirect("/login");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export async function getLiveRuns(): Promise<LiveRun[]> {
|
|||||||
return Core.getLiveRuns();
|
return Core.getLiveRuns();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLiveRun(id: string): Promise<LiveRun | undefined> {
|
export async function getLiveRun(id: string): Promise<LiveRun | null> {
|
||||||
return Core.getLiveRun(id);
|
return Core.getLiveRun(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,39 +2,115 @@
|
|||||||
|
|
||||||
import "server-only";
|
import "server-only";
|
||||||
import { LiveRun, LiveRunMove } from "./types";
|
import { LiveRun, LiveRunMove } from "./types";
|
||||||
|
import { SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
import { redis } from "@/lib/redis";
|
||||||
|
import { randomInt } from "crypto";
|
||||||
|
|
||||||
const liveRuns: LiveRun[] = [];
|
/** -------------------- Live Runs in Redis -------------------- */
|
||||||
const liveRunMoves: Record<string, LiveRunMove[]> = {};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a live run to Redis
|
||||||
|
*/
|
||||||
|
export async function addLiveRun(run: LiveRun) {
|
||||||
|
const exists = await redis.exists(`liveRun:${run.id}`);
|
||||||
|
if (exists) throw new Error("Duplicate run");
|
||||||
|
|
||||||
|
await redis.set(`liveRun:${run.id}`, JSON.stringify(run));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a live run from Redis
|
||||||
|
*/
|
||||||
|
export async function getLiveRun(id: string): Promise<LiveRun | null> {
|
||||||
|
const data = await redis.get(`liveRun:${id}`);
|
||||||
|
if (!data) return null;
|
||||||
|
return JSON.parse(data) as LiveRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all live runs
|
||||||
|
*/
|
||||||
export async function getLiveRuns(): Promise<LiveRun[]> {
|
export async function getLiveRuns(): Promise<LiveRun[]> {
|
||||||
return liveRuns;
|
const keys = await redis.keys("liveRun:*");
|
||||||
|
if (keys.length === 0) return [];
|
||||||
|
const runs = await redis.mget(...keys);
|
||||||
|
return runs.filter(Boolean).map((r) => JSON.parse(r!) as LiveRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLiveRun(id: string): Promise<LiveRun | undefined> {
|
/**
|
||||||
return liveRuns.find((r) => r.id === id);
|
* Remove a live run from Redis
|
||||||
|
*/
|
||||||
|
export async function removeLiveRun(id: string) {
|
||||||
|
await redis.del(`liveRun:${id}`, `liveRunMoves:${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLiveRunMoves(
|
/** -------------------- Live Run Moves -------------------- */
|
||||||
id: string,
|
|
||||||
): Promise<LiveRunMove[] | undefined> {
|
|
||||||
return liveRunMoves[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function addRun(run: LiveRun) {
|
|
||||||
if (!liveRuns.find((r) => r.id === run.id || r.username === run.username))
|
|
||||||
throw "Duplicate run";
|
|
||||||
|
|
||||||
liveRuns.push(run);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add moves to a live run (ephemeral)
|
||||||
|
*/
|
||||||
export async function addLiveRunMoves(id: string, moves: LiveRunMove[]) {
|
export async function addLiveRunMoves(id: string, moves: LiveRunMove[]) {
|
||||||
if (!liveRunMoves[id]) throw "Invalid run";
|
const runExists = await redis.exists(`liveRun:${id}`);
|
||||||
|
if (!runExists) throw new Error("Invalid run");
|
||||||
|
|
||||||
// Add the moves immediately
|
const pipeline = redis.pipeline();
|
||||||
liveRunMoves[id] = [...liveRunMoves[id], ...moves];
|
moves.forEach((move) => {
|
||||||
|
pipeline.rpush(`liveRunMoves:${id}`, JSON.stringify(move));
|
||||||
|
});
|
||||||
|
|
||||||
// After 3 seconds, remove only the moves we just added
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
liveRunMoves[id] = liveRunMoves[id].filter((move) => !moves.includes(move));
|
redis.del(`liveRunMoves:${id}`);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
|
await pipeline.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get live moves for a run
|
||||||
|
*/
|
||||||
|
export async function getLiveRunMoves(id: string): Promise<LiveRunMove[]> {
|
||||||
|
const moves = await redis.lrange(`liveRunMoves:${id}`, 0, -1);
|
||||||
|
return moves.map((m) => JSON.parse(m)) as LiveRunMove[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** -------------------- Submit Run -------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a run to Supabase (persistent storage)
|
||||||
|
* and remove it from Redis
|
||||||
|
*/
|
||||||
|
export async function submitRun(
|
||||||
|
supabase: SupabaseClient,
|
||||||
|
run: LiveRun,
|
||||||
|
user_id: string,
|
||||||
|
) {
|
||||||
|
const now = new Date();
|
||||||
|
const durationMs = now.getTime() - run.start;
|
||||||
|
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from("runs")
|
||||||
|
.insert([
|
||||||
|
{
|
||||||
|
id: run.id,
|
||||||
|
user_id,
|
||||||
|
problem_id: run.problem,
|
||||||
|
category: run.category,
|
||||||
|
assisted: false,
|
||||||
|
duration_ms: durationMs,
|
||||||
|
started_at: new Date(run.start),
|
||||||
|
finished_at: now,
|
||||||
|
valid: false,
|
||||||
|
invalid_reason: null,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.select();
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error("Error inserting run:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
await removeLiveRun(run.id);
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface LiveRun {
|
|||||||
export interface LiveRunMove {
|
export interface LiveRunMove {
|
||||||
latency: number;
|
latency: number;
|
||||||
cursor: number;
|
cursor: number;
|
||||||
|
moveId: number;
|
||||||
changes?: {
|
changes?: {
|
||||||
from: number;
|
from: number;
|
||||||
to: number;
|
to: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user