snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 01:21:02 +05:00
commit 30810eecd7
10161 changed files with 987110 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
import type { ISetting, SettingValue } from '@rocket.chat/core-typings';
export const convertValue = (value: 'true' | 'false' | string, type: ISetting['type']): SettingValue => {
if (value.toLowerCase() === 'true') {
return true;
}
if (value.toLowerCase() === 'false') {
return false;
}
if (type === 'int') {
return parseInt(value);
}
if (type === 'multiSelect') {
return JSON.parse(value);
}
return value;
};

View File

@@ -0,0 +1,46 @@
import type { ISetting, ISettingColor } from '@rocket.chat/core-typings';
import { isSettingColor, isSettingRange } from '@rocket.chat/core-typings';
export const getSettingDefaults = (
setting: Partial<ISetting> & Pick<ISetting, '_id' | 'value' | 'type'>,
blockedSettings: Set<string> = new Set(),
hiddenSettings: Set<string> = new Set(),
wizardRequiredSettings: Set<string> = new Set(),
): ISetting => {
const { _id, value, sorter, ...data } = setting;
const options = Object.fromEntries(Object.entries(data).filter(([, value]) => value !== undefined)) as Partial<typeof data>;
return {
_id,
value,
packageValue: value,
valueSource: 'packageValue',
secret: false,
enterprise: false,
i18nDescription: `${_id}_Description`,
autocomplete: true,
sorter: sorter || 0,
ts: new Date(),
createdAt: new Date(),
_updatedAt: options._updatedAt ?? new Date(),
...options,
...(options.enableQuery ? { enableQuery: JSON.stringify(options.enableQuery) } : undefined),
...(options.validation ? { validation: JSON.stringify(options.validation) } : undefined),
i18nLabel: options.i18nLabel || _id,
hidden: options.hidden || hiddenSettings.has(_id),
blocked: options.blocked || blockedSettings.has(_id),
requiredOnWizard: options.requiredOnWizard || wizardRequiredSettings.has(_id),
type: options.type || 'string',
env: options.env || false,
public: options.public || false,
...(options.displayQuery ? { displayQuery: JSON.stringify(options.displayQuery) } : undefined),
...(isSettingColor(setting as ISetting) && {
packageEditor: (setting as ISettingColor).editor,
}),
...(isSettingRange(setting as ISetting) && {
minValue: 0,
maxValue: 100,
}),
};
};

View File

@@ -0,0 +1,57 @@
import type { ISetting, SettingValueMultiSelect, SettingValueRoomPick } from '@rocket.chat/core-typings';
import { convertValue } from './convertValue';
const compareSettingsValue = (a: ISetting['value'], b: ISetting['value'], type?: ISetting['type']): boolean => {
if (Array.isArray(a) && Array.isArray(b)) {
if (type === 'multiSelect') {
a = a as SettingValueMultiSelect;
b = b as SettingValueMultiSelect;
return a.length === b.length && a.every((value, index) => compareSettingsValue(value, (b as SettingValueMultiSelect)[index]));
}
if (type === 'roomPick') {
a = a as SettingValueRoomPick;
b = b as SettingValueRoomPick;
return (
a.length === b.length &&
a.every((value, index) => {
return Object.keys(value).every((key) =>
compareSettingsValue(
value[key as keyof typeof value],
(b as SettingValueRoomPick)[index as keyof typeof b][key as keyof typeof b],
),
);
})
);
}
}
return a === b;
};
export const overrideGenerator =
(fn: (key: string) => string | undefined) =>
(setting: ISetting): ISetting => {
const overwriteValue = fn(setting._id);
if (overwriteValue === null || overwriteValue === undefined) {
return setting;
}
try {
const value = convertValue(overwriteValue, setting.type);
if (compareSettingsValue(value, setting.value, setting.type) && compareSettingsValue(value, setting.processEnvValue, setting.type)) {
return setting;
}
return {
...setting,
value,
processEnvValue: value,
valueSource: 'processEnvValue',
};
} catch (error) {
console.error(`Error converting value for setting ${setting._id} expected "${setting.type}" type`);
return setting;
}
};

View File

@@ -0,0 +1,3 @@
import { overrideGenerator } from './overrideGenerator';
export const overrideSetting = overrideGenerator((key: string) => process.env[key]);

View File

@@ -0,0 +1,3 @@
import { overrideGenerator } from './overrideGenerator';
export const overwriteSetting = overrideGenerator((key: string) => process.env[`OVERWRITE_SETTING_${key}`]);

View File

@@ -0,0 +1,10 @@
import type { ISetting } from '@rocket.chat/core-typings';
import { ajv } from '@rocket.chat/rest-typings';
const schemas = new Map<ISetting['_id'], ReturnType<typeof ajv.compile>>();
export const registerSettingSchema = (_id: ISetting['_id'], schema: Record<string, unknown>): void => {
schemas.set(_id, ajv.compile(schema));
};
export const getSettingSchemaValidator = (_id: ISetting['_id']): ReturnType<typeof ajv.compile> | undefined => schemas.get(_id);

View File

@@ -0,0 +1,112 @@
import type { ISetting } from '@rocket.chat/core-typings';
import type { ICachedSettings } from '../CachedSettings';
type Dictionary = {
[index: string]: any;
};
class SettingsClass {
settings: ICachedSettings;
private delay = 0;
setDelay(delay: number): void {
this.delay = delay;
}
find(): any[] {
return [];
}
public data = new Map<string, Dictionary>();
public upsertCalls = 0;
public insertCalls = 0;
private checkQueryMatch(key: string, data: Dictionary, queryValue: any): boolean {
if (typeof queryValue === 'object') {
if (queryValue.$exists !== undefined) {
return (data.hasOwnProperty(key) && data[key] !== undefined) === queryValue.$exists;
}
}
return queryValue === data[key];
}
findOne(query: Dictionary): any {
return [...this.data.values()].find((data) => Object.entries(query).every(([key, value]) => this.checkQueryMatch(key, data, value)));
}
insertOne(doc: any): void {
this.data.set(doc._id, doc);
this.settings.set(doc);
this.insertCalls++;
}
updateOne(query: any, update: any, options?: any): void {
const existent = this.findOne(query);
const data = { ...existent, ...query, ...update, ...update.$set };
if (!existent) {
Object.assign(data, update.$setOnInsert);
}
if (update.$unset) {
Object.keys(update.$unset).forEach((key) => {
delete data[key];
});
}
const modifiers = ['$set', '$setOnInsert', '$unset'];
modifiers.forEach((key) => {
delete data[key];
});
if (options?.upsert === true && !modifiers.some((key) => Object.keys(update).includes(key))) {
throw new Error('Invalid upsert');
}
if (this.delay) {
setTimeout(() => {
// console.log(query, data);
this.data.set(query._id, data);
// Can't import before the mock command on end of this file!
this.settings.set(data);
}, this.delay);
} else {
this.data.set(query._id, data);
// Can't import before the mock command on end of this file!
this.settings.set(data);
}
this.upsertCalls++;
}
findOneAndUpdate({ _id }: { _id: string }, value: any, options?: any) {
this.updateOne({ _id }, value, options);
return { value: this.findOne({ _id }) };
}
updateValueById(id: string, value: any): void {
this.data.set(id, { ...this.data.get(id), value });
// Can't import before the mock command on end of this file!
if (this.delay) {
setTimeout(() => {
this.settings.set(this.data.get(id) as ISetting);
}, this.delay);
} else {
this.settings.set(this.data.get(id) as ISetting);
}
}
}
export const Settings = new SettingsClass();

View File

@@ -0,0 +1,59 @@
import { isActionSettingWithEndpoint, type ISetting } from '@rocket.chat/core-typings';
export const validateSetting = <T extends ISetting>(_id: T['_id'], type: T['type'], value: T['value'] | unknown): boolean => {
switch (type) {
case 'asset':
if (typeof value !== 'object') {
throw new Error(`Setting ${_id} is of type ${type} but got ${typeof value}`);
}
break;
case 'action':
if (typeof value !== 'string' && !isActionSettingWithEndpoint(value as never)) {
throw new Error(`Setting ${_id} is of type ${type} but got ${typeof value}`);
}
break;
case 'string':
case 'relativeUrl':
case 'password':
case 'language':
case 'color':
case 'font':
case 'code':
case 'roomPick':
case 'group':
if (typeof value !== 'string') {
throw new Error(`Setting ${_id} is of type ${type} but got ${typeof value}`);
}
break;
case 'boolean':
if (typeof value !== 'boolean') {
throw new Error(`Setting ${_id} is of type boolean but got ${typeof value}`);
}
break;
case 'int':
if (typeof value !== 'number') {
throw new Error(`Setting ${_id} is of type int but got ${typeof value}`);
}
break;
case 'multiSelect':
if (!Array.isArray(value)) {
throw new Error(`Setting ${_id} is of type array but got ${typeof value}`);
}
break;
case 'select':
case 'lookup':
if (typeof value !== 'string' && typeof value !== 'number') {
throw new Error(`Setting ${_id} is of type ${type} but got ${typeof value}`);
}
break;
case 'date':
if (!(value instanceof Date)) {
throw new Error(`Setting ${_id} is of type date but got ${typeof value}`);
}
break;
default:
return true;
}
return true;
};

View File

@@ -0,0 +1,14 @@
import type { ISetting, SettingValidationRule } from '@rocket.chat/core-typings';
export const positiveOrDisabled = (): SettingValidationRule => ({
query: { $or: [{ value: -1 }, { value: { $gte: 1 } }] },
});
export const notGreaterThanSetting = (otherId: ISetting['_id']): SettingValidationRule => ({
query: { $or: [{ value: { $lt: 1 } }, { value: { $lte: { $setting: otherId } } }] },
appliesWhen: { _id: otherId, value: { $gte: 1 } },
});
export const notLowerThanSetting = (otherId: ISetting['_id']): SettingValidationRule => ({
query: { $or: [{ value: { $lt: 1 } }, { value: { $gte: { $setting: otherId } } }] },
});