diff --git a/.eslintrc.json b/.eslintrc.json index d87d588a..aa43ea62 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,6 +4,7 @@ "rules": { "prettier/prettier": ["error"], "@typescript-eslint/no-unused-vars": "warn", + "@typescript-eslint/no-explicit-any": "off", "react/react-in-jsx-scope": "off" } } diff --git a/package-lock.json b/package-lock.json index 1dad5a3b..56ccfaa4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,10 @@ "@fullcalendar/react": "^6.1.15", "@types/react-datepicker": "^4.19.5", "date-fns": "^2.30.0", + "fabric": "^6.4.3", + "jsonwebtoken": "^9.0.2", "moment": "2.30.1", + "mongodb": "^6.10.0", "next": "14.2.14", "react": "^18", "react-datepicker": "^4.21.0", @@ -23,6 +26,8 @@ "tailwind-merge": "^2.5.3" }, "devDependencies": { + "@types/fabric": "^5.3.9", + "@types/jsonwebtoken": "^9.0.7", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", @@ -286,6 +291,35 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", + "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@next/env": { "version": "14.2.14", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.14.tgz", @@ -536,12 +570,38 @@ "tslib": "^2.4.0" } }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/fabric": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/@types/fabric/-/fabric-5.3.9.tgz", + "integrity": "sha512-2UEVcGUG/taX5MRqW7mjCedHFdh6VZLseyMWw3DiILH0h/fdwW0mwijgZGTqAvl+uhfdv793wU3XcQxMVbuXZA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz", + "integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "20.17.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.1.tgz", @@ -585,6 +645,19 @@ "@types/react": "*" } }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.11.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz", @@ -797,11 +870,26 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, + "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -809,6 +897,17 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -818,6 +917,32 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "optional": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -853,7 +978,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -892,6 +1017,28 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -1069,6 +1216,13 @@ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, + "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", + "optional": true + }, "node_modules/autoprefixer": { "version": "10.4.20", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", @@ -1143,7 +1297,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "devOptional": true }, "node_modules/binary-extensions": { "version": "2.3.0", @@ -1161,7 +1315,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1211,6 +1365,19 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bson": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.9.0.tgz", + "integrity": "sha512-X9hJeyeM0//Fus+0pc5dSUMhhrrmWwQUtdavaQeF3Ta6m69matZkGWV/MrBcnwUeLC8W9kwwc2hfkZgUuCX3Ig==", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -1278,6 +1445,22 @@ } ] }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1330,6 +1513,16 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", @@ -1439,12 +1632,35 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "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", + "optional": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -1458,7 +1674,14 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "devOptional": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -1486,6 +1709,33 @@ "node": ">=4" } }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "license": "MIT", + "optional": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "license": "MIT", + "optional": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "license": "MIT", + "optional": true + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1497,6 +1747,48 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "license": "MIT", + "optional": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -1567,7 +1859,7 @@ "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, + "devOptional": true, "dependencies": { "ms": "^2.1.3" }, @@ -1580,6 +1872,26 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "license": "MIT", + "optional": true + }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1620,6 +1932,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1644,12 +1983,34 @@ "node": ">=6.0.0" } }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "license": "MIT", + "optional": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.47", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz", @@ -1675,6 +2036,19 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "optional": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -1866,6 +2240,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, "node_modules/eslint": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", @@ -2291,6 +2687,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -2319,7 +2729,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=4.0" } @@ -2328,7 +2738,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -2362,6 +2772,19 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/fabric": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fabric/-/fabric-6.4.3.tgz", + "integrity": "sha512-z/bJna3kWOBv+wmvVK4XxUQgCXLGb//VaSr5xPFIP708obH7472uuVsWbXam+xq+y21bLBtr4OHO1HuJyYi4FQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "jsdom": "^20.0.1" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2508,6 +2931,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -2521,11 +2959,37 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "devOptional": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -2577,39 +3041,100 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/get-stream": { - "version": "8.0.1", + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, @@ -2830,6 +3355,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -2842,6 +3374,48 @@ "node": ">= 0.4" } }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "license": "MIT", + "optional": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -2866,6 +3440,19 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2905,7 +3492,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, + "devOptional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2915,7 +3502,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "devOptional": true }, "node_modules/internal-slot": { "version": "1.0.7", @@ -3185,6 +3772,13 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT", + "optional": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3397,6 +3991,79 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "license": "MIT", + "optional": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -3427,6 +4094,27 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -3442,6 +4130,25 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3650,12 +4357,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/log-update": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", @@ -3802,6 +4544,37 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3830,6 +4603,29 @@ "node": ">=8.6" } }, + "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", + "optional": true, + "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", + "optional": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -3854,11 +4650,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3884,6 +4693,46 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -3892,11 +4741,64 @@ "node": "*" } }, + "node_modules/mongodb": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz", + "integrity": "sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, "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==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/mz": { "version": "2.7.0", @@ -3909,6 +4811,13 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", + "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", + "license": "MIT", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -4008,12 +4917,74 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "optional": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4059,6 +5030,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz", + "integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==", + "license": "MIT", + "optional": true + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4182,7 +5174,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, + "devOptional": true, "dependencies": { "wrappy": "1" } @@ -4261,6 +5253,19 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4274,7 +5279,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -4642,15 +5647,31 @@ "react-is": "^16.13.1" } }, + "node_modules/psl": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.10.0.tgz", + "integrity": "sha512-KSKHEbjAnpUuAUserOq0FxGXCUrzC3WniuSJhvdbs102rL55266ZcHBqLWOsG30spQMlPdpy7icATiAQehg/iA==", + "license": "MIT", + "optional": true, + "dependencies": { + "punycode": "^2.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT", + "optional": true + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4765,6 +5786,21 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -4821,6 +5857,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT", + "optional": true + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -4908,7 +5951,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, + "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -4924,7 +5967,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "devOptional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4981,6 +6024,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -4998,6 +6060,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT", + "optional": true + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "optional": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -5010,7 +6092,6 @@ "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -5018,6 +6099,13 @@ "node": ">=10" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -5101,6 +6189,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -5129,6 +6250,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5137,6 +6268,14 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -5145,6 +6284,16 @@ "node": ">=10.0.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -5331,7 +6480,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "devOptional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5462,6 +6611,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT", + "optional": true + }, "node_modules/synckit": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", @@ -5542,6 +6698,34 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5581,6 +6765,33 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -5747,6 +6958,16 @@ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -5786,11 +7007,35 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "devOptional": true + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "license": "MIT", + "optional": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } }, "node_modules/warning": { "version": "4.0.3", @@ -5800,6 +7045,49 @@ "loose-envify": "^1.0.0" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5894,6 +7182,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -6010,7 +7340,53 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "devOptional": true + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT", + "optional": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true }, "node_modules/yaml": { "version": "2.5.1", diff --git a/package.json b/package.json index 3bc85f0a..47f2a600 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,10 @@ "@fullcalendar/react": "^6.1.15", "@types/react-datepicker": "^4.19.5", "date-fns": "^2.30.0", + "fabric": "^6.4.3", + "jsonwebtoken": "^9.0.2", "moment": "2.30.1", + "mongodb": "^6.10.0", "next": "14.2.14", "react": "^18", "react-datepicker": "^4.21.0", @@ -29,6 +32,8 @@ "tailwind-merge": "^2.5.3" }, "devDependencies": { + "@types/fabric": "^5.3.9", + "@types/jsonwebtoken": "^9.0.7", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", diff --git a/src/app/admin/(block)/block-menu.tsx b/src/app/admin/(block)/block-menu.tsx index 90735648..716786a1 100644 --- a/src/app/admin/(block)/block-menu.tsx +++ b/src/app/admin/(block)/block-menu.tsx @@ -1,8 +1,8 @@ import React, { SetStateAction } from "react"; -import { blockTypes } from "@config/block_types"; +import { blockTypes } from "@/types/block_types"; import Link from "next/link"; import Image from "next/image"; -import Portal from "@app/components/Portal"; +import Portal from "@app/components/portal"; import Contour from "@app/admin/(block)/components/contour"; import { usePathname } from "next/navigation"; @@ -32,10 +32,10 @@ const BlockMenu = ({ isOpen, setIsOpen }: Props) => { -
+

블록 선택하기

- 블록 타입 + 블록 타입
    {blockTypes.map((item, index) => { return ( diff --git a/src/app/admin/(block)/calendar/components/schedule-form.tsx b/src/app/admin/(block)/calendar/components/schedule-form.tsx index 166e245d..1edc64d6 100644 --- a/src/app/admin/(block)/calendar/components/schedule-form.tsx +++ b/src/app/admin/(block)/calendar/components/schedule-form.tsx @@ -74,19 +74,10 @@ export default function ScheduleForm({ if (mode === "edit") return; try { - const token = sessionStorage.getItem("token"); - if (!token) { - throw new Error("로그인이 필요합니다."); - } - - const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/link/list`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - }, - ); + const response = await fetch("/api/link/list", { + credentials: "include", + method: "GET", + }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); @@ -121,17 +112,10 @@ export default function ScheduleForm({ }; try { - const token = sessionStorage.getItem("token"); - if (!token) throw new Error("인증 토큰이 없습니다. 다시 로그인해주세요."); - - const listResponse = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/link/list`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - }, - ); + const listResponse = await fetch("/api/link/list", { + credentials: "include", + method: "GET", + }); if (!listResponse.ok) { throw new Error("기존 일정을 불러오는데 실패했습니다."); @@ -161,33 +145,23 @@ export default function ScheduleForm({ requestBody = { id: blockId, type: 7, - sequence: existingCalendarBlock?.sequence || 1, style: existingCalendarBlock?.style || 1, schedule: updatedSchedules, }; } else { // 새로운 캘린더 블록 생성 및 일정 추가 - const nextSequence = await getSequence(token); - if (!nextSequence) return; requestBody = { type: 7, - sequence: nextSequence + 1, style: 1, schedule: [newSchedule], }; } - const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/link/${blockId ? "update" : "add"}`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify(requestBody), - }, - ); + const response = await fetch(`/api/link/${blockId ? "update" : "add"}`, { + credentials: "include", + method: "POST", + body: JSON.stringify(requestBody), + }); if (!response.ok) { throw new Error( diff --git a/src/app/admin/(block)/calendar/components/schedule-list.tsx b/src/app/admin/(block)/calendar/components/schedule-list.tsx index 40a66f2d..54469944 100644 --- a/src/app/admin/(block)/calendar/components/schedule-list.tsx +++ b/src/app/admin/(block)/calendar/components/schedule-list.tsx @@ -1,9 +1,9 @@ import Image from "next/image"; -import { useRouter } from "next/navigation"; +import { usePathname, useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { BsCalendarXFill } from "react-icons/bs"; -interface Schedule { +export interface Schedule { id: number; title: string; url: string; @@ -61,15 +61,17 @@ function EmptyState({ message }: { message: React.ReactNode }) { ); } -function ScheduleItem({ +export function ScheduleItem({ schedule, onDelete, }: { schedule: Schedule; - onDelete: (id: number) => void; + onDelete?: (id: number) => void; }) { const router = useRouter(); const status = getScheduleStatus(schedule); + const pathname = usePathname(); + const isCalendarPage = pathname.includes("/admin/calendar"); const handleEdit = () => { router.push(`/admin/calendar/manage?mode=edit&id=${schedule.id}`); @@ -96,28 +98,30 @@ function ScheduleItem({ }} />
-
+
{formatDate(schedule.dateStart)} ~ {formatDate(schedule.dateEnd)}
{schedule.title}
-
- - -
+ {isCalendarPage && ( +
+ + +
+ )}
-
+ {isCalendarPage &&
}
); } @@ -140,19 +144,9 @@ export default function ScheduleList() { const fetchSchedules = async () => { setError(null); try { - const token = sessionStorage.getItem("token"); - if (!token) { - throw new Error("로그인이 필요합니다."); - } - - const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/link/list`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - }, - ); + const response = await fetch(`/api/link/list`, { + credentials: "include", + }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); @@ -192,11 +186,6 @@ export default function ScheduleList() { throw new Error("캘린더 블록을 찾을 수 없습니다."); } - const token = sessionStorage.getItem("token"); - if (!token) { - throw new Error("로그인이 필요합니다."); - } - const updatedSchedules = schedules.filter( (schedule) => schedule.id !== scheduleId, ); @@ -204,22 +193,18 @@ export default function ScheduleList() { const requestBody = { id: calendarBlock.id, type: 7, - sequence: calendarBlock.sequence, style: calendarBlock.style, schedule: updatedSchedules, }; - const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/link/update`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify(requestBody), + const response = await fetch(`/api/link/update`, { + method: "POST", + headers: { + "Content-Type": "application/json", }, - ); + credentials: "include", + body: JSON.stringify(requestBody), + }); if (!response.ok) { const errorData = await response.json(); diff --git a/src/app/admin/(block)/calendar/components/style-setting.tsx b/src/app/admin/(block)/calendar/components/style-setting.tsx index 0a08bd07..098d8d0e 100644 --- a/src/app/admin/(block)/calendar/components/style-setting.tsx +++ b/src/app/admin/(block)/calendar/components/style-setting.tsx @@ -52,17 +52,10 @@ export default function StyleSetting() { const fetchSchedules = async () => { try { - const token = sessionStorage.getItem("token"); - if (!token) { - throw new Error("로그인이 필요합니다."); - } - const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/api/link/list`, { - headers: { - Authorization: `Bearer ${token}`, - }, + credentials: "include", }, ); diff --git a/src/app/admin/(block)/calendar/manage/page.tsx b/src/app/admin/(block)/calendar/manage/page.tsx index 5f41a274..9dd01b05 100644 --- a/src/app/admin/(block)/calendar/manage/page.tsx +++ b/src/app/admin/(block)/calendar/manage/page.tsx @@ -50,17 +50,10 @@ function ScheduleContent() { } try { - const token = sessionStorage.getItem("token"); - if (!token) throw new Error("로그인이 필요합니다."); - - const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/link/list`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - }, - ); + const response = await fetch("/api/link/list", { + credentials: "include", + method: "POST", + }); if (!response.ok) throw new Error("데이터를 불러오는데 실패했습니다."); diff --git a/src/app/admin/(block)/divider/components/divider-preview.tsx b/src/app/admin/(block)/divider/components/divider-preview.tsx index dd8d1f6e..1603774b 100644 --- a/src/app/admin/(block)/divider/components/divider-preview.tsx +++ b/src/app/admin/(block)/divider/components/divider-preview.tsx @@ -10,21 +10,12 @@ interface DividerContentProps { type: DividerType; } -const DividerContent = ({ type }: DividerContentProps) => { +export const DividerContent = ({ type }: DividerContentProps) => { const commonClasses = "flex h-12 items-center justify-center"; switch (type) { case "Space": return
; - case "Dashed": - case "Solid": - return ( -
-
-
- ); case "Point": return
· · ·
; case "Zigzag": @@ -38,6 +29,15 @@ const DividerContent = ({ type }: DividerContentProps) => { />
); + case "Dashed": + case "Solid": + return ( +
+
+
+ ); default: return
; } diff --git a/src/app/admin/(block)/event/components/event-form.tsx b/src/app/admin/(block)/event/components/event-form.tsx index 91118ccc..c6d22f01 100644 --- a/src/app/admin/(block)/event/components/event-form.tsx +++ b/src/app/admin/(block)/event/components/event-form.tsx @@ -8,7 +8,6 @@ import ButtonBox from "../../components/buttons/button-box"; import AddButton from "../../components/buttons/add-button"; import FormInput from "../../components/form-input"; import { useRouter, useSearchParams } from "next/navigation"; -import { getSequence } from "lib/get-sequence"; import "react-datepicker/dist/react-datepicker.css"; import { adminApiInstance } from "../../../../../utils/apis"; diff --git a/src/app/admin/(block)/event/components/event-preview.tsx b/src/app/admin/(block)/event/components/event-preview.tsx index 5ad312a4..5cecd378 100644 --- a/src/app/admin/(block)/event/components/event-preview.tsx +++ b/src/app/admin/(block)/event/components/event-preview.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef, useState } from "react"; import { IoIosArrowDown } from "react-icons/io"; import { twMerge } from "tailwind-merge"; +import { usePathname } from "next/navigation"; export default function EventPreview({ title, @@ -24,6 +25,8 @@ export default function EventPreview({ const [isTitleOverflowing, setIsTitleOverflowing] = useState(false); // 타이틀 텍스트 넘침 여부 const descriptionRef = useRef(null); const titleRef = useRef(null); + const pathname = usePathname(); + const isEvent = pathname.includes("event"); const calculateTimeLeft = () => { if (endDate && endTime) { @@ -88,7 +91,13 @@ export default function EventPreview({ } }; return ( -
+
void; selectedImageUrl: string; + connectingUrl?: string; + title: string | null; } -const ImageBox = ({ selectedImageUrl }: Props) => { +const ImageBox = ({ selectedImageUrl, connectingUrl, title }: Props) => { return ( -
- {/**/} - {/* */} - {/**/} -
- 이미지 URL을 확인해주세요 +
+
+ {/**/} + {/* */} + {/**/} + +
+ 이미지 URL을 확인해주세요 +
+
+ {title && ( +
{title}
+ )}
); }; diff --git a/src/app/admin/(block)/image/page.tsx b/src/app/admin/(block)/image/page.tsx index aff506c8..4c1af7b3 100644 --- a/src/app/admin/(block)/image/page.tsx +++ b/src/app/admin/(block)/image/page.tsx @@ -137,6 +137,8 @@ const Page = () => { {/*/>*/} >; - isValidUrl: (url: string) => boolean; + url?: string; + setIsImgUrlConnectionErrorMsg?: Dispatch>; + isValidUrl?: (url: string) => boolean; }) { const placeholderImage = "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="; @@ -24,6 +27,7 @@ export default function StylePreview({ // 이미지 URL이 변경될 때마다 이미지 로드 상태를 초기화 useEffect(() => { + if (!isValidUrl || !setIsImgUrlConnectionErrorMsg) return; if (selectedStyle === "배경" && linkImg && isValidUrl(linkImg)) { setHasImgError(false); setIsImgUrlConnectionErrorMsg(false); @@ -50,84 +54,92 @@ export default function StylePreview({ // Image에서 error 발생시 오류 메시지 출력 const imgErrorHandler = () => { setHasImgError(true); + if (!setIsImgUrlConnectionErrorMsg) return; setIsImgUrlConnectionErrorMsg(true); }; const imgUrl = - !hasImgError && isValidUrl(linkImg) ? linkImg : placeholderImage; + !hasImgError && isValidUrl && isValidUrl(linkImg) + ? linkImg + : placeholderImage; const backgroundStyle = - !hasImgError && isValidUrl(linkImg) + !hasImgError && isValidUrl && isValidUrl(linkImg) ? { backgroundImage: `url(${linkImg}), url(${placeholderImage})` } : { backgroundImage: `url(${placeholderImage})` }; return ( -
- {selectedStyle === "썸네일" && ( -
-
-
+ +
+ {selectedStyle === "썸네일" && ( +
+
+
+ {`${selectedStyle} +
+
+

{title || "타이틀을 입력해주세요"}

+
+
+
+ )} + + {selectedStyle === "심플" && ( +
+

{title || "타이틀을 입력해주세요"}

+
+ )} + + {selectedStyle === "카드" && ( +
+
{`${selectedStyle}
-
-

{title || "타이틀을 입력해주세요"}

-
+

{title || "타이틀을 입력해주세요"}

-
- )} + )} - {selectedStyle === "심플" && ( -
-

{title || "타이틀을 입력해주세요"}

-
- )} - - {selectedStyle === "카드" && ( -
-
- {`${selectedStyle} -
-

{title || "타이틀을 입력해주세요"}

-
- )} - - {selectedStyle === "배경" && ( -
- {!hasImgError && isValidUrl(linkImg) && ( -
- )} -

- {title || "타이틀을 입력해주세요"} -

-
- )} -
+ {!hasImgError && isValidUrl && isValidUrl(linkImg) && ( +
+ )} +

+ {title || "타이틀을 입력해주세요"} +

+
+ )} +
+ ); } diff --git a/src/app/admin/(block)/paint/page.tsx b/src/app/admin/(block)/paint/page.tsx new file mode 100644 index 00000000..cbb9b946 --- /dev/null +++ b/src/app/admin/(block)/paint/page.tsx @@ -0,0 +1,67 @@ +"use client"; +import React, { + FormEvent, + useEffect, + useLayoutEffect, + useRef, + useState, +} from "react"; +import Layout from "@app/admin/(block)/components/layout"; +import { useSearchParams } from "next/navigation"; +import * as fabric from "fabric"; + +const Page = () => { + const [canvas, setCanvas] = useState(); + const canvasRef = useRef(null); + const layoutRef = useRef(null); + + const prevPath = useSearchParams().get("prevPath") || "/admin"; + + useLayoutEffect(() => { + if (!layoutRef.current) return; + const { width, height } = layoutRef.current.getBoundingClientRect(); + const newCanvas = new fabric.Canvas("canvas", { + width, + height, + }); + setCanvas(newCanvas); + + return () => { + newCanvas.dispose().then(); + }; + }, []); + + const addImageBlock = async () => { + // const params = { + // type: 4, + // title, + // url: connectingUrl, + // imgUrl: selectedImageUrl, + // }; + // + // const blockApis = await adminApiInstance; + // const response = await blockApis.addBlock(params); + // if (!response) return; + // if (response.ok) { + // alert("이미지 블록 추가 완료"); + // router.push("/admin"); + // } else await blockApis.handleError(response); + }; + + const handleAddButtonClick = (e: FormEvent) => { + e.preventDefault(); + }; + return ( + +
+ +
+
+ ); +}; + +export default Page; diff --git a/src/app/admin/components/buttons/circle-button.tsx b/src/app/admin/components/buttons/circle-button.tsx new file mode 100644 index 00000000..dd7bf099 --- /dev/null +++ b/src/app/admin/components/buttons/circle-button.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +interface Props { + text: string; + onClick: () => void; +} +const CircleButton = ({ text, onClick }: Props) => { + return ( +
+ +
+ ); +}; + +export default CircleButton; diff --git a/src/app/admin/components/home-menu.tsx b/src/app/admin/components/home-menu.tsx index 8b71f5ab..09784762 100644 --- a/src/app/admin/components/home-menu.tsx +++ b/src/app/admin/components/home-menu.tsx @@ -11,12 +11,14 @@ const HomeMenu = () => { async function handleLogout() { try { // 인증 관련 데이터 제거 - sessionStorage.removeItem("token"); - document.cookie = - "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; - - router.push(ClientRoute.MAIN); - router.refresh(); + const response = await fetch("/api/logout", { + credentials: "include", + method: "POST", + }); + if (response.ok) { + alert("로그아웃 되었습니다."); + router.push(`/intro`); + } } catch (error) { console.error("로그아웃 중 오류 발생:", error); } @@ -57,6 +59,9 @@ const HomeMenu = () => {
  • +
  • + Login +
  • )} diff --git a/src/app/admin/components/preview/components/preview-calendar.tsx b/src/app/admin/components/preview/components/preview-calendar.tsx new file mode 100644 index 00000000..d060516e --- /dev/null +++ b/src/app/admin/components/preview/components/preview-calendar.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { Block } from "@app/admin/page"; +import { ScheduleItem } from "@app/admin/(block)/calendar/components/schedule-list"; + +// interface Schedule { +// id: number; +// title: string; +// url: string; +// dateStart: string; +// dateEnd: string; +// } + +interface Props { + block: Block; +} +const PreviewCalendar = ({ block }: Props) => { + const { id, title: subject, url, dateStart: start, dateEnd: end } = block; + const title = subject as string; + const dateStart = start as string; + const dateEnd = end as string; + const schedule = { id, title, url, dateStart, dateEnd }; + return ( +
    + +
    + ); +}; + +export default PreviewCalendar; diff --git a/src/app/admin/components/preview/components/preview-divider.tsx b/src/app/admin/components/preview/components/preview-divider.tsx new file mode 100644 index 00000000..5897f01a --- /dev/null +++ b/src/app/admin/components/preview/components/preview-divider.tsx @@ -0,0 +1,36 @@ +import React, { useEffect, useState } from "react"; +import { Block } from "@app/admin/page"; +import { DividerType } from "@app/admin/(block)/divider/types"; +import { DividerContent } from "@app/admin/(block)/divider/components/divider-preview"; + +interface Props { + block: Block; +} + +const PreviewDivider = ({ block }: Props) => { + const [selectedDivider, setSelectedDivider] = useState("Space"); + const { style } = block; + + useEffect(() => { + if (!style) return; + setSelectedDivider(getDividerStyle(style)); + }, [block]); + + const getDividerStyle = (type: number): DividerType => { + const styles: Record = { + 1: "Space", + 2: "Dashed", + 3: "Solid", + 4: "Point", + 5: "Zigzag", + }; + return styles[type] || "Space"; + }; + return ( +
    + +
    + ); +}; + +export default PreviewDivider; diff --git a/src/app/admin/components/preview/components/preview-event.tsx b/src/app/admin/components/preview/components/preview-event.tsx new file mode 100644 index 00000000..4f449b0c --- /dev/null +++ b/src/app/admin/components/preview/components/preview-event.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import { Block } from "@app/admin/page"; +import EventPreview from "@app/admin/(block)/event/components/event-preview"; + +interface Props { + block: Block; +} +const PreviewEvent = ({ block }: Props) => { + const { title: subject, subText01, dateStart: start, dateEnd: end } = block; + const title = subject as string; + const description = subText01 as string; + const dateStart = new Date(start as string); + const dateEnd = new Date(end as string); + + return ( + + ); +}; + +export default PreviewEvent; diff --git a/src/app/admin/components/preview/components/preview-image.tsx b/src/app/admin/components/preview/components/preview-image.tsx new file mode 100644 index 00000000..a8aa8cd0 --- /dev/null +++ b/src/app/admin/components/preview/components/preview-image.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { Block } from "@app/admin/page"; +import ImageBox from "@app/admin/(block)/image/components/image-box"; + +interface Props { + block: Block; +} +const PreviewImage = ({ block }: Props) => { + const { imgUrl, url, title } = block; + return ( +
    + +
    + ); +}; + +export default PreviewImage; diff --git a/src/app/admin/components/preview/components/preview-link.tsx b/src/app/admin/components/preview/components/preview-link.tsx new file mode 100644 index 00000000..147e03fa --- /dev/null +++ b/src/app/admin/components/preview/components/preview-link.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { Block } from "@app/admin/page"; +import { usePathname } from "next/navigation"; +import StylePreview from "@app/admin/(block)/link/components/style-preview"; + +interface Props { + block: Block; +} + +const styleItemNames = ["썸네일", "심플", "카드", "배경"]; +const PreviewLink = ({ block }: Props) => { + const pathname = usePathname(); + const isAdmin = pathname.includes("admin"); + const { url, title: subject, imgUrl: image, style } = block; + const title = subject as string; + const imgUrl = image as string; + const type = style as number; + const selectedStyle = styleItemNames[type - 1]; + + return ( + + ); +}; + +export default PreviewLink; diff --git a/src/app/admin/components/preview/components/preview-text.tsx b/src/app/admin/components/preview/components/preview-text.tsx new file mode 100644 index 00000000..e118a619 --- /dev/null +++ b/src/app/admin/components/preview/components/preview-text.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { Block } from "@app/admin/page"; +import { twMerge } from "tailwind-merge"; + +interface Props { + block: Block; +} +const PreviewText = ({ block }: Props) => { + const { title } = block; + return ( +
    + {title} +
    + ); +}; + +export default PreviewText; diff --git a/src/app/admin/components/preview/components/preview-video.tsx b/src/app/admin/components/preview/components/preview-video.tsx new file mode 100644 index 00000000..42ab59de --- /dev/null +++ b/src/app/admin/components/preview/components/preview-video.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { Block } from "@app/admin/page"; +import { twMerge } from "tailwind-merge"; +import { usePathname } from "next/navigation"; + +interface Props { + block: Block; +} +const PreviewVideo = ({ block }: Props) => { + const { url: videoUrl } = block; + const pathname = usePathname(); + const isAdmin = pathname.includes("/admin"); + return ( +
    + {videoUrl && ( + +
    동영상 주소를 확인해주세요
    +
    + )} +
    + ); +}; + +export default PreviewVideo; diff --git a/src/app/admin/components/preview/components/preview.tsx b/src/app/admin/components/preview/components/preview.tsx new file mode 100644 index 00000000..19572b99 --- /dev/null +++ b/src/app/admin/components/preview/components/preview.tsx @@ -0,0 +1,19 @@ +import React, { SetStateAction } from "react"; +import ProfileBox from "@app/admin/components/profile-box"; + +import BlockList from "@app/components/page/block-list"; + +interface Props { + setIsOpen?: React.Dispatch>; +} +const Preview = ({ setIsOpen }: Props) => { + return ( + //
    + <> + + + + ); +}; + +export default Preview; diff --git a/src/app/admin/components/preview/preview-modal.tsx b/src/app/admin/components/preview/preview-modal.tsx new file mode 100644 index 00000000..71592547 --- /dev/null +++ b/src/app/admin/components/preview/preview-modal.tsx @@ -0,0 +1,34 @@ +import React, { SetStateAction } from "react"; +import Portal from "@app/components/portal"; +import { Block } from "@app/admin/page"; +import Preview from "@app/admin/components/preview/components/preview"; + +interface Props { + isOpen: boolean; + setIsOpen: React.Dispatch>; + data: Block[]; +} + +const PreviewModal = ({ isOpen, setIsOpen, data }: Props) => { + if (!isOpen) return null; + + const handleClose = () => { + setIsOpen(false); + }; + + console.log(data[data.length - 1]); + return ( + + +
    + +
    +
    + ); +}; + +export default PreviewModal; diff --git a/src/app/admin/components/profile-box.tsx b/src/app/admin/components/profile-box.tsx new file mode 100644 index 00000000..e12e50e4 --- /dev/null +++ b/src/app/admin/components/profile-box.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import { twMerge } from "tailwind-merge"; +import HomeMenu from "@app/admin/components/home-menu"; +import Link from "next/link"; +import { ClientRoute } from "@config/route"; +import Image from "next/image"; +import { useTheme } from "@components/providers/theme-provider"; +import { usePathname } from "next/navigation"; + +const ProfileBox = () => { + const { theme } = useTheme(); + const pathname = usePathname(); + const isAdmin = pathname === "/admin"; + + return ( + <> +
    +
    + {"공유 +
    + + profile + momomoc + + + {!isAdmin && } +
    + + ); +}; + +export default ProfileBox; diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 52c9b850..a0a60d32 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,20 +1,19 @@ "use client"; import BlockMenu from "@app/admin/(block)/block-menu"; -import HomeMenu from "@app/admin/components/home-menu"; import BasicBlock from "@app/intro/components/basicblock"; import EmptyBlock from "@app/intro/components/UI/empty-block"; -import { useTheme } from "@components/providers/theme-provider"; -import { ClientRoute } from "@config/route"; + import Image from "next/image"; -import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import { useEffect, useRef, useState } from "react"; import { postBlock } from "../../lib/post-block"; import { adminApiInstance } from "../../utils/apis"; -import { twMerge } from "tailwind-merge"; +import ProfileBox from "@app/admin/components/profile-box"; +import PreviewModal from "@app/admin/components/preview/preview-modal"; +import CircleButton from "@app/admin/components/buttons/circle-button"; -interface Block { +export interface Block { id: number; type: number; sequence: number; @@ -34,30 +33,6 @@ interface Block { function Admin() { useEffect(() => { - const setVisitor = async () => { - const adminApis = await adminApiInstance; - if (!adminApis) { - alert("로그인이 필요합니다"); - if (typeof window !== "undefined") { - window.location.href = "/login"; - return; - } - } - const response = await adminApis.getVisitor(); - if (!response) return; - if (!response.ok) { - sessionStorage.removeItem("token"); - // alert("방문자 조회 실패"); - } else { - const infor = await response.json(); - setShowToday(infor.data.today); - setShowRealTime(infor.data.realTime); - setShowTotal(infor.data.total); - } - }; - setVisitor() - .then() - .catch((e) => console.log(e)); getBlocks().then(); }, []); useEffect(() => { @@ -81,6 +56,7 @@ function Admin() { const [showRealTime, setShowRealTime] = useState(0); const [isScrollTopVisible, setIsScrollTopVisible] = useState(false); const [isBlockMenuOn, setIsBlockMenuOn] = useState(false); + const [isPreviewOn, setIsPreviewOn] = useState(false); const [blocks, setBlocks] = useState([]); @@ -135,28 +111,13 @@ function Admin() { } }); }; - - const { theme } = useTheme(); + const handlePreviewOpen = () => { + setIsPreviewOn(true); + }; return ( -
    -
    - {!isAdmin && } - - profile - momomoc - -
    +
    +
    @@ -198,46 +159,50 @@ function Admin() {

    - {blocks.length == 0 ? ( - - ) : ( - blocks.map((block, index) => ( - - )) - )} +
    + {blocks === undefined || blocks.length == 0 ? ( + + ) : ( + blocks.map((block, index) => { + console.log(block); + return ( + + ); + }) + )} +
    + {isAdmin && ( <> -
    -
    - -
    +
    + + - )} + {/*{isScrollTopVisible && (*/} + {/* */} + {/* ▲*/} + {/* */} + {/*)}*/}
    ); } diff --git a/src/app/api/link/add/route.tsx b/src/app/api/link/add/route.tsx new file mode 100644 index 00000000..6519b7fe --- /dev/null +++ b/src/app/api/link/add/route.tsx @@ -0,0 +1,106 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import jwt from "jsonwebtoken"; +import clientPromise from "../../../../lib/mongodb"; + +interface JwtPayload { + userId: string; +} + +interface ScheduleType { + id: number; + title: string; + url: string; + dateStart: string; + dateEnd: string; +} + +interface NewData { + id: number; + type: number; + url?: string; + style?: number; + title?: string; + imgUrl?: string; + subText01?: string; + subText02?: string; + dateStart?: string; + dateEnd?: string; + schedule?: ScheduleType[]; +} + +interface UserDocument { + userId: string; + data: NewData[]; +} + +export async function POST(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + const client = await clientPromise; + const db = client.db("linkle"); + const collection = db.collection("userdata"); + const decoded = jwt.verify( + token, + process.env.JWT_SECRET as string, + ) as JwtPayload; + const userId = decoded.userId; + const userDocument = await collection.findOne({ userId }); + const newId = userDocument?.data?.length ?? 0; + + const body = await request.json(); + const { + type, + url, + style, + title, + imgUrl, + subText01, + subText02, + dateStart, + dateEnd, + schedule, + } = body; + + const newData: NewData = { + id: newId, + type, + url, + style, + title, + imgUrl, + subText01, + subText02, + dateStart, + dateEnd, + schedule: schedule?.map((item: ScheduleType, index: number) => ({ + ...item, + id: index, + })), + }; + + const result = await collection.updateOne( + { userId }, + { $push: { data: newData } }, + { upsert: true }, + ); + + return NextResponse.json( + { message: "Data successfully added", result }, + { status: 200 }, + ); + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/link/delete/route.tsx b/src/app/api/link/delete/route.tsx new file mode 100644 index 00000000..4bb55f95 --- /dev/null +++ b/src/app/api/link/delete/route.tsx @@ -0,0 +1,54 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import jwt from "jsonwebtoken"; +import clientPromise from "../../../../lib/mongodb"; +import { Collection } from "mongodb"; + +interface JwtPayload { + userId: string; +} +interface UserDocument { + userId: string; + data: Array<{ id: string }>; +} + +export async function POST(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + + const { id } = await request.json(); + const client = await clientPromise; + const db = client.db("linkle"); + const collection: Collection = db.collection("userdata"); + + const decoded = jwt.verify( + token, + process.env.JWT_SECRET as string, + ) as JwtPayload; + const userId = decoded.userId; + + const result = await collection.updateOne( + { userId: userId }, + { $pull: { data: { id: id } } }, + ); + + if (result.modifiedCount > 0) { + return NextResponse.json({ message: "Data deleted successfully" }); + } else { + return NextResponse.json({ message: "Data not found" }, { status: 404 }); + } + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/link/list/route.tsx b/src/app/api/link/list/route.tsx new file mode 100644 index 00000000..dbb422be --- /dev/null +++ b/src/app/api/link/list/route.tsx @@ -0,0 +1,41 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import jwt from "jsonwebtoken"; +import clientPromise from "../../../../lib/mongodb"; + +interface JwtPayload { + userId: string; +} + +export async function GET(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + const client = await clientPromise; + const db = client.db("linkle"); + const collection = db.collection("userdata"); + const decoded = jwt.verify( + token, + process.env.JWT_SECRET as string, + ) as JwtPayload; + const userId = decoded.userId; + const userData = await collection.find({ userId: userId }).toArray(); + const data = userData.length > 0 ? userData[0].data : []; + return NextResponse.json( + { message: "Success to get blocks", data }, + { status: 200 }, + ); + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/link/update/route.tsx b/src/app/api/link/update/route.tsx new file mode 100644 index 00000000..4200e6b0 --- /dev/null +++ b/src/app/api/link/update/route.tsx @@ -0,0 +1,107 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import jwt from "jsonwebtoken"; +import clientPromise from "../../../../lib/mongodb"; +import { Collection } from "mongodb"; + +interface JwtPayload { + userId: string; +} +interface UserDocument { + userId: string; + data: Array<{ id: string }>; +} + +interface ScheduleType { + id?: number; + title: string; + url: string; + dateStart: string; + dateEnd: string; +} + +interface NewData { + id: number; + type: number; + sequence: number; + url?: string; + style?: number; + title?: string; + imgUrl?: string; + subText01?: string; + subText02?: string; + dateStart?: string; + dateEnd?: string; + schedule?: ScheduleType[]; +} + +export async function POST(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + const body = await request.json(); + const { + id, + type, + sequence, + url, + style, + title, + imgUrl, + subText01, + subText02, + dateStart, + dateEnd, + schedule, + } = body; + const client = await clientPromise; + const db = client.db("linkle"); + const collection: Collection = db.collection("userdata"); + + const decoded = jwt.verify( + token, + process.env.JWT_SECRET as string, + ) as JwtPayload; + const userId = decoded.userId; + + const newData: NewData = { + id, + type, + sequence, + url, + style, + title, + imgUrl, + subText01, + subText02, + dateStart, + dateEnd, + schedule, + }; + + const result = await collection.updateOne( + { userId: userId, "data.id": id }, + { + $set: { + "data.$": newData, + }, + }, + ); + return NextResponse.json( + { message: "Data successfully updated", result }, + { status: 200 }, + ); + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/login/route.tsx b/src/app/api/login/route.tsx new file mode 100644 index 00000000..be42cad3 --- /dev/null +++ b/src/app/api/login/route.tsx @@ -0,0 +1,57 @@ +import { NextResponse } from "next/server"; +import clientPromise from "../../../lib/mongodb"; +import jwt from "jsonwebtoken"; +import type { NextRequest } from "next/server"; +import type { MongoClient, Db, Collection } from "mongodb"; + +interface User { + userId: string; + password: string; +} + +export async function POST(request: NextRequest) { + try { + const { userId, password }: { userId: string; password: string } = + await request.json(); + const client: MongoClient = await clientPromise; + const db: Db = client.db("linkle"); + const collection: Collection = db.collection("userdata"); + + const user: User | null = await collection.findOne({ userId }); + if (!user) { + return NextResponse.json({ message: "User not found" }, { status: 404 }); + } + + if (user.password === password) { + const token = jwt.sign({ userId }, process.env.JWT_SECRET as string, { + expiresIn: "1h", + }); + + const response = NextResponse.json( + { message: "Login Successfully" }, + { status: 200 }, + ); + response.cookies.set("token", token, { + httpOnly: true, + secure: true, + maxAge: 60 * 60, + path: "/", + sameSite: "none", + }); + + return response; + } else { + return NextResponse.json( + { message: "Password invalid" }, + { status: 401 }, + ); + } + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to find data", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/logout/route.tsx b/src/app/api/logout/route.tsx new file mode 100644 index 00000000..52f8662f --- /dev/null +++ b/src/app/api/logout/route.tsx @@ -0,0 +1,32 @@ +import { NextResponse } from "next/server"; + +export async function POST() { + try { + const response = NextResponse.json({ message: "Logged out successfully" }); + + try { + response.cookies.set("token", "", { + path: "/", + maxAge: 0, + httpOnly: true, + secure: true, + sameSite: "none", + }); + } catch (cookieError: unknown) { + const errorMessage = + cookieError instanceof Error ? cookieError.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to Delete data", error: errorMessage }, + { status: 500 }, + ); + } + return response; + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to fetch", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/protected/route.tsx b/src/app/api/protected/route.tsx new file mode 100644 index 00000000..f78919ab --- /dev/null +++ b/src/app/api/protected/route.tsx @@ -0,0 +1,22 @@ +import { NextRequest } from "next/server"; +import { NextResponse } from "next/server"; + +export async function POST(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + return NextResponse.json({ message: "success" }, { status: 200 }); + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/user/add/route.tsx b/src/app/api/user/add/route.tsx new file mode 100644 index 00000000..207a97a8 --- /dev/null +++ b/src/app/api/user/add/route.tsx @@ -0,0 +1,38 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import clientPromise from "../../../../lib/mongodb"; + +export async function POST(request: NextRequest) { + try { + const { name, userId, password, email } = await request.json(); + + const client = await clientPromise; + const db = client.db("linkle"); + const check = await db.collection("userdata").findOne({ userId: userId }); + if (!check) { + await db.collection("userdata").insertOne({ + name, + userId, + password, + email, + dateCreate: new Date(), + }); + return NextResponse.json( + { message: "Sign up successfully" }, + { status: 200 }, + ); + } else { + return NextResponse.json( + { message: "Name already exists" }, + { status: 409 }, + ); + } + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to create data", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/user/delete/route.tsx b/src/app/api/user/delete/route.tsx new file mode 100644 index 00000000..c5c4747d --- /dev/null +++ b/src/app/api/user/delete/route.tsx @@ -0,0 +1,43 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import jwt from "jsonwebtoken"; +import clientPromise from "../../../../lib/mongodb"; + +interface JwtPayload { + userId: string; +} + +export async function POST(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + const { userId } = await request.json(); + const client = await clientPromise; + const db = client.db("linkle"); + const collection = db.collection("userdata"); + const result = await collection.deleteOne({ userId: userId }); + if (result.deletedCount > 0) { + return NextResponse.json( + { message: "User data deleted successfully" }, + { status: 200 }, + ); + } else { + return NextResponse.json( + { message: "No document matched the userId" }, + { status: 404 }, + ); + } + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/user/info/route.tsx b/src/app/api/user/info/route.tsx new file mode 100644 index 00000000..04faa5dc --- /dev/null +++ b/src/app/api/user/info/route.tsx @@ -0,0 +1,44 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import jwt from "jsonwebtoken"; +import clientPromise from "../../../../lib/mongodb"; + +interface JwtPayload { + userId: string; +} + +export async function GET(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + const client = await clientPromise; + const db = client.db("linkle"); + const collection = db.collection("userdata"); + const decoded = jwt.verify( + token, + process.env.JWT_SECRET as string, + ) as JwtPayload; + const userId = decoded.userId; + const user = await collection.findOne( + { userId }, + { projection: { name: 1, userId: 1, email: 1, dateCreate: 1 } }, + ); + + if (!user) { + return NextResponse.json({ message: "User not found" }, { status: 404 }); + } + return NextResponse.json({ message: "User found", user }, { status: 200 }); + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/user/update/route.tsx b/src/app/api/user/update/route.tsx new file mode 100644 index 00000000..5228cc0a --- /dev/null +++ b/src/app/api/user/update/route.tsx @@ -0,0 +1,51 @@ +import { NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import jwt from "jsonwebtoken"; +import clientPromise from "../../../../lib/mongodb"; + +interface JwtPayload { + userId: string; +} + +export async function POST(request: NextRequest) { + try { + const token = request.cookies.get("token")?.value; + if (!token) { + return NextResponse.json( + { message: "Cookie not found" }, + { status: 401 }, + ); + } + const { name, password, email } = await request.json(); + const decoded = jwt.verify( + token, + process.env.JWT_SECRET as string, + ) as JwtPayload; + const baseUserId = decoded.userId; + const client = await clientPromise; + const db = client.db("linkle"); + const collection = db.collection("userdata"); + const result = await collection.updateOne( + { userId: baseUserId }, + { $set: { name, password, email } }, + ); + if (result.modifiedCount > 0) { + return NextResponse.json( + { message: "User information updated successfully" }, + { status: 200 }, + ); + } else { + return NextResponse.json( + { message: "No document matched or nothing to update" }, + { status: 404 }, + ); + } + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return NextResponse.json( + { message: "Failed to authenticate", error: errorMessage }, + { status: 500 }, + ); + } +} diff --git a/src/app/components/page/block-list.tsx b/src/app/components/page/block-list.tsx new file mode 100644 index 00000000..d19e14b8 --- /dev/null +++ b/src/app/components/page/block-list.tsx @@ -0,0 +1,94 @@ +import React, { Suspense, useEffect, useState } from "react"; +import { Block } from "@app/admin/page"; +import dynamic from "next/dynamic"; +import PreviewLink from "@app/admin/components/preview/components/preview-link"; +import PreviewText from "@app/admin/components/preview/components/preview-text"; +import CircleButton from "@app/admin/components/buttons/circle-button"; +import EmptyBlock from "@app/intro/components/UI/empty-block"; +import { usePathname } from "next/navigation"; +import { adminApiInstance } from "../../../utils/apis"; +const PreviewImage = dynamic( + () => import("@app/admin/components/preview/components/preview-image"), +); +const PreviewVideo = dynamic( + () => import("@app/admin/components/preview/components/preview-video"), +); +const PreviewDivider = dynamic( + () => import("@app/admin/components/preview/components/preview-divider"), +); +const PreviewCalendar = dynamic( + () => import("@app/admin/components/preview/components/preview-calendar"), +); +const PreviewEvent = dynamic( + () => import("@app/admin/components/preview/components/preview-event"), +); + +interface Props { + setIsOpen?: React.Dispatch>; +} +const BlockList = ({ setIsOpen }: Props) => { + const pathname = usePathname(); + const isAdmin = pathname.includes("admin"); + const [blocks, setBlocks] = useState([]); + + useEffect(() => { + getBlocks().then(); + }, []); + + async function getBlocks() { + const blockApis = await adminApiInstance; + const response = await blockApis.getBlocks(); + if (!response) return; + if (response.ok) { + const { data } = await response.json(); + setBlocks(data); + } else { + sessionStorage.removeItem("token"); + // alert("블록 조회 실패"); + } + } + + if (!blocks || blocks.length === 0) return ; + + const setComponentType = (block: Block) => { + const { type } = block; + return { + 1: , + 2: ( + Loading video...

    }> + +
    + ), + 3: , + 4: , + 5: , + 6: , + 7: , + }[type]; + }; + return ( + <> +
      + {blocks.map((block, index) => { + return ( +
    • + {setComponentType(block)} +
    • + ); + })} +
    + {isAdmin && ( +
    + setIsOpen && setIsOpen(false)} + /> +
    + )} + + ); +}; + +export default BlockList; diff --git a/src/app/components/Portal.tsx b/src/app/components/portal.tsx similarity index 100% rename from src/app/components/Portal.tsx rename to src/app/components/portal.tsx diff --git a/src/app/intro/components/UI/empty-block.tsx b/src/app/intro/components/UI/empty-block.tsx index e18a2c08..a627da6e 100644 --- a/src/app/intro/components/UI/empty-block.tsx +++ b/src/app/intro/components/UI/empty-block.tsx @@ -11,11 +11,11 @@ export default function EmptyBlock() { width={80} height={40} /> -

    지금 공개된 링크가 없다...

    +

    지금 공개된 링크가 없습니다

    - 소식받기 버튼을 눌러다오 + 소식받기 버튼을 눌러주세요

    -

    새로운 링크가 생기면 알려줌.,..

    +

    새로운 링크가 생기면 알려드리겠습니다

    ); diff --git a/src/app/intro/components/basicblock.tsx b/src/app/intro/components/basicblock.tsx index 98cc5b80..9ade950b 100644 --- a/src/app/intro/components/basicblock.tsx +++ b/src/app/intro/components/basicblock.tsx @@ -39,16 +39,10 @@ export default function BasicBlock({ sequence, style, title, - subText01, - subText02, url, imgUrl, dateStart, dateEnd, - openYn, - keepYn, - dateCreate, - dateUpdate, index, dragStart, dragEnter, @@ -127,25 +121,18 @@ export default function BasicBlock({ } async function deleteHandler() { - const token = sessionStorage.getItem("token"); - if (!token) { - alert("인증 토큰이 없습니다."); - return; - } + console.log(id); try { - const response = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/api/link/delete`, - { - method: "POST", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - id: id, - }), + const response = await fetch(`/api/link/delete`, { + credentials: "include", + method: "POST", + headers: { + "Content-Type": "application/json", }, - ); + body: JSON.stringify({ + id: id, + }), + }); if (!response.ok) { alert("삭제 실패"); } else { @@ -221,7 +208,10 @@ export default function BasicBlock({ {isAdmin ? (
    -