Merge branch 'staging' into small-bookmark-updates

d082c2f14dae9840f6e9fbeae9d6e4f4dbd5de26

Cohee <18619528+Cohee1207@users.noreply.github.com>

13 files changed, +744 -127Showing whitespace changes
.github/readme.md+40 -0
@@ -276,6 +276,46 @@ In order to enable viewing your keys by clicking a button in the API block:
2761. Set the value of `allowKeysExposure` to `true` in `config.yaml` file.2761. Set the value of `allowKeysExposure` to `true` in `config.yaml` file.
2772. Restart the SillyTavern server.2772. Restart the SillyTavern server.
278278
279## Command-line arguments
280
281You can pass command-line arguments to SillyTavern server startup to override some settings in `config.yaml`.
282
283### Examples
284
285```shell
286node server.js --port 8000 --listen false
287# or
288npm run start -- --port 8000 --listen false
289# or (Windows only)
290Start.bat --port 8000 --listen false
291```
292
293### Supported arguments
294
295| Option | Description | Type | Default |
296|-------------------------|------------------------------------------------------------------------------------------------------|----------|------------------------------|
297| `--version` | Show version number | boolean | |
298| `--enableIPv6` | Enables IPv6. | boolean | false |
299| `--enableIPv4` | Enables IPv4. | boolean | true |
300| `--port` | Sets the port under which SillyTavern will run. If not provided falls back to yaml config 'port'. | number | 8000 |
301| `--dnsPreferIPv6` | Prefers IPv6 for dns. If not provided falls back to yaml config 'preferIPv6'. | boolean | false |
302| `--autorun` | Automatically launch SillyTavern in the browser. If not provided falls back to yaml config 'autorun'.| boolean | false |
303| `--autorunHostname` | The autorun hostname, probably best left on 'auto'. | string | null |
304| `--autorunPortOverride` | Overrides the port for autorun. | string | null |
305| `--listen` | SillyTavern is listening on all network interfaces. If not provided falls back to yaml config 'listen'.| boolean | false |
306| `--corsProxy` | Enables CORS proxy. If not provided falls back to yaml config 'enableCorsProxy'. | boolean | false |
307| `--disableCsrf` | Disables CSRF protection | boolean | null |
308| `--ssl` | Enables SSL | boolean | false |
309| `--certPath` | Path to your certificate file. | string | "certs/cert.pem" |
310| `--keyPath` | Path to your private key file. | string | "certs/privkey.pem" |
311| `--whitelist` | Enables whitelist mode | boolean | null |
312| `--dataRoot` | Root directory for data storage | string | null |
313| `--avoidLocalhost` | Avoids using 'localhost' for autorun in auto mode. | boolean | null |
314| `--basicAuthMode` | Enables basic authentication | boolean | null |
315| `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean | null |
316| `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string | null |
317| `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array | null |
318
279## Remote connections319## Remote connections
280320
281Most often this is for people who want to use SillyTavern on their mobile phones while their PC runs the ST server on the same wifi network.321Most often this is for people who want to use SillyTavern on their mobile phones while their PC runs the ST server on the same wifi network.
default/config.yaml+10 -0
@@ -37,6 +37,16 @@ basicAuthUser:
37 password: "password"37 password: "password"
38# Enables CORS proxy middleware38# Enables CORS proxy middleware
39enableCorsProxy: false39enableCorsProxy: false
40# -- REQUEST PROXY CONFIGURATION --
41requestProxy:
42 # If a proxy is enabled, all outgoing HTTP/HTTPS requests will be routed through it.
43 enabled: false
44 # Proxy URL. Possible protocols: http, https, socks, socks5, socks4, pac
45 url: "socks5://username:password@example.com:1080"
46 # Proxy bypass list. Requests to these hosts won't be routed through the proxy.
47 bypass:
48 - localhost
49 - 127.0.0.1
40# Enable multi-user mode50# Enable multi-user mode
41enableUserAccounts: false51enableUserAccounts: false
42# Enable discreet login mode: hides user list on the login screen52# Enable discreet login mode: hides user list on the login screen
package-lock.json+483 -33
@@ -22,7 +22,7 @@
22 "cookie-session": "^2.1.0",22 "cookie-session": "^2.1.0",
23 "cors": "^2.8.5",23 "cors": "^2.8.5",
24 "csrf-csrf": "^2.2.3",24 "csrf-csrf": "^2.2.3",
25 "express": "^4.19.2",25 "express": "^4.20.0",
26 "form-data": "^4.0.0",26 "form-data": "^4.0.0",
27 "google-translate-api-browser": "^3.0.1",27 "google-translate-api-browser": "^3.0.1",
28 "he": "^1.2.0",28 "he": "^1.2.0",
@@ -40,6 +40,7 @@
40 "png-chunk-text": "^1.0.0",40 "png-chunk-text": "^1.0.0",
41 "png-chunks-encode": "^1.0.0",41 "png-chunks-encode": "^1.0.0",
42 "png-chunks-extract": "^1.0.0",42 "png-chunks-extract": "^1.0.0",
43 "proxy-agent": "^6.4.0",
43 "rate-limiter-flexible": "^5.0.0",44 "rate-limiter-flexible": "^5.0.0",
44 "response-time": "^2.3.2",45 "response-time": "^2.3.2",
45 "sanitize-filename": "^1.6.3",46 "sanitize-filename": "^1.6.3",
@@ -941,6 +942,12 @@
941 "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",942 "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
942 "license": "MIT"943 "license": "MIT"
943 },944 },
945 "node_modules/@tootallnate/quickjs-emscripten": {
946 "version": "0.23.0",
947 "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
948 "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
949 "license": "MIT"
950 },
944 "node_modules/@types/cacheable-request": {951 "node_modules/@types/cacheable-request": {
945 "version": "6.0.3",952 "version": "6.0.3",
946 "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",953 "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
@@ -1080,6 +1087,41 @@
1080 "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"1087 "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
1081 }1088 }
1082 },1089 },
1090 "node_modules/agent-base": {
1091 "version": "7.1.1",
1092 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
1093 "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
1094 "license": "MIT",
1095 "dependencies": {
1096 "debug": "^4.3.4"
1097 },
1098 "engines": {
1099 "node": ">= 14"
1100 }
1101 },
1102 "node_modules/agent-base/node_modules/debug": {
1103 "version": "4.3.7",
1104 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1105 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1106 "license": "MIT",
1107 "dependencies": {
1108 "ms": "^2.1.3"
1109 },
1110 "engines": {
1111 "node": ">=6.0"
1112 },
1113 "peerDependenciesMeta": {
1114 "supports-color": {
1115 "optional": true
1116 }
1117 }
1118 },
1119 "node_modules/agent-base/node_modules/ms": {
1120 "version": "2.1.3",
1121 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1122 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1123 "license": "MIT"
1124 },
1083 "node_modules/agentkeepalive": {1125 "node_modules/agentkeepalive": {
1084 "version": "4.5.0",1126 "version": "4.5.0",
1085 "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",1127 "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",
@@ -1382,6 +1424,18 @@
1382 "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",1424 "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
1383 "license": "MIT"1425 "license": "MIT"
1384 },1426 },
1427 "node_modules/ast-types": {
1428 "version": "0.13.4",
1429 "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
1430 "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
1431 "license": "MIT",
1432 "dependencies": {
1433 "tslib": "^2.0.1"
1434 },
1435 "engines": {
1436 "node": ">=4"
1437 }
1438 },
1385 "node_modules/async": {1439 "node_modules/async": {
1386 "version": "3.2.5",1440 "version": "3.2.5",
1387 "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",1441 "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
@@ -1445,6 +1499,15 @@
1445 ],1499 ],
1446 "license": "MIT"1500 "license": "MIT"
1447 },1501 },
1502 "node_modules/basic-ftp": {
1503 "version": "5.0.5",
1504 "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
1505 "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
1506 "license": "MIT",
1507 "engines": {
1508 "node": ">=10.0.0"
1509 }
1510 },
1448 "node_modules/bing-translate-api": {1511 "node_modules/bing-translate-api": {
1449 "version": "2.9.1",1512 "version": "2.9.1",
1450 "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-2.9.1.tgz",1513 "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-2.9.1.tgz",
@@ -2250,6 +2313,15 @@
2250 "url": "https://github.com/sponsors/fb55"2313 "url": "https://github.com/sponsors/fb55"
2251 }2314 }
2252 },2315 },
2316 "node_modules/data-uri-to-buffer": {
2317 "version": "6.0.2",
2318 "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
2319 "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
2320 "license": "MIT",
2321 "engines": {
2322 "node": ">= 14"
2323 }
2324 },
2253 "node_modules/debug": {2325 "node_modules/debug": {
2254 "version": "2.6.9",2326 "version": "2.6.9",
2255 "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",2327 "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -2316,6 +2388,20 @@
2316 "node": ">=8"2388 "node": ">=8"
2317 }2389 }
2318 },2390 },
2391 "node_modules/degenerator": {
2392 "version": "5.0.1",
2393 "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
2394 "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
2395 "license": "MIT",
2396 "dependencies": {
2397 "ast-types": "^0.13.4",
2398 "escodegen": "^2.1.0",
2399 "esprima": "^4.0.1"
2400 },
2401 "engines": {
2402 "node": ">= 14"
2403 }
2404 },
2319 "node_modules/delayed-stream": {2405 "node_modules/delayed-stream": {
2320 "version": "1.0.0",2406 "version": "1.0.0",
2321 "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",2407 "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -2528,6 +2614,27 @@
2528 "node": ">=0.8.0"2614 "node": ">=0.8.0"
2529 }2615 }
2530 },2616 },
2617 "node_modules/escodegen": {
2618 "version": "2.1.0",
2619 "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
2620 "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
2621 "license": "BSD-2-Clause",
2622 "dependencies": {
2623 "esprima": "^4.0.1",
2624 "estraverse": "^5.2.0",
2625 "esutils": "^2.0.2"
2626 },
2627 "bin": {
2628 "escodegen": "bin/escodegen.js",
2629 "esgenerate": "bin/esgenerate.js"
2630 },
2631 "engines": {
2632 "node": ">=6.0"
2633 },
2634 "optionalDependencies": {
2635 "source-map": "~0.6.1"
2636 }
2637 },
2531 "node_modules/eslint": {2638 "node_modules/eslint": {
2532 "version": "8.57.0",2639 "version": "8.57.0",
2533 "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",2640 "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
@@ -2683,6 +2790,19 @@
2683 "url": "https://opencollective.com/eslint"2790 "url": "https://opencollective.com/eslint"
2684 }2791 }
2685 },2792 },
2793 "node_modules/esprima": {
2794 "version": "4.0.1",
2795 "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
2796 "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
2797 "license": "BSD-2-Clause",
2798 "bin": {
2799 "esparse": "bin/esparse.js",
2800 "esvalidate": "bin/esvalidate.js"
2801 },
2802 "engines": {
2803 "node": ">=4"
2804 }
2805 },
2686 "node_modules/esquery": {2806 "node_modules/esquery": {
2687 "version": "1.5.0",2807 "version": "1.5.0",
2688 "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",2808 "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
@@ -2713,7 +2833,6 @@
2713 "version": "5.3.0",2833 "version": "5.3.0",
2714 "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",2834 "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
2715 "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",2835 "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
2716 "dev": true,
2717 "license": "BSD-2-Clause",2836 "license": "BSD-2-Clause",
2718 "engines": {2837 "engines": {
2719 "node": ">=4.0"2838 "node": ">=4.0"
@@ -2723,7 +2842,6 @@
2723 "version": "2.0.3",2842 "version": "2.0.3",
2724 "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",2843 "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
2725 "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",2844 "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
2726 "dev": true,
2727 "license": "BSD-2-Clause",2845 "license": "BSD-2-Clause",
2728 "engines": {2846 "engines": {
2729 "node": ">=0.10.0"2847 "node": ">=0.10.0"
@@ -3071,6 +3189,20 @@
3071 "node": ">= 0.6"3189 "node": ">= 0.6"
3072 }3190 }
3073 },3191 },
3192 "node_modules/fs-extra": {
3193 "version": "11.2.0",
3194 "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
3195 "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
3196 "license": "MIT",
3197 "dependencies": {
3198 "graceful-fs": "^4.2.0",
3199 "jsonfile": "^6.0.1",
3200 "universalify": "^2.0.0"
3201 },
3202 "engines": {
3203 "node": ">=14.14"
3204 }
3205 },
3074 "node_modules/fs.realpath": {3206 "node_modules/fs.realpath": {
3075 "version": "1.0.0",3207 "version": "1.0.0",
3076 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",3208 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -3130,6 +3262,44 @@
3130 "url": "https://github.com/sponsors/sindresorhus"3262 "url": "https://github.com/sponsors/sindresorhus"
3131 }3263 }
3132 },3264 },
3265 "node_modules/get-uri": {
3266 "version": "6.0.3",
3267 "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz",
3268 "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==",
3269 "license": "MIT",
3270 "dependencies": {
3271 "basic-ftp": "^5.0.2",
3272 "data-uri-to-buffer": "^6.0.2",
3273 "debug": "^4.3.4",
3274 "fs-extra": "^11.2.0"
3275 },
3276 "engines": {
3277 "node": ">= 14"
3278 }
3279 },
3280 "node_modules/get-uri/node_modules/debug": {
3281 "version": "4.3.7",
3282 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
3283 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
3284 "license": "MIT",
3285 "dependencies": {
3286 "ms": "^2.1.3"
3287 },
3288 "engines": {
3289 "node": ">=6.0"
3290 },
3291 "peerDependenciesMeta": {
3292 "supports-color": {
3293 "optional": true
3294 }
3295 }
3296 },
3297 "node_modules/get-uri/node_modules/ms": {
3298 "version": "2.1.3",
3299 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
3300 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
3301 "license": "MIT"
3302 },
3133 "node_modules/gifwrap": {3303 "node_modules/gifwrap": {
3134 "version": "0.10.1",3304 "version": "0.10.1",
3135 "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz",3305 "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz",
@@ -3369,6 +3539,42 @@
3369 "node": ">= 0.8"3539 "node": ">= 0.8"
3370 }3540 }
3371 },3541 },
3542 "node_modules/http-proxy-agent": {
3543 "version": "7.0.2",
3544 "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
3545 "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
3546 "license": "MIT",
3547 "dependencies": {
3548 "agent-base": "^7.1.0",
3549 "debug": "^4.3.4"
3550 },
3551 "engines": {
3552 "node": ">= 14"
3553 }
3554 },
3555 "node_modules/http-proxy-agent/node_modules/debug": {
3556 "version": "4.3.7",
3557 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
3558 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
3559 "license": "MIT",
3560 "dependencies": {
3561 "ms": "^2.1.3"
3562 },
3563 "engines": {
3564 "node": ">=6.0"
3565 },
3566 "peerDependenciesMeta": {
3567 "supports-color": {
3568 "optional": true
3569 }
3570 }
3571 },
3572 "node_modules/http-proxy-agent/node_modules/ms": {
3573 "version": "2.1.3",
3574 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
3575 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
3576 "license": "MIT"
3577 },
3372 "node_modules/http2-wrapper": {3578 "node_modules/http2-wrapper": {
3373 "version": "1.0.3",3579 "version": "1.0.3",
3374 "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",3580 "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
@@ -3382,6 +3588,42 @@
3382 "node": ">=10.19.0"3588 "node": ">=10.19.0"
3383 }3589 }
3384 },3590 },
3591 "node_modules/https-proxy-agent": {
3592 "version": "7.0.5",
3593 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
3594 "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
3595 "license": "MIT",
3596 "dependencies": {
3597 "agent-base": "^7.0.2",
3598 "debug": "4"
3599 },
3600 "engines": {
3601 "node": ">= 14"
3602 }
3603 },
3604 "node_modules/https-proxy-agent/node_modules/debug": {
3605 "version": "4.3.7",
3606 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
3607 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
3608 "license": "MIT",
3609 "dependencies": {
3610 "ms": "^2.1.3"
3611 },
3612 "engines": {
3613 "node": ">=6.0"
3614 },
3615 "peerDependenciesMeta": {
3616 "supports-color": {
3617 "optional": true
3618 }
3619 }
3620 },
3621 "node_modules/https-proxy-agent/node_modules/ms": {
3622 "version": "2.1.3",
3623 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
3624 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
3625 "license": "MIT"
3626 },
3385 "node_modules/humanize-ms": {3627 "node_modules/humanize-ms": {
3386 "version": "1.2.1",3628 "version": "1.2.1",
3387 "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",3629 "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
@@ -3485,6 +3727,19 @@
3485 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",3727 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
3486 "license": "ISC"3728 "license": "ISC"
3487 },3729 },
3730 "node_modules/ip-address": {
3731 "version": "9.0.5",
3732 "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
3733 "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
3734 "license": "MIT",
3735 "dependencies": {
3736 "jsbn": "1.1.0",
3737 "sprintf-js": "^1.1.3"
3738 },
3739 "engines": {
3740 "node": ">= 12"
3741 }
3742 },
3488 "node_modules/ip-matching": {3743 "node_modules/ip-matching": {
3489 "version": "2.1.2",3744 "version": "2.1.2",
3490 "resolved": "https://registry.npmjs.org/ip-matching/-/ip-matching-2.1.2.tgz",3745 "resolved": "https://registry.npmjs.org/ip-matching/-/ip-matching-2.1.2.tgz",
@@ -3669,6 +3924,12 @@
3669 "js-yaml": "bin/js-yaml.js"3924 "js-yaml": "bin/js-yaml.js"
3670 }3925 }
3671 },3926 },
3927 "node_modules/jsbn": {
3928 "version": "1.1.0",
3929 "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
3930 "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
3931 "license": "MIT"
3932 },
3672 "node_modules/json-buffer": {3933 "node_modules/json-buffer": {
3673 "version": "3.0.1",3934 "version": "3.0.1",
3674 "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",3935 "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -3761,6 +4022,18 @@
3761 "dev": true,4022 "dev": true,
3762 "license": "MIT"4023 "license": "MIT"
3763 },4024 },
4025 "node_modules/jsonfile": {
4026 "version": "6.1.0",
4027 "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
4028 "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
4029 "license": "MIT",
4030 "dependencies": {
4031 "universalify": "^2.0.0"
4032 },
4033 "optionalDependencies": {
4034 "graceful-fs": "^4.1.6"
4035 }
4036 },
3764 "node_modules/keygrip": {4037 "node_modules/keygrip": {
3765 "version": "1.1.0",4038 "version": "1.1.0",
3766 "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",4039 "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
@@ -4053,6 +4326,15 @@
4053 "node": ">= 0.6"4326 "node": ">= 0.6"
4054 }4327 }
4055 },4328 },
4329 "node_modules/netmask": {
4330 "version": "2.0.2",
4331 "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
4332 "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
4333 "license": "MIT",
4334 "engines": {
4335 "node": ">= 0.4.0"
4336 }
4337 },
4056 "node_modules/node-domexception": {4338 "node_modules/node-domexception": {
4057 "version": "1.0.0",4339 "version": "1.0.0",
4058 "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",4340 "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@@ -4323,6 +4605,61 @@
4323 "url": "https://github.com/sponsors/sindresorhus"4605 "url": "https://github.com/sponsors/sindresorhus"
4324 }4606 }
4325 },4607 },
4608 "node_modules/pac-proxy-agent": {
4609 "version": "7.0.2",
4610 "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz",
4611 "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==",
4612 "license": "MIT",
4613 "dependencies": {
4614 "@tootallnate/quickjs-emscripten": "^0.23.0",
4615 "agent-base": "^7.0.2",
4616 "debug": "^4.3.4",
4617 "get-uri": "^6.0.1",
4618 "http-proxy-agent": "^7.0.0",
4619 "https-proxy-agent": "^7.0.5",
4620 "pac-resolver": "^7.0.1",
4621 "socks-proxy-agent": "^8.0.4"
4622 },
4623 "engines": {
4624 "node": ">= 14"
4625 }
4626 },
4627 "node_modules/pac-proxy-agent/node_modules/debug": {
4628 "version": "4.3.7",
4629 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
4630 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
4631 "license": "MIT",
4632 "dependencies": {
4633 "ms": "^2.1.3"
4634 },
4635 "engines": {
4636 "node": ">=6.0"
4637 },
4638 "peerDependenciesMeta": {
4639 "supports-color": {
4640 "optional": true
4641 }
4642 }
4643 },
4644 "node_modules/pac-proxy-agent/node_modules/ms": {
4645 "version": "2.1.3",
4646 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
4647 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
4648 "license": "MIT"
4649 },
4650 "node_modules/pac-resolver": {
4651 "version": "7.0.1",
4652 "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
4653 "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
4654 "license": "MIT",
4655 "dependencies": {
4656 "degenerator": "^5.0.0",
4657 "netmask": "^2.0.2"
4658 },
4659 "engines": {
4660 "node": ">= 14"
4661 }
4662 },
4326 "node_modules/pako": {4663 "node_modules/pako": {
4327 "version": "1.0.11",4664 "version": "1.0.11",
4328 "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",4665 "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@@ -4618,6 +4955,57 @@
4618 "node": ">= 0.10"4955 "node": ">= 0.10"
4619 }4956 }
4620 },4957 },
4958 "node_modules/proxy-agent": {
4959 "version": "6.4.0",
4960 "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz",
4961 "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==",
4962 "license": "MIT",
4963 "dependencies": {
4964 "agent-base": "^7.0.2",
4965 "debug": "^4.3.4",
4966 "http-proxy-agent": "^7.0.1",
4967 "https-proxy-agent": "^7.0.3",
4968 "lru-cache": "^7.14.1",
4969 "pac-proxy-agent": "^7.0.1",
4970 "proxy-from-env": "^1.1.0",
4971 "socks-proxy-agent": "^8.0.2"
4972 },
4973 "engines": {
4974 "node": ">= 14"
4975 }
4976 },
4977 "node_modules/proxy-agent/node_modules/debug": {
4978 "version": "4.3.7",
4979 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
4980 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
4981 "license": "MIT",
4982 "dependencies": {
4983 "ms": "^2.1.3"
4984 },
4985 "engines": {
4986 "node": ">=6.0"
4987 },
4988 "peerDependenciesMeta": {
4989 "supports-color": {
4990 "optional": true
4991 }
4992 }
4993 },
4994 "node_modules/proxy-agent/node_modules/lru-cache": {
4995 "version": "7.18.3",
4996 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
4997 "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
4998 "license": "ISC",
4999 "engines": {
5000 "node": ">=12"
5001 }
5002 },
5003 "node_modules/proxy-agent/node_modules/ms": {
5004 "version": "2.1.3",
5005 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
5006 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
5007 "license": "MIT"
5008 },
4621 "node_modules/proxy-from-env": {5009 "node_modules/proxy-from-env": {
4622 "version": "1.1.0",5010 "version": "1.1.0",
4623 "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",5011 "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -5006,36 +5394,6 @@
5006 "node": ">= 0.8.0"5394 "node": ">= 0.8.0"
5007 }5395 }
5008 },5396 },
5009 "node_modules/serve-static/node_modules/ms": {
5010 "version": "2.1.3",
5011 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
5012 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
5013 "license": "MIT"
5014 },
5015 "node_modules/serve-static/node_modules/send": {
5016 "version": "0.18.0",
5017 "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
5018 "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
5019 "license": "MIT",
5020 "dependencies": {
5021 "debug": "2.6.9",
5022 "depd": "2.0.0",
5023 "destroy": "1.2.0",
5024 "encodeurl": "~1.0.2",
5025 "escape-html": "~1.0.3",
5026 "etag": "~1.8.1",
5027 "fresh": "0.5.2",
5028 "http-errors": "2.0.0",
5029 "mime": "1.6.0",
5030 "ms": "2.1.3",
5031 "on-finished": "2.4.1",
5032 "range-parser": "~1.2.1",
5033 "statuses": "2.0.1"
5034 },
5035 "engines": {
5036 "node": ">= 0.8.0"
5037 }
5038 },
5039 "node_modules/set-function-length": {5397 "node_modules/set-function-length": {
5040 "version": "1.2.2",5398 "version": "1.2.2",
5041 "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",5399 "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -5165,6 +5523,83 @@
5165 "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==",5523 "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==",
5166 "license": "MIT"5524 "license": "MIT"
5167 },5525 },
5526 "node_modules/smart-buffer": {
5527 "version": "4.2.0",
5528 "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
5529 "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
5530 "license": "MIT",
5531 "engines": {
5532 "node": ">= 6.0.0",
5533 "npm": ">= 3.0.0"
5534 }
5535 },
5536 "node_modules/socks": {
5537 "version": "2.8.3",
5538 "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
5539 "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
5540 "license": "MIT",
5541 "dependencies": {
5542 "ip-address": "^9.0.5",
5543 "smart-buffer": "^4.2.0"
5544 },
5545 "engines": {
5546 "node": ">= 10.0.0",
5547 "npm": ">= 3.0.0"
5548 }
5549 },
5550 "node_modules/socks-proxy-agent": {
5551 "version": "8.0.4",
5552 "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",
5553 "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",
5554 "license": "MIT",
5555 "dependencies": {
5556 "agent-base": "^7.1.1",
5557 "debug": "^4.3.4",
5558 "socks": "^2.8.3"
5559 },
5560 "engines": {
5561 "node": ">= 14"
5562 }
5563 },
5564 "node_modules/socks-proxy-agent/node_modules/debug": {
5565 "version": "4.3.7",
5566 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
5567 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
5568 "license": "MIT",
5569 "dependencies": {
5570 "ms": "^2.1.3"
5571 },
5572 "engines": {
5573 "node": ">=6.0"
5574 },
5575 "peerDependenciesMeta": {
5576 "supports-color": {
5577 "optional": true
5578 }
5579 }
5580 },
5581 "node_modules/socks-proxy-agent/node_modules/ms": {
5582 "version": "2.1.3",
5583 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
5584 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
5585 "license": "MIT"
5586 },
5587 "node_modules/source-map": {
5588 "version": "0.6.1",
5589 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
5590 "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
5591 "license": "BSD-3-Clause",
5592 "optional": true,
5593 "engines": {
5594 "node": ">=0.10.0"
5595 }
5596 },
5597 "node_modules/sprintf-js": {
5598 "version": "1.1.3",
5599 "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
5600 "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
5601 "license": "BSD-3-Clause"
5602 },
5168 "node_modules/statuses": {5603 "node_modules/statuses": {
5169 "version": "2.0.1",5604 "version": "2.0.1",
5170 "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",5605 "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -5378,6 +5813,12 @@
5378 "utf8-byte-length": "^1.0.1"5813 "utf8-byte-length": "^1.0.1"
5379 }5814 }
5380 },5815 },
5816 "node_modules/tslib": {
5817 "version": "2.7.0",
5818 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
5819 "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
5820 "license": "0BSD"
5821 },
5381 "node_modules/tsscmp": {5822 "node_modules/tsscmp": {
5382 "version": "1.0.6",5823 "version": "1.0.6",
5383 "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",5824 "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
@@ -5437,6 +5878,15 @@
5437 "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",5878 "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
5438 "license": "MIT"5879 "license": "MIT"
5439 },5880 },
5881 "node_modules/universalify": {
5882 "version": "2.0.1",
5883 "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
5884 "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
5885 "license": "MIT",
5886 "engines": {
5887 "node": ">= 10.0.0"
5888 }
5889 },
5440 "node_modules/unpipe": {5890 "node_modules/unpipe": {
5441 "version": "1.0.0",5891 "version": "1.0.0",
5442 "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",5892 "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
package.json+5 -1
@@ -12,7 +12,7 @@
12 "cookie-session": "^2.1.0",12 "cookie-session": "^2.1.0",
13 "cors": "^2.8.5",13 "cors": "^2.8.5",
14 "csrf-csrf": "^2.2.3",14 "csrf-csrf": "^2.2.3",
15 "express": "^4.19.2",15 "express": "^4.20.0",
16 "form-data": "^4.0.0",16 "form-data": "^4.0.0",
17 "google-translate-api-browser": "^3.0.1",17 "google-translate-api-browser": "^3.0.1",
18 "he": "^1.2.0",18 "he": "^1.2.0",
@@ -30,6 +30,7 @@
30 "png-chunk-text": "^1.0.0",30 "png-chunk-text": "^1.0.0",
31 "png-chunks-encode": "^1.0.0",31 "png-chunks-encode": "^1.0.0",
32 "png-chunks-extract": "^1.0.0",32 "png-chunks-extract": "^1.0.0",
33 "proxy-agent": "^6.4.0",
33 "rate-limiter-flexible": "^5.0.0",34 "rate-limiter-flexible": "^5.0.0",
34 "response-time": "^2.3.2",35 "response-time": "^2.3.2",
35 "sanitize-filename": "^1.6.3",36 "sanitize-filename": "^1.6.3",
@@ -62,6 +63,9 @@
62 },63 },
63 "node-fetch": {64 "node-fetch": {
64 "whatwg-url": "^14.0.0"65 "whatwg-url": "^14.0.0"
66 },
67 "express": {
68 "send": "^0.19.0"
65 }69 }
66 },70 },
67 "name": "sillytavern",71 "name": "sillytavern",
public/index.html+1 -1
@@ -6479,8 +6479,8 @@
6479 </div>6479 </div>
64806480
6481 <!-- Script includes -->6481 <!-- Script includes -->
6482 <script src="lib/polyfill.js"></script>
6482 <script src="lib/diff_match_patch.js"></script>6483 <script src="lib/diff_match_patch.js"></script>
6483 <script src="lib/object-hasown.js"></script>
6484 <script src="lib/jquery-3.5.1.min.js"></script>6484 <script src="lib/jquery-3.5.1.min.js"></script>
6485 <script src="lib/jquery-ui.min.js"></script>6485 <script src="lib/jquery-ui.min.js"></script>
6486 <script src="lib/jquery.transit.min.js"></script>6486 <script src="lib/jquery.transit.min.js"></script>
public/lib/object-hasown.js+0 -4
@@ -1,4 +0,0 @@
1// Polyfill for old Safari versions
2if (!Object.hasOwn) {
3 Object.hasOwn = function (obj, prop) { return obj.hasOwnProperty(prop); }
4}
public/lib/polyfill.js+19 -0
@@ -0,0 +1,19 @@
1// Polyfills for old Safari versions
2if (!Object.hasOwn) {
3 Object.hasOwn = function (obj, prop) { return obj.hasOwnProperty(prop); }
4}
5
6if (!Array.prototype.findLastIndex) {
7 Array.prototype.findLastIndex = function (callback, thisArg) {
8 for (let i = this.length - 1; i >= 0; i--) {
9 if (callback.call(thisArg, this[i], i, this)) return i;
10 }
11 return -1;
12 };
13}
14
15if (!Array.prototype.toSorted) {
16 Array.prototype.toSorted = function (compareFunction) {
17 return this.slice().sort(compareFunction);
18 };
19}
public/script.js+56 -51
@@ -7472,7 +7472,7 @@ export function showSwipeButtons() {
74727472
7473 const currentMessage = $('#chat').children().filter(`[mesid="${chat.length - 1}"]`);7473 const currentMessage = $('#chat').children().filter(`[mesid="${chat.length - 1}"]`);
7474 const swipeId = chat[chat.length - 1].swipe_id;7474 const swipeId = chat[chat.length - 1].swipe_id;
7475 var swipesCounterHTML = (`${(swipeId + 1)}/${(chat[chat.length - 1].swipes.length)}`);7475 const swipeCounterText = (`${(swipeId + 1)}\u200B/\u200b${(chat[chat.length - 1].swipes.length)}`);
74767476
7477 if (swipeId !== undefined && (chat[chat.length - 1].swipes.length > 1 || swipeId > 0)) {7477 if (swipeId !== undefined && (chat[chat.length - 1].swipes.length > 1 || swipeId > 0)) {
7478 currentMessage.children('.swipe_left').css('display', 'flex');7478 currentMessage.children('.swipe_left').css('display', 'flex');
@@ -7489,7 +7489,7 @@ export function showSwipeButtons() {
7489 }7489 }
7490 //console.log(swipesCounterHTML);7490 //console.log(swipesCounterHTML);
74917491
7492 $('.swipes-counter').html(swipesCounterHTML);7492 $('.swipes-counter').text(swipeCounterText);
74937493
7494 //console.log(swipeId);7494 //console.log(swipeId);
7495 //console.log(chat[chat.length - 1].swipes.length);7495 //console.log(chat[chat.length - 1].swipes.length);
@@ -7878,13 +7878,19 @@ async function createOrEditCharacter(e) {
7878 formData.set('avatar', convertedFile);7878 formData.set('avatar', convertedFile);
7879 }7879 }
78807880
7881 const headers = getRequestHeaders();
7882 delete headers['Content-Type'];
7883
7881 if ($('#form_create').attr('actiontype') == 'createcharacter') {7884 if ($('#form_create').attr('actiontype') == 'createcharacter') {
7882 if (String($('#character_name_pole').val()).length > 0) {7885 if (String($('#character_name_pole').val()).length === 0) {
7886 toastr.error('Name is required');
7887 return;
7888 }
7883 if (is_group_generating || is_send_press) {7889 if (is_group_generating || is_send_press) {
7884 toastr.error('Cannot create characters while generating. Stop the request and try again.', 'Creation aborted');7890 toastr.error('Cannot create characters while generating. Stop the request and try again.', 'Creation aborted');
7885 throw new Error('Cannot import character while generating');7891 return;
7886 }7892 }
78877893 try {
7888 //if the character name text area isn't empty (only posible when creating a new character)7894 //if the character name text area isn't empty (only posible when creating a new character)
7889 let url = '/api/characters/create';7895 let url = '/api/characters/create';
78907896
@@ -7899,18 +7905,19 @@ async function createOrEditCharacter(e) {
78997905
7900 formData.append('extensions', JSON.stringify(create_save.extensions));7906 formData.append('extensions', JSON.stringify(create_save.extensions));
79017907
7902 await jQuery.ajax({7908 const fetchResult = await fetch(url, {
7903 type: 'POST',7909 method: 'POST',
7904 url: url,7910 headers: headers,
7905 data: formData,7911 body: formData,
7906 beforeSend: function () {7912 cache: 'no-cache',
7907 $('#create_button').attr('disabled', String(true));7913 });
7908 $('#create_button').attr('value', '⏳');7914
7909 },7915 if (!fetchResult.ok) {
7910 cache: false,7916 throw new Error('Fetch result is not ok');
7911 contentType: false,7917 }
7912 processData: false,7918
7913 success: async function (html) {7919 const avatarId = await fetchResult.text();
7920
7914 $('#character_cross').trigger('click'); //closes the advanced character editing popup7921 $('#character_cross').trigger('click'); //closes the advanced character editing popup
7915 const fields = [7922 const fields = [
7916 { id: '#character_name_pole', callback: value => create_save.name = value },7923 { id: '#character_name_pole', callback: value => create_save.name = value },
@@ -7945,33 +7952,29 @@ async function createOrEditCharacter(e) {
79457952
7946 create_save.avatar = '';7953 create_save.avatar = '';
79477954
7948 $('#create_button').removeAttr('disabled');
7949 $('#add_avatar_button').replaceWith(7955 $('#add_avatar_button').replaceWith(
7950 $('#add_avatar_button').val('').clone(true),7956 $('#add_avatar_button').val('').clone(true),
7951 );7957 );
79527958
7953 $('#create_button').attr('value', '✅');
7954 let oldSelectedChar = null;7959 let oldSelectedChar = null;
7955 if (this_chid !== undefined) {7960 if (this_chid !== undefined) {
7956 oldSelectedChar = characters[this_chid].avatar;7961 oldSelectedChar = characters[this_chid].avatar;
7957 }7962 }
79587963
7959 console.log(`new avatar id: ${html}`);7964 console.log(`new avatar id: ${avatarId}`);
7960 createTagMapFromList('#tagList', html);7965 createTagMapFromList('#tagList', avatarId);
7961 await getCharacters();7966 await getCharacters();
79627967
7963 select_rm_info('char_create', html, oldSelectedChar);7968 select_rm_info('char_create', avatarId, oldSelectedChar);
79647969
7965 crop_data = undefined;7970 crop_data = undefined;
7966 },7971
7967 error: function (jqXHR, exception) {7972 } catch (error) {
7968 $('#create_button').removeAttr('disabled');7973 console.error('Error creating character', error);
7969 },7974 toastr.error('Failed to create character');
7970 });
7971 } else {
7972 toastr.error('Name is required');
7973 }7975 }
7974 } else {7976 } else {
7977 try {
7975 let url = '/api/characters/edit';7978 let url = '/api/characters/edit';
79767979
7977 if (crop_data != undefined) {7980 if (crop_data != undefined) {
@@ -7986,19 +7989,16 @@ async function createOrEditCharacter(e) {
7986 }7989 }
7987 }7990 }
79887991
7989 await jQuery.ajax({7992 const fetchResult = await fetch(url, {
7990 type: 'POST',7993 method: 'POST',
7991 url: url,7994 headers: headers,
7992 data: formData,7995 body: formData,
7993 beforeSend: function () {7996 cache: 'no-cache',
7994 $('#create_button').attr('disabled', String(true));7997 });
7995 $('#create_button').attr('value', 'Save');7998
7996 },7999 if (!fetchResult.ok) {
7997 cache: false,8000 throw new Error('Fetch result is not ok');
7998 contentType: false,8001 }
7999 processData: false,
8000 success: async function (html) {
8001 $('#create_button').removeAttr('disabled');
80028002
8003 await getOneCharacter(formData.get('avatar_url'));8003 await getOneCharacter(formData.get('avatar_url'));
8004 favsToHotswap(); // Update fav state8004 favsToHotswap(); // Update fav state
@@ -8008,7 +8008,7 @@ async function createOrEditCharacter(e) {
8008 );8008 );
8009 $('#create_button').attr('value', 'Save');8009 $('#create_button').attr('value', 'Save');
8010 crop_data = undefined;8010 crop_data = undefined;
8011 eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } });8011 await eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } });
80128012
8013 // Recreate the chat if it hasn't been used at least once (i.e. with continue).8013 // Recreate the chat if it hasn't been used at least once (i.e. with continue).
8014 const message = getFirstMessage();8014 const message = getFirstMessage();
@@ -8028,13 +8028,10 @@ async function createOrEditCharacter(e) {
8028 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, messageId);8028 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, messageId);
8029 await saveChatConditional();8029 await saveChatConditional();
8030 }8030 }
8031 },8031 } catch (error) {
8032 error: function (jqXHR, exception) {8032 console.log(error);
8033 $('#create_button').removeAttr('disabled');
8034 console.log('Error! Either a file with the same name already existed, or the image file provided was in an invalid format. Double check that the image is not a webp.');
8035 toastr.error('Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.');8033 toastr.error('Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.');
8036 },8034 }
8037 });
8038 }8035 }
8039}8036}
80408037
@@ -8526,7 +8523,7 @@ async function selectContextCallback(args, name) {
85268523
8527async function selectInstructCallback(args, name) {8524async function selectInstructCallback(args, name) {
8528 if (!name) {8525 if (!name) {
8529 return power_user.instruct.preset;8526 return power_user.instruct.enabled || isTrueBoolean(args?.forceGet) ? power_user.instruct.preset : '';
8530 }8527 }
85318528
8532 const quiet = isTrueBoolean(args?.quiet);8529 const quiet = isTrueBoolean(args?.quiet);
@@ -9227,6 +9224,13 @@ jQuery(async function () {
9227 defaultValue: 'false',9224 defaultValue: 'false',
9228 enumList: commonEnumProviders.boolean('trueFalse')(),9225 enumList: commonEnumProviders.boolean('trueFalse')(),
9229 }),9226 }),
9227 SlashCommandNamedArgument.fromProps({
9228 name: 'forceGet',
9229 description: 'Force getting a name even if instruct mode is disabled',
9230 typeList: [ARGUMENT_TYPE.BOOLEAN],
9231 defaultValue: 'false',
9232 enumList: commonEnumProviders.boolean('trueFalse')(),
9233 }),
9230 ],9234 ],
9231 unnamedArgumentList: [9235 unnamedArgumentList: [
9232 SlashCommandArgument.fromProps({9236 SlashCommandArgument.fromProps({
@@ -9237,7 +9241,8 @@ jQuery(async function () {
9237 ],9241 ],
9238 helpString: `9242 helpString: `
9239 <div>9243 <div>
9240 Selects instruct mode template by name. Gets the current instruct template if no name is provided.9244 Selects instruct mode template by name. Enables instruct mode if not already enabled.
9245 Gets the current instruct template if no name is provided and instruct mode is enabled or <code>forceGet=true</code> is passed.
9241 </div>9246 </div>
9242 <div>9247 <div>
9243 <strong>Example:</strong>9248 <strong>Example:</strong>
public/scripts/slash-commands.js+39 -29
@@ -24,6 +24,7 @@ import {
24 main_api,24 main_api,
25 name1,25 name1,
26 name2,26 name2,
27 neutralCharacterName,
27 reloadCurrentChat,28 reloadCurrentChat,
28 removeMacros,29 removeMacros,
29 renameCharacter,30 renameCharacter,
@@ -427,6 +428,7 @@ export function initDefaultSlashCommands() {
427 SlashCommandParser.addCommandObject(SlashCommand.fromProps({428 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
428 name: 'ask',429 name: 'ask',
429 callback: askCharacter,430 callback: askCharacter,
431 returns: 'the generated text',
430 namedArgumentList: [432 namedArgumentList: [
431 SlashCommandNamedArgument.fromProps({433 SlashCommandNamedArgument.fromProps({
432 name: 'name',434 name: 'name',
@@ -438,7 +440,7 @@ export function initDefaultSlashCommands() {
438 ],440 ],
439 unnamedArgumentList: [441 unnamedArgumentList: [
440 new SlashCommandArgument(442 new SlashCommandArgument(
441 'prompt', [ARGUMENT_TYPE.STRING], true, false,443 'prompt', [ARGUMENT_TYPE.STRING], false, false,
442 ),444 ),
443 ],445 ],
444 helpString: 'Asks a specified character card a prompt. Character name must be provided in a named argument.',446 helpString: 'Asks a specified character card a prompt. Character name must be provided in a named argument.',
@@ -2467,44 +2469,40 @@ async function askCharacter(args, text) {
2467 // Not supported in group chats2469 // Not supported in group chats
2468 // TODO: Maybe support group chats?2470 // TODO: Maybe support group chats?
2469 if (selected_group) {2471 if (selected_group) {
2470 toastr.error('Cannot run this command in a group chat!');2472 toastr.error('Cannot run /ask command in a group chat!');
2471 return '';
2472 }
2473
2474 if (!text) {
2475 console.warn('WARN: No text provided for /ask command');
2476 toastr.warning('No text provided for /ask command');
2477 return '';2473 return '';
2478 }2474 }
24792475
2480 let name = '';2476 let name = '';
2481 let mesText = '';
24822477
2483 if (args?.name) {2478 if (args?.name) {
2484 name = args.name.trim();2479 name = args.name.trim();
2485 mesText = text.trim();
24862480
2487 if (!name && !mesText) {2481 if (!name) {
2488 toastr.warning('You must specify a name and text to ask.');2482 toastr.warning('You must specify a name of the character to ask.');
2489 return '';2483 return '';
2490 }2484 }
2491 }2485 }
24922486
2493 mesText = getRegexedString(mesText, regex_placement.SLASH_COMMAND);
2494
2495 const prevChId = this_chid;2487 const prevChId = this_chid;
24962488
2497 // Find the character2489 // Find the character
2498 const chId = characters.findIndex((e) => e.name === name);2490 const chId = characters.findIndex((e) => e.name === name || e.avatar === name);
2499 if (!characters[chId] || chId === -1) {2491 if (!characters[chId] || chId === -1) {
2500 toastr.error('Character not found.');2492 toastr.error('Character not found.');
2501 return '';2493 return '';
2502 }2494 }
25032495
2496 if (text) {
2497 const mesText = getRegexedString(text.trim(), regex_placement.SLASH_COMMAND);
2498 // Sending a message implicitly saves the chat, so this needs to be done before changing the character
2499 // Otherwise, a corruption will occur
2500 await sendMessageAsUser(mesText, '');
2501 }
2502
2504 // Override character and send a user message2503 // Override character and send a user message
2505 setCharacterId(String(chId));2504 setCharacterId(String(chId));
25062505
2507 // TODO: Maybe look up by filename instead of name
2508 const character = characters[chId];2506 const character = characters[chId];
2509 let force_avatar, original_avatar;2507 let force_avatar, original_avatar;
25102508
@@ -2519,9 +2517,11 @@ async function askCharacter(args, text) {
25192517
2520 setCharacterName(character.name);2518 setCharacterName(character.name);
25212519
2522 await sendMessageAsUser(mesText, '');
2523
2524 const restoreCharacter = () => {2520 const restoreCharacter = () => {
2521 if (String(this_chid) !== String(chId)) {
2522 return;
2523 }
2524
2525 setCharacterId(prevChId);2525 setCharacterId(prevChId);
2526 setCharacterName(characters[prevChId].name);2526 setCharacterName(characters[prevChId].name);
25272527
@@ -2532,23 +2532,27 @@ async function askCharacter(args, text) {
2532 lastMessage.force_avatar = force_avatar;2532 lastMessage.force_avatar = force_avatar;
2533 lastMessage.original_avatar = original_avatar;2533 lastMessage.original_avatar = original_avatar;
2534 }2534 }
2535
2536 // Kill this callback once the event fires
2537 eventSource.removeListener(event_types.CHARACTER_MESSAGE_RENDERED, restoreCharacter);
2538 };2535 };
25392536
2540 // Run generate and restore previous character on error2537 let askResult = '';
2538
2539 // Run generate and restore previous character
2541 try {2540 try {
2541 eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter);
2542 toastr.info(`Asking ${character.name} something...`);2542 toastr.info(`Asking ${character.name} something...`);
2543 await Generate('ask_command');2543 askResult = await Generate('ask_command');
2544 } catch {2544 } catch (error) {
2545 restoreCharacter();2545 restoreCharacter();
2546 console.error('Error running /ask command', error);
2547 } finally {
2548 if (String(this_chid) === String(prevChId)) {
2549 await saveChatConditional();
2550 } else {
2551 toastr.error('It is strongly recommended to reload the page.', 'Something went wrong');
2552 }
2546 }2553 }
25472554
2548 // Restore previous character once message renders2555 return askResult;
2549 // Hack for generate
2550 eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, restoreCharacter);
2551 return '';
2552}2556}
25532557
2554async function hideMessageCallback(_, arg) {2558async function hideMessageCallback(_, arg) {
@@ -3129,7 +3133,13 @@ export async function sendMessageAs(args, text) {
3129 const character = characters.find(x => x.avatar === name) ?? characters.find(x => x.name === name);3133 const character = characters.find(x => x.avatar === name) ?? characters.find(x => x.name === name);
3130 let force_avatar, original_avatar;3134 let force_avatar, original_avatar;
31313135
3132 if (character && character.avatar !== 'none') {3136 const chatCharacter = this_chid !== undefined ? characters[this_chid] : null;
3137 const isNeutralCharacter = !chatCharacter && name2 === neutralCharacterName && name === neutralCharacterName;
3138
3139 if (chatCharacter === character || isNeutralCharacter) {
3140 // If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars
3141 }
3142 else if (character && character.avatar !== 'none') {
3133 force_avatar = getThumbnailUrl('avatar', character.avatar);3143 force_avatar = getThumbnailUrl('avatar', character.avatar);
3134 original_avatar = character.avatar;3144 original_avatar = character.avatar;
3135 }3145 }
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js+10 -7
@@ -1,4 +1,4 @@
1import { chat_metadata, characters, substituteParams, chat, extension_prompt_roles, extension_prompt_types } from '../../script.js';1import { chat_metadata, characters, substituteParams, chat, extension_prompt_roles, extension_prompt_types, name2, neutralCharacterName } from '../../script.js';
2import { extension_settings } from '../extensions.js';2import { extension_settings } from '../extensions.js';
3import { getGroupMembers, groups } from '../group-chats.js';3import { getGroupMembers, groups } from '../group-chats.js';
4import { power_user } from '../power-user.js';4import { power_user } from '../power-user.js';
@@ -6,7 +6,9 @@ import { searchCharByName, getTagsList, tags } from '../tags.js';
6import { world_names } from '../world-info.js';6import { world_names } from '../world-info.js';
7import { SlashCommandClosure } from './SlashCommandClosure.js';7import { SlashCommandClosure } from './SlashCommandClosure.js';
8import { SlashCommandEnumValue, enumTypes } from './SlashCommandEnumValue.js';8import { SlashCommandEnumValue, enumTypes } from './SlashCommandEnumValue.js';
9import { SlashCommandScope } from "./SlashCommandScope.js";9
10/** @typedef {import('./SlashCommandExecutor.js').SlashCommandExecutor} SlashCommandExecutor */
11/** @typedef {import('./SlashCommandScope.js').SlashCommandScope} SlashCommandScope */
1012
11/**13/**
12 * A collection of regularly used enum icons14 * A collection of regularly used enum icons
@@ -140,7 +142,7 @@ export const commonEnumProviders = {
140 * @param {...('global'|'local'|'scope'|'all')} type - The type of variables to include in the array. Can be 'all', 'global', or 'local'.142 * @param {...('global'|'local'|'scope'|'all')} type - The type of variables to include in the array. Can be 'all', 'global', or 'local'.
141 * @returns {(executor:SlashCommandExecutor, scope:SlashCommandScope) => SlashCommandEnumValue[]}143 * @returns {(executor:SlashCommandExecutor, scope:SlashCommandScope) => SlashCommandEnumValue[]}
142 */144 */
143 variables: (...type) => (executor, scope) => {145 variables: (...type) => (_, scope) => {
144 const types = type.flat();146 const types = type.flat();
145 const isAll = types.includes('all');147 const isAll = types.includes('all');
146 return [148 return [
@@ -160,6 +162,7 @@ export const commonEnumProviders = {
160 return [162 return [
161 ...['all', 'character'].includes(mode) ? characters.map(char => new SlashCommandEnumValue(char.name, null, enumTypes.name, enumIcons.character)) : [],163 ...['all', 'character'].includes(mode) ? characters.map(char => new SlashCommandEnumValue(char.name, null, enumTypes.name, enumIcons.character)) : [],
162 ...['all', 'group'].includes(mode) ? groups.map(group => new SlashCommandEnumValue(group.name, null, enumTypes.qr, enumIcons.group)) : [],164 ...['all', 'group'].includes(mode) ? groups.map(group => new SlashCommandEnumValue(group.name, null, enumTypes.qr, enumIcons.group)) : [],
165 ...(name2 === neutralCharacterName) ? [new SlashCommandEnumValue(neutralCharacterName, null, enumTypes.name, '🥸')] : [],
163 ];166 ];
164 },167 },
165168
@@ -184,7 +187,7 @@ export const commonEnumProviders = {
184 * @param {('all' | 'existing' | 'not-existing')?} [mode='all'] - Which types of tags to show187 * @param {('all' | 'existing' | 'not-existing')?} [mode='all'] - Which types of tags to show
185 * @returns {() => SlashCommandEnumValue[]}188 * @returns {() => SlashCommandEnumValue[]}
186 */189 */
187 tagsForChar: (mode = 'all') => (/** @type {import('./SlashCommandExecutor.js').SlashCommandExecutor} */ executor) => {190 tagsForChar: (mode = 'all') => (/** @type {SlashCommandExecutor} */ executor) => {
188 // Try to see if we can find the char during execution to filter down the tags list some more. Otherwise take all tags.191 // Try to see if we can find the char during execution to filter down the tags list some more. Otherwise take all tags.
189 const charName = executor.namedArgumentList.find(it => it.name == 'name')?.value;192 const charName = executor.namedArgumentList.find(it => it.name == 'name')?.value;
190 if (charName instanceof SlashCommandClosure) throw new Error('Argument \'name\' does not support closures');193 if (charName instanceof SlashCommandClosure) throw new Error('Argument \'name\' does not support closures');
@@ -202,13 +205,13 @@ export const commonEnumProviders = {
202 * @param {object} [options={}] - Optional arguments205 * @param {object} [options={}] - Optional arguments
203 * @param {boolean} [options.allowIdAfter=false] - Whether to add an enum option for the new message id after the last message206 * @param {boolean} [options.allowIdAfter=false] - Whether to add an enum option for the new message id after the last message
204 * @param {boolean} [options.allowVars=false] - Whether to add enum option for variable names207 * @param {boolean} [options.allowVars=false] - Whether to add enum option for variable names
205 * @returns {() => SlashCommandEnumValue[]}208 * @returns {(executor:SlashCommandExecutor, scope:SlashCommandScope) => SlashCommandEnumValue[]}
206 */209 */
207 messages: ({ allowIdAfter = false, allowVars = false } = {}) => () => {210 messages: ({ allowIdAfter = false, allowVars = false } = {}) => (_, scope) => {
208 return [211 return [
209 ...chat.map((message, index) => new SlashCommandEnumValue(String(index), `${message.name}: ${message.mes}`, enumTypes.number, message.is_user ? enumIcons.user : message.is_system ? enumIcons.system : enumIcons.assistant)),212 ...chat.map((message, index) => new SlashCommandEnumValue(String(index), `${message.name}: ${message.mes}`, enumTypes.number, message.is_user ? enumIcons.user : message.is_system ? enumIcons.system : enumIcons.assistant)),
210 ...allowIdAfter ? [new SlashCommandEnumValue(String(chat.length), '>> After Last Message >>', enumTypes.enum, '➕')] : [],213 ...allowIdAfter ? [new SlashCommandEnumValue(String(chat.length), '>> After Last Message >>', enumTypes.enum, '➕')] : [],
211 ...allowVars ? commonEnumProviders.variables('all')() : [],214 ...allowVars ? commonEnumProviders.variables('all')(_, scope) : [],
212 ];215 ];
213 },216 },
214217
public/style.css+1 -1
@@ -993,7 +993,7 @@ body .panelControlBar {
993 padding: 0;993 padding: 0;
994 font-family: var(--mainFontFamily);994 font-family: var(--mainFontFamily);
995 font-weight: 400;995 font-weight: 400;
996 align-self: self-end;996 align-self: center;
997}997}
998998
999.swipe_left {999.swipe_left {
server.js+24 -0
@@ -37,6 +37,7 @@ util.inspect.defaultOptions.depth = 4;
37const userModule = require('./src/users');37const userModule = require('./src/users');
38const basicAuthMiddleware = require('./src/middleware/basicAuth');38const basicAuthMiddleware = require('./src/middleware/basicAuth');
39const whitelistMiddleware = require('./src/middleware/whitelist');39const whitelistMiddleware = require('./src/middleware/whitelist');
40const initRequestProxy = require('./src/request-proxy');
40const contentManager = require('./src/endpoints/content-manager');41const contentManager = require('./src/endpoints/content-manager');
41const {42const {
42 getVersion,43 getVersion,
@@ -75,6 +76,10 @@ const DEFAULT_AVOID_LOCALHOST = false;
75const DEFAULT_AUTORUN_HOSTNAME = 'auto';76const DEFAULT_AUTORUN_HOSTNAME = 'auto';
76const DEFAULT_AUTORUN_PORT = -1;77const DEFAULT_AUTORUN_PORT = -1;
7778
79const DEFAULT_PROXY_ENABLED = false;
80const DEFAULT_PROXY_URL = '';
81const DEFAULT_PROXY_BYPASS = [];
82
78const cliArguments = yargs(hideBin(process.argv))83const cliArguments = yargs(hideBin(process.argv))
79 .usage('Usage: <your-start-script> <command> [options]')84 .usage('Usage: <your-start-script> <command> [options]')
80 .option('enableIPv6', {85 .option('enableIPv6', {
@@ -145,6 +150,18 @@ const cliArguments = yargs(hideBin(process.argv))
145 type: 'boolean',150 type: 'boolean',
146 default: null,151 default: null,
147 describe: 'Enables basic authentication',152 describe: 'Enables basic authentication',
153 }).option('requestProxyEnabled', {
154 type: 'boolean',
155 default: null,
156 describe: 'Enables a use of proxy for outgoing requests',
157 }).option('requestProxyUrl', {
158 type: 'string',
159 default: null,
160 describe: 'Request proxy URL (HTTP or SOCKS protocols)',
161 }).option('requestProxyBypass', {
162 type: 'array',
163 default: null,
164 describe: 'Request proxy bypass list (space separated list of hosts)',
148 }).parseSync();165 }).parseSync();
149166
150// change all relative paths167// change all relative paths
@@ -181,6 +198,10 @@ const dnsPreferIPv6 = cliArguments.dnsPreferIPv6 ?? getConfigValue('dnsPreferIPv
181198
182const avoidLocalhost = cliArguments.avoidLocalhost ?? getConfigValue('avoidLocalhost', DEFAULT_AVOID_LOCALHOST);199const avoidLocalhost = cliArguments.avoidLocalhost ?? getConfigValue('avoidLocalhost', DEFAULT_AVOID_LOCALHOST);
183200
201const proxyEnabled = cliArguments.requestProxyEnabled ?? getConfigValue('requestProxy.enabled', DEFAULT_PROXY_ENABLED);
202const proxyUrl = cliArguments.requestProxyUrl ?? getConfigValue('requestProxy.url', DEFAULT_PROXY_URL);
203const proxyBypass = cliArguments.requestProxyBypass ?? getConfigValue('requestProxy.bypass', DEFAULT_PROXY_BYPASS);
204
184if (dnsPreferIPv6) {205if (dnsPreferIPv6) {
185 // Set default DNS resolution order to IPv6 first206 // Set default DNS resolution order to IPv6 first
186 dns.setDefaultResultOrder('ipv6first');207 dns.setDefaultResultOrder('ipv6first');
@@ -662,6 +683,9 @@ const preSetupTasks = async function () {
662 console.error('Uncaught exception:', err);683 console.error('Uncaught exception:', err);
663 exitProcess();684 exitProcess();
664 });685 });
686
687 // Add request proxy.
688 initRequestProxy({ enabled: proxyEnabled, url: proxyUrl, bypass: proxyBypass });
665};689};
666690
667/**691/**
src/request-proxy.js+56 -0
@@ -0,0 +1,56 @@
1const http = require('node:http');
2const https = require('node:https');
3
4const { isValidUrl, color } = require('./util.js');
5
6const LOG_HEADER = '[Request Proxy]';
7
8/**
9 * Initialize request proxy.
10 * @param {ProxySettings} settings Proxy settings.
11 * @typedef {object} ProxySettings
12 * @property {boolean} enabled Whether proxy is enabled.
13 * @property {string} url Proxy URL.
14 * @property {string[]} bypass List of URLs to bypass proxy.
15 */
16function initRequestProxy({ enabled, url, bypass }) {
17 try {
18 const { ProxyAgent } = require('proxy-agent');
19
20 // No proxy is enabled, so return
21 if (!enabled) {
22 return;
23 }
24
25 if (!url) {
26 console.error(color.red(LOG_HEADER), 'No proxy URL provided');
27 return;
28 }
29
30 if (!isValidUrl(url)) {
31 console.error(color.red(LOG_HEADER), 'Invalid proxy URL provided');
32 return;
33 }
34
35 // ProxyAgent uses proxy-from-env under the hood
36 // Reference: https://github.com/Rob--W/proxy-from-env
37 process.env.all_proxy = url;
38
39
40 if (Array.isArray(bypass) && bypass.length > 0) {
41 process.env.no_proxy = bypass.join(',');
42 }
43
44 const proxyAgent = new ProxyAgent();
45 http.globalAgent = proxyAgent;
46 https.globalAgent = proxyAgent;
47
48 console.log();
49 console.log(color.green(LOG_HEADER), 'Proxy URL is used:', color.blue(url));
50 console.log();
51 } catch (error) {
52 console.error(color.red(LOG_HEADER), 'Failed to initialize request proxy:', error);
53 }
54}
55
56module.exports = initRequestProxy;