diff --git a/package.json b/package.json index 9f1bd6a..658197e 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.6", "@types/babel__core": "^7.20.5", + "@types/express": "^5.0.3", "@types/fontmin": "^0.9.5", "@types/fs-extra": "^9.0.13", "@types/lodash-es": "^4.17.12", @@ -65,6 +66,7 @@ "eslint-plugin-prettier": "^5.5.0", "eslint-plugin-react": "^7.37.5", "eslint-plugin-vue": "^9.33.0", + "express": "^5.1.0", "fontmin": "^0.9.9", "form-data": "^4.0.2", "fs-extra": "^10.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 43ef4da..26af0f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,6 +93,9 @@ importers: '@types/babel__core': specifier: ^7.20.5 version: 7.20.5 + '@types/express': + specifier: ^5.0.3 + version: 5.0.3 '@types/fontmin': specifier: ^0.9.5 version: 0.9.5 @@ -138,6 +141,9 @@ importers: eslint-plugin-vue: specifier: ^9.33.0 version: 9.33.0(eslint@9.33.0) + express: + specifier: ^5.1.0 + version: 5.1.0 fontmin: specifier: ^0.9.9 version: 0.9.9 @@ -2237,6 +2243,12 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/d3-array@3.2.1': resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} @@ -2333,6 +2345,12 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/express-serve-static-core@5.0.7': + resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} + + '@types/express@5.0.3': + resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} + '@types/fontmin@0.9.5': resolution: {integrity: sha512-WQwvTQV73bx7u6MRrZp13L9GeXhTjzLeRrHVk24+iquhLQMyCaL3n1R1K/P6Sghreq52hdZFAdUynzmR/mdL3A==} @@ -2345,6 +2363,9 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2366,6 +2387,9 @@ packages: '@types/mdurl@2.0.0': resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} @@ -2375,9 +2399,21 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/send@0.17.5': + resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} + + '@types/serve-static@1.15.8': + resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -2663,6 +2699,10 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2885,6 +2925,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2950,6 +2994,10 @@ packages: resolution: {integrity: sha512-Qg0ggJUWJq90vtg4lDsGN9CDWvzBMQxhiEkSOD/sJfYt6BLect3eV1/S6K7SCSKJ34n60rf6U5eUPmQENVE4UA==} engines: {node: '>=8.12.0'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + cacache@16.1.3: resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -3148,12 +3196,28 @@ packages: console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + copy-anything@2.0.6: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} @@ -3452,6 +3516,10 @@ packages: delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dependency-tree@11.1.1: resolution: {integrity: sha512-pnkCd8VGOq70EVaEQxDC9mZCjCwYj4yG4j8h+PEJswuWp+rdE6p8zbtVvWk+yPwaVimOjlhNi782U9K5KOU9MQ==} engines: {node: '>=18'} @@ -3550,6 +3618,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.122: resolution: {integrity: sha512-EML1wnwkY5MFh/xUnCvY8FrhUuKzdYhowuZExZOfwJo+Zu9OsNCI23Cgl5y7awy7HrUHSwB1Z8pZX5TI34lsUg==} @@ -3568,6 +3639,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} @@ -3649,6 +3724,9 @@ packages: resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==} engines: {node: '>=10'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -3752,12 +3830,20 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} exponential-backoff@3.1.2: resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + exsolve@1.0.4: resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==} @@ -3818,6 +3904,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -3867,9 +3957,17 @@ packages: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -4085,6 +4183,10 @@ packages: http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -4171,6 +4273,10 @@ packages: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-absolute@1.0.0: resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} engines: {node: '>=0.10.0'} @@ -4287,6 +4393,9 @@ packages: resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} engines: {node: '>=0.10.0'} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -4605,6 +4714,10 @@ packages: mdast-util-to-hast@13.2.0: resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + mensch@0.3.4: resolution: {integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==} @@ -4616,6 +4729,10 @@ packages: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -4649,10 +4766,18 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -4795,6 +4920,10 @@ packages: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -4883,6 +5012,10 @@ packages: ogg-opus-decoder@1.7.0: resolution: {integrity: sha512-/lrj4+ZGjxZCCNiDSlNEckLrCL+UU9N9XtqES7sXq/Lm6PMi8Pwn/D6TTsbvG45krt21ohAh2FqdEsMuI7ZN4w==} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -4957,6 +5090,10 @@ packages: parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -4985,6 +5122,10 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -5249,6 +5390,10 @@ packages: property-information@7.0.0: resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -5268,6 +5413,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + quansync@0.2.10: resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} @@ -5284,6 +5433,14 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -5455,6 +5612,10 @@ packages: roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -5522,9 +5683,17 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -5543,6 +5712,9 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shallow-equal@1.2.1: resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==} @@ -5653,6 +5825,14 @@ packages: resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -5826,6 +6006,10 @@ packages: resolution: {integrity: sha512-+QIz37Ly7acM4EMdw2PRN389OneM5+d844tirkGp4dPKzI5OE72V9OsbFp+CIYJDahZ41ZV05hNtcPAQUAm9/Q==} engines: {node: '>= 0.10'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -5883,6 +6067,10 @@ packages: resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} engines: {node: '>=10'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -5979,6 +6167,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unplugin-vue-components@0.22.12: resolution: {integrity: sha512-FxyzsuBvMCYPIk+8cgscGBQ345tvwVu+qY5IhE++eorkyvA4Z1TiD/HCiim+Kbqozl10i4K+z+NCa2WO2jexRA==} engines: {node: '>=14'} @@ -6024,6 +6216,10 @@ packages: resolution: {integrity: sha512-jdBB2FrWvQC/pnPtIqcLsMaQgjhdb6B7tk1MMyTKapox+tQZbdRP4uLxu/JY0t7fbfDCUMnuelzEYv5GsxHhdg==} engines: {node: '>= 0.10'} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vfile-message@4.0.2: resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} @@ -7183,7 +7379,7 @@ snapshots: '@babel/parser': 7.28.3 '@babel/template': 7.27.2 '@babel/types': 7.27.1 - debug: 4.4.0 + debug: 4.4.1 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -8111,6 +8307,15 @@ snapshots: dependencies: '@babel/types': 7.26.10 + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 18.19.123 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 18.19.123 + '@types/d3-array@3.2.1': {} '@types/d3-axis@3.0.6': @@ -8230,6 +8435,19 @@ snapshots: '@types/estree@1.0.6': {} + '@types/express-serve-static-core@5.0.7': + dependencies: + '@types/node': 18.19.123 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.5 + + '@types/express@5.0.3': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.0.7 + '@types/serve-static': 1.15.8 + '@types/fontmin@0.9.5': dependencies: '@types/node': 18.19.123 @@ -8244,6 +8462,8 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/http-errors@2.0.5': {} + '@types/json-schema@7.0.15': {} '@types/linkify-it@5.0.0': {} @@ -8265,6 +8485,8 @@ snapshots: '@types/mdurl@2.0.0': {} + '@types/mime@1.3.5': {} + '@types/minimist@1.2.5': {} '@types/node@18.19.123': @@ -8273,8 +8495,23 @@ snapshots: '@types/normalize-package-data@2.4.4': {} + '@types/qs@6.14.0': {} + + '@types/range-parser@1.2.7': {} + '@types/resolve@1.20.2': {} + '@types/send@0.17.5': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 18.19.123 + + '@types/serve-static@1.15.8': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 18.19.123 + '@types/send': 0.17.5 + '@types/trusted-types@2.0.7': optional: true @@ -8675,6 +8912,11 @@ snapshots: abbrev@1.1.1: {} + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 @@ -8954,6 +9196,20 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.1 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} brace-expansion@1.1.11: @@ -9026,6 +9282,8 @@ snapshots: dependencies: readable-stream: 3.6.2 + bytes@3.1.2: {} + cacache@16.1.3: dependencies: '@npmcli/fs': 2.1.2 @@ -9251,10 +9509,20 @@ snapshots: console-control-strings@1.1.0: {} + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + copy-anything@2.0.6: dependencies: is-what: 3.14.1 @@ -9570,6 +9838,8 @@ snapshots: delegates@1.0.0: {} + depd@2.0.0: {} + dependency-tree@11.1.1: dependencies: commander: 12.1.0 @@ -9692,6 +9962,8 @@ snapshots: eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} + electron-to-chromium@1.5.122: {} electron-to-chromium@1.5.157: {} @@ -9704,6 +9976,8 @@ snapshots: emoji-regex@9.2.2: {} + encodeurl@2.0.0: {} + encoding@0.1.13: dependencies: iconv-lite: 0.6.3 @@ -9894,6 +10168,8 @@ snapshots: escape-goat@3.0.0: {} + escape-html@1.0.3: {} + escape-string-regexp@4.0.0: {} escodegen@2.1.0: @@ -10038,10 +10314,44 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + eventemitter3@5.0.1: {} exponential-backoff@3.1.2: {} + express@5.1.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + exsolve@1.0.4: {} extend@3.0.2: {} @@ -10104,6 +10414,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -10173,8 +10494,12 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + forwarded@0.2.0: {} + fraction.js@4.3.7: {} + fresh@2.0.0: {} + fs-constants@1.0.0: {} fs-extra@10.1.0: @@ -10423,6 +10748,14 @@ snapshots: http-cache-semantics@4.1.1: {} + 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 + http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 @@ -10500,6 +10833,8 @@ snapshots: jsbn: 1.1.0 sprintf-js: 1.1.3 + ipaddr.js@1.9.1: {} + is-absolute@1.0.0: dependencies: is-relative: 1.0.0 @@ -10605,6 +10940,8 @@ snapshots: is-plain-object@3.0.1: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.6 @@ -10949,6 +11286,8 @@ snapshots: unist-util-visit: 5.0.0 vfile: 6.0.3 + media-typer@1.1.0: {} + mensch@0.3.4: {} meow@10.1.5: @@ -10968,6 +11307,8 @@ snapshots: meow@13.2.0: {} + merge-descriptors@2.0.0: {} + merge2@1.4.1: {} mermaid@11.9.0: @@ -11021,10 +11362,16 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: optional: true @@ -11152,6 +11499,8 @@ snapshots: negotiator@0.6.4: {} + negotiator@1.0.0: {} + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -11261,6 +11610,10 @@ snapshots: codec-parser: 2.5.0 opus-decoder: 0.7.10 + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -11353,6 +11706,8 @@ snapshots: parse5@6.0.1: {} + parseurl@1.3.3: {} + path-browserify@1.0.1: {} path-data-parser@0.1.0: {} @@ -11372,6 +11727,8 @@ snapshots: lru-cache: 11.0.2 minipass: 7.1.2 + path-to-regexp@8.2.0: {} + pathe@2.0.3: {} pend@1.2.0: {} @@ -11696,6 +12053,11 @@ snapshots: property-information@7.0.0: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} prr@1.0.1: @@ -11719,6 +12081,10 @@ snapshots: punycode@2.3.1: {} + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + quansync@0.2.10: {} queue-microtask@1.2.3: {} @@ -11731,6 +12097,15 @@ snapshots: dependencies: safe-buffer: 5.2.1 + range-parser@1.2.1: {} + + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -11938,6 +12313,16 @@ snapshots: points-on-curve: 0.2.0 points-on-path: 0.2.1 + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -11999,10 +12384,35 @@ snapshots: semver@7.7.2: {} + send@1.2.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: {} set-function-length@1.2.2: @@ -12029,6 +12439,8 @@ snapshots: setimmediate@1.0.5: {} + setprototypeof@1.2.0: {} + shallow-equal@1.2.1: {} shebang-command@2.0.0: @@ -12146,6 +12558,10 @@ snapshots: dependencies: minipass: 3.3.6 + statuses@2.0.1: {} + + statuses@2.0.2: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -12355,6 +12771,8 @@ snapshots: dependencies: through2: 2.0.5 + toidentifier@1.0.1: {} + tr46@0.0.3: {} tree-kill@1.2.2: {} @@ -12409,6 +12827,12 @@ snapshots: type-fest@1.4.0: {} + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -12521,6 +12945,8 @@ snapshots: universalify@2.0.1: {} + unpipe@1.0.0: {} + unplugin-vue-components@0.22.12(@babel/parser@7.28.3)(rollup@3.29.5)(vue@3.5.18(typescript@5.9.2)): dependencies: '@antfu/utils': 0.7.10 @@ -12582,6 +13008,8 @@ snapshots: value-or-function@3.0.0: {} + vary@1.1.2: {} + vfile-message@4.0.2: dependencies: '@types/unist': 3.0.3 diff --git a/public/libs/core.js b/public/libs/core.js index 59238d5..e429f54 100644 --- a/public/libs/core.js +++ b/public/libs/core.js @@ -360,7 +360,7 @@ core.prototype._loadGameProcess = async function () { if (main.pluginUseCompress) { await main.loadScript(`project/processG.min.js`); } else { - await main.loadScript(`src/editor.esm.ts`, true); + await main.loadScript(`esm?name=src/editor.ts`, true); } } } @@ -545,10 +545,10 @@ core.prototype._init_platform = function () { core.platform.string = core.platform.isPC ? 'PC' : core.platform.isAndroid - ? 'Android' - : core.platform.isIOS - ? 'iOS' - : ''; + ? 'Android' + : core.platform.isIOS + ? 'iOS' + : ''; core.platform.supportCopy = document.queryCommandSupported && document.queryCommandSupported('copy'); diff --git a/script/dev.ts b/script/dev.ts index 9fac794..8a23aa6 100644 --- a/script/dev.ts +++ b/script/dev.ts @@ -1,13 +1,8 @@ import { createServer } from 'vite'; -import { - IncomingMessage, - Server, - ServerResponse, - createServer as http -} from 'http'; -import { isNil } from 'lodash-es'; -import fs from 'fs-extra'; -import { resolve, basename } from 'path'; +import { Server } from 'http'; +import { ensureDir, move, pathExists, remove } from 'fs-extra'; +import { readFile, readdir, writeFile } from 'fs/promises'; +import { resolve, basename, join } from 'path'; import * as rollup from 'rollup'; import typescript from '@rollup/plugin-typescript'; import nodeResolve from '@rollup/plugin-node-resolve'; @@ -17,17 +12,27 @@ import chokidar from 'chokidar'; import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; import replace from '@rollup/plugin-replace'; +import express, { Request, Response } from 'express'; const [, , vitePortStr = '5173', serverPortStr = '3000'] = process.argv; const vitePort = parseInt(vitePortStr); const serverPort = parseInt(serverPortStr); -const base = './public'; +const checkBase = resolve(process.cwd()); +const base = resolve(process.cwd(), 'public'); -type Request = IncomingMessage; -type Response = ServerResponse & { - req: IncomingMessage; -}; +const enum APIStatus { + Success, + PermissionDeny, + WriteError, + FileNotExist, + ReadError +} + +interface ResolveResult { + safe: boolean; + resolved: string; +} interface RollupInfo { dir: string; @@ -38,7 +43,6 @@ interface RollupInfo { const rollupMap = new Map(); let bundleIndex = 0; let ws: WebSocket; -let h: Server; let wt: chokidar.FSWatcher; class RefValue extends EventEmitter { @@ -73,60 +77,115 @@ class RefValue extends EventEmitter { } } -function resolvePath(path: string) { - return resolve(base, path); +function resolvePath(path: string): ResolveResult { + const targetPath = resolve(base, path); + + const safe = targetPath.startsWith(checkBase); + return { + safe, + resolved: targetPath + }; } -/** - * 请求文件 - */ -async function getFile(req: Request, res: Response, path: string) { - try { - const data = await fs.readFile(resolvePath(path)); - if (path.endsWith('.js')) - res.writeHead(200, { 'Content-type': 'text/javascript' }); - if (path.endsWith('.css')) - res.writeHead(200, { 'Content-type': 'text/css' }); - if (path.endsWith('.html')) - res.writeHead(200, { 'Content-type': 'text/html' }); - return (res.end(data), true); - } catch (e) { - console.log(e); - return false; - } -} - -/** - * 高层塔优化及动画加载 - * @param suffix 后缀名 - * @param dir 文件夹路径 - * @param join 分隔符 - */ -async function getAll( - req: Request, - res: Response, - ids: string[], - suffix: string, - dir: string, - join: string -) { - let data: Record = {}; - const tasks = ids.map(v => { - return new Promise(res => { - const d = resolvePath(`${dir}${v}${suffix}`); - try { - fs.readFile(d).then(vv => { - data[v] = vv; - res(`${v} pack success.`); - }); - } catch (e) { - console.log(e); - } - }); +function parseBodyParam(body: string) { + const arr = body.split('&'); + const obj: Record = {}; + arr.forEach(v => { + const [name, value] = v.split('='); + obj[name] = value; }); - await Promise.all(tasks); - const result = ids.map(v => data[v]); - return (res.end(result.join(join)), true); + return obj; +} + +function withSafeCheck( + exec: (req: Request, res: Response, path: ResolveResult) => void +) { + return async (req: Request, res: Response) => { + const query = parseBodyParam(req.body); + const path = query.name ?? ''; + if (typeof path !== 'string') { + res.status(500).end('Parameter Error: File path is required.'); + return; + } + const dir = resolvePath(path); + if (!dir.safe) { + res.status(500).end( + 'Permission Error: Cannot access file outside current working directory.' + ); + return; + } else { + exec(req, res, dir); + } + }; +} + +interface AllFilesStatus { + status: APIStatus; + content: string; +} + +function getAllFiles(suffix: string, dir: string, join: string) { + return async (req: Request, res: Response) => { + const query = req.query ? req.query : parseBodyParam(req.body); + const id = query.id; + if (typeof id !== 'string') { + res.status(404).end('Parameter Error: file names is required.'); + return; + } + + const list = id.split(','); + const tasks = list.map>(async v => { + const path = resolvePath(`${dir}${v}${suffix}`); + if (!path.safe) { + return Promise.resolve({ + status: APIStatus.PermissionDeny, + content: '' + }); + } + + const exist = await pathExists(path.resolved); + if (!exist) { + return Promise.resolve({ + status: APIStatus.FileNotExist, + content: '' + }); + } + + return readFile(path.resolved, 'utf-8').then( + value => { + return { + status: APIStatus.Success, + content: value + }; + }, + reason => { + console.error(reason); + return { status: APIStatus.ReadError, content: '' }; + } + ); + }); + + const contents = await Promise.all(tasks); + if (contents.every(v => v.status === APIStatus.Success)) { + const content = contents.map(v => v.content).join(join); + if (suffix === '.js') { + res.writeHead(200, { 'Content-type': 'text/javascript' }); + } + res.end(content); + } else { + const strArray = contents.map((v, i) => { + if (v.status === APIStatus.PermissionDeny) { + return `Index: ${i}; Permission Error: Cannot access file outside current working directory`; + } else if (v.status === APIStatus.Success) { + return `Index: ${i}: Internal Error: Read file error.`; + } else { + return 'Success'; + } + }); + const str = strArray.filter(v => v !== 'Success').join('\n'); + res.status(500).end(str); + } + }; } async function getEsmFile( @@ -134,16 +193,22 @@ async function getEsmFile( res: Response, dir: string ): Promise { - const path = resolvePath(dir.replace('.esm', '')); + const path = resolvePath(dir); + if (!path.safe) { + res.status(500).end( + 'Permission Error: Cannot access file outside current working directory' + ); + return; + } - const watcher = rollupMap.get(path); + const watcher = rollupMap.get(path.resolved); if (!watcher) { const file = (bundleIndex++).toString(); - await fs.ensureDir('_bundle'); + await ensureDir('_bundle'); // 配置rollup监听器 const w = rollup.watch({ - input: path, + input: path.resolved, output: { file: `_bundle/${file}.js`, sourcemap: true, @@ -183,12 +248,13 @@ async function getEsmFile( }; w.on('event', e => { if (e.code === 'ERROR') { + res.status(500).end('Internal Error: Esm build error.'); console.log(e.error); } if (e.code === 'BUNDLE_END') { info.bundled.value = true; - console.log(`${path} bundle end`); + console.log(`${path.resolved} bundle end`); } if (e.code === 'BUNDLE_START') { @@ -197,184 +263,240 @@ async function getEsmFile( }); w.on('change', id => { console.log(`${id} changed. Refresh Page.`); - ws && ws.send(JSON.stringify({ type: 'reload' })); + if (ws) { + ws.send(JSON.stringify({ type: 'reload' })); + } }); - rollupMap.set(path, info); + rollupMap.set(path.resolved, info); // 配置完毕,直接重新获取即可( return getEsmFile(req, res, dir); } else { try { await watcher.bundled.waitValueTo(true); - const content = await fs.readFile(watcher.file, 'utf-8'); + const content = await readFile(watcher.file, 'utf-8'); res.writeHead(200, { 'Content-type': 'text/javascript' }); res.end(content); } catch (e) { - console.log(e); + console.error(e); } } } -/** - * 获取POST数据 - */ -async function getPostData(req: Request) { - let data = ''; - await new Promise(res => { - req.on('data', chunk => { - data += chunk.toString(); +const apiListFile = withSafeCheck(async (_, res, path) => { + const exist = await pathExists(path.resolved); + if (!exist) { + res.status(404).end('Permission Error: Path does not exist.'); + return; + } + try { + const data = await readdir(path.resolved); + res.end(JSON.stringify(data)); + } catch (e) { + console.error(e); + res.status(500).end('Internal Error: Read dir error.'); + } +}); + +const apiMakeDir = withSafeCheck(async (_, res, path) => { + try { + await ensureDir(path.resolved); + res.end(); + } catch (e) { + console.error(e); + res.status(500).end('Internal Error: Make dir error.'); + } +}); + +const apiReadFile = withSafeCheck(async (req, res, path) => { + const query = parseBodyParam(req.body); + const type = query.type ?? 'utf8'; + if (typeof type !== 'string') { + res.status(500).end('Internal Error: Query parsed failed.'); + return; + } + const exist = await pathExists(path.resolved); + if (!exist) { + res.status(404).end('Permission Error: Path does not exist.'); + return; + } + + try { + const file = await readFile(path.resolved, { + encoding: type as BufferEncoding }); - req.on('end', res); - }); - return data; -} - -async function readDir(req: Request, res: Response) { - const data = await getPostData(req); - const dir = resolvePath(data.toString().slice(5)); - try { - const info = await fs.readdir(dir); - res.end(JSON.stringify(info)); + res.end(file); } catch (e) { - console.log(e); - res.end(`Error: Read dir ${dir} fail. Does the dir exists?`); + console.error(e); + res.status(500).end('Internal Error: Read file error.'); } -} +}); -async function mkdir(req: Request, res: Response) { - const data = await getPostData(req); - const dir = resolvePath(data.toString().slice(5)); +const apiWriteFile = withSafeCheck(async (req, res, path) => { + const query = parseBodyParam(req.body); + const type = query.type ?? 'utf8'; + if (typeof type !== 'string') { + res.status(500).end('Internal Error: Query parsed failed.'); + return; + } + const value = query.value; + if (typeof value !== 'string') { + res.status(500).end('Parameter Error: File content is required.'); + return; + } try { - await fs.ensureDir(dir); - } catch (e) { - console.log(e); - } - res.end(); -} - -async function readFile(req: Request, res: Response) { - const data = (await getPostData(req)).toString(); - const dir = resolvePath(data.split('&name=')[1]); - try { - const type = /^type=(utf8|base64)/.exec(data)?.[0].slice(5) ?? 'utf8'; - const info = await fs.readFile(dir, { encoding: type }); - res.end(info); - } catch (e) { - console.log(e); - } -} - -async function writeFile(req: Request, res: Response) { - const data = (await getPostData(req)).toString(); - const name = data.split('&name=')[1].split('&value=')[0]; - const dir = resolvePath(name); - try { - const type = /^type=(utf8|base64)/.exec(data)?.[0].slice(5) ?? 'utf8'; - const value = /&value=.+/.exec(data)?.[0].slice(7) ?? ''; - await fs.writeFile(dir, value, { encoding: type }); - if (name.endsWith('project/events.js')) doDeclaration('events', value); - if (name.endsWith('project/items.js')) doDeclaration('items', value); - if (name.endsWith('project/maps.js')) doDeclaration('maps', value); - if (name.endsWith('project/data.js')) doDeclaration('data', value); - } catch (e) { - console.log(e); - res.end( - `error: Write file ${dir} fail. Does the parent folder exists?` - ); - } - res.end(); -} - -async function rm(req: Request, res: Response) { - const data = (await getPostData(req)).toString(); - const dir = resolvePath(data.slice(5)); - try { - await fs.remove(dir); - } catch (e) { - console.log(e); - res.end(`error: Remove file ${dir} fail. Does this file exists?`); - } - res.end(); -} - -async function moveFile(req: Request, res: Response) { - const data = (await getPostData(req)).toString(); - const info = data.split('&dest='); - const src = resolvePath(info[0].slice(4)); - const dest = resolvePath(info[1]); - try { - await fs.move(src, dest); - } catch (e) { - console.log(e); - } - res.end(); -} - -async function writeMultiFiles(req: Request, res: Response) { - const data = (await getPostData(req)).toString(); - const names = - /name=.+&value=/.exec(data)?.[0].slice(5, -7).split(';') ?? []; - const value = /&value=.+/.exec(data)?.[0].slice(7).split(';') ?? []; - - const tasks = names.map((v, i) => { - try { - return new Promise(res => { - fs.writeFile( - resolvePath(v), - value[i], - 'base64' // 多文件是base64写入的 - ).then(v => { - res(`write ${v} success.`); - }); - }); - } catch (e) { - console.log(e); - res.end(`error: Write multi files fail.`); + await writeFile(path.resolved, value, { + encoding: type as BufferEncoding + }); + res.end(); + if (path.resolved.endsWith('project/events.js')) { + doDeclaration('events', value); + } + if (path.resolved.endsWith('project/items.js')) { + doDeclaration('items', value); + } + if (path.resolved.endsWith('project/maps.js')) { + doDeclaration('maps', value); + } + if (path.resolved.endsWith('project/data.js')) { + doDeclaration('data', value); } - }); - await Promise.all(tasks).catch(e => console.log(e)); - res.end(); -} - -async function writeDevResource(data: string) { - return; - try { - const buf = Buffer.from(data, 'base64'); - data = buf.toString('utf-8'); - const info = JSON.parse(data.split('\n').slice(1).join('')); - const res: string[] = []; - const icons = await fs.readFile('./public/project/icons.js', 'utf-8'); - const iconData = JSON.parse(icons.split('\n').slice(1).join('')); - res.push( - ...info.main.bgms.map((v: any) => `audio/${v}`), - ...info.main.fonts.map((v: any) => `buffer/project/fonts/${v}.ttf`), - ...info.main.images.map((v: any) => `image/project/images/${v}`), - ...info.main.sounds.map((v: any) => `buffer/${v}`), - ...info.main.tilesets.map((v: any) => `image/project/tilesets${v}`), - ...Object.keys(iconData.autotile).map( - v => `image/project/autotiles/${v}.png` - ), - ...[ - 'animates', - 'cloud', - 'enemy48', - 'enemys', - 'fog', - 'icons', - 'items', - 'keyboard', - 'npc48', - 'npcs', - 'sun', - 'terrains' - ].map(v => `material/${v}.png`) - ); - const text = JSON.stringify(res, void 0, 4); - await fs.writeFile('./src/data/resource-dev.json', text, 'utf-8'); } catch (e) { - console.log(e); + console.error(e); + res.status(500).end( + 'Internal Error: Fail to write file or fail to do declaration.' + ); } -} +}); + +const apiDeleteFile = withSafeCheck(async (_, res, path) => { + const exist = await pathExists(path.resolved); + if (!exist) { + res.status(404).end('Permission Error: Path does not exist.'); + return; + } + try { + await remove(path.resolved); + res.end(); + } catch (e) { + console.error(e); + res.status(500).end('Internal Error: Remove file error.'); + } +}); + +const apiMoveFile = async (req: Request, res: Response) => { + const query = parseBodyParam(req.body); + const src = query.src; + const dest = query.dest; + + if (typeof src !== 'string' || typeof dest !== 'string') { + res.status(500).end( + 'Parameter Error: Source path or destination path is required.' + ); + return; + } + + const srcPath = resolvePath(src); + const destPath = resolvePath(dest); + + if (!srcPath.safe || !destPath.safe) { + res.status(500).end( + 'Permission Error: Cannot access file outside current working directory.' + ); + } + + try { + await move(srcPath.resolved, destPath.resolved); + res.end(); + } catch (e) { + console.error(e); + res.status(500).end('Internal Error: Move file error.'); + } +}; + +const apiWriteMultiFiles = async (req: Request, res: Response) => { + const query = parseBodyParam(req.body); + const name = query.name; + const value = query.value; + + if (typeof name !== 'string' || typeof value !== 'string') { + res.status(500).end( + 'Parameter Error: File names and content is required.' + ); + return; + } + + const pathList = name.split(';'); + const valueList = value.split(';'); + + if (pathList.length !== valueList.length) { + res.status(500).end( + 'Parameter Error: File name and content count must match.' + ); + return; + } + + const tasks = pathList.map>((v, i) => { + const path = resolvePath(v); + if (!path.safe) { + return Promise.resolve(APIStatus.PermissionDeny); + } + return new Promise(resolve => { + writeFile(v, valueList[i]).then( + () => { + resolve(APIStatus.Success); + }, + reason => { + console.error(reason); + resolve(APIStatus.WriteError); + } + ); + }); + }); + + const status = await Promise.all(tasks); + + if (status.every(v => v === APIStatus.Success)) { + res.end(); + } else { + const strArray = status.map((v, i) => { + if (v === APIStatus.PermissionDeny) { + return `Index: ${i}; Permission Error: Cannot access file outside current working directory`; + } else if (v === APIStatus.Success) { + return `Index: ${i}: Internal Error: Write file error.`; + } else { + return 'Success'; + } + }); + const str = strArray.filter(v => v !== 'Success').join('\n'); + res.status(500).end(str); + } +}; + +const apiGetAllFloors = getAllFiles('.js', 'project/floors/', '\n'); +const apiGetAllAnimates = getAllFiles( + '.animate', + 'project/animates/', + '@@@~~~###~~~@@@' +); + +const apiGetEsmFiles = async (req: Request, res: Response) => { + const query = req.query ? req.query : parseBodyParam(req.body); + const name = query.name; + if (typeof name !== 'string') { + res.status(500).end('Parameter Error: File name is required.'); + return; + } + const path = resolvePath(join('..', name)); + if (!path.safe) { + res.status(500).end( + 'Permission Error: Cannot access file outside current working directory' + ); + return; + } + + return getEsmFile(req, res, path.resolved); +}; /** * 声明某种类型 @@ -393,7 +515,7 @@ async function doDeclaration(type: string, data: string) { for (const id in eventData.commonEvent) { eventDec += ` | '${id}'\n`; } - await fs.writeFile('src/source/events.d.ts', eventDec, 'utf-8'); + await writeFile('src/source/events.d.ts', eventDec, 'utf-8'); } else if (type === 'items') { // 道具 const itemData = JSON.parse(data.split('\n').slice(1).join('')); @@ -403,7 +525,7 @@ async function doDeclaration(type: string, data: string) { itemDec += ` ${id}: '${itemData[id].cls}';\n`; } itemDec += '}'; - await fs.writeFile('src/source/items.d.ts', itemDec, 'utf-8'); + await writeFile('src/source/items.d.ts', itemDec, 'utf-8'); } else if (type === 'maps') { // 映射 const d = JSON.parse(data.split('\n').slice(1).join('')); @@ -420,8 +542,8 @@ async function doDeclaration(type: string, data: string) { id2cls += '}'; id2num += '}'; num2id += '}'; - await fs.writeFile('src/source/cls.d.ts', id2cls, 'utf-8'); - await fs.writeFile( + await writeFile('src/source/cls.d.ts', id2cls, 'utf-8'); + await writeFile( 'src/source/maps.d.ts', `${id2num}\n${num2id}`, 'utf-8' @@ -449,7 +571,7 @@ async function doDeclaration(type: string, data: string) { } names += '}'; - await fs.writeFile( + await writeFile( 'src/source/data.d.ts', ` ${floorId} @@ -468,75 +590,6 @@ ${names} } } -async function startHttpServer(port: number = 3000) { - if (h) return h; - const server = http(); - const data = await fs.readFile('public/project/data.js', 'utf-8'); - const json = data.split('\n').slice(1).join('\n'); - const parsed = JSON.parse(json); - const name = parsed.firstData.name; - - server.listen(port, '127.0.0.1'); - - server.on('listening', () => { - console.log(`编辑器地址:http://127.0.0.1:${port}/editor.html`); - console.log(`文档地址:http://127.0.0.1:${port}/_docs/index.html`); - setupHttp(server, name); - }); - - return server; -} - -function setupHttp(server: Server, name: string) { - server.on('request', async (req, res) => { - const p = req.url - ?.replace(`/games/${name}`, '') - .replace('/all/', '/') // 样板中特殊处理的all文件 - .replace('/forceTem/', '/') // 强制用样板的http服务获取文件 - .replace('/src/', '../src/'); // src在上一级目录 - if (isNil(p)) return; - - if (req.method === 'GET') { - const dir = resolvePath( - p === '/' ? 'index.html' : p.slice(1) - ).split('?v=')[0]; - - if (/.*\.esm\..*/.test(p)) { - // xxx.esm.xxx,说明是需要打包的es模块化文件,需要rollup打包后传输 - return getEsmFile(req, res, p); - } - - if (p.startsWith('/__all_floors__.js')) { - const all = p.split('&id=')[1].split(','); - res.writeHead(200, { 'Content-type': 'text/javascript' }); - return getAll(req, res, all, '.js', 'project/floors/', '\n'); - } - - if (p.startsWith('/__all_animates__')) { - const all = p.split('&id=')[1].split(','); - const split = '@@@~~~###~~~@@@'; - const dir = 'project/animates/'; - return getAll(req, res, all, '.animate', dir, split); - } - - if (await getFile(req, res, dir)) return; - } - - if (req.method === 'POST') { - if (p === '/listFile') return readDir(req, res); - if (p === '/makeDir') return mkdir(req, res); - if (p === '/readFile') return readFile(req, res); - if (p === '/writeFile') return writeFile(req, res); - if (p === '/deleteFile') return rm(req, res); - if (p === '/moveFile') return moveFile(req, res); - if (p === '/writeMultiFiles') return writeMultiFiles(req, res); - } - - res.statusCode = 404; - res.end(); - }); -} - function watchProject() { if (wt) return; const watcher = chokidar.watch('public/', { @@ -548,25 +601,26 @@ function watchProject() { '**/_docs/**', '**/_save/**', /\.min\./, - /(^|[\/\\])\../, - /(^|[\/\\])[^a-zA-Z:\._0-9\/\\]/, + /(^|[/\\])\../, + /(^|[/\\])[^a-zA-Z:._0-9/\\]/, /_.*/ ] }); wt = watcher; watcher.removeAllListeners(); watcher.on('change', async path => { + if (!ws) return; // 楼层热重载 if (/project(\/|\\)floors(\/|\\).*\.js$/.test(path)) { const floor = basename(path).slice(0, -3); - ws && ws.send(JSON.stringify({ type: 'floorHotReload', floor })); + ws.send(JSON.stringify({ type: 'floorHotReload', floor })); console.log(`Floor hot reload: ${floor}.`); return; } // 脚本编辑热重载 if (/project(\/|\\)functions\.js$/.test(path)) { - ws && ws.send(JSON.stringify({ type: 'functionsHotReload' })); + ws.send(JSON.stringify({ type: 'functionsHotReload' })); console.log(`Functions hot reload.`); return; } @@ -574,20 +628,20 @@ function watchProject() { // 数据热重载 if (/project(\/|\\).*\.js/.test(path)) { const data = basename(path).slice(0, -3); - ws && ws.send(JSON.stringify({ type: 'dataHotReload', data })); + ws.send(JSON.stringify({ type: 'dataHotReload', data })); console.log(`Data hot reload: ${data}.`); return; } // css热重载 if (/.*\.css$/.test(path)) { - ws && ws.send(JSON.stringify({ type: 'cssHotReload', path })); + ws.send(JSON.stringify({ type: 'cssHotReload', path })); console.log(`Css hot reload: ${path}.`); return; } // 剩余内容全部reload - ws && ws.send(JSON.stringify({ type: 'reload' })); + ws.send(JSON.stringify({ type: 'reload' })); }); } @@ -599,23 +653,24 @@ function setupSocket(socket: WebSocket) { async function startWsServer(http: Server) { if (ws) return; - return new Promise(res => { - const server = new WebSocketServer({ - server: http - }); - server.on('connection', socket => { - setupSocket(socket); - res(server); - }); + const server = new WebSocketServer({ + server: http + }); + + server.on('connection', socket => { + setupSocket(socket); }); } async function ensureConfig() { - try { - await fs.readFile(resolvePath('_server/config.json')); - } catch { - await fs.writeFile(resolvePath('_server/config.json'), '{}', 'utf-8'); + const { resolved, safe } = resolvePath('_server/config.json'); + if (!safe) { + throw new Error('Internal Error: Fail to access editor config file.'); + } + const exist = await pathExists(resolved); + if (!exist) { + return writeFile(resolved, '{}', { encoding: 'utf-8' }); } } @@ -627,11 +682,34 @@ async function ensureConfig() { // 2. 启动样板http服务 await ensureConfig(); - const server = await startHttpServer(serverPort); - h = server; + + const app = express(); + app.use(express.text()); + app.use(express.urlencoded({ extended: true })); + app.use(express.static(base)); + + app.post('/listFile', apiListFile); + app.post('/makeDir', apiMakeDir); + app.post('/readFile', apiReadFile); + app.post('/writeFile', apiWriteFile); + app.post('/deleteFile', apiDeleteFile); + app.post('/moveFile', apiMoveFile); + app.post('/writeMultiFiles', apiWriteMultiFiles); + app.get('/all/__all_floors__.js', apiGetAllFloors); + app.get('/all/__all_animates__', apiGetAllAnimates); + app.get('/esm', apiGetEsmFiles); + + const server = app.listen(serverPort); + + server.on('listening', () => { + console.log(`编辑器地址:http://127.0.0.1:${serverPort}/editor.html`); + console.log( + `文档地址:http://127.0.0.1:${serverPort}/_docs/index.html` + ); + }); // 3. 启动样板ws热重载服务 - await startWsServer(server); + startWsServer(server); process.on('SIGTERM', () => { vite.close(); diff --git a/vite.config.ts b/vite.config.ts index 3c82cd4..f0f4f14 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -70,13 +70,7 @@ export default defineConfig({ '/makeDir': FSHOST, '/moveFile': FSHOST, '/deleteFile': FSHOST, - '^/all/.*': { - target: FSHOST, - changeOrigin: true, - rewrite(path) { - return path.replace(/^\/all/, ''); - }, - }, + '^/all/.*': FSHOST, '^/forceTem/.*': { target: FSHOST, changeOrigin: true,