Feat/global install (#4289) * Update npm dependencies * Add global paths mode Closes #4209 * Update src/command-line.js Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Async => Promise.resolve * Remove unnecessary Promise.resolve() --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed| @@ -330,12 +330,44 @@ chmod +x launcher.sh && ./launcher.sh | |||
| 330 | > \[!NOTE] | 330 | > \[!NOTE] |
| 331 | > **SillyTavern can be run natively on Android devices using Termux, but we do not provide official support for this use case.** | 331 | > **SillyTavern can be run natively on Android devices using Termux, but we do not provide official support for this use case.** |
| 332 | > | 332 | > |
| 333 | > **Please refer to this guide by ArroganceComplex#2659:** | 333 | > **Please refer to the documentation for more information:** |
| 334 | > | 334 | > |
| 335 | > * <https://rentry.org/STAI-Termux> | 335 | > * <https://docs.sillytavern.app/installation/android-(termux)/> |
| 336 | 336 | ||
| 337 | **Unsupported platform: android arm LEtime-web.** 32-bit Android requires an external dependency that can't be installed with npm. Use the following command to install it: `pkg install esbuild`. Then run the usual installation steps. | 337 | **Unsupported platform: android arm LEtime-web.** 32-bit Android requires an external dependency that can't be installed with npm. Use the following command to install it: `pkg install esbuild`. Then run the usual installation steps. |
| 338 | 338 | ||
| 339 | ## Global / Standalone mode | ||
| 340 | |||
| 341 | There are two modes of running SillyTavern that differ in how they handle the configuration and data paths. | ||
| 342 | |||
| 343 | * **Standalone mode** (default) - uses the `config.yaml` file and `data` directory in the server directory. All data will be constrained to the installation path. This is the recommended mode for most users. | ||
| 344 | * **Global mode** - uses the system-wide paths for configuration and data. This is useful for installing SillyTavern as a package or when you want to share the same configuration and data across multiple installations. | ||
| 345 | |||
| 346 | > [!NOTE] | ||
| 347 | > Installations made by using the [official npm package](https://www.npmjs.com/package/sillytavern) (e.g. `npx sillytavern@latest`) will run in global mode by default. | ||
| 348 | |||
| 349 | ### Data paths | ||
| 350 | |||
| 351 | **Standalone mode** paths are relative to the SillyTavern installation directory: | ||
| 352 | |||
| 353 | * **Config path**: `./config.yaml` | ||
| 354 | * **Data root**: `./data/` | ||
| 355 | |||
| 356 | **Global mode** paths are OS-dependent: | ||
| 357 | |||
| 358 | * **Linux**: `~/.local/share/SillyTavern/config.yaml` and `~/.local/share/SillyTavern/data/` | ||
| 359 | * **Windows**: `%APPDATA%\SillyTavern\config.yaml` and `%APPDATA%\SillyTavern\data\` | ||
| 360 | * **MacOS**: `~/Library/Application Support/SillyTavern/config.yaml` and `~/Library/Application Support/SillyTavern/data/` | ||
| 361 | |||
| 362 | ### How to run in global mode | ||
| 363 | |||
| 364 | > [!WARNING] | ||
| 365 | > `dataRoot` and `configPath` can't be overridden with CLI arguments or config.yaml when running in global mode. | ||
| 366 | |||
| 367 | 1. Pass the `--global` argument to the server startup command (e.g. `node server.js --global`). | ||
| 368 | 2. Pass the `--global` argument to the shell startup script (e.g. `Start.bat --global` or `./start.sh --global`). | ||
| 369 | 3. Use the `start:global` script in the `package.json` file (e.g. `npm run start:global`). | ||
| 370 | |||
| 339 | ## Command-line arguments | 371 | ## Command-line arguments |
| 340 | 372 | ||
| 341 | You can pass command-line arguments to SillyTavern server startup to override some settings in `config.yaml`. | 373 | You can pass command-line arguments to SillyTavern server startup to override some settings in `config.yaml`. |
| @@ -357,29 +389,30 @@ Start.bat --port 8000 --listen false | |||
| 357 | 389 | ||
| 358 | | Option | Description | Type | | 390 | | Option | Description | Type | |
| 359 | |---------------------------------|----------------------------------------------------------------------|----------| | 391 | |---------------------------------|----------------------------------------------------------------------|----------| |
| 360 | | `--version` | Show version number | boolean | | 392 | | `--version` | Shows the version number | boolean | |
| 361 | | `--configPath` | Override the path to the config.yaml file | string | | 393 | | `--global` | Forces the use of system-wide paths for application data (see above) | boolean | |
| 362 | | `--dataRoot` | Root directory for data storage | string | | 394 | | `--configPath` | Overrides the path to the config.yaml file (standalone mode only) | string | |
| 395 | | `--dataRoot` | Sets the root directory for data storage (standalone mode only) | string | | ||
| 363 | | `--port` | Sets the port under which SillyTavern will run | number | | 396 | | `--port` | Sets the port under which SillyTavern will run | number | |
| 364 | | `--listen` | SillyTavern will listen on all network interfaces | boolean | | 397 | | `--listen` | Makes SillyTavern listen on all network interfaces | boolean | |
| 365 | | `--whitelist` | Enables whitelist mode | boolean | | 398 | | `--whitelist` | Enables whitelist mode | boolean | |
| 366 | | `--basicAuthMode` | Enables basic authentication | boolean | | 399 | | `--basicAuthMode` | Enables basic authentication | boolean | |
| 367 | | `--enableIPv4` | Enables IPv4 protocol | boolean | | 400 | | `--enableIPv4` | Enables the IPv4 protocol | boolean | |
| 368 | | `--enableIPv6` | Enables IPv6 protocol | boolean | | 401 | | `--enableIPv6` | Enables the IPv6 protocol | boolean | |
| 369 | | `--listenAddressIPv4` | Specific IPv4 address to listen to | string | | 402 | | `--listenAddressIPv4` | Specifies the IPv4 address to listen on | string | |
| 370 | | `--listenAddressIPv6` | Specific IPv6 address to listen to | string | | 403 | | `--listenAddressIPv6` | Specifies the IPv6 address to listen on | string | |
| 371 | | `--dnsPreferIPv6` | Prefers IPv6 for DNS | boolean | | 404 | | `--dnsPreferIPv6` | Prefers IPv6 for DNS | boolean | |
| 372 | | `--ssl` | Enables SSL | boolean | | 405 | | `--ssl` | Enables SSL | boolean | |
| 373 | | `--certPath` | Path to your certificate file | string | | 406 | | `--certPath` | Sets the path to your certificate file | string | |
| 374 | | `--keyPath` | Path to your private key file | string | | 407 | | `--keyPath` | Sets the path to your private key file | string | |
| 375 | | `--browserLaunchEnabled` | Automatically launch SillyTavern in the browser | boolean | | 408 | | `--browserLaunchEnabled` | Automatically launches SillyTavern in the browser | boolean | |
| 376 | | `--browserLaunchHostname` | Browser launch hostname | string | | 409 | | `--browserLaunchHostname` | Sets the browser launch hostname | string | |
| 377 | | `--browserLaunchPort` | Overrides the port for browser launch | string | | 410 | | `--browserLaunchPort` | Overrides the port for browser launch | string | |
| 378 | | `--browserLaunchAvoidLocalhost` | Avoids using 'localhost' for browser launch in auto mode | boolean | | 411 | | `--browserLaunchAvoidLocalhost` | Avoids using 'localhost' for browser launch in auto mode | boolean | |
| 379 | | `--corsProxy` | Enables CORS proxy | boolean | | 412 | | `--corsProxy` | Enables the CORS proxy | boolean | |
| 380 | | `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean | | 413 | | `--requestProxyEnabled` | Enables the use of a proxy for outgoing requests | boolean | |
| 381 | | `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string | | 414 | | `--requestProxyUrl` | Sets the request proxy URL (HTTP or SOCKS protocols) | string | |
| 382 | | `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array | | 415 | | `--requestProxyBypass` | Sets the request proxy bypass list (space-separated list of hosts) | array | |
| 383 | | `--disableCsrf` | Disables CSRF protection (NOT RECOMMENDED) | boolean | | 416 | | `--disableCsrf` | Disables CSRF protection (NOT RECOMMENDED) | boolean | |
| 384 | 417 | ||
| 385 | ## Remote connections | 418 | ## Remote connections |
| @@ -66,4 +66,9 @@ declare global { | |||
| 66 | * Parsed command line arguments. | 66 | * Parsed command line arguments. |
| 67 | */ | 67 | */ |
| 68 | var COMMAND_LINE_ARGS: CommandLineArguments; | 68 | var COMMAND_LINE_ARGS: CommandLineArguments; |
| 69 | |||
| 70 | /** | ||
| 71 | * Forces a global mode if set to `true` before parsing the CLI arguments. | ||
| 72 | */ | ||
| 73 | var FORCE_GLOBAL_MODE: boolean; | ||
| 69 | } | 74 | } |
| @@ -40,7 +40,7 @@ | |||
| 40 | "@popperjs/core": "^2.11.8", | 40 | "@popperjs/core": "^2.11.8", |
| 41 | "@zeldafan0225/ai_horde": "^5.2.0", | 41 | "@zeldafan0225/ai_horde": "^5.2.0", |
| 42 | "archiver": "^7.0.1", | 42 | "archiver": "^7.0.1", |
| 43 | "bing-translate-api": "^4.0.2", | 43 | "bing-translate-api": "^4.1.0", |
| 44 | "body-parser": "^1.20.2", | 44 | "body-parser": "^1.20.2", |
| 45 | "bowser": "^2.11.0", | 45 | "bowser": "^2.11.0", |
| 46 | "bytes": "^3.1.2", | 46 | "bytes": "^3.1.2", |
| @@ -55,8 +55,9 @@ | |||
| 55 | "diff-match-patch": "^1.0.5", | 55 | "diff-match-patch": "^1.0.5", |
| 56 | "dompurify": "^3.2.6", | 56 | "dompurify": "^3.2.6", |
| 57 | "droll": "^0.2.1", | 57 | "droll": "^0.2.1", |
| 58 | "env-paths": "^3.0.0", | ||
| 58 | "express": "^4.21.0", | 59 | "express": "^4.21.0", |
| 59 | "form-data": "^4.0.3", | 60 | "form-data": "^4.0.4", |
| 60 | "fuse.js": "^7.1.0", | 61 | "fuse.js": "^7.1.0", |
| 61 | "google-translate-api-browser": "^3.0.1", | 62 | "google-translate-api-browser": "^3.0.1", |
| 62 | "google-translate-api-x": "^10.7.2", | 63 | "google-translate-api-x": "^10.7.2", |
| @@ -77,7 +78,7 @@ | |||
| 77 | "multer": "^2.0.2", | 78 | "multer": "^2.0.2", |
| 78 | "node-fetch": "^3.3.2", | 79 | "node-fetch": "^3.3.2", |
| 79 | "node-persist": "^4.0.4", | 80 | "node-persist": "^4.0.4", |
| 80 | "open": "^10.1.2", | 81 | "open": "^10.2.0", |
| 81 | "png-chunk-text": "^1.0.0", | 82 | "png-chunk-text": "^1.0.0", |
| 82 | "png-chunks-extract": "^1.0.0", | 83 | "png-chunks-extract": "^1.0.0", |
| 83 | "proxy-agent": "^6.5.0", | 84 | "proxy-agent": "^6.5.0", |
| @@ -95,13 +96,13 @@ | |||
| 95 | "wavefile": "^11.0.0", | 96 | "wavefile": "^11.0.0", |
| 96 | "webpack": "^5.98.0", | 97 | "webpack": "^5.98.0", |
| 97 | "write-file-atomic": "^5.0.1", | 98 | "write-file-atomic": "^5.0.1", |
| 98 | "ws": "^8.18.2", | 99 | "ws": "^8.18.3", |
| 99 | "yaml": "^2.8.0", | 100 | "yaml": "^2.8.0", |
| 100 | "yargs": "^17.7.1", | 101 | "yargs": "^17.7.1", |
| 101 | "yauzl": "^3.2.0" | 102 | "yauzl": "^3.2.0" |
| 102 | }, | 103 | }, |
| 103 | "bin": { | 104 | "bin": { |
| 104 | "sillytavern": "server.js" | 105 | "sillytavern": "src/server-global.js" |
| 105 | }, | 106 | }, |
| 106 | "devDependencies": { | 107 | "devDependencies": { |
| 107 | "@types/archiver": "^6.0.3", | 108 | "@types/archiver": "^6.0.3", |
| @@ -117,9 +118,9 @@ | |||
| 117 | "@types/jquery-cropper": "^1.0.4", | 118 | "@types/jquery-cropper": "^1.0.4", |
| 118 | "@types/jquery.transit": "^0.9.33", | 119 | "@types/jquery.transit": "^0.9.33", |
| 119 | "@types/jqueryui": "^1.12.24", | 120 | "@types/jqueryui": "^1.12.24", |
| 120 | "@types/lodash": "^4.17.17", | 121 | "@types/lodash": "^4.17.20", |
| 121 | "@types/mime-types": "^3.0.1", | 122 | "@types/mime-types": "^3.0.1", |
| 122 | "@types/multer": "^1.4.13", | 123 | "@types/multer": "^2.0.0", |
| 123 | "@types/node": "^18.19.84", | 124 | "@types/node": "^18.19.84", |
| 124 | "@types/node-persist": "^3.1.8", | 125 | "@types/node-persist": "^3.1.8", |
| 125 | "@types/png-chunk-text": "^1.0.3", | 126 | "@types/png-chunk-text": "^1.0.3", |
| @@ -1972,9 +1973,9 @@ | |||
| 1972 | } | 1973 | } |
| 1973 | }, | 1974 | }, |
| 1974 | "node_modules/@types/lodash": { | 1975 | "node_modules/@types/lodash": { |
| 1975 | "version": "4.17.17", | 1976 | "version": "4.17.20", |
| 1976 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", | 1977 | "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", |
| 1977 | "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", | 1978 | "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", |
| 1978 | "dev": true, | 1979 | "dev": true, |
| 1979 | "license": "MIT" | 1980 | "license": "MIT" |
| 1980 | }, | 1981 | }, |
| @@ -1999,9 +2000,9 @@ | |||
| 1999 | "license": "MIT" | 2000 | "license": "MIT" |
| 2000 | }, | 2001 | }, |
| 2001 | "node_modules/@types/multer": { | 2002 | "node_modules/@types/multer": { |
| 2002 | "version": "1.4.13", | 2003 | "version": "2.0.0", |
| 2003 | "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.13.tgz", | 2004 | "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz", |
| 2004 | "integrity": "sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw==", | 2005 | "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", |
| 2005 | "dev": true, | 2006 | "dev": true, |
| 2006 | "license": "MIT", | 2007 | "license": "MIT", |
| 2007 | "dependencies": { | 2008 | "dependencies": { |
| @@ -2832,9 +2833,9 @@ | |||
| 2832 | } | 2833 | } |
| 2833 | }, | 2834 | }, |
| 2834 | "node_modules/bing-translate-api": { | 2835 | "node_modules/bing-translate-api": { |
| 2835 | "version": "4.0.2", | 2836 | "version": "4.1.0", |
| 2836 | "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-4.0.2.tgz", | 2837 | "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-4.1.0.tgz", |
| 2837 | "integrity": "sha512-JJ8XUehnxzOhHU91oy86xEtp8OOMjVEjCZJX042fKxoO19NNvxJ5omeCcxQNFoPbDqVpBJwqiGVquL0oPdQm1Q==", | 2838 | "integrity": "sha512-oP2663Yd5MXX4kbB/3LdS9YgPiE+ls9+2iFZH2ZXigWhWyHT3R4m6aCup4TNJd3/U4gqHHnQoxTaIW7uOf4+vA==", |
| 2838 | "license": "MIT", | 2839 | "license": "MIT", |
| 2839 | "dependencies": { | 2840 | "dependencies": { |
| 2840 | "got": "^11.8.6" | 2841 | "got": "^11.8.6" |
| @@ -4087,6 +4088,18 @@ | |||
| 4087 | "url": "https://github.com/fb55/entities?sponsor=1" | 4088 | "url": "https://github.com/fb55/entities?sponsor=1" |
| 4088 | } | 4089 | } |
| 4089 | }, | 4090 | }, |
| 4091 | "node_modules/env-paths": { | ||
| 4092 | "version": "3.0.0", | ||
| 4093 | "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", | ||
| 4094 | "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", | ||
| 4095 | "license": "MIT", | ||
| 4096 | "engines": { | ||
| 4097 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" | ||
| 4098 | }, | ||
| 4099 | "funding": { | ||
| 4100 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 4101 | } | ||
| 4102 | }, | ||
| 4090 | "node_modules/es-define-property": { | 4103 | "node_modules/es-define-property": { |
| 4091 | "version": "1.0.1", | 4104 | "version": "1.0.1", |
| 4092 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", | 4105 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", |
| @@ -4786,9 +4799,9 @@ | |||
| 4786 | } | 4799 | } |
| 4787 | }, | 4800 | }, |
| 4788 | "node_modules/form-data": { | 4801 | "node_modules/form-data": { |
| 4789 | "version": "4.0.3", | 4802 | "version": "4.0.4", |
| 4790 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", | 4803 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", |
| 4791 | "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", | 4804 | "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", |
| 4792 | "license": "MIT", | 4805 | "license": "MIT", |
| 4793 | "dependencies": { | 4806 | "dependencies": { |
| 4794 | "asynckit": "^0.4.0", | 4807 | "asynckit": "^0.4.0", |
| @@ -6420,15 +6433,15 @@ | |||
| 6420 | } | 6433 | } |
| 6421 | }, | 6434 | }, |
| 6422 | "node_modules/open": { | 6435 | "node_modules/open": { |
| 6423 | "version": "10.1.2", | 6436 | "version": "10.2.0", |
| 6424 | "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz", | 6437 | "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", |
| 6425 | "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", | 6438 | "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", |
| 6426 | "license": "MIT", | 6439 | "license": "MIT", |
| 6427 | "dependencies": { | 6440 | "dependencies": { |
| 6428 | "default-browser": "^5.2.1", | 6441 | "default-browser": "^5.2.1", |
| 6429 | "define-lazy-prop": "^3.0.0", | 6442 | "define-lazy-prop": "^3.0.0", |
| 6430 | "is-inside-container": "^1.0.0", | 6443 | "is-inside-container": "^1.0.0", |
| 6431 | "is-wsl": "^3.1.0" | 6444 | "wsl-utils": "^0.1.0" |
| 6432 | }, | 6445 | }, |
| 6433 | "engines": { | 6446 | "engines": { |
| 6434 | "node": ">=18" | 6447 | "node": ">=18" |
| @@ -8503,9 +8516,9 @@ | |||
| 8503 | } | 8516 | } |
| 8504 | }, | 8517 | }, |
| 8505 | "node_modules/ws": { | 8518 | "node_modules/ws": { |
| 8506 | "version": "8.18.2", | 8519 | "version": "8.18.3", |
| 8507 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", | 8520 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", |
| 8508 | "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", | 8521 | "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", |
| 8509 | "license": "MIT", | 8522 | "license": "MIT", |
| 8510 | "engines": { | 8523 | "engines": { |
| 8511 | "node": ">=10.0.0" | 8524 | "node": ">=10.0.0" |
| @@ -8523,6 +8536,21 @@ | |||
| 8523 | } | 8536 | } |
| 8524 | } | 8537 | } |
| 8525 | }, | 8538 | }, |
| 8539 | "node_modules/wsl-utils": { | ||
| 8540 | "version": "0.1.0", | ||
| 8541 | "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", | ||
| 8542 | "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", | ||
| 8543 | "license": "MIT", | ||
| 8544 | "dependencies": { | ||
| 8545 | "is-wsl": "^3.1.0" | ||
| 8546 | }, | ||
| 8547 | "engines": { | ||
| 8548 | "node": ">=18" | ||
| 8549 | }, | ||
| 8550 | "funding": { | ||
| 8551 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 8552 | } | ||
| 8553 | }, | ||
| 8526 | "node_modules/xhr": { | 8554 | "node_modules/xhr": { |
| 8527 | "version": "2.6.0", | 8555 | "version": "2.6.0", |
| 8528 | "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", | 8556 | "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", |
| @@ -30,7 +30,7 @@ | |||
| 30 | "@popperjs/core": "^2.11.8", | 30 | "@popperjs/core": "^2.11.8", |
| 31 | "@zeldafan0225/ai_horde": "^5.2.0", | 31 | "@zeldafan0225/ai_horde": "^5.2.0", |
| 32 | "archiver": "^7.0.1", | 32 | "archiver": "^7.0.1", |
| 33 | "bing-translate-api": "^4.0.2", | 33 | "bing-translate-api": "^4.1.0", |
| 34 | "body-parser": "^1.20.2", | 34 | "body-parser": "^1.20.2", |
| 35 | "bowser": "^2.11.0", | 35 | "bowser": "^2.11.0", |
| 36 | "bytes": "^3.1.2", | 36 | "bytes": "^3.1.2", |
| @@ -45,8 +45,9 @@ | |||
| 45 | "diff-match-patch": "^1.0.5", | 45 | "diff-match-patch": "^1.0.5", |
| 46 | "dompurify": "^3.2.6", | 46 | "dompurify": "^3.2.6", |
| 47 | "droll": "^0.2.1", | 47 | "droll": "^0.2.1", |
| 48 | "env-paths": "^3.0.0", | ||
| 48 | "express": "^4.21.0", | 49 | "express": "^4.21.0", |
| 49 | "form-data": "^4.0.3", | 50 | "form-data": "^4.0.4", |
| 50 | "fuse.js": "^7.1.0", | 51 | "fuse.js": "^7.1.0", |
| 51 | "google-translate-api-browser": "^3.0.1", | 52 | "google-translate-api-browser": "^3.0.1", |
| 52 | "google-translate-api-x": "^10.7.2", | 53 | "google-translate-api-x": "^10.7.2", |
| @@ -67,7 +68,7 @@ | |||
| 67 | "multer": "^2.0.2", | 68 | "multer": "^2.0.2", |
| 68 | "node-fetch": "^3.3.2", | 69 | "node-fetch": "^3.3.2", |
| 69 | "node-persist": "^4.0.4", | 70 | "node-persist": "^4.0.4", |
| 70 | "open": "^10.1.2", | 71 | "open": "^10.2.0", |
| 71 | "png-chunk-text": "^1.0.0", | 72 | "png-chunk-text": "^1.0.0", |
| 72 | "png-chunks-extract": "^1.0.0", | 73 | "png-chunks-extract": "^1.0.0", |
| 73 | "proxy-agent": "^6.5.0", | 74 | "proxy-agent": "^6.5.0", |
| @@ -85,7 +86,7 @@ | |||
| 85 | "wavefile": "^11.0.0", | 86 | "wavefile": "^11.0.0", |
| 86 | "webpack": "^5.98.0", | 87 | "webpack": "^5.98.0", |
| 87 | "write-file-atomic": "^5.0.1", | 88 | "write-file-atomic": "^5.0.1", |
| 88 | "ws": "^8.18.2", | 89 | "ws": "^8.18.3", |
| 89 | "yaml": "^2.8.0", | 90 | "yaml": "^2.8.0", |
| 90 | "yargs": "^17.7.1", | 91 | "yargs": "^17.7.1", |
| 91 | "yauzl": "^3.2.0" | 92 | "yauzl": "^3.2.0" |
| @@ -115,6 +116,7 @@ | |||
| 115 | "scripts": { | 116 | "scripts": { |
| 116 | "start": "node server.js", | 117 | "start": "node server.js", |
| 117 | "debug": "node --inspect server.js", | 118 | "debug": "node --inspect server.js", |
| 119 | "start:global": "node server.js --global", | ||
| 118 | "start:electron": "cd ./src/electron && npm run start", | 120 | "start:electron": "cd ./src/electron && npm run start", |
| 119 | "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js", | 121 | "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js", |
| 120 | "start:bun": "bun server.js", | 122 | "start:bun": "bun server.js", |
| @@ -126,7 +128,7 @@ | |||
| 126 | "plugins:install": "node plugins install" | 128 | "plugins:install": "node plugins install" |
| 127 | }, | 129 | }, |
| 128 | "bin": { | 130 | "bin": { |
| 129 | "sillytavern": "./server.js" | 131 | "sillytavern": "./src/server-global.js" |
| 130 | }, | 132 | }, |
| 131 | "rules": { | 133 | "rules": { |
| 132 | "no-path-concat": "off", | 134 | "no-path-concat": "off", |
| @@ -147,9 +149,9 @@ | |||
| 147 | "@types/jquery-cropper": "^1.0.4", | 149 | "@types/jquery-cropper": "^1.0.4", |
| 148 | "@types/jquery.transit": "^0.9.33", | 150 | "@types/jquery.transit": "^0.9.33", |
| 149 | "@types/jqueryui": "^1.12.24", | 151 | "@types/jqueryui": "^1.12.24", |
| 150 | "@types/lodash": "^4.17.17", | 152 | "@types/lodash": "^4.17.20", |
| 151 | "@types/mime-types": "^3.0.1", | 153 | "@types/mime-types": "^3.0.1", |
| 152 | "@types/multer": "^1.4.13", | 154 | "@types/multer": "^2.0.0", |
| 153 | "@types/node": "^18.19.84", | 155 | "@types/node": "^18.19.84", |
| 154 | "@types/node-persist": "^3.1.8", | 156 | "@types/node-persist": "^3.1.8", |
| 155 | "@types/png-chunk-text": "^1.0.3", | 157 | "@types/png-chunk-text": "^1.0.3", |
| @@ -2,6 +2,8 @@ | |||
| 2 | import { CommandLineParser } from './src/command-line.js'; | 2 | import { CommandLineParser } from './src/command-line.js'; |
| 3 | import { serverDirectory } from './src/server-directory.js'; | 3 | import { serverDirectory } from './src/server-directory.js'; |
| 4 | 4 | ||
| 5 | console.log(`Node version: ${process.version}. Running in ${process.env.NODE_ENV} environment. Server directory: ${serverDirectory}`); | ||
| 6 | |||
| 5 | // config.yaml will be set when parsing command line arguments | 7 | // config.yaml will be set when parsing command line arguments |
| 6 | const cliArgs = new CommandLineParser().parse(process.argv); | 8 | const cliArgs = new CommandLineParser().parse(process.argv); |
| 7 | globalThis.DATA_ROOT = cliArgs.dataRoot; | 9 | globalThis.DATA_ROOT = cliArgs.dataRoot; |
| @@ -1,6 +1,9 @@ | |||
| 1 | import fs from 'node:fs'; | ||
| 2 | import path from 'node:path'; | ||
| 1 | import yargs from 'yargs/yargs'; | 3 | import yargs from 'yargs/yargs'; |
| 2 | import { hideBin } from 'yargs/helpers'; | 4 | import { hideBin } from 'yargs/helpers'; |
| 3 | import ipRegex from 'ip-regex'; | 5 | import ipRegex from 'ip-regex'; |
| 6 | import envPaths from 'env-paths'; | ||
| 4 | import { canResolve, color, getConfigValue, stringToBool } from './util.js'; | 7 | import { canResolve, color, getConfigValue, stringToBool } from './util.js'; |
| 5 | import { initConfig } from './config-init.js'; | 8 | import { initConfig } from './config-init.js'; |
| 6 | 9 | ||
| @@ -39,11 +42,18 @@ import { initConfig } from './config-init.js'; | |||
| 39 | * Provides a command line arguments parser. | 42 | * Provides a command line arguments parser. |
| 40 | */ | 43 | */ |
| 41 | export class CommandLineParser { | 44 | export class CommandLineParser { |
| 42 | constructor() { | 45 | /** |
| 43 | /** @type {CommandLineArguments} */ | 46 | * Gets the default configuration values. |
| 44 | this.default = Object.freeze({ | 47 | * @param {boolean} isGlobal If the configuration is global or not |
| 45 | configPath: './config.yaml', | 48 | * @returns {CommandLineArguments} Default configuration values |
| 46 | dataRoot: './data', | 49 | */ |
| 50 | getDefaultConfig(isGlobal) { | ||
| 51 | const appPaths = envPaths('SillyTavern', { suffix: '' }); | ||
| 52 | const configPath = isGlobal ? path.join(appPaths.data, 'config.yaml') : './config.yaml'; | ||
| 53 | const dataPath = isGlobal ? path.join(appPaths.data, 'data') : './data'; | ||
| 54 | return Object.freeze({ | ||
| 55 | configPath: configPath, | ||
| 56 | dataRoot: dataPath, | ||
| 47 | port: 8000, | 57 | port: 8000, |
| 48 | listen: false, | 58 | listen: false, |
| 49 | listenAddressIPv6: '[::]', | 59 | listenAddressIPv6: '[::]', |
| @@ -78,7 +88,9 @@ export class CommandLineParser { | |||
| 78 | throw new Error('getBrowserLaunchUrl is not implemented'); | 88 | throw new Error('getBrowserLaunchUrl is not implemented'); |
| 79 | }, | 89 | }, |
| 80 | }); | 90 | }); |
| 91 | } | ||
| 81 | 92 | ||
| 93 | constructor() { | ||
| 82 | this.booleanAutoOptions = [true, false, 'auto']; | 94 | this.booleanAutoOptions = [true, false, 'auto']; |
| 83 | } | 95 | } |
| 84 | 96 | ||
| @@ -91,10 +103,15 @@ export class CommandLineParser { | |||
| 91 | parse(args) { | 103 | parse(args) { |
| 92 | const cliArguments = yargs(hideBin(args)) | 104 | const cliArguments = yargs(hideBin(args)) |
| 93 | .usage('Usage: <your-start-script> [options]\nOptions that are not provided will be filled with config values.') | 105 | .usage('Usage: <your-start-script> [options]\nOptions that are not provided will be filled with config values.') |
| 106 | .option('global', { | ||
| 107 | type: 'boolean', | ||
| 108 | default: null, | ||
| 109 | describe: 'Use global data and config paths instead of the server directory', | ||
| 110 | }) | ||
| 94 | .option('configPath', { | 111 | .option('configPath', { |
| 95 | type: 'string', | 112 | type: 'string', |
| 96 | default: null, | 113 | default: null, |
| 97 | describe: 'Path to the config file', | 114 | describe: 'Path to the config file (only for standalone mode)', |
| 98 | }) | 115 | }) |
| 99 | .option('enableIPv6', { | 116 | .option('enableIPv6', { |
| 100 | type: 'string', | 117 | type: 'string', |
| @@ -184,7 +201,7 @@ export class CommandLineParser { | |||
| 184 | .option('dataRoot', { | 201 | .option('dataRoot', { |
| 185 | type: 'string', | 202 | type: 'string', |
| 186 | default: null, | 203 | default: null, |
| 187 | describe: 'Root directory for data storage', | 204 | describe: 'Root directory for data storage (only for standalone mode)', |
| 188 | }) | 205 | }) |
| 189 | .option('basicAuthMode', { | 206 | .option('basicAuthMode', { |
| 190 | type: 'boolean', | 207 | type: 'boolean', |
| @@ -228,33 +245,57 @@ export class CommandLineParser { | |||
| 228 | }) | 245 | }) |
| 229 | .parseSync(); | 246 | .parseSync(); |
| 230 | 247 | ||
| 231 | const configPath = cliArguments.configPath ?? this.default.configPath; | 248 | const isGlobal = globalThis.FORCE_GLOBAL_MODE ?? cliArguments.global ?? false; |
| 249 | const defaultConfig = this.getDefaultConfig(isGlobal); | ||
| 250 | |||
| 251 | if (isGlobal && cliArguments.configPath) { | ||
| 252 | console.warn(color.yellow('Warning: "--configPath" argument is ignored in global mode')); | ||
| 253 | } | ||
| 254 | |||
| 255 | if (isGlobal && cliArguments.dataRoot) { | ||
| 256 | console.warn(color.yellow('Warning: "--dataRoot" argument is ignored in global mode')); | ||
| 257 | } | ||
| 258 | |||
| 259 | const configPath = isGlobal | ||
| 260 | ? defaultConfig.configPath | ||
| 261 | : (cliArguments.configPath ?? defaultConfig.configPath); | ||
| 262 | if (isGlobal && !fs.existsSync(path.dirname(configPath))) { | ||
| 263 | fs.mkdirSync(path.dirname(configPath), { recursive: true }); | ||
| 264 | } | ||
| 232 | initConfig(configPath); | 265 | initConfig(configPath); |
| 266 | |||
| 267 | const dataRoot = isGlobal | ||
| 268 | ? defaultConfig.dataRoot | ||
| 269 | : (cliArguments.dataRoot ?? getConfigValue('dataRoot', defaultConfig.dataRoot)); | ||
| 270 | if (isGlobal && !fs.existsSync(dataRoot)) { | ||
| 271 | fs.mkdirSync(dataRoot, { recursive: true }); | ||
| 272 | } | ||
| 273 | |||
| 233 | /** @type {CommandLineArguments} */ | 274 | /** @type {CommandLineArguments} */ |
| 234 | const result = { | 275 | const result = { |
| 235 | configPath: configPath, | 276 | configPath: configPath, |
| 236 | dataRoot: cliArguments.dataRoot ?? getConfigValue('dataRoot', this.default.dataRoot), | 277 | dataRoot: dataRoot, |
| 237 | port: cliArguments.port ?? getConfigValue('port', this.default.port, 'number'), | 278 | port: cliArguments.port ?? getConfigValue('port', defaultConfig.port, 'number'), |
| 238 | listen: cliArguments.listen ?? getConfigValue('listen', this.default.listen, 'boolean'), | 279 | listen: cliArguments.listen ?? getConfigValue('listen', defaultConfig.listen, 'boolean'), |
| 239 | listenAddressIPv6: cliArguments.listenAddressIPv6 ?? getConfigValue('listenAddress.ipv6', this.default.listenAddressIPv6), | 280 | listenAddressIPv6: cliArguments.listenAddressIPv6 ?? getConfigValue('listenAddress.ipv6', defaultConfig.listenAddressIPv6), |
| 240 | listenAddressIPv4: cliArguments.listenAddressIPv4 ?? getConfigValue('listenAddress.ipv4', this.default.listenAddressIPv4), | 281 | listenAddressIPv4: cliArguments.listenAddressIPv4 ?? getConfigValue('listenAddress.ipv4', defaultConfig.listenAddressIPv4), |
| 241 | enableIPv4: stringToBool(cliArguments.enableIPv4) ?? stringToBool(getConfigValue('protocol.ipv4', this.default.enableIPv4)) ?? this.default.enableIPv4, | 282 | enableIPv4: stringToBool(cliArguments.enableIPv4) ?? stringToBool(getConfigValue('protocol.ipv4', defaultConfig.enableIPv4)) ?? defaultConfig.enableIPv4, |
| 242 | enableIPv6: stringToBool(cliArguments.enableIPv6) ?? stringToBool(getConfigValue('protocol.ipv6', this.default.enableIPv6)) ?? this.default.enableIPv6, | 283 | enableIPv6: stringToBool(cliArguments.enableIPv6) ?? stringToBool(getConfigValue('protocol.ipv6', defaultConfig.enableIPv6)) ?? defaultConfig.enableIPv6, |
| 243 | dnsPreferIPv6: cliArguments.dnsPreferIPv6 ?? getConfigValue('dnsPreferIPv6', this.default.dnsPreferIPv6, 'boolean'), | 284 | dnsPreferIPv6: cliArguments.dnsPreferIPv6 ?? getConfigValue('dnsPreferIPv6', defaultConfig.dnsPreferIPv6, 'boolean'), |
| 244 | browserLaunchEnabled: cliArguments.browserLaunchEnabled ?? cliArguments.autorun ?? getConfigValue('browserLaunch.enabled', this.default.browserLaunchEnabled, 'boolean'), | 285 | browserLaunchEnabled: cliArguments.browserLaunchEnabled ?? cliArguments.autorun ?? getConfigValue('browserLaunch.enabled', defaultConfig.browserLaunchEnabled, 'boolean'), |
| 245 | browserLaunchHostname: cliArguments.browserLaunchHostname ?? cliArguments.autorunHostname ?? getConfigValue('browserLaunch.hostname', this.default.browserLaunchHostname), | 286 | browserLaunchHostname: cliArguments.browserLaunchHostname ?? cliArguments.autorunHostname ?? getConfigValue('browserLaunch.hostname', defaultConfig.browserLaunchHostname), |
| 246 | browserLaunchPort: cliArguments.browserLaunchPort ?? cliArguments.autorunPortOverride ?? getConfigValue('browserLaunch.port', this.default.browserLaunchPort, 'number'), | 287 | browserLaunchPort: cliArguments.browserLaunchPort ?? cliArguments.autorunPortOverride ?? getConfigValue('browserLaunch.port', defaultConfig.browserLaunchPort, 'number'), |
| 247 | browserLaunchAvoidLocalhost: cliArguments.browserLaunchAvoidLocalhost ?? cliArguments.avoidLocalhost ?? getConfigValue('browserLaunch.avoidLocalhost', this.default.browserLaunchAvoidLocalhost, 'boolean'), | 288 | browserLaunchAvoidLocalhost: cliArguments.browserLaunchAvoidLocalhost ?? cliArguments.avoidLocalhost ?? getConfigValue('browserLaunch.avoidLocalhost', defaultConfig.browserLaunchAvoidLocalhost, 'boolean'), |
| 248 | enableCorsProxy: cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', this.default.enableCorsProxy, 'boolean'), | 289 | enableCorsProxy: cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', defaultConfig.enableCorsProxy, 'boolean'), |
| 249 | disableCsrf: cliArguments.disableCsrf ?? getConfigValue('disableCsrfProtection', this.default.disableCsrf, 'boolean'), | 290 | disableCsrf: cliArguments.disableCsrf ?? getConfigValue('disableCsrfProtection', defaultConfig.disableCsrf, 'boolean'), |
| 250 | ssl: cliArguments.ssl ?? getConfigValue('ssl.enabled', this.default.ssl, 'boolean'), | 291 | ssl: cliArguments.ssl ?? getConfigValue('ssl.enabled', defaultConfig.ssl, 'boolean'), |
| 251 | certPath: cliArguments.certPath ?? getConfigValue('ssl.certPath', this.default.certPath), | 292 | certPath: cliArguments.certPath ?? getConfigValue('ssl.certPath', defaultConfig.certPath), |
| 252 | keyPath: cliArguments.keyPath ?? getConfigValue('ssl.keyPath', this.default.keyPath), | 293 | keyPath: cliArguments.keyPath ?? getConfigValue('ssl.keyPath', defaultConfig.keyPath), |
| 253 | whitelistMode: cliArguments.whitelist ?? getConfigValue('whitelistMode', this.default.whitelistMode, 'boolean'), | 294 | whitelistMode: cliArguments.whitelist ?? getConfigValue('whitelistMode', defaultConfig.whitelistMode, 'boolean'), |
| 254 | basicAuthMode: cliArguments.basicAuthMode ?? getConfigValue('basicAuthMode', this.default.basicAuthMode, 'boolean'), | 295 | basicAuthMode: cliArguments.basicAuthMode ?? getConfigValue('basicAuthMode', defaultConfig.basicAuthMode, 'boolean'), |
| 255 | requestProxyEnabled: cliArguments.requestProxyEnabled ?? getConfigValue('requestProxy.enabled', this.default.requestProxyEnabled, 'boolean'), | 296 | requestProxyEnabled: cliArguments.requestProxyEnabled ?? getConfigValue('requestProxy.enabled', defaultConfig.requestProxyEnabled, 'boolean'), |
| 256 | requestProxyUrl: cliArguments.requestProxyUrl ?? getConfigValue('requestProxy.url', this.default.requestProxyUrl), | 297 | requestProxyUrl: cliArguments.requestProxyUrl ?? getConfigValue('requestProxy.url', defaultConfig.requestProxyUrl), |
| 257 | requestProxyBypass: cliArguments.requestProxyBypass ?? getConfigValue('requestProxy.bypass', this.default.requestProxyBypass), | 298 | requestProxyBypass: cliArguments.requestProxyBypass ?? getConfigValue('requestProxy.bypass', defaultConfig.requestProxyBypass), |
| 258 | getIPv4ListenUrl: function () { | 299 | getIPv4ListenUrl: function () { |
| 259 | const isValid = ipRegex.v4({ exact: true }).test(this.listenAddressIPv4); | 300 | const isValid = ipRegex.v4({ exact: true }).test(this.listenAddressIPv4); |
| 260 | return new URL( | 301 | return new URL( |
| @@ -302,13 +343,13 @@ export class CommandLineParser { | |||
| 302 | }; | 343 | }; |
| 303 | 344 | ||
| 304 | if (!this.booleanAutoOptions.includes(result.enableIPv6)) { | 345 | if (!this.booleanAutoOptions.includes(result.enableIPv6)) { |
| 305 | console.warn(color.red('`protocol: ipv6` option invalid'), '\n use:', this.booleanAutoOptions, '\n setting to:', this.default.enableIPv6); | 346 | console.warn(color.red('`protocol: ipv6` option invalid'), '\n use:', this.booleanAutoOptions, '\n setting to:', defaultConfig.enableIPv6); |
| 306 | result.enableIPv6 = this.default.enableIPv6; | 347 | result.enableIPv6 = defaultConfig.enableIPv6; |
| 307 | } | 348 | } |
| 308 | 349 | ||
| 309 | if (!this.booleanAutoOptions.includes(result.enableIPv4)) { | 350 | if (!this.booleanAutoOptions.includes(result.enableIPv4)) { |
| 310 | console.warn(color.red('`protocol: ipv4` option invalid'), '\n use:', this.booleanAutoOptions, '\n setting to:', this.default.enableIPv4); | 351 | console.warn(color.red('`protocol: ipv4` option invalid'), '\n use:', this.booleanAutoOptions, '\n setting to:', defaultConfig.enableIPv4); |
| 311 | result.enableIPv4 = this.default.enableIPv4; | 352 | result.enableIPv4 = defaultConfig.enableIPv4; |
| 312 | } | 353 | } |
| 313 | 354 | ||
| 314 | return result; | 355 | return result; |
| @@ -148,6 +148,13 @@ function getAllKeys(obj, prefix = '') { | |||
| 148 | export function addMissingConfigValues(configPath) { | 148 | export function addMissingConfigValues(configPath) { |
| 149 | try { | 149 | try { |
| 150 | const defaultConfig = yaml.parse(fs.readFileSync(path.join(serverDirectory, './default/config.yaml'), 'utf8')); | 150 | const defaultConfig = yaml.parse(fs.readFileSync(path.join(serverDirectory, './default/config.yaml'), 'utf8')); |
| 151 | |||
| 152 | if (!fs.existsSync(configPath)) { | ||
| 153 | console.warn(color.yellow(`Warning: config.yaml not found at ${configPath}. Creating a new one with default values.`)); | ||
| 154 | fs.writeFileSync(configPath, yaml.stringify(defaultConfig)); | ||
| 155 | return; | ||
| 156 | } | ||
| 157 | |||
| 151 | let config = yaml.parse(fs.readFileSync(configPath, 'utf8')); | 158 | let config = yaml.parse(fs.readFileSync(configPath, 'utf8')); |
| 152 | 159 | ||
| 153 | // Migrate old keys to new keys | 160 | // Migrate old keys to new keys |
| @@ -224,6 +231,7 @@ export function addMissingConfigValues(configPath) { | |||
| 224 | * @param {string} configPath Path to config.yaml | 231 | * @param {string} configPath Path to config.yaml |
| 225 | */ | 232 | */ |
| 226 | export function initConfig(configPath) { | 233 | export function initConfig(configPath) { |
| 234 | console.log('Using config path:', color.green(configPath)); | ||
| 227 | setConfigFilePath(configPath); | 235 | setConfigFilePath(configPath); |
| 228 | addMissingConfigValues(configPath); | 236 | addMissingConfigValues(configPath); |
| 229 | } | 237 | } |
| @@ -41,7 +41,7 @@ function startServer() { | |||
| 41 | const sillyTavernRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); | 41 | const sillyTavernRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); |
| 42 | process.chdir(sillyTavernRoot); | 42 | process.chdir(sillyTavernRoot); |
| 43 | 43 | ||
| 44 | import('../../server.js'); | 44 | import('../server-global.js'); |
| 45 | }); | 45 | }); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | #!/usr/bin/env node | ||
| 2 | globalThis.FORCE_GLOBAL_MODE = true; | ||
| 3 | await import('../server.js'); | ||
| 4 | |||
| 5 | export {}; | ||
| @@ -19,16 +19,6 @@ import bodyParser from 'body-parser'; | |||
| 19 | import './fetch-patch.js'; | 19 | import './fetch-patch.js'; |
| 20 | import { serverDirectory } from './server-directory.js'; | 20 | import { serverDirectory } from './server-directory.js'; |
| 21 | 21 | ||
| 22 | console.log(`Node version: ${process.version}. Running in ${process.env.NODE_ENV} environment. Server directory: ${serverDirectory}`); | ||
| 23 | |||
| 24 | // Work around a node v20.0.0, v20.1.0, and v20.2.0 bug. The issue was fixed in v20.3.0. | ||
| 25 | // https://github.com/nodejs/node/issues/47822#issuecomment-1564708870 | ||
| 26 | // Safe to remove once support for Node v20 is dropped. | ||
| 27 | if (process.versions && process.versions.node && process.versions.node.match(/20\.[0-2]\.0/)) { | ||
| 28 | // @ts-ignore | ||
| 29 | if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false); | ||
| 30 | } | ||
| 31 | |||
| 32 | import { serverEvents, EVENT_NAMES } from './server-events.js'; | 22 | import { serverEvents, EVENT_NAMES } from './server-events.js'; |
| 33 | import { loadPlugins } from './plugin-loader.js'; | 23 | import { loadPlugins } from './plugin-loader.js'; |
| 34 | import { | 24 | import { |
| @@ -78,6 +68,14 @@ import { redirectDeprecatedEndpoints, ServerStartup, setupPrivateEndpoints } fro | |||
| 78 | import { diskCache } from './endpoints/characters.js'; | 68 | import { diskCache } from './endpoints/characters.js'; |
| 79 | import { migrateFlatSecrets } from './endpoints/secrets.js'; | 69 | import { migrateFlatSecrets } from './endpoints/secrets.js'; |
| 80 | 70 | ||
| 71 | // Work around a node v20.0.0, v20.1.0, and v20.2.0 bug. The issue was fixed in v20.3.0. | ||
| 72 | // https://github.com/nodejs/node/issues/47822#issuecomment-1564708870 | ||
| 73 | // Safe to remove once support for Node v20 is dropped. | ||
| 74 | if (process.versions && process.versions.node && process.versions.node.match(/20\.[0-2]\.0/)) { | ||
| 75 | // @ts-ignore | ||
| 76 | if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false); | ||
| 77 | } | ||
| 78 | |||
| 81 | // Unrestrict console logs display limit | 79 | // Unrestrict console logs display limit |
| 82 | util.inspect.defaultOptions.maxArrayLength = null; | 80 | util.inspect.defaultOptions.maxArrayLength = null; |
| 83 | util.inspect.defaultOptions.maxStringLength = null; | 81 | util.inspect.defaultOptions.maxStringLength = null; |
| @@ -91,18 +89,6 @@ if (!cliArgs.enableIPv6 && !cliArgs.enableIPv4) { | |||
| 91 | process.exit(1); | 89 | process.exit(1); |
| 92 | } | 90 | } |
| 93 | 91 | ||
| 94 | try { | ||
| 95 | if (cliArgs.dnsPreferIPv6) { | ||
| 96 | dns.setDefaultResultOrder('ipv6first'); | ||
| 97 | console.log('Preferring IPv6 for DNS resolution'); | ||
| 98 | } else { | ||
| 99 | dns.setDefaultResultOrder('ipv4first'); | ||
| 100 | console.log('Preferring IPv4 for DNS resolution'); | ||
| 101 | } | ||
| 102 | } catch (error) { | ||
| 103 | console.warn('Failed to set DNS resolution order. Possibly unsupported in this Node version.'); | ||
| 104 | } | ||
| 105 | |||
| 106 | const app = express(); | 92 | const app = express(); |
| 107 | app.use(helmet({ | 93 | app.use(helmet({ |
| 108 | contentSecurityPolicy: false, | 94 | contentSecurityPolicy: false, |
| @@ -400,8 +386,26 @@ function apply404Middleware() { | |||
| 400 | }); | 386 | }); |
| 401 | } | 387 | } |
| 402 | 388 | ||
| 389 | /** | ||
| 390 | * Sets the DNS resolution order based on the command line arguments. | ||
| 391 | */ | ||
| 392 | function setDnsResolutionOrder() { | ||
| 393 | try { | ||
| 394 | if (cliArgs.dnsPreferIPv6) { | ||
| 395 | dns.setDefaultResultOrder('ipv6first'); | ||
| 396 | console.log('Preferring IPv6 for DNS resolution'); | ||
| 397 | } else { | ||
| 398 | dns.setDefaultResultOrder('ipv4first'); | ||
| 399 | console.log('Preferring IPv4 for DNS resolution'); | ||
| 400 | } | ||
| 401 | } catch (error) { | ||
| 402 | console.warn('Failed to set DNS resolution order. Possibly unsupported in this Node version.'); | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 403 | // User storage module needs to be initialized before starting the server | 406 | // User storage module needs to be initialized before starting the server |
| 404 | initUserStorage(globalThis.DATA_ROOT) | 407 | initUserStorage(globalThis.DATA_ROOT) |
| 408 | .then(setDnsResolutionOrder) | ||
| 405 | .then(ensurePublicDirectoriesExist) | 409 | .then(ensurePublicDirectoriesExist) |
| 406 | .then(migrateUserData) | 410 | .then(migrateUserData) |
| 407 | .then(migrateSystemPrompts) | 411 | .then(migrateSystemPrompts) |