diff --git a/embedg-app/package-lock.json b/embedg-app/package-lock.json new file mode 100644 index 000000000..d3db17773 --- /dev/null +++ b/embedg-app/package-lock.json @@ -0,0 +1,3710 @@ +{ + "name": "embedg-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "embedg-app", + "version": "0.0.0", + "dependencies": { + "@codemirror/lang-json": "^6.0.1", + "@codemirror/lint": "^6.2.0", + "@discord/embedded-app-sdk": "^1.0.2", + "@emoji-mart/react": "^1.1.1", + "@formkit/auto-animate": "^1.0.0-beta.6", + "@heroicons/react": "^2.0.17", + "@openpanel/web": "^1.3.0", + "@types/debounce": "^1.2.1", + "@types/react-twemoji": "^0.4.1", + "@uiw/codemirror-theme-github": "^4.19.11", + "@uiw/react-codemirror": "^4.19.11", + "autoprefixer": "^10.4.14", + "clsx": "^1.2.1", + "cronstrue": "^2.47.0", + "date-fns": "^2.29.3", + "debounce": "^1.2.1", + "emoji-mart": "^5.5.2", + "highlight.js": "^11.7.0", + "immer": "^9.0.21", + "just-debounce-it": "^3.2.0", + "postcss": "^8.4.21", + "react": "^18.2.0", + "react-colorful": "^5.6.1", + "react-cron-generator": "^2.0.10", + "react-datetime-picker": "^5.2.0", + "react-dom": "^18.2.0", + "react-error-boundary": "^5.0.0", + "react-query": "^3.39.3", + "react-router-dom": "^6.10.0", + "react-textarea-autosize": "^8.4.1", + "react-twemoji": "^0.5.0", + "simple-markdown": "^0.7.3", + "tailwindcss": "^3.3.1", + "vaul": "^0.7.0", + "zod": "^3.21.4", + "zundo": "^2.1.0", + "zustand": "^4.3.7" + }, + "devDependencies": { + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@vitejs/plugin-react-swc": "^3.0.0", + "typescript": "^5.8.3", + "vite": "^4.2.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", + "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.4.2.tgz", + "integrity": "sha512-8WE2xp+D0MpWEv5lZ6zPW1/tf4AGb358T5GWYiKEuCP8MvFfT3tH2mIF9Y2yr2e3KbHuSvsVhosiEyqCpiJhZQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.6.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.2.tgz", + "integrity": "sha512-s9lPVW7TxXrI/7voZ+HmD/yiAlwAYn9PH5SUVSUhsxXHhv4yl5eZ3KLntSoTynfdgVYM0oIpccQEWRBQgmNZyw==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.2.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz", + "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz", + "integrity": "sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.2.0.tgz", + "integrity": "sha512-KVCECmR2fFeYBr1ZXDVue7x3q5PMI0PzcIbA+zKufnkniMBo1325t0h1jM85AKp8l3tj67LRxVpZfgDxEXlQkg==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.3.0.tgz", + "integrity": "sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.0.tgz", + "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==", + "license": "MIT" + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.1.tgz", + "integrity": "sha512-+CfzmScfJuD6uDF5bHJkAjWTQ2QAAHxODCPxUEgcImDYcJLT+4l5vLnBHmDVv46kCC5uUJGMrBJct2Z6JbvqyQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.9.3.tgz", + "integrity": "sha512-BJ5mvEIhFM+SrNwc5X8pLIvMM9ffjkviVbxpg84Xk2OE8ZyKaEbId8kX+nAYEEso7+qnbwsXe1bkAHsasebMow==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.1.4", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@discord/embedded-app-sdk": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discord/embedded-app-sdk/-/embedded-app-sdk-1.0.2.tgz", + "integrity": "sha512-ah4LgBdsyX3Y9n5qJtzVH6D0tH/xA/LM07eiTRY7SKp+VmSD5PTXuKOKCHV38Ld82u12zAhO8LxOJEc21nKptQ==", + "license": "MIT", + "dependencies": { + "@types/lodash.transform": "^4.6.6", + "@types/uuid": "^8.3.1", + "big-integer": "1.6.48", + "decimal.js-light": "2.5.0", + "eventemitter3": "^4.0.7", + "lodash.transform": "^4.6.0", + "rollup": "^4.8.0", + "uuid": "^8.3.2", + "zod": "^3.9.8" + } + }, + "node_modules/@discord/embedded-app-sdk/node_modules/rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/@discord/embedded-app-sdk/node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@emoji-mart/react": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emoji-mart/react/-/react-1.1.1.tgz", + "integrity": "sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g==", + "license": "MIT", + "peerDependencies": { + "emoji-mart": "^5.2", + "react": "^16.8 || ^17 || ^18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz", + "integrity": "sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@formkit/auto-animate": { + "version": "1.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-1.0.0-beta.6.tgz", + "integrity": "sha512-PVDhLAlr+B4Xb7e+1wozBUWmXa6BFU8xUPR/W/E+TsQhPS1qkAdAsJ25keEnFrcePSnXHrOsh3tiFbEToOzV9w==", + "license": "MIT" + }, + "node_modules/@heroicons/react": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.0.17.tgz", + "integrity": "sha512-90GMZktkA53YbNzHp6asVEDevUQCMtxWH+2UK2S8OpnLEu7qckTJPhNxNQG52xIR1WFTwFqtH6bt7a60ZNcLLA==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lezer/common": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", + "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==", + "license": "MIT" + }, + "node_modules/@lezer/highlight": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.4.tgz", + "integrity": "sha512-IECkFmw2l7sFcYXrV8iT9GeY4W0fU4CxX0WMwhmhMIVjoDdD1Hr6q3G2NqVtLg/yVe5n7i4menG3tJ2r4eCrPQ==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz", + "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==", + "license": "MIT", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.3.tgz", + "integrity": "sha512-JPQe3mwJlzEVqy67iQiiGozhcngbO8QBgpqZM6oL1Wj/dXckrEexpBLeFkq0edtW5IqnPRFxA24BHJni8Js69w==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@openpanel/sdk": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@openpanel/sdk/-/sdk-1.3.0.tgz", + "integrity": "sha512-VK/1oawBjGdxA+oYtqcWlNXlLT1zRJ9tslHoMvqqsqlcLNOhH26ltcHpyGp5RhtIF7uIkCltiicALfFN7fyldw==" + }, + "node_modules/@openpanel/web": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@openpanel/web/-/web-1.3.0.tgz", + "integrity": "sha512-geUPcn35oMqWlBS7rB4ejP6qzKGs4VDAZhoSw9MD3q/UYkD/pfTEx70z1ydGVJMjHREdXoAL1XVhBLdZmu1gsw==", + "dependencies": { + "@openpanel/sdk": "1.3.0", + "@rrweb/types": "2.0.0-alpha.20", + "rrweb": "2.0.0-alpha.20" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", + "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", + "integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz", + "integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz", + "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz", + "integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-escape-keydown": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz", + "integrity": "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz", + "integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz", + "integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz", + "integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz", + "integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz", + "integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", + "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", + "integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz", + "integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz", + "integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz", + "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@remix-run/router": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rrweb/types": { + "version": "2.0.0-alpha.20", + "resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.20.tgz", + "integrity": "sha512-RbnDgKxA/odwB1R4gF7eUUj+rdSrq6ROQJsnMw7MIsGzlbSYvJeZN8YY4XqU0G6sKJvXI6bSzk7w/G94jNwzhw==", + "license": "MIT" + }, + "node_modules/@rrweb/utils": { + "version": "2.0.0-alpha.20", + "resolved": "https://registry.npmjs.org/@rrweb/utils/-/utils-2.0.0-alpha.20.tgz", + "integrity": "sha512-MTQOmhPRe39C0fYaCnnVYOufQsyGzwNXpUStKiyFSfGLUJrzuwhbRoUAKR5w6W2j5XuA0bIz3ZDIBztkquOhLw==", + "license": "MIT" + }, + "node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/css-font-loading-module": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz", + "integrity": "sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==", + "license": "MIT" + }, + "node_modules/@types/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-epMsEE85fi4lfmJUH/89/iV/LI+F5CvNIvmgs5g5jYFPfhO2S/ae8WSsLOKWdwtoaZw9Q2IhJ4tQ5tFCcS/4HA==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "license": "MIT" + }, + "node_modules/@types/lodash.memoize": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/lodash.memoize/-/lodash.memoize-4.1.7.tgz", + "integrity": "sha512-lGN7WeO4vO6sICVpf041Q7BX/9k1Y24Zo3FY0aUezr1QlKznpjzsDk3T3wvH8ofYzoK0QupN9TWcFAFZlyPwQQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/lodash.transform": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/@types/lodash.transform/-/lodash.transform-4.6.9.tgz", + "integrity": "sha512-1iIn+l7Vrj8hsr2iZLtxRkcV9AtjTafIyxKO9DX2EEcdOgz3Op5dhwKQFhMJgdfIRbYHBUF+SU97Y6P+zyLXNg==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.0.32", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.32.tgz", + "integrity": "sha512-gYGXdtPQ9Cj0w2Fwqg5/ak6BcK3Z15YgjSqtyDizWUfx7mQ8drs0NBUzRRsAdoFVTO8kJ8L2TL8Skm7OFPnLUw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-twemoji": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/react-twemoji/-/react-twemoji-0.4.1.tgz", + "integrity": "sha512-7ASz6rMUlbotgNnuTzDM6WTHFusSwTAOIHCzgzBjxA6gIzNH9fux4twiV2gnNPPSeGAuw/OMK7rNW3hG9lAdYQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" + }, + "node_modules/@uiw/codemirror-extensions-basic-setup": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.19.11.tgz", + "integrity": "sha512-yT7DtFUZESyqyMm0kcMbT6dQ8TIK8tcA6XzMtkgLtsiB883rlc9kYVJScyDz8M9mCckycVbuFlhEdqN54PoiGw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "peerDependencies": { + "@codemirror/autocomplete": ">=6.0.0", + "@codemirror/commands": ">=6.0.0", + "@codemirror/language": ">=6.0.0", + "@codemirror/lint": ">=6.0.0", + "@codemirror/search": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, + "node_modules/@uiw/codemirror-theme-github": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-github/-/codemirror-theme-github-4.19.11.tgz", + "integrity": "sha512-tNhQ7ACy+GsUZltJ03ybWc/SJNEApMJGUPyXbuUFRh0cXKzoZDBllfvyvPjiCIu6Cs0icMwPfzpTIsijTaiGhA==", + "license": "MIT", + "dependencies": { + "@uiw/codemirror-themes": "4.19.11" + } + }, + "node_modules/@uiw/codemirror-themes": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.19.11.tgz", + "integrity": "sha512-4bh0vfkqeVJ7L2aGimKXqQtaoSEe/1xZb9nkGn35V5daHXkxRhb+BRFMOSrMsjGm74hM+dvYi5iH8HXVsvjJrQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "peerDependencies": { + "@codemirror/language": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, + "node_modules/@uiw/react-codemirror": { + "version": "4.19.11", + "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.19.11.tgz", + "integrity": "sha512-KoTMg0krVi8EgIPotMYAfTTB+9U4CrJe1ZeSLVR92Wif0pPjYLN5TQF0kqiiH97gJNGHVte/mUftmDjK7Sv2ZA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.6", + "@codemirror/commands": "^6.1.0", + "@codemirror/state": "^6.1.1", + "@codemirror/theme-one-dark": "^6.0.0", + "@uiw/codemirror-extensions-basic-setup": "4.19.11", + "codemirror": "^6.0.0" + }, + "peerDependencies": { + "@babel/runtime": ">=7.11.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/theme-one-dark": ">=6.0.0", + "@codemirror/view": ">=6.0.0", + "codemirror": ">=6.0.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.2.0.tgz", + "integrity": "sha512-IcBoXL/mcH7JdQr/nfDlDwTdIaH8Rg7LpfQDF4nAht+juHWIuv6WhpKPCSfY4+zztAaB07qdBoFz1XCZsgo3pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.3.35" + }, + "peerDependencies": { + "vite": "^4" + } + }, + "node_modules/@wojtekmaj/date-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.4.1.tgz", + "integrity": "sha512-Fjs0KJz0//0AmlJVFx9AQmWpmxOTw4foDo4DKoswWVVjHsna4rdu+fXwid5YHNgzv/wHi9AkZCRPmHWsf890lg==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/date-utils?sponsor=1" + } + }, + "node_modules/@xstate/fsm": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@xstate/fsm/-/fsm-1.6.5.tgz", + "integrity": "sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==", + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/aria-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz", + "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/broadcast-channel": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz", + "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.2", + "detect-node": "^2.1.0", + "js-sha3": "0.8.0", + "microseconds": "0.2.0", + "nano-time": "1.0.0", + "oblivious-set": "1.0.0", + "rimraf": "3.0.2", + "unload": "2.2.0" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/crelt": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", + "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==", + "license": "MIT" + }, + "node_modules/cronstrue": { + "version": "2.47.0", + "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.47.0.tgz", + "integrity": "sha512-fnFwJy7zslTEz6h7O7BkwgHNBvuuPmkhAYKqPDxK5mBQLz2nG08T9afbnjm+yrvcc/wxrd+otaVSnoXT9ulUOw==", + "license": "MIT", + "bin": { + "cronstrue": "bin/cli.js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "license": "MIT" + }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "license": "MIT", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "license": "MIT" + }, + "node_modules/decimal.js-light": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.0.tgz", + "integrity": "sha512-b3VJCbd2hwUpeRGG3Toob+CRo8W22xplipNhP3tN7TSVB/cyMX71P1vM2Xjc9H74uV6dS2hDDmo/rHq8L87Upg==", + "license": "MIT" + }, + "node_modules/detect-element-overflow": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/detect-element-overflow/-/detect-element-overflow-1.4.1.tgz", + "integrity": "sha512-6a1wXl5+KbnXhO5FWgKq+omp8km42QLWgd1UYj99SS6o/aYBuTPU/ByI9dLgPYi9aes5TAg62IRoRKpqrDb0PQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/detect-element-overflow?sponsor=1" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT" + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.348", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.348.tgz", + "integrity": "sha512-gM7TdwuG3amns/1rlgxMbeeyNoBFPa+4Uu0c7FeROWh4qWmvSOnvcslKmWy51ggLKZ2n/F/4i2HJ+PVNxH9uCQ==", + "license": "ISC" + }, + "node_modules/emoji-mart": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-5.5.2.tgz", + "integrity": "sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A==", + "license": "MIT" + }, + "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" + }, + "node_modules/esbuild": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.15.tgz", + "integrity": "sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.15", + "@esbuild/android-arm64": "0.17.15", + "@esbuild/android-x64": "0.17.15", + "@esbuild/darwin-arm64": "0.17.15", + "@esbuild/darwin-x64": "0.17.15", + "@esbuild/freebsd-arm64": "0.17.15", + "@esbuild/freebsd-x64": "0.17.15", + "@esbuild/linux-arm": "0.17.15", + "@esbuild/linux-arm64": "0.17.15", + "@esbuild/linux-ia32": "0.17.15", + "@esbuild/linux-loong64": "0.17.15", + "@esbuild/linux-mips64el": "0.17.15", + "@esbuild/linux-ppc64": "0.17.15", + "@esbuild/linux-riscv64": "0.17.15", + "@esbuild/linux-s390x": "0.17.15", + "@esbuild/linux-x64": "0.17.15", + "@esbuild/netbsd-x64": "0.17.15", + "@esbuild/openbsd-x64": "0.17.15", + "@esbuild/sunos-x64": "0.17.15", + "@esbuild/win32-arm64": "0.17.15", + "@esbuild/win32-ia32": "0.17.15", + "@esbuild/win32-x64": "0.17.15" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-extra/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "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==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-user-locale": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-2.3.0.tgz", + "integrity": "sha512-I3rQvAUwu2nauRD9YyQBSXVFJZixNouwA+eZld51Sn4Pn0N1qFbgcgOi/nPigJPQlNY519mT95fiSPRgflQiTA==", + "license": "MIT", + "dependencies": { + "@types/lodash.memoize": "^4.1.7", + "lodash.memoize": "^4.1.1" + }, + "funding": { + "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz", + "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-5.0.0.tgz", + "integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==", + "license": "MIT", + "dependencies": { + "universalify": "^0.1.2" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-debounce-it": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/just-debounce-it/-/just-debounce-it-3.2.0.tgz", + "integrity": "sha512-WXzwLL0745uNuedrCsCs3rpmfD6DBaf7uuVwaq98/8dafURfgQaBsSpjiPp5+CW6Vjltwy9cOGI6qE71b3T8iQ==", + "license": "MIT" + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" + }, + "node_modules/lodash.transform": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz", + "integrity": "sha512-LO37ZnhmBVx0GvOU/caQuipEh4GN82TcWv3yHlebGDgOxbxiwwzW5Pcx2AcvpIv2WmvmSMoC492yQFNhy/l/UQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/make-event-props": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.1.tgz", + "integrity": "sha512-JhvWq/iz1BvlmnPvLJjXv+xnMPJZuychrDC68V+yCGQJn5chcA8rLGKo5EP1XwIKVrigSXKLmbeXAGkf36wdCQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" + } + }, + "node_modules/match-sorter": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.1.tgz", + "integrity": "sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "remove-accents": "0.4.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/microseconds": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz", + "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nano-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz", + "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==", + "license": "ISC", + "dependencies": { + "big-integer": "^1.6.16" + } + }, + "node_modules/nano-time/node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/oblivious-set": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz", + "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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" + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-calendar": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-4.3.0.tgz", + "integrity": "sha512-TyCv8NbXnqXADyXNtMG0szkGvJNH3NG/WMTEE2q6g3RqAsFNyHwYbQD5Kvb6jRV/CqO0WB+oMCtkxblprdeT5A==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^1.2.1", + "get-user-locale": "^2.2.1", + "prop-types": "^15.6.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-calendar?sponsor=1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-clock": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/react-clock/-/react-clock-4.2.0.tgz", + "integrity": "sha512-H/700hJPu34ADDGH3fCjY6+4aTwvuVOhvpiOPrl2K67kwxa6npe2UNdO7nwayrTiGtZfgn2j2x2KRsn9TIHv1g==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@wojtekmaj/date-utils": "^1.1.2", + "clsx": "^1.2.1", + "get-user-locale": "^2.2.1", + "prop-types": "^15.6.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-clock?sponsor=1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-cron-generator": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/react-cron-generator/-/react-cron-generator-2.0.10.tgz", + "integrity": "sha512-N2KaRCcbWWJdgjP/3SkEEMPaAw9LRV8i3UHBL00WXi/uP3ePVU5StkhiCX91L2tJ47kBeTSX6J0HCL10aV1rlw==", + "license": "ISC", + "dependencies": { + "cronstrue": "^2.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-date-picker": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/react-date-picker/-/react-date-picker-10.2.0.tgz", + "integrity": "sha512-AapiakQ9hY2sPNyaBgLJgPDXeeZyiC3Px75jWbkB9NwJqX1gAwRQ7O8qshRqGWJX7T4/cUh6n59j+N+M4GpGow==", + "license": "MIT", + "dependencies": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^1.2.1", + "get-user-locale": "^2.2.1", + "make-event-props": "^1.4.2", + "prop-types": "^15.6.0", + "react-calendar": "^4.2.1", + "react-fit": "^1.5.1", + "update-input-width": "^1.3.1" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-date-picker?sponsor=1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-datetime-picker": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-datetime-picker/-/react-datetime-picker-5.2.0.tgz", + "integrity": "sha512-jSoDDw2EMn1qgnUVi7NS8uOuE82yMPwf+JwsOTM0aJMZW0cXyFIwffM6phsB2Hox80Oc8vNcVtFCTeH30w3qsg==", + "license": "MIT", + "dependencies": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^1.2.1", + "get-user-locale": "^2.2.1", + "make-event-props": "^1.4.2", + "prop-types": "^15.6.0", + "react-calendar": "^4.2.1", + "react-clock": "^4.2.0", + "react-date-picker": "^10.0.0", + "react-fit": "^1.5.1", + "react-time-picker": "^6.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-datetime-picker?sponsor=1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-error-boundary": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-5.0.0.tgz", + "integrity": "sha512-tnjAxG+IkpLephNcePNA7v6F/QpWLH8He65+DmedchDwg162JZqx4NmbXj0mlAYVVEd81OW7aFhmbsScYfiAFQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, + "node_modules/react-fit": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/react-fit/-/react-fit-1.5.1.tgz", + "integrity": "sha512-r86m/6GuJa7j6dLYjC7kENBQRBaDMLTU0mBBoqnh42d/Iil9rmWEeOtdB2KEQEUyDQ8rZXojIx8u+gNFJ+9y1w==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "detect-element-overflow": "^1.3.1", + "prop-types": "^15.6.0", + "tiny-warning": "^1.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-fit?sponsor=1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-fit/node_modules/@types/react-dom": { + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.6.tgz", + "integrity": "sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-query": { + "version": "3.39.3", + "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz", + "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "broadcast-channel": "^3.4.1", + "match-sorter": "^6.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", + "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.3", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz", + "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.5.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.1.tgz", + "integrity": "sha512-aD2C+qK6QypknC+lCMzteOdIjoMbNlgSFmJjCV+DrfTPwp59i/it9mMNf2HDzvRjQgKAyBDPyLJhcrzElf2U4Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-time-picker": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/react-time-picker/-/react-time-picker-6.2.0.tgz", + "integrity": "sha512-MMedSF9mTcrL7tjXJSrXaKTb7bwnw/xWlvgC6mB+CPW93KZ8RH8Xek75Ntk7LhCVdFZMVcuW9kssLd+B4Jrg+Q==", + "license": "MIT", + "dependencies": { + "@wojtekmaj/date-utils": "^1.1.3", + "clsx": "^1.2.1", + "get-user-locale": "^2.2.1", + "make-event-props": "^1.4.2", + "prop-types": "^15.6.0", + "react-clock": "^4.2.0", + "react-fit": "^1.5.1", + "update-input-width": "^1.3.1" + }, + "funding": { + "url": "https://github.com/wojtekmaj/react-time-picker?sponsor=1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-twemoji": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/react-twemoji/-/react-twemoji-0.5.0.tgz", + "integrity": "sha512-xz3NLWTFCfWOmPd559jcFX4f976ORIPpL9SwdBQO5BZwIYD1U1vpbY2E6k2vwPCVH78s2m1GbG5jpHKGUPZ+gw==", + "license": "MIT", + "dependencies": { + "lodash.isequal": "^4.5.0", + "prop-types": "^15.7.2", + "twemoji": "14.0.1" + }, + "engines": { + "node": ">=5.0" + }, + "peerDependencies": { + "react": ">=16.4.2" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "license": "MIT" + }, + "node_modules/remove-accents": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz", + "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/rollup": { + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.2.tgz", + "integrity": "sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rrdom": { + "version": "2.0.0-alpha.20", + "resolved": "https://registry.npmjs.org/rrdom/-/rrdom-2.0.0-alpha.20.tgz", + "integrity": "sha512-hoqjS4662LtBp82qEz9GrqU36UpEmCvTA2Hns3qdF7cklLFFy3G+0Th8hLytJENleHHWxsB5nWJ3eXz5mSRxdQ==", + "license": "MIT", + "dependencies": { + "rrweb-snapshot": "^2.0.0-alpha.20" + } + }, + "node_modules/rrweb": { + "version": "2.0.0-alpha.20", + "resolved": "https://registry.npmjs.org/rrweb/-/rrweb-2.0.0-alpha.20.tgz", + "integrity": "sha512-CZKDlm+j1VA50Ko3gnMbpvguCAleljsTNXPnVk9aeNP8o6T6kolRbISHyDZpqZ4G+bdDLlQOignPP3jEsXs8Gg==", + "license": "MIT", + "dependencies": { + "@rrweb/types": "^2.0.0-alpha.20", + "@rrweb/utils": "^2.0.0-alpha.20", + "@types/css-font-loading-module": "0.0.7", + "@xstate/fsm": "^1.4.0", + "base64-arraybuffer": "^1.0.1", + "mitt": "^3.0.0", + "rrdom": "^2.0.0-alpha.20", + "rrweb-snapshot": "^2.0.0-alpha.20" + } + }, + "node_modules/rrweb-snapshot": { + "version": "2.0.0-alpha.20", + "resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-2.0.0-alpha.20.tgz", + "integrity": "sha512-YTNf9YVeaGRo/jxY3FKBge2c/Ojd/KTHmuWloUSB+oyPXuY73ZeeG873qMMmhIpqEn7hn7aBF1eWEQmP7wjf8A==", + "license": "MIT", + "dependencies": { + "postcss": "^8.4.38" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-markdown": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/simple-markdown/-/simple-markdown-0.7.3.tgz", + "integrity": "sha512-uGXIc13NGpqfPeFJIt/7SHHxd6HekEJYtsdoCM06mEBPL9fQH/pSD7LRM6PZ7CKchpSvxKL4tvwMamqAaNDAyg==", + "license": "MIT", + "dependencies": { + "@types/react": ">=16.0.0" + } + }, + "node_modules/simple-markdown/node_modules/@types/react": { + "version": "18.0.33", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.33.tgz", + "integrity": "sha512-sHxzVxeanvQyQ1lr8NSHaj0kDzcNiGpILEVt69g9S31/7PfMvNCKLKcsHw4lYKjs3cGNJjXSP4mYzX43QlnjNA==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "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", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/style-mod": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.2.tgz", + "integrity": "sha512-C4myMmRTO8iaC5Gg+N1ftK2WT4eXUTMAa+HEFPPrfVeO/NtqLTtAmV1HbqnuGtLwCek44Ra76fdGUkSqjiMPcQ==", + "license": "MIT" + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/tailwindcss/node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, + "node_modules/twemoji": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/twemoji/-/twemoji-14.0.1.tgz", + "integrity": "sha512-eoqhea0sUhmC10iTacksyp1v9O4BP1jKmVqtK+Nztw40/dzawSHkXL3/xCpyh+mukmEvJ0Gw9VLvwZfQ9HKXDw==", + "license": [ + "MIT", + "CC-BY-4.0" + ], + "dependencies": { + "fs-extra": "^8.0.1", + "jsonfile": "^5.0.0", + "twemoji-parser": "14.0.0", + "universalify": "^0.1.2" + } + }, + "node_modules/twemoji-parser": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/twemoji-parser/-/twemoji-parser-14.0.0.tgz", + "integrity": "sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unload": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz", + "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.6.2", + "detect-node": "^2.0.4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-input-width": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/update-input-width/-/update-input-width-1.4.1.tgz", + "integrity": "sha512-/FDlfTvxlEQ9+/duf5PoC1q0uYQd/nE4w7K7rVAAoW/QKKa4bdhccuPaWtfkrWEy2r08rzX6wlmCHeGL+vgJOw==", + "license": "MIT", + "funding": { + "url": "https://github.com/wojtekmaj/update-input-width?sponsor=1" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz", + "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-composed-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz", + "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz", + "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==", + "license": "MIT", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.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==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vaul": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-0.7.0.tgz", + "integrity": "sha512-qhn8oEqvoisxLsebjyatO555DZAnCyRk0+zZlYPOOlUAs8+LWjFCRYg5KjYzVlQiAU/bkwsOqr1YVHztY08H9w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.0.4" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.17.5", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.18.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", + "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "license": "ISC", + "engines": { + "node": ">= 14" + } + }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zundo": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/zundo/-/zundo-2.1.0.tgz", + "integrity": "sha512-IMhYXDZWbyGu/p3rQb1d3orhCfAyi9hGkx6N579ZtO7mWrzvBdNyGEcxciv1jtIYPKBqLSAgzKqjLguau09f9g==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/charkour" + }, + "peerDependencies": { + "zustand": "^4.3.0" + }, + "peerDependenciesMeta": { + "zustand": { + "optional": false + } + } + }, + "node_modules/zustand": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.7.tgz", + "integrity": "sha512-dY8ERwB9Nd21ellgkBZFhudER8KVlelZm8388B5nDAXhO/+FZDhYMuRnqDgu5SYyRgz/iaf8RKnbUs/cHfOGlQ==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/embedg-app/package.json b/embedg-app/package.json index 5f97fd6d0..0b1526aa5 100644 --- a/embedg-app/package.json +++ b/embedg-app/package.json @@ -15,6 +15,7 @@ "@emoji-mart/react": "^1.1.1", "@formkit/auto-animate": "^1.0.0-beta.6", "@heroicons/react": "^2.0.17", + "@openpanel/web": "^1.3.0", "@types/debounce": "^1.2.1", "@types/react-twemoji": "^0.4.1", "@uiw/codemirror-theme-github": "^4.19.11", diff --git a/embedg-app/src/components/AnalyticsProvider.tsx b/embedg-app/src/components/AnalyticsProvider.tsx new file mode 100644 index 000000000..10a623e18 --- /dev/null +++ b/embedg-app/src/components/AnalyticsProvider.tsx @@ -0,0 +1,27 @@ +import { OpenPanel } from "@openpanel/web"; +import { useEffect } from "react"; +import { useUserQuery } from "../api/queries"; + +export const op = new OpenPanel({ + clientId: "f4dd2f20-2d9f-4ff5-9486-6d88b5326fc7", + apiUrl: "https://analytics.vaven.io/api", + trackScreenViews: true, + trackOutgoingLinks: true, +}); + +export default function AnalyticsProvider() { + const { data } = useUserQuery(); + + const user = data?.success ? data.data : null; + + useEffect(() => { + if (user?.id) { + op.identify({ + profileId: user.id, + firstName: user.name, + }); + } + }, [user?.id, op.identify]); + + return null; +} diff --git a/embedg-app/src/components/ChannelSelect.tsx b/embedg-app/src/components/ChannelSelect.tsx index 67e6502d7..7973fd780 100644 --- a/embedg-app/src/components/ChannelSelect.tsx +++ b/embedg-app/src/components/ChannelSelect.tsx @@ -1,11 +1,13 @@ import { + ArrowPathIcon, ChatBubbleLeftRightIcon, ChevronDownIcon, } from "@heroicons/react/24/outline"; import clsx from "clsx"; -import { useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useGuildChannelsQuery } from "../api/queries"; import ClickOutsideHandler from "./ClickOutsideHandler"; +import { useToasts } from "../util/toasts"; interface Props { guildId: string | null; @@ -27,6 +29,7 @@ function canSelectChannelType(type: number) { export function ChannelSelect({ guildId, channelId, onChange }: Props) { const { data } = useGuildChannelsQuery(guildId); + const toast = useToasts((state) => state.create); const inputRef = useRef(null); @@ -48,6 +51,16 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) { setOpen(false); } + useEffect(() => { + if (data?.success === false) { + toast({ + title: "Failed to load channels", + message: data.error.message, + type: "error", + }); + } + }, [data]); + const channels = useMemo(() => { const rawChannels = data?.success ? data.data : []; @@ -56,6 +69,7 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) { a.position === b.position && a.type === 4 ? 1 : a.position - b.position ); + const added = new Set(); const res = []; // This is really inefficient but it should be fine because there are never more than 500 channels @@ -70,6 +84,7 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) { rootChannel.type === 15 ) { // text, category, announcement, stage, forum + added.add(rootChannel.id); res.push({ ...rootChannel, level: 0, @@ -93,6 +108,7 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) { childChannel.type === 15 ) { // text, announcement, announcement thread, text thread, stage, forum + added.add(childChannel.id); res.push({ ...childChannel, level: 1, @@ -112,6 +128,7 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) { childThread.type === 12 ) { // announcement thread, text thread + added.add(childThread.id); res.push({ ...childThread, level: 2, @@ -125,6 +142,18 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) { } } + for (const channel of rawChannels) { + if (added.has(channel.id)) continue; + res.push({ + ...channel, + level: 2, + canSelect: + channel.user_access && + channel.bot_access && + canSelectChannelType(channel.type), + }); + } + return res; }, [data]); @@ -159,7 +188,12 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) { )} />
- {channel ? ( + {!data ? ( +
+ +
Loading...
+
+ ) : channel ? (
{channel.type === 15 ? ( diff --git a/embedg-app/src/components/GuildSelect.tsx b/embedg-app/src/components/GuildSelect.tsx index a1af722ea..f73a492cc 100644 --- a/embedg-app/src/components/GuildSelect.tsx +++ b/embedg-app/src/components/GuildSelect.tsx @@ -4,6 +4,8 @@ import { useEffect, useMemo, useState } from "react"; import { useGuildsQuery } from "../api/queries"; import { guildIconUrl } from "../discord/cdn"; import ClickOutsideHandler from "./ClickOutsideHandler"; +import { useToasts } from "../util/toasts"; +import { ArrowPathIcon } from "@heroicons/react/24/outline"; interface Props { guildId: string | null; @@ -12,6 +14,17 @@ interface Props { export default function GuildSelect({ guildId, onChange }: Props) { const { data: guilds, isLoading } = useGuildsQuery(); + const toast = useToasts((state) => state.create); + + useEffect(() => { + if (guilds?.success === false) { + toast({ + title: "Failed to load guilds", + message: guilds.error.message, + type: "error", + }); + } + }, [guilds]); const guild = useMemo( () => guilds?.success && guilds.data.find((g) => g.id === guildId), @@ -56,7 +69,12 @@ export default function GuildSelect({ guildId, onChange }: Props) { role="button" className="flex-auto" > - {guild ? ( + {!guilds ? ( +
+ +
Loading...
+
+ ) : guild ? (
+ diff --git a/embedg-app/yarn.lock b/embedg-app/yarn.lock index bafccfc3f..6f99d8db5 100644 --- a/embedg-app/yarn.lock +++ b/embedg-app/yarn.lock @@ -116,116 +116,11 @@ resolved "https://registry.npmjs.org/@emoji-mart/react/-/react-1.1.1.tgz" integrity sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g== -"@esbuild/android-arm64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.15.tgz#893ad71f3920ccb919e1757c387756a9bca2ef42" - integrity sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA== - -"@esbuild/android-arm@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.15.tgz#143e0d4e4c08c786ea410b9a7739779a9a1315d8" - integrity sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg== - -"@esbuild/android-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.15.tgz#d2d12a7676b2589864281b2274355200916540bc" - integrity sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ== - "@esbuild/darwin-arm64@0.17.15": version "0.17.15" resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz" integrity sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA== -"@esbuild/darwin-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.15.tgz#9384e64c0be91388c57be6d3a5eaf1c32a99c91d" - integrity sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg== - -"@esbuild/freebsd-arm64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.15.tgz#2ad5a35bc52ebd9ca6b845dbc59ba39647a93c1a" - integrity sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg== - -"@esbuild/freebsd-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.15.tgz#b513a48446f96c75fda5bef470e64d342d4379cd" - integrity sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ== - -"@esbuild/linux-arm64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.15.tgz#9697b168175bfd41fa9cc4a72dd0d48f24715f31" - integrity sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA== - -"@esbuild/linux-arm@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.15.tgz#5b22062c54f48cd92fab9ffd993732a52db70cd3" - integrity sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw== - -"@esbuild/linux-ia32@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.15.tgz#eb28a13f9b60b5189fcc9e98e1024f6b657ba54c" - integrity sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q== - -"@esbuild/linux-loong64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.15.tgz#32454bdfe144cf74b77895a8ad21a15cb81cfbe5" - integrity sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ== - -"@esbuild/linux-mips64el@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.15.tgz#af12bde0d775a318fad90eb13a0455229a63987c" - integrity sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ== - -"@esbuild/linux-ppc64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.15.tgz#34c5ed145b2dfc493d3e652abac8bd3baa3865a5" - integrity sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg== - -"@esbuild/linux-riscv64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.15.tgz#87bd515e837f2eb004b45f9e6a94dc5b93f22b92" - integrity sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA== - -"@esbuild/linux-s390x@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.15.tgz#20bf7947197f199ddac2ec412029a414ceae3aa3" - integrity sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg== - -"@esbuild/linux-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.15.tgz#31b93f9c94c195e852c20cd3d1914a68aa619124" - integrity sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg== - -"@esbuild/netbsd-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.15.tgz#8da299b3ac6875836ca8cdc1925826498069ac65" - integrity sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA== - -"@esbuild/openbsd-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.15.tgz#04a1ec3d4e919714dba68dcf09eeb1228ad0d20c" - integrity sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w== - -"@esbuild/sunos-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.15.tgz#6694ebe4e16e5cd7dab6505ff7c28f9c1c695ce5" - integrity sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ== - -"@esbuild/win32-arm64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.15.tgz#1f95b2564193c8d1fee8f8129a0609728171d500" - integrity sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q== - -"@esbuild/win32-ia32@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.15.tgz#c362b88b3df21916ed7bcf75c6d09c6bf3ae354a" - integrity sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w== - -"@esbuild/win32-x64@0.17.15": - version "0.17.15" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.15.tgz#c2e737f3a201ebff8e2ac2b8e9f246b397ad19b8" - integrity sha512-DjDa9ywLUUmjhV2Y9wUTIF+1XsmuFGvZoCmOWkli1XcNAh5t25cc7fgsCx4Zi/Uurep3TTLyDiKATgGEg61pkA== - "@formkit/auto-animate@^1.0.0-beta.6": version "1.0.0-beta.6" resolved "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-1.0.0-beta.6.tgz" @@ -315,7 +210,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -328,6 +223,20 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@openpanel/sdk@1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@openpanel/sdk/-/sdk-1.3.0.tgz" + integrity sha512-VK/1oawBjGdxA+oYtqcWlNXlLT1zRJ9tslHoMvqqsqlcLNOhH26ltcHpyGp5RhtIF7uIkCltiicALfFN7fyldw== + +"@openpanel/web@^1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@openpanel/web/-/web-1.3.0.tgz" + integrity sha512-geUPcn35oMqWlBS7rB4ejP6qzKGs4VDAZhoSw9MD3q/UYkD/pfTEx70z1ydGVJMjHREdXoAL1XVhBLdZmu1gsw== + dependencies: + "@openpanel/sdk" "1.3.0" + "@rrweb/types" "2.0.0-alpha.20" + rrweb "2.0.0-alpha.20" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" @@ -480,121 +389,26 @@ resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz" integrity sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg== -"@rollup/rollup-android-arm-eabi@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz#b98786c1304b4ff8db3a873180b778649b5dff2b" - integrity sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg== - -"@rollup/rollup-android-arm64@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz#8833679af11172b1bf1ab7cb3bad84df4caf0c9e" - integrity sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q== - "@rollup/rollup-darwin-arm64@4.13.0": version "4.13.0" resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz" integrity sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g== -"@rollup/rollup-darwin-x64@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz#3ce5b9bcf92b3341a5c1c58a3e6bcce0ea9e7455" - integrity sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg== - -"@rollup/rollup-linux-arm-gnueabihf@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz#3d3d2c018bdd8e037c6bfedd52acfff1c97e4be4" - integrity sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ== - -"@rollup/rollup-linux-arm64-gnu@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz#5fc8cc978ff396eaa136d7bfe05b5b9138064143" - integrity sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w== - -"@rollup/rollup-linux-arm64-musl@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz#f2ae7d7bed416ffa26d6b948ac5772b520700eef" - integrity sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw== - -"@rollup/rollup-linux-riscv64-gnu@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz#303d57a328ee9a50c85385936f31cf62306d30b6" - integrity sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA== - -"@rollup/rollup-linux-x64-gnu@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz#f672f6508f090fc73f08ba40ff76c20b57424778" - integrity sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA== - -"@rollup/rollup-linux-x64-musl@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz#d2f34b1b157f3e7f13925bca3288192a66755a89" - integrity sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw== - -"@rollup/rollup-win32-arm64-msvc@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz#8ffecc980ae4d9899eb2f9c4ae471a8d58d2da6b" - integrity sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA== - -"@rollup/rollup-win32-ia32-msvc@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz#a7505884f415662e088365b9218b2b03a88fc6f2" - integrity sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw== +"@rrweb/types@^2.0.0-alpha.20", "@rrweb/types@2.0.0-alpha.20": + version "2.0.0-alpha.20" + resolved "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.20.tgz" + integrity sha512-RbnDgKxA/odwB1R4gF7eUUj+rdSrq6ROQJsnMw7MIsGzlbSYvJeZN8YY4XqU0G6sKJvXI6bSzk7w/G94jNwzhw== -"@rollup/rollup-win32-x64-msvc@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz#6abd79db7ff8d01a58865ba20a63cfd23d9e2a10" - integrity sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw== +"@rrweb/utils@^2.0.0-alpha.20": + version "2.0.0-alpha.20" + resolved "https://registry.npmjs.org/@rrweb/utils/-/utils-2.0.0-alpha.20.tgz" + integrity sha512-MTQOmhPRe39C0fYaCnnVYOufQsyGzwNXpUStKiyFSfGLUJrzuwhbRoUAKR5w6W2j5XuA0bIz3ZDIBztkquOhLw== "@swc/core-darwin-arm64@1.3.44": version "1.3.44" resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz" integrity sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g== -"@swc/core-darwin-x64@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz#a8de4c176a9b12f201fc754a56331113a53ec69c" - integrity sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg== - -"@swc/core-linux-arm-gnueabihf@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz#300731367c88bf02b8ae20264d4d402362e444df" - integrity sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg== - -"@swc/core-linux-arm64-gnu@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz#8b52d1cd28f277d47bb45c6791f44da568a62bc4" - integrity sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g== - -"@swc/core-linux-arm64-musl@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz#7b0e62255ae13c397f09ca5da8bf2266482a28c2" - integrity sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw== - -"@swc/core-linux-x64-gnu@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz#0b8b2544c312f247aa5c5f31671a175ad6488309" - integrity sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg== - -"@swc/core-linux-x64-musl@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz#5b1f76fc1dc75875df59d8c0ff37e99e030f9552" - integrity sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ== - -"@swc/core-win32-arm64-msvc@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz#bd4aefcd7734229f780c9bec0502935884935f0f" - integrity sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ== - -"@swc/core-win32-ia32-msvc@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz#0c2ba768f33acb580422e17d4ae816ebfd3dcfe0" - integrity sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA== - -"@swc/core-win32-x64-msvc@1.3.44": - version "1.3.44" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz#b137abefbeb3b73a47cc398bc5603ea6bf6a3a7b" - integrity sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w== - "@swc/core@^1.3.35": version "1.3.44" resolved "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz" @@ -611,6 +425,11 @@ "@swc/core-win32-ia32-msvc" "1.3.44" "@swc/core-win32-x64-msvc" "1.3.44" +"@types/css-font-loading-module@0.0.7": + version "0.0.7" + resolved "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz" + integrity sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q== + "@types/debounce@^1.2.1": version "1.2.1" resolved "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.1.tgz" @@ -747,6 +566,11 @@ resolved "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.4.1.tgz" integrity sha512-Fjs0KJz0//0AmlJVFx9AQmWpmxOTw4foDo4DKoswWVVjHsna4rdu+fXwid5YHNgzv/wHi9AkZCRPmHWsf890lg== +"@xstate/fsm@^1.4.0": + version "1.6.5" + resolved "https://registry.npmjs.org/@xstate/fsm/-/fsm-1.6.5.tgz" + integrity sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -811,16 +635,21 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -big-integer@1.6.48: - version "1.6.48" - resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz" - integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== +base64-arraybuffer@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz" + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== big-integer@^1.6.16: version "1.6.51" resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== +big-integer@1.6.48: + version "1.6.48" + resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz" + integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" @@ -1401,6 +1230,11 @@ minimatch@^9.0.1: resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== +mitt@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz" + integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== + mz@^2.7.0: version "2.7.0" resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" @@ -1417,10 +1251,10 @@ nano-time@1.0.0: dependencies: big-integer "^1.6.16" -nanoid@^3.3.4, nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== node-releases@^2.0.8: version "2.0.10" @@ -1482,10 +1316,10 @@ path-scurry@^1.10.1: lru-cache "^9.1.1 || ^10.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" @@ -1546,23 +1380,14 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.21: - version "8.4.21" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz" - integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== - dependencies: - nanoid "^3.3.4" - picocolors "^1.0.0" - source-map-js "^1.0.2" - -postcss@^8.4.23: - version "8.4.33" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz" - integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg== +postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.38: + version "8.5.8" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz" + integrity sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg== dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.0.2" + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" prop-types@^15.6.0, prop-types@^15.7.2: version "15.8.1" @@ -1652,7 +1477,7 @@ react-dom@^18.2.0: react-error-boundary@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-5.0.0.tgz#6b6c7e075c922afb0283147e5b084efa44e68570" + resolved "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-5.0.0.tgz" integrity sha512-tnjAxG+IkpLephNcePNA7v6F/QpWLH8He65+DmedchDwg162JZqx4NmbXj0mlAYVVEd81OW7aFhmbsScYfiAFQ== dependencies: "@babel/runtime" "^7.12.5" @@ -1838,6 +1663,34 @@ rollup@^4.8.0: "@rollup/rollup-win32-x64-msvc" "4.13.0" fsevents "~2.3.2" +rrdom@^2.0.0-alpha.20: + version "2.0.0-alpha.20" + resolved "https://registry.npmjs.org/rrdom/-/rrdom-2.0.0-alpha.20.tgz" + integrity sha512-hoqjS4662LtBp82qEz9GrqU36UpEmCvTA2Hns3qdF7cklLFFy3G+0Th8hLytJENleHHWxsB5nWJ3eXz5mSRxdQ== + dependencies: + rrweb-snapshot "^2.0.0-alpha.20" + +rrweb-snapshot@^2.0.0-alpha.20: + version "2.0.0-alpha.20" + resolved "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-2.0.0-alpha.20.tgz" + integrity sha512-YTNf9YVeaGRo/jxY3FKBge2c/Ojd/KTHmuWloUSB+oyPXuY73ZeeG873qMMmhIpqEn7hn7aBF1eWEQmP7wjf8A== + dependencies: + postcss "^8.4.38" + +rrweb@2.0.0-alpha.20: + version "2.0.0-alpha.20" + resolved "https://registry.npmjs.org/rrweb/-/rrweb-2.0.0-alpha.20.tgz" + integrity sha512-CZKDlm+j1VA50Ko3gnMbpvguCAleljsTNXPnVk9aeNP8o6T6kolRbISHyDZpqZ4G+bdDLlQOignPP3jEsXs8Gg== + dependencies: + "@rrweb/types" "^2.0.0-alpha.20" + "@rrweb/utils" "^2.0.0-alpha.20" + "@types/css-font-loading-module" "0.0.7" + "@xstate/fsm" "^1.4.0" + base64-arraybuffer "^1.0.1" + mitt "^3.0.0" + rrdom "^2.0.0-alpha.20" + rrweb-snapshot "^2.0.0-alpha.20" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -1876,13 +1729,21 @@ simple-markdown@^0.7.3: dependencies: "@types/react" ">=16.0.0" -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: - name string-width-cjs +string-width@^4.1.0: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -1900,8 +1761,14 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: - name strip-ansi-cjs +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== diff --git a/embedg-server/api/handlers/images/handler.go b/embedg-server/api/handlers/images/handler.go index d414086fc..ac2c35ae0 100644 --- a/embedg-server/api/handlers/images/handler.go +++ b/embedg-server/api/handlers/images/handler.go @@ -21,8 +21,6 @@ import ( "gopkg.in/guregu/null.v4" ) -var appPublicURL *url.URL - type ImagesHandler struct { pg *postgres.PostgresStore am *access.AccessManager diff --git a/embedg-server/bot/listeners.go b/embedg-server/bot/listeners.go index 7237b2e86..db0b54082 100644 --- a/embedg-server/bot/listeners.go +++ b/embedg-server/bot/listeners.go @@ -62,6 +62,7 @@ func (b *Bot) onInteractionCreate(_ *discordgo.Session, i *discordgo.Interaction } func (b *Bot) onRawEvent(_ *discordgo.Session, e *discordgo.Event) { + // TODO: discordgo.Event is no longer dispatched when using Stateway, so we need to handle entitlements differently. if e.Type == "ENTITLEMENT_CREATE" || e.Type == "ENTITLEMENT_UPDATE" || e.Type == "ENTITLEMENT_DELETE" { entitlement := &Entitlement{} err := json.Unmarshal(e.RawData, entitlement) diff --git a/embedg-server/entry/database/backup.go b/embedg-server/entry/database/backup.go index 9bf6aa75c..d2bedcbf3 100644 --- a/embedg-server/entry/database/backup.go +++ b/embedg-server/entry/database/backup.go @@ -40,7 +40,7 @@ func Backup(ctx context.Context, db string, opts BackupOpts) error { slog.Info("Creating database backup", "database", db, "operation", opts.Operation) - tmpFile, err := os.CreateTemp("", "xvault-pg-backup-*.tar") + tmpFile, err := os.CreateTemp("", "embedg-pg-backup-*.tar") if err != nil { return fmt.Errorf("failed to create temporary file: %w", err) } @@ -73,7 +73,7 @@ func Backup(ctx context.Context, db string, opts BackupOpts) error { slog.Info("Successfully created database dump", "file", tmpFile.Name(), "size", stat.Size()) // Create a temporary gzipped file - gzipFile, err := os.CreateTemp("", "xvault-pg-backup-*.tar.gz") + gzipFile, err := os.CreateTemp("", "embedg-pg-backup-*.tar.gz") if err != nil { return fmt.Errorf("failed to create temporary gzip file: %w", err) } diff --git a/embedg-server/go.mod b/embedg-server/go.mod index 5ed03fd3e..4e94db768 100644 --- a/embedg-server/go.mod +++ b/embedg-server/go.mod @@ -53,7 +53,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251109101747-4829dfd63e8d // indirect + github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251113155245-58bf88272926 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect diff --git a/embedg-server/go.sum b/embedg-server/go.sum index 16b0c26c6..65e36dc19 100644 --- a/embedg-server/go.sum +++ b/embedg-server/go.sum @@ -786,6 +786,7 @@ github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= @@ -851,6 +852,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= @@ -907,6 +909,8 @@ github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251108220848-8195b521776b github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251108220848-8195b521776b/go.mod h1:lBq4eaCNMEMiMs9HmainZm8nUNiXEqbuj/fiAUN2WHU= github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251109101747-4829dfd63e8d h1:m1nl+T0JorfW/GvhKgjcYyARv5h9bbL5lUrDBy2I9LU= github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251109101747-4829dfd63e8d/go.mod h1:lBq4eaCNMEMiMs9HmainZm8nUNiXEqbuj/fiAUN2WHU= +github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251113155245-58bf88272926 h1:cHYOssZzAWarRvmp3b9Q9iU31xeDBqunAa5U7NdNomw= +github.com/merlinfuchs/stateway/stateway-lib v0.0.0-20251113155245-58bf88272926/go.mod h1:lBq4eaCNMEMiMs9HmainZm8nUNiXEqbuj/fiAUN2WHU= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= @@ -1087,6 +1091,7 @@ github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qq github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= diff --git a/embedg-service/.gitignore b/embedg-service/.gitignore new file mode 100644 index 000000000..89936728e --- /dev/null +++ b/embedg-service/.gitignore @@ -0,0 +1,2 @@ +embedg.toml +embedg-service diff --git a/embedg-service/README.md b/embedg-service/README.md new file mode 100644 index 000000000..c7ecf6ade --- /dev/null +++ b/embedg-service/README.md @@ -0,0 +1,3 @@ +# Embed Generator Service + +Re-implementation of the Embed Generator backend as a stateless service. It depends on [stateway](https://github.com/merlinfuchs/stateway) for connecting to the Discord gateway and caching. diff --git a/embedg-service/access/access.go b/embedg-service/access/access.go new file mode 100644 index 000000000..e251aa0ff --- /dev/null +++ b/embedg-service/access/access.go @@ -0,0 +1,208 @@ +package access + +import ( + "context" + "fmt" + + discache "github.com/disgoorg/disgo/cache" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/rest" + "github.com/merlinfuchs/discordgo" + "github.com/merlinfuchs/embed-generator/embedg-service/common" + "github.com/merlinfuchs/embed-generator/embedg-service/store" + "github.com/merlinfuchs/stateway/stateway-lib/cache" +) + +const RequiredPermissions = discord.PermissionManageWebhooks + +type AccessManager struct { + cache cache.Cache + caches discache.Caches + rest rest.Rest + appContext store.AppContext +} + +func New(cache cache.Cache, caches discache.Caches, rest rest.Rest, appContext store.AppContext) *AccessManager { + return &AccessManager{ + cache: cache, + caches: caches, + rest: rest, + appContext: appContext, + } +} + +type GuildAccess struct { + CombinedUserPermissions discord.Permissions + CombinedBotPermissions discord.Permissions +} + +func (g *GuildAccess) HasChannelWithUserAccess() bool { + return g.CombinedUserPermissions&(RequiredPermissions|discord.PermissionAdministrator) != 0 +} + +func (g *GuildAccess) HasChannelWithBotAccess() bool { + return g.CombinedBotPermissions&(RequiredPermissions|discord.PermissionAdministrator) != 0 +} + +type ChannelAccess struct { + UserPermissions discord.Permissions + BotPermissions discord.Permissions +} + +func (c *ChannelAccess) UserAccess() bool { + return c.UserPermissions&(RequiredPermissions|discord.PermissionAdministrator) != 0 +} + +func (c *ChannelAccess) BotAccess() bool { + return c.BotPermissions&(RequiredPermissions|discord.PermissionAdministrator) != 0 +} + +func (m *AccessManager) CheckGuildsKnown(guildID []common.ID) ([]bool, error) { + known, err := m.cache.CheckGuildsExist(context.Background(), guildID) + if err != nil { + return nil, fmt.Errorf("Failed to check guilds known: %w", err) + } + + return known, nil +} + +func (m *AccessManager) GetGuildAccessForUser(userID common.ID, guildID common.ID) (GuildAccess, *discord.Guild, error) { + res := GuildAccess{} + + botMember, err := m.GetGuildMember(guildID, m.appContext.ApplicationID()) + if err != nil { + if common.IsDiscordRestErrorCode( + err, + discordgo.ErrCodeMissingAccess, + discordgo.ErrCodeUnknownGuild, + discordgo.ErrCodeUnknownMember, + ) { + // The bot is not in the server, so we can't compute the permissions + return res, nil, nil + } + return res, nil, fmt.Errorf("Failed to get bot member: %w", err) + } + + guild, err := m.cache.GetGuildWithPermissions( + context.Background(), + guildID, + m.appContext.ApplicationID(), + botMember.RoleIDs, + RequiredPermissions, + nil..., + ) + if err != nil { + return res, nil, fmt.Errorf("Failed to get guild with permissions: %w", err) + } + + res.CombinedBotPermissions = guild.MaxChannelPermissions + if !res.HasChannelWithBotAccess() { + // No point in checking user access if the bot doesn't have access to any channels + return res, &guild.Guild.Data, nil + } + + member, err := m.GetGuildMember(guildID, userID) + if err != nil { + if common.IsDiscordRestErrorCode( + err, + discordgo.ErrCodeMissingAccess, + discordgo.ErrCodeUnknownGuild, + discordgo.ErrCodeUnknownMember, + ) { + // The user is not in the server, so we can't compute the permissions + return res, nil, nil + } + return res, nil, fmt.Errorf("Failed to get guild member: %w", err) + } + + guild, err = m.cache.GetGuildWithPermissions( + context.Background(), + guildID, + userID, + member.RoleIDs, + RequiredPermissions, + nil..., + ) + if err != nil { + return res, nil, fmt.Errorf("Failed to get guild with permissions: %w", err) + } + + res.CombinedUserPermissions = guild.MaxChannelPermissions + return res, &guild.Guild.Data, nil +} + +func (m *AccessManager) GetChannelAccessForUser(userID common.ID, channelID common.ID) (ChannelAccess, error) { + res := ChannelAccess{} + + err := m.SetChannelAccessUserPermissions(&res, userID, channelID) + if err != nil { + return res, err + } + + err = m.SetChannelAccessBotPermissions(&res, channelID) + if err != nil { + return res, err + } + + return res, nil +} + +func (m *AccessManager) SetChannelAccessUserPermissions(res *ChannelAccess, userID common.ID, channelID common.ID) (err error) { + res.UserPermissions, err = m.ComputeUserPermissionsForChannel(userID, channelID) + if err != nil { + if common.IsDiscordRestErrorCode(err, discordgo.ErrCodeUnknownMember) { + // The user is not in the server, so we can't compute the permissions + return nil + } + return err + } + + return nil +} + +func (m *AccessManager) SetChannelAccessBotPermissions(res *ChannelAccess, channelID common.ID) error { + botPerms, err := m.ComputeBotPermissionsForChannel(channelID) + if err != nil { + return err + } + if botPerms == 0 { + // The bot doesn't have access to the server so there is no point in checking access for the user + return nil + } + res.BotPermissions = botPerms + + return nil +} + +func (m *AccessManager) ComputeUserPermissionsForChannel(userID common.ID, channelID common.ID) (discord.Permissions, error) { + channel, ok := m.caches.Channel(channelID) + if !ok || channel.GuildID() == 0 { + return 0, nil + } + + member, err := m.GetGuildMember(channel.GuildID(), userID) + if err != nil { + // TODO: Handle this error + return 0, nil + } + + return m.caches.MemberPermissionsInChannel(channel, *member), nil +} + +func (m *AccessManager) ComputeBotPermissionsForChannel(channelID common.ID) (discord.Permissions, error) { + return m.ComputeUserPermissionsForChannel(m.appContext.ApplicationID(), channelID) +} + +func (m *AccessManager) GetGuildMember(guildID common.ID, userID common.ID) (*discord.Member, error) { + cached, ok := m.caches.Member(guildID, userID) + if ok { + return &cached, nil + } + + member, err := m.rest.GetMember(guildID, userID) + if err != nil { + return nil, fmt.Errorf("Failed to get guild member: %w", err) + } + + return member, nil +} diff --git a/embedg-service/access/check.go b/embedg-service/access/check.go new file mode 100644 index 000000000..71b2916e6 --- /dev/null +++ b/embedg-service/access/check.go @@ -0,0 +1,46 @@ +package access + +import ( + "github.com/gofiber/fiber/v2" + "github.com/merlinfuchs/embed-generator/embedg-service/api/handlers" + "github.com/merlinfuchs/embed-generator/embedg-service/api/session" + "github.com/merlinfuchs/embed-generator/embedg-service/common" +) + +func (m *AccessManager) CheckGuildAccessForRequest(c *fiber.Ctx, guildID common.ID) error { + session := c.Locals("session").(*session.Session) + + access, _, err := m.GetGuildAccessForUser(session.UserID, guildID) + if err != nil { + return err + } + + if !access.HasChannelWithBotAccess() { + return handlers.Forbidden("bot_missing_access", "The bot doesn't have access to this guild") + } + + if !access.HasChannelWithUserAccess() { + return handlers.Forbidden("missing_access", "You don't have access to this guild") + } + + return nil +} + +func (m *AccessManager) CheckChannelAccessForRequest(c *fiber.Ctx, channelID common.ID) error { + session := c.Locals("session").(*session.Session) + + access, err := m.GetChannelAccessForUser(session.UserID, channelID) + if err != nil { + return err + } + + if !access.BotAccess() { + return handlers.Forbidden("bot_missing_access", "The bot doesn't have access to this channel") + } + + if !access.UserAccess() { + return handlers.Forbidden("missing_access", "You don't have access to this channel") + } + + return nil +} diff --git a/embedg-service/access/helpers.go b/embedg-service/access/helpers.go new file mode 100644 index 000000000..8b43b9600 --- /dev/null +++ b/embedg-service/access/helpers.go @@ -0,0 +1,82 @@ +package access + +import ( + "github.com/disgoorg/disgo/discord" + "github.com/merlinfuchs/embed-generator/embedg-service/common" +) + +func memberPermissions(guild *discord.Guild, roles []discord.Role, channel discord.GuildChannel, userID common.ID, roleIDs []common.ID) (apermissions discord.Permissions) { + if userID == guild.OwnerID { + apermissions = discord.PermissionsAll + return + } + + for _, role := range roles { + if role.ID == guild.ID { + apermissions |= role.Permissions + break + } + } + + for _, role := range roles { + for _, roleID := range roleIDs { + if role.ID == roleID { + apermissions |= role.Permissions + break + } + } + } + + if apermissions&discord.PermissionAdministrator == discord.PermissionAdministrator { + apermissions |= discord.PermissionsAll + return // Administrator bypasses all overrides + } + + if channel == nil { + return + } + + // Apply @everyone overrides from the channel. + for _, overwrite := range channel.PermissionOverwrites() { + if roleOverwrite, ok := overwrite.(discord.RolePermissionOverwrite); ok { + if guild.ID == roleOverwrite.ID() { + apermissions &= ^roleOverwrite.Deny + apermissions |= roleOverwrite.Allow + break + } + } + } + + var denies, allows discord.Permissions + // Member overwrites can override role overrides, so do two passes + for _, overwrite := range channel.PermissionOverwrites() { + if roleOverwrite, ok := overwrite.(discord.RolePermissionOverwrite); ok { + for _, roleID := range roleIDs { + if roleOverwrite.ID() == roleID { + denies |= roleOverwrite.Deny + allows |= roleOverwrite.Allow + break + } + } + } + } + + apermissions &= ^denies + apermissions |= allows + + for _, overwrite := range channel.PermissionOverwrites() { + if memberOverwrite, ok := overwrite.(discord.MemberPermissionOverwrite); ok { + if memberOverwrite.ID() == userID { + apermissions &= ^memberOverwrite.Deny + apermissions |= memberOverwrite.Allow + break + } + } + } + + if apermissions&discord.PermissionAdministrator == discord.PermissionAdministrator { + apermissions |= discord.PermissionsAll + } + + return apermissions +} diff --git a/embedg-service/actions/data.go b/embedg-service/actions/data.go new file mode 100644 index 000000000..d84002583 --- /dev/null +++ b/embedg-service/actions/data.go @@ -0,0 +1,144 @@ +package actions + +import ( + "slices" + + "github.com/disgoorg/disgo/discord" + "github.com/merlinfuchs/embed-generator/embedg-service/common" +) + +type MessageWithActions struct { + Content string `json:"content,omitempty"` + Username string `json:"username,omitempty"` + AvatarURL string `json:"avatar_url,omitempty"` + TTS bool `json:"tts,omitempty"` + Embeds []discord.Embed `json:"embeds,omitempty"` + AllowedMentions *discord.AllowedMentions `json:"allowed_mentions,omitempty"` + Components []ComponentWithActions `json:"components,omitempty"` + Actions map[string]ActionSet `json:"actions,omitempty"` + Flags discord.MessageFlags `json:"flags,omitempty"` +} + +func (m MessageWithActions) ComponentsV2Enabled() bool { + return m.Flags&(1<<15) != 0 +} + +type ComponentWithActions struct { + ID int `json:"id,omitempty"` + Type discord.ComponentType `json:"type"` + Disabled bool `json:"disabled,omitempty"` + Spoiler bool `json:"spoiler,omitempty"` + + // Action Row & Section & Container + Components []ComponentWithActions `json:"components,omitempty"` + + // Button + Style discord.ButtonStyle `json:"style,omitempty"` + Label string `json:"label,omitempty"` + Emoji *discord.ComponentEmoji `json:"emoji,omitempty"` + URL string `json:"url,omitempty"` + ActionSetID string `json:"action_set_id,omitempty"` + + // Select Menu + Placeholder string `json:"placeholder,omitempty"` + MinValues *int `json:"min_values,omitempty"` + MaxValues int `json:"max_values,omitempty"` + Options []ComponentSelectOptionWithActions `json:"options,omitempty"` + + // Section + Accessory *ComponentWithActions `json:"accessory"` + + // Text Display + Content string `json:"content,omitempty"` + + // Thumbnail + Description string `json:"description,omitempty"` + Media *UnfurledMediaItem `json:"media,omitempty"` + + // Media Gallery + Items []ComponentMediaGalleryItem `json:"items,omitempty"` + + // File + File *UnfurledMediaItem `json:"file,omitempty"` + + // Separator + Divider bool `json:"divider,omitempty"` + Spacing int `json:"spacing,omitempty"` + + // Container + AccentColor int `json:"accent_color,omitempty"` +} + +type UnfurledMediaItem struct { + URL string `json:"url"` +} + +type ComponentSelectOptionWithActions struct { + Label string `json:"label"` + Description string `json:"description"` + Emoji *discord.ComponentEmoji `json:"emoji"` + Default bool `json:"default"` + ActionSetID string `json:"action_set_id"` +} + +type ComponentMediaGalleryItem struct { + Media UnfurledMediaItem `json:"media"` + Description string `json:"description,omitempty"` + Spoiler bool `json:"spoiler,omitempty"` +} + +type ActionType int + +const ( + ActionTypeTextResponse ActionType = 1 + ActionTypeToggleRole ActionType = 2 + ActionTypeAddRole ActionType = 3 + ActionTypeRemoveRole ActionType = 4 + ActionTypeSavedMessageResponse ActionType = 5 + ActionTypeTextDM ActionType = 6 + ActionTypeSavedMessageDM ActionType = 7 + ActionTypeTextEdit ActionType = 8 + ActionTypeSavedMessageEdit ActionType = 9 + ActionTypePermissionCheck ActionType = 10 +) + +type Action struct { + Type ActionType `json:"type"` + TargetID string `json:"target_id"` + Text string `json:"text"` + Public bool `json:"public"` + AllowRoleMentions bool `json:"allow_role_mentions"` + DisableDefaultResponse bool `json:"disable_default_response"` + Permissions string `json:"permissions"` + RoleIDs []string `json:"role_ids"` +} + +type ActionSet struct { + Actions []Action `json:"actions"` +} + +type ActionDerivedPermissions struct { + UserID common.ID `json:"user_id"` + GuildIsOwner bool `json:"guild_is_owner"` + GuildPermissions uint64 `json:"guild_permissions"` + ChannelPermissions uint64 `json:"channel_permissions"` + AllowedRoleIDs []common.ID `json:"lower_role_ids"` +} + +func (a *ActionDerivedPermissions) HasChannelPermission(permission discord.Permissions) bool { + perms := discord.Permissions(a.ChannelPermissions) + return a.GuildIsOwner || perms.Has(discord.PermissionAdministrator) || perms.Has(permission) +} + +func (a *ActionDerivedPermissions) HasGuildPermission(permission discord.Permissions) bool { + perms := discord.Permissions(a.GuildPermissions) + return a.GuildIsOwner || perms.Has(discord.PermissionAdministrator) || perms.Has(permission) +} + +func (a *ActionDerivedPermissions) CanManageRole(roleID common.ID) bool { + if a.GuildIsOwner { + return true + } + + return a.HasGuildPermission(discord.PermissionManageRoles) && slices.Contains(a.AllowedRoleIDs, roleID) +} diff --git a/embedg-service/actions/handler/handle.go b/embedg-service/actions/handler/handle.go new file mode 100644 index 000000000..521e630fb --- /dev/null +++ b/embedg-service/actions/handler/handle.go @@ -0,0 +1,579 @@ +package handler + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "slices" + "strconv" + "strings" + + "log/slog" + + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/rest" + "github.com/disgoorg/snowflake/v2" + "github.com/merlinfuchs/discordgo" + "github.com/merlinfuchs/embed-generator/embedg-service/actions" + "github.com/merlinfuchs/embed-generator/embedg-service/actions/parser" + "github.com/merlinfuchs/embed-generator/embedg-service/actions/template" + "github.com/merlinfuchs/embed-generator/embedg-service/common" + "github.com/merlinfuchs/embed-generator/embedg-service/store" +) + +const roleErrorMessage = "Failed to add or remove role.\n\n" + + "Please make sure the role is below the 'Embed Generator' role and that the bot has the manage roles permission." + +type ActionHandler struct { + customCommandStore store.CustomCommandStore + savedMessageStore store.SavedMessageStore + actionSetStore store.MessageActionSetStore + kvEntryStore store.KVEntryStore + parser *parser.ActionParser + planStore store.PlanStore +} + +func New( + customCommandStore store.CustomCommandStore, + savedMessageStore store.SavedMessageStore, + actionSetStore store.MessageActionSetStore, + kvEntryStore store.KVEntryStore, + parser *parser.ActionParser, + planStore store.PlanStore, +) *ActionHandler { + return &ActionHandler{ + customCommandStore: customCommandStore, + savedMessageStore: savedMessageStore, + actionSetStore: actionSetStore, + kvEntryStore: kvEntryStore, + parser: parser, + planStore: planStore, + } +} + +func (m *ActionHandler) HandleActionInteraction(restClient rest.Rest, i Interaction) error { + interaction := i.Interaction() + + var actionSet actions.ActionSet + var derivedPerms *actions.ActionDerivedPermissions + + if interaction.Type() == discord.InteractionTypeComponent { + compInteraction := interaction.(discord.ComponentInteraction) + data := compInteraction.Data + + if !strings.HasPrefix(data.CustomID(), "action:") { + return nil + } + + actionSetID := data.CustomID()[7:] + + if strings.HasPrefix(actionSetID, "options:") { + // Handle select menu values + if selectData, ok := data.(discord.StringSelectMenuInteractionData); ok { + actionSetID = selectData.Values[0][7:] + } + } + + col, err := m.actionSetStore.GetMessageActionSet(context.TODO(), compInteraction.Message.ID, actionSetID) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil + } + + slog.Error("Failed to get message action set", slog.Any("error", err)) + return err + } + actionSet = col.Actions + derivedPerms = col.DerivedPermissions + } else if interaction.Type() == discord.InteractionTypeApplicationCommand { + appCommandInteraction := interaction.(discord.ApplicationCommandInteraction) + slashData := appCommandInteraction.SlashCommandInteractionData() + fullName := slashData.CommandName() + if slashData.SubCommandGroupName != nil { + fullName += " " + *slashData.SubCommandGroupName + } + if slashData.SubCommandName != nil { + fullName += " " + *slashData.SubCommandName + } + + if interaction.GuildID() == nil { + return nil + } + + col, err := m.customCommandStore.GetCustomCommandByName(context.TODO(), *interaction.GuildID(), fullName) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil + } + + slog.Error("Failed to get custom command action set", slog.Any("error", err)) + return err + } + actionSet = col.Actions + derivedPerms = col.DerivedPermissions + } else { + return fmt.Errorf("invalid interaciont type") + } + + // For messages created before the permission context was added we don't run permission checks here + legacyPermissions := derivedPerms == nil + + // DEPRECATED: This has been replaced by templates, it's only here for backwards compatibility + // TODO: Refactor variables to use disgo types + // variables := variables.NewContext( + // variables.NewInteractionVariables(interaction), + // variables.NewGuildVariables(interaction.GuildID().String(), s.State, nil), + // variables.NewChannelVariables(interaction.ChannelID, s.State, nil), + // ) + + features, err := m.planStore.GetPlanFeaturesForGuild(context.TODO(), *interaction.GuildID()) + if err != nil { + return fmt.Errorf("could not get plan features: %w", err) + } + + templates := template.NewContext( + "HANDLE_ACTION", features.MaxTemplateOps, + template.NewInteractionProvider(nil, interaction), // TODO: Fix caches access + template.NewKVProvider(*interaction.GuildID(), m.kvEntryStore, features.MaxKVKeys), + ) + + for _, action := range actionSet.Actions { + switch action.Type { + case actions.ActionTypeTextResponse: + var flags discord.MessageFlags + if !action.Public { + flags = discord.MessageFlagEphemeral + } + + content, ok := executeTemplate(i, templates, action.Text) // TODO: Fix variables.FillString + if !ok { + return nil + } + + allowedMentions := []discord.AllowedMentionType{ + discord.AllowedMentionTypeUsers, + } + if action.AllowRoleMentions { + allowedMentions = append( + allowedMentions, + discord.AllowedMentionTypeRoles, + discord.AllowedMentionTypeEveryone, + ) + } + + i.Respond(discord.MessageCreate{ + Content: content, + Flags: flags, + AllowedMentions: &discord.AllowedMentions{ + Parse: allowedMentions, + }, + }) + case actions.ActionTypeToggleRole: + if !legacyPermissions { + roleID, err := snowflake.Parse(action.TargetID) + if err != nil { + slog.Error("Failed to parse role ID", slog.Any("error", err)) + return err + } + if !derivedPerms.CanManageRole(roleID) { + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("The user that has created this message doesn't have permissions to toggle the role <@&%s>.", action.TargetID), + Flags: discord.MessageFlagEphemeral, + }) + return nil + } + } + + hasRole := false + if member := interaction.Member(); member != nil { + for _, roleID := range member.RoleIDs { + if roleID.String() == action.TargetID { + hasRole = true + break + } + } + } + + var err error + if member := interaction.Member(); member != nil { + roleID, err := snowflake.Parse(action.TargetID) + if err != nil { + slog.Error("Failed to parse role ID", slog.Any("error", err)) + return err + } + + if hasRole { + err = restClient.RemoveMemberRole(*interaction.GuildID(), member.User.ID, roleID) + if err == nil { + if !action.DisableDefaultResponse { + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("Removed role <@&%s>", action.TargetID), + Flags: discord.MessageFlagEphemeral, + }) + } + } + } else { + err = restClient.AddMemberRole(*interaction.GuildID(), member.User.ID, roleID) + if err == nil { + if !action.DisableDefaultResponse { + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("Added role <@&%s>", action.TargetID), + Flags: discord.MessageFlagEphemeral, + }) + } + } + } + } + if err != nil { + i.Respond(discord.MessageCreate{ + Content: roleErrorMessage, + Flags: discord.MessageFlagEphemeral, + }) + } + case actions.ActionTypeAddRole: + if !legacyPermissions { + roleID, err := snowflake.Parse(action.TargetID) + if err != nil { + slog.Error("Failed to parse role ID", slog.Any("error", err)) + return err + } + if !derivedPerms.CanManageRole(roleID) { + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("The user that has created this message doesn't have permissions to assign the role <@&%s>.", action.TargetID), + Flags: discord.MessageFlagEphemeral, + }) + return nil + } + } + + if member := interaction.Member(); member != nil { + roleID, err := snowflake.Parse(action.TargetID) + if err != nil { + slog.Error("Failed to parse role ID", slog.Any("error", err)) + return err + } + + err = restClient.AddMemberRole(*interaction.GuildID(), member.User.ID, roleID) + if err == nil { + if !action.DisableDefaultResponse { + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("Added role <@&%s>", action.TargetID), + Flags: discord.MessageFlagEphemeral, + }) + } + } else { + i.Respond(discord.MessageCreate{ + Content: roleErrorMessage, + Flags: discord.MessageFlagEphemeral, + }) + } + } + case actions.ActionTypeRemoveRole: + if !legacyPermissions { + roleID, err := snowflake.Parse(action.TargetID) + if err != nil { + slog.Error("Failed to parse role ID", slog.Any("error", err)) + return err + } + if !derivedPerms.CanManageRole(roleID) { + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("The user that has created this message doesn't have permissions to remove the role <@&%s>.", action.TargetID), + Flags: discord.MessageFlagEphemeral, + }) + return nil + } + } + + if member := interaction.Member(); member != nil { + roleID, err := snowflake.Parse(action.TargetID) + if err != nil { + slog.Error("Failed to parse role ID", slog.Any("error", err)) + return err + } + + err = restClient.RemoveMemberRole(*interaction.GuildID(), member.User.ID, roleID) + if err == nil { + if !action.DisableDefaultResponse { + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("Removed role <@&%s>", action.TargetID), + Flags: discord.MessageFlagEphemeral, + }) + } + } else { + i.Respond(discord.MessageCreate{ + Content: roleErrorMessage, + Flags: discord.MessageFlagEphemeral, + }) + } + } + case actions.ActionTypeSavedMessageResponse: + if interaction.GuildID() == nil { + continue + } + + msg, err := m.savedMessageStore.GetSavedMessageForGuild(context.TODO(), *interaction.GuildID(), action.TargetID) + if err != nil { + return err + } + + data := &actions.MessageWithActions{} + err = json.Unmarshal(msg.Data, data) + if err != nil { + return err + } + + // TODO: Fix variables system - variables.FillMessage(data) + if !executeTemplateMessage(i, templates, data) { + return nil + } + + if !action.Public { + data.Flags |= discord.MessageFlagEphemeral + } + + var components []discord.LayoutComponent + if !legacyPermissions { + components, err = m.parser.ParseMessageComponents(data.Components, features.ComponentTypes) + if err != nil { + return fmt.Errorf("Invalid actions: %w", err) + } + } + + allowedMentions := []discord.AllowedMentionType{ + discord.AllowedMentionTypeUsers, + } + if action.AllowRoleMentions { + allowedMentions = append( + allowedMentions, + discord.AllowedMentionTypeRoles, + discord.AllowedMentionTypeEveryone, + ) + } + + // We need to get the message id of the response, so it has to be a followup response + if !i.HasResponded() { + i.Respond(discord.MessageCreate{ + Flags: data.Flags, + }, discord.InteractionResponseTypeDeferredCreateMessage) + } + + newMsg := i.Respond(discord.MessageCreate{ + Content: data.Content, + Embeds: data.Embeds, + Components: components, + Flags: data.Flags, + AllowedMentions: &discord.AllowedMentions{ + Parse: allowedMentions, + }, + }) + if newMsg != nil && !legacyPermissions { + err = m.parser.CreateActionsForMessage(context.TODO(), data.Actions, *derivedPerms, newMsg.ID, !action.Public) + if err != nil { + slog.Error("failed to create actions for message", slog.Any("error", err)) + return err + } + } + case actions.ActionTypeTextDM: + channel, err := restClient.CreateDMChannel(interaction.User().ID, rest.WithCtx(context.TODO())) + if err != nil { + slog.Error("Failed to create DM channel", slog.Any("error", err)) + return fmt.Errorf("failed to create DM channel: %w", err) + } + + _, err = restClient.CreateMessage(channel.ID(), discord.MessageCreate{ + Content: action.Text, + }, rest.WithCtx(context.TODO())) + if err != nil { + if common.IsDiscordRestErrorCode(err, discordgo.ErrCodeCannotSendMessagesToThisUser) { + i.Respond(discord.MessageCreate{ + Content: "You have blocked the bot from sending you DMs. Please allow DMs from server members in your privacy settings.", + Flags: discord.MessageFlagEphemeral, + }) + return nil + } + return fmt.Errorf("failed to send DM: %w", err) + } + case actions.ActionTypeSavedMessageDM: + if interaction.GuildID() == nil { + continue + } + + msg, err := m.savedMessageStore.GetSavedMessageForGuild(context.TODO(), *interaction.GuildID(), action.TargetID) + if err != nil { + return err + } + + data := &actions.MessageWithActions{} + err = json.Unmarshal(msg.Data, data) + if err != nil { + return err + } + + // TODO: Fix variables system - variables.FillMessage(data) + if !executeTemplateMessage(i, templates, data) { + return nil + } + + // We support displaying components in DMs, but don't hook them up to actions + components, err := m.parser.ParseMessageComponents(data.Components, features.ComponentTypes) + if err != nil { + return fmt.Errorf("Invalid actions: %w", err) + } + + channel, err := restClient.CreateDMChannel(interaction.User().ID, rest.WithCtx(context.TODO())) + if err != nil { + slog.Error("Failed to create DM channel", slog.Any("error", err)) + return fmt.Errorf("failed to create DM channel: %w", err) + } + + _, err = restClient.CreateMessage(channel.ID(), discord.MessageCreate{ + Content: data.Content, + Embeds: data.Embeds, + Components: components, + Flags: data.Flags, + }, rest.WithCtx(context.TODO())) + if err != nil { + slog.Error("Failed to send DM", slog.Any("error", err)) + return fmt.Errorf("failed to send DM: %w", err) + } + case actions.ActionTypeTextEdit: + content, ok := executeTemplate(i, templates, action.Text) // TODO: Fix variables system + if !ok { + return nil + } + + i.Respond(discord.MessageUpdate{ + Content: &content, + }, discord.InteractionResponseTypeUpdateMessage) + case actions.ActionTypeSavedMessageEdit: + if interaction.GuildID() == nil { + continue + } + + msg, err := m.savedMessageStore.GetSavedMessageForGuild(context.TODO(), *interaction.GuildID(), action.TargetID) + if err != nil { + return err + } + + data := &actions.MessageWithActions{} + err = json.Unmarshal(msg.Data, data) + if err != nil { + return err + } + + // TODO: Fix variables system - variables.FillMessage(data) + if !executeTemplateMessage(i, templates, data) { + return nil + } + + var components []discord.LayoutComponent + if !legacyPermissions { + components, err = m.parser.ParseMessageComponents(data.Components, features.ComponentTypes) + if err != nil { + return fmt.Errorf("Invalid actions: %w", err) + } + } + + newMsg := i.Respond(discord.MessageUpdate{ + Content: &data.Content, + Embeds: &data.Embeds, + Components: &components, + Flags: &data.Flags, + }, discord.InteractionResponseTypeUpdateMessage) + + if compInteraction, ok := interaction.(discord.ComponentInteraction); ok { + newMsg = &compInteraction.Message + } + + if !legacyPermissions && newMsg != nil { + ephemeral := newMsg.Flags&discord.MessageFlagEphemeral != 0 + err = m.parser.CreateActionsForMessage(context.TODO(), data.Actions, *derivedPerms, newMsg.ID, ephemeral) + if err != nil { + slog.Error("failed to create actions for message", slog.Any("error", err)) + return err + } + } + case actions.ActionTypePermissionCheck: + perms, _ := strconv.ParseInt(action.Permissions, 10, 64) + + member := interaction.Member() + if member == nil { + return fmt.Errorf("member not found") + } + + if member.Permissions&discord.Permissions(perms) != discord.Permissions(perms) { + responseText := "You don't have the required permissions to use this component or command." + if action.DisableDefaultResponse { + responseText = action.Text + } + + i.Respond(discord.MessageCreate{ + Content: responseText, + Flags: discord.MessageFlagEphemeral, + }) + return nil + } + + responseText := "You don't have the required roles to use this component or command." + if action.DisableDefaultResponse { + responseText = action.Text + } + + if len(action.RoleIDs) != 0 { + for _, roleID := range action.RoleIDs { + roleIDSnowflake, err := snowflake.Parse(roleID) + if err != nil { + continue + } + if !slices.Contains(member.RoleIDs, roleIDSnowflake) { + i.Respond(discord.MessageCreate{ + Content: responseText, + Flags: discord.MessageFlagEphemeral, + }) + return nil + } + } + } + } + } + + if !i.HasResponded() { + if interaction.Type() == discord.InteractionTypeComponent { + i.Respond(discord.MessageCreate{}, discord.InteractionResponseTypeDeferredUpdateMessage) + } else { + i.Respond(discord.MessageCreate{ + Content: "No response", + Flags: discord.MessageFlagEphemeral, + }) + } + } + + return nil +} + +func executeTemplate(i Interaction, templates *template.TemplateContext, text string) (string, bool) { + res, err := templates.ParseAndExecute(text) + if err != nil { + slog.Error("Failed to execute template", slog.Any("error", err)) + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("Failed to execute template variables:\n```%s```", err.Error()), + Flags: discord.MessageFlagEphemeral, + }) + return "", false + } + return res, true +} + +func executeTemplateMessage(i Interaction, templates *template.TemplateContext, m *actions.MessageWithActions) bool { + if err := templates.ParseAndExecuteMessage(m); err != nil { + slog.Error("Failed to execute template", slog.Any("error", err)) + i.Respond(discord.MessageCreate{ + Content: fmt.Sprintf("Failed to execute template variables:\n```%s```", err.Error()), + Flags: discord.MessageFlagEphemeral, + }) + return false + } + + return true +} diff --git a/embedg-service/actions/handler/interaction.go b/embedg-service/actions/handler/interaction.go new file mode 100644 index 000000000..59e3cb007 --- /dev/null +++ b/embedg-service/actions/handler/interaction.go @@ -0,0 +1,187 @@ +package handler + +import ( + "fmt" + + "log/slog" + + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/disgo/rest" +) + +type Interaction interface { + Interaction() discord.Interaction + HasResponded() bool + Respond(data discord.InteractionResponseData, t ...discord.InteractionResponseType) *discord.Message +} + +type GenericInteraction struct { + Responded bool + Rest rest.Rest + Inner discord.Interaction + RespondFunc events.InteractionResponderFunc +} + +func (i *GenericInteraction) Interaction() discord.Interaction { + return i.Inner +} + +func (i *GenericInteraction) HasResponded() bool { + return i.Responded +} + +func (i *GenericInteraction) Respond(data discord.InteractionResponseData, t ...discord.InteractionResponseType) *discord.Message { + responseType := discord.InteractionResponseTypeCreateMessage + if len(t) > 0 { + responseType = t[0] + } + + var err error + var msg *discord.Message + + if !i.Responded { + err = i.RespondFunc(responseType, data) + } else if responseType == discord.InteractionResponseTypeCreateMessage { + msgData, ok := data.(discord.MessageCreate) + if !ok { + err = fmt.Errorf("can't create followup message, data is not a MessageCreate") + } else { + msg, err = i.Rest.CreateFollowupMessage(i.Inner.ApplicationID(), i.Inner.Token(), msgData) + } + } else if responseType == discord.InteractionResponseTypeUpdateMessage { + msgData, ok := data.(discord.MessageUpdate) + if !ok { + err = fmt.Errorf("can't update followup message, data is not a MessageUpdate") + } else { + msg, err = i.Rest.UpdateInteractionResponse(i.Inner.ApplicationID(), i.Inner.Token(), msgData) + } + } else { + err = fmt.Errorf("invalid response type after initial response, %d", responseType) + } + + if err != nil { + slog.Error("Failed to respond to interaction", slog.Any("error", err)) + } else { + i.Responded = true + } + + return msg +} + +type GatewayInteraction struct { + Responded bool + Rest rest.Rest + Inner discord.Interaction +} + +func (i *GatewayInteraction) Interaction() discord.Interaction { + return i.Inner +} + +func (i *GatewayInteraction) HasResponded() bool { + return i.Responded +} + +func (i *GatewayInteraction) Respond(data discord.InteractionResponseData, t ...discord.InteractionResponseType) *discord.Message { + var err error + + responseType := discord.InteractionResponseTypeCreateMessage + if len(t) > 0 { + responseType = t[0] + } + + var msg *discord.Message + + if !i.Responded { + err = i.Rest.CreateInteractionResponse( + i.Inner.ID(), + i.Inner.Token(), + discord.InteractionResponse{ + Type: responseType, + Data: data, + }, + ) + } else if responseType == discord.InteractionResponseTypeCreateMessage { + msgData, ok := data.(discord.MessageCreate) + if !ok { + err = fmt.Errorf("can't create followup message, data is not a MessageCreate") + } else { + msg, err = i.Rest.CreateFollowupMessage(i.Inner.ApplicationID(), i.Inner.Token(), msgData) + } + } else if responseType == discord.InteractionResponseTypeUpdateMessage { + msgData, ok := data.(discord.MessageUpdate) + if !ok { + err = fmt.Errorf("can't update followup message, data is not a MessageUpdate") + } else { + msg, err = i.Rest.UpdateInteractionResponse(i.Inner.ApplicationID(), i.Inner.Token(), msgData) + } + } else { + err = fmt.Errorf("invalid response type after initial response, %d", responseType) + } + + if err != nil { + slog.Error("Failed to respond to interaction", slog.Any("error", err)) + } else { + i.Responded = true + } + + return msg +} + +type RestInteraction struct { + Responded bool + InitialResponse chan *discord.InteractionResponse + Rest rest.Rest + Inner discord.Interaction +} + +func (i *RestInteraction) Interaction() discord.Interaction { + return i.Inner +} + +func (i *RestInteraction) HasResponded() bool { + return i.Responded +} + +func (i *RestInteraction) Respond(data discord.InteractionResponseData, t ...discord.InteractionResponseType) *discord.Message { + var err error + + responseType := discord.InteractionResponseTypeCreateMessage + if len(t) > 0 { + responseType = t[0] + } + + var msg *discord.Message + + if !i.Responded { + i.InitialResponse <- &discord.InteractionResponse{ + Type: responseType, + Data: data, + } + } else if responseType == discord.InteractionResponseTypeCreateMessage { + msgData, ok := data.(discord.MessageCreate) + if !ok { + err = fmt.Errorf("can't create followup message, data is not a MessageCreate") + } else { + msg, err = i.Rest.CreateFollowupMessage(i.Inner.ApplicationID(), i.Inner.Token(), msgData) + } + } else if responseType == discord.InteractionResponseTypeUpdateMessage { + msgData, ok := data.(discord.MessageUpdate) + if !ok { + err = fmt.Errorf("can't update followup message, data is not a MessageUpdate") + } else { + msg, err = i.Rest.UpdateInteractionResponse(i.Inner.ApplicationID(), i.Inner.Token(), msgData) + } + } else { + err = fmt.Errorf("invalid response type after initial response, %d", responseType) + } + + if err != nil { + slog.Error("Failed to respond to interaction", slog.Any("error", err)) + } else { + i.Responded = true + } + + return msg +} diff --git a/embedg-service/actions/parser/actions.go b/embedg-service/actions/parser/actions.go new file mode 100644 index 000000000..79c86909a --- /dev/null +++ b/embedg-service/actions/parser/actions.go @@ -0,0 +1,53 @@ +package parser + +import ( + "context" + "fmt" + + "log/slog" + + "github.com/merlinfuchs/embed-generator/embedg-service/actions" + "github.com/merlinfuchs/embed-generator/embedg-service/common" + "github.com/merlinfuchs/embed-generator/embedg-service/model" +) + +func (m *ActionParser) CreateActionsForMessage(ctx context.Context, actionSets map[string]actions.ActionSet, derivedPerms actions.ActionDerivedPermissions, messageID common.ID, ephemeral bool) error { + err := m.actionSetStore.DeleteMessageActionSetsForMessage(ctx, messageID) + if err != nil { + slog.Error("Failed to delete message action sets", slog.Any("error", err)) + } + + for actionSetID, actionSet := range actionSets { + _, err = m.actionSetStore.CreateMessageActionSet(ctx, model.MessageActionSet{ + ID: common.InternalID(), + MessageID: messageID, + SetID: actionSetID, + Actions: actionSet, + DerivedPermissions: &derivedPerms, + Ephemeral: ephemeral, + }) + if err != nil { + slog.Error("Failed to insert message action set", slog.Any("error", err)) + } + } + return nil +} + +func (m *ActionParser) RetrieveActionsForMessage(ctx context.Context, messageID common.ID) (map[string]actions.ActionSet, error) { + rows, err := m.actionSetStore.GetMessageActionSets(ctx, messageID) + if err != nil { + return nil, fmt.Errorf("Failed to get message action sets: %w", err) + } + + res := make(map[string]actions.ActionSet, len(rows)) + + for _, row := range rows { + res[row.SetID] = row.Actions + } + + return res, nil +} + +func (m *ActionParser) DeleteActionsForMessage(ctx context.Context, messageID common.ID) error { + return m.actionSetStore.DeleteMessageActionSetsForMessage(ctx, messageID) +} diff --git a/embedg-service/actions/parser/parse.go b/embedg-service/actions/parser/parse.go new file mode 100644 index 000000000..7835a9b01 --- /dev/null +++ b/embedg-service/actions/parser/parse.go @@ -0,0 +1,370 @@ +package parser + +import ( + "errors" + "fmt" + "slices" + "strings" + + "github.com/disgoorg/disgo/cache" + "github.com/disgoorg/disgo/discord" + "github.com/merlinfuchs/embed-generator/embedg-service/access" + "github.com/merlinfuchs/embed-generator/embedg-service/actions" + "github.com/merlinfuchs/embed-generator/embedg-service/common" + "github.com/merlinfuchs/embed-generator/embedg-service/store" +) + +type ActionParser struct { + accessManager *access.AccessManager + actionSetStore store.MessageActionSetStore + savedMessageStore store.SavedMessageStore + caches cache.Caches +} + +func New( + accessManager *access.AccessManager, + actionSetStore store.MessageActionSetStore, + savedMessageStore store.SavedMessageStore, + caches cache.Caches, +) *ActionParser { + return &ActionParser{ + accessManager: accessManager, + actionSetStore: actionSetStore, + savedMessageStore: savedMessageStore, + caches: caches, + } +} + +func (m *ActionParser) ParseMessageComponents(data []actions.ComponentWithActions, allowedComponentTypes []int) ([]discord.LayoutComponent, error) { + components := make([]discord.LayoutComponent, 0, len(data)) + + for _, component := range data { + parsed, err := m.ParseMessageComponent(component, allowedComponentTypes) + if err != nil { + return nil, err + } + + // Convert to LayoutComponent + if layoutComp, ok := parsed.(discord.LayoutComponent); ok { + components = append(components, layoutComp) + } else { + return nil, fmt.Errorf("component type %T cannot be used as LayoutComponent", parsed) + } + } + + return components, nil +} + +func (m *ActionParser) ParseMessageComponent(data actions.ComponentWithActions, allowedComponentTypes []int) (discord.Component, error) { + if !slices.Contains(allowedComponentTypes, int(data.Type)) { + return nil, fmt.Errorf("component type %d not allowed, you need to upgrade to a premium plan to use this component", data.Type) + } + + switch data.Type { + case discord.ComponentTypeActionRow: + ar := discord.ActionRowComponent{ + ID: data.ID, + Components: make([]discord.InteractiveComponent, 0, len(data.Components)), + } + + for _, component := range data.Components { + parsed, err := m.ParseMessageComponent(component, allowedComponentTypes) + if err != nil { + return nil, err + } + + if interactiveComp, ok := parsed.(discord.InteractiveComponent); ok { + ar.Components = append(ar.Components, interactiveComp) + } else { + return nil, fmt.Errorf("component type %T cannot be used as InteractiveComponent", parsed) + } + } + + return ar, nil + case discord.ComponentTypeButton: + if data.Style == discord.ButtonStyleLink { + return discord.ButtonComponent{ + Label: data.Label, + Style: data.Style, + Disabled: data.Disabled, + URL: data.URL, + Emoji: data.Emoji, + }, nil + } else { + return discord.ButtonComponent{ + CustomID: "action:" + data.ActionSetID, + Label: data.Label, + Style: data.Style, + Disabled: data.Disabled, + Emoji: data.Emoji, + }, nil + } + case discord.ComponentTypeStringSelectMenu: + options := make([]discord.StringSelectMenuOption, len(data.Options)) + for x, option := range data.Options { + options[x] = discord.StringSelectMenuOption{ + Label: option.Label, + Value: "action:" + option.ActionSetID, + Description: option.Description, + Default: option.Default, + Emoji: option.Emoji, + } + } + + return discord.StringSelectMenuComponent{ + CustomID: "action:options:" + common.InternalID(), + Placeholder: data.Placeholder, + MinValues: data.MinValues, + MaxValues: data.MaxValues, + Options: options, + Disabled: data.Disabled, + }, nil + case discord.ComponentTypeSection: + se := discord.SectionComponent{ + Components: make([]discord.SectionSubComponent, 0, len(data.Components)), + } + + for _, component := range data.Components { + parsed, err := m.ParseMessageComponent(component, allowedComponentTypes) + if err != nil { + return nil, err + } + + if sectionSubComp, ok := parsed.(discord.SectionSubComponent); ok { + se.Components = append(se.Components, sectionSubComp) + } else { + return nil, fmt.Errorf("component type %T cannot be used as SectionSubComponent", parsed) + } + } + + if data.Accessory != nil { + parsed, err := m.ParseMessageComponent(*data.Accessory, allowedComponentTypes) + if err != nil { + return nil, err + } + if sectionAccessoryComp, ok := parsed.(discord.SectionAccessoryComponent); ok { + se.Accessory = sectionAccessoryComp + } else { + return nil, fmt.Errorf("component type %T cannot be used as SectionAccessoryComponent", parsed) + } + } + + return se, nil + case discord.ComponentTypeTextDisplay: + return discord.TextDisplayComponent{ + Content: data.Content, + }, nil + case discord.ComponentTypeThumbnail: + if data.Media == nil { + return nil, errors.New("media is required for thumbnail component") + } + + return discord.ThumbnailComponent{ + Media: discord.UnfurledMediaItem{URL: data.Media.URL}, + Description: data.Description, + Spoiler: data.Spoiler, + }, nil + case discord.ComponentTypeMediaGallery: + items := make([]discord.MediaGalleryItem, len(data.Items)) + for x, item := range data.Items { + items[x] = discord.MediaGalleryItem{ + Media: discord.UnfurledMediaItem{URL: item.Media.URL}, + Description: item.Description, + Spoiler: item.Spoiler, + } + } + + return discord.MediaGalleryComponent{ + Items: items, + }, nil + case discord.ComponentTypeFile: + if data.File == nil { + return nil, errors.New("file is required for file component") + } + + return discord.FileComponent{ + File: discord.UnfurledMediaItem{URL: data.File.URL}, + Spoiler: data.Spoiler, + }, nil + case discord.ComponentTypeSeparator: + var divider *bool + if data.Divider { + divider = &data.Divider + } + + return discord.SeparatorComponent{ + Divider: divider, + Spacing: discord.SeparatorSpacingSize(data.Spacing), + }, nil + case discord.ComponentTypeContainer: + c := discord.ContainerComponent{ + Components: make([]discord.ContainerSubComponent, 0, len(data.Components)), + AccentColor: data.AccentColor, + Spoiler: data.Spoiler, + } + + for _, component := range data.Components { + parsed, err := m.ParseMessageComponent(component, allowedComponentTypes) + if err != nil { + return nil, err + } + + if containerSubComp, ok := parsed.(discord.ContainerSubComponent); ok { + c.Components = append(c.Components, containerSubComp) + } else { + return nil, fmt.Errorf("component type %T cannot be used as ContainerSubComponent", parsed) + } + } + + return c, nil + default: + return nil, errors.New("invalid component type") + } +} + +func (m *ActionParser) UnparseMessageComponents(data []discord.LayoutComponent) ([]actions.ComponentWithActions, error) { + res := make([]actions.ComponentWithActions, 0, len(data)) + + for _, comp := range data { + parsed, err := m.UnparseMessageComponent(comp) + if err != nil { + return nil, err + } + res = append(res, parsed) + } + + return res, nil +} + +func (m *ActionParser) UnparseMessageComponent(data discord.Component) (actions.ComponentWithActions, error) { + switch c := data.(type) { + case discord.ActionRowComponent: + ar := actions.ComponentWithActions{ + Type: discord.ComponentTypeActionRow, + Components: make([]actions.ComponentWithActions, 0, len(c.Components)), + } + + for _, comp := range c.Components { + parsed, err := m.UnparseMessageComponent(comp) + if err != nil { + return actions.ComponentWithActions{}, err + } + ar.Components = append(ar.Components, parsed) + } + + return ar, nil + case discord.ButtonComponent: + return actions.ComponentWithActions{ + Type: discord.ComponentTypeButton, + Disabled: c.Disabled, + Style: c.Style, + Label: c.Label, + Emoji: c.Emoji, + URL: c.URL, + ActionSetID: strings.TrimPrefix(c.CustomID, "action:"), + }, nil + case discord.StringSelectMenuComponent: + options := make([]actions.ComponentSelectOptionWithActions, 0, len(c.Options)) + for _, option := range c.Options { + options = append(options, actions.ComponentSelectOptionWithActions{ + Label: option.Label, + Description: option.Description, + Emoji: option.Emoji, + Default: option.Default, + ActionSetID: strings.TrimPrefix(option.Value, "action:"), + }) + } + + return actions.ComponentWithActions{ + Type: discord.ComponentTypeStringSelectMenu, + Disabled: c.Disabled, + Placeholder: c.Placeholder, + MinValues: c.MinValues, + MaxValues: c.MaxValues, + Options: options, + }, nil + case discord.SectionComponent: + se := actions.ComponentWithActions{ + Type: discord.ComponentTypeSection, + Components: make([]actions.ComponentWithActions, 0, len(c.Components)), + } + + for _, comp := range c.Components { + parsed, err := m.UnparseMessageComponent(comp) + if err != nil { + return actions.ComponentWithActions{}, err + } + se.Components = append(se.Components, parsed) + } + + if c.Accessory != nil { + parsed, err := m.UnparseMessageComponent(c.Accessory) + if err != nil { + return actions.ComponentWithActions{}, err + } + se.Accessory = &parsed + } + + return se, nil + case discord.TextDisplayComponent: + return actions.ComponentWithActions{ + Type: discord.ComponentTypeTextDisplay, + Content: c.Content, + }, nil + case discord.ThumbnailComponent: + return actions.ComponentWithActions{ + Type: discord.ComponentTypeThumbnail, + Media: &actions.UnfurledMediaItem{URL: c.Media.URL}, + Description: c.Description, + }, nil + case discord.MediaGalleryComponent: + items := make([]actions.ComponentMediaGalleryItem, 0, len(c.Items)) + for _, item := range c.Items { + items = append(items, actions.ComponentMediaGalleryItem{ + Media: actions.UnfurledMediaItem{URL: item.Media.URL}, + Description: item.Description, + Spoiler: item.Spoiler, + }) + } + + return actions.ComponentWithActions{ + Type: discord.ComponentTypeMediaGallery, + Items: items, + }, nil + case discord.FileComponent: + return actions.ComponentWithActions{ + Type: discord.ComponentTypeFile, + File: &actions.UnfurledMediaItem{URL: c.File.URL}, + Spoiler: c.Spoiler, + }, nil + case discord.SeparatorComponent: + var divider bool + if c.Divider != nil { + divider = *c.Divider + } + + return actions.ComponentWithActions{ + Type: discord.ComponentTypeSeparator, + Divider: divider, + Spacing: int(c.Spacing), + }, nil + case discord.ContainerComponent: + components := make([]actions.ComponentWithActions, 0, len(c.Components)) + for _, comp := range c.Components { + parsed, err := m.UnparseMessageComponent(comp) + if err != nil { + return actions.ComponentWithActions{}, err + } + components = append(components, parsed) + } + + return actions.ComponentWithActions{ + Type: discord.ComponentTypeContainer, + Components: components, + AccentColor: c.AccentColor, + Spoiler: c.Spoiler, + }, nil + default: + return actions.ComponentWithActions{}, fmt.Errorf("invalid component type: %T", c) + } +} diff --git a/embedg-service/actions/parser/permissions.go b/embedg-service/actions/parser/permissions.go new file mode 100644 index 000000000..d56597ba6 --- /dev/null +++ b/embedg-service/actions/parser/permissions.go @@ -0,0 +1,192 @@ +package parser + +import ( + "context" + "encoding/json" + "errors" + "fmt" + + "github.com/disgoorg/disgo/discord" + "github.com/merlinfuchs/embed-generator/embedg-service/access" + "github.com/merlinfuchs/embed-generator/embedg-service/actions" + "github.com/merlinfuchs/embed-generator/embedg-service/common" + "github.com/merlinfuchs/embed-generator/embedg-service/store" +) + +func (m *ActionParser) CheckPermissionsForActionSets(actionSets map[string]actions.ActionSet, userID common.ID, guildID common.ID, channelID common.ID) error { + if channelID != 0 { + channel, ok := m.caches.Channel(channelID) + if !ok { + return fmt.Errorf("channel not found in cache") + } + + if channel.GuildID() != guildID { + return fmt.Errorf("Channel %s does not belong to guild %s", channelID, guildID) + } + } + + guild, ok := m.caches.Guild(guildID) + if !ok { + return fmt.Errorf("guild not found in cache") + } + + var channelAccess *access.ChannelAccess + if channelID != 0 { + ca, err := m.accessManager.GetChannelAccessForUser(userID, channelID) + if err != nil { + return err + } + channelAccess = &ca + + if !channelAccess.UserAccess() { + return fmt.Errorf("You have no access to the channel %s", channelID) + } + } + + member, err := m.accessManager.GetGuildMember(guildID, userID) + if err != nil { + return err + } + + memberIsOwner := guild.OwnerID == userID + + highestRolePosition := 0 + var permissions discord.Permissions + + defaultRole, ok := m.caches.Role(guildID, guildID) + if ok { + highestRolePosition = defaultRole.Position + permissions = defaultRole.Permissions + } + + for _, roleID := range member.RoleIDs { + role, ok := m.caches.Role(guildID, roleID) + if ok && role.Position > highestRolePosition { + highestRolePosition = role.Position + permissions |= role.Permissions + } + } + + if channelAccess != nil { + permissions = channelAccess.UserPermissions + } + + var checkActions func(actionSets map[string]actions.ActionSet, nestingLevel int) error + + checkActions = func(actionSets map[string]actions.ActionSet, nestingLevel int) error { + if nestingLevel > 5 { + return fmt.Errorf("You can't nest more than 5 saved messages with actions") + } + + for _, actionSet := range actionSets { + for _, action := range actionSet.Actions { + switch action.Type { + case actions.ActionTypeTextResponse, actions.ActionTypeTextDM, actions.ActionTypeTextEdit: + break + case actions.ActionTypeAddRole, actions.ActionTypeRemoveRole, actions.ActionTypeToggleRole: + if permissions&discord.PermissionManageRoles == 0 { + return fmt.Errorf("You have no permission to manage roles in the channel %s", channelID) + } + + roleID, err := common.ParseID(action.TargetID) + if err != nil { + return fmt.Errorf("Invalid role ID: %s", action.TargetID) + } + + role, ok := m.caches.Role(guildID, roleID) + if !ok { + return fmt.Errorf("Role %s does not exist", action.TargetID) + } + + if !memberIsOwner && role.Position >= highestRolePosition { + return fmt.Errorf("You can not assign the role %s", action.TargetID) + } + break + case actions.ActionTypeSavedMessageResponse, actions.ActionTypeSavedMessageDM, actions.ActionTypeSavedMessageEdit: + msg, err := m.savedMessageStore.GetSavedMessageForGuild(context.TODO(), guildID, action.TargetID) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return fmt.Errorf("Saved message %s does not exist or belongs to a different server", action.TargetID) + } + return err + } + + data := &actions.MessageWithActions{} + err = json.Unmarshal(msg.Data, data) + if err != nil { + return err + } + + return checkActions(data.Actions, nestingLevel+1) + } + } + } + + return nil + } + + return checkActions(actionSets, 0) +} + +func (m *ActionParser) DerivePermissionsForActions(userID common.ID, guildID common.ID, channelID common.ID) (actions.ActionDerivedPermissions, error) { + res := actions.ActionDerivedPermissions{ + UserID: userID, + } + + // TODO?: Refactor and rely on Stateway for this + + if channelID != 0 { + channel, ok := m.caches.Channel(channelID) + if !ok { + return res, fmt.Errorf("channel not found in cache") + } + + if channel.GuildID() != guildID { + return res, fmt.Errorf("Channel %s does not belong to guild %s", channelID, guildID) + } + } + + guild, ok := m.caches.Guild(guildID) + if !ok { + return res, fmt.Errorf("guild not found in cache") + } + + res.GuildIsOwner = guild.OwnerID == userID + + if channelID != 0 { + ca, err := m.accessManager.GetChannelAccessForUser(userID, channelID) + if err != nil { + return res, err + } + res.ChannelPermissions = uint64(ca.UserPermissions) + } + + member, err := m.accessManager.GetGuildMember(guildID, userID) + if err != nil { + return res, err + } + + highestRolePosition := 0 + + defaultRole, ok := m.caches.Role(guildID, guildID) + if ok { + highestRolePosition = defaultRole.Position + res.GuildPermissions = uint64(defaultRole.Permissions) + } + + for _, roleID := range member.RoleIDs { + role, ok := m.caches.Role(guildID, roleID) + if ok && role.Position > highestRolePosition { + highestRolePosition = role.Position + res.GuildPermissions |= uint64(role.Permissions) + } + } + + for role := range m.caches.Roles(guildID) { + if role.Position < highestRolePosition { + res.AllowedRoleIDs = append(res.AllowedRoleIDs, role.ID) + } + } + + return res, nil +} diff --git a/embedg-service/actions/template/base.go b/embedg-service/actions/template/base.go new file mode 100644 index 000000000..a5e8a9dfd --- /dev/null +++ b/embedg-service/actions/template/base.go @@ -0,0 +1,267 @@ +package template + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" + + "errors" + + "github.com/botlabs-gg/yagpdb/v2/lib/template" +) + +func isContainer(v interface{}) bool { + rv, _ := indirect(reflect.ValueOf(v)) + switch rv.Kind() { + case reflect.Array, reflect.Slice, reflect.Map: + return true + default: + return false + } +} + +// Cyclic value detection is modified from encoding/json/encode.go. +const startDetectingCyclesAfter = 250 + +type cyclicValueDetector struct { + ptrLevel uint + ptrSeen map[interface{}]struct{} +} + +func (c *cyclicValueDetector) Check(v reflect.Value) error { + v, _ = indirect(v) + switch v.Kind() { + case reflect.Map: + if c.ptrLevel++; c.ptrLevel > startDetectingCyclesAfter { + ptr := v.Pointer() + if _, ok := c.ptrSeen[ptr]; ok { + return fmt.Errorf("encountered a cycle via %s", v.Type()) + } + c.ptrSeen[ptr] = struct{}{} + } + + it := v.MapRange() + for it.Next() { + if err := c.Check(it.Value()); err != nil { + return err + } + } + c.ptrLevel-- + return nil + case reflect.Array, reflect.Slice: + if c.ptrLevel++; c.ptrLevel > startDetectingCyclesAfter { + ptr := struct { + ptr uintptr + len int + }{v.Pointer(), v.Len()} + if _, ok := c.ptrSeen[ptr]; ok { + return fmt.Errorf("encountered a cycle via %s", v.Type()) + } + c.ptrSeen[ptr] = struct{}{} + } + + for i := 0; i < v.Len(); i++ { + elem := v.Index(i) + if err := c.Check(elem); err != nil { + return err + } + } + c.ptrLevel-- + return nil + default: + return nil + } +} + +func detectCyclicValue(v interface{}) error { + c := &cyclicValueDetector{ptrSeen: make(map[interface{}]struct{})} + return c.Check(reflect.ValueOf(v)) +} + +type Dict map[interface{}]interface{} + +func (d Dict) Set(key interface{}, value interface{}) (string, error) { + d[key] = value + if isContainer(value) { + if err := detectCyclicValue(d); err != nil { + return "", template.UncatchableError(err) + } + } + return "", nil +} + +func (d Dict) Get(key interface{}) interface{} { + out, ok := d[key] + if !ok { + switch key.(type) { + case int: + out = d[ToInt64(key)] + case int64: + out = d[tmplToInt(key)] + } + } + return out +} + +func (d Dict) Del(key interface{}) string { + delete(d, key) + return "" +} + +func (d Dict) HasKey(k interface{}) (ok bool) { + _, ok = d[k] + return +} + +func (d Dict) MarshalJSON() ([]byte, error) { + md := make(map[string]interface{}) + for k, v := range d { + krv := reflect.ValueOf(k) + switch krv.Kind() { + case reflect.String: + md[krv.String()] = v + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + md[strconv.FormatInt(krv.Int(), 10)] = v + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + md[strconv.FormatUint(krv.Uint(), 10)] = v + default: + return nil, fmt.Errorf("cannot encode dict with key type %s; only string and integer keys are supported", krv.Type()) + } + } + return json.Marshal(md) +} + +type SDict map[string]interface{} + +func (d SDict) Set(key string, value interface{}) (string, error) { + d[key] = value + if isContainer(value) { + if err := detectCyclicValue(d); err != nil { + return "", template.UncatchableError(err) + } + } + return "", nil +} + +func (d SDict) Get(key string) interface{} { + return d[key] +} + +func (d SDict) Del(key string) string { + delete(d, key) + return "" +} + +func (d SDict) HasKey(k string) (ok bool) { + _, ok = d[k] + return +} + +type Slice []interface{} + +func (s Slice) Append(item interface{}) (interface{}, error) { + if len(s)+1 > 10000 { + return nil, errors.New("resulting slice exceeds slice size limit") + } + + switch v := item.(type) { + case nil: + result := reflect.Append(reflect.ValueOf(&s).Elem(), reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) + return result.Interface(), nil + default: + result := reflect.Append(reflect.ValueOf(&s).Elem(), reflect.ValueOf(v)) + return result.Interface(), nil + } +} + +func (s Slice) Set(index int, item interface{}) (string, error) { + if index >= len(s) { + return "", errors.New("Index out of bounds") + } + + s[index] = item + if isContainer(item) { + if err := detectCyclicValue(s); err != nil { + return "", template.UncatchableError(err) + } + } + return "", nil +} + +func (s Slice) AppendSlice(slice interface{}) (interface{}, error) { + val, _ := indirect(reflect.ValueOf(slice)) + switch val.Kind() { + case reflect.Slice, reflect.Array: + // this is valid + + default: + return nil, errors.New("value passed is not an array or slice") + } + + if len(s)+val.Len() > 10000 { + return nil, errors.New("resulting slice exceeds slice size limit") + } + + result := reflect.ValueOf(&s).Elem() + for i := 0; i < val.Len(); i++ { + switch v := val.Index(i).Interface().(type) { + case nil: + result = reflect.Append(result, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) + + default: + result = reflect.Append(result, reflect.ValueOf(v)) + } + } + + return result.Interface(), nil +} + +func (s Slice) StringSlice(flag ...bool) interface{} { + strict := false + if len(flag) > 0 { + strict = flag[0] + } + + StringSlice := make([]string, 0, len(s)) + + for _, Sliceval := range s { + switch t := Sliceval.(type) { + case string: + StringSlice = append(StringSlice, t) + + case fmt.Stringer: + if strict { + return nil + } + StringSlice = append(StringSlice, t.String()) + + default: + if strict { + return nil + } + } + } + + return StringSlice +} + +func withOutputLimit(f func(...interface{}) string, limit int) func(...interface{}) (string, error) { + return func(args ...interface{}) (string, error) { + out := f(args...) + if len(out) > limit { + return "", fmt.Errorf("string grew too long: length %d (max %d)", len(out), limit) + } + return out, nil + } +} + +func withOutputLimitF(f func(string, ...interface{}) string, limit int) func(string, ...interface{}) (string, error) { + return func(format string, args ...interface{}) (string, error) { + out := f(format, args...) + if len(out) > limit { + return "", fmt.Errorf("string grew too long: length %d (max %d)", len(out), limit) + } + return out, nil + } +} diff --git a/embedg-service/actions/template/context.go b/embedg-service/actions/template/context.go new file mode 100644 index 000000000..01bb8a718 --- /dev/null +++ b/embedg-service/actions/template/context.go @@ -0,0 +1,212 @@ +package template + +import ( + "bytes" + "fmt" + "io" + "maps" + "strings" + + "github.com/botlabs-gg/yagpdb/v2/lib/template" + "github.com/merlinfuchs/embed-generator/embedg-service/actions" +) + +const DefaultMaxOps = 10000 +const DefaultMaxOutput = 4000 + +const DelimLeft = "{{" +const DelimRight = "}}" + +type TemplateContext struct { + name string + data map[string]interface{} + funcs map[string]interface{} + + MaxOps int + MaxOutput int64 +} + +func NewContext(name string, maxOps int, providers ...ContextProvider) *TemplateContext { + data := make(map[string]interface{}, len(standardDataMap)) + maps.Copy(data, standardDataMap) + + funcs := make(map[string]interface{}, len(standardFuncMap)) + maps.Copy(funcs, standardFuncMap) + + for _, provider := range providers { + provider.ProvideData(data) + provider.ProvideFuncs(funcs) + } + + if maxOps == 0 { + maxOps = DefaultMaxOps + } + + return &TemplateContext{ + name: name, + data: data, + funcs: funcs, + + MaxOps: maxOps, + MaxOutput: DefaultMaxOutput, + } +} + +func (c *TemplateContext) ParseAndExecuteMessage(m *actions.MessageWithActions) error { + var err error + + m.Content, err = c.ParseAndExecute(m.Content) + if err != nil { + return err + } + m.Username, err = c.ParseAndExecute(m.Username) + if err != nil { + return err + } + m.AvatarURL, err = c.ParseAndExecute(m.AvatarURL) + if err != nil { + return err + } + + for _, embed := range m.Embeds { + embed.Title, err = c.ParseAndExecute(embed.Title) + if err != nil { + return err + } + embed.Description, err = c.ParseAndExecute(embed.Description) + if err != nil { + return err + } + embed.URL, err = c.ParseAndExecute(embed.URL) + if err != nil { + return err + } + + if embed.Author != nil { + embed.Author.Name, err = c.ParseAndExecute(embed.Author.Name) + if err != nil { + return err + } + embed.Author.URL, err = c.ParseAndExecute(embed.Author.URL) + if err != nil { + return err + } + embed.Author.IconURL, err = c.ParseAndExecute(embed.Author.IconURL) + if err != nil { + return err + } + } + + if embed.Footer != nil { + embed.Footer.Text, err = c.ParseAndExecute(embed.Footer.Text) + if err != nil { + return err + } + embed.Footer.IconURL, err = c.ParseAndExecute(embed.Footer.IconURL) + if err != nil { + return err + } + } + + if embed.Image != nil { + embed.Image.URL, err = c.ParseAndExecute(embed.Image.URL) + if err != nil { + return err + } + } + + if embed.Thumbnail != nil { + embed.Thumbnail.URL, err = c.ParseAndExecute(embed.Thumbnail.URL) + if err != nil { + return err + } + } + + for _, field := range embed.Fields { + field.Name, err = c.ParseAndExecute(field.Name) + if err != nil { + return err + } + field.Value, err = c.ParseAndExecute(field.Value) + if err != nil { + return err + } + } + } + + for _, row := range m.Components { + for _, component := range row.Components { + component.Label, err = c.ParseAndExecute(component.Label) + if err != nil { + return err + } + + component.URL, err = c.ParseAndExecute(component.URL) + if err != nil { + return err + } + + component.Placeholder, err = c.ParseAndExecute(component.Placeholder) + if err != nil { + return err + } + + for _, option := range component.Options { + option.Label, err = c.ParseAndExecute(option.Label) + if err != nil { + return err + } + + option.Description, err = c.ParseAndExecute(option.Description) + if err != nil { + return err + } + } + } + } + + return nil +} + +func (c *TemplateContext) ParseAndExecute(text string) (string, error) { + if text == "" || !strings.Contains(text, DelimLeft) { + return text, nil + } + + tmpl, err := c.Parse(text) + if err != nil { + return "", err + } + + return c.Execute(tmpl) +} + +func (c *TemplateContext) Parse(text string) (*template.Template, error) { + return template.New(c.name). + Delims(DelimLeft, DelimRight). + Funcs(c.funcs). + Parse(text) +} + +func (c *TemplateContext) Execute(tmpl *template.Template) (string, error) { + tmpl = tmpl.MaxOps(c.MaxOps) + + var buf bytes.Buffer + w := LimitWriter(&buf, c.MaxOutput) + + err := tmpl.Execute(w, c.data) + if err != nil { + if err == io.ErrShortWrite { + err = fmt.Errorf("output exceeded %d characters", c.MaxOutput) + } + return "", err + } + + res := buf.String() + + return res, nil +} + +func (c *TemplateContext) Set(key string, value interface{}) { + c.data[key] = value +} diff --git a/embedg-service/actions/template/data.go b/embedg-service/actions/template/data.go new file mode 100644 index 000000000..cbab19f04 --- /dev/null +++ b/embedg-service/actions/template/data.go @@ -0,0 +1,544 @@ +package template + +import ( + "fmt" + "time" + + "github.com/disgoorg/disgo/cache" + "github.com/disgoorg/disgo/discord" + "github.com/merlinfuchs/embed-generator/embedg-service/common" +) + +var standardDataMap = map[string]interface{}{} + +type InteractionData struct { + caches cache.Caches + i discord.Interaction +} + +func NewInteractionData(caches cache.Caches, i discord.Interaction) *InteractionData { + return &InteractionData{ + caches: caches, + i: i, + } +} + +func (d *InteractionData) User() interface{} { + if d.i.Member() != nil { + res := NewMemberData(d.caches, *d.i.GuildID(), d.i.Member().Member) + return &res + } + + return NewUserData(d.i.User()) +} + +func (d *InteractionData) Member() *MemberData { + if d.i.Member() == nil { + return nil + } + + return NewMemberData(d.caches, *d.i.GuildID(), d.i.Member().Member) +} + +func (d *InteractionData) Command() *CommandData { + if d.i.Type() != discord.InteractionTypeApplicationCommand { + return nil + } + + cmdInteraction, ok := d.i.(discord.ApplicationCommandInteraction) + if !ok { + return nil + } + + return NewCommandData(d.caches, *d.i.GuildID(), cmdInteraction.Data) +} + +type UserData struct { + u discord.User +} + +func NewUserData(u discord.User) *UserData { + return &UserData{u: u} +} + +func (d *UserData) String() string { + return d.Mention() +} + +func (d *UserData) ID() string { + return d.u.ID.String() +} + +func (d *UserData) Name() string { + if d.u.GlobalName != nil { + return *d.u.GlobalName + } + + return d.u.Username +} + +func (d *UserData) Username() string { + return d.u.Username +} + +func (d *UserData) GlobalName() string { + if d.u.GlobalName != nil { + return *d.u.GlobalName + } + + return "" +} + +func (d *UserData) Discriminator() string { + return d.u.Discriminator +} + +func (d *UserData) Avatar() string { + if d.u.Avatar != nil { + return *d.u.Avatar + } + + return "" +} + +func (d *UserData) Banner() string { + if d.u.Banner != nil { + return *d.u.Banner + } + + return "" +} + +func (d *UserData) Mention() string { + return d.u.Mention() +} + +func (d *UserData) AvatarURL() string { + avatarURL := d.u.AvatarURL(discord.WithSize(512)) + if avatarURL == nil { + return "" + } + + return *avatarURL +} + +func (d *UserData) BannerURL() string { + bannerURL := d.u.BannerURL(discord.WithSize(1024)) + if bannerURL == nil { + return "" + } + + return *bannerURL +} + +type MemberData struct { + UserData + caches cache.Caches + guildID common.ID + m discord.Member +} + +func NewMemberData(caches cache.Caches, guildID common.ID, m discord.Member) *MemberData { + return &MemberData{ + UserData: UserData{m.User}, + caches: caches, + guildID: guildID, + m: m, + } +} + +func (d *MemberData) Nick() string { + if d.m.Nick != nil { + return *d.m.Nick + } + + return "" +} + +func (d *MemberData) Roles() []*RoleData { + res := make([]*RoleData, len(d.m.RoleIDs)) + for i, roleID := range d.m.RoleIDs { + res[i] = NewRoleData(d.caches, d.guildID, roleID, nil) + } + + return res +} + +func (d *MemberData) JoinedAt() time.Time { + if d.m.JoinedAt != nil { + return *d.m.JoinedAt + } + + return time.Time{} +} + +func (d *MemberData) Name() string { + if d.m.Nick != nil { + return *d.m.Nick + } + + return d.UserData.Name() +} + +func (d *MemberData) Avatar() string { + if d.m.Avatar != nil { + return *d.m.Avatar + } + + return d.UserData.Avatar() +} + +func (d *MemberData) AvatarURL() string { + return d.m.EffectiveAvatarURL(discord.WithSize(512)) +} + +type CommandData struct { + caches cache.Caches + guildID common.ID + c discord.ApplicationCommandInteractionData +} + +func NewCommandData(caches cache.Caches, guildID common.ID, c discord.ApplicationCommandInteractionData) *CommandData { + return &CommandData{ + caches: caches, + guildID: guildID, + c: c, + } +} + +func (d *CommandData) String() string { + return d.Mention() +} + +func (d *CommandData) ID() string { + return d.c.CommandID().String() +} + +func (d *CommandData) Name() string { + return d.c.CommandName() +} + +func (d *CommandData) Mention() string { + return fmt.Sprintf("", d.c.CommandName(), d.c.CommandID().String()) +} + +func (d *CommandData) Options() map[string]interface{} { + res := make(map[string]interface{}) + + if slashCMD, ok := d.c.(discord.SlashCommandInteractionData); ok { + for _, opt := range slashCMD.Options { + res[opt.Name] = NewCommandOptionData(d.caches, d.guildID, slashCMD, opt) + } + } + + return res +} + +func (d *CommandData) Args() map[string]interface{} { + return d.Options() +} + +func NewCommandOptionData(caches cache.Caches, guildID common.ID, c discord.SlashCommandInteractionData, o discord.SlashCommandOption) interface{} { + switch o.Type { + case discord.ApplicationCommandOptionTypeString: + return o.String() + case discord.ApplicationCommandOptionTypeInt: + return o.Int() + case discord.ApplicationCommandOptionTypeBool: + return o.Bool() + case discord.ApplicationCommandOptionTypeUser: + userID := o.Snowflake() + resolved, ok := c.Resolved.Users[userID] + if ok { + return UserData{resolved} + } + return UserData{u: discord.User{ID: userID}} + case discord.ApplicationCommandOptionTypeChannel: + channelID := o.Snowflake() + return NewChannelData(caches, channelID, nil) + case discord.ApplicationCommandOptionTypeRole: + roleID := o.Snowflake() + resolved, ok := c.Resolved.Roles[roleID] + if ok { + return NewRoleData(caches, guildID, roleID, &resolved) + } + return NewRoleData(caches, guildID, roleID, nil) + case discord.ApplicationCommandOptionTypeFloat: + return o.Float() + case discord.ApplicationCommandOptionTypeAttachment: + attachmentID := o.Snowflake() + resolved, ok := c.Resolved.Attachments[attachmentID] + if ok { + return NewAttachmentData(resolved) + } + return NewAttachmentData(discord.Attachment{ID: attachmentID}) + } + + return nil +} + +type GuildData struct { + caches cache.Caches + guildID common.ID + guild *discord.Guild +} + +func NewGuildData(caches cache.Caches, guildID common.ID, g *discord.Guild) *GuildData { + return &GuildData{ + caches: caches, + guildID: guildID, + guild: g, + } +} + +func (d *GuildData) ensureGuild() error { + if d.guild != nil { + return nil + } + + guild, ok := d.caches.Guild(d.guildID) + if !ok { + return fmt.Errorf("guild not found in cache") + } + + d.guild = &guild + return nil +} + +func (d *GuildData) String() string { + if err := d.ensureGuild(); err != nil { + return d.guildID.String() + } + return d.guild.Name +} + +func (d *GuildData) ID() string { + return d.guildID.String() +} + +func (d *GuildData) Name() (string, error) { + if err := d.ensureGuild(); err != nil { + return "", err + } + + return d.guild.Name, nil +} + +func (d *GuildData) Description() (string, error) { + if err := d.ensureGuild(); err != nil { + return "", err + } + + if d.guild.Description != nil { + return *d.guild.Description, nil + } + + return "", nil +} + +func (d *GuildData) Icon() (string, error) { + if err := d.ensureGuild(); err != nil { + return "", err + } + + if d.guild.Icon != nil { + return *d.guild.Icon, nil + } + + return "", nil +} + +func (d *GuildData) IconURL() (string, error) { + if err := d.ensureGuild(); err != nil { + return "", err + } + + iconURL := d.guild.IconURL(discord.WithSize(512)) + if iconURL == nil { + return "", nil + } + + return *iconURL, nil +} + +func (d *GuildData) Banner() (string, error) { + if err := d.ensureGuild(); err != nil { + return "", err + } + + if d.guild.Banner != nil { + return *d.guild.Banner, nil + } + + return "", nil +} + +func (d *GuildData) BannerURL() (string, error) { + if err := d.ensureGuild(); err != nil { + return "", err + } + + bannerURL := d.guild.BannerURL(discord.WithSize(1024)) + if bannerURL == nil { + return "", nil + } + + return *bannerURL, nil +} + +func (d *GuildData) MemberCount() (int, error) { + if err := d.ensureGuild(); err != nil { + return 0, err + } + + return d.guild.MemberCount, nil +} + +func (d *GuildData) BoostCount() (int, error) { + if err := d.ensureGuild(); err != nil { + return 0, err + } + + return d.guild.PremiumSubscriptionCount, nil +} + +func (d *GuildData) BoostLevel() (int, error) { + if err := d.ensureGuild(); err != nil { + return 0, err + } + + return int(d.guild.PremiumTier), nil +} + +type ChannelData struct { + caches cache.Caches + channelID common.ID + channel discord.GuildChannel +} + +func NewChannelData(caches cache.Caches, channelID common.ID, c discord.GuildChannel) *ChannelData { + return &ChannelData{ + caches: caches, + channelID: channelID, + channel: c, + } +} + +func (d *ChannelData) ensureChannel() error { + if d.channel != nil { + return nil + } + + channel, ok := d.caches.Channel(d.channelID) + if !ok { + return fmt.Errorf("channel not found in cache") + } + + d.channel = channel + return nil +} + +func (d *ChannelData) String() string { + return d.Mention() +} + +func (d *ChannelData) ID() string { + return d.channelID.String() +} + +func (d *ChannelData) Name() (string, error) { + if err := d.ensureChannel(); err != nil { + return "", err + } + + return d.channel.Name(), nil +} + +func (d *ChannelData) Mention() string { + return fmt.Sprintf("<#%s>", d.channelID) +} + +func (d *ChannelData) Topic() (string, error) { + if err := d.ensureChannel(); err != nil { + return "", err + } + + if text, ok := d.channel.(discord.GuildTextChannel); ok { + topic := text.Topic() + if topic != nil { + return *topic, nil + } + } + + return "", nil +} + +type RoleData struct { + caches cache.Caches + guildID common.ID + roleID common.ID + role *discord.Role +} + +func NewRoleData(caches cache.Caches, guildID common.ID, roleID common.ID, role *discord.Role) *RoleData { + return &RoleData{ + caches: caches, + guildID: guildID, + roleID: roleID, + role: role, + } +} + +func (d *RoleData) ensureRole() error { + if d.role != nil { + return nil + } + + role, ok := d.caches.Role(d.guildID, d.roleID) + if !ok { + return fmt.Errorf("role not found in cache") + } + + d.role = &role + return nil +} + +func (d *RoleData) String() string { + return d.Mention() +} + +func (d *RoleData) ID() string { + return d.roleID.String() +} + +func (d *RoleData) Mention() string { + return fmt.Sprintf("<@&%s>", d.roleID.String()) +} + +func (d *RoleData) Name() (string, error) { + if err := d.ensureRole(); err != nil { + return "", err + } + + return d.role.Name, nil +} + +type AttachmentData struct { + a discord.Attachment +} + +func NewAttachmentData(a discord.Attachment) *AttachmentData { + return &AttachmentData{a: a} +} + +func (d *AttachmentData) String() string { + return d.URL() +} + +func (d *AttachmentData) ID() string { + return d.a.ID.String() +} + +func (d *AttachmentData) URL() string { + return d.a.URL +} diff --git a/embedg-service/actions/template/func.go b/embedg-service/actions/template/func.go new file mode 100644 index 000000000..4de451573 --- /dev/null +++ b/embedg-service/actions/template/func.go @@ -0,0 +1,1202 @@ +package template + +import ( + "encoding/json" + "errors" + "fmt" + "math" + "math/rand" + "net/url" + "reflect" + "regexp" + "strconv" + "strings" + "time" +) + +var standardFuncMap = map[string]interface{}{ + // conversion functions + "toString": ToString, + "toInt": tmplToInt, + "toInt64": ToInt64, + "toFloat": ToFloat64, + "toRune": ToRune, + "toByte": ToByte, + + // string manipulation + "hasPrefix": strings.HasPrefix, + "hasSuffix": strings.HasSuffix, + "joinStr": joinStrings, + "lower": strings.ToLower, + "slice": slice, + "split": strings.Split, + "title": strings.Title, + "trimSpace": strings.TrimSpace, + "upper": strings.ToUpper, + "urlescape": url.PathEscape, + "urlunescape": url.PathUnescape, + + // regexp + "reQuoteMeta": regexp.QuoteMeta, + + // math + "add": add, + "cbrt": tmplCbrt, + "div": tmplDiv, + "fdiv": tmplFDiv, + "log": tmplLog, + "mathConst": tmplMathConstant, + "max": tmplMax, + "min": tmplMin, + "mod": tmplMod, + "mult": tmplMult, + "pow": tmplPow, + "round": tmplRound, + "roundCeil": tmplRoundCeil, + "roundEven": tmplRoundEven, + "roundFloor": tmplRoundFloor, + "sqrt": tmplSqrt, + "sub": tmplSub, + + // bitwise ops + "bitwiseAnd": tmplBitwiseAnd, + "bitwiseOr": tmplBitwiseOr, + "bitwiseXor": tmplBitwiseXor, + "bitwiseNot": tmplBitwiseNot, + "bitwiseAndNot": tmplBitwiseAndNot, + "bitwiseLeftShift": tmplBitwiseLeftShift, + "bitwiseRightShift": tmplBitwiseRightShift, + + // misc + "humanizeThousands": tmplHumanizeThousands, + "dict": Dictionary, + "sdict": StringKeyDictionary, + "structToSdict": StructToSdict, + "cslice": CreateSlice, + "kindOf": KindOf, + + "in": in, + "inFold": inFold, + "json": tmplJson, + "jsonToSdict": tmplJSONToSDict, + "randInt": randInt, + "seq": sequence, + + "shuffle": shuffle, + + // time functions + "currentTime": tmplCurrentTime, + "parseTime": tmplParseTime, + "formatTime": tmplFormatTime, + "loadLocation": time.LoadLocation, + "newDate": tmplNewDate, + "timestampToTime": tmplTimestampToTime, + "weekNumber": tmplWeekNumber, +} + +// dictionary creates a map[string]interface{} from the given parameters by +// walking the parameters and treating them as key-value pairs. The number +// of parameters must be even. +func Dictionary(values ...interface{}) (Dict, error) { + if len(values) == 1 { + val, isNil := indirect(reflect.ValueOf(values[0])) + if isNil || values[0] == nil { + return nil, errors.New("dict: nil value passed") + } + + if Dict, ok := val.Interface().(Dict); ok { + return Dict, nil + } + + switch val.Kind() { + case reflect.Map: + iter := val.MapRange() + mapCopy := make(map[interface{}]interface{}) + for iter.Next() { + mapCopy[iter.Key().Interface()] = iter.Value().Interface() + } + return Dict(mapCopy), nil + default: + return nil, errors.New("cannot convert data of type: " + reflect.TypeOf(values[0]).String()) + } + + } + + if len(values)%2 != 0 { + return nil, errors.New("invalid dict call") + } + + dict := make(map[interface{}]interface{}, len(values)/2) + for i := 0; i < len(values); i += 2 { + key := values[i] + dict[key] = values[i+1] + } + + return Dict(dict), nil +} + +func StringKeyDictionary(values ...interface{}) (SDict, error) { + + if len(values) == 1 { + val, isNil := indirect(reflect.ValueOf(values[0])) + if isNil || values[0] == nil { + return nil, errors.New("Sdict: nil value passed") + } + + if sdict, ok := val.Interface().(SDict); ok { + return sdict, nil + } + + switch val.Kind() { + case reflect.Map: + iter := val.MapRange() + mapCopy := make(map[string]interface{}) + for iter.Next() { + + key, isNil := indirect(iter.Key()) + if isNil { + return nil, errors.New("map with nil key encountered") + } + if key.Kind() == reflect.String { + mapCopy[key.String()] = iter.Value().Interface() + } else { + return nil, errors.New("map has non string key of type: " + key.Type().String()) + } + } + return SDict(mapCopy), nil + default: + return nil, errors.New("cannot convert data of type: " + reflect.TypeOf(values[0]).String()) + } + + } + + if len(values)%2 != 0 { + return nil, errors.New("invalid dict call") + } + dict := make(map[string]interface{}, len(values)/2) + for i := 0; i < len(values); i += 2 { + key := values[i] + s, ok := key.(string) + if !ok { + return nil, errors.New("Only string keys supported in sdict") + } + + dict[s] = values[i+1] + } + + return SDict(dict), nil +} + +func KindOf(input interface{}, flag ...bool) (string, error) { //flag used only for indirect vs direct for now. + + switch len(flag) { + + case 0: + return reflect.ValueOf(input).Kind().String(), nil + case 1: + if flag[0] { + val, isNil := indirect(reflect.ValueOf(input)) + if isNil || input == nil { + return "invalid", nil + } + return val.Kind().String(), nil + } + return reflect.ValueOf(input).Kind().String(), nil + default: + return "", errors.New("Too many flags") + } +} + +func StructToSdict(value interface{}) (SDict, error) { + val, isNil := indirect(reflect.ValueOf(value)) + typeOfS := val.Type() + if isNil || value == nil { + return nil, errors.New("Expected - struct, got - Nil ") + } + + if val.Kind() != reflect.Struct { + return nil, errors.New(fmt.Sprintf("Expected - struct, got - %s", val.Type().String())) + } + + fields := make(map[string]interface{}) + for i := 0; i < val.NumField(); i++ { + curr := val.Field(i) + if curr.CanInterface() { + fields[typeOfS.Field(i).Name] = curr.Interface() + } + } + return SDict(fields), nil + +} + +func CreateSlice(values ...interface{}) (Slice, error) { + slice := make([]interface{}, len(values)) + copy(slice, values) + return Slice(slice), nil +} + +// indirect is taken from 'text/template/exec.go' +func indirect(v reflect.Value) (rv reflect.Value, isNil bool) { + for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() { + if v.IsNil() { + return v, true + } + if v.Kind() == reflect.Interface && v.NumMethod() > 0 { + break + } + } + return v, false +} + +// in returns whether v is in the set l. l may be an array or slice. +func in(l interface{}, v interface{}) bool { + lv, _ := indirect(reflect.ValueOf(l)) + vv := reflect.ValueOf(v) + + if !reflect.ValueOf(vv).IsZero() { + switch lv.Kind() { + case reflect.Array, reflect.Slice: + for i := 0; i < lv.Len(); i++ { + lvv := lv.Index(i) + lvv, isNil := indirect(lvv) + if isNil { + continue + } + switch lvv.Kind() { + case reflect.String: + if vv.Type() == lvv.Type() && vv.String() == lvv.String() { + return true + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch vv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if vv.Int() == lvv.Int() { + return true + } + } + case reflect.Float32, reflect.Float64: + switch vv.Kind() { + case reflect.Float32, reflect.Float64: + if vv.Float() == lvv.Float() { + return true + } + } + } + } + case reflect.String: + if vv.Type() == lv.Type() && strings.Contains(lv.String(), vv.String()) { + return true + } + } + } + + return false +} + +// in returns whether v is in the set l. l may only be a slice of strings, or a string, v may only be a string +// it differs from "in" because its case insensitive +func inFold(l interface{}, v string) bool { + lv, _ := indirect(reflect.ValueOf(l)) + vv := reflect.ValueOf(v) + + switch lv.Kind() { + case reflect.Array, reflect.Slice: + for i := 0; i < lv.Len(); i++ { + lvv := lv.Index(i) + lvv, isNil := indirect(lvv) + if isNil { + continue + } + switch lvv.Kind() { + case reflect.String: + if vv.Type() == lvv.Type() && strings.EqualFold(vv.String(), lvv.String()) { + return true + } + } + } + case reflect.String: + if vv.Type() == lv.Type() && strings.Contains(strings.ToLower(lv.String()), strings.ToLower(vv.String())) { + return true + } + } + + return false +} + +func add(args ...interface{}) interface{} { + if len(args) < 1 { + return 0 + } + + switch args[0].(type) { + case float32, float64: + sumF := float64(0) + for _, v := range args { + sumF += ToFloat64(v) + } + return sumF + default: + sumI := 0 + for _, v := range args { + sumI += tmplToInt(v) + } + return sumI + } +} + +func tmplSub(args ...interface{}) interface{} { + if len(args) < 1 { + return 0 + } + + switch args[0].(type) { + case float32, float64: + subF := ToFloat64(args[0]) + for i, v := range args { + if i == 0 { + continue + } + subF -= ToFloat64(v) + } + return subF + default: + subI := tmplToInt(args[0]) + for i, v := range args { + if i == 0 { + continue + } + subI -= tmplToInt(v) + } + return subI + } +} + +var mathConstantsMap = map[string]float64{ + //base + "e": math.E, + "pi": math.Pi, + "phi": math.Phi, + + // square roots + "sqrt2": math.Sqrt2, + "sqrte": math.SqrtE, + "sqrtpi": math.SqrtPi, + "sqrtphi": math.SqrtPhi, + + // logarithms + "ln2": math.Ln2, + "log2e": math.Log2E, + "ln10": math.Ln10, + "log10e": math.Log10E, + + // floating-point limit values + "maxfloat32": math.MaxFloat32, + "smallestnonzerofloat32": math.SmallestNonzeroFloat32, + "maxfloat64": math.MaxFloat64, + "smallestnonzerofloat64": math.SmallestNonzeroFloat64, + + // integer limit values + "maxint": math.MaxInt, + "minint": math.MinInt, + "maxint8": math.MaxInt8, + "minint8": math.MinInt8, + "maxint16": math.MaxInt16, + "minint16": math.MinInt16, + "maxint32": math.MaxInt32, + "minint32": math.MinInt32, + "maxint64": math.MaxInt64, + "minint64": math.MinInt64, + "maxuint": math.MaxUint, + "maxuint8": math.MaxUint8, + "maxuint16": math.MaxUint16, + "maxuint32": math.MaxUint32, + "maxuint64": math.MaxUint64, +} + +func tmplMathConstant(arg string) float64 { + constant := mathConstantsMap[strings.ToLower(arg)] + if constant == 0 { + return math.NaN() + } + + return constant +} + +func tmplMult(args ...interface{}) interface{} { + if len(args) < 1 { + return 0 + } + + switch args[0].(type) { + case float32, float64: + sumF := ToFloat64(args[0]) + for i, v := range args { + if i == 0 { + continue + } + + sumF *= ToFloat64(v) + } + return sumF + default: + sumI := tmplToInt(args[0]) + for i, v := range args { + if i == 0 { + continue + } + + sumI *= tmplToInt(v) + } + return sumI + } +} + +func tmplDiv(args ...interface{}) interface{} { + if len(args) < 1 { + return 0 + } + + switch args[0].(type) { + case float32, float64: + sumF := ToFloat64(args[0]) + for i, v := range args { + if i == 0 { + continue + } + + sumF /= ToFloat64(v) + } + return sumF + default: + sumI := tmplToInt(args[0]) + for i, v := range args { + if i == 0 { + continue + } + + sumI /= tmplToInt(v) + } + return sumI + } +} + +func tmplMod(args ...interface{}) float64 { + if len(args) != 2 { + return math.NaN() + } + + return math.Mod(ToFloat64(args[0]), ToFloat64(args[1])) +} + +func tmplFDiv(args ...interface{}) interface{} { + if len(args) < 1 { + return 0 + } + + sumF := ToFloat64(args[0]) + for i, v := range args { + if i == 0 { + continue + } + + sumF /= ToFloat64(v) + } + + return sumF +} + +func tmplSqrt(arg interface{}) float64 { + switch arg.(type) { + case int, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64: + return math.Sqrt(ToFloat64(arg)) + default: + return math.Sqrt(-1) + } +} + +func tmplCbrt(arg interface{}) float64 { + switch arg.(type) { + case int, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64: + return math.Cbrt(ToFloat64(arg)) + default: + return math.NaN() + } +} + +func tmplPow(argX, argY interface{}) float64 { + var xyValue float64 + var xySlice []float64 + + switchSlice := []interface{}{argX, argY} + + for _, v := range switchSlice { + switch v.(type) { + case int, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64: + xyValue = ToFloat64(v) + default: + xyValue = math.NaN() + } + xySlice = append(xySlice, xyValue) + } + return math.Pow(xySlice[0], xySlice[1]) +} + +func tmplMax(argX, argY interface{}) float64 { + var xyValue float64 + var xySlice []float64 + + switchSlice := []interface{}{argX, argY} + + for _, v := range switchSlice { + switch v.(type) { + case int, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64: + xyValue = ToFloat64(v) + default: + xyValue = math.NaN() + } + xySlice = append(xySlice, xyValue) + } + return math.Max(xySlice[0], xySlice[1]) +} + +func tmplMin(argX, argY interface{}) float64 { + var xyValue float64 + var xySlice []float64 + + switchSlice := []interface{}{argX, argY} + + for _, v := range switchSlice { + switch v.(type) { + case int, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64: + xyValue = ToFloat64(v) + default: + xyValue = math.NaN() + } + xySlice = append(xySlice, xyValue) + } + return math.Min(xySlice[0], xySlice[1]) +} + +/* +tmplLog is a function for templates using (log base of x = logarithm) as return value. +It is using natural logarithm as default to change the base. +*/ +func tmplLog(arguments ...interface{}) (float64, error) { + var x, base, logarithm float64 + + x = ToFloat64(arguments[0]) + + if len(arguments) < 1 || len(arguments) > 2 { + return 0, errors.New("wrong number of arguments") + } else if len(arguments) == 1 { + base = math.E + } else { + base = ToFloat64(arguments[1]) + } + /*In an exponential function, the base is always defined to be positive, + but can't be equal to 1. Because of that also x can't be a negative.*/ + if base == 1 || base <= 0 { + logarithm = math.NaN() + } else if base == math.E { + logarithm = math.Log(x) + } else { + logarithm = math.Log(x) / math.Log(base) + } + + return logarithm, nil +} + +func tmplBitwiseAnd(arg1, arg2 interface{}) int { + return tmplToInt(arg1) & tmplToInt(arg2) +} + +func tmplBitwiseOr(args ...interface{}) (res int) { + for _, arg := range args { + res |= tmplToInt(arg) + } + return +} + +func tmplBitwiseXor(arg1, arg2 interface{}) int { + return tmplToInt(arg1) ^ tmplToInt(arg2) +} + +func tmplBitwiseNot(arg interface{}) int { + return ^tmplToInt(arg) +} + +func tmplBitwiseAndNot(arg1, arg2 interface{}) int { + return tmplToInt(arg1) &^ tmplToInt(arg2) +} + +func tmplBitwiseLeftShift(arg1, arg2 interface{}) int { + return tmplToInt(arg1) << tmplToInt(arg2) +} + +func tmplBitwiseRightShift(arg1, arg2 interface{}) int { + return tmplToInt(arg1) >> tmplToInt(arg2) +} + +// tmplHumanizeThousands comma separates thousands +func tmplHumanizeThousands(input interface{}) string { + var f1, f2 string + + i := tmplToInt(input) + if i < 0 { + i = i * -1 + f2 = "-" + } + str := strconv.Itoa(i) + + idx := 0 + for i = len(str) - 1; i >= 0; i-- { + idx++ + if idx == 4 { + idx = 1 + f1 = f1 + "," + } + f1 = f1 + string(str[i]) + } + + for i = len(f1) - 1; i >= 0; i-- { + f2 = f2 + string(f1[i]) + } + return f2 +} + +func randInt(args ...interface{}) (int, error) { + min := int64(0) + max := int64(10) + if len(args) >= 2 { + min = ToInt64(args[0]) + max = ToInt64(args[1]) + } else if len(args) == 1 { + max = ToInt64(args[0]) + } + + diff := max - min + if diff <= 0 { + return 0, errors.New("start must be strictly less than stop") + } + + r := rand.Int63n(diff) + return int(r + min), nil +} + +func tmplRound(args ...interface{}) float64 { + if len(args) < 1 { + return 0 + } + return math.Round(ToFloat64(args[0])) +} + +func tmplRoundCeil(args ...interface{}) float64 { + if len(args) < 1 { + return 0 + } + return math.Ceil(ToFloat64(args[0])) +} + +func tmplRoundFloor(args ...interface{}) float64 { + if len(args) < 1 { + return 0 + } + return math.Floor(ToFloat64(args[0])) +} + +func tmplRoundEven(args ...interface{}) float64 { + if len(args) < 1 { + return 0 + } + return math.RoundToEven(ToFloat64(args[0])) +} + +var ErrStringTooLong = errors.New("String is too long (max 1MB)") + +const MaxStringLength = 1000000 + +func joinStrings(sep string, args ...interface{}) (string, error) { + + var builder strings.Builder + + for _, v := range args { + if builder.Len() != 0 { + builder.WriteString(sep) + } + + switch t := v.(type) { + + case string: + builder.WriteString(t) + + case int, uint, int32, uint32, int64, uint64: + builder.WriteString(ToString(v)) + + case float64: + builder.WriteString(fmt.Sprintf("%g", v)) + + case fmt.Stringer: + builder.WriteString(t.String()) + + default: + cast, ok := castToStringSlice(reflect.ValueOf(v)) + if !ok { + break + } + + for j, s := range cast { + if j != 0 { + builder.WriteString(sep) + } + + builder.WriteString(s) + if builder.Len() > MaxStringLength { + return "", ErrStringTooLong + } + } + } + + if builder.Len() > MaxStringLength { + return "", ErrStringTooLong + } + + } + + return builder.String(), nil +} + +var stringSliceType = reflect.TypeOf([]string(nil)) + +func castToStringSlice(rv reflect.Value) ([]string, bool) { + rv, _ = indirect(rv) + switch rv.Kind() { + case reflect.Array, reflect.Slice: + // ok + default: + return nil, false + } + + // fast path + if rv.Type() == stringSliceType { + return rv.Interface().([]string), true + } + + ret := make([]string, rv.Len()) + for i := 0; i < rv.Len(); i++ { + irv, _ := indirect(rv.Index(i)) + if irv.Kind() != reflect.String { + return nil, false + } + ret[i] = irv.String() + } + return ret, true +} + +func sequence(start, stop int) ([]int, error) { + + if stop < start { + return nil, errors.New("stop is less than start?") + } + + if stop-start > 10000 { + return nil, errors.New("Sequence max length is 10000") + } + + out := make([]int, stop-start) + + ri := 0 + for i := start; i < stop; i++ { + out[ri] = i + ri++ + } + return out, nil +} + +// shuffle returns the given rangeable list in a randomised order. +func shuffle(seq interface{}) (interface{}, error) { + if seq == nil { + return nil, errors.New("both count and seq must be provided") + } + + seqv := reflect.ValueOf(seq) + seqv, isNil := indirect(seqv) + if isNil { + return nil, errors.New("can't iterate over a nil value") + } + + if seqv.Kind() != reflect.Slice { + return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String()) + } + + shuffled := reflect.MakeSlice(seqv.Type(), seqv.Len(), seqv.Len()) + + rand.Seed(time.Now().UTC().UnixNano()) + randomIndices := rand.Perm(seqv.Len()) + + for index, value := range randomIndices { + shuffled.Index(value).Set(seqv.Index(index)) + } + + return shuffled.Interface(), nil +} + +func tmplToInt(from interface{}) int { + switch t := from.(type) { + case int: + return t + case int32: + return int(t) + case int64: + return int(t) + case float32: + return int(t) + case float64: + return int(t) + case uint: + return int(t) + case uint8: + return int(t) + case uint32: + return int(t) + case uint64: + return int(t) + case string: + parsed, _ := strconv.ParseInt(t, 10, 64) + return int(parsed) + case time.Duration: + return int(t) + case time.Month: + return int(t) + case time.Weekday: + return int(t) + default: + return 0 + } +} + +func ToInt64(from interface{}) int64 { + switch t := from.(type) { + case int: + return int64(t) + case int32: + return int64(t) + case int64: + return int64(t) + case float32: + return int64(t) + case float64: + return int64(t) + case uint: + return int64(t) + case uint32: + return int64(t) + case uint64: + return int64(t) + case string: + parsed, _ := strconv.ParseInt(t, 10, 64) + return parsed + case time.Duration: + return int64(t) + case time.Month: + return int64(t) + case time.Weekday: + return int64(t) + default: + return 0 + } +} + +func ToString(from interface{}) string { + switch t := from.(type) { + case int: + return strconv.Itoa(t) + case int32: + return strconv.FormatInt(int64(t), 10) + case int64: + return strconv.FormatInt(t, 10) + case float32: + return strconv.FormatFloat(float64(t), 'E', -1, 32) + case float64: + return strconv.FormatFloat(t, 'E', -1, 64) + case uint: + return strconv.FormatUint(uint64(t), 10) + case uint32: + return strconv.FormatUint(uint64(t), 10) + case uint64: + return strconv.FormatUint(uint64(t), 10) + case []rune: + return string(t) + case []byte: + return string(t) + case fmt.Stringer: + return t.String() + case string: + return t + default: + return "" + } +} + +func ToFloat64(from interface{}) float64 { + switch t := from.(type) { + case int: + return float64(t) + case int32: + return float64(t) + case int64: + return float64(t) + case float32: + return float64(t) + case float64: + return float64(t) + case uint: + return float64(t) + case uint32: + return float64(t) + case uint64: + return float64(t) + case string: + parsed, _ := strconv.ParseFloat(t, 64) + return parsed + case time.Duration: + return float64(t) + case time.Month: + return float64(t) + case time.Weekday: + return float64(t) + default: + return 0 + } +} + +func ToRune(from interface{}) []rune { + switch t := from.(type) { + case int, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64: + return []rune(ToString(t)) + case string: + return []rune(t) + default: + return nil + } +} + +func ToByte(from interface{}) []byte { + switch t := from.(type) { + case int, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64: + return []byte(ToString(t)) + case string: + return []byte(t) + default: + return nil + } +} + +func tmplJson(v interface{}, flags ...bool) (string, error) { + var b []byte + var err error + + switch len(flags) { + + case 0: + b, err = json.Marshal(v) + if err != nil { + return "", err + } + + case 1: + if flags[0] { + b, err = json.MarshalIndent(v, "", "\t") + if err != nil { + return "", err + } + } else { + b, err = json.Marshal(v) + if err != nil { + return "", err + } + } + + default: + return "", errors.New("Too many flags") + } + + return string(b), nil +} + +func tmplJSONToSDict(v interface{}) (SDict, error) { + var toSDict SDict + err := json.Unmarshal([]byte(ToString(v)), &toSDict) + if err != nil { + return nil, err + } + + return toSDict, nil +} + +func tmplFormatTime(t time.Time, args ...string) string { + layout := time.RFC822 + if len(args) > 0 { + layout = args[0] + } + + return t.Format(layout) +} + +func tmplTimestampToTime(v interface{}) time.Time { + return time.Unix(ToInt64(v), 0).UTC() +} + +type variadicFunc func([]reflect.Value) (reflect.Value, error) + +// callVariadic allows the given function to be called with either a variadic +// sequence of arguments (i.e., fixed in the template definition) or a slice +// (i.e., from a pipeline or context variable). In effect, a limited `flatten` +// operation. +func callVariadic(f variadicFunc, skipNil bool, values ...reflect.Value) (reflect.Value, error) { + var vs []reflect.Value + for _, val := range values { + v, _ := indirect(val) + switch { + case !v.IsValid(): + if !skipNil { + vs = append(vs, v) + } else { + continue + } + case v.Kind() == reflect.Array || v.Kind() == reflect.Slice: + for i := 0; i < v.Len(); i++ { + irv, _ := indirect(v.Index(i)) + vs = append(vs, irv) + } + default: + vs = append(vs, v) + } + } + + return f(vs) +} + +// slice returns the result of creating a new slice with the given arguments. +// "slice x 1 2" is, in Go syntax, x[1:2], and "slice x 1" is equivalent to +// x[1:]. +func slice(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) { + v, _ := indirect(item) + if !v.IsValid() { + return reflect.Value{}, errors.New("index of untyped nil") + } + + var args []int + for _, i := range indices { + index, _ := indirect(i) + switch index.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + args = append(args, int(index.Int())) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + args = append(args, int(index.Uint())) + case reflect.Invalid: + return reflect.Value{}, errors.New("cannot index slice/array with nil") + default: + return reflect.Value{}, fmt.Errorf("cannot index slice/array with type %s", index.Type()) + } + } + + switch v.Kind() { + case reflect.Array, reflect.Slice, reflect.String: + startIndex := 0 + endIndex := 0 + + switch len(args) { + case 0: + // No start or end index provided same as slice[:] + return v, nil + case 1: + // Only start index provided, same as slice[i:] + startIndex = args[0] + endIndex = v.Len() + // args = append(args, v.Len()+1-args[0]) + case 2: + // Both start and end index provided + startIndex = args[0] + endIndex = args[1] + default: + return reflect.Value{}, fmt.Errorf("unexpected slice arguments %d", len(args)) + } + + if startIndex < 0 || startIndex >= v.Len() { + return reflect.Value{}, fmt.Errorf("start index out of range: %d", startIndex) + } else if endIndex <= startIndex || endIndex > v.Len() { + return reflect.Value{}, fmt.Errorf("end index out of range: %d", endIndex) + } + + return v.Slice(startIndex, endIndex), nil + default: + return reflect.Value{}, fmt.Errorf("can't index item of type %s", v.Type()) + } +} + +func tmplCurrentTime() time.Time { + return time.Now().UTC() +} + +func tmplParseTime(input string, layout interface{}, locations ...string) (time.Time, error) { + loc := time.UTC + + var err error + if len(locations) > 0 { + loc, err = time.LoadLocation(locations[0]) + if err != nil { + return time.Time{}, err + } + } + + var parsed time.Time + + rv, _ := indirect(reflect.ValueOf(layout)) + switch rv.Kind() { + case reflect.Slice, reflect.Array: + if rv.Len() > 50 { + return time.Time{}, errors.New("max number of layouts is 50") + } + + for i := 0; i < rv.Len(); i++ { + lv, _ := indirect(rv.Index(i)) + if lv.Kind() != reflect.String { + return time.Time{}, errors.New("layout must be either a slice of strings or a single string") + } + + parsed, err = time.ParseInLocation(lv.String(), input, loc) + if err == nil { + // found a layout that matched + break + } + } + case reflect.String: + parsed, _ = time.ParseInLocation(rv.String(), input, loc) + default: + return time.Time{}, errors.New("layout must be either a slice of strings or a single string") + } + + // if no layout matched, parsed will be the zero Time. + // thus, users can call