合并server client端仓库

This commit is contained in:
feie9456 2025-05-12 20:40:46 +08:00
parent 7c93428f73
commit 1d9d1b9a2f
6 changed files with 760 additions and 189 deletions

2
.env Normal file
View File

@ -0,0 +1,2 @@
SECRET_KEY=zjh94544549ok
ROOT_PATH=/Users/feie9454/Documents

233
bun.lock
View File

@ -5,11 +5,18 @@
"name": "online-editor", "name": "online-editor",
"dependencies": { "dependencies": {
"monaco-editor": "^0.52.0", "monaco-editor": "^0.52.0",
"normalize.css": "^8.0.1",
"vite-plugin-singlefile": "^2.1.0", "vite-plugin-singlefile": "^2.1.0",
"vue": "^3.5.13", "vue": "^3.5.13",
}, },
"devDependencies": { "devDependencies": {
"@fastify/basic-auth": "^6.0.1",
"@fastify/cors": "^10.0.1",
"@fastify/multipart": "^9.0.1",
"@fastify/static": "^8.0.2",
"@types/node": "^22.8.1",
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
"fastify": "^5.0.0",
"sass-embedded": "^1.83.0", "sass-embedded": "^1.83.0",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"vite": "^6.0.1", "vite": "^6.0.1",
@ -79,8 +86,40 @@
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="], "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
"@fastify/accept-negotiator": ["@fastify/accept-negotiator@2.0.1", "", {}, "sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ=="],
"@fastify/ajv-compiler": ["@fastify/ajv-compiler@4.0.2", "", { "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0" } }, "sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ=="],
"@fastify/basic-auth": ["@fastify/basic-auth@6.2.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastify-plugin": "^5.0.0" } }, "sha512-Ao9Jf8TyW8v7p3CPy++c+E3qcCDeWfAlSIfFo0CsKrfvm81i0OCpnobIMwaSSkg/At0rzsLzbJPDWrgNru0G1w=="],
"@fastify/busboy": ["@fastify/busboy@3.1.1", "", {}, "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw=="],
"@fastify/cors": ["@fastify/cors@10.1.0", "", { "dependencies": { "fastify-plugin": "^5.0.0", "mnemonist": "0.40.0" } }, "sha512-MZyBCBJtII60CU9Xme/iE4aEy8G7QpzGR8zkdXZkDFt7ElEMachbE61tfhAG/bvSaULlqlf0huMT12T7iqEmdQ=="],
"@fastify/deepmerge": ["@fastify/deepmerge@2.0.2", "", {}, "sha512-3wuLdX5iiiYeZWP6bQrjqhrcvBIf0NHbQH1Ur1WbHvoiuTYUEItgygea3zs8aHpiitn0lOB8gX20u1qO+FDm7Q=="],
"@fastify/error": ["@fastify/error@4.1.0", "", {}, "sha512-KeFcciOr1eo/YvIXHP65S94jfEEqn1RxTRBT1aJaHxY5FK0/GDXYozsQMMWlZoHgi8i0s+YtrLsgj/JkUUjSkQ=="],
"@fastify/fast-json-stringify-compiler": ["@fastify/fast-json-stringify-compiler@5.0.3", "", { "dependencies": { "fast-json-stringify": "^6.0.0" } }, "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ=="],
"@fastify/forwarded": ["@fastify/forwarded@3.0.0", "", {}, "sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA=="],
"@fastify/merge-json-schemas": ["@fastify/merge-json-schemas@0.2.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A=="],
"@fastify/multipart": ["@fastify/multipart@9.0.3", "", { "dependencies": { "@fastify/busboy": "^3.0.0", "@fastify/deepmerge": "^2.0.0", "@fastify/error": "^4.0.0", "fastify-plugin": "^5.0.0", "secure-json-parse": "^3.0.0" } }, "sha512-pJogxQCrT12/6I5Fh6jr3narwcymA0pv4B0jbC7c6Bl9wnrxomEUnV0d26w6gUls7gSXmhG8JGRMmHFIPsxt1g=="],
"@fastify/proxy-addr": ["@fastify/proxy-addr@5.0.0", "", { "dependencies": { "@fastify/forwarded": "^3.0.0", "ipaddr.js": "^2.1.0" } }, "sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA=="],
"@fastify/send": ["@fastify/send@3.3.1", "", { "dependencies": { "@lukeed/ms": "^2.0.2", "escape-html": "~1.0.3", "fast-decode-uri-component": "^1.0.1", "http-errors": "^2.0.0", "mime": "^3" } }, "sha512-6pofeVwaHN+E/MAofCwDqkWUliE3i++jlD0VH/LOfU8TJlCkMUSgKvA9bawDdVXxjve7XrdYMyDmkiYaoGWEtA=="],
"@fastify/static": ["@fastify/static@8.1.1", "", { "dependencies": { "@fastify/accept-negotiator": "^2.0.0", "@fastify/send": "^3.2.0", "content-disposition": "^0.5.4", "fastify-plugin": "^5.0.0", "fastq": "^1.17.1", "glob": "^11.0.0" } }, "sha512-TW9eyVHJLytZNpBlSIqd0bl1giJkEaRaPZG+5AT3L/OBKq9U8D7g/OYmc2NPQZnzPURGhMt3IAWuyVkvd2nOkQ=="],
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "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" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
"@lukeed/ms": ["@lukeed/ms@2.0.2", "", {}, "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.40.2", "", { "os": "android", "cpu": "arm" }, "sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg=="], "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.40.2", "", { "os": "android", "cpu": "arm" }, "sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.40.2", "", { "os": "android", "cpu": "arm64" }, "sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.40.2", "", { "os": "android", "cpu": "arm64" }, "sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw=="],
@ -123,6 +162,8 @@
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
"@types/node": ["@types/node@22.15.17", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw=="],
"@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="], "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.4", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA=="],
"@volar/language-core": ["@volar/language-core@2.4.13", "", { "dependencies": { "@volar/source-map": "2.4.13" } }, "sha512-MnQJ7eKchJx5Oz+YdbqyFUk8BN6jasdJv31n/7r6/WwlOOv7qzvot6B66887l2ST3bUW4Mewml54euzpJWA6bg=="], "@volar/language-core": ["@volar/language-core@2.4.13", "", { "dependencies": { "@volar/source-map": "2.4.13" } }, "sha512-MnQJ7eKchJx5Oz+YdbqyFUk8BN6jasdJv31n/7r6/WwlOOv7qzvot6B66887l2ST3bUW4Mewml54euzpJWA6bg=="],
@ -153,8 +194,22 @@
"@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], "@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="],
"abstract-logging": ["abstract-logging@2.0.1", "", {}, "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="],
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
"alien-signals": ["alien-signals@1.0.13", "", {}, "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg=="], "alien-signals": ["alien-signals@1.0.13", "", {}, "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg=="],
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
"avvio": ["avvio@9.1.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], "brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
@ -163,37 +218,107 @@
"buffer-builder": ["buffer-builder@0.2.0", "", {}, "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg=="], "buffer-builder": ["buffer-builder@0.2.0", "", {}, "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"colorjs.io": ["colorjs.io@0.5.2", "", {}, "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw=="], "colorjs.io": ["colorjs.io@0.5.2", "", {}, "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw=="],
"content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"de-indent": ["de-indent@1.0.2", "", {}, "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg=="], "de-indent": ["de-indent@1.0.2", "", {}, "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg=="],
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], "esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-json-stringify": ["fast-json-stringify@6.0.1", "", { "dependencies": { "@fastify/merge-json-schemas": "^0.2.0", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0", "json-schema-ref-resolver": "^2.0.0", "rfdc": "^1.2.0" } }, "sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg=="],
"fast-querystring": ["fast-querystring@1.1.2", "", { "dependencies": { "fast-decode-uri-component": "^1.0.1" } }, "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg=="],
"fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="],
"fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="],
"fastify": ["fastify@5.3.2", "", { "dependencies": { "@fastify/ajv-compiler": "^4.0.0", "@fastify/error": "^4.0.0", "@fastify/fast-json-stringify-compiler": "^5.0.0", "@fastify/proxy-addr": "^5.0.0", "abstract-logging": "^2.0.1", "avvio": "^9.0.0", "fast-json-stringify": "^6.0.0", "find-my-way": "^9.0.0", "light-my-request": "^6.0.0", "pino": "^9.0.0", "process-warning": "^5.0.0", "rfdc": "^1.3.1", "secure-json-parse": "^4.0.0", "semver": "^7.6.0", "toad-cache": "^3.7.0" } }, "sha512-AIPqBgtqBAwkOkrnwesEE+dOyU30dQ4kh7udxeGVR05CRGwubZx+p2H8P0C4cRnQT0+EPK4VGea2DTL2RtWttg=="],
"fastify-plugin": ["fastify-plugin@5.0.1", "", {}, "sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="], "fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-my-way": ["find-my-way@9.3.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg=="],
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"glob": ["glob@11.0.2", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^4.0.1", "minimatch": "^10.0.0", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
"immutable": ["immutable@5.1.2", "", {}, "sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ=="], "immutable": ["immutable@5.1.2", "", {}, "sha512-qHKXW1q6liAk1Oys6umoaZbDRqjcjgSrbnrifHsfsttza7zcvRAsL7mMV6xWcyhwQy7Xj5v4hhbr6b+iDYwlmQ=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"jackspeak": ["jackspeak@4.1.0", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw=="],
"json-schema-ref-resolver": ["json-schema-ref-resolver@2.0.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q=="],
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"light-my-request": ["light-my-request@6.6.0", "", { "dependencies": { "cookie": "^1.0.1", "process-warning": "^4.0.0", "set-cookie-parser": "^2.6.0" } }, "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A=="],
"lru-cache": ["lru-cache@11.1.0", "", {}, "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"minimatch": ["minimatch@10.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ=="],
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
"mnemonist": ["mnemonist@0.40.0", "", { "dependencies": { "obliterator": "^2.0.4" } }, "sha512-kdd8AFNig2AD5Rkih7EPCXhu/iMvwevQFX/uEiGhZyPZi7fHqOoF4V4kHLpCfysxXMgQ4B52kdPMCwARshKvEg=="],
"monaco-editor": ["monaco-editor@0.52.2", "", {}, "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ=="], "monaco-editor": ["monaco-editor@0.52.2", "", {}, "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ=="],
@ -201,18 +326,56 @@
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"normalize.css": ["normalize.css@8.0.1", "", {}, "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="],
"obliterator": ["obliterator@2.0.5", "", {}, "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw=="],
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-scurry": ["path-scurry@2.0.0", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
"pino": ["pino@9.6.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg=="],
"pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
"pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="],
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
"process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
"ret": ["ret@0.5.0", "", {}, "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
"rollup": ["rollup@4.40.2", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.2", "@rollup/rollup-android-arm64": "4.40.2", "@rollup/rollup-darwin-arm64": "4.40.2", "@rollup/rollup-darwin-x64": "4.40.2", "@rollup/rollup-freebsd-arm64": "4.40.2", "@rollup/rollup-freebsd-x64": "4.40.2", "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", "@rollup/rollup-linux-arm-musleabihf": "4.40.2", "@rollup/rollup-linux-arm64-gnu": "4.40.2", "@rollup/rollup-linux-arm64-musl": "4.40.2", "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", "@rollup/rollup-linux-riscv64-gnu": "4.40.2", "@rollup/rollup-linux-riscv64-musl": "4.40.2", "@rollup/rollup-linux-s390x-gnu": "4.40.2", "@rollup/rollup-linux-x64-gnu": "4.40.2", "@rollup/rollup-linux-x64-musl": "4.40.2", "@rollup/rollup-win32-arm64-msvc": "4.40.2", "@rollup/rollup-win32-ia32-msvc": "4.40.2", "@rollup/rollup-win32-x64-msvc": "4.40.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg=="], "rollup": ["rollup@4.40.2", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.2", "@rollup/rollup-android-arm64": "4.40.2", "@rollup/rollup-darwin-arm64": "4.40.2", "@rollup/rollup-darwin-x64": "4.40.2", "@rollup/rollup-freebsd-arm64": "4.40.2", "@rollup/rollup-freebsd-x64": "4.40.2", "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", "@rollup/rollup-linux-arm-musleabihf": "4.40.2", "@rollup/rollup-linux-arm64-gnu": "4.40.2", "@rollup/rollup-linux-arm64-musl": "4.40.2", "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", "@rollup/rollup-linux-riscv64-gnu": "4.40.2", "@rollup/rollup-linux-riscv64-musl": "4.40.2", "@rollup/rollup-linux-s390x-gnu": "4.40.2", "@rollup/rollup-linux-x64-gnu": "4.40.2", "@rollup/rollup-linux-x64-musl": "4.40.2", "@rollup/rollup-win32-arm64-msvc": "4.40.2", "@rollup/rollup-win32-ia32-msvc": "4.40.2", "@rollup/rollup-win32-x64-msvc": "4.40.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg=="],
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"safe-regex2": ["safe-regex2@5.0.0", "", { "dependencies": { "ret": "~0.5.0" } }, "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw=="],
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
"sass-embedded": ["sass-embedded@1.88.0", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-android-arm": "1.88.0", "sass-embedded-android-arm64": "1.88.0", "sass-embedded-android-ia32": "1.88.0", "sass-embedded-android-riscv64": "1.88.0", "sass-embedded-android-x64": "1.88.0", "sass-embedded-darwin-arm64": "1.88.0", "sass-embedded-darwin-x64": "1.88.0", "sass-embedded-linux-arm": "1.88.0", "sass-embedded-linux-arm64": "1.88.0", "sass-embedded-linux-ia32": "1.88.0", "sass-embedded-linux-musl-arm": "1.88.0", "sass-embedded-linux-musl-arm64": "1.88.0", "sass-embedded-linux-musl-ia32": "1.88.0", "sass-embedded-linux-musl-riscv64": "1.88.0", "sass-embedded-linux-musl-x64": "1.88.0", "sass-embedded-linux-riscv64": "1.88.0", "sass-embedded-linux-x64": "1.88.0", "sass-embedded-win32-arm64": "1.88.0", "sass-embedded-win32-ia32": "1.88.0", "sass-embedded-win32-x64": "1.88.0" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-GQUxgZFuej3NZ1TSPUHU8aebtYdnIeXqYsbNEEKBtE+SC7/Gr18KH1ijTAZHPw25OUfQCdtJaRy6Fo866dHmgw=="], "sass-embedded": ["sass-embedded@1.88.0", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-android-arm": "1.88.0", "sass-embedded-android-arm64": "1.88.0", "sass-embedded-android-ia32": "1.88.0", "sass-embedded-android-riscv64": "1.88.0", "sass-embedded-android-x64": "1.88.0", "sass-embedded-darwin-arm64": "1.88.0", "sass-embedded-darwin-x64": "1.88.0", "sass-embedded-linux-arm": "1.88.0", "sass-embedded-linux-arm64": "1.88.0", "sass-embedded-linux-ia32": "1.88.0", "sass-embedded-linux-musl-arm": "1.88.0", "sass-embedded-linux-musl-arm64": "1.88.0", "sass-embedded-linux-musl-ia32": "1.88.0", "sass-embedded-linux-musl-riscv64": "1.88.0", "sass-embedded-linux-musl-x64": "1.88.0", "sass-embedded-linux-riscv64": "1.88.0", "sass-embedded-linux-x64": "1.88.0", "sass-embedded-win32-arm64": "1.88.0", "sass-embedded-win32-ia32": "1.88.0", "sass-embedded-win32-x64": "1.88.0" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-GQUxgZFuej3NZ1TSPUHU8aebtYdnIeXqYsbNEEKBtE+SC7/Gr18KH1ijTAZHPw25OUfQCdtJaRy6Fo866dHmgw=="],
"sass-embedded-android-arm": ["sass-embedded-android-arm@1.88.0", "", { "os": "android", "cpu": "arm" }, "sha512-jveGkHhHxJ2+GnNxl3OyhZAxR8YXJCSuj7JYzoVuFTxlsaFqFQwtUrvZro61xOVOrwfe8xMk2HE3ZEw6dolhBA=="], "sass-embedded-android-arm": ["sass-embedded-android-arm@1.88.0", "", { "os": "android", "cpu": "arm" }, "sha512-jveGkHhHxJ2+GnNxl3OyhZAxR8YXJCSuj7JYzoVuFTxlsaFqFQwtUrvZro61xOVOrwfe8xMk2HE3ZEw6dolhBA=="],
@ -255,22 +418,58 @@
"sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.88.0", "", { "os": "win32", "cpu": "x64" }, "sha512-j4pOP/S9vD4enRqbfwno07Xx+j0RkfVYGV31ZxzAIF+a1+3dDBlsbwgDNP68XemJx5SjpP8yM8the6nHAnMUiQ=="], "sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.88.0", "", { "os": "win32", "cpu": "x64" }, "sha512-j4pOP/S9vD4enRqbfwno07Xx+j0RkfVYGV31ZxzAIF+a1+3dDBlsbwgDNP68XemJx5SjpP8yM8the6nHAnMUiQ=="],
"secure-json-parse": ["secure-json-parse@3.0.2", "", {}, "sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w=="],
"semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
"string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
"sync-child-process": ["sync-child-process@1.0.2", "", { "dependencies": { "sync-message-port": "^1.0.0" } }, "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA=="], "sync-child-process": ["sync-child-process@1.0.2", "", { "dependencies": { "sync-message-port": "^1.0.0" } }, "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA=="],
"sync-message-port": ["sync-message-port@1.1.3", "", {}, "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg=="], "sync-message-port": ["sync-message-port@1.1.3", "", {}, "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg=="],
"thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
"tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="], "tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"toad-cache": ["toad-cache@3.7.0", "", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="],
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], "typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
"varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="], "varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="],
"vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], "vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
@ -285,6 +484,38 @@
"vue-tsc": ["vue-tsc@2.2.10", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.10" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-jWZ1xSaNbabEV3whpIDMbjVSVawjAyW+x1n3JeGQo7S0uv2n9F/JMgWW90tGWNFRKya4YwKMZgCtr0vRAM7DeQ=="], "vue-tsc": ["vue-tsc@2.2.10", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.10" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-jWZ1xSaNbabEV3whpIDMbjVSVawjAyW+x1n3JeGQo7S0uv2n9F/JMgWW90tGWNFRKya4YwKMZgCtr0vRAM7DeQ=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"@vue/language-core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"fastify/secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="],
"light-my-request/process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"pino/process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="],
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
} }
} }

124
index.ts Normal file
View File

@ -0,0 +1,124 @@
import Fastify from 'fastify';
import cors from '@fastify/cors'
import fastifyStat from '@fastify/static'
const app = Fastify({ logger: false });
import path, { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { rename, writeFile } from 'fs/promises';
import crypto from 'crypto';
import { spawn } from 'child_process';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
await app.register(cors)
await app.register(fastifyStat, { root: join(__dirname, 'dist'), });
const secretKey = process.env.SECRET_KEY
const rootPath = process.env.ROOT_PATH
if (!secretKey) {
throw new Error('SECRET_KEY is not set');
}
if (!rootPath) {
throw new Error('ROOT_PATH is not set');
}
// 创建 HMAC 函数
function createHmac(message: string, secretKey: string) {
const hmac = crypto.createHmac('sha256', secretKey);
hmac.update(message);
return hmac.digest('hex');
}
// 验证 HMAC
function verifyHmac(message: string, secretKey: string, hash: string) {
const calculatedHash = createHmac(message, secretKey);
console.log(`calculatedHash: ${calculatedHash}, hash: ${hash}`);
return calculatedHash === hash;
}
app.get<{ Params: { pj: string, ['*']: string }, Querystring: { secretKey: string } }>('/file/:pj/*', async (req, res) => {
const { pj, '*': pth } = req.params;
const targetFile = path.join(pj, pth);
if (!verifyHmac(targetFile, secretKey, req.query.secretKey)) {
return res.status(401).send({
message: 'Invalid secret key'
});
}
return res.sendFile(targetFile, rootPath);
});
app.get<{ Params: { pj: string, ['*']: string }, Querystring: { secretKey: string }, Body: string }>
('/compile/:pj/*', async (req, res) => {
const { pj, '*': pth } = req.params;
const targetFile = path.join(pj, pth);
console.log(`targetFile: ${targetFile}`);
console.log(createHmac(targetFile, secretKey));
if (!verifyHmac(targetFile, secretKey, req.query.secretKey)) {
return res.status(401).send({
message: 'Invalid secret key'
});
}
const targetPjPath = path.join(rootPath, pj);
res.raw.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
});
function formatSSEData(data: any): string {
const message = typeof data === 'string' ? data : JSON.stringify(data);
// 处理多行数据:
// 1. 将整个消息按换行符分割
// 2. 每行前面加上 "data: "
// 3. 最后加上额外的换行符
return message
.split('\n')
.map(line => `data: ${line}`)
.join('\n') + '\n\n';
}
const process = spawn('npm', ['run', 'build'], { cwd: targetPjPath });
process.stdout.on('data', (data) => {
res.raw.write(`event: stdout\n${formatSSEData(data.toString())}`);
});
process.stderr.on('data', (data) => {
res.raw.write(`event: stderr\n${formatSSEData(data.toString())}`);
});
process.on('close', (code) => {
res.raw.end(`event: close\n${formatSSEData({ code })}`);
});
});
app.post<{ Params: { pj: string, ['*']: string }, Querystring: { secretKey: string }, Body: string }>
('/file/:pj/*', async (req, res) => {
const { pj, '*': pth } = req.params;
const targetFile = path.join(pj, pth);
console.log(createHmac(targetFile, secretKey));
if (!verifyHmac(targetFile, secretKey, req.query.secretKey)) {
return res.status(401).send({
message: 'Invalid secret key'
});
}
const targetPath = path.join(rootPath, targetFile);
await rename(targetPath, `${targetPath}.${Date.now()}.bak`)
await writeFile(targetPath, req.body)
console.log(`File ${targetPath} saved successfully`);
return res.send({
message: 'File uploaded successfully'
});
});
app.listen({ port: 3000, host: '0.0.0.0' })

View File

@ -6,10 +6,13 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vue-tsc -b && vite build", "build": "vue-tsc -b && vite build",
"preview": "vite preview" "preview": "vite preview",
"start": "vue-tsc -b && vite build && bun index.ts",
"serve": "bun --watch index.ts"
}, },
"dependencies": { "dependencies": {
"monaco-editor": "^0.52.0", "monaco-editor": "^0.52.0",
"normalize.css": "^8.0.1",
"vite-plugin-singlefile": "^2.1.0", "vite-plugin-singlefile": "^2.1.0",
"vue": "^3.5.13" "vue": "^3.5.13"
}, },
@ -19,6 +22,12 @@
"typescript": "~5.6.2", "typescript": "~5.6.2",
"vite": "^6.0.1", "vite": "^6.0.1",
"vite-plugin-monaco-editor": "^1.1.0", "vite-plugin-monaco-editor": "^1.1.0",
"vue-tsc": "^2.1.10" "vue-tsc": "^2.1.10",
"@fastify/basic-auth": "^6.0.1",
"@fastify/cors": "^10.0.1",
"@fastify/multipart": "^9.0.1",
"@fastify/static": "^8.0.2",
"@types/node": "^22.8.1",
"fastify": "^5.0.0"
} }
} }

View File

@ -1,16 +1,74 @@
<script setup lang="ts"> <script setup lang="ts">
import * as monaco from 'monaco-editor'; import * as monaco from 'monaco-editor';
import { onMounted, ref, watch } from 'vue'; import { onMounted, ref, watch } from 'vue';
import './worker' import './worker';
const originCode = ref('') const params = new URLSearchParams(window.location.search);
const serverPath = ref(params.get('server') ?? location.origin);
const filePath = ref(params.get('path') ?? '');
const secretKey = ref(params.get('key') ?? '');
const footSelection = ref<'errors' | 'logs'>('errors');
//
const encryptionKey = ref(localStorage.getItem('encryptionKey') ?? '');
//
watch(encryptionKey, (newValue) => {
localStorage.setItem('encryptionKey', newValue);
});
console.log(params);
/* --------------- 新增:语言检测及用户选择 --------------- */
type MonacoLanguage =
| 'typescript' | 'javascript' | 'markdown' | 'json' | 'html'
| 'css' | 'scss' | 'sass' | 'vue' | 'plaintext';
const languageSelection = ref<'auto' | MonacoLanguage>(
(localStorage.getItem('languageSelection') as 'auto' | MonacoLanguage) ?? 'auto'
);
const selectedLanguage = ref<MonacoLanguage>(languageSelection.value === 'auto' ? detectLanguageByPath(filePath.value) : languageSelection.value);
/** 根据文件扩展名推断编辑语言 */
function detectLanguageByPath(path: string): MonacoLanguage {
const ext = path.split('.').pop()?.toLowerCase() ?? '';
switch (ext) {
case 'ts':
case 'tsx':
return 'typescript';
case 'js':
case 'jsx':
return 'javascript';
case 'json':
return 'json';
case 'md':
case 'mdx':
return 'markdown';
case 'html':
case 'htm':
return 'html';
case 'scss':
return 'scss';
case 'sass':
return 'sass';
case 'css':
return 'css';
case 'vue':
return 'vue';
default:
return 'plaintext';
}
}
/* ------------------------------------------------------- */
const originCode = ref('');
let editor: monaco.editor.IStandaloneCodeEditor | null = null; let editor: monaco.editor.IStandaloneCodeEditor | null = null;
const errors = ref<monaco.editor.IMarker[]>([]); const errors = ref<monaco.editor.IMarker[]>([]);
onMounted(async () => { onMounted(async () => {
const container = document.querySelector('.monaco-container') as HTMLDivElement; const container = document.querySelector('.monaco-container') as HTMLDivElement;
if (!container) return; if (!container) return;
//
/* 设置 TS 语言服务配置(对其他语言不产生影响) */
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ESNext, target: monaco.languages.typescript.ScriptTarget.ESNext,
allowNonTsExtensions: true, allowNonTsExtensions: true,
@ -20,203 +78,237 @@ onMounted(async () => {
esModuleInterop: true, esModuleInterop: true,
strict: true, strict: true,
}); });
monaco.editor.onDidChangeMarkers(([uri]) => { monaco.editor.onDidChangeMarkers(([uri]) => {
const markers = monaco.editor.getModelMarkers({ resource: uri }) errors.value = monaco.editor.getModelMarkers({ resource: uri });
errors.value = markers });
})
console.log(`当前语言:${selectedLanguage.value}`);
editor = monaco.editor.create(container, { editor = monaco.editor.create(container, {
value: `"Loading..."`, value: `"Loading..."`,
language: 'typescript', language: selectedLanguage.value,
automaticLayout: true, automaticLayout: true,
contextmenu: true, contextmenu: true,
fontFamily: 'Fira Code', fontFamily: 'Fira Code',
fontLigatures: true, fontLigatures: true,
theme: colorMode.value === 'light' ? 'vs' : 'vs-dark', theme: colorMode.value === 'light' ? 'vs' : 'vs-dark',
fontSize: fontSize.value, fontSize: fontSize.value,
}); wordWrap: wordWrap.value,
//
try {
const url = new URL('file/' + filePath.value, serverPath.value)
url.searchParams.append('secretKey', secretKey.value)
const res = await fetch(url)
const code = await res.text()
if (!res.ok)
originCode.value = `加载文件失败,请检查设置:\n${JSON.stringify(JSON.parse(code), null, 2)}`
else
originCode.value = code
} catch (error) {
originCode.value = `加载文件失败,请检查设置:\n${JSON.stringify(error, null, 2)}`
}
editor.setValue(originCode.value)
}); });
/* 读取文件内容并填充编辑器 */
try {
const url = new URL('file/' + encodeURI(filePath.value), serverPath.value);
url.searchParams.append('secretKey', secretKey.value);
const res = await fetch(url);
const code = await res.text();
if (!res.ok)
originCode.value = `加载文件失败,请检查设置:\n${JSON.stringify(JSON.parse(code), null, 2)}`;
else
originCode.value = code;
} catch (error) {
originCode.value = `加载文件失败,请检查设置:\n${JSON.stringify(error, null, 2)}`;
}
editor.setValue(originCode.value);
});
/* ------------ watch文件路径或语言选择变化时切换语言 ------------- */
watch([filePath, languageSelection], () => {
if (languageSelection.value === 'auto')
selectedLanguage.value = detectLanguageByPath(filePath.value);
else
selectedLanguage.value = languageSelection.value;
// Secret Key
if (encryptionKey.value && filePath.value) {
createHmac(filePath.value, encryptionKey.value).then(result => {
secretKey.value = result;
});
}
});
watch(selectedLanguage, () => {
if (editor && editor.getModel())
monaco.editor.setModelLanguage(editor.getModel()!, selectedLanguage.value);
});
/* ------------------------------------------------------------------ */
async function upload() { async function upload() {
if (!editor) return if (!editor) return;
if (!confirm('文件将被覆盖,历史文件将被备份并保留。\n\n请确认无报错后再上传否则可能导致编译错误或运行时错误。\n\n确认上传吗')) return if (
const value = editor.getValue() !confirm(
footSelection.value = 'logs' '文件将被覆盖,历史文件将被备份并保留。\n\n请确认无报错后再上传否则可能导致编译错误或运行时错误。\n\n确认上传吗'
const url = new URL('file/' + filePath.value, serverPath.value) )
url.searchParams.append('secretKey', secretKey.value) )
logContent.value += `[${new Date().toLocaleString()}] 开始上传...\n` return;
const value = editor.getValue();
footSelection.value = 'logs';
const url = new URL('file/' + encodeURI(filePath.value), serverPath.value);
url.searchParams.append('secretKey', secretKey.value);
logContent.value += `[${new Date().toLocaleString()}] 开始上传...\n`;
try { try {
const res = await fetch(url, { const res = await fetch(url, {
body: value, body: value,
method: 'POST' method: 'POST',
}) });
const code = await res.text() const code = await res.text();
if (!res.ok) if (!res.ok)
logContent.value += `[${new Date().toLocaleString()}] 上传失败:\n${JSON.stringify(JSON.parse(code), null, 2)}\n` logContent.value += `[${new Date().toLocaleString()}] 上传失败:\n${JSON.stringify(
else JSON.parse(code),
logContent.value += `[${new Date().toLocaleString()}] 上传成功!\n` null,
2
)}\n`;
else logContent.value += `[${new Date().toLocaleString()}] 上传成功!\n`;
} catch (error) { } catch (error) {
logContent.value += `[${new Date().toLocaleString()}] 上传失败:\n${JSON.stringify(error, null, 2)}\n` logContent.value += `[${new Date().toLocaleString()}] 上传失败:\n${JSON.stringify(
error,
null,
2
)}\n`;
}
} }
} const showSettings = ref(false);
const params = new URLSearchParams(window.location.search);
const serverPath = ref(params.get('server') ?? location.origin)
const filePath = ref(params.get('path') ?? '')
const secretKey = ref(params.get('key') ?? '')
const footSelection = ref('errors')
console.log(params);
const showSettings = ref(false)
function saveSettings() { function saveSettings() {
const url = new URL(window.location.href) const url = new URL(window.location.href);
if (serverPath.value !== url.origin) if (serverPath.value !== url.origin) url.searchParams.set('server', serverPath.value);
url.searchParams.set('server', serverPath.value) url.searchParams.set('path', filePath.value);
url.searchParams.set('path', filePath.value)
url.searchParams.set('key', secretKey.value) // Secret Key
window.location.href = url.href if (encryptionKey.value && filePath.value) {
createHmac(filePath.value, encryptionKey.value).then(result => {
secretKey.value = result;
url.searchParams.set('key', secretKey.value);
localStorage.setItem('languageSelection', languageSelection.value);
window.location.href = url.href;
});
} else {
url.searchParams.set('key', secretKey.value);
localStorage.setItem('languageSelection', languageSelection.value);
window.location.href = url.href;
}
} }
const logContent = ref('');
const logContent = ref("")
async function compile() { async function compile() {
footSelection.value = 'logs' footSelection.value = 'logs';
const url = new URL('compile/' + filePath.value, serverPath.value) const url = new URL('compile/' + encodeURI(filePath.value), serverPath.value);
url.searchParams.append('secretKey', secretKey.value) url.searchParams.append('secretKey', secretKey.value);
logContent.value += `[${new Date().toLocaleString()}] 正在发送编译任务...\n` logContent.value += `[${new Date().toLocaleString()}] 正在发送编译任务...\n`;
const sse = new EventSource(url) const sse = new EventSource(url);
sse.addEventListener('stdout', (event) => (logContent.value += `${event.data}`));
// sse.addEventListener('stderr', (event) => (logContent.value += `${event.data}`));
sse.addEventListener('stdout', (event) => {
logContent.value += `${event.data}`
})
//
sse.addEventListener('stderr', (event) => {
logContent.value += `${event.data}`
})
//
sse.addEventListener('close', (event) => { sse.addEventListener('close', (event) => {
logContent.value += `[${new Date().toLocaleString()}] 编译完成,退出码:${event.data}\n` logContent.value += `[${new Date().toLocaleString()}] 编译完成,退出码:${event.data}\n`;
sse.close() // EventSource sse.close();
}) });
sse.onerror = (event) => {
sse.onerror = event => { logContent.value += `[${new Date().toLocaleString()}] 编译失败:\n${JSON.stringify(event, null, 2)}\n`;
logContent.value += `[${new Date().toLocaleString()}] 编译失败:\n${JSON.stringify(event, null, 2)}\n` sse.close();
sse.close() // };
sse.onopen = () => (logContent.value += `[${new Date().toLocaleString()}] 开始编译...\n`);
} }
sse.onopen = () => { const footerHeight = ref(200);
logContent.value += `[${new Date().toLocaleString()}] 开始编译...\n`
}
}
const footerHeight = ref(200)
function resize(event: PointerEvent) { function resize(event: PointerEvent) {
if (event.buttons != 1) return if (event.buttons != 1) return;
event.preventDefault() event.preventDefault();
let target = event.target as HTMLElement (event.target as HTMLElement).setPointerCapture(event.pointerId);
target.setPointerCapture(event.pointerId) footerHeight.value -= event.movementY;
console.log(event.movementY); if (footerHeight.value < 32) footerHeight.value = 32;
footerHeight.value -= event.movementY
if (footerHeight.value < 32) footerHeight.value = 32
} }
const logContentContainer = ref<HTMLDivElement | null>(null) const logContentContainer = ref<HTMLDivElement | null>(null);
watch(logContent, () => { watch(logContent, () => {
if (!logContentContainer.value) return if (!logContentContainer.value) return;
requestAnimationFrame(() => { requestAnimationFrame(() =>
logContentContainer.value!.scrollIntoView({ behavior: 'smooth', block: 'end' }) logContentContainer.value!.scrollIntoView({ behavior: 'smooth', block: 'end' })
}) );
}) });
const colorMode = ref<'light' | 'dark'>((localStorage.getItem('colorMode') as 'light' | 'dark') ?? 'dark')
const colorMode = ref<'light' | 'dark'>(
(localStorage.getItem('colorMode') as 'light' | 'dark') ?? 'dark'
);
watch(colorMode, () => { watch(colorMode, () => {
if (!editor) return if (!editor) return;
editor.updateOptions({ editor.updateOptions({ theme: colorMode.value === 'light' ? 'vs' : 'vs-dark' });
theme: colorMode.value === 'light' ? 'vs' : 'vs-dark' localStorage.setItem('colorMode', colorMode.value);
}) });
localStorage.setItem('colorMode', colorMode.value)
}) //
const wordWrap = ref<'off' | 'on'>(
(localStorage.getItem('wordWrap') as 'off' | 'on') ?? 'on'
);
watch(wordWrap, () => {
if (!editor) return;
editor.updateOptions({ wordWrap: wordWrap.value });
localStorage.setItem('wordWrap', wordWrap.value);
});
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent navigator.userAgent
); );
const fontSize = ref<number>(+(localStorage.getItem('fontSize') ?? (isMobile ? '11' : '14')));
const fontSize = ref(+(localStorage.getItem('fontSize') ?? (isMobile ? '11' : '14')))
watch(fontSize, () => { watch(fontSize, () => {
if (!editor) return if (!editor) return;
editor.updateOptions({ editor.updateOptions({ fontSize: fontSize.value });
fontSize: fontSize.value localStorage.setItem('fontSize', fontSize.value.toString());
}) });
localStorage.setItem('fontSize', fontSize.value.toString())
}) /* ---- Secret Key 计算器逻辑 ---- */
const showSecretKeyCalculator = ref(false) const showSecretKeyCalculator = ref(false);
const secretKeyCalculatorData = ref({ const secretKeyCalculatorData = ref({ filePath: '', secretKey: '', result: '' });
filePath: '',
secretKey: '', //
result: '' watch(showSecretKeyCalculator, (isVisible) => {
}) if (isVisible) {
secretKeyCalculatorData.value.filePath = filePath.value;
secretKeyCalculatorData.value.secretKey = encryptionKey.value;
//
if (secretKeyCalculatorData.value.filePath && secretKeyCalculatorData.value.secretKey) {
createHmac(secretKeyCalculatorData.value.filePath, secretKeyCalculatorData.value.secretKey).then(
(result) => (secretKeyCalculatorData.value.result = result)
);
}
}
});
async function createHmac(message: string, secretKey: string) { async function createHmac(message: string, secretKey: string) {
// Uint8Array if (!message || !secretKey) return '';
const encoder = new TextEncoder(); const encoder = new TextEncoder();
const messageBuffer = encoder.encode(message); const messageBuffer = encoder.encode(message);
const keyBuffer = encoder.encode(secretKey); const keyBuffer = encoder.encode(secretKey);
//
const key = await window.crypto.subtle.importKey( const key = await window.crypto.subtle.importKey(
'raw', 'raw',
keyBuffer, keyBuffer,
{ { name: 'HMAC', hash: { name: 'SHA-256' } },
name: 'HMAC',
hash: { name: 'SHA-256' }
},
false, false,
['sign'] ['sign']
); );
const signature = await window.crypto.subtle.sign('HMAC', key, messageBuffer);
// HMAC
const signature = await window.crypto.subtle.sign(
'HMAC',
key,
messageBuffer
);
//
return Array.from(new Uint8Array(signature)) return Array.from(new Uint8Array(signature))
.map(b => b.toString(16).padStart(2, '0')) .map((b) => b.toString(16).padStart(2, '0'))
.join(''); .join('');
} }
watch(secretKeyCalculatorData, () => {
watch(
secretKeyCalculatorData,
() => {
if (secretKeyCalculatorData.value.filePath === '' || secretKeyCalculatorData.value.secretKey === '') { if (secretKeyCalculatorData.value.filePath === '' || secretKeyCalculatorData.value.secretKey === '') {
secretKeyCalculatorData.value.result = '' secretKeyCalculatorData.value.result = '';
return return;
} }
createHmac(secretKeyCalculatorData.value.filePath, secretKeyCalculatorData.value.secretKey) createHmac(secretKeyCalculatorData.value.filePath, secretKeyCalculatorData.value.secretKey).then(
.then(result => { (result) => (secretKeyCalculatorData.value.result = result)
secretKeyCalculatorData.value.result = result );
}) },
},{deep: true}) { deep: true }
);
</script> </script>
<template> <template>
@ -225,108 +317,159 @@ watch(secretKeyCalculatorData, () => {
<div class="title">鹅鹅协作编辑器</div> <div class="title">鹅鹅协作编辑器</div>
<div class="action"> <div class="action">
<button @click="showSettings = !showSettings">设置</button> <button @click="showSettings = !showSettings">设置</button>
<button @click="colorMode = colorMode === 'light' ? 'dark' : 'light'">{{ <button @click="colorMode = colorMode === 'light' ? 'dark' : 'light'">
colorMode === 'light' ? 'Dark' : 'Light' }}</button> {{ colorMode === 'light' ? 'Dark' : 'Light' }}
<button </button>
@click="editor?.getAction('editor.action.formatDocument')!.run()">格式化</button> <button @click="editor?.getAction('editor.action.formatDocument')!.run()">格式化</button>
<button @click="upload">上传</button> <button @click="upload">上传</button>
<button @click="compile">编译</button> <button @click="compile">编译</button>
</div> </div>
</header> </header>
<main class="">
<div class="monaco-container"></div> <main>
<div class="monaco-container" />
</main> </main>
<div class="resize-bar"> <div class="resize-bar">
<div class="pointer-catcher" @pointermove="resize" @touchstart.prevent> <div class="pointer-catcher" @pointermove="resize" @touchstart.prevent />
</div>
</div> </div>
<footer :style="{ height: `${footerHeight}px` }"> <footer :style="{ height: `${footerHeight}px` }">
<div class="selector"> <div class="selector">
<div class="item" :class="{ active: footSelection === 'errors' }" <div class="item" :class="{ active: footSelection === 'errors' }" @click="footSelection = 'errors'">
@click="footSelection = 'errors'">问题</div> 问题
<div class="item" :class="{ active: footSelection === 'logs' }" </div>
@click="footSelection = 'logs'">日志</div> <div class="item" :class="{ active: footSelection === 'logs' }" @click="footSelection = 'logs'">
日志
</div>
</div> </div>
<div class="content"> <div class="content">
<div class="errors" v-if="footSelection === 'errors'"> <div class="errors" v-if="footSelection === 'errors'">
<div class="item" v-for="(error, index) in errors"> <div class="item" v-for="(error, index) in errors" :key="index">
<div class="index">{{ index + 1 }}.</div> <div class="index">{{ index + 1 }}.</div>
<div class="content">{{ error.message }}</div> <div class="content">{{ error.message }}</div>
<div class="position"> <div class="position">[{{ error.startLineNumber }}, {{ error.startColumn }}]</div>
[{{ error.startLineNumber }}, {{ error.startColumn }}]
</div> </div>
</div> </div>
</div> <div class="logs" v-if="footSelection === 'logs'" v-html="logContent" ref="logContentContainer" />
<div class="logs" v-if="footSelection === 'logs'" v-html="logContent"
ref="logContentContainer">
</div>
</div> </div>
</footer> </footer>
<!-- 设置弹窗 -->
<div class="mask" v-if="showSettings"> <div class="mask" v-if="showSettings">
<div class="settings content"> <div class="settings content">
<div class="title">设置</div> <div class="title">设置</div>
<!-- 新增语言服务选择 -->
<div class="item"> <div class="item">
<label for="file-path">编辑器字体大小</label> <label for="language-select">语言服务</label>
<input type="number" id="server-path" v-model="fontSize" <select id="language-select" v-model="languageSelection">
spellcheck="false"> <option value="auto">自动检测</option>
<option value="typescript">TypeScript</option>
<option value="javascript">JavaScript</option>
<option value="markdown">Markdown</option>
<option value="json">JSON</option>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="scss">SCSS</option>
<option value="sass">Sass</option>
<option value="vue">Vue</option>
<option value="plaintext">Plain Text</option>
</select>
</div> </div>
<div class="item"> <div class="item">
<label for="file-path">Server</label> <label for="font-size">编辑器字体大小</label>
<input type="text" id="server-path" v-model="serverPath" <input type="number" id="font-size" v-model="fontSize" spellcheck="false" />
spellcheck="false">
</div> </div>
<div class="item">
<label for="word-wrap">自动换行</label>
<select id="word-wrap" v-model="wordWrap">
<option value="on">开启</option>
<option value="off">关闭</option>
</select>
</div>
<div class="item">
<label for="server-path">Server</label>
<input type="text" id="server-path" v-model="serverPath" spellcheck="false" />
</div>
<div class="item"> <div class="item">
<label for="file-path">文件路径</label> <label for="file-path">文件路径</label>
<input type="text" id="file-path" v-model="filePath" <input type="text" id="file-path" v-model="filePath" spellcheck="false" />
spellcheck="false">
</div> </div>
<div class="item">
<label for="encryption-key">加密密钥</label>
<div class="input-with-button">
<input type="text" id="encryption-key" v-model="encryptionKey" spellcheck="false" />
<button @click="createHmac(filePath, encryptionKey).then(result => secretKey = result)"
title="生成 Secret Key">生成</button>
</div>
</div>
<div class="item"> <div class="item">
<label for="secret-key">Secret Key</label> <label for="secret-key">Secret Key</label>
<textarea type="text" id="secret-key" v-model="secretKey" <textarea id="secret-key" v-model="secretKey" spellcheck="false" />
spellcheck="false" />
</div> </div>
<div class="action"> <div class="action">
<button @click="showSecretKeyCalculator = true">Secret Key <button @click="showSecretKeyCalculator = true">高级计算器</button>
计算器</button> <div class="placeholder" />
<div class="placeholder"></div>
<button @click="showSettings = false">取消</button> <button @click="showSettings = false">取消</button>
<button @click="saveSettings">保存</button> <button @click="saveSettings">保存</button>
</div> </div>
</div> </div>
</div> </div>
<!-- Secret Key 计算器 (高级模式) -->
<div class="mask" v-if="showSecretKeyCalculator"> <div class="mask" v-if="showSecretKeyCalculator">
<div class="content"> <div class="content">
<div class="title">Secret Key 计算器</div> <div class="title">Secret Key 高级计算器</div>
<div class="item"> <div class="item">
<label for="file-path">文件路径</label> <label>文件路径</label>
<input type="text" v-model="secretKeyCalculatorData.filePath" <input type="text" v-model="secretKeyCalculatorData.filePath" spellcheck="false" />
spellcheck="false">
</div> </div>
<div class="item"> <div class="item">
<label for="secret-key">加密密钥</label> <label>加密密钥</label>
<textarea type="text" v-model="secretKeyCalculatorData.secretKey" <textarea v-model="secretKeyCalculatorData.secretKey" spellcheck="false" />
spellcheck="false" />
</div> </div>
<div class="item"> <div class="item">
<label for="secret-key">Secret Key</label> <label>Secret Key</label>
<textarea type="text" id="secret-key" <textarea v-model="secretKeyCalculatorData.result" spellcheck="false" readonly />
v-model="secretKeyCalculatorData.result" spellcheck="false"
readonly />
</div> </div>
<div class="action"> <div class="action">
<button
@click="encryptionKey = secretKeyCalculatorData.secretKey; secretKey = secretKeyCalculatorData.result; showSecretKeyCalculator = false">应用并关闭</button>
<button @click="showSecretKeyCalculator = false">关闭</button> <button @click="showSecretKeyCalculator = false">关闭</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
/* 样式基本保持原样,这里仅在 item > select 处复用 input/textarea 的样式 */
.placeholder { .placeholder {
flex: 1; flex: 1;
} }
/* 让 select 与 input/textarea 的外观一致 */
.mask .content .input-with-button {
display: flex;
gap: 8px;
width: 100%;
input {
flex: 1;
margin-bottom: 0;
}
margin-bottom: 20px;
}
.app.dark-mode { .app.dark-mode {
background-color: #191919; background-color: #191919;
@ -362,13 +505,29 @@ watch(secretKeyCalculatorData, () => {
.content { .content {
background-color: #1E1E1E; background-color: #1E1E1E;
select,
textarea, textarea,
input { input {
border: 1px solid #FFFFFF33; border: 1px solid #FFFFFF33;
background-color: #000000EE; background-color: #000000EE;
color: #FFFFFFEE; color: #FFFFFFEE;
} }
&::-webkit-scrollbar-thumb {
background-color: #424242;
}
&::-webkit-scrollbar-thumb:hover {
background-color: #4F4F4F;
}
&::-webkit-scrollbar-thumb:active {
background-color: #5E5E5E;
}
&::-webkit-scrollbar {
width: 14px;
}
} }
} }
@ -443,21 +602,66 @@ header {
background-color: #fff; background-color: #fff;
padding: 20px; padding: 20px;
min-width: min(500px, 95vw); min-width: min(500px, 95vw);
max-height: 90vh;
overflow-y: auto;
border-radius: 5px; border-radius: 5px;
box-shadow: 0 0 10px #00000033; box-shadow: 0 0 10px #00000033;
&::-webkit-scrollbar-thumb {
background-color: #C1C1C0;
}
&::-webkit-scrollbar-thumb:hover {
background-color: #929292;
}
&::-webkit-scrollbar-thumb:active {
background-color: #666666;
}
&::-webkit-scrollbar {
width: 14px;
}
>.title { >.title {
font-size: larger; font-size: larger;
margin-bottom: 20px; margin-bottom: 20px;
} }
label { label {
display: block; display: block;
margin-bottom: 10px; margin-bottom: 10px;
} }
select {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 20px;
font-family: 'Fira Code', Consolas, 'Courier New', monospace;
background-color: #FFF;
color: inherit;
height: 32px;
appearance: none;
--webkit-appearance: none;
border: 1px solid #ccc;
}
button {
padding: 6px 12px;
border-radius: 5px;
height: 32px;
white-space: nowrap;
min-width: 60px;
border: 1px solid #ccc;
}
textarea, textarea,
input { input {
width: 100%; width: 100%;
padding: 8px; padding: 8px;
height: 32px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 5px; border-radius: 5px;
margin-bottom: 20px; margin-bottom: 20px;

View File

@ -1,6 +1,7 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import './style.css' import './style.css'
import './assets/stylesheet.css' import './assets/stylesheet.css'
/* import 'normalize.css' */
import App from './App.vue' import App from './App.vue'
createApp(App).mount('#app') createApp(App).mount('#app')