Allow extensions to specify minimum ST client version (#4350) * allow extensions to specify minimum client version * using existing version compare function * Move versionCompare to utils module --------- Co-authored-by: qvink <qvink@users.noreply.github.com> Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

5865a1a85b0fa51230e50e6cb49cab61c8458e7d

qvink <191186569+qvink@users.noreply.github.com>

Signed
3 files changed, +24 -14Showing whitespace changes
public/scripts/extensions.js+13 -3
@@ -1,10 +1,10 @@
1import { DOMPurify, Popper } from '../lib.js';1import { DOMPurify, Popper } from '../lib.js';
22
3import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js';3import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration, CLIENT_VERSION } from '../script.js';
4import { showLoader } from './loader.js';4import { showLoader } from './loader.js';
5import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';5import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
6import { renderTemplate, renderTemplateAsync } from './templates.js';6import { renderTemplate, renderTemplateAsync } from './templates.js';
7import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js';7import { delay, isSubsetOf, sanitizeSelector, setValueByPath, versionCompare } from './utils.js';
8import { getContext } from './st-context.js';8import { getContext } from './st-context.js';
9import { isAdmin } from './user.js';9import { isAdmin } from './user.js';
10import { addLocaleData, getCurrentLocale, t } from './i18n.js';10import { addLocaleData, getCurrentLocale, t } from './i18n.js';
@@ -387,6 +387,7 @@ async function getManifests(names) {
387 */387 */
388async function activateExtensions() {388async function activateExtensions() {
389 extensionLoadErrors.clear();389 extensionLoadErrors.clear();
390 const clientVersion = CLIENT_VERSION.split(':')[1];
390 const extensions = Object.entries(manifests).sort((a, b) => sortManifestsByOrder(a[1], b[1]));391 const extensions = Object.entries(manifests).sort((a, b) => sortManifestsByOrder(a[1], b[1]));
391 const extensionNames = extensions.map(x => x[0]);392 const extensionNames = extensions.map(x => x[0]);
392 const promises = [];393 const promises = [];
@@ -396,11 +397,17 @@ async function activateExtensions() {
396 const manifest = entry[1];397 const manifest = entry[1];
397 const extrasRequirements = manifest.requires;398 const extrasRequirements = manifest.requires;
398 const extensionDependencies = manifest.dependencies;399 const extensionDependencies = manifest.dependencies;
400 const minClientVersion = manifest.minimum_client_version;
399 const displayName = manifest.display_name || name;401 const displayName = manifest.display_name || name;
400402
401 if (activeExtensions.has(name)) {403 if (activeExtensions.has(name)) {
402 continue;404 continue;
403 }405 }
406 // Client version requirement: pass if 'minimum_client_version' is undefined or null.
407 let meetsClientMinimumVersion = true;
408 if (minClientVersion !== undefined) {
409 meetsClientMinimumVersion = versionCompare(clientVersion, minClientVersion);
410 }
404411
405 // Module requirements: pass if 'requires' is undefined, null, or not an array; check subset if it's an array412 // Module requirements: pass if 'requires' is undefined, null, or not an array; check subset if it's an array
406 let meetsModuleRequirements = true;413 let meetsModuleRequirements = true;
@@ -438,7 +445,7 @@ async function activateExtensions() {
438445
439 const isDisabled = extension_settings.disabledExtensions.includes(name);446 const isDisabled = extension_settings.disabledExtensions.includes(name);
440447
441 if (meetsModuleRequirements && meetsExtensionDeps && !isDisabled) {448 if (meetsModuleRequirements && meetsExtensionDeps && meetsClientMinimumVersion && !isDisabled) {
442 try {449 try {
443 console.debug('Activating extension', name);450 console.debug('Activating extension', name);
444 const promise = addExtensionLocale(name, manifest).finally(() =>451 const promise = addExtensionLocale(name, manifest).finally(() =>
@@ -465,6 +472,9 @@ async function activateExtensions() {
465 console.warn(t`Extension "${name}" did not load. Missing required extensions: "${missingDependencies.join(', ')}"`);472 console.warn(t`Extension "${name}" did not load. Missing required extensions: "${missingDependencies.join(', ')}"`);
466 extensionLoadErrors.add(t`Extension "${displayName}" did not load. Missing required extensions: "${missingDependencies.join(', ')}"`);473 extensionLoadErrors.add(t`Extension "${displayName}" did not load. Missing required extensions: "${missingDependencies.join(', ')}"`);
467 }474 }
475 } else if (!meetsClientMinimumVersion && !isDisabled) {
476 console.warn(t`Extension "${name}" did not load. Requires ST client version ${minClientVersion}, but current version is ${clientVersion}.`);
477 extensionLoadErrors.add(t`Extension "${displayName}" did not load. Requires ST client version ${minClientVersion}, but current version is ${clientVersion}.`);
468 }478 }
469 }479 }
470480
public/scripts/kai-settings.js+1 -11
@@ -20,7 +20,7 @@ import {
20 power_user,20 power_user,
21} from './power-user.js';21} from './power-user.js';
22import { getEventSourceStream } from './sse-stream.js';22import { getEventSourceStream } from './sse-stream.js';
23import { getSortableDelay } from './utils.js';23import { getSortableDelay, versionCompare } from './utils.js';
2424
25export let koboldai_settings;25export let koboldai_settings;
26export let koboldai_setting_names;26export let koboldai_setting_names;
@@ -389,16 +389,6 @@ export function setKoboldFlags(koboldUnitedVersion, koboldCppVersion) {
389}389}
390390
391/**391/**
392 * Compares two version numbers, returning true if srcVersion >= minVersion
393 * @param {string} srcVersion The current version.
394 * @param {string} minVersion The target version number to test against
395 * @returns {boolean} True if srcVersion >= minVersion, false if not
396 */
397function versionCompare(srcVersion, minVersion) {
398 return (srcVersion || '0.0.0').localeCompare(minVersion, undefined, { numeric: true, sensitivity: 'base' }) > -1;
399}
400
401/**
402 * Sorts the sampler items by the given order.392 * Sorts the sampler items by the given order.
403 * @param {any[]} orderArray Sampler order array.393 * @param {any[]} orderArray Sampler order array.
404 */394 */
public/scripts/utils.js+10 -0
@@ -2550,3 +2550,13 @@ export function textValueMatcher(params, data) {
2550 // If it doesn't contain the term, don't return anything2550 // If it doesn't contain the term, don't return anything
2551 return null;2551 return null;
2552}2552}
2553
2554/**
2555 * Compares two version numbers, returning true if srcVersion >= minVersion
2556 * @param {string} srcVersion The current version.
2557 * @param {string} minVersion The target version number to test against
2558 * @returns {boolean} True if srcVersion >= minVersion, false if not
2559 */
2560export function versionCompare(srcVersion, minVersion) {
2561 return (srcVersion || '0.0.0').localeCompare(minVersion, undefined, { numeric: true, sensitivity: 'base' }) > -1;
2562}