Bump dependencies

This commit is contained in:
Alexander Zinchuk 2025-06-04 20:36:48 +02:00
parent daea14f37c
commit f38f7d65cc
884 changed files with 19367 additions and 23494 deletions

View File

@ -1,22 +0,0 @@
src/lib/rlottie/rlottie-wasm.js
src/lib/video-preview/polyfill
src/lib/fasttextweb/fasttext-wasm.js
src/lib/gramjs/tl/types-generator/template.ts
src/lib/gramjs/tl/api.d.ts
src/lib/gramjs/tl/apiTl.ts
src/lib/gramjs/tl/schemaTl.ts
src/lib/lovely-chart
src/lib/music-metadata-browser
jest.config.js
src/lib/secret-sauce/
playwright.config.ts
dist
dist-electron
public
deploy/update_version.js

212
.eslintrc
View File

@ -1,212 +0,0 @@
{
"extends": [
"teact-app",
"airbnb",
"airbnb-typescript"
],
"plugins": [
"no-async-without-await",
"no-null",
"simple-import-sort",
"react-hooks-static-deps",
"eslint-multitab-tt"
],
"rules": {
"eslint-multitab-tt/no-immediate-global": "error",
"eslint-multitab-tt/must-update-global-after-await": "off",
"eslint-multitab-tt/set-global-only-variable": "error",
"eslint-multitab-tt/no-getactions-in-actions": "error",
"eslint-multitab-tt/must-specify-action-handler-return-type": "error",
"indent": [
"error",
2,
{
"SwitchCase": 1
}
],
"max-len": [
"error",
{
"code": 120,
"ignoreComments": true,
"ignorePattern": "\\sd=\".+\"" // Ignore lines with "d" attribute
}
],
"array-bracket-newline": [
2,
"consistent"
],
"no-null/no-null": 2,
"no-console": "error",
"semi": "error",
"no-implicit-coercion": "error",
"react-hooks/exhaustive-deps": "off",
"react-hooks-static-deps/exhaustive-deps": [
"error",
{
"additionalHooks": "(useSyncEffect|useAsync|useDebouncedCallback|useThrottledCallback|useEffectWithPrevDeps|useLayoutEffectWithPrevDeps|useDerivedState|useDerivedSignal|useThrottledResolver|useDebouncedResolver|useThrottleForHeavyAnimation)$",
"staticHooks": {
"getActions": true,
"useFlag": [false, true, true],
"useForceUpdate": true,
"useReducer": [false, true],
"useLastCallback": true
}
}
],
"arrow-body-style": "off",
"no-else-return": "off",
"no-plusplus": "off",
"no-void": "off",
"no-continue": "off",
"default-case": "off",
"no-param-reassign": "off",
"no-prototype-builtins": "off",
"no-await-in-loop": "off",
"no-nested-ternary": "off",
"function-paren-newline": [
"error",
"consistent"
],
"prefer-destructuring": "off",
// Allow for...of. Edited from:
// https://github.com/airbnb/javascript/blob/b4377fb03089dd7f08955242695860d47f9caab4/packages/eslint-config-airbnb-base/rules/style.js#L333
"no-restricted-syntax": [
"error",
{
"selector": "ForInStatement",
"message": "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array."
},
{
"selector": "LabeledStatement",
"message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand."
},
{
"selector": "WithStatement",
"message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
}
],
"import/no-extraneous-dependencies": "off",
"import/prefer-default-export": "off",
"import/named": "off",
"import/no-webpack-loader-syntax": "off",
"import/no-cycle": [
"error",
{
"allowUnsafeDynamicCyclicDependency": true // TODO: Fix this
}
],
"react/prop-types": "off",
"react/jsx-one-expression-per-line": "off",
"react/button-has-type": "off",
"react/require-default-props": "off",
"react/function-component-definition": "off",
// Teact feature
"react/style-prop-object": "off",
"react/no-unknown-property": "off",
"react/jsx-no-bind": [
"error",
{
"ignoreRefs": true,
"allowArrowFunctions": false,
"allowFunctions": false,
"allowBind": false,
"ignoreDOMComponents": true
}
],
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/mouse-events-have-key-events": "off",
"jsx-a11y/no-static-element-interactions": "off",
"jsx-a11y/label-has-associated-control": "off",
"jsx-a11y/anchor-is-valid": "off",
"jsx-a11y/no-noninteractive-element-to-interactive-role": "off",
"jsx-a11y/media-has-caption": "off",
"no-async-without-await/no-async-without-await": 1,
"@typescript-eslint/no-use-before-define": [
"error",
{
"functions": false
}
],
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/member-delimiter-style": "error",
"@typescript-eslint/default-param-last": "off",
"@typescript-eslint/return-await": [
"error",
"in-try-catch"
],
"@typescript-eslint/consistent-type-imports": [
"error",
{
"prefer": "type-imports",
"disallowTypeAnnotations": false
}
],
"simple-import-sort/imports": [
"error",
{
"groups": [
// Side effect imports
["^\\u0000"],
// Lib and global imports
[
"^react",
"^@?\\w",
"dist(/.*|$)",
"^(\\.+/)+(lib/(teact|gramjs))(/.*|$)",
"^(\\.+/)+global$"
],
// Type imports
[
"^(\\.+/)+.+\\u0000$",
"^(\\.+/|\\w+/)+(types)(/.*|$)",
"^(\\.+/|\\w+/)+(types)\\u0000"
],
// Config, utils, helpers
[
"^(\\.+/)+config",
"^(\\.+/)+(lib)(?!/(gramjs|teact))(/.*|$)",
"^(\\.+/)+global/.+",
"^(\\.+/)+(util)(/.*|$)",
"^\\.\\.(?!/?$)",
"^\\.\\./?$",
"^\\./(?=.*/)(?!/?$)",
"^\\.(?!/?$)",
"^\\./?$"
],
// Hooks
[
".+(/hooks/)(.*|$)"
],
// Components
[
"\/[A-Z](([a-z]+[A-Z]?)*)"
],
// Styles and CSS modules
[
"^.+\\.s?css$"
],
// Assets: images, stickers, etc
[
"^(\\.+/)+(assets)(/.*|$)"
]
]
}
]
},
"settings": {
"import/resolver": {
"webpack": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
},
"import/core-modules": [
"fs",
"path",
"crypto"
]
},
"parserOptions": {
"project": "./tsconfig.json"
}
}

View File

@ -1,4 +1,4 @@
module.exports = {
export default {
inputDir: './src/assets/font-icons',
outputDir: './src/styles',
name: 'icons',
@ -7,7 +7,7 @@ module.exports = {
tag: '',
// Use a custom Handlebars template
templates: {
scss: './dev/icons.scss.hbs'
scss: './dev/icons.scss.hbs',
},
formatOptions: {
ts: {

View File

@ -11,7 +11,8 @@ name: Package and publish
on:
workflow_dispatch:
push:
branches: master
branches:
- master
env:
APP_NAME: Telegram A
@ -67,6 +68,7 @@ jobs:
TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}

1
.node-version Normal file
View File

@ -0,0 +1 @@
24

1
.npmrc Normal file
View File

@ -0,0 +1 @@
node-options="--no-experimental-strip-types"

View File

@ -13,7 +13,7 @@
"stylelint-high-performance-animation",
"stylelint-group-selectors",
"stylelint-selector-tag-no-without-class",
"./dev/wholePixel.js"
"./dev/wholePixel.mjs"
],
"rules": {
"property-no-unknown": [

View File

@ -1,22 +1,21 @@
const isTest = process.env.APP_ENV === 'test';
const isMocked = Boolean(process.env.APP_MOCKED_CLIENT);
export default function (api) {
api.cache(true);
module.exports = {
presets: [
[
const isTest = process.env.APP_ENV === 'test';
const isMocked = Boolean(process.env.APP_MOCKED_CLIENT);
const presets = [
'@babel/typescript',
],
[
'@babel/preset-env',
],
[
'@babel/preset-react',
],
],
plugins: [
'@babel/plugin-transform-class-properties',
'@babel/plugin-syntax-nullish-coalescing-operator',
'@babel/plugin-transform-logical-assignment-operators',
];
const plugins = [
...(isTest && !isMocked ? ['babel-plugin-transform-import-meta'] : []),
],
};
];
return {
presets,
plugins,
};
}

View File

@ -1,6 +1,4 @@
/* eslint-env node */
module.exports = async ({ github, context, body }) => {
export default async ({ github, context, body }) => {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,

View File

@ -1,11 +1,10 @@
/* eslint-env node */
import { readFileSync } from 'fs';
const fs = require('fs');
const createPRComment = require('./createPRComment');
const template = require('../.github/workflows/statoscope-comment');
import template from '../.github/workflows/statoscope-comment.js';
import createPRComment from './createPRComment.js';
module.exports = async ({ github, context }) => {
const data = JSON.parse(fs.readFileSync('result.json', 'utf8'));
export default async ({ github, context }) => {
const data = JSON.parse(readFileSync('result.json', 'utf8'));
data.prNumber = context.issue.number;
const body = template(data);

View File

@ -1,19 +0,0 @@
"use strict";
module.exports = {
root: true,
extends: [
"eslint:recommended",
"plugin:eslint-plugin/recommended",
"plugin:node/recommended",
],
env: {
node: true,
},
overrides: [
{
files: ["tests/**/*.js"],
env: { mocha: true },
},
],
};

View File

@ -1,22 +0,0 @@
/**
* @fileoverview eslint-multitab-tt
* @author undrfined
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const requireIndex = require("requireindex");
//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------
// import all rules in lib/rules
module.exports.rules = requireIndex(__dirname + "/rules");

View File

@ -1,39 +0,0 @@
/**
* @fileoverview Must specify action handler return type
* @author undrfined
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description: "Must specify action handler return type",
recommended: false,
url: null,
},
fixable: null,
schema: [],
messages: {
mustSpecifyActionHandlerReturnType: "Must specify action handler return type",
}
},
create(context) {
return {
ArrowFunctionExpression: (node) => {
if(node.parent.type === "CallExpression" && node.parent.callee.name === 'addActionHandler' && !node.returnType) {
context.report({
node,
messageId: "mustSpecifyActionHandlerReturnType",
})
}
}
};
},
};

View File

@ -1,108 +0,0 @@
/**
* @fileoverview Must update global after await
* @author undrfined
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
// TODO This rule is not working properly
module.exports = {
meta: {
type: "problem",
docs: {
description: "Must update global after await",
recommended: false,
url: null,
},
fixable: null,
schema: [],
messages: {
mustUpdateGlobalAfterAwait: "Global is outdated because of await here -> {{before}}, use global = getGlobal() to update",
}
},
create(context) {
let hasAssignmentOnBlockLevel;
let blocks = 0;
let d;
let hasAwait = false;
let hasAwaitOnBlockLevel;
let assigned;
//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
function endFunction() {
hasAwait = false;
assigned = undefined;
d = undefined;
hasAssignmentOnBlockLevel = undefined;
hasAwaitOnBlockLevel = undefined;
}
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return {
'FunctionDeclaration:exit': endFunction,
'FunctionExpression:exit': endFunction,
'ArrowFunctionExpression:exit': endFunction,
'AwaitExpression:exit': (node) => {
if(!node) return;
hasAwait = true;
hasAwaitOnBlockLevel = blocks;
d = node;
},
'BlockStatement': () => {
blocks += 1;
},
'BlockStatement:exit': () => {
blocks -= 1;
if(hasAwaitOnBlockLevel && blocks === hasAwaitOnBlockLevel) {
hasAwaitOnBlockLevel = undefined;
}
},
'ReturnStatement:exit': (node) => {
if(hasAwait && hasAwaitOnBlockLevel && blocks === hasAwaitOnBlockLevel && node.parent.type === 'BlockExpression') {
endFunction();
}
},
'AssignmentExpression': (node) => {
if(node.left.type !== "Identifier" || node.left.name !== "global") return;
if(node.right.type !== "CallExpression" || node.right.callee.name !== "getGlobal") return;
if(hasAwaitOnBlockLevel && blocks === hasAwaitOnBlockLevel) {
hasAwait = false;
hasAwaitOnBlockLevel = undefined;
d = undefined;
} else {
hasAssignmentOnBlockLevel = blocks;
assigned = node;
}
},
Identifier: (node) => {
if(node.name !== "global") return;
if(node.parent === assigned) return;
if(hasAwait) {
if(hasAssignmentOnBlockLevel !== undefined && hasAssignmentOnBlockLevel <= blocks) {
endFunction();
return;
}
context.report({
node,
messageId: "mustUpdateGlobalAfterAwait",
data: {
before: d ? d.loc.start.line + ':' + d.loc.start.column : 'unknown'
},
})
}
},
"Program:exit": endFunction,
};
},
};

View File

@ -1,40 +0,0 @@
/**
* @fileoverview Forbid usage of getActions in actions
* @author undrfined
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description: "Forbid usage of getActions in action handlers",
recommended: false,
url: null,
},
fixable: null,
schema: [],
messages: {
noGetActionsInActions: "Do not use getActions inside action handlers, instead use the second argument of the action handler",
}
},
create(context) {
return {
CallExpression: (node) => {
if(!context.getPhysicalFilename().substring(context.getCwd().length).startsWith('/src/global')) return;
if(node.callee.name === 'getActions') {
context.report({
node,
messageId: 'noGetActionsInActions',
})
}
}
};
},
};

View File

@ -1,42 +0,0 @@
/**
* @fileoverview No immediate global
* @author undrfined
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description: "No immediate global",
recommended: false,
url: null,
},
fixable: null,
schema: [],
messages: {
noImmediateGlobal: "Only use getGlobal() to assign to global variable",
}
},
create(context) {
return {
CallExpression: (node) => {
if(!context.getPhysicalFilename().substring(context.getCwd().length).startsWith('/src/global')) return;
if(node.callee.name === 'getGlobal'
&& node.parent.type !== 'AssignmentExpression'
) {
context.report({
node,
messageId: "noImmediateGlobal",
})
}
}
};
},
};

View File

@ -1,53 +0,0 @@
/**
* @fileoverview setGlobal must only be used with 'global' variable
* @author undrfined
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description: "setGlobal must only be used with 'global' variable",
recommended: false,
url: null,
},
fixable: null,
schema: [],
hasSuggestions: true,
messages: {
setGlobalOnlyVariable: "setGlobal must only be used with 'global' variable",
}
},
create(context) {
return {
CallExpression: (node) => {
if(node.callee.name === 'setGlobal') {
if(node.arguments[0] && node.arguments[0].type !== 'Identifier' || node.arguments[0].name !== 'global') {
context.report({
node,
messageId: 'setGlobalOnlyVariable',
...(node.parent.type === 'ExpressionStatement' && {
suggest: [{
desc: "Move the global assignment before the setGlobal call",
*fix(fixer) {
const sc = context.getSourceCode();
const parent = node.parent;
yield fixer.insertTextBefore(parent, 'global = ' + sc.getText(node.arguments[0]) + ';\n');
yield fixer.replaceText(node.arguments[0], 'global');
},
}]
}),
})
}
}
}
};
},
};

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +0,0 @@
{
"name": "eslint-plugin-eslint-multitab-tt",
"version": "0.0.0",
"description": "eslint-multitab-tt",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin"
],
"author": "undrfined",
"main": "./lib/index.js",
"exports": "./lib/index.js",
"scripts": {
"lint": "npm-run-all \"lint:*\"",
"lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"",
"lint:js": "eslint .",
"test": "mocha tests --recursive",
"update:eslint-docs": "eslint-doc-generator"
},
"dependencies": {
"requireindex": "^1.2.0"
},
"devDependencies": {
"chalk": "^5.3.0",
"eslint": "^8.57.0",
"eslint-doc-generator": "^1.7.0",
"eslint-plugin-eslint-plugin": "^6.1.0",
"eslint-plugin-node": "^11.1.0",
"mocha": "^10.4.0",
"npm-run-all": "^4.1.5"
},
"engines": {
"node": "^20 || ^22"
},
"peerDependencies": {
"eslint": ">=8"
},
"license": "ISC"
}

View File

@ -67,5 +67,5 @@ function formatKeyWithVariables(isPlural: boolean, keysWithVars: Record<string,
const typeName = isPlural ? 'LangPairPlural' : 'LangPair';
return `export interface ${typeName} {\n${entries}}\n
export interface ${typeName}WithVariables<V extends unknown = LangVariable> {\n${variableEntries}}\n`;
export interface ${typeName}WithVariables<V = LangVariable> {\n${variableEntries}}\n`;
}

View File

@ -1,11 +1,12 @@
/* eslint-disable max-len */
const Telegraph = require('telegraph-node');
const { JSDOM } = require('jsdom');
const { gitlogPromise } = require('gitlog');
/* eslint-disable @stylistic/max-len */
import gitlog from 'gitlog';
import { JSDOM } from 'jsdom';
import Telegraph from 'telegraph-node';
import packageJson from '../package.json' with { type: 'json' };
// CONSTANTS
const AUTH_TOKEN = process.env.TELEGRAPH_TOKEN;
const version = require('../package.json').version;
const gitOptions = {
repo: '.',
@ -17,7 +18,7 @@ const gitOptions = {
const pageTemplate = `
<body>\
<aside><img src="https://tga.dev/icon-dev-512x512.png" /></aside>
<h3>Commits since ${version}</h3>\
<h3>Commits since ${packageJson.version}</h3>\
<p><i>This list is automatically updated when a new commit pushed to the beta repo</i></p>\
<ul id="list"></ul>\
<aside><a href="https://t.me/webatalks">Web A Discussion</a> <b>|</b> <a href="https://t.me/webatalksru">Web A Обсуждение</a> <b>|</b> <a href="https://t.me/webatalksuk">Web A Обговорення</a></aside>\
@ -51,7 +52,7 @@ async function updateTelegraph(dom) {
async function preparePage() {
const dom = new JSDOM(pageTemplate);
const commits = await getCommitsSince(version);
const commits = await getCommitsSince(packageJson.version);
commits.forEach((commit) => (
dom.window.document.getElementById('list').appendChild(renderCommit(dom, commit))
@ -59,7 +60,7 @@ async function preparePage() {
if (!commits?.length) {
const li = dom.window.document.createElement('li');
li.innerHTML = `<p>Nothing changed since ${version}</p>`;
li.innerHTML = `<p>Nothing changed since ${packageJson.version}</p>`;
dom.window.document.getElementById('list').appendChild(li);
}
@ -74,7 +75,7 @@ function renderCommit(dom, commit) {
}
function getCommits() {
return gitlogPromise(gitOptions).then((log) => {
return gitlog(gitOptions).then((log) => {
return log.map((commit) => {
return {
hash: commit.hash,

View File

@ -1,10 +1,10 @@
const fs = require('fs');
const path = require('path');
import { readFileSync, writeFileSync } from 'fs';
import { resolve } from 'path';
const API_TL_PATH = path.resolve('./src/lib/gramjs/tl/static/api.tl');
const API_TL_PATH = resolve('./src/lib/gramjs/tl/static/api.tl');
function rehash() {
const data = fs.readFileSync(API_TL_PATH, 'utf8');
const data = readFileSync(API_TL_PATH, 'utf8');
const lines = data.split('\n');
// eslint-disable-next-line no-console
@ -30,7 +30,7 @@ function rehash() {
// eslint-disable-next-line no-console
console.log(`Writing ${resultLines.length} lines`);
fs.writeFileSync(API_TL_PATH, resultLines.join('\n'));
writeFileSync(API_TL_PATH, resultLines.join('\n'));
}
function getHash(line) {

View File

@ -1,6 +1,5 @@
const stylelint = require('stylelint');
// eslint-disable-next-line import/no-unresolved -- TS BUG
const postcss = require('postcss');
import { list } from 'postcss';
import stylelint from 'stylelint';
const ruleName = 'plugin/whole-pixel';
@ -14,7 +13,7 @@ const PX_PER_REM = 16;
const unitRegex = /(px|rem)$/;
const numberRegex = /^([-0-9.]+)/;
module.exports = stylelint.createPlugin(ruleName, (primaryOption, secondaryOptionObject, context) => {
const plugin = stylelint.createPlugin(ruleName, (primaryOption, secondaryOptionObject, context) => {
const secondaryOptions = secondaryOptionObject || {};
return (root, result) => {
const validOptions = stylelint.utils.validateOptions(
@ -74,12 +73,12 @@ module.exports = stylelint.createPlugin(ruleName, (primaryOption, secondaryOptio
root.walkDecls((decl) => {
if (!decl.value || ignoreList.includes(decl.prop)) return;
const values = postcss.list.space(decl.value);
const values = list.space(decl.value);
if (!values?.length) return;
values.forEach((value) => handleValue(decl, value));
});
};
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;
export { ruleName, messages };
export default plugin;

204
eslint.config.mjs Normal file
View File

@ -0,0 +1,204 @@
import eslint from '@eslint/js';
import stylisticJs from '@stylistic/eslint-plugin';
import { globalIgnores } from 'eslint/config';
import importsPlugin from 'eslint-plugin-import';
import jestPlugin from 'eslint-plugin-jest';
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
import noNullPlugin from 'eslint-plugin-no-null';
import reactPlugin from 'eslint-plugin-react';
import reactHooksStaticDeps from 'eslint-plugin-react-hooks-static-deps';
import reactXPlugin from 'eslint-plugin-react-x';
import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
import ttMultitabPlugin from 'eslint-plugin-tt-multitab';
import unusedImports from 'eslint-plugin-unused-imports';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
reactPlugin.configs.flat.recommended,
reactXPlugin.configs['recommended-type-checked'],
jsxA11yPlugin.flatConfigs.recommended,
ttMultitabPlugin.configs.recommended,
stylisticJs.configs.customize({
semi: true,
arrowParens: 'always',
braceStyle: '1tbs',
quoteProps: 'as-needed',
}),
globalIgnores([
'src/lib/rlottie/rlottie-wasm.js',
'src/lib/video-preview/polyfill',
'src/lib/fasttextweb/fasttext-wasm.cjs',
'src/lib/gramjs/tl/',
'src/lib/lovely-chart',
'src/lib/music-metadata-browser',
'src/lib/secret-sauce/',
'src/types/language.d.ts',
'dist/',
'dist-electron/',
'public/',
'deploy/update_version.js',
]),
{
name: 'teact-config',
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
settings: {
react: {
version: '19',
},
},
rules: {
'no-null/no-null': 'error',
'no-console': 'error',
'@stylistic/max-len': ['error', {
code: 120,
ignoreComments: true,
ignorePattern: '\\sd=".+"', // Ignore lines with "d" attribute
}],
'@stylistic/indent': ['error', 2, {
SwitchCase: 1,
flatTernaryExpressions: false,
}],
'@stylistic/multiline-ternary': 'off',
'no-prototype-builtins': 'off',
'no-undef': 'off',
'no-unused-vars': 'off',
'simple-import-sort/imports': [
'error',
{
groups: [
// Side effect imports
['^\\u0000'],
// Lib and global imports
[
'^react',
'^@?\\w',
'dist(/.*|$)',
'^(\\.+/)+(lib/(teact|gramjs))(/.*|$)',
'^(\\.+/)+global$',
],
// Type imports
[
'^(\\.+/)+.+\\u0000$',
'^(\\.+/|\\w+/)+(types)(/.*|$)',
'^(\\.+/|\\w+/)+(types)\\u0000',
],
// Config, utils, helpers
[
'^(\\.+/)+config',
'^(\\.+/)+(lib)(?!/(gramjs|teact))(/.*|$)',
'^(\\.+/)+global/.+',
'^(\\.+/)+(util)(/.*|$)',
'^\\.\\.(?!/?$)',
'^\\.\\./?$',
'^\\./(?=.*/)(?!/?$)',
'^\\.(?!/?$)',
'^\\./?$',
],
// Hooks
[
'.+(/hooks/)(.*|$)',
],
// Components
[
'/[A-Z](([a-z]+[A-Z]?)*)',
],
// Styles and CSS modules
[
'^.+\\.s?css$',
],
// Assets: images, stickers, etc
[
'^(\\.+/)+(assets)(/.*|$)',
],
],
},
],
// TypeScript type imports preference
'@typescript-eslint/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
disallowTypeAnnotations: false,
},
],
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-misused-promises': [
'error',
{
checksVoidReturn: false,
},
],
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'none',
caughtErrors: 'none',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/prefer-promise-reject-errors': 'off',
'@typescript-eslint/unbound-method': 'off',
'unused-imports/no-unused-imports': 'error',
'react-hooks/exhaustive-deps': 'off',
'react-hooks-static-deps/exhaustive-deps': [
'error',
{
// eslint-disable-next-line @stylistic/max-len
additionalHooks: '(useSyncEffect|useAsync|useDebouncedCallback|useThrottledCallback|useEffectWithPrevDeps|useLayoutEffectWithPrevDeps|useDerivedState|useDerivedSignal|useThrottledResolver|useDebouncedResolver|useThrottleForHeavyAnimation)$',
staticHooks: {
getActions: true,
useFlag: [false, true, true],
useForceUpdate: true,
useReducer: [false, true],
useLastCallback: true,
},
},
],
'react/prop-types': 'off',
'react/no-unknown-property': 'off',
'react/display-name': 'off',
'react/jsx-key': 'off',
'react-x/no-use-context': 'off',
'react-x/no-context-provider': 'off',
'react-x/no-array-index-key': 'off',
'react-x/no-missing-key': 'off',
'react-x/no-nested-component-definitions': 'off',
'react-x/no-leaked-conditional-rendering': 'error',
'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/mouse-events-have-key-events': 'off',
'jsx-a11y/no-static-element-interactions': 'off',
'jsx-a11y/label-has-associated-control': 'off',
'jsx-a11y/anchor-is-valid': 'off',
'jsx-a11y/no-noninteractive-element-to-interactive-role': 'off',
'jsx-a11y/media-has-caption': 'off',
},
plugins: {
'no-null': noNullPlugin,
'simple-import-sort': simpleImportSortPlugin,
import: importsPlugin,
'unused-imports': unusedImports,
react: reactPlugin,
'react-hooks-static-deps': reactHooksStaticDeps,
jest: jestPlugin,
'tt-multitab': ttMultitabPlugin,
},
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
globals: jestPlugin.environments.globals.globals,
},
},
);

View File

@ -1,4 +1,4 @@
module.exports = {
export default {
setupFilesAfterEnv: ['./tests/init.js'],
moduleNameMapper: {
'\\.(css|scss|wasm|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|tgs)$':
@ -16,7 +16,7 @@ module.exports = {
'\\.txt$': '@glen/jest-raw-loader',
},
globals: {
APP_REVISION: "jest-test",
APP_VERSION: "0.0.1",
APP_REVISION: 'jest-test',
APP_VERSION: '0.0.1',
},
};

19328
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
"name": "telegram-t",
"version": "10.9.51",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"dev": "cross-env APP_ENV=development webpack serve --mode development",
@ -11,19 +12,17 @@
"build:mocked": "cross-env APP_ENV=test APP_MOCKED_CLIENT=1 npm run build:dev",
"build:production": "webpack && bash ./deploy/copy_to_dist.sh",
"web:release:production": "npm i && npm run build:production && git add -A && git commit -a -m '[Build]' --no-verify && git push",
"electron:dev": "npm run electron:webpack && IS_PACKAGED_ELECTRON=true concurrently -n main,renderer,electron \"npm run electron:webpack -- --watch\" \"npm run dev\" \"electronmon dist/electron\"",
"electron:dev": "npm run electron:webpack && IS_PACKAGED_ELECTRON=true concurrently -n main,renderer,electron \"npm run electron:webpack -- --watch\" \"npm run dev\" \"electronmon dist/electron.cjs\"",
"electron:webpack": "cross-env APP_ENV=$ENV webpack --config ./webpack-electron.config.ts",
"electron:build": "IS_PACKAGED_ELECTRON=true npm run build:$ENV && electron-builder install-app-deps && electron-rebuild && ENV=$ENV npm run electron:webpack",
"electron:package": "npm run electron:build && npx rimraf dist-electron && electron-builder build --win --mac --linux --config src/electron/config.yml",
"electron:package:staging": "ENV=staging npm run electron:package -- -p never",
"electron:release:production": "ENV=production npm run electron:package -- -p always",
"telegraph:update_changelog": "node ./dev/telegraphChangelog.js",
"check": "tsc && stylelint \"**/*.{css,scss}\" && eslint . --ext .ts,.tsx,.js --ignore-pattern src/lib/gramjs",
"check": "tsc && stylelint \"**/*.{css,scss}\" && eslint .",
"check:fix": "npm run check -- --fix",
"tl:rehash": "node ./dev/tlHash.js",
"gramjs:tl": "tsx ./src/lib/gramjs/tl/generateModules.ts",
"gramjs:lint": "cd src/lib/gramjs && eslint --ext .ts,.tsx,.js .",
"gramjs:lint:fix": "npm run gramjs:lint -- --fix",
"lang:ts": "tsx ./dev/generateLangTypes.js",
"lang:initial": "tsx ./dev/generateInitialLangFallback.js",
"icons:build": "fantasticon",
@ -31,12 +30,11 @@
"test:playwright": "playwright test",
"test:record": "playwright codegen localhost:1235",
"statoscope:validate-diff": "statoscope validate --input input.json --reference reference.json",
"postinstall": "(cd dev/eslint-multitab && npm i)",
"postversion": "echo $(node -p \"require('./package.json').version\") > public/version.txt && git commit --amend --no-verify --no-edit public/version.txt"
},
"engines": {
"node": "^20 || ^22",
"npm": "^9 || ^10"
"node": "^22.6 || ^24",
"npm": "^10.8 || ^11"
},
"lint-staged": {
"*.{ts,tsx,js}": "eslint --fix",
@ -48,90 +46,89 @@
"author": "Alexander Zinchuk (alexander@zinchuk.com)",
"license": "GPL-3.0-or-later",
"devDependencies": {
"@babel/core": "^7.24.5",
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
"@babel/plugin-transform-class-properties": "^7.24.1",
"@babel/plugin-transform-logical-assignment-operators": "^7.24.1",
"@babel/preset-env": "^7.24.5",
"@babel/preset-react": "^7.24.1",
"@babel/preset-typescript": "^7.24.1",
"@babel/register": "^7.23.7",
"@electron/rebuild": "^3.6.0",
"@babel/core": "^7.27.1",
"@babel/preset-env": "^7.27.2",
"@babel/preset-react": "^7.27.1",
"@babel/preset-typescript": "^7.27.1",
"@babel/register": "^7.27.1",
"@electron/rebuild": "^4.0.1",
"@eslint/js": "^9.26.0",
"@glen/jest-raw-loader": "^2.0.0",
"@playwright/test": "^1.44.0",
"@statoscope/cli": "5.28.2",
"@statoscope/webpack-plugin": "5.28.2",
"@stylistic/stylelint-config": "^1.0.1",
"@stylistic/stylelint-plugin": "^2.1.2",
"@testing-library/jest-dom": "^6.4.5",
"@twbs/fantasticon": "^3.0.0",
"@playwright/test": "^1.52.0",
"@statoscope/cli": "5.29.0",
"@statoscope/webpack-plugin": "5.29.0",
"@stylistic/eslint-plugin": "^4.2.0",
"@stylistic/stylelint-config": "^2.0.0",
"@stylistic/stylelint-plugin": "^3.1.2",
"@testing-library/jest-dom": "^6.6.3",
"@twbs/fantasticon": "^3.1.0",
"@types/croppie": "^2.6.4",
"@types/dom-view-transitions": "^1.0.6",
"@types/hast": "^3.0.4",
"@types/jest": "^29.5.12",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"@types/jest": "^29.5.14",
"@types/node": "^22.15.17",
"@types/react": "^19.1.4",
"@types/react-dom": "^19.1.5",
"@types/webpack": "^5.28.5",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"@typescript-eslint/parser": "^7.8.0",
"@webpack-cli/serve": "^2.0.5",
"autoprefixer": "^10.4.19",
"babel-loader": "^9.1.3",
"babel-plugin-transform-import-meta": "^2.2.1",
"@typescript-eslint/eslint-plugin": "^8.32.1",
"@typescript-eslint/parser": "^8.32.1",
"@webpack-cli/serve": "^3.0.1",
"autoprefixer": "^10.4.21",
"babel-loader": "^10.0.0",
"babel-plugin-transform-import-meta": "^2.3.2",
"bindings": "git+https://github.com/zubiden/node-bindings#6b9b0711a12e9df9cbf59a3271c25bf34c306907",
"browserlist": "^1.0.1",
"buffer": "^6.0.3",
"concurrently": "^8.2.2",
"concurrently": "^9.1.2",
"cross-env": "^7.0.3",
"css-loader": "^7.1.1",
"dotenv": "^16.4.5",
"electron": "^22.3.27",
"electron-builder": "^24.13.3",
"electron-context-menu": "^3.6.1",
"electron-store": "^8.2.0",
"electron-updater": "^6.1.8",
"css-loader": "^7.1.2",
"dotenv": "^16.5.0",
"electron": "^36.2.0",
"electron-builder": "^26.0.12",
"electron-conf": "^1.3.0",
"electron-context-menu": "^4.0.5",
"electron-drag-click": "git+https://github.com/zubiden/electron-drag-click#cf6918ddb648e13ebcf6cf1e7aa008258edc06ad",
"electron-updater": "^6.6.2",
"electronmon": "^2.0.3",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-config-teact-app": "git+https://github.com/zubiden/eslint-config-teact-app#ebb14df4114e549fe9855d7ed0ca6cf11098e9fe",
"eslint-import-resolver-webpack": "^0.13.8",
"eslint-plugin-eslint-multitab-tt": "file:dev/eslint-multitab",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-no-async-without-await": "^1.2.0",
"eslint": "^9.26.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.11.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-no-null": "^1.0.2",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-hooks-static-deps": "^1.0.7",
"eslint-plugin-simple-import-sort": "^12.1.0",
"eslint-plugin-teactn": "git+https://github.com/korenskoy/eslint-plugin-teactn#c2c39dd005d58c07c24c4361de804dce1c6261b5",
"fake-indexeddb": "^6.0.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks-static-deps": "git+https://github.com/zubiden/eslint-plugin-react-hooks-static-deps#c16f35bf2e6e364cbc692c73cc350c1c5d46cc6e",
"eslint-plugin-react-x": "^1.49.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-tt-multitab": "git+https://github.com/zubiden/eslint-plugin-tt-multitab#15d542004d39ec7c29d50385484511bab0b77ea9",
"eslint-plugin-unused-imports": "^4.1.4",
"fake-indexeddb": "^6.0.1",
"git-revision-webpack-plugin": "^5.0.0",
"gitlog": "^4.0.8",
"html-webpack-plugin": "^5.6.0",
"husky": "^9.0.11",
"gitlog": "^5.1.0",
"html-webpack-plugin": "^5.6.3",
"husky": "^9.1.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"lint-staged": "^15.2.2",
"mini-css-extract-plugin": "^2.9.0",
"lint-staged": "^16.0.0",
"mini-css-extract-plugin": "^2.9.2",
"postcss-loader": "^8.1.1",
"postcss-modules": "^6.0.0",
"react": "^18.3.1",
"sass": "^1.77.0",
"sass-loader": "^14.2.1",
"postcss-modules": "^6.0.1",
"react": "^19.1.0",
"sass": "^1.88.0",
"sass-loader": "^16.0.5",
"script-loader": "^0.7.2",
"serve": "^14.2.3",
"stylelint": "^16.5.0",
"stylelint-config-recommended-scss": "^14.0.0",
"serve": "^14.2.4",
"stylelint": "^16.19.1",
"stylelint-config-recommended-scss": "^15.0.0",
"stylelint-declaration-block-no-ignored-properties": "^2.8.0",
"stylelint-group-selectors": "^1.0.10",
"stylelint-high-performance-animation": "^1.10.0",
"stylelint-high-performance-animation": "^1.11.0",
"stylelint-selector-tag-no-without-class": "^3.0.1",
"telegraph-node": "^1.0.4",
"tsx": "^4.11.0",
"typescript": "^5.4.5",
"webpack": "^5.91.0",
"webpack-dev-server": "^5.0.4"
"tsx": "^4.19.4",
"typescript": "^5.8.3",
"typescript-eslint": "^8.32.1",
"webpack": "^5.99.8",
"webpack-dev-server": "^5.2.1"
},
"dependencies": {
"@cryptography/aes": "^0.1.1",
@ -139,18 +136,20 @@
"big-integer": "github:painor/BigInteger.js",
"croppie": "^2.6.5",
"emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#443f1c9d7b16a82e7ee53f7f226d7d9a9920a105",
"idb-keyval": "^6.2.1",
"lowlight": "^2.9.0",
"mp4box": "^0.5.2",
"idb-keyval": "^6.2.2",
"lowlight": "^3.3.0",
"mp4box": "^0.5.4",
"opus-recorder": "github:Ajaxy/opus-recorder",
"os-browserify": "^0.3.0",
"pako": "^2.1.0",
"path-browserify": "^1.0.1",
"qr-code-styling": "github:zubiden/qr-code-styling#dbbfed0",
"v8-compile-cache": "^2.4.0"
"qr-code-styling": "^1.9.2"
},
"optionalDependencies": {
"dmg-license": "^1.0.11",
"fsevents": "2.3.3"
},
"overrides": {
"bindings": "$bindings"
}
}

View File

@ -1,4 +1,4 @@
import { PlaywrightTestConfig, devices } from '@playwright/test';
import { devices, type PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: 'tests/playwright',

View File

@ -1 +1 @@
10.4.6
10.4.51

View File

@ -12,9 +12,14 @@ declare namespace React {
teactExperimentControlled?: boolean;
}
// Teact feature
// Teact features
// eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-wrapper-object-types
interface CSSProperties extends String {}
interface ClassAttributes<T> extends RefAttributes<T> {
ref?: ((instance: T | undefined) => void) | React.RefObject<T | undefined> | undefined; // Teact ref
}
interface Attributes {
// Optimization for DOM nodes reordering. Requires `teactFastList` for parent
teactOrderKey?: number;
@ -60,17 +65,35 @@ type EmojiWithSkins = Record<number, Emoji>;
type AllEmojis = Record<string, Emoji | EmojiWithSkins>;
// Declare supported for import formats as modules
declare module '*.png';
declare module '*.jpg';
declare module '*.svg';
declare module '*.tgs';
declare module '*.wasm';
declare module '*.strings';
// Declare supported formats as modules
declare module '*.png' {
const url: string;
export default url;
}
declare module '*.jpg' {
const url: string;
export default url;
}
declare module '*.svg' {
const url: string;
export default url;
}
declare module '*.txt' {
const content: string;
export default content;
const url: string;
export default url;
}
declare module '*.tgs' {
const url: string;
export default url;
}
declare module '*.wasm' {
const url: string;
export default url;
}
declare module '*.strings' {
const url: string;
export default url;
}
declare module 'pako/dist/pako_inflate' {
@ -79,6 +102,7 @@ declare module 'pako/dist/pako_inflate' {
declare module 'opus-recorder' {
export interface IOpusRecorder extends Omit<MediaRecorder, 'start' | 'ondataavailable'> {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(options: AnyLiteral): IOpusRecorder;
start(stream?: MediaStreamAudioSourceNode): void;
@ -104,8 +128,8 @@ interface IWebpWorker extends Worker {
}
interface Document {
mozFullScreenElement: any;
webkitFullscreenElement: any;
mozFullScreenElement: HTMLElement;
webkitFullscreenElement: HTMLElement;
mozCancelFullScreen?: () => Promise<void>;
webkitCancelFullScreen?: () => Promise<void>;
webkitExitFullscreen?: () => Promise<void>;
@ -138,14 +162,15 @@ type Falsy = false | 0 | '' | null | undefined;
interface BooleanConstructor {
new<T>(value: T | Falsy): value is T;
<T>(value: T | Falsy): value is T;
// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
readonly prototype: Boolean;
}
interface Array<T> {
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Exclude<S, Falsy>[];
filter<S extends T>(predicate: BooleanConstructor, thisArg?: unknown): Exclude<S, Falsy>[];
}
interface ReadonlyArray<T> {
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Exclude<S, Falsy>[];
filter<S extends T>(predicate: BooleanConstructor, thisArg?: unknown): Exclude<S, Falsy>[];
}
// Missing type definitions for OPFS (Origin Private File System) API
@ -162,7 +187,7 @@ interface FileSystemSyncAccessHandle {
truncate: (size: number) => Promise<undefined>;
getSize: () => Promise<number>;
flush: () => Promise<undefined> ;
flush: () => Promise<undefined>;
close: () => Promise<undefined>;
}

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/naming-convention */
import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';

View File

@ -144,7 +144,7 @@ export function buildPhoneCall(call: GramJs.TypePhoneCall): ApiPhoneCall {
keyFingerprint: keyFingerprint.toString(),
startDate,
isP2pAllowed: Boolean(p2pAllowed),
connections: connections.map(buildApiCallConnection).filter(Boolean) as ApiPhoneCallConnection[],
connections: connections.map(buildApiCallConnection).filter(Boolean),
};
}

View File

@ -1,4 +1,3 @@
import type BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import type { Entity } from '../../../lib/gramjs/types';
@ -298,11 +297,11 @@ export function getApiChatTypeFromPeerEntity(peerEntity: GramJs.TypeChat | GramJ
export function getPeerKey(peer: GramJs.TypePeer) {
if (isMtpPeerUser(peer)) {
return `user${peer.userId}`;
return `user${peer.userId.toString()}`;
} else if (isMtpPeerChat(peer)) {
return `chat${peer.chatId}`;
return `chat${peer.chatId.toString()}`;
} else {
return `chat${peer.channelId}`;
return `chat${peer.channelId.toString()}`;
}
}
@ -330,7 +329,7 @@ export function buildChatMember(
return {
userId,
inviterId: 'inviterId' in member && member.inviterId
? buildApiPeerId(member.inviterId as BigInt.BigInteger, 'user')
? buildApiPeerId(member.inviterId, 'user')
: undefined,
joinedDate: 'date' in member ? member.date : undefined,
kickedByUserId: 'kickedBy' in member && member.kickedBy ? buildApiPeerId(member.kickedBy, 'user') : undefined,

View File

@ -16,7 +16,7 @@ export function bytesToDataUri(bytes: Buffer, shouldOmitPrefix = false, mimeType
return `${prefix}${btoa(String.fromCharCode(...bytes))}`;
}
export function omitVirtualClassFields<T extends GramJs.VirtualClass<T> & { flags?: any }>(
export function omitVirtualClassFields<T extends GramJs.VirtualClass<T> & { flags?: unknown }>(
instance: T,
): OmitVirtualFields<T> {
const {

View File

@ -214,7 +214,6 @@ export function buildVideoFromDocument(document: GramJs.Document, params?: {
id, mimeType, thumbs, size, videoThumbs, attributes,
} = document;
// eslint-disable-next-line no-restricted-globals
if (mimeType === VIDEO_WEBM_TYPE && !(self as any).isWebmSupported) {
return undefined;
}

View File

@ -441,7 +441,7 @@ export function buildLocalMessage(
const emojiOnlyCount = getEmojiOnlyCountForMessage(message.content, message.groupedId);
const finalMessage : ApiMessage = {
const finalMessage: ApiMessage = {
...message,
...(emojiOnlyCount && { emojiOnlyCount }),
};

View File

@ -1,6 +1,3 @@
/* eslint-disable no-bitwise */
// eslint-disable-next-line max-len
const TEMPLATE = '<?xml version="1.0" encoding="utf-8"?><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 {{width}} {{height}}" xml:space="preserve"><path fill-opacity="0.1" d="{{path}}" /></svg>';
const LOOKUP = 'AACAAAAHAAALMAAAQASTAVAAAZaacaaaahaaalmaaaqastava.az0123456789-,';

View File

@ -32,7 +32,7 @@ export function buildApiPeerId(id: BigInt.BigInteger, type: 'user' | 'chat' | 'c
return `-1${id.toString().padStart(CHANNEL_ID_LENGTH - 2, '0')}`;
}
return `-${id}`;
return `-${id.toString()}`;
}
export function getApiChatIdFromMtpPeer(peer: TypePeerOrInput) {

View File

@ -166,7 +166,7 @@ export function buildApiAvailableEffect(availableEffect: GramJs.AvailableEffect)
};
}
export function buildApiPaidReactionPrivacy(privacy: GramJs.TypePaidReactionPrivacy) : ApiPaidReactionPrivacyType {
export function buildApiPaidReactionPrivacy(privacy: GramJs.TypePaidReactionPrivacy): ApiPaidReactionPrivacyType {
if (privacy instanceof GramJs.PaidReactionPrivacyAnonymous) {
return { type: 'anonymous' };
}

View File

@ -53,7 +53,6 @@ export function buildStickerFromDocument(document: GramJs.TypeDocument,
(s): s is GramJs.PhotoCachedSize => s instanceof GramJs.PhotoCachedSize,
);
// eslint-disable-next-line no-restricted-globals
if (mimeType === VIDEO_STICKER_MIME_TYPE && !(self as any).isWebmSupported && !cachedThumb) {
const staticThumb = document.thumbs && document.thumbs.find(
(s): s is GramJs.PhotoSize => s instanceof GramJs.PhotoSize,
@ -78,7 +77,7 @@ export function buildStickerFromDocument(document: GramJs.TypeDocument,
const { w: width, h: height } = cachedThumb as GramJs.PhotoCachedSize || sizeAttribute || {};
const hasEffect = !isNoPremium && videoThumbs && compact(videoThumbs
?.filter((thumb) => thumb instanceof GramJs.VideoSize) as GramJs.VideoSize[])
?.filter((thumb) => thumb instanceof GramJs.VideoSize))
.some(({ type }) => type === 'f');
return {

View File

@ -118,7 +118,7 @@ export function addDocumentToLocalDb(document: GramJs.TypeDocument) {
export function addStoryRepairInfo<T extends GramJs.TypeDocument | GramJs.TypeWebDocument | GramJs.TypePhoto>(
media: T, peerId: string, story: GramJs.TypeStoryItem,
) : T & RepairInfo {
): T & RepairInfo {
if (!(media instanceof GramJs.Document && media instanceof GramJs.Photo)) return media;
const repairableMedia = media as T & RepairInfo;
repairableMedia.localRepairInfo = {
@ -131,7 +131,7 @@ export function addStoryRepairInfo<T extends GramJs.TypeDocument | GramJs.TypeWe
export function addMessageRepairInfo<T extends GramJs.TypeDocument | GramJs.TypeWebDocument | GramJs.TypePhoto>(
media: T, context?: MediaRepairContext,
) : T & RepairInfo {
): T & RepairInfo {
if (!context?.peerId) return media;
if (!(media instanceof GramJs.Document || media instanceof GramJs.Photo || media instanceof GramJs.WebDocument)) {
return media;

View File

@ -70,7 +70,7 @@ export function deserializeBytes(value: string) {
}
export function log(suffix: keyof typeof LOG_SUFFIX, ...data: any) {
/* eslint-disable max-len */
/* eslint-disable @stylistic/max-len */
/* eslint-disable no-console */
const func = suffix === 'UNEXPECTED RESPONSE' ? console.error
: suffix === 'INVOKE ERROR' || suffix === 'UNEXPECTED UPDATE' ? console.warn : console.log;
@ -81,7 +81,7 @@ export function log(suffix: keyof typeof LOG_SUFFIX, ...data: any) {
`color: ${LOG_SUFFIX[suffix]}; background: ${LOG_BACKGROUND}; padding: 0.25rem; border-radius: 0.25rem; margin-left: 0.25rem;`,
...data,
);
/* eslint-enable max-len */
/* eslint-enable @stylistic/max-len */
}
export function isResponseUpdate<T extends GramJs.AnyRequest>(result: T['__response']): result is GramJs.TypeUpdate {

View File

@ -73,7 +73,7 @@ export async function changeSessionTtl({
return result;
}
export async function resolveBusinessChatLink({ slug } : { slug: string }) {
export async function resolveBusinessChatLink({ slug }: { slug: string }) {
const result = await invokeRequest(new GramJs.account.ResolveBusinessChatLink({
slug,
}), {

View File

@ -9,8 +9,8 @@ import { wrapError } from '../helpers/misc';
import { sendApiUpdate } from '../updates/apiUpdateEmitter';
const authController: {
resolve?: Function;
reject?: Function;
resolve?: AnyToVoidFunction;
reject?: (error: Error) => void;
} = {};
export function onWebAuthTokenFailed() {

View File

@ -530,13 +530,13 @@ export async function acceptLinkUrlAuth({ url, isWriteAllowed }: { url: string;
return authResult;
}
export function fetchBotCanSendMessage({ bot } : { bot: ApiUser }) {
export function fetchBotCanSendMessage({ bot }: { bot: ApiUser }) {
return invokeRequest(new GramJs.bots.CanSendMessage({
bot: buildInputUser(bot.id, bot.accessHash),
}));
}
export function allowBotSendMessages({ bot } : { bot: ApiUser }) {
export function allowBotSendMessages({ bot }: { bot: ApiUser }) {
return invokeRequest(new GramJs.bots.AllowSendMessage({
bot: buildInputUser(bot.id, bot.accessHash),
}), {
@ -554,9 +554,9 @@ export async function invokeWebViewCustomMethod({
parameters: string;
}): Promise<{
result: object;
} | {
} | {
error: string;
}> {
}> {
try {
const result = await invokeRequest(new GramJs.bots.InvokeWebViewCustomMethod({
bot: buildInputUser(bot.id, bot.accessHash),
@ -579,7 +579,7 @@ export async function invokeWebViewCustomMethod({
}
}
export async function fetchPreviewMedias({ bot } : { bot: ApiUser }) {
export async function fetchPreviewMedias({ bot }: { bot: ApiUser }) {
const result = await invokeRequest(new GramJs.bots.GetPreviewMedias({
bot: buildInputUser(bot.id, bot.accessHash),
}));
@ -613,7 +613,7 @@ export function checkBotDownloadFileParams({
});
}
export function toggleUserEmojiStatusPermission({ bot, isEnabled } : { bot: ApiUser; isEnabled: boolean }) {
export function toggleUserEmojiStatusPermission({ bot, isEnabled }: { bot: ApiUser; isEnabled: boolean }) {
return invokeRequest(new GramJs.bots.ToggleUserEmojiStatusPermission({
bot: buildInputUser(bot.id, bot.accessHash),
enabled: isEnabled,

View File

@ -965,7 +965,7 @@ export async function editChatPhoto({
return invokeRequest(
chatType === 'channel'
? new GramJs.channels.EditPhoto({
channel: buildInputChannel(chatId, accessHash!),
channel: buildInputChannel(chatId, accessHash),
photo: inputPhoto,
})
: new GramJs.messages.EditChatPhoto({
@ -1319,7 +1319,7 @@ export async function fetchMembers({
memberFilter = 'recent',
offset,
query = '',
} : {
}: {
chat: ApiChat;
memberFilter?: ChannelMembersFilter;
offset?: number;
@ -1577,7 +1577,7 @@ function preparePeers(
const store: Record<string, GramJs.TypeChat | GramJs.TypeUser> = {};
result.chats?.forEach((chat) => {
const key = `chat${chat.id}`;
const key = `chat${chat.id.toString()}`;
if (currentStore?.[key] && 'min' in chat && chat.min) {
return;
@ -1587,7 +1587,7 @@ function preparePeers(
});
result.users?.forEach((user) => {
const key = `user${user.id}`;
const key = `user${user.id.toString()}`;
if (currentStore?.[key] && 'min' in user && user.min) {
return;
@ -1708,7 +1708,7 @@ export async function fetchTopics({
shouldOrderByCreateDate?: boolean;
draftsById: Record<number, ReturnType<typeof buildMessageDraft>>;
readInboxMessageIdByTopicId: Record<number, number>;
} | undefined> {
} | undefined> {
const { id, accessHash } = chat;
const result = await invokeRequest(new GramJs.channels.GetForumTopics({
@ -1758,7 +1758,7 @@ export async function fetchTopicById({
}): Promise<{
topic: ApiTopic;
messages: ApiMessage[];
} | undefined> {
} | undefined> {
const { id, accessHash } = chat;
const result = await invokeRequest(new GramJs.channels.GetForumTopicsByID({

View File

@ -81,9 +81,8 @@ export async function init(initialArgs: ApiInitialArgs) {
const session = new sessions.CallbackSession(sessionData, onSessionUpdate);
// eslint-disable-next-line no-restricted-globals
(self as any).isWebmSupported = isWebmSupported;
// eslint-disable-next-line no-restricted-globals
(self as any).maxBufferSize = maxBufferSize;
client = new TelegramClient(
@ -113,9 +112,8 @@ export async function init(initialArgs: ApiInitialArgs) {
if (DEBUG) {
log('CONNECTING');
// eslint-disable-next-line no-restricted-globals
(self as any).invoke = invokeRequest;
// eslint-disable-next-line no-restricted-globals
(self as any).GramJs = GramJs;
}
@ -218,7 +216,7 @@ export function handleGramJsUpdate(update: any) {
const updates = 'updates' in update ? update.updates : [update];
updates.forEach((nestedUpdate: any) => {
if (!(nestedUpdate instanceof GramJs.UpdateConfig)) return;
// eslint-disable-next-line no-underscore-dangle
const currentUser = (nestedUpdate as UpdateConfig)._entities
?.find((entity) => entity instanceof GramJs.User && buildApiPeerId(entity.id, 'user') === currentUserId);
if (!(currentUser instanceof GramJs.User)) return;

View File

@ -16,6 +16,7 @@ export function initApi(_onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs, ini
if (initialLocalDb) updateFullLocalDb(initialLocalDb);
// IMPORTANT: Do not await this, or login will not work
initClient(initialArgs);
}

View File

@ -42,7 +42,7 @@ export default async function downloadMedia(
return undefined;
}
const parsed = await parseMedia(data, mediaFormat, mimeType);
const parsed = parseMedia(data, mediaFormat, mimeType);
if (!parsed) {
return undefined;
}
@ -184,10 +184,9 @@ async function download(
}
}
// eslint-disable-next-line no-async-without-await/no-async-without-await
async function parseMedia(
function parseMedia(
data: Buffer | File, mediaFormat: ApiMediaFormat, mimeType?: string,
): Promise<ApiParsedMedia | undefined> {
): ApiParsedMedia | undefined {
if (data instanceof File) {
return data;
}
@ -243,7 +242,7 @@ export function parseMediaUrl(url: string) {
: url.startsWith('webDocument')
? url.match(/(webDocument):(.+)/)
: url.match(
// eslint-disable-next-line max-len
/(avatar|profile|photo|stickerSet|sticker|wallpaper|document)([-\d\w./]+)(?::\d+)?(\?size=\w+)?/,
);
if (!mediaMatch) {

View File

@ -297,7 +297,7 @@ export function sendMessageLocal(
wasDrafted,
});
return localMessage;
return Promise.resolve(localMessage);
}
export function sendApiMessage(
@ -422,11 +422,11 @@ export function sendApiMessage(
return messagePromise;
}
export function sendMessage(
export async function sendMessage(
params: SendMessageParams,
onProgress?: ApiOnProgress,
) {
const localMessage = params.localMessage || sendMessageLocal(params);
const localMessage = params.localMessage || await sendMessageLocal(params);
return localMessage ? sendApiMessage(params, localMessage, onProgress) : undefined;
}
@ -495,7 +495,7 @@ function sendGroupedMedia(
const inputMedia = await fetchInputMedia(
buildInputPeer(chat.id, chat.accessHash),
media as GramJs.InputMediaUploadedPhoto | GramJs.InputMediaUploadedDocument,
media,
);
await prevMediaQueue;
@ -1557,7 +1557,7 @@ export function forwardMessagesLocal(params: ForwardMessagesParams) {
wasDrafted,
});
});
return { messageIds, localMessages };
return Promise.resolve({ messageIds, localMessages });
}
export async function forwardApiMessages(params: ForwardMessagesParams) {
@ -1617,7 +1617,7 @@ export async function forwardMessages(params: ForwardMessagesParams) {
} else {
const newParams = {
...params,
forwardedLocalMessagesSlice: forwardMessagesLocal(params),
forwardedLocalMessagesSlice: await forwardMessagesLocal(params),
};
await forwardApiMessages(newParams);
}
@ -2114,7 +2114,7 @@ export async function fetchOutboxReadDate({ chat, messageId }: { chat: ApiChat;
const peer = buildInputPeer(id, accessHash);
const result = await invokeRequest(new GramJs.messages.GetOutboxReadDate({
peer: peer as GramJs.TypeInputPeer,
peer: peer,
msgId: messageId,
}), { shouldThrow: true });

View File

@ -51,7 +51,7 @@ export async function validateRequestedInfo({
}): Promise<{
id: string;
shippingOptions: any;
} | undefined> {
} | undefined> {
const result = await invokeRequest(new GramJs.payments.ValidateRequestedInfo({
invoice: buildInputInvoice(inputInvoice),
save: shouldSave || undefined,
@ -258,7 +258,7 @@ export async function fetchMyBoosts() {
export async function applyBoost({
chat,
slots,
} : {
}: {
chat: ApiChat;
slots: number[];
}) {

View File

@ -117,7 +117,7 @@ class PhoneCallState {
});
}
const message = await this.state.decryptMessageData(Buffer.from(data));
const message = await this.state.decryptMessageData(Buffer.from(data)) as Buffer;
return JSON.parse(message.toString());
}
@ -161,7 +161,7 @@ export function destroyPhoneCallState() {
}
type FunctionPropertyOf<T> = {
[P in keyof T]: T[P] extends Function
[P in keyof T]: T[P] extends AnyFunction
? P
: never
}[keyof T];

View File

@ -115,8 +115,8 @@ export async function fetchAvailableEffects() {
const effects = result.effects.map(buildApiAvailableEffect);
const stickers : ApiSticker[] = [];
const emojis : ApiSticker[] = [];
const stickers: ApiSticker[] = [];
const emojis: ApiSticker[] = [];
for (const effect of effects) {
if (effect.effectAnimationId) {
@ -126,7 +126,9 @@ export async function fetchAvailableEffects() {
} else {
const document = localDb.documents[effect.effectStickerId];
const sticker = buildStickerFromDocument(document);
if (sticker) { stickers.push(sticker); }
if (sticker) {
stickers.push(sticker);
}
}
}

View File

@ -57,7 +57,7 @@ export async function fetchSavedStarGifts({
}) {
type GetSavedStarGiftsParams = ConstructorParameters<typeof GramJs.payments.GetSavedStarGifts>[0];
const params : GetSavedStarGiftsParams = {
const params: GetSavedStarGiftsParams = {
peer: buildInputPeer(peer.id, peer.accessHash),
offset,
limit,

View File

@ -113,7 +113,7 @@ export async function fetchMessagePublicForwards({
forwards?: ApiMessagePublicForward[];
count?: number;
nextOffset?: string;
} | undefined> {
} | undefined> {
const result = await invokeRequest(new GramJs.stats.GetMessagePublicForwards({
channel: buildInputChannel(chat.id, chat.accessHash),
msgId: messageId,
@ -196,7 +196,7 @@ export async function fetchStoryPublicForwards({
publicForwards: (ApiMessagePublicForward | ApiStoryPublicForward)[] | undefined;
count?: number;
nextOffset?: string;
} | undefined> {
} | undefined> {
const result = await invokeRequest(new GramJs.stats.GetStoryPublicForwards({
peer: buildInputPeer(chat.id, chat.accessHash),
id: storyId,

View File

@ -317,7 +317,7 @@ export async function fetchStoriesViews({
};
}
export async function fetchStoryLink({ peer, storyId }: { peer: ApiPeer ; storyId: number }) {
export async function fetchStoryLink({ peer, storyId }: { peer: ApiPeer; storyId: number }) {
const result = await invokeRequest(new GramJs.stories.ExportStoryLink({
peer: buildInputPeer(peer.id, peer.accessHash),
id: storyId,

View File

@ -7,8 +7,8 @@ import {
} from './client';
const emailCodeController: {
resolve?: Function;
reject?: Function;
resolve?: (code: string) => void;
reject?: (error: Error) => void;
} = {};
export async function getPasswordInfo() {

View File

@ -1,8 +1,7 @@
import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import type {
ApiChat, ApiEmojiStatusType, ApiPeer, ApiUser,
import type { ApiEmojiStatusType, ApiPeer, ApiUser,
} from '../../types';
import { buildApiChatFromPreview } from '../apiBuilders/chats';
@ -147,7 +146,7 @@ export async function fetchContactList() {
return undefined;
}
const users = result.users.map(buildApiUser).filter(Boolean) as ApiUser[];
const users = result.users.map(buildApiUser).filter(Boolean);
const userStatusesById = buildApiUserStatuses(result.users);
return {
@ -164,7 +163,7 @@ export async function fetchUsers({ users }: { users: ApiUser[] }) {
return undefined;
}
const apiUsers = result.map(buildApiUser).filter(Boolean) as ApiUser[];
const apiUsers = result.map(buildApiUser).filter(Boolean);
const userStatusesById = buildApiUserStatuses(result);
return {
@ -278,7 +277,7 @@ export async function fetchProfilePhotos({
offset?: number;
limit?: number;
}) {
const chat = 'title' in peer ? peer as ApiChat : undefined;
const chat = 'title' in peer ? peer : undefined;
const user = !chat ? peer as ApiUser : undefined;
if (user) {
const { id, accessHash } = user;

View File

@ -1,4 +1,3 @@
/* eslint-disable max-classes-per-file */
import type { BigInteger } from 'big-integer';
export class LocalUpdatePts {

View File

@ -44,7 +44,7 @@ function flushUpdates(throttleId: number) {
return;
}
const currentUpdates = pendingUpdates!;
const currentUpdates = pendingUpdates;
pendingUpdates = undefined;
currentUpdates.forEach(onUpdate);
}

View File

@ -217,7 +217,6 @@ export function updater(update: Update) {
peerId: message.chatId,
});
} else if (action instanceof GramJs.MessageActionChatDeleteUser) {
// eslint-disable-next-line no-underscore-dangle
if (update._entities && update._entities.some((e): e is GramJs.User => (
e instanceof GramJs.User && Boolean(e.self) && e.id === action.userId
))) {
@ -231,7 +230,6 @@ export function updater(update: Update) {
});
}
} else if (action instanceof GramJs.MessageActionChatAddUser) {
// eslint-disable-next-line no-underscore-dangle
if (update._entities && update._entities.some((e): e is GramJs.User => (
e instanceof GramJs.User && Boolean(e.self) && action.users.includes(e.id)
))) {
@ -263,13 +261,13 @@ export function updater(update: Update) {
sendApiUpdate({
'@type': 'updateTopic',
chatId: getApiChatIdFromMtpPeer(update.message.peerId!),
chatId: getApiChatIdFromMtpPeer(update.message.peerId),
topicId,
});
} else if (action instanceof GramJs.MessageActionTopicCreate) {
sendApiUpdate({
'@type': 'updateTopics',
chatId: getApiChatIdFromMtpPeer(update.message.peerId!),
chatId: getApiChatIdFromMtpPeer(update.message.peerId),
});
}
}
@ -659,7 +657,6 @@ export function updater(update: Update) {
typingStatus: buildChatTypingStatus(update),
});
} else if (update instanceof GramJs.UpdateChannel) {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { _entities } = update;
if (!_entities) {
return;

View File

@ -76,7 +76,6 @@ export function processUpdate(update: Update, isFromDifference?: boolean, should
if (update instanceof GramJs.Updates || update instanceof GramJs.UpdatesCombined) {
if (isFromDifference) {
// eslint-disable-next-line no-underscore-dangle
(update as SeqUpdate)._isFromDifference = true;
}
@ -90,7 +89,6 @@ export function processUpdate(update: Update, isFromDifference?: boolean, should
return;
}
if (isFromDifference) {
// eslint-disable-next-line no-underscore-dangle
(update as PtsUpdate)._isFromDifference = true;
}
savePtsUpdate(update, shouldOnlySave);
@ -145,7 +143,6 @@ function applyUpdate(updateObject: SeqUpdate | PtsUpdate) {
updateObject.updates.forEach((update) => {
if (entities) {
// eslint-disable-next-line no-underscore-dangle
(update as any)._entities = entities;
}
@ -180,7 +177,6 @@ function popSeqQueue() {
const localSeq = localDb.commonBoxState.seq;
const seqStart = 'seqStart' in update ? update.seqStart : update.seq;
// eslint-disable-next-line no-underscore-dangle
if (seqStart === 0 || (update._isFromDifference && seqStart >= localSeq + 1)) {
applyUpdate(update);
} else if (seqStart === localSeq + 1) {
@ -210,13 +206,12 @@ function popPtsQueue(channelId: string) {
if (localPts === undefined) {
if (DEBUG) {
// Uncomment to debug missing updates
// eslint-disable-next-line no-console
// console.error('[UpdateManager] Got pts update without local state', channelId);
}
return;
}
// eslint-disable-next-line no-underscore-dangle
if (update._isFromDifference && pts >= localPts + ptsCount) {
applyUpdate(update);
} else if (pts === localPts + ptsCount) {

View File

@ -15,12 +15,14 @@ import { pause, throttleWithTickEnd } from '../../../util/schedulers';
type RequestState = {
messageId: string;
resolve: Function;
reject: Function;
resolve: AnyToVoidFunction;
reject: AnyToVoidFunction;
callback?: AnyToVoidFunction;
DEBUG_payload?: any;
};
type EnsurePromise<T> = Promise<Awaited<T>>;
const HEALTH_CHECK_TIMEOUT = 150;
const HEALTH_CHECK_MIN_DELAY = 5 * 1000; // 5 sec
const NO_QUEUE_BEFORE_INIT = new Set(['destroy']);
@ -153,16 +155,18 @@ export function setShouldEnableDebugLog(value: boolean) {
* Call a worker method on this tab's worker, without transferring to master tab
* Mostly needed to disconnect worker when re-electing master
*/
export function callApiLocal<T extends keyof Methods>(fnName: T, ...args: MethodArgs<T>) {
export function callApiLocal<T extends keyof Methods>(
fnName: T, ...args: MethodArgs<T>
): EnsurePromise<MethodResponse<T>> {
if (!isInited) {
if (NO_QUEUE_BEFORE_INIT.has(fnName)) {
return Promise.resolve(undefined) as MethodResponse<T>;
return Promise.resolve(undefined) as EnsurePromise<MethodResponse<T>>;
}
const deferred = new Deferred();
localApiRequestsQueue.push({ fnName, args, deferred });
return deferred.promise as MethodResponse<T>;
return deferred.promise as EnsurePromise<MethodResponse<T>>;
}
const promise = makeRequest({
@ -194,19 +198,19 @@ export function callApiLocal<T extends keyof Methods>(fnName: T, ...args: Method
})();
}
return promise as MethodResponse<T>;
return promise as EnsurePromise<MethodResponse<T>>;
}
export function callApi<T extends keyof Methods>(fnName: T, ...args: MethodArgs<T>) {
export function callApi<T extends keyof Methods>(fnName: T, ...args: MethodArgs<T>): EnsurePromise<MethodResponse<T>> {
if (!isInited && isMasterTab) {
if (NO_QUEUE_BEFORE_INIT.has(fnName)) {
return Promise.resolve(undefined) as MethodResponse<T>;
return Promise.resolve(undefined) as EnsurePromise<MethodResponse<T>>;
}
const deferred = new Deferred();
apiRequestsQueue.push({ fnName, args, deferred });
return deferred.promise as MethodResponse<T>;
return deferred.promise as EnsurePromise<MethodResponse<T>>;
}
const promise = isMasterTab ? makeRequest({
@ -241,7 +245,7 @@ export function callApi<T extends keyof Methods>(fnName: T, ...args: MethodArgs<
})();
}
return promise as MethodResponse<T>;
return promise as EnsurePromise<MethodResponse<T>>;
}
export function cancelApiProgress(progressCallback: ApiOnProgress) {
@ -274,7 +278,6 @@ function subscribeToWorker(onUpdate: OnApiUpdate) {
worker?.addEventListener('message', ({ data }: WorkerMessageEvent) => {
data?.payloads.forEach((payload) => {
if (payload.type === 'updates') {
// eslint-disable-next-line @typescript-eslint/naming-convention
let DEBUG_startAt: number | undefined;
if (DEBUG) {
DEBUG_startAt = performance.now();

View File

@ -54,7 +54,7 @@ onmessage = ({ data }: OriginMessageEvent) => {
switch (payload.type) {
case 'initApi': {
const { messageId, args } = payload;
await initApi(onUpdate, args[0], args[1]);
initApi(onUpdate, args[0], args[1]);
if (messageId) {
sendToOrigin({
type: 'methodResponse',

View File

@ -253,7 +253,7 @@ export interface ApiTopic {
isPinned?: boolean;
isHidden?: boolean;
isOwner?: boolean;
// eslint-disable-next-line max-len
// TODO[forums] https://github.com/telegramdesktop/tdesktop/blob/1aece79a471d99a8b63d826b1bce1f36a04d7293/Telegram/SourceFiles/data/data_forum_topic.cpp#L318
isMin?: boolean;
date: number;

View File

@ -271,13 +271,13 @@ export interface ApiMessageActionExpiredContent extends ActionMediaType {
export interface ApiMessageActionPaidMessagesRefunded extends ActionMediaType {
type: 'paidMessagesRefunded';
count:number;
stars:number;
count: number;
stars: number;
}
export interface ApiMessageActionPaidMessagesPrice extends ActionMediaType {
type: 'paidMessagesPrice';
stars:number;
stars: number;
}
export interface ApiMessageActionUnsupported extends ActionMediaType {
@ -285,16 +285,16 @@ export interface ApiMessageActionUnsupported extends ActionMediaType {
}
export type ApiMessageAction = ApiMessageActionUnsupported | ApiMessageActionChatCreate | ApiMessageActionChatEditTitle
| ApiMessageActionChatEditPhoto | ApiMessageActionChatDeletePhoto | ApiMessageActionChatAddUser
| ApiMessageActionChatDeleteUser | ApiMessageActionChatJoinedByLink | ApiMessageActionChannelCreate
| ApiMessageActionChatMigrateTo | ApiMessageActionChannelMigrateFrom | ApiMessageActionPinMessage
| ApiMessageActionHistoryClear | ApiMessageActionGameScore | ApiMessageActionPaymentSent | ApiMessageActionPhoneCall
| ApiMessageActionScreenshotTaken | ApiMessageActionCustomAction | ApiMessageActionBotAllowed
| ApiMessageActionBoostApply | ApiMessageActionContactSignUp | ApiMessageActionExpiredContent
| ApiMessageActionGroupCall | ApiMessageActionInviteToGroupCall | ApiMessageActionGroupCallScheduled
| ApiMessageActionChatJoinedByRequest | ApiMessageActionWebViewDataSent | ApiMessageActionGiftPremium
| ApiMessageActionTopicCreate | ApiMessageActionTopicEdit | ApiMessageActionSuggestProfilePhoto
| ApiMessageActionChannelJoined | ApiMessageActionGiftCode | ApiMessageActionGiveawayLaunch
| ApiMessageActionGiveawayResults | ApiMessageActionPaymentRefunded | ApiMessageActionGiftStars
| ApiMessageActionPrizeStars | ApiMessageActionStarGift | ApiMessageActionStarGiftUnique
| ApiMessageActionPaidMessagesRefunded | ApiMessageActionPaidMessagesPrice;
| ApiMessageActionChatEditPhoto | ApiMessageActionChatDeletePhoto | ApiMessageActionChatAddUser
| ApiMessageActionChatDeleteUser | ApiMessageActionChatJoinedByLink | ApiMessageActionChannelCreate
| ApiMessageActionChatMigrateTo | ApiMessageActionChannelMigrateFrom | ApiMessageActionPinMessage
| ApiMessageActionHistoryClear | ApiMessageActionGameScore | ApiMessageActionPaymentSent | ApiMessageActionPhoneCall
| ApiMessageActionScreenshotTaken | ApiMessageActionCustomAction | ApiMessageActionBotAllowed
| ApiMessageActionBoostApply | ApiMessageActionContactSignUp | ApiMessageActionExpiredContent
| ApiMessageActionGroupCall | ApiMessageActionInviteToGroupCall | ApiMessageActionGroupCallScheduled
| ApiMessageActionChatJoinedByRequest | ApiMessageActionWebViewDataSent | ApiMessageActionGiftPremium
| ApiMessageActionTopicCreate | ApiMessageActionTopicEdit | ApiMessageActionSuggestProfilePhoto
| ApiMessageActionChannelJoined | ApiMessageActionGiftCode | ApiMessageActionGiveawayLaunch
| ApiMessageActionGiveawayResults | ApiMessageActionPaymentRefunded | ApiMessageActionGiftStars
| ApiMessageActionPrizeStars | ApiMessageActionStarGift | ApiMessageActionStarGiftUnique
| ApiMessageActionPaidMessagesRefunded | ApiMessageActionPaidMessagesPrice;

View File

@ -474,8 +474,8 @@ export type ApiMessageEntityQuoteFocus = {
};
export type ApiMessageEntity = ApiMessageEntityDefault | ApiMessageEntityPre | ApiMessageEntityTextUrl |
ApiMessageEntityMentionName | ApiMessageEntityCustomEmoji | ApiMessageEntityBlockquote | ApiMessageEntityTimestamp |
ApiMessageEntityQuoteFocus;
ApiMessageEntityMentionName | ApiMessageEntityCustomEmoji | ApiMessageEntityBlockquote | ApiMessageEntityTimestamp |
ApiMessageEntityQuoteFocus;
export enum ApiMessageEntityTypes {
Bold = 'MessageEntityBold',
@ -695,7 +695,7 @@ export type ApiSavedReactionTag = {
};
export type ApiPaidReactionPrivacyType = ApiPaidReactionPrivacyDefault |
ApiPaidReactionPrivacyAnonymous | PaidReactionPrivacyPeer;
ApiPaidReactionPrivacyAnonymous | PaidReactionPrivacyPeer;
export type ApiPaidReactionPrivacyDefault = {
type: 'default';
@ -870,7 +870,7 @@ export type ApiGlobalMessageSearchType = 'text' | 'channels' | 'media' | 'docume
export type ApiMessageSearchContext = 'all' | 'users' | 'groups' | 'channels';
export type ApiReportReason = 'spam' | 'violence' | 'pornography' | 'childAbuse'
| 'copyright' | 'geoIrrelevant' | 'fake' | 'illegalDrugs' | 'personalDetails' | 'other';
| 'copyright' | 'geoIrrelevant' | 'fake' | 'illegalDrugs' | 'personalDetails' | 'other';
export type ApiSendMessageAction = {
type: 'cancel' | 'typing' | 'recordAudio' | 'chooseSticker' | 'playingGame';

View File

@ -189,7 +189,7 @@ export type ApiInputStorePaymentStarsGiveaway = {
};
export type ApiInputStorePaymentPurpose = ApiInputStorePaymentGiveaway | ApiInputStorePaymentGiftcode |
ApiInputStorePaymentStarsTopup | ApiInputStorePaymentStarsGift | ApiInputStorePaymentStarsGiveaway;
ApiInputStorePaymentStarsTopup | ApiInputStorePaymentStarsGift | ApiInputStorePaymentStarsGiveaway;
export interface ApiPremiumGiftCodeOption {
users: number;
@ -399,9 +399,9 @@ export type ApiInputInvoiceStarGiftTransfer = {
};
export type ApiInputInvoice = ApiInputInvoiceMessage | ApiInputInvoiceSlug | ApiInputInvoiceGiveaway
| ApiInputInvoiceGiftCode | ApiInputInvoicePremiumGiftStars | ApiInputInvoiceStars | ApiInputInvoiceStarsGift
| ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription
| ApiInputInvoiceStarGiftUpgrade | ApiInputInvoiceStarGiftTransfer | ApiInputInvoiceStarGiftResale;
| ApiInputInvoiceGiftCode | ApiInputInvoicePremiumGiftStars | ApiInputInvoiceStars | ApiInputInvoiceStarsGift
| ApiInputInvoiceStarsGiveaway | ApiInputInvoiceStarGift | ApiInputInvoiceChatInviteSubscription
| ApiInputInvoiceStarGiftUpgrade | ApiInputInvoiceStarGiftTransfer | ApiInputInvoiceStarGiftResale;
/* Used for Invoice request */
export type ApiRequestInputInvoiceMessage = {
@ -471,7 +471,7 @@ export type ApiRequestInputInvoiceStarGiftTransfer = {
};
export type ApiRequestInputInvoice = ApiRequestInputInvoiceMessage | ApiRequestInputInvoiceSlug
| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway
| ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift | ApiRequestInputInvoiceStarGiftUpgrade
| ApiRequestInputInvoiceStarGiftTransfer | ApiRequestInputInvoicePremiumGiftStars
| ApiRequestInputInvoiceStarGiftResale;
| ApiRequestInputInvoiceGiveaway | ApiRequestInputInvoiceStars | ApiRequestInputInvoiceStarsGiveaway
| ApiRequestInputInvoiceChatInviteSubscription | ApiRequestInputInvoiceStarGift
| ApiRequestInputInvoiceStarGiftUpgrade | ApiRequestInputInvoiceStarGiftTransfer
| ApiRequestInputInvoicePremiumGiftStars | ApiRequestInputInvoiceStarGiftResale;

View File

@ -2,7 +2,7 @@ import type { ApiChat } from './chats';
import type { ApiUser } from './users';
export type ApiPrivacyKey = 'phoneNumber' | 'addByPhone' | 'lastSeen' | 'profilePhoto' | 'voiceMessages' |
'forwards' | 'chatInvite' | 'phoneCall' | 'phoneP2P' | 'bio' | 'birthday' | 'gifts' | 'noPaidMessages';
'forwards' | 'chatInvite' | 'phoneCall' | 'phoneP2P' | 'bio' | 'birthday' | 'gifts' | 'noPaidMessages';
export type PrivacyVisibility = 'everybody' | 'contacts' | 'closeFriends' | 'nonContacts' | 'nobody';
export type BotsPrivacyType = 'allow' | 'disallow' | 'none';

View File

@ -71,7 +71,7 @@ export interface ApiStarGiftAttributeOriginalDetails {
}
export type ApiStarGiftAttribute = ApiStarGiftAttributeModel | ApiStarGiftAttributePattern
| ApiStarGiftAttributeBackdrop | ApiStarGiftAttributeOriginalDetails;
| ApiStarGiftAttributeBackdrop | ApiStarGiftAttributeOriginalDetails;
export interface ApiSavedStarGift {
isNameHidden?: boolean;
@ -155,14 +155,14 @@ export interface ApiStarsTransactionPeerPeer {
}
export type ApiStarsTransactionPeer =
| ApiStarsTransactionPeerUnsupported
| ApiStarsTransactionPeerAppStore
| ApiStarsTransactionPeerPlayMarket
| ApiStarsTransactionPeerPremiumBot
| ApiStarsTransactionPeerFragment
| ApiStarsTransactionPeerAds
| ApiStarsTransactionApi
| ApiStarsTransactionPeerPeer;
| ApiStarsTransactionPeerUnsupported
| ApiStarsTransactionPeerAppStore
| ApiStarsTransactionPeerPlayMarket
| ApiStarsTransactionPeerPremiumBot
| ApiStarsTransactionPeerFragment
| ApiStarsTransactionPeerAds
| ApiStarsTransactionApi
| ApiStarsTransactionPeerPeer;
export interface ApiStarsTransaction {
id?: string;

View File

@ -183,4 +183,4 @@ export type ApiMediaAreaUniqueGift = {
};
export type ApiMediaArea = ApiMediaAreaVenue | ApiMediaAreaGeoPoint | ApiMediaAreaSuggestedReaction
| ApiMediaAreaChannelPost | ApiMediaAreaUrl | ApiMediaAreaWeather | ApiMediaAreaUniqueGift;
| ApiMediaAreaChannelPost | ApiMediaAreaUrl | ApiMediaAreaWeather | ApiMediaAreaUniqueGift;

View File

@ -1588,6 +1588,9 @@
"PrivacyEnablePremiumGifts" = "Enable Premium Gifts";
"DisplayGiftsButton" = "Display Gifts Button";
"HideGiftsButton" = "Hide Gifts Button";
"Review" = "Review";
"CheckPrivacyCallsText" = "You've restricted who can message you, but anyone can still call you. Would you like to review these settings?";
"CheckPrivacyInviteText" = "You've restricted who can message you, but anyone can still invite you to groups and channels. Would you like to review these settings?";
"CustomShareGiftsInfo" = "You can add users or entire groups as exceptions that will override the settings above.";
"StarsSubscribeBotText_one" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** star per month?";
"StarsSubscribeBotText_other" = "Do you want to subscribe to **{name}** in **{bot}** for **{amount}** stars per month?";

View File

@ -128,7 +128,7 @@ const App: FC<StateProps> = ({
// return <Test />;
let activeKey: number;
let activeKey: AppScreens;
let page: UiLoaderPage | undefined;
if (isInactive) {
@ -200,7 +200,6 @@ const App: FC<StateProps> = ({
const prevActiveKey = usePreviousDeprecated(activeKey);
// eslint-disable-next-line consistent-return
function renderContent() {
switch (activeKey) {
case AppScreens.auth:

View File

@ -46,8 +46,7 @@ const Auth: FC<StateProps> = ({
onBack: handleChangeAuthorizationMethod,
});
// eslint-disable-next-line no-null/no-null
const containerRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>();
useElectronDrag(containerRef);
// For animation purposes

View File

@ -35,8 +35,7 @@ const AuthCode: FC<StateProps> = ({
} = getActions();
const lang = useLang();
// eslint-disable-next-line no-null/no-null
const inputRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLInputElement>();
const [code, setCode] = useState<string>('');
const [isTracking, setIsTracking] = useState(false);

View File

@ -73,8 +73,7 @@ const AuthPhoneNumber: FC<StateProps> = ({
} = getActions();
const lang = useLang();
// eslint-disable-next-line no-null/no-null
const inputRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLInputElement>();
const suggestedLanguage = getSuggestedLanguage();
const isConnected = connectionState === 'connectionStateReady';
@ -207,11 +206,11 @@ const AuthPhoneNumber: FC<StateProps> = ({
IS_SAFARI && country && fullNumber !== undefined
&& value.length - fullNumber.length > 1 && !isJustPastedRef.current
);
parseFullNumber(shouldFixSafariAutoComplete ? `${country!.countryCode} ${value}` : value);
parseFullNumber(shouldFixSafariAutoComplete ? `${country.countryCode} ${value}` : value);
});
const handleKeepSessionChange = useLastCallback((e: ChangeEvent<HTMLInputElement>) => {
setAuthRememberMe(e.target.checked);
setAuthRememberMe({ value: e.target.checked });
});
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {

View File

@ -40,7 +40,7 @@ const QR_SIZE = 280;
const QR_PLANE_SIZE = 54;
const QR_CODE_MUTATION_DURATION = 50; // The library is asynchronous and we need to wait for its mutation code
let qrCodeStylingPromise: Promise<typeof import('qr-code-styling')>;
let qrCodeStylingPromise: Promise<typeof import('qr-code-styling')> | undefined;
function ensureQrCodeStyling() {
if (!qrCodeStylingPromise) {
@ -62,8 +62,7 @@ const AuthCode = ({
const suggestedLanguage = getSuggestedLanguage();
const lang = useLang();
// eslint-disable-next-line no-null/no-null
const qrCodeRef = useRef<HTMLDivElement>(null);
const qrCodeRef = useRef<HTMLDivElement>();
const isConnected = connectionState === 'connectionStateReady';
const continueText = useLangString('AuthContinueOnThisLanguage', suggestedLanguage);
@ -133,7 +132,7 @@ const AuthCode = ({
}
return undefined;
}, [isConnected, authQrCode, isQrMounted, markQrMounted, unmarkQrMounted, qrCode]);
}, [isConnected, authQrCode, isQrMounted, qrCode]);
const handleBackNavigation = useLastCallback(() => {
navigateBack();

View File

@ -44,8 +44,7 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
phoneCodeList,
}) => {
const lang = useLang();
// eslint-disable-next-line no-null/no-null
const inputRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLInputElement>();
const [filter, setFilter] = useState<string | undefined>();
const [filteredList, setFilteredList] = useState<ApiCountryCode[]>([]);
@ -105,7 +104,7 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
handleTrigger();
};
const emoji = value && IS_EMOJI_SUPPORTED && renderText(isoToEmoji(value.iso2), ['hq_emoji']);
const emoji = value && IS_EMOJI_SUPPORTED && isoToEmoji(value.iso2);
const name = value?.name || value?.defaultName || '';
const inputValue = filter ?? [emoji, name].filter(Boolean).join(' ');
@ -143,12 +142,15 @@ const CountryCodeInput: FC<OwnProps & StateProps> = ({
<MenuItem
key={`${country.iso2}-${country.countryCode}`}
className={value && country.iso2 === value.iso2 ? 'selected' : ''}
// eslint-disable-next-line react/jsx-no-bind
onClick={() => handleChange(country)}
>
<span className="country-flag">{renderText(isoToEmoji(country.iso2), ['hq_emoji'])}</span>
<span className="country-name">{country.name || country.defaultName}</span>
<span className="country-code">+{country.countryCode}</span>
<span className="country-code">
+
{country.countryCode}
</span>
</MenuItem>
))}
{!filteredList.length && (

View File

@ -29,11 +29,11 @@ const ActiveCallHeader: FC<StateProps> = ({
useEffect(() => {
document.body.classList.toggle('has-call-header', Boolean(isCallPanelVisible));
window.electron?.setTrafficLightPosition(isCallPanelVisible ? 'lowered' : 'standard');
window.electron?.setWindowButtonsPosition(isCallPanelVisible ? 'lowered' : 'standard');
return () => {
document.body.classList.toggle('has-call-header', false);
window.electron?.setTrafficLightPosition('standard');
window.electron?.setWindowButtonsPosition('standard');
};
}, [isCallPanelVisible]);

View File

@ -11,7 +11,6 @@ const GroupCallAsync: FC<OwnProps> = (props) => {
const { groupCallId } = props;
const GroupCall = useModuleLoader(Bundles.Calls, 'GroupCall', !groupCallId);
// eslint-disable-next-line react/jsx-props-no-spreading
return GroupCall ? <GroupCall {...props} /> : undefined;
};

View File

@ -80,18 +80,13 @@ const GroupCall: FC<OwnProps & StateProps> = ({
} = getActions();
const lang = useOldLang();
// eslint-disable-next-line no-null/no-null
const containerRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>();
// eslint-disable-next-line no-null/no-null
const primaryVideoContainerRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
const secondaryVideoContainerRef = useRef<HTMLDivElement>(null);
const primaryVideoContainerRef = useRef<HTMLDivElement>();
const secondaryVideoContainerRef = useRef<HTMLDivElement>();
// eslint-disable-next-line no-null/no-null
const panelScrollTriggerRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
const panelRef = useRef<HTMLDivElement>(null);
const panelScrollTriggerRef = useRef<HTMLDivElement>();
const panelRef = useRef<HTMLDivElement>();
const [isLeaving, setIsLeaving] = useState(false);
const isOpen = !isCallPanelVisible && !isLeaving;
@ -560,7 +555,7 @@ export default memo(withGlobal<OwnProps>(
(global, { groupCallId }): StateProps => {
const {
connectionState, title, participants, participantsCount, chatId,
} = selectGroupCall(global, groupCallId)! || {};
} = selectGroupCall(global, groupCallId) || {};
const chat = chatId ? selectChat(global, chatId) : undefined;

View File

@ -38,10 +38,8 @@ const GroupCallParticipant: FC<OwnProps & StateProps> = ({
participant,
peer,
}) => {
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
const menuRef = useRef<HTMLDivElement>(null);
const ref = useRef<HTMLDivElement>();
const menuRef = useRef<HTMLDivElement>();
const lang = useOldLang();
const {

View File

@ -1,4 +1,4 @@
import type { FC } from '../../../lib/teact/teact';
import type { ElementRef, FC } from '../../../lib/teact/teact';
import React, { memo, useEffect, useState } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
@ -31,7 +31,7 @@ type OwnProps =
onCloseAnimationEnd: VoidFunction;
onClose: VoidFunction;
isDropdownOpen: boolean;
menuRef?: React.RefObject<HTMLDivElement>;
menuRef?: ElementRef<HTMLDivElement>;
}
& MenuPositionOptions;
@ -172,7 +172,7 @@ const GroupCallParticipantMenu: FC<OwnProps & StateProps> = ({
onClose={onClose}
onCloseAnimationEnd={onCloseAnimationEnd}
className="participant-menu with-menu-transitions"
// eslint-disable-next-line react/jsx-props-no-spreading
{...menuPositionOptions}
>
{!isSelf && !shouldRaiseHand && (
@ -199,7 +199,10 @@ const GroupCallParticipantMenu: FC<OwnProps & StateProps> = ({
playSegment={speakerIconPlaySegment}
size={SPEAKER_ICON_SIZE}
/>
<span>{localVolume}%</span>
<span>
{localVolume}
%
</span>
</div>
</div>
</div>

View File

@ -63,12 +63,9 @@ const GroupCallParticipantVideo: FC<OwnProps & StateProps> = ({
}) => {
const lang = useOldLang();
// eslint-disable-next-line no-null/no-null
const thumbnailRef = useRef<HTMLCanvasElement>(null);
// eslint-disable-next-line no-null/no-null
const videoRef = useRef<HTMLVideoElement>(null);
// eslint-disable-next-line no-null/no-null
const videoFallbackRef = useRef<HTMLCanvasElement>(null);
const thumbnailRef = useRef<HTMLCanvasElement>();
const videoRef = useRef<HTMLVideoElement>();
const videoFallbackRef = useRef<HTMLCanvasElement>();
const {
x, y, width, height, noAnimate, isRemoved,
@ -202,10 +199,8 @@ const GroupCallParticipantVideo: FC<OwnProps & StateProps> = ({
};
}, [stream]);
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
const menuRef = useRef<HTMLDivElement>(null);
const ref = useRef<HTMLDivElement>();
const menuRef = useRef<HTMLDivElement>();
const {
isContextMenuOpen,

View File

@ -1,4 +1,5 @@
import type { RefObject } from 'react';
import type {
ElementRef } from '../../../../lib/teact/teact';
import {
useEffect, useMemo, useState,
} from '../../../../lib/teact/teact';
@ -37,8 +38,8 @@ export default function useGroupCallVideoLayout({
isLandscapeLayout,
pinnedVideo,
}: {
primaryContainerRef: RefObject<HTMLDivElement>;
secondaryContainerRef: RefObject<HTMLDivElement>;
primaryContainerRef: ElementRef<HTMLDivElement>;
secondaryContainerRef: ElementRef<HTMLDivElement>;
videoParticipants: VideoParticipant[];
isLandscapeLayout: boolean;
pinnedVideo: VideoParticipant | undefined;

View File

@ -55,8 +55,7 @@ const PhoneCall: FC<StateProps> = ({
const {
hangUp, requestMasterAndAcceptCall, playGroupCallSound, toggleGroupCallPanel, connectToActivePhoneCall,
} = getActions();
// eslint-disable-next-line no-null/no-null
const containerRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>();
const [isFullscreen, openFullscreen, closeFullscreen] = useFlag();
const { isMobile } = useAppLayout();

View File

@ -11,7 +11,6 @@ const RatePhoneCallModalAsync: FC<OwnProps> = (props) => {
const { isOpen } = props;
const RatePhoneCallModal = useModuleLoader(Bundles.Calls, 'RatePhoneCallModal', !isOpen);
// eslint-disable-next-line react/jsx-props-no-spreading
return RatePhoneCallModal ? <RatePhoneCallModal {...props} /> : undefined;
};

View File

@ -24,8 +24,7 @@ const RatePhoneCallModal: FC<OwnProps> = ({
}) => {
const { closeCallRatingModal, setCallRating } = getActions();
// eslint-disable-next-line no-null/no-null
const inputRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLInputElement>();
const lang = useOldLang();
const [rating, setRating] = useState<number | undefined>();

View File

@ -11,7 +11,6 @@ const AboutMonetizationModalAsync: FC<OwnProps> = (props) => {
const { isOpen } = props;
const AboutMonetizationModal = useModuleLoader(Bundles.Extra, 'AboutMonetizationModal', !isOpen);
// eslint-disable-next-line react/jsx-props-no-spreading
return AboutMonetizationModal ? <AboutMonetizationModal {...props} /> : undefined;
};

View File

@ -1,4 +1,4 @@
import type { FC } from '../../lib/teact/teact';
import type { ElementRef, FC } from '../../lib/teact/teact';
import React, { memo, useEffect, useMemo } from '../../lib/teact/teact';
import { getGlobal } from '../../global';
@ -16,7 +16,7 @@ type OwnProps = {
text: string;
className?: string;
isDisabled?: boolean;
ref?: React.RefObject<HTMLSpanElement>;
ref?: ElementRef<HTMLSpanElement>;
};
const ANIMATION_TIME = 200;

View File

@ -54,7 +54,7 @@ function AnimatedIcon(props: OwnProps) {
noLoop={noLoop}
onClick={!nonInteractive ? handleClick : undefined}
onLoad={handleLoad}
/* eslint-disable-next-line react/jsx-props-no-spreading */
{...otherProps}
/>
);

View File

@ -33,7 +33,7 @@ function AnimatedIconFromSticker(props: OwnProps) {
tgsUrl={tgsUrl}
previewUrl={previewBlobUrl}
thumbDataUri={thumbDataUri}
// eslint-disable-next-line react/jsx-props-no-spreading
{...otherProps}
/>
);

View File

@ -65,7 +65,7 @@ function AnimatedIconWithPreview(props: OwnProps) {
onLoad={handlePreviewLoad}
/>
)}
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
{ }
<AnimatedIcon {...otherProps} onLoad={handleAnimationReady} />
</div>
);

View File

@ -1,5 +1,4 @@
import type { RefObject } from 'react';
import type { FC } from '../../lib/teact/teact';
import type { ElementRef, FC } from '../../lib/teact/teact';
import React, {
getIsHeavyAnimating,
memo,
@ -33,7 +32,7 @@ import useUniqueId from '../../hooks/useUniqueId';
import useBackgroundMode, { isBackgroundModeActive } from '../../hooks/window/useBackgroundMode';
export type OwnProps = {
ref?: RefObject<HTMLDivElement>;
ref?: ElementRef<HTMLDivElement>;
renderId?: string;
className?: string;
style?: string;
@ -81,8 +80,7 @@ const AnimatedSticker: FC<OwnProps> = ({
onEnded,
onLoop,
}) => {
// eslint-disable-next-line no-null/no-null
let containerRef = useRef<HTMLDivElement>(null);
let containerRef = useRef<HTMLDivElement>();
if (ref) {
containerRef = ref;
}

View File

@ -1,4 +1,4 @@
import type { FC } from '../../lib/teact/teact';
import type { ElementRef, FC } from '../../lib/teact/teact';
import React, {
memo, useEffect, useLayoutEffect, useMemo, useRef, useState,
} from '../../lib/teact/teact';
@ -123,8 +123,7 @@ const Audio: FC<OwnProps> = ({
const mediaSource = (voice || video);
const isVoice = Boolean(voice || video);
const isSeeking = useRef<boolean>(false);
// eslint-disable-next-line no-null/no-null
const seekerRef = useRef<HTMLDivElement>(null);
const seekerRef = useRef<HTMLDivElement>();
const lang = useOldLang();
const { isRtl } = lang;
@ -504,7 +503,7 @@ function renderAudio(
isPlaying: boolean,
playProgress: number,
bufferedRanges: BufferedRange[],
seekerRef: React.Ref<HTMLElement>,
seekerRef: ElementRef<HTMLDivElement>,
showProgress?: boolean,
date?: number,
progress?: number,
@ -529,7 +528,8 @@ function renderAudio(
)}
{!showSeekline && showProgress && (
<div className="meta" dir={isRtl ? 'rtl' : undefined}>
{progress ? `${getFileSizeString(audio!.size * progress)} / ` : undefined}{getFileSizeString(audio!.size)}
{progress ? `${getFileSizeString(audio.size * progress)} / ` : undefined}
{getFileSizeString(audio.size)}
</div>
)}
{!showSeekline && !showProgress && (
@ -557,8 +557,8 @@ function renderAudio(
function renderVoice(
media: ApiVoice | ApiVideo,
seekerRef: React.Ref<HTMLDivElement>,
waveformCanvasRef: React.Ref<HTMLCanvasElement>,
seekerRef: ElementRef<HTMLDivElement>,
waveformCanvasRef: ElementRef<HTMLCanvasElement>,
playProgress: number,
isMediaUnread?: boolean,
isTranscribing?: boolean,
@ -580,7 +580,7 @@ function renderVoice(
<canvas ref={waveformCanvasRef} />
</div>
{onClickTranscribe && (
// eslint-disable-next-line react/jsx-no-bind
<Button onClick={() => {
if ((isTranscribed || isTranscriptionError) && onHideTranscription) {
onHideTranscription(!isTranscriptionHidden);
@ -621,7 +621,7 @@ function renderVoice(
dir="auto"
>
{playProgress === 0 || playProgress === 1
? formatMediaDuration(media!.duration) : formatMediaDuration(media!.duration * playProgress)}
? formatMediaDuration(media.duration) : formatMediaDuration(media.duration * playProgress)}
</p>
</div>
);
@ -636,8 +636,7 @@ function useWaveformCanvas(
isMobile = false,
isReverse = false,
) {
// eslint-disable-next-line no-null/no-null
const canvasRef = useRef<HTMLCanvasElement>(null);
const canvasRef = useRef<HTMLCanvasElement>();
const { data: spikes, peak } = useMemo(() => {
if (!media) {
@ -688,12 +687,12 @@ function useWaveformCanvas(
function renderSeekline(
playProgress: number,
bufferedRanges: BufferedRange[],
seekerRef: React.Ref<HTMLElement>,
seekerRef: ElementRef<HTMLDivElement>,
) {
return (
<div
className="seekline"
ref={seekerRef as React.Ref<HTMLDivElement>}
ref={seekerRef}
>
{bufferedRanges.map(({ start, end }) => (
<div

View File

@ -21,11 +21,11 @@ import {
isAnonymousForwardsChat,
isChatWithRepliesBot,
isDeletedUser,
isUserId,
} from '../../global/helpers';
import { isApiPeerChat, isApiPeerUser } from '../../global/helpers/peers';
import buildClassName, { createClassNameBuilder } from '../../util/buildClassName';
import buildStyle from '../../util/buildStyle';
import { isUserId } from '../../util/entities/ids';
import { getFirstLetters } from '../../util/textFormat';
import { REM } from './helpers/mediaDimensions';
import { getPeerColorClass } from './helpers/peerColor';
@ -115,8 +115,7 @@ const Avatar: FC<OwnProps> = ({
}) => {
const { openStoryViewer } = getActions();
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement>(null);
const ref = useRef<HTMLDivElement>();
const videoLoopCountRef = useRef(0);
const isCustomPeer = peer && 'isCustomPeer' in peer;
const realPeer = peer && !isCustomPeer ? peer : undefined;

View File

@ -13,7 +13,7 @@ import { REM } from './helpers/mediaDimensions';
import useDevicePixelRatio from '../../hooks/window/useDevicePixelRatio';
interface OwnProps {
// eslint-disable-next-line react/no-unused-prop-types
peerId: string;
className?: string;
size: number;
@ -53,8 +53,7 @@ function AvatarStoryCircle({
withExtraGap,
appTheme,
}: OwnProps & StateProps) {
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLCanvasElement>(null);
const ref = useRef<HTMLCanvasElement>();
const dpr = useDevicePixelRatio();

View File

@ -23,8 +23,7 @@ type OwnProps = {
const MAX_LINES = 4;
const Blockquote = ({ canBeCollapsible, isToggleDisabled, children }: OwnProps) => {
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLQuoteElement>(null);
const ref = useRef<HTMLQuoteElement>();
const {
isCollapsed, isCollapsible, setIsCollapsed,
} = useCollapsibleLines(ref, MAX_LINES, undefined, !canBeCollapsible);

View File

@ -11,7 +11,6 @@ const CalendarModalAsync: FC<OwnProps> = (props) => {
const { isOpen } = props;
const CalendarModal = useModuleLoader(Bundles.Extra, 'CalendarModal', !isOpen);
// eslint-disable-next-line react/jsx-props-no-spreading
return CalendarModal ? <CalendarModal {...props} /> : undefined;
};

View File

@ -42,10 +42,8 @@ const ChatForumLastMessage: FC<OwnProps> = ({
}) => {
const { openThread } = getActions();
// eslint-disable-next-line no-null/no-null
const lastMessageRef = useRef<HTMLDivElement>(null);
// eslint-disable-next-line no-null/no-null
const mainColumnRef = useRef<HTMLDivElement>(null);
const lastMessageRef = useRef<HTMLDivElement>();
const mainColumnRef = useRef<HTMLDivElement>();
const lang = useOldLang();

Some files were not shown because too many files have changed in this diff Show More