Add config value type converters for numbers and booleans
| @@ -261,26 +261,26 @@ app.use(responseTime()); | |||
| 261 | 261 | ||
| 262 | 262 | ||
| 263 | /** @type {number} */ | 263 | /** @type {number} */ |
| 264 | const server_port = cliArguments.port ?? getConfigValue('port', DEFAULT_PORT); | 264 | const server_port = cliArguments.port ?? getConfigValue('port', DEFAULT_PORT, 'number'); |
| 265 | /** @type {boolean} */ | 265 | /** @type {boolean} */ |
| 266 | const autorun = (cliArguments.autorun ?? getConfigValue('autorun', DEFAULT_AUTORUN)) && !cliArguments.ssl; | 266 | const autorun = (cliArguments.autorun ?? getConfigValue('autorun', DEFAULT_AUTORUN, 'boolean')) && !cliArguments.ssl; |
| 267 | /** @type {boolean} */ | 267 | /** @type {boolean} */ |
| 268 | const listen = cliArguments.listen ?? getConfigValue('listen', DEFAULT_LISTEN); | 268 | const listen = cliArguments.listen ?? getConfigValue('listen', DEFAULT_LISTEN, 'boolean'); |
| 269 | /** @type {string} */ | 269 | /** @type {string} */ |
| 270 | const listenAddressIPv6 = cliArguments.listenAddressIPv6 ?? getConfigValue('listenAddress.ipv6', DEFAULT_LISTEN_ADDRESS_IPV6); | 270 | const listenAddressIPv6 = cliArguments.listenAddressIPv6 ?? getConfigValue('listenAddress.ipv6', DEFAULT_LISTEN_ADDRESS_IPV6); |
| 271 | /** @type {string} */ | 271 | /** @type {string} */ |
| 272 | const listenAddressIPv4 = cliArguments.listenAddressIPv4 ?? getConfigValue('listenAddress.ipv4', DEFAULT_LISTEN_ADDRESS_IPV4); | 272 | const listenAddressIPv4 = cliArguments.listenAddressIPv4 ?? getConfigValue('listenAddress.ipv4', DEFAULT_LISTEN_ADDRESS_IPV4); |
| 273 | /** @type {boolean} */ | 273 | /** @type {boolean} */ |
| 274 | const enableCorsProxy = cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', DEFAULT_CORS_PROXY); | 274 | const enableCorsProxy = cliArguments.corsProxy ?? getConfigValue('enableCorsProxy', DEFAULT_CORS_PROXY, 'boolean'); |
| 275 | const enableWhitelist = cliArguments.whitelist ?? getConfigValue('whitelistMode', DEFAULT_WHITELIST); | 275 | const enableWhitelist = cliArguments.whitelist ?? getConfigValue('whitelistMode', DEFAULT_WHITELIST, 'boolean'); |
| 276 | /** @type {string} */ | 276 | /** @type {string} */ |
| 277 | globalThis.DATA_ROOT = cliArguments.dataRoot ?? getConfigValue('dataRoot', './data'); | 277 | globalThis.DATA_ROOT = cliArguments.dataRoot ?? getConfigValue('dataRoot', './data'); |
| 278 | /** @type {boolean} */ | 278 | /** @type {boolean} */ |
| 279 | const disableCsrf = cliArguments.disableCsrf ?? getConfigValue('disableCsrfProtection', DEFAULT_CSRF_DISABLED); | 279 | const disableCsrf = cliArguments.disableCsrf ?? getConfigValue('disableCsrfProtection', DEFAULT_CSRF_DISABLED, 'boolean'); |
| 280 | const basicAuthMode = cliArguments.basicAuthMode ?? getConfigValue('basicAuthMode', DEFAULT_BASIC_AUTH); | 280 | const basicAuthMode = cliArguments.basicAuthMode ?? getConfigValue('basicAuthMode', DEFAULT_BASIC_AUTH, 'boolean'); |
| 281 | const perUserBasicAuth = getConfigValue('perUserBasicAuth', DEFAULT_PER_USER_BASIC_AUTH); | 281 | const perUserBasicAuth = getConfigValue('perUserBasicAuth', DEFAULT_PER_USER_BASIC_AUTH, 'boolean'); |
| 282 | /** @type {boolean} */ | 282 | /** @type {boolean} */ |
| 283 | const enableAccounts = getConfigValue('enableUserAccounts', DEFAULT_ACCOUNTS); | 283 | const enableAccounts = getConfigValue('enableUserAccounts', DEFAULT_ACCOUNTS, 'boolean'); |
| 284 | 284 | ||
| 285 | const uploadsPath = path.join(globalThis.DATA_ROOT, UPLOADS_DIRECTORY); | 285 | const uploadsPath = path.join(globalThis.DATA_ROOT, UPLOADS_DIRECTORY); |
| 286 | 286 | ||
| @@ -293,15 +293,15 @@ let enableIPv4 = stringToBool(cliArguments.enableIPv4) ?? getConfigValue('protoc | |||
| 293 | /** @type {string} */ | 293 | /** @type {string} */ |
| 294 | const autorunHostname = cliArguments.autorunHostname ?? getConfigValue('autorunHostname', DEFAULT_AUTORUN_HOSTNAME); | 294 | const autorunHostname = cliArguments.autorunHostname ?? getConfigValue('autorunHostname', DEFAULT_AUTORUN_HOSTNAME); |
| 295 | /** @type {number} */ | 295 | /** @type {number} */ |
| 296 | const autorunPortOverride = cliArguments.autorunPortOverride ?? getConfigValue('autorunPortOverride', DEFAULT_AUTORUN_PORT); | 296 | const autorunPortOverride = cliArguments.autorunPortOverride ?? getConfigValue('autorunPortOverride', DEFAULT_AUTORUN_PORT, 'number'); |
| 297 | 297 | ||
| 298 | /** @type {boolean} */ | 298 | /** @type {boolean} */ |
| 299 | const dnsPreferIPv6 = cliArguments.dnsPreferIPv6 ?? getConfigValue('dnsPreferIPv6', DEFAULT_PREFER_IPV6); | 299 | const dnsPreferIPv6 = cliArguments.dnsPreferIPv6 ?? getConfigValue('dnsPreferIPv6', DEFAULT_PREFER_IPV6, 'boolean'); |
| 300 | 300 | ||
| 301 | /** @type {boolean} */ | 301 | /** @type {boolean} */ |
| 302 | const avoidLocalhost = cliArguments.avoidLocalhost ?? getConfigValue('avoidLocalhost', DEFAULT_AVOID_LOCALHOST); | 302 | const avoidLocalhost = cliArguments.avoidLocalhost ?? getConfigValue('avoidLocalhost', DEFAULT_AVOID_LOCALHOST, 'boolean'); |
| 303 | 303 | ||
| 304 | const proxyEnabled = cliArguments.requestProxyEnabled ?? getConfigValue('requestProxy.enabled', DEFAULT_PROXY_ENABLED); | 304 | const proxyEnabled = cliArguments.requestProxyEnabled ?? getConfigValue('requestProxy.enabled', DEFAULT_PROXY_ENABLED, 'boolean'); |
| 305 | const proxyUrl = cliArguments.requestProxyUrl ?? getConfigValue('requestProxy.url', DEFAULT_PROXY_URL); | 305 | const proxyUrl = cliArguments.requestProxyUrl ?? getConfigValue('requestProxy.url', DEFAULT_PROXY_URL); |
| 306 | const proxyBypass = cliArguments.requestProxyBypass ?? getConfigValue('requestProxy.bypass', DEFAULT_PROXY_BYPASS); | 306 | const proxyBypass = cliArguments.requestProxyBypass ?? getConfigValue('requestProxy.bypass', DEFAULT_PROXY_BYPASS); |
| 307 | 307 | ||
| @@ -395,7 +395,7 @@ if (enableCorsProxy) { | |||
| 395 | 395 | ||
| 396 | function getSessionCookieAge() { | 396 | function getSessionCookieAge() { |
| 397 | // Defaults to "no expiration" if not set | 397 | // Defaults to "no expiration" if not set |
| 398 | const configValue = getConfigValue('sessionTimeout', -1); | 398 | const configValue = getConfigValue('sessionTimeout', -1, 'number'); |
| 399 | 399 | ||
| 400 | // Convert to milliseconds | 400 | // Convert to milliseconds |
| 401 | if (configValue > 0) { | 401 | if (configValue > 0) { |
| @@ -924,7 +924,7 @@ function setWindowTitle(title) { | |||
| 924 | function logSecurityAlert(message) { | 924 | function logSecurityAlert(message) { |
| 925 | if (basicAuthMode || enableWhitelist) return; // safe! | 925 | if (basicAuthMode || enableWhitelist) return; // safe! |
| 926 | console.error(color.red(message)); | 926 | console.error(color.red(message)); |
| 927 | if (getConfigValue('securityOverride', false)) { | 927 | if (getConfigValue('securityOverride', false, 'boolean')) { |
| 928 | console.warn(color.red('Security has been overridden. If it\'s not a trusted network, change the settings.')); | 928 | console.warn(color.red('Security has been overridden. If it\'s not a trusted network, change the settings.')); |
| 929 | return; | 929 | return; |
| 930 | } | 930 | } |
| @@ -106,8 +106,8 @@ async function sendClaudeRequest(request, response) { | |||
| 106 | const apiUrl = new URL(request.body.reverse_proxy || API_CLAUDE).toString(); | 106 | const apiUrl = new URL(request.body.reverse_proxy || API_CLAUDE).toString(); |
| 107 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.CLAUDE); | 107 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.CLAUDE); |
| 108 | const divider = '-'.repeat(process.stdout.columns); | 108 | const divider = '-'.repeat(process.stdout.columns); |
| 109 | const enableSystemPromptCache = getConfigValue('claude.enableSystemPromptCache', false) && request.body.model.startsWith('claude-3'); | 109 | const enableSystemPromptCache = getConfigValue('claude.enableSystemPromptCache', false, 'boolean') && request.body.model.startsWith('claude-3'); |
| 110 | let cachingAtDepth = getConfigValue('claude.cachingAtDepth', -1); | 110 | let cachingAtDepth = getConfigValue('claude.cachingAtDepth', -1, 'number'); |
| 111 | // Disabled if not an integer or negative, or if the model doesn't support it | 111 | // Disabled if not an integer or negative, or if the model doesn't support it |
| 112 | if (!Number.isInteger(cachingAtDepth) || cachingAtDepth < 0 || !request.body.model.startsWith('claude-3')) { | 112 | if (!Number.isInteger(cachingAtDepth) || cachingAtDepth < 0 || !request.body.model.startsWith('claude-3')) { |
| 113 | cachingAtDepth = -1; | 113 | cachingAtDepth = -1; |
| @@ -969,7 +969,7 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 969 | bodyParams.logprobs = true; | 969 | bodyParams.logprobs = true; |
| 970 | } | 970 | } |
| 971 | 971 | ||
| 972 | if (getConfigValue('openai.randomizeUserId', false)) { | 972 | if (getConfigValue('openai.randomizeUserId', false, 'boolean')) { |
| 973 | bodyParams['user'] = uuidv4(); | 973 | bodyParams['user'] = uuidv4(); |
| 974 | } | 974 | } |
| 975 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) { | 975 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENROUTER) { |
| @@ -1008,7 +1008,7 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 1008 | bodyParams['include_reasoning'] = true; | 1008 | bodyParams['include_reasoning'] = true; |
| 1009 | } | 1009 | } |
| 1010 | 1010 | ||
| 1011 | let cachingAtDepth = getConfigValue('claude.cachingAtDepth', -1); | 1011 | let cachingAtDepth = getConfigValue('claude.cachingAtDepth', -1, 'number'); |
| 1012 | if (Number.isInteger(cachingAtDepth) && cachingAtDepth >= 0 && request.body.model?.startsWith('anthropic/claude-3')) { | 1012 | if (Number.isInteger(cachingAtDepth) && cachingAtDepth >= 0 && request.body.model?.startsWith('anthropic/claude-3')) { |
| 1013 | cachingAtDepthForOpenRouterClaude(request.body.messages, cachingAtDepth); | 1013 | cachingAtDepthForOpenRouterClaude(request.body.messages, cachingAtDepth); |
| 1014 | } | 1014 | } |
| @@ -372,8 +372,8 @@ router.post('/generate', jsonParser, async function (request, response) { | |||
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | if (request.body.api_type === TEXTGEN_TYPES.OLLAMA) { | 374 | if (request.body.api_type === TEXTGEN_TYPES.OLLAMA) { |
| 375 | const keepAlive = getConfigValue('ollama.keepAlive', -1); | 375 | const keepAlive = getConfigValue('ollama.keepAlive', -1, 'number'); |
| 376 | const numBatch = getConfigValue('ollama.batchSize', -1); | 376 | const numBatch = getConfigValue('ollama.batchSize', -1, 'number'); |
| 377 | if (numBatch > 0) { | 377 | if (numBatch > 0) { |
| 378 | request.body['num_batch'] = numBatch; | 378 | request.body['num_batch'] = numBatch; |
| 379 | } | 379 | } |
| @@ -24,7 +24,7 @@ import { importRisuSprites } from './sprites.js'; | |||
| 24 | const defaultAvatarPath = './public/img/ai4.png'; | 24 | const defaultAvatarPath = './public/img/ai4.png'; |
| 25 | 25 | ||
| 26 | // KV-store for parsed character data | 26 | // KV-store for parsed character data |
| 27 | const cacheCapacity = Number(getConfigValue('cardsCacheCapacity', 100)); // MB | 27 | const cacheCapacity = getConfigValue('cardsCacheCapacity', 100, 'number'); // MB |
| 28 | // With 100 MB limit it would take roughly 3000 characters to reach this limit | 28 | // With 100 MB limit it would take roughly 3000 characters to reach this limit |
| 29 | const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity); | 29 | const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity); |
| 30 | // Some Android devices require tighter memory management | 30 | // Some Android devices require tighter memory management |
| @@ -19,9 +19,9 @@ import { | |||
| 19 | formatBytes, | 19 | formatBytes, |
| 20 | } from '../util.js'; | 20 | } from '../util.js'; |
| 21 | 21 | ||
| 22 | const isBackupEnabled = !!getConfigValue('backups.chat.enabled', true); | 22 | const isBackupEnabled = getConfigValue('backups.chat.enabled', true, 'boolean'); |
| 23 | const maxTotalChatBackups = Number(getConfigValue('backups.chat.maxTotalBackups', -1)); | 23 | const maxTotalChatBackups = getConfigValue('backups.chat.maxTotalBackups', -1, 'number'); |
| 24 | const throttleInterval = Number(getConfigValue('backups.chat.throttleInterval', 10_000)); | 24 | const throttleInterval = getConfigValue('backups.chat.throttleInterval', 10_000, 'number'); |
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | * Saves a chat to the backups directory. | 27 | * Saves a chat to the backups directory. |
| @@ -165,7 +165,7 @@ async function seedContentForUser(contentIndex, directories, forceCategories) { | |||
| 165 | */ | 165 | */ |
| 166 | export async function checkForNewContent(directoriesList, forceCategories = []) { | 166 | export async function checkForNewContent(directoriesList, forceCategories = []) { |
| 167 | try { | 167 | try { |
| 168 | const contentCheckSkip = getConfigValue('skipContentCheck', false); | 168 | const contentCheckSkip = getConfigValue('skipContentCheck', false, 'boolean'); |
| 169 | if (contentCheckSkip && forceCategories?.length === 0) { | 169 | if (contentCheckSkip && forceCategories?.length === 0) { |
| 170 | return; | 170 | return; |
| 171 | } | 171 | } |
| @@ -183,7 +183,7 @@ router.post('/read', jsonParser, (request, response) => { | |||
| 183 | }); | 183 | }); |
| 184 | 184 | ||
| 185 | router.post('/view', jsonParser, async (request, response) => { | 185 | router.post('/view', jsonParser, async (request, response) => { |
| 186 | const allowKeysExposure = getConfigValue('allowKeysExposure', false); | 186 | const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean'); |
| 187 | 187 | ||
| 188 | if (!allowKeysExposure) { | 188 | if (!allowKeysExposure) { |
| 189 | console.error('secrets.json could not be viewed unless the value of allowKeysExposure in config.yaml is set to true'); | 189 | console.error('secrets.json could not be viewed unless the value of allowKeysExposure in config.yaml is set to true'); |
| @@ -205,7 +205,7 @@ router.post('/view', jsonParser, async (request, response) => { | |||
| 205 | }); | 205 | }); |
| 206 | 206 | ||
| 207 | router.post('/find', jsonParser, (request, response) => { | 207 | router.post('/find', jsonParser, (request, response) => { |
| 208 | const allowKeysExposure = getConfigValue('allowKeysExposure', false); | 208 | const allowKeysExposure = getConfigValue('allowKeysExposure', false, 'boolean'); |
| 209 | const key = request.body.key; | 209 | const key = request.body.key; |
| 210 | 210 | ||
| 211 | if (!allowKeysExposure && !EXPORTABLE_KEYS.includes(key)) { | 211 | if (!allowKeysExposure && !EXPORTABLE_KEYS.includes(key)) { |
| @@ -11,9 +11,9 @@ import { jsonParser } from '../express-common.js'; | |||
| 11 | import { getAllUserHandles, getUserDirectories } from '../users.js'; | 11 | import { getAllUserHandles, getUserDirectories } from '../users.js'; |
| 12 | import { getFileNameValidationFunction } from '../middleware/validateFileName.js'; | 12 | import { getFileNameValidationFunction } from '../middleware/validateFileName.js'; |
| 13 | 13 | ||
| 14 | const ENABLE_EXTENSIONS = !!getConfigValue('extensions.enabled', true); | 14 | const ENABLE_EXTENSIONS = getConfigValue('extensions.enabled', true, 'boolean'); |
| 15 | const ENABLE_EXTENSIONS_AUTO_UPDATE = !!getConfigValue('extensions.autoUpdate', true); | 15 | const ENABLE_EXTENSIONS_AUTO_UPDATE = getConfigValue('extensions.autoUpdate', true, 'boolean'); |
| 16 | const ENABLE_ACCOUNTS = getConfigValue('enableUserAccounts', false); | 16 | const ENABLE_ACCOUNTS = getConfigValue('enableUserAccounts', false, 'boolean'); |
| 17 | 17 | ||
| 18 | // 10 minutes | 18 | // 10 minutes |
| 19 | const AUTOSAVE_INTERVAL = 10 * 60 * 1000; | 19 | const AUTOSAVE_INTERVAL = 10 * 60 * 1000; |
| @@ -12,8 +12,8 @@ import { getAllUserHandles, getUserDirectories } from '../users.js'; | |||
| 12 | import { getConfigValue } from '../util.js'; | 12 | import { getConfigValue } from '../util.js'; |
| 13 | import { jsonParser } from '../express-common.js'; | 13 | import { jsonParser } from '../express-common.js'; |
| 14 | 14 | ||
| 15 | const thumbnailsEnabled = !!getConfigValue('thumbnails.enabled', true); | 15 | const thumbnailsEnabled = !!getConfigValue('thumbnails.enabled', true, 'boolean'); |
| 16 | const quality = Math.min(100, Math.max(1, parseInt(getConfigValue('thumbnails.quality', 95)))); | 16 | const quality = Math.min(100, Math.max(1, parseInt(getConfigValue('thumbnails.quality', 95, 'number')))); |
| 17 | const pngFormat = String(getConfigValue('thumbnails.format', 'jpg')).toLowerCase().trim() === 'png'; | 17 | const pngFormat = String(getConfigValue('thumbnails.format', 'jpg')).toLowerCase().trim() === 'png'; |
| 18 | 18 | ||
| 19 | /** @type {Record<string, number[]>} */ | 19 | /** @type {Record<string, number[]>} */ |
| @@ -56,7 +56,7 @@ export const TEXT_COMPLETION_MODELS = [ | |||
| 56 | ]; | 56 | ]; |
| 57 | 57 | ||
| 58 | const CHARS_PER_TOKEN = 3.35; | 58 | const CHARS_PER_TOKEN = 3.35; |
| 59 | const IS_DOWNLOAD_ALLOWED = getConfigValue('enableDownloadableTokenizers', true); | 59 | const IS_DOWNLOAD_ALLOWED = getConfigValue('enableDownloadableTokenizers', true, 'boolean'); |
| 60 | 60 | ||
| 61 | /** | 61 | /** |
| 62 | * Gets a path to the tokenizer model. Downloads the model if it's a URL. | 62 | * Gets a path to the tokenizer model. Downloads the model if it's a URL. |
| @@ -7,7 +7,7 @@ import { jsonParser, getIpFromRequest } from '../express-common.js'; | |||
| 7 | import { color, Cache, getConfigValue } from '../util.js'; | 7 | import { color, Cache, getConfigValue } from '../util.js'; |
| 8 | import { KEY_PREFIX, getUserAvatar, toKey, getPasswordHash, getPasswordSalt } from '../users.js'; | 8 | import { KEY_PREFIX, getUserAvatar, toKey, getPasswordHash, getPasswordSalt } from '../users.js'; |
| 9 | 9 | ||
| 10 | const DISCREET_LOGIN = getConfigValue('enableDiscreetLogin', false); | 10 | const DISCREET_LOGIN = getConfigValue('enableDiscreetLogin', false, 'boolean'); |
| 11 | const MFA_CACHE = new Cache(5 * 60 * 1000); | 11 | const MFA_CACHE = new Cache(5 * 60 * 1000); |
| 12 | 12 | ||
| 13 | export const router = express.Router(); | 13 | export const router = express.Router(); |
| @@ -7,8 +7,8 @@ import storage from 'node-persist'; | |||
| 7 | import { getAllUserHandles, toKey, getPasswordHash } from '../users.js'; | 7 | import { getAllUserHandles, toKey, getPasswordHash } from '../users.js'; |
| 8 | import { getConfig, getConfigValue, safeReadFileSync } from '../util.js'; | 8 | import { getConfig, getConfigValue, safeReadFileSync } from '../util.js'; |
| 9 | 9 | ||
| 10 | const PER_USER_BASIC_AUTH = getConfigValue('perUserBasicAuth', false); | 10 | const PER_USER_BASIC_AUTH = getConfigValue('perUserBasicAuth', false, 'boolean'); |
| 11 | const ENABLE_ACCOUNTS = getConfigValue('enableUserAccounts', false); | 11 | const ENABLE_ACCOUNTS = getConfigValue('enableUserAccounts', false, 'boolean'); |
| 12 | 12 | ||
| 13 | const basicAuthMiddleware = async function (request, response, callback) { | 13 | const basicAuthMiddleware = async function (request, response, callback) { |
| 14 | const unauthorizedWebpage = safeReadFileSync('./public/error/unauthorized.html') ?? ''; | 14 | const unauthorizedWebpage = safeReadFileSync('./public/error/unauthorized.html') ?? ''; |
| @@ -8,7 +8,7 @@ import { getIpFromRequest } from '../express-common.js'; | |||
| 8 | import { color, getConfigValue, safeReadFileSync } from '../util.js'; | 8 | import { color, getConfigValue, safeReadFileSync } from '../util.js'; |
| 9 | 9 | ||
| 10 | const whitelistPath = path.join(process.cwd(), './whitelist.txt'); | 10 | const whitelistPath = path.join(process.cwd(), './whitelist.txt'); |
| 11 | const enableForwardedWhitelist = getConfigValue('enableForwardedWhitelist', false); | 11 | const enableForwardedWhitelist = getConfigValue('enableForwardedWhitelist', false, 'boolean'); |
| 12 | let whitelist = getConfigValue('whitelist', []); | 12 | let whitelist = getConfigValue('whitelist', []); |
| 13 | let knownIPs = new Set(); | 13 | let knownIPs = new Set(); |
| 14 | 14 | ||
| @@ -7,8 +7,8 @@ import { default as git } from 'simple-git'; | |||
| 7 | import { sync as commandExistsSync } from 'command-exists'; | 7 | import { sync as commandExistsSync } from 'command-exists'; |
| 8 | import { getConfigValue, color } from './util.js'; | 8 | import { getConfigValue, color } from './util.js'; |
| 9 | 9 | ||
| 10 | const enableServerPlugins = !!getConfigValue('enableServerPlugins', false); | 10 | const enableServerPlugins = getConfigValue('enableServerPlugins', false, 'boolean'); |
| 11 | const enableServerPluginsAutoUpdate = !!getConfigValue('enableServerPluginsAutoUpdate', true); | 11 | const enableServerPluginsAutoUpdate = getConfigValue('enableServerPluginsAutoUpdate', true, 'boolean'); |
| 12 | 12 | ||
| 13 | /** | 13 | /** |
| 14 | * Map of loaded plugins. | 14 | * Map of loaded plugins. |
| @@ -572,7 +572,7 @@ export function convertMistralMessages(messages, names) { | |||
| 572 | } | 572 | } |
| 573 | 573 | ||
| 574 | // Make the last assistant message a prefill | 574 | // Make the last assistant message a prefill |
| 575 | const prefixEnabled = getConfigValue('mistral.enablePrefix', false); | 575 | const prefixEnabled = getConfigValue('mistral.enablePrefix', false, 'boolean'); |
| 576 | const lastMsg = messages[messages.length - 1]; | 576 | const lastMsg = messages[messages.length - 1]; |
| 577 | if (prefixEnabled && messages.length > 0 && lastMsg?.role === 'assistant') { | 577 | if (prefixEnabled && messages.length > 0 && lastMsg?.role === 'assistant') { |
| 578 | lastMsg.prefix = true; | 578 | lastMsg.prefix = true; |
| @@ -132,7 +132,7 @@ export async function getPipeline(task, forceModel = '') { | |||
| 132 | 132 | ||
| 133 | const cacheDir = path.join(globalThis.DATA_ROOT, '_cache'); | 133 | const cacheDir = path.join(globalThis.DATA_ROOT, '_cache'); |
| 134 | const model = forceModel || getModelForTask(task); | 134 | const model = forceModel || getModelForTask(task); |
| 135 | const localOnly = !getConfigValue('extensions.models.autoDownload', true); | 135 | const localOnly = !getConfigValue('extensions.models.autoDownload', true, 'boolean'); |
| 136 | console.log('Initializing transformers.js pipeline for task', task, 'with model', model); | 136 | console.log('Initializing transformers.js pipeline for task', task, 'with model', model); |
| 137 | const instance = await pipeline(task, model, { cache_dir: cacheDir, quantized: tasks[task].quantized ?? true, local_files_only: localOnly }); | 137 | const instance = await pipeline(task, model, { cache_dir: cacheDir, quantized: tasks[task].quantized ?? true, local_files_only: localOnly }); |
| 138 | tasks[task].pipeline = instance; | 138 | tasks[task].pipeline = instance; |
| @@ -21,9 +21,9 @@ import { getContentOfType } from './endpoints/content-manager.js'; | |||
| 21 | 21 | ||
| 22 | export const KEY_PREFIX = 'user:'; | 22 | export const KEY_PREFIX = 'user:'; |
| 23 | const AVATAR_PREFIX = 'avatar:'; | 23 | const AVATAR_PREFIX = 'avatar:'; |
| 24 | const ENABLE_ACCOUNTS = getConfigValue('enableUserAccounts', false); | 24 | const ENABLE_ACCOUNTS = getConfigValue('enableUserAccounts', false, 'boolean'); |
| 25 | const AUTHELIA_AUTH = getConfigValue('autheliaAuth', false); | 25 | const AUTHELIA_AUTH = getConfigValue('autheliaAuth', false, 'boolean'); |
| 26 | const PER_USER_BASIC_AUTH = getConfigValue('perUserBasicAuth', false); | 26 | const PER_USER_BASIC_AUTH = getConfigValue('perUserBasicAuth', false, 'boolean'); |
| 27 | const ANON_CSRF_SECRET = crypto.randomBytes(64).toString('base64'); | 27 | const ANON_CSRF_SECRET = crypto.randomBytes(64).toString('base64'); |
| 28 | 28 | ||
| 29 | /** | 29 | /** |
| @@ -54,19 +54,33 @@ export function getConfig() { | |||
| 54 | } | 54 | } |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | |||
| 57 | /** | 58 | /** |
| 58 | * Returns the value for the given key from the config object. | 59 | * Returns the value for the given key from the config object. |
| 59 | * @param {string} key - Key to get from the config object | 60 | * @param {string} key - Key to get from the config object |
| 60 | * @param {any} defaultValue - Default value to return if the key is not found | 61 | * @param {any} defaultValue - Default value to return if the key is not found |
| 62 | * @param {'number'|'boolean'|null} typeConverter - Type to convert the value to | ||
| 61 | * @returns {any} Value for the given key | 63 | * @returns {any} Value for the given key |
| 62 | */ | 64 | */ |
| 63 | export function getConfigValue(key, defaultValue = null) { | 65 | export function getConfigValue(key, defaultValue = null, typeConverter = null) { |
| 64 | const envKey = keyToEnv(key); | 66 | function _getValue() { |
| 65 | if (envKey in process.env) { | 67 | const envKey = keyToEnv(key); |
| 66 | return process.env[envKey]; | 68 | if (envKey in process.env) { |
| 69 | return process.env[envKey]; | ||
| 70 | } | ||
| 71 | const config = getConfig(); | ||
| 72 | return _.get(config, key, defaultValue); | ||
| 73 | } | ||
| 74 | |||
| 75 | const value = _getValue(); | ||
| 76 | switch (typeConverter) { | ||
| 77 | case 'number': | ||
| 78 | return Number(value); | ||
| 79 | case 'boolean': | ||
| 80 | return toBoolean(value); | ||
| 81 | default: | ||
| 82 | return value; | ||
| 67 | } | 83 | } |
| 68 | const config = getConfig(); | ||
| 69 | return _.get(config, key, defaultValue); | ||
| 70 | } | 84 | } |
| 71 | 85 | ||
| 72 | /** | 86 | /** |
| @@ -392,7 +406,7 @@ export function generateTimestamp() { | |||
| 392 | * @param {number?} limit Maximum number of backups to keep. If null, the limit is determined by the `backups.common.numberOfBackups` config value. | 406 | * @param {number?} limit Maximum number of backups to keep. If null, the limit is determined by the `backups.common.numberOfBackups` config value. |
| 393 | */ | 407 | */ |
| 394 | export function removeOldBackups(directory, prefix, limit = null) { | 408 | export function removeOldBackups(directory, prefix, limit = null) { |
| 395 | const MAX_BACKUPS = limit ?? Number(getConfigValue('backups.common.numberOfBackups', 50)); | 409 | const MAX_BACKUPS = limit ?? Number(getConfigValue('backups.common.numberOfBackups', 50, 'number')); |
| 396 | 410 | ||
| 397 | let files = fs.readdirSync(directory).filter(f => f.startsWith(prefix)); | 411 | let files = fs.readdirSync(directory).filter(f => f.startsWith(prefix)); |
| 398 | if (files.length > MAX_BACKUPS) { | 412 | if (files.length > MAX_BACKUPS) { |
| @@ -745,6 +759,27 @@ export async function canResolve(name, useIPv6 = true, useIPv4 = true) { | |||
| 745 | } | 759 | } |
| 746 | } | 760 | } |
| 747 | 761 | ||
| 762 | /** | ||
| 763 | * Converts various JavaScript primitives to boolean values. | ||
| 764 | * Handles special case for "true"/"false" strings (case-insensitive) | ||
| 765 | * | ||
| 766 | * @param {any} value - The value to convert to boolean | ||
| 767 | * @returns {boolean} - The boolean representation of the value | ||
| 768 | */ | ||
| 769 | export function toBoolean(value) { | ||
| 770 | // Handle string values case-insensitively | ||
| 771 | if (typeof value === 'string') { | ||
| 772 | // Trim and convert to lowercase for case-insensitive comparison | ||
| 773 | const trimmedLower = value.trim().toLowerCase(); | ||
| 774 | |||
| 775 | // Handle explicit "true"/"false" strings | ||
| 776 | if (trimmedLower === 'true') return true; | ||
| 777 | if (trimmedLower === 'false') return false; | ||
| 778 | } | ||
| 779 | |||
| 780 | // Handle all other JavaScript values based on their "truthiness" | ||
| 781 | return Boolean(value); | ||
| 782 | } | ||
| 748 | 783 | ||
| 749 | /** | 784 | /** |
| 750 | * converts string to boolean accepts 'true' or 'false' else it returns the string put in | 785 | * converts string to boolean accepts 'true' or 'false' else it returns the string put in |
| @@ -761,7 +796,7 @@ export function stringToBool(str) { | |||
| 761 | * Setup the minimum log level | 796 | * Setup the minimum log level |
| 762 | */ | 797 | */ |
| 763 | export function setupLogLevel() { | 798 | export function setupLogLevel() { |
| 764 | const logLevel = getConfigValue('minLogLevel', LOG_LEVELS.DEBUG); | 799 | const logLevel = getConfigValue('minLogLevel', LOG_LEVELS.DEBUG, 'number'); |
| 765 | 800 | ||
| 766 | globalThis.console.debug = logLevel <= LOG_LEVELS.DEBUG ? console.debug : () => {}; | 801 | globalThis.console.debug = logLevel <= LOG_LEVELS.DEBUG ? console.debug : () => {}; |
| 767 | globalThis.console.info = logLevel <= LOG_LEVELS.INFO ? console.info : () => {}; | 802 | globalThis.console.info = logLevel <= LOG_LEVELS.INFO ? console.info : () => {}; |