Bump dependencies (#6358)

This commit is contained in:
zubiden 2025-10-15 19:57:09 +02:00 committed by Alexander Zinchuk
parent 042193908b
commit 0a606739d1
74 changed files with 3221 additions and 2868 deletions

View File

@ -37,49 +37,107 @@
"ignore": "paint-properties" "ignore": "paint-properties"
} }
], ],
"plugin/stylelint-group-selectors": [true, { "severity": "warning" }], "plugin/stylelint-group-selectors": [
"plugin/whole-pixel": [true, { "ignoreList": ["letter-spacing"] }], true,
{
"severity": "warning"
}
],
"plugin/whole-pixel": [
true,
{
"ignoreList": [
"letter-spacing"
]
}
],
"selector-pseudo-class-no-unknown": [ "selector-pseudo-class-no-unknown": [
true, true,
{ {
"ignorePseudoClasses": ["global", "local"] "ignorePseudoClasses": [
"global",
"local"
]
}
],
"no-invalid-position-declaration": [
true,
{ "ignoreAtRules": ["mixin"] }
],
"nesting-selector-no-missing-scoping-root": [
true,
{ "ignoreAtRules": ["include", "mixin"] }
],
"plugin/selector-tag-no-without-class": [
"/^(?!body|html)([^_-]*)$/",
{
"severity": "warning"
}
],
"plugin/use-baseline": [
true,
{
"severity": "warning",
"ignoreSelectors": [
"nesting",
"dir",
"selection",
"view-transition",
"view-transition-group",
"view-transition-image-pair",
"view-transition-old",
"view-transition-new"
],
"ignoreProperties": {
"property-name": [
"text-wrap",
"outline",
"backdrop-filter",
"user-select",
"scrollbar-gutter",
"scrollbar-width",
"scrollbar-color",
"box-decoration-break",
"offset-anchor"
]
}
} }
], ],
"plugin/selector-tag-no-without-class": ["/^(?!body|html)([^_-]*)$/", { "severity": "warning" }],
"plugin/use-baseline": [true, {
"severity": "warning",
"ignoreSelectors": [
"nesting",
"dir",
"selection",
"view-transition",
"view-transition-group",
"view-transition-image-pair",
"view-transition-old",
"view-transition-new"
],
"ignoreProperties": [
"text-wrap",
"outline",
"backdrop-filter",
"user-select",
"scrollbar-gutter",
"scrollbar-width",
"scrollbar-color",
"box-decoration-break",
"offset-anchor"
]
}],
"@stylistic/number-leading-zero": "always", "@stylistic/number-leading-zero": "always",
"@stylistic/string-quotes": null, "@stylistic/string-quotes": null,
"@stylistic/color-hex-case": null, "@stylistic/color-hex-case": null,
"@stylistic/selector-list-comma-newline-after": null, "@stylistic/selector-list-comma-newline-after": null,
"@stylistic/block-closing-brace-newline-after": null, "@stylistic/block-closing-brace-newline-after": null,
"@stylistic/indentation": [2, { "ignore": ["value"] }], "@stylistic/indentation": [
"at-rule-empty-line-before": ["always", { "ignore": ["first-nested", "after-comment", "blockless-after-blockless"] }], 2,
"rule-empty-line-before": ["always", { {
"except": ["after-single-line-comment", "first-nested"], "ignore": [
"ignore": ["after-comment", "inside-block"] "value"
}] ]
}
],
"at-rule-empty-line-before": [
"always",
{
"ignore": [
"first-nested",
"after-comment",
"blockless-after-blockless"
]
}
],
"rule-empty-line-before": [
"always",
{
"except": [
"after-single-line-comment",
"first-nested"
],
"ignore": [
"after-comment",
"inside-block"
]
}
]
} }
} }

View File

@ -69,6 +69,7 @@ export default tseslint.config(
'no-undef': 'off', 'no-undef': 'off',
'no-unused-vars': 'off', 'no-unused-vars': 'off',
'@stylistic/multiline-ternary': 'off', '@stylistic/multiline-ternary': 'off',
'@stylistic/operator-linebreak': 'off',
'@stylistic/max-len': ['error', { '@stylistic/max-len': ['error', {
code: 120, code: 120,
ignoreComments: true, ignoreComments: true,
@ -202,6 +203,7 @@ export default tseslint.config(
'react-x/no-array-index-key': 'off', 'react-x/no-array-index-key': 'off',
'react-x/no-missing-key': 'off', 'react-x/no-missing-key': 'off',
'react-x/no-nested-component-definitions': 'off', 'react-x/no-nested-component-definitions': 'off',
'react-x/no-unused-props': 'off',
'react-x/no-leaked-conditional-rendering': 'error', 'react-x/no-leaked-conditional-rendering': 'error',
'jsx-a11y/click-events-have-key-events': 'off', 'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/mouse-events-have-key-events': 'off', 'jsx-a11y/mouse-events-have-key-events': 'off',

4228
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -40,88 +40,87 @@
"*.{css,scss}": "stylelint --fix" "*.{css,scss}": "stylelint --fix"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.27.4", "@babel/core": "^7.28.4",
"@babel/preset-env": "^7.27.2", "@babel/preset-env": "^7.28.3",
"@babel/preset-react": "^7.27.1", "@babel/preset-react": "^7.27.1",
"@babel/preset-typescript": "^7.27.1", "@babel/preset-typescript": "^7.27.1",
"@babel/register": "^7.27.1", "@babel/register": "^7.28.3",
"@eslint/js": "^9.29.0", "@eslint/js": "^9.37.0",
"@glen/jest-raw-loader": "^2.0.0", "@glen/jest-raw-loader": "^2.0.0",
"@mytonwallet/stylelint-whole-pixel": "github:mytonwallet-org/stylelint-whole-pixel#fd07e44d786460f7d469076b1d2cb1b05297896c", "@mytonwallet/stylelint-whole-pixel": "github:mytonwallet-org/stylelint-whole-pixel#6208102",
"@mytonwallet/webpack-watch-file-plugin": "github:mytonwallet-org/webpack-watch-file-plugin#747b7fd29da9a928aa8b63299adfba461d2f1231", "@mytonwallet/webpack-watch-file-plugin": "github:mytonwallet-org/webpack-watch-file-plugin#6c9386b",
"@playwright/test": "^1.53.0", "@playwright/test": "^1.56.0",
"@statoscope/cli": "5.29.0", "@statoscope/cli": "5.29.0",
"@statoscope/webpack-plugin": "5.29.0", "@statoscope/webpack-plugin": "5.29.0",
"@stylistic/eslint-plugin": "^4.4.1", "@stylistic/eslint-plugin": "^5.4.0",
"@stylistic/stylelint-config": "^2.0.0", "@stylistic/stylelint-config": "^3.0.1",
"@stylistic/stylelint-plugin": "^3.1.2", "@stylistic/stylelint-plugin": "^4.0.0",
"@tauri-apps/cli": "^2.8.0", "@tauri-apps/cli": "^2.8.4",
"@testing-library/jest-dom": "^6.6.3", "@testing-library/jest-dom": "^6.9.1",
"@twbs/fantasticon": "^3.1.0", "@twbs/fantasticon": "^3.1.0",
"@types/dom-view-transitions": "^1.0.6", "@types/dom-view-transitions": "^1.0.6",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^24.0.3", "@types/node": "^24.7.2",
"@types/react": "^19.1.8", "@types/react": "^19.2.2",
"@types/react-dom": "^19.1.6", "@types/react-dom": "^19.2.1",
"@types/webpack": "^5.28.5", "@types/webpack": "^5.28.5",
"@typescript-eslint/eslint-plugin": "^8.34.1", "@typescript-eslint/eslint-plugin": "^8.46.0",
"@typescript-eslint/parser": "^8.34.1", "@typescript-eslint/parser": "^8.46.0",
"@webpack-cli/serve": "^3.0.1", "@webpack-cli/serve": "^3.0.1",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"babel-loader": "^10.0.0", "babel-loader": "^10.0.0",
"babel-plugin-transform-import-meta": "^2.3.3", "babel-plugin-transform-import-meta": "^2.3.3",
"browserslist-config-baseline": "^0.5.0",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"concurrently": "^9.1.2", "concurrently": "^9.2.1",
"copy-webpack-plugin": "^13.0.0", "copy-webpack-plugin": "^13.0.1",
"cross-env": "^7.0.3", "cross-env": "^10.1.0",
"css-loader": "^7.1.2", "css-loader": "^7.1.2",
"dotenv": "^16.5.0", "dotenv": "^17.2.3",
"eslint": "^9.29.0", "eslint": "^9.37.0",
"eslint-plugin-import": "^2.31.0", "eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest": "^28.14.0", "eslint-plugin-jest": "^29.0.1",
"eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-no-null": "^1.0.2", "eslint-plugin-no-null": "^1.0.2",
"eslint-plugin-react": "^7.37.5", "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-hooks-static-deps": "git+https://github.com/zubiden/eslint-plugin-react-hooks-static-deps#c16f35b",
"eslint-plugin-react-x": "^1.52.2", "eslint-plugin-react-x": "^2.0.6",
"eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-tt-multitab": "git+https://github.com/zubiden/eslint-plugin-tt-multitab#15d542004d39ec7c29d50385484511bab0b77ea9", "eslint-plugin-tt-multitab": "git+https://github.com/zubiden/eslint-plugin-tt-multitab#137cf50",
"eslint-plugin-unused-imports": "^4.1.4", "eslint-plugin-unused-imports": "^4.2.0",
"fake-indexeddb": "^6.0.1", "fake-indexeddb": "^6.2.3",
"git-revision-webpack-plugin": "^5.0.0", "git-revision-webpack-plugin": "^5.0.0",
"gitlog": "^5.1.0", "gitlog": "^5.1.0",
"glob": "^11.0.3", "glob": "^11.0.3",
"html-webpack-plugin": "^5.6.3", "html-webpack-plugin": "^5.6.4",
"husky": "^9.1.7", "husky": "^9.1.7",
"jest": "^30.0.0", "jest": "^30.2.0",
"jest-environment-jsdom": "^30.0.0", "jest-environment-jsdom": "^30.2.0",
"lint-staged": "^16.1.2", "lint-staged": "^16.2.4",
"mini-css-extract-plugin": "^2.9.2", "mini-css-extract-plugin": "^2.9.4",
"minimatch": "^10.0.3", "minimatch": "^10.0.3",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"postcss-load-config": "^6.0.1", "postcss-load-config": "^6.0.1",
"postcss-loader": "^8.1.1", "postcss-loader": "^8.2.0",
"postcss-modules": "^6.0.1", "postcss-modules": "^6.0.1",
"react": "^19.1.0", "react": "^19.2.0",
"sass": "^1.89.2", "sass": "^1.93.2",
"sass-loader": "^16.0.5", "sass-loader": "^16.0.5",
"script-loader": "^0.7.2", "script-loader": "^0.7.2",
"serve": "^14.2.4", "serve": "^14.2.5",
"stylelint": "^16.20.0", "stylelint": "^16.25.0",
"stylelint-config-clean-order": "^7.0.0", "stylelint-config-clean-order": "^7.0.0",
"stylelint-config-recommended-scss": "^15.0.1", "stylelint-config-recommended-scss": "^16.0.2",
"stylelint-declaration-block-no-ignored-properties": "^2.8.0", "stylelint-declaration-block-no-ignored-properties": "^2.8.0",
"stylelint-group-selectors": "^1.0.10", "stylelint-group-selectors": "^1.0.10",
"stylelint-high-performance-animation": "^1.11.0", "stylelint-high-performance-animation": "^1.11.0",
"stylelint-plugin-use-baseline": "^0.9.1", "stylelint-plugin-use-baseline": "^1.0.2",
"stylelint-selector-tag-no-without-class": "^3.0.1", "stylelint-selector-tag-no-without-class": "^3.0.1",
"telegraph-node": "^1.0.4", "telegraph-node": "^1.0.4",
"tsx": "^4.20.3", "tsx": "^4.20.6",
"typescript": "^5.8.3", "typescript": "5.9.3",
"typescript-eslint": "^8.34.1", "typescript-eslint": "^8.46.0",
"webpack": "^5.99.9", "webpack": "^5.102.1",
"webpack-dev-server": "^5.2.2" "webpack-dev-server": "^5.2.2"
}, },
"dependencies": { "dependencies": {
@ -132,13 +131,12 @@
"@tauri-apps/plugin-shell": "^2.3.1", "@tauri-apps/plugin-shell": "^2.3.1",
"@tauri-apps/plugin-updater": "^2.9.0", "@tauri-apps/plugin-updater": "^2.9.0",
"async-mutex": "^0.5.0", "async-mutex": "^0.5.0",
"browserslist-config-baseline": "^0.5.0", "emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#443f1c9",
"emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#443f1c9d7b16a82e7ee53f7f226d7d9a9920a105",
"idb-keyval": "^6.2.2", "idb-keyval": "^6.2.2",
"lowlight": "^3.3.0", "lowlight": "^3.3.0",
"mp4box": "^0.5.4", "mp4box": "^0.5.4",
"music-metadata": "^11.3.0", "music-metadata": "^11.9.0",
"opus-recorder": "github:Ajaxy/opus-recorder", "opus-recorder": "github:Ajaxy/opus-recorder#116830a",
"os-browserify": "^0.3.0", "os-browserify": "^0.3.0",
"pako": "^2.1.0", "pako": "^2.1.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
@ -148,10 +146,10 @@
"dmg-license": "^1.0.11", "dmg-license": "^1.0.11",
"fsevents": "^2.3.3" "fsevents": "^2.3.3"
}, },
"overrides": {
"@borewit/text-codec": "0.2.0"
},
"browserslist": [ "browserslist": [
"extends browserslist-config-baseline" "baseline widely available"
], ]
"browserslist-config-baseline": {
"logConfigToConsole": false
}
} }

View File

@ -116,7 +116,7 @@ declare module 'opus-recorder' {
sourceNode: MediaStreamAudioSourceNode; sourceNode: MediaStreamAudioSourceNode;
ondataavailable: (typedArray: Uint8Array) => void; ondataavailable: (typedArray: Uint8Array<ArrayBuffer>) => void;
} }
const recorder: IOpusRecorder; const recorder: IOpusRecorder;

View File

@ -194,11 +194,11 @@ export async function destroy(noLogOut = false, noClearLocalDb = false) {
resetUpdatesManager(); resetUpdatesManager();
} }
await client.destroy(); client.destroy();
} }
export async function disconnect() { export function disconnect() {
await client.disconnect(); client.disconnect();
} }
export function getClient() { export function getClient() {

View File

@ -185,7 +185,7 @@ async function download(
} }
function parseMedia( function parseMedia(
data: Buffer | File, mediaFormat: ApiMediaFormat, mimeType?: string, data: Buffer<ArrayBuffer> | File, mediaFormat: ApiMediaFormat, mimeType?: string,
): ApiParsedMedia | undefined { ): ApiParsedMedia | undefined {
if (data instanceof File) { if (data instanceof File) {
return data; return data;

View File

@ -80,7 +80,7 @@ export async function fetchStarGifts() {
// Right now, only regular star gifts can be bought, but API are not specific // Right now, only regular star gifts can be bought, but API are not specific
const gifts const gifts
= result.gifts.map(buildApiStarGift).filter((gift): gift is ApiStarGiftRegular => gift.type === 'starGift'); = result.gifts.map(buildApiStarGift).filter((gift): gift is ApiStarGiftRegular => gift.type === 'starGift');
return { return {
gifts, gifts,
@ -102,33 +102,33 @@ export async function fetchResaleGifts({
attributesHash?: string; attributesHash?: string;
filter?: ResaleGiftsFilterOptions; filter?: ResaleGiftsFilterOptions;
}) { }) {
type GetResaleStarGifts = ConstructorParameters<typeof GramJs.payments.GetResaleStarGifts>[0]; type GetResaleStarGifts = ConstructorParameters<typeof GramJs.payments.GetResaleStarGifts>[0];
const attributes: ApiStarGiftAttributeId[] = [ const attributes: ApiStarGiftAttributeId[] = [
...(filter?.backdropAttributes ?? []), ...(filter?.backdropAttributes ?? []),
...(filter?.modelAttributes ?? []), ...(filter?.modelAttributes ?? []),
...(filter?.patternAttributes ?? []), ...(filter?.patternAttributes ?? []),
]; ];
const params: GetResaleStarGifts = { const params: GetResaleStarGifts = {
giftId: BigInt(giftId), giftId: BigInt(giftId),
offset, offset,
limit, limit,
attributesHash: attributesHash ? BigInt(attributesHash) : DEFAULT_PRIMITIVES.BIGINT, attributesHash: attributesHash ? BigInt(attributesHash) : DEFAULT_PRIMITIVES.BIGINT,
attributes: buildInputResaleGiftsAttributes(attributes), attributes: buildInputResaleGiftsAttributes(attributes),
...(filter && { ...(filter && {
sortByPrice: filter.sortType === 'byPrice' || undefined, sortByPrice: filter.sortType === 'byPrice' || undefined,
sortByNum: filter.sortType === 'byNumber' || undefined, sortByNum: filter.sortType === 'byNumber' || undefined,
} satisfies Partial<GetResaleStarGifts>), } satisfies Partial<GetResaleStarGifts>),
}; };
const result = await invokeRequest(new GramJs.payments.GetResaleStarGifts(params)); const result = await invokeRequest(new GramJs.payments.GetResaleStarGifts(params));
if (!result) { if (!result) {
return undefined; return undefined;
} }
return buildApiResaleGifts(result); return buildApiResaleGifts(result);
} }
export async function fetchSavedStarGifts({ export async function fetchSavedStarGifts({

View File

@ -36,7 +36,7 @@ function AnimatedIcon(props: OwnProps) {
onLoad?.(); onLoad?.();
}); });
const [playKey, setPlayKey] = useState(String(Math.random())); const [playKey, setPlayKey] = useState(() => String(Math.random()));
const handleClick = useLastCallback(() => { const handleClick = useLastCallback(() => {
if (play === true) { if (play === true) {

View File

@ -83,15 +83,15 @@ const CalendarModal: FC<OwnProps> = ({
const [isTimeInputFocused, markTimeInputAsFocused] = useFlag(false); const [isTimeInputFocused, markTimeInputAsFocused] = useFlag(false);
const [selectedDate, setSelectedDate] = useState<Date>(passedSelectedDate); const [selectedDate, setSelectedDate] = useState<Date>(passedSelectedDate);
const [currentMonthAndYear, setCurrentMonthAndYear] = useState<Date>( const [currentMonthAndYear, setCurrentMonthAndYear] = useState<Date>(() => (
new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1), new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1)
); ));
const [selectedHours, setSelectedHours] = useState<string>( const [selectedHours, setSelectedHours] = useState<string>(() => (
formatInputTime(passedSelectedDate.getHours()), formatInputTime(passedSelectedDate.getHours())
); ));
const [selectedMinutes, setSelectedMinutes] = useState<string>( const [selectedMinutes, setSelectedMinutes] = useState<string>(() => (
formatInputTime(passedSelectedDate.getMinutes()), formatInputTime(passedSelectedDate.getMinutes())
); ));
const selectedDay = formatDay(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()); const selectedDay = formatDay(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
const currentYear = currentMonthAndYear.getFullYear(); const currentYear = currentMonthAndYear.getFullYear();

View File

@ -143,7 +143,7 @@ const StickerSet: FC<OwnProps & StateProps> = ({
const [isConfirmModalOpen, openConfirmModal, closeConfirmModal] = useFlag(); const [isConfirmModalOpen, openConfirmModal, closeConfirmModal] = useFlag();
const { isMobile } = useAppLayout(); const { isMobile } = useAppLayout();
const [itemsPerRow, setItemsPerRow] = useState(getItemsPerRowFallback(windowWidth)); const [itemsPerRow, setItemsPerRow] = useState(() => getItemsPerRowFallback(windowWidth));
const isIntersecting = useIsIntersecting(ref, observeIntersection ?? observeIntersectionForShowingItems); const isIntersecting = useIsIntersecting(ref, observeIntersection ?? observeIntersectionForShowingItems);
const transitionClassNames = useMediaTransitionDeprecated(isIntersecting); const transitionClassNames = useMediaTransitionDeprecated(isIntersecting);

View File

@ -54,7 +54,7 @@
text-align: initial; text-align: initial;
@media (max-width: 600px) { @media (max-width: 600px) {
grid-gap: 0.5rem; gap: 0.5rem;
} }
} }

View File

@ -60,7 +60,7 @@ function preloadAvatars() {
return undefined; return undefined;
} }
return Promise.all(listIds.active.slice(0, AVATARS_TO_PRELOAD).map((chatId) => { return Promise.all(listIds.active.slice(0, AVATARS_TO_PRELOAD).map(async (chatId) => {
const chat = byId[chatId]; const chat = byId[chatId];
if (!chat) { if (!chat) {
return undefined; return undefined;

View File

@ -43,11 +43,11 @@ const GiftRibbon = ({
const isDarkTheme = theme === 'dark'; const isDarkTheme = theme === 'dark';
const gradientColor: GradientColor | undefined const gradientColor: GradientColor | undefined
= Array.isArray(color) = Array.isArray(color)
? color as GradientColor ? color as GradientColor
: colorKey : colorKey
? COLORS[colorKey][isDarkTheme ? 1 : 0] ? COLORS[colorKey][isDarkTheme ? 1 : 0]
: undefined; : undefined;
const startColor = gradientColor ? gradientColor[0] : color; const startColor = gradientColor ? gradientColor[0] : color;
const endColor = gradientColor ? gradientColor[1] : color; const endColor = gradientColor ? gradientColor[1] : color;

View File

@ -21,7 +21,7 @@ import SafeLink from '../SafeLink';
export type TextFilter = ( export type TextFilter = (
'escape_html' | 'hq_emoji' | 'emoji' | 'emoji_html' | 'br' | 'br_html' | 'highlight' | 'links' | 'escape_html' | 'hq_emoji' | 'emoji' | 'emoji_html' | 'br' | 'br_html' | 'highlight' | 'links' |
'simple_markdown' | 'simple_markdown_html' | 'tg_links' 'simple_markdown' | 'simple_markdown_html' | 'tg_links'
); );
const SIMPLE_MARKDOWN_REGEX = /(\*\*|__).+?\1/g; const SIMPLE_MARKDOWN_REGEX = /(\*\*|__).+?\1/g;

View File

@ -6,17 +6,15 @@ import type { GlobalState } from '../../../global/types';
import { selectCanPlayAnimatedEmojis, selectCustomEmoji } from '../../../global/selectors'; import { selectCanPlayAnimatedEmojis, selectCustomEmoji } from '../../../global/selectors';
import { addCustomEmojiCallback, removeCustomEmojiCallback } from '../../../util/emoji/customEmojiManager'; import { addCustomEmojiCallback, removeCustomEmojiCallback } from '../../../util/emoji/customEmojiManager';
import ensureCustomEmoji from '../../../util/emoji/ensureCustomEmoji';
import useEnsureCustomEmoji from '../../../hooks/useEnsureCustomEmoji';
import useLastCallback from '../../../hooks/useLastCallback'; import useLastCallback from '../../../hooks/useLastCallback';
export default function useCustomEmoji(documentId?: string) { export default function useCustomEmoji(documentId?: string) {
const [customEmoji, setCustomEmoji] = useState<ApiSticker | undefined>( const [customEmoji, setCustomEmoji] = useState<ApiSticker | undefined>(() => (
documentId ? selectCustomEmoji(getGlobal(), documentId) : undefined, documentId ? selectCustomEmoji(getGlobal(), documentId) : undefined
); ));
const [canPlay, setCanPlay] = useState(selectCanPlayAnimatedEmojis(getGlobal())); const [canPlay, setCanPlay] = useState(() => selectCanPlayAnimatedEmojis(getGlobal()));
useEnsureCustomEmoji(documentId);
const handleGlobalChange = useLastCallback((customEmojis?: GlobalState['customEmojis']) => { const handleGlobalChange = useLastCallback((customEmojis?: GlobalState['customEmojis']) => {
if (!documentId) return; if (!documentId) return;
@ -26,7 +24,11 @@ export default function useCustomEmoji(documentId?: string) {
setCanPlay(selectCanPlayAnimatedEmojis(newGlobal)); setCanPlay(selectCanPlayAnimatedEmojis(newGlobal));
}); });
useEffect(handleGlobalChange, [documentId, handleGlobalChange]); useEffect(() => {
ensureCustomEmoji(documentId);
}, [documentId]);
useEffect(() => handleGlobalChange(), [documentId]);
useEffect(() => { useEffect(() => {
if (!documentId) return undefined; if (!documentId) return undefined;

View File

@ -108,8 +108,8 @@
.media-list { .media-list {
display: grid; display: grid;
grid-auto-rows: 1fr; grid-auto-rows: 1fr;
grid-gap: 0.25rem;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 0.25rem;
padding: 0.5rem; padding: 0.5rem;

View File

@ -4,8 +4,8 @@
.settings-wallpapers { .settings-wallpapers {
display: grid; display: grid;
grid-auto-rows: 1fr; grid-auto-rows: 1fr;
grid-gap: 0.0625rem;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 0.0625rem;
@include mixins.side-panel-section; @include mixins.side-panel-section;
} }

View File

@ -73,8 +73,8 @@
.predefined-colors { .predefined-colors {
display: grid; display: grid;
grid-auto-rows: 1fr; grid-auto-rows: 1fr;
grid-gap: 0.0625rem;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 0.0625rem;
@include mixins.side-panel-section; @include mixins.side-panel-section;
} }

View File

@ -68,7 +68,7 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps> = ({
const huePickerRef = useRef<HTMLDivElement>(); const huePickerRef = useRef<HTMLDivElement>();
const isFirstRunRef = useRef(true); const isFirstRunRef = useRef(true);
const [hsv, setHsv] = useState(getInitialHsv(backgroundColor)); const [hsv, setHsv] = useState(() => getInitialHsv(backgroundColor));
// Cache for drag handlers // Cache for drag handlers
const hsvRef = useRef(hsv); const hsvRef = useRef(hsv);
useEffect(() => { useEffect(() => {

View File

@ -158,7 +158,7 @@ const GiveawayModal: FC<OwnProps & StateProps> = ({
}); });
} }
const [customExpireDate, setCustomExpireDate] = useState<number>(Date.now() + DEFAULT_CUSTOM_EXPIRE_DATE); const [customExpireDate, setCustomExpireDate] = useState<number>(() => Date.now() + DEFAULT_CUSTOM_EXPIRE_DATE);
const [isHeaderHidden, setHeaderHidden] = useState(true); const [isHeaderHidden, setHeaderHidden] = useState(true);
const [selectedRandomUserCount, setSelectedRandomUserCount] = useState<number>(DEFAULT_BOOST_COUNT); const [selectedRandomUserCount, setSelectedRandomUserCount] = useState<number>(DEFAULT_BOOST_COUNT);
const [selectedGiveawayOption, setGiveawayOption] = useState<ApiGiveawayType>(TYPE_OPTIONS[0].value); const [selectedGiveawayOption, setGiveawayOption] = useState<ApiGiveawayType>(TYPE_OPTIONS[0].value);

View File

@ -38,11 +38,6 @@
.frame { .frame {
aspect-ratio: 1; aspect-ratio: 1;
@supports not (aspect-ratio: 1) {
height: 0;
padding-bottom: 100%;
}
} }
.slide { .slide {
@ -104,11 +99,6 @@
border-top-right-radius: var(--border-radius-default); border-top-right-radius: var(--border-radius-default);
background: var(--premium-feature-background); background: var(--premium-feature-background);
@supports not (aspect-ratio: 1) {
height: 0;
padding-bottom: 100%;
}
} }
.title { .title {

View File

@ -6,11 +6,6 @@
justify-content: center; justify-content: center;
aspect-ratio: 1; aspect-ratio: 1;
@supports not (aspect-ratio: 1) {
height: 0;
padding-bottom: 100%;
}
} }
.wrapper { .wrapper {
@ -37,10 +32,6 @@
width: 70%; width: 70%;
opacity: calc(1 - var(--abs-scroll-progress-converted) * 0.4); opacity: calc(1 - var(--abs-scroll-progress-converted) * 0.4);
@supports not (aspect-ratio: 1) {
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.005, 0, -342.2, 0, 1);
}
} }
.down { .down {
@ -71,10 +62,8 @@
border-radius: 0 0 10% 10%; border-radius: 0 0 10% 10%;
} }
@supports (aspect-ratio: 1) { .down .video {
.down .video { top: 0;
top: 0; bottom: initial;
bottom: initial; border-radius: 10% 10% 0 0;
border-radius: 10% 10% 0 0;
}
} }

View File

@ -5,10 +5,10 @@
left: 0; left: 0;
display: grid; display: grid;
grid-column-gap: 0;
grid-row-gap: 0;
grid-template-columns: auto; grid-template-columns: auto;
grid-template-rows: auto 1fr; grid-template-rows: auto 1fr;
row-gap: 0;
column-gap: 0;
align-items: center; align-items: center;
justify-items: stretch; justify-items: stretch;

View File

@ -53,7 +53,7 @@ import useFlag from '../../hooks/useFlag';
import useForceUpdate from '../../hooks/useForceUpdate'; import useForceUpdate from '../../hooks/useForceUpdate';
import useLastCallback from '../../hooks/useLastCallback'; import useLastCallback from '../../hooks/useLastCallback';
import useOldLang from '../../hooks/useOldLang'; import useOldLang from '../../hooks/useOldLang';
import { exitPictureInPictureIfNeeded, usePictureInPictureSignal } from '../../hooks/usePictureInPicture'; import { exitPictureInPictureIfNeeded, PICTURE_IN_PICTURE_SIGNAL } from '../../hooks/usePictureInPicture';
import usePreviousDeprecated from '../../hooks/usePreviousDeprecated'; import usePreviousDeprecated from '../../hooks/usePreviousDeprecated';
import { dispatchPriorityPlaybackEvent } from '../../hooks/usePriorityPlaybackCheck'; import { dispatchPriorityPlaybackEvent } from '../../hooks/usePriorityPlaybackCheck';
import { useMediaProps } from './hooks/useMediaProps'; import { useMediaProps } from './hooks/useMediaProps';
@ -181,7 +181,7 @@ const MediaViewer = ({
animationKey.current = isSingle ? 0 : (messageId || mediaIndex); animationKey.current = isSingle ? 0 : (messageId || mediaIndex);
} }
const [getIsPictureInPicture] = usePictureInPictureSignal(); const [getIsPictureInPicture] = PICTURE_IN_PICTURE_SIGNAL;
useEffect(() => { useEffect(() => {
if (!isOpen || getIsPictureInPicture()) { if (!isOpen || getIsPictureInPicture()) {

View File

@ -30,6 +30,6 @@
display: grid; display: grid;
grid-auto-flow: dense; grid-auto-flow: dense;
grid-auto-rows: 6.25rem; grid-auto-rows: 6.25rem;
grid-gap: 0.125rem;
grid-template-columns: repeat(6, 1fr); grid-template-columns: repeat(6, 1fr);
gap: 0.125rem;
} }

View File

@ -9,8 +9,8 @@
display: grid; display: grid;
grid-auto-flow: dense; grid-auto-flow: dense;
grid-gap: 1px;
grid-template-columns: repeat(8, 1fr); grid-template-columns: repeat(8, 1fr);
gap: 1px;
padding: 0; padding: 0;

View File

@ -314,6 +314,6 @@
} }
@media (max-width: 600px) { @media (max-width: 600px) {
grid-gap: 0.5rem; gap: 0.5rem;
} }
} }

View File

@ -64,7 +64,7 @@ const ToDoListModal = ({
const itemsListRef = useRef<HTMLDivElement>(); const itemsListRef = useRef<HTMLDivElement>();
const [title, setTitle] = useState<string>(''); const [title, setTitle] = useState<string>('');
const [items, setItems] = useState<Item[]>([{ id: generateUniqueNumberId(), text: '' }]); const [items, setItems] = useState<Item[]>(() => [{ id: generateUniqueNumberId(), text: '' }]);
const [isOthersCanAppend, setIsOthersCanAppend] = useState(true); const [isOthersCanAppend, setIsOthersCanAppend] = useState(true);
const [isOthersCanComplete, setIsOthersCanComplete] = useState(true); const [isOthersCanComplete, setIsOthersCanComplete] = useState(true);
const [hasErrors, setHasErrors] = useState<boolean>(false); const [hasErrors, setHasErrors] = useState<boolean>(false);

View File

@ -33,11 +33,6 @@
} }
.skeleton { .skeleton {
aspect-ratio: 16/9; aspect-ratio: 16 / 9;
@supports not (aspect-ratio: 16/9) {
height: 0 !important;
padding-bottom: 56.25%;
}
} }
} }

View File

@ -65,11 +65,11 @@ const Poll: FC<OwnProps> = ({
const [isSubmitting, setIsSubmitting] = useState<boolean>(false); const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const [chosenOptions, setChosenOptions] = useState<string[]>([]); const [chosenOptions, setChosenOptions] = useState<string[]>([]);
const [wasSubmitted, setWasSubmitted] = useState<boolean>(false); const [wasSubmitted, setWasSubmitted] = useState<boolean>(false);
const [closePeriod, setClosePeriod] = useState<number>( const [closePeriod, setClosePeriod] = useState<number>(() => (
!summary.closed && summary.closeDate && summary.closeDate > 0 !summary.closed && summary.closeDate && summary.closeDate > 0
? Math.min(summary.closeDate - getServerTime(), summary.closePeriod!) ? Math.min(summary.closeDate - getServerTime(), summary.closePeriod!)
: 0, : 0
); ));
const countdownRef = useRef<HTMLDivElement>(); const countdownRef = useRef<HTMLDivElement>();
const timerCircleRef = useRef<SVGCircleElement>(); const timerCircleRef = useRef<SVGCircleElement>();
const { results: voteResults, totalVoters } = results; const { results: voteResults, totalVoters } = results;

View File

@ -51,14 +51,14 @@ type OwnProps =
canPost?: boolean; canPost?: boolean;
}; };
type StateProps = { type StateProps = {
sender?: ApiPeer; sender?: ApiPeer;
canShowSender: boolean; canShowSender: boolean;
originSender?: ApiPeer; originSender?: ApiPeer;
isChatWithSelf?: boolean; isChatWithSelf?: boolean;
isRepliesChat?: boolean; isRepliesChat?: boolean;
isAnonymousForwards?: boolean; isAnonymousForwards?: boolean;
}; };
const SenderGroupContainer: FC<OwnProps & StateProps> = ({ const SenderGroupContainer: FC<OwnProps & StateProps> = ({
message, message,

View File

@ -173,80 +173,80 @@ const GiftResaleFilters: FC<StateProps & OwnProps> = ({
const getPatternMenuElement = useLastCallback(() => patternMenuRef.current!); const getPatternMenuElement = useLastCallback(() => patternMenuRef.current!);
const SortMenuButton: FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }> const SortMenuButton: FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }>
= useMemo(() => { = useMemo(() => {
const sortType = filter.sortType; const sortType = filter.sortType;
return ({ onTrigger, isOpen: isMenuOpen }) => ( return ({ onTrigger, isOpen: isMenuOpen }) => (
<div <div
className={styles.item} className={styles.item}
onClick={onTrigger} onClick={onTrigger}
> >
{sortType === 'byDate' && lang('ValueGiftSortByDate')} {sortType === 'byDate' && lang('ValueGiftSortByDate')}
{sortType === 'byNumber' && lang('ValueGiftSortByNumber')} {sortType === 'byNumber' && lang('ValueGiftSortByNumber')}
{sortType === 'byPrice' && lang('ValueGiftSortByPrice')} {sortType === 'byPrice' && lang('ValueGiftSortByPrice')}
<Icon <Icon
name="dropdown-arrows" name="dropdown-arrows"
className={styles.itemIcon} className={styles.itemIcon}
/> />
</div> </div>
); );
}, [lang, filter]); }, [lang, filter]);
const ModelMenuButton: const ModelMenuButton:
FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }> FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }>
= useMemo(() => { = useMemo(() => {
const attributesCount = filter?.modelAttributes?.length || 0; const attributesCount = filter?.modelAttributes?.length || 0;
return ({ onTrigger, isOpen: isMenuOpen }) => ( return ({ onTrigger, isOpen: isMenuOpen }) => (
<div <div
className={styles.item} className={styles.item}
onClick={onTrigger} onClick={onTrigger}
> >
{attributesCount === 0 && lang('GiftAttributeModel')} {attributesCount === 0 && lang('GiftAttributeModel')}
{attributesCount > 0 {attributesCount > 0
&& lang('GiftAttributeModelPlural', { count: attributesCount }, { pluralValue: attributesCount })} && lang('GiftAttributeModelPlural', { count: attributesCount }, { pluralValue: attributesCount })}
<Icon <Icon
name="dropdown-arrows" name="dropdown-arrows"
className={styles.itemIcon} className={styles.itemIcon}
/> />
</div> </div>
); );
}, [lang, filter]); }, [lang, filter]);
const BackdropMenuButton: const BackdropMenuButton:
FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }> FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }>
= useMemo(() => { = useMemo(() => {
const attributesCount = filter?.backdropAttributes?.length || 0; const attributesCount = filter?.backdropAttributes?.length || 0;
return ({ onTrigger, isOpen: isMenuOpen }) => ( return ({ onTrigger, isOpen: isMenuOpen }) => (
<div <div
className={styles.item} className={styles.item}
onClick={onTrigger} onClick={onTrigger}
> >
{attributesCount === 0 && lang('GiftAttributeBackdrop')} {attributesCount === 0 && lang('GiftAttributeBackdrop')}
{attributesCount > 0 {attributesCount > 0
&& lang('GiftAttributeBackdropPlural', { count: attributesCount }, { pluralValue: attributesCount })} && lang('GiftAttributeBackdropPlural', { count: attributesCount }, { pluralValue: attributesCount })}
<Icon <Icon
name="dropdown-arrows" name="dropdown-arrows"
className={styles.itemIcon} className={styles.itemIcon}
/> />
</div> </div>
); );
}, [lang, filter]); }, [lang, filter]);
const PatternMenuButton: FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }> const PatternMenuButton: FC<{ onTrigger: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => void; isOpen?: boolean }>
= useMemo(() => { = useMemo(() => {
const attributesCount = filter?.patternAttributes?.length || 0; const attributesCount = filter?.patternAttributes?.length || 0;
return ({ onTrigger, isOpen: isMenuOpen }) => ( return ({ onTrigger, isOpen: isMenuOpen }) => (
<div <div
className={styles.item} className={styles.item}
onClick={onTrigger} onClick={onTrigger}
> >
{attributesCount === 0 && lang('GiftAttributeSymbol')} {attributesCount === 0 && lang('GiftAttributeSymbol')}
{attributesCount > 0 {attributesCount > 0
&& lang('GiftAttributeSymbolPlural', { count: attributesCount }, { pluralValue: attributesCount })} && lang('GiftAttributeSymbolPlural', { count: attributesCount }, { pluralValue: attributesCount })}
<Icon <Icon
name="dropdown-arrows" name="dropdown-arrows"
className={styles.itemIcon} className={styles.itemIcon}
/> />
</div> </div>
); );
}, [lang, filter]); }, [lang, filter]);
const handleSortMenuItemClick = useLastCallback((type: ResaleGiftsSortType) => { const handleSortMenuItemClick = useLastCallback((type: ResaleGiftsSortType) => {
updateResaleGiftsFilter({ filter: { updateResaleGiftsFilter({ filter: {

View File

@ -26,7 +26,7 @@
.optionText { .optionText {
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
word-wrap: break-word; overflow-wrap: anywhere;
white-space: normal; white-space: normal;
} }

View File

@ -145,7 +145,7 @@ const SuggestedPostApprovalModal = ({
const time = formatScheduledDateTime(scheduleDate, lang, oldLang); const time = formatScheduledDateTime(scheduleDate, lang, oldLang);
const key const key
= isAdmin ? 'SuggestedPostConfirmDetailsWithTimeAdmin' : 'SuggestedPostConfirmDetailsWithTimeUser'; = isAdmin ? 'SuggestedPostConfirmDetailsWithTimeAdmin' : 'SuggestedPostConfirmDetailsWithTimeUser';
return ( return (
<> <>

View File

@ -10,8 +10,8 @@
display: grid; display: grid;
grid-auto-flow: dense; grid-auto-flow: dense;
grid-auto-rows: 6.25rem; grid-auto-rows: 6.25rem;
grid-gap: 0.25rem;
grid-template-columns: repeat(6, 1fr); grid-template-columns: repeat(6, 1fr);
gap: 0.25rem;
} }
} }

View File

@ -55,7 +55,7 @@ const ManageInvite: FC<OwnProps & StateProps> = ({
const [isCalendarOpened, openCalendar, closeCalendar] = useFlag(); const [isCalendarOpened, openCalendar, closeCalendar] = useFlag();
const [isRequestNeeded, setIsRequestNeeded] = useState(false); const [isRequestNeeded, setIsRequestNeeded] = useState(false);
const [title, setTitle] = useState(''); const [title, setTitle] = useState('');
const [customExpireDate, setCustomExpireDate] = useState<number>(Date.now() + DEFAULT_CUSTOM_EXPIRE_DATE); const [customExpireDate, setCustomExpireDate] = useState<number>(() => Date.now() + DEFAULT_CUSTOM_EXPIRE_DATE);
const [selectedExpireOption, setSelectedExpireOption] = useState('unlimited'); const [selectedExpireOption, setSelectedExpireOption] = useState('unlimited');
const [customUsageLimit, setCustomUsageLimit] = useState<number | undefined>(10); const [customUsageLimit, setCustomUsageLimit] = useState<number | undefined>(10);
const [selectedUsageOption, setSelectedUsageOption] = useState('0'); const [selectedUsageOption, setSelectedUsageOption] = useState('0');

View File

@ -48,7 +48,7 @@ const NewDiscussionGroup: FC<OwnProps & StateProps> = ({
onBack: onClose, onBack: onClose,
}); });
const [title, setTitle] = useState(lang('NewDiscussionChatTitle', { name: chat?.title })); const [title, setTitle] = useState(() => lang('NewDiscussionChatTitle', { name: chat?.title }));
const [photo, setPhoto] = useState<File | undefined>(); const [photo, setPhoto] = useState<File | undefined>();
const [error, setError] = useState<string | undefined>(); const [error, setError] = useState<string | undefined>();

View File

@ -21,7 +21,7 @@ type AnimationName = (
'none' | 'slide' | 'slideRtl' | 'slideFade' | 'zoomFade' | 'zoomBounceSemiFade' | 'slideLayers' 'none' | 'slide' | 'slideRtl' | 'slideFade' | 'zoomFade' | 'zoomBounceSemiFade' | 'slideLayers'
| 'fade' | 'pushSlide' | 'reveal' | 'slideOptimized' | 'slideOptimizedRtl' | 'semiFade' | 'fade' | 'pushSlide' | 'reveal' | 'slideOptimized' | 'slideOptimizedRtl' | 'semiFade'
| 'slideVertical' | 'slideVerticalFade' | 'slideFadeAndroid' | 'slideVertical' | 'slideVerticalFade' | 'slideFadeAndroid'
); );
export type ChildrenFn = (isActive: boolean, isFrom: boolean, currentKey: number, activeKey: number) => React.ReactNode; export type ChildrenFn = (isActive: boolean, isFrom: boolean, currentKey: number, activeKey: number) => React.ReactNode;
export type TransitionProps = { export type TransitionProps = {
ref?: ElementRef<HTMLDivElement>; ref?: ElementRef<HTMLDivElement>;

View File

@ -559,7 +559,7 @@ addActionHandler('sendInviteMessages', async (global, actions, payload): Promise
await Promise.all(userIds.map((userId) => { await Promise.all(userIds.map((userId) => {
const chat = selectChat(global, userId); const chat = selectChat(global, userId);
if (!chat) { if (!chat) {
return undefined; return Promise.resolve(undefined);
} }
const userFullName = getUserFullName(selectUser(global, userId)); const userFullName = getUserFullName(selectUser(global, userId));
if (userFullName) { if (userFullName) {

View File

@ -117,7 +117,7 @@ export type FoldersActions = (
'setTitle' | 'saveFilters' | 'editFolder' | 'reset' | 'setChatFilter' | 'setIsLoading' | 'setError' | 'setTitle' | 'saveFilters' | 'editFolder' | 'reset' | 'setChatFilter' | 'setIsLoading' | 'setError' |
'editIncludeFilters' | 'editExcludeFilters' | 'setIncludeFilters' | 'setExcludeFilters' | 'setIsTouched' | 'editIncludeFilters' | 'editExcludeFilters' | 'setIncludeFilters' | 'setExcludeFilters' | 'setIsTouched' |
'setFolderId' | 'setIsChatlist' | 'setColor' 'setFolderId' | 'setIsChatlist' | 'setColor'
); );
export type FolderEditDispatch = Dispatch<FoldersState, FoldersActions>; export type FolderEditDispatch = Dispatch<FoldersState, FoldersActions>;
const INITIAL_STATE: FoldersState = { const INITIAL_STATE: FoldersState = {

View File

@ -23,7 +23,7 @@ export default function useMultiaccountInfo(currentUser?: ApiUser) {
const isUpdater = Boolean(currentUser) && getGlobal().authRememberMe; const isUpdater = Boolean(currentUser) && getGlobal().authRememberMe;
const isSynced = useSelector(selectIsSynced); const isSynced = useSelector(selectIsSynced);
const [accountsInfo, setAccountsInfo] = useState(getAccountsInfo()); const [accountsInfo, setAccountsInfo] = useState(() => getAccountsInfo());
const avatarHash = currentUser && getChatAvatarHash(currentUser); const avatarHash = currentUser && getChatAvatarHash(currentUser);
const avatarUrl = useMedia(avatarHash, !isUpdater); const avatarUrl = useMedia(avatarHash, !isUpdater);

View File

@ -12,9 +12,7 @@ type CallbackType = () => void;
const signal = createSignal(false); const signal = createSignal(false);
const setIsPictureInPicture = signal[1]; const setIsPictureInPicture = signal[1];
export function usePictureInPictureSignal() { export const PICTURE_IN_PICTURE_SIGNAL = signal;
return signal;
}
export default function usePictureInPicture( export default function usePictureInPicture(
elRef: ElementRef<HTMLVideoElement>, elRef: ElementRef<HTMLVideoElement>,

View File

@ -51,7 +51,7 @@ export function readBufferFromBigInt(
bytesNumber: number, bytesNumber: number,
little = true, little = true,
signed = false, signed = false,
): Buffer { ): Buffer<ArrayBuffer> {
if (!Number.isInteger(bytesNumber) || bytesNumber <= 0) { if (!Number.isInteger(bytesNumber) || bytesNumber <= 0) {
throw new RangeError('bytesNumber must be a positive integer'); throw new RangeError('bytesNumber must be a positive integer');
} }
@ -138,13 +138,13 @@ export function convertToLittle(buf: Uint32Array) {
return correct; return correct;
} }
export function sha1(data: Buffer): Promise<Buffer> { export function sha1(data: Buffer): Promise<Buffer<ArrayBuffer>> {
const shaSum = createHash('sha1'); const shaSum = createHash('sha1');
shaSum.update(data); shaSum.update(data);
return shaSum.digest(); return shaSum.digest();
} }
export function sha256(data: Buffer): Promise<Buffer> { export function sha256(data: Buffer): Promise<Buffer<ArrayBuffer>> {
const shaSum = createHash('sha256'); const shaSum = createHash('sha256');
shaSum.update(data); shaSum.update(data);
return shaSum.digest(); return shaSum.digest();
@ -171,7 +171,7 @@ export function modExp(
return result; return result;
} }
export function getByteArray(integer: bigint, signed = false): Buffer { export function getByteArray(integer: bigint, signed = false): Buffer<ArrayBuffer> {
if (!signed && integer < 0n) { if (!signed && integer < 0n) {
throw new RangeError('Cannot convert negative to unsigned'); throw new RangeError('Cannot convert negative to unsigned');
} }

View File

@ -45,7 +45,7 @@ function isGoodLarge(number: bigint, p: bigint): boolean {
return number > 0n && number < p; return number > 0n && number < p;
} }
function numBytesForHash(number: Buffer): Buffer { function numBytesForHash(number: Buffer): Buffer<ArrayBuffer> {
return Buffer.concat([Buffer.alloc(SIZE_FOR_HASH - number.length), number]); return Buffer.concat([Buffer.alloc(SIZE_FOR_HASH - number.length), number]);
} }
@ -77,7 +77,7 @@ function xor(a: Buffer, b: Buffer) {
return a; return a;
} }
function pbkdf2sha512(password: Buffer, salt: Buffer, iterations: number): any { function pbkdf2sha512(password: Buffer<ArrayBuffer>, salt: Buffer<ArrayBuffer>, iterations: number): any {
return pbkdf2(password, salt, iterations); return pbkdf2(password, salt, iterations);
} }
@ -92,7 +92,7 @@ async function computeHash(
) { ) {
const hash1 = await sha256(Buffer.concat([algo.salt1, Buffer.from(password, 'utf-8'), algo.salt1])); const hash1 = await sha256(Buffer.concat([algo.salt1, Buffer.from(password, 'utf-8'), algo.salt1]));
const hash2 = await sha256(Buffer.concat([algo.salt2, hash1, algo.salt2])); const hash2 = await sha256(Buffer.concat([algo.salt2, hash1, algo.salt2]));
const hash3 = await pbkdf2sha512(hash2, algo.salt1, 100000); const hash3 = await pbkdf2sha512(hash2, algo.salt1 as Buffer<ArrayBuffer>, 100000);
return sha256(Buffer.concat([algo.salt2, hash3, algo.salt2])); return sha256(Buffer.concat([algo.salt2, hash3, algo.salt2]));
} }

View File

@ -81,7 +81,7 @@ export function getInputPeer(
* @param stripped{Buffer} * @param stripped{Buffer}
* @returns {Buffer} * @returns {Buffer}
*/ */
export function strippedPhotoToJpg(stripped: Buffer) { export function strippedPhotoToJpg(stripped: Buffer<ArrayBuffer>): Buffer<ArrayBuffer> {
// Note: Changes here should update _stripped_real_length // Note: Changes here should update _stripped_real_length
if (stripped.length < 3 || stripped[0] !== 1) { if (stripped.length < 3 || stripped[0] !== 1) {
return stripped; return stripped;

View File

@ -370,14 +370,14 @@ class TelegramClient {
async setForceHttpTransport(forceHttpTransport: boolean) { async setForceHttpTransport(forceHttpTransport: boolean) {
this._shouldForceHttpTransport = forceHttpTransport; this._shouldForceHttpTransport = forceHttpTransport;
await this.disconnect(); this.disconnect();
this._sender = undefined; this._sender = undefined;
await this.connect(); await this.connect();
} }
async setAllowHttpTransport(allowHttpTransport: boolean) { async setAllowHttpTransport(allowHttpTransport: boolean) {
this._shouldAllowHttpTransport = allowHttpTransport; this._shouldAllowHttpTransport = allowHttpTransport;
await this.disconnect(); this.disconnect();
this._sender = undefined; this._sender = undefined;
await this.connect(); await this.connect();
} }
@ -467,26 +467,22 @@ class TelegramClient {
lastPongAt = undefined; lastPongAt = undefined;
} }
} }
await this.disconnect(); this.disconnect();
} }
/** /**
* Disconnects from the Telegram server * Disconnects from the Telegram server
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async disconnect() { disconnect() {
this._sender?.disconnect(); this._sender?.disconnect();
await Promise.all( Object.values(this._exportedSenderPromises)
Object.values(this._exportedSenderPromises) .forEach((promises) => {
.map((promises) => { Object.values(promises).forEach((promise) => {
return Object.values(promises).map((promise) => { promise?.then((sender) => sender?.disconnect());
return promise?.then((sender) => { });
return sender?.disconnect(); });
});
});
}).flat(),
);
Object.values(this._exportedSenderReleaseTimeouts).forEach((timeouts) => { Object.values(this._exportedSenderReleaseTimeouts).forEach((timeouts) => {
Object.values(timeouts).forEach((releaseTimeout) => { Object.values(timeouts).forEach((releaseTimeout) => {
@ -503,11 +499,11 @@ class TelegramClient {
* Disconnects all senders and removes all handlers * Disconnects all senders and removes all handlers
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async destroy() { destroy() {
this._destroyed = true; this._destroyed = true;
try { try {
await this.disconnect(); this.disconnect();
this._sender?.destroy(); this._sender?.destroy();
} catch (err) { } catch (err) {
// Do nothing // Do nothing
@ -531,7 +527,7 @@ class TelegramClient {
await this._sender.authKey.setKey(undefined); await this._sender.authKey.setKey(undefined);
this.session.setAuthKey(undefined); this.session.setAuthKey(undefined);
this._isSwitchingDc = true; this._isSwitchingDc = true;
await this.disconnect(); this.disconnect();
this._sender = undefined; this._sender = undefined;
return this.connect(); return this.connect();
} }
@ -839,7 +835,7 @@ class TelegramClient {
return this.downloadFile(loc, { return this.downloadFile(loc, {
dcId, dcId,
isPriority: true, isPriority: true,
}) as Promise<Buffer | undefined>; // Profile photo cannot be larger than 2GB, right? }) as Promise<Buffer<ArrayBuffer> | undefined>; // Profile photo cannot be larger than 2GB, right?
} }
downloadStickerSetThumb(stickerSet: Api.StickerSet) { downloadStickerSetThumb(stickerSet: Api.StickerSet) {
@ -859,7 +855,7 @@ class TelegramClient {
thumbVersion, thumbVersion,
}), }),
{ dcId: stickerSet.thumbDcId! }, { dcId: stickerSet.thumbDcId! },
) as Promise<Buffer | undefined>; // Sticker thumb cannot be larger than 2GB, right? ) as Promise<Buffer<ArrayBuffer> | undefined>; // Sticker thumb cannot be larger than 2GB, right?
} }
return this.invoke(new Api.messages.GetCustomEmojiDocuments({ return this.invoke(new Api.messages.GetCustomEmojiDocuments({
@ -879,7 +875,7 @@ class TelegramClient {
{ {
fileSize: toJSNumber(doc.size), fileSize: toJSNumber(doc.size),
dcId: doc.dcId, dcId: doc.dcId,
}) as Promise<Buffer | undefined>; // Sticker thumb cannot be larger than 2GB, right? }) as Promise<Buffer<ArrayBuffer> | undefined>; // Sticker thumb cannot be larger than 2GB, right?
}); });
} }
@ -905,7 +901,7 @@ class TelegramClient {
return undefined; return undefined;
} }
_downloadCachedPhotoSize(size: Api.PhotoCachedSize | Api.PhotoStrippedSize) { _downloadCachedPhotoSize(size: Api.PhotoCachedSize | Api.PhotoStrippedSize): Buffer<ArrayBuffer> {
// No need to download anything, simply write the bytes // No need to download anything, simply write the bytes
let data; let data;
if (size instanceof Api.PhotoStrippedSize) { if (size instanceof Api.PhotoStrippedSize) {
@ -1191,7 +1187,7 @@ class TelegramClient {
state.after = undefined; state.after = undefined;
} else if (e instanceof RPCError && e.errorMessage === 'CONNECTION_NOT_INITED') { } else if (e instanceof RPCError && e.errorMessage === 'CONNECTION_NOT_INITED') {
await this.disconnect(); this.disconnect();
await sleep(2000); await sleep(2000);
await this.connect(); await this.connect();
} else if (e instanceof TimedOutError) { } else if (e instanceof TimedOutError) {
@ -1340,7 +1336,7 @@ class TelegramClient {
} }
} }
function timeout(cb: () => void, ms: number) { function timeout(cb: () => void | Promise<unknown>, ms: number) {
let isResolved = false; let isResolved = false;
return Promise.race([ return Promise.race([
@ -1351,7 +1347,7 @@ function timeout(cb: () => void, ms: number) {
}); });
} }
async function attempts(cb: () => Promise<void> | void, times: number, pause: number) { async function attempts(cb: () => Promise<unknown> | void, times: number, pause: number) {
for (let i = 0; i < times; i++) { for (let i = 0; i < times; i++) {
try { try {
// We need to `return await` here so it can be caught locally // We need to `return await` here so it can be caught locally

View File

@ -318,9 +318,9 @@ async function signInUserWithQrCode(
async function sendCode( async function sendCode(
client: TelegramClient, apiCredentials: ApiCredentials, phoneNumber: string, forceSMS = false, client: TelegramClient, apiCredentials: ApiCredentials, phoneNumber: string, forceSMS = false,
): Promise<{ ): Promise<{
phoneCodeHash: string; phoneCodeHash: string;
isCodeViaApp: boolean; isCodeViaApp: boolean;
}> { }> {
try { try {
const { apiId, apiHash } = apiCredentials; const { apiId, apiHash } = apiCredentials;
const sendResult = await client.invoke(new Api.auth.SendCode({ const sendResult = await client.invoke(new Api.auth.SendCode({

View File

@ -53,7 +53,7 @@ class FileView {
private size?: number; private size?: number;
private buffer?: Buffer; private buffer?: Buffer<ArrayBuffer>;
private largeFile?: FileSystemFileHandle; private largeFile?: FileSystemFileHandle;
@ -92,7 +92,7 @@ class FileView {
} }
} }
async getData(): Promise<Buffer | File> { async getData(): Promise<Buffer<ArrayBuffer> | File> {
if (this.type === 'opfs') { if (this.type === 'opfs') {
return this.largeFile!.getFile(); return this.largeFile!.getFile();
} else { } else {

View File

@ -9,15 +9,15 @@ import {
} from '../Helpers'; } from '../Helpers';
export class AuthKey { export class AuthKey {
_key?: Buffer; _key?: Buffer<ArrayBuffer>;
_hash?: Buffer; _hash?: Buffer<ArrayBuffer>;
private auxHash?: bigint; private auxHash?: bigint;
keyId?: bigint; keyId?: bigint;
constructor(value?: Buffer, hash?: Buffer) { constructor(value?: Buffer<ArrayBuffer>, hash?: Buffer<ArrayBuffer>) {
if (!hash || !value) { if (!hash || !value) {
return; return;
} }
@ -29,7 +29,7 @@ export class AuthKey {
this.keyId = reader.readLong(false); this.keyId = reader.readLong(false);
} }
async setKey(value?: Buffer | AuthKey) { async setKey(value?: Buffer<ArrayBuffer> | AuthKey) {
if (!value) { if (!value) {
this._key = undefined; this._key = undefined;
this.auxHash = undefined; this.auxHash = undefined;

View File

@ -13,11 +13,11 @@ export class CTR {
this.decipher = createDecipheriv('AES-256-CTR', key, iv); this.decipher = createDecipheriv('AES-256-CTR', key, iv);
} }
encrypt(data: Buffer) { encrypt(data: Buffer<ArrayBuffer>) {
return Buffer.from(this.cipher.update(data)); return Buffer.from(this.cipher.update(data));
} }
decrypt(data: Buffer) { decrypt(data: Buffer<ArrayBuffer>) {
return Buffer.from(this.decipher.update(data)); return Buffer.from(this.decipher.update(data));
} }
} }

View File

@ -14,7 +14,7 @@ class IGENEW {
* @param cipherText {Buffer} * @param cipherText {Buffer}
* @returns {Buffer} * @returns {Buffer}
*/ */
decryptIge(cipherText: Buffer): Buffer { decryptIge(cipherText: Buffer): Buffer<ArrayBuffer> {
return convertToLittle(this.ige.decrypt(cipherText)); return convertToLittle(this.ige.decrypt(cipherText));
} }
@ -23,7 +23,7 @@ class IGENEW {
* @param plainText {Buffer} * @param plainText {Buffer}
* @returns {Buffer} * @returns {Buffer}
*/ */
encryptIge(plainText: Buffer): Buffer { encryptIge(plainText: Buffer): Buffer<ArrayBuffer> {
const padding = plainText.length % 16; const padding = plainText.length % 16;
if (padding) { if (padding) {
plainText = Buffer.concat([ plainText = Buffer.concat([

View File

@ -20,14 +20,14 @@ export function i2abLow(buf: Uint32Array): ArrayBuffer {
/** /**
* Uint32Array -> ArrayBuffer (big-endian os) * Uint32Array -> ArrayBuffer (big-endian os)
*/ */
export function i2abBig(buf: Uint32Array): ArrayBuffer { export function i2abBig(buf: Uint32Array<ArrayBuffer>): ArrayBuffer {
return buf.buffer; return buf.buffer;
} }
/** /**
* ArrayBuffer -> Uint32Array (low-endian os) * ArrayBuffer -> Uint32Array (low-endian os)
*/ */
export function ab2iLow(ab: ArrayBuffer | SharedArrayBuffer | Uint8Array): Uint32Array { export function ab2iLow(ab: ArrayBuffer | Uint8Array): Uint32Array {
const uint8 = new Uint8Array(ab); const uint8 = new Uint8Array(ab);
const buf = new Uint32Array(uint8.length / 4); const buf = new Uint32Array(uint8.length / 4);
@ -46,7 +46,7 @@ export function ab2iLow(ab: ArrayBuffer | SharedArrayBuffer | Uint8Array): Uint3
/** /**
* ArrayBuffer -> Uint32Array (big-endian os) * ArrayBuffer -> Uint32Array (big-endian os)
*/ */
export function ab2iBig(ab: ArrayBuffer | SharedArrayBuffer | Uint8Array): Uint32Array { export function ab2iBig(ab: ArrayBuffer | Uint8Array): Uint32Array {
return new Uint32Array(ab); return new Uint32Array(ab);
} }

View File

@ -4,7 +4,7 @@ import { ab2i, i2ab } from './converters';
import { getWords } from './words'; import { getWords } from './words';
class Counter { class Counter {
_counter: Buffer; _counter: Buffer<ArrayBuffer>;
constructor(initialValue: Buffer) { constructor(initialValue: Buffer) {
this._counter = Buffer.from(initialValue); this._counter = Buffer.from(initialValue);
@ -44,16 +44,22 @@ class CTR {
this._aes = new AES(getWords(key)); this._aes = new AES(getWords(key));
} }
update(plainText: Buffer) { update(plainText: Buffer<ArrayBuffer>) {
return this.encrypt(plainText); return this.encrypt(plainText);
} }
encrypt(plainText: Buffer) { encrypt(plainText: Buffer<ArrayBuffer>) {
const encrypted = Buffer.from(plainText); const encrypted = Buffer.from(plainText);
for (let i = 0; i < encrypted.length; i++) { for (let i = 0; i < encrypted.length; i++) {
if (this._remainingCounterIndex === 16) { if (this._remainingCounterIndex === 16) {
this._remainingCounter = Buffer.from(i2ab(this._aes.encrypt(ab2i(this._counter._counter)))); this._remainingCounter = Buffer.from(
i2ab(
this._aes.encrypt(
ab2i(this._counter._counter),
) as Uint32Array<ArrayBuffer>,
),
);
this._remainingCounterIndex = 0; this._remainingCounterIndex = 0;
this._counter.increment(); this._counter.increment();
} }
@ -111,7 +117,7 @@ class Hash {
} }
} }
export async function pbkdf2(password: Buffer, salt: Buffer, iterations: number) { export async function pbkdf2(password: Buffer<ArrayBuffer>, salt: Buffer<ArrayBuffer>, iterations: number) {
const passwordKey = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveBits']); const passwordKey = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveBits']);
return Buffer.from(await crypto.subtle.deriveBits({ return Buffer.from(await crypto.subtle.deriveBits({
name: 'PBKDF2', name: 'PBKDF2',

View File

@ -1,15 +1,15 @@
export default class BinaryWriter { export default class BinaryWriter {
private readonly _buffers: Buffer[]; private readonly _buffers: Buffer<ArrayBuffer>[];
constructor(stream: Buffer) { constructor(stream: Buffer<ArrayBuffer>) {
this._buffers = [stream]; this._buffers = [stream];
} }
write(buffer: Buffer) { write(buffer: Buffer<ArrayBuffer>) {
this._buffers.push(buffer); this._buffers.push(buffer);
} }
getValue(): Buffer { getValue(): Buffer<ArrayBuffer> {
return Buffer.concat(this._buffers); return Buffer.concat(this._buffers);
} }
} }

View File

@ -12,7 +12,7 @@ export default class HttpStream {
private isClosed: boolean; private isClosed: boolean;
private stream: Buffer[] = []; private stream: Buffer<ArrayBuffer>[] = [];
private canRead: Promise<void> = Promise.resolve(); private canRead: Promise<void> = Promise.resolve();
@ -80,7 +80,7 @@ export default class HttpStream {
this.isClosed = false; this.isClosed = false;
} }
write(data: Buffer) { write(data: Buffer<ArrayBuffer>) {
if (this.isClosed || !this.url) { if (this.isClosed || !this.url) {
this.handleDisconnect(); this.handleDisconnect();
throw closeError; throw closeError;

View File

@ -150,7 +150,7 @@ export default class PromisedWebSockets {
}); });
} }
write(data: Buffer) { write(data: Buffer<ArrayBuffer>) {
if (this.closed) { if (this.closed) {
throw closeError; throw closeError;
} }

View File

@ -141,7 +141,7 @@ export default class MTProtoState {
* @param afterId * @param afterId
*/ */
async writeDataAsMessage( async writeDataAsMessage(
buffer: BinaryWriter, data: Buffer, contentRelated: boolean, afterId?: bigint, buffer: BinaryWriter, data: Buffer<ArrayBuffer>, contentRelated: boolean, afterId?: bigint,
): Promise<bigint> { ): Promise<bigint> {
const msgId = this._getNewMsgId(); const msgId = this._getNewMsgId();
const seqNo = this._getSeqNo(contentRelated); const seqNo = this._getSeqNo(contentRelated);
@ -174,7 +174,7 @@ export default class MTProtoState {
* following MTProto 2.0 guidelines core.telegram.org/mtproto/description. * following MTProto 2.0 guidelines core.telegram.org/mtproto/description.
* @param data * @param data
*/ */
async encryptMessageData(data: Buffer) { async encryptMessageData(data: Buffer<ArrayBuffer>): Promise<Buffer<ArrayBuffer>> {
if (!this.authKey) { if (!this.authKey) {
throw new Error('Auth key unset'); throw new Error('Auth key unset');
} }
@ -237,7 +237,7 @@ export default class MTProtoState {
* Inverse of `encrypt_message_data` for incoming server messages. * Inverse of `encrypt_message_data` for incoming server messages.
* @param body * @param body
*/ */
async decryptMessageData(body: Buffer) { async decryptMessageData(body: Buffer<ArrayBuffer>) {
if (!this.authKey) { if (!this.authKey) {
throw new Error('Auth key unset'); throw new Error('Auth key unset');
} }

View File

@ -12,7 +12,7 @@ export default class RequestState<T extends CallableRequest = CallableRequest> {
public request: any; public request: any;
public data: Buffer; public data: Buffer<ArrayBuffer>;
public after: any; public after: any;

View File

@ -50,9 +50,9 @@ export class Connection {
protected _obfuscation: any; protected _obfuscation: any;
_sendArray: AsyncQueue<Buffer>; _sendArray: AsyncQueue<Buffer<ArrayBuffer>>;
_recvArray: AsyncQueue<Buffer | undefined>; _recvArray: AsyncQueue<Buffer<ArrayBuffer> | undefined>;
socket: PromisedWebSockets | HttpStream; socket: PromisedWebSockets | HttpStream;
@ -73,8 +73,8 @@ export class Connection {
this._recvTask = undefined; this._recvTask = undefined;
this._codec = undefined; this._codec = undefined;
this._obfuscation = undefined; // TcpObfuscated and MTProxy this._obfuscation = undefined; // TcpObfuscated and MTProxy
this._sendArray = new AsyncQueue<Buffer>(); this._sendArray = new AsyncQueue<Buffer<ArrayBuffer>>();
this._recvArray = new AsyncQueue<Buffer>(); this._recvArray = new AsyncQueue<Buffer<ArrayBuffer>>();
// this.socket = new PromiseSocket(new Socket()) // this.socket = new PromiseSocket(new Socket())
this.shouldLongPoll = false; this.shouldLongPoll = false;
@ -120,7 +120,7 @@ export class Connection {
} }
} }
async send(data: Buffer) { async send(data: Buffer<ArrayBuffer>) {
if (!this._connected) { if (!this._connected) {
throw new Error('Not connected'); throw new Error('Not connected');
} }
@ -241,7 +241,7 @@ export class HttpConnection extends Connection {
this.href = HttpStream.getURL(this._ip, this._port, this._isTestServer, this._isPremium); this.href = HttpStream.getURL(this._ip, this._port, this._isTestServer, this._isPremium);
} }
send(data: Buffer) { send(data: Buffer<ArrayBuffer>) {
return this.socket.write(data); return this.socket.write(data);
} }

View File

@ -81,7 +81,7 @@ class ObfuscatedIO {
return this._decrypt.encrypt(data); return this._decrypt.encrypt(data);
} }
write(data: Buffer) { write(data: Buffer<ArrayBuffer>) {
this.connection.write(this._encrypt.encrypt(data)); this.connection.write(this._encrypt.encrypt(data));
} }
} }

View File

@ -22,7 +22,7 @@ namespace Api {
type int128 = bigint; type int128 = bigint;
type int256 = bigint; type int256 = bigint;
type long = bigint; type long = bigint;
type bytes = Buffer; type bytes = Buffer<ArrayBuffer>;
class VirtualClass<Args extends AnyLiteral> { class VirtualClass<Args extends AnyLiteral> {
static CONSTRUCTOR_ID: number; static CONSTRUCTOR_ID: number;
@ -30,9 +30,9 @@ namespace Api {
static className: string; static className: string;
static classType: 'constructor' | 'request'; static classType: 'constructor' | 'request';
static serializeBytes(data: Buffer | string): Buffer; static serializeBytes(data: Buffer<ArrayBuffer> | string): Buffer<ArrayBuffer>;
getBytes(): Buffer; getBytes(): Buffer<ArrayBuffer>;
CONSTRUCTOR_ID: number; CONSTRUCTOR_ID: number;
SUBCLASS_OF_ID: number; SUBCLASS_OF_ID: number;
className: string; className: string;
@ -42,7 +42,7 @@ namespace Api {
} }
class Request<Args, Response> extends VirtualClass<Args> { class Request<Args, Response> extends VirtualClass<Args> {
static readResult(reader: Reader): Buffer; static readResult(reader: Reader): Buffer<ArrayBuffer>;
__response: Response; __response: Response;
} }

View File

@ -9,19 +9,19 @@ export default class GZIPPacked {
static classType = 'constructor'; static classType = 'constructor';
data: Buffer; data: Buffer<ArrayBuffer>;
private CONSTRUCTOR_ID: number; private CONSTRUCTOR_ID: number;
private classType: string; private classType: string;
constructor(data: Buffer) { constructor(data: Buffer<ArrayBuffer>) {
this.data = data; this.data = data;
this.CONSTRUCTOR_ID = 0x3072cfa1; this.CONSTRUCTOR_ID = 0x3072cfa1;
this.classType = 'constructor'; this.classType = 'constructor';
} }
static async gzipIfSmaller(contentRelated: boolean, data: Buffer) { static async gzipIfSmaller(contentRelated: boolean, data: Buffer<ArrayBuffer>) {
if (contentRelated && data.length > 512) { if (contentRelated && data.length > 512) {
const gzipped = await new GZIPPacked(data).toBytes(); const gzipped = await new GZIPPacked(data).toBytes();
if (gzipped.length < data.length) { if (gzipped.length < data.length) {
@ -31,7 +31,7 @@ export default class GZIPPacked {
return data; return data;
} }
static gzip(input: Buffer) { static gzip(input: Buffer<ArrayBuffer>) {
return Buffer.from(input); return Buffer.from(input);
// TODO this usually makes it faster for large requests // TODO this usually makes it faster for large requests
// return Buffer.from(deflate(input, { level: 9, gzip: true })) // return Buffer.from(deflate(input, { level: 9, gzip: true }))

View File

@ -179,7 +179,7 @@ namespace Api {
type int128 = bigint; type int128 = bigint;
type int256 = bigint; type int256 = bigint;
type long = bigint; type long = bigint;
type bytes = Buffer; type bytes = Buffer<ArrayBuffer>;
class VirtualClass<Args extends AnyLiteral> { class VirtualClass<Args extends AnyLiteral> {
static CONSTRUCTOR_ID: number; static CONSTRUCTOR_ID: number;
@ -187,9 +187,9 @@ namespace Api {
static className: string; static className: string;
static classType: 'constructor' | 'request'; static classType: 'constructor' | 'request';
static serializeBytes(data: Buffer | string): Buffer; static serializeBytes(data: Buffer<ArrayBuffer> | string): Buffer<ArrayBuffer>;
getBytes(): Buffer; getBytes(): Buffer<ArrayBuffer>;
CONSTRUCTOR_ID: number; CONSTRUCTOR_ID: number;
SUBCLASS_OF_ID: number; SUBCLASS_OF_ID: number;
className: string; className: string;
@ -199,7 +199,7 @@ namespace Api {
} }
class Request<Args, Response> extends VirtualClass<Args> { class Request<Args, Response> extends VirtualClass<Args> {
static readResult(reader: Reader): Buffer; static readResult(reader: Reader): Buffer<ArrayBuffer>;
__response: Response; __response: Response;
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable react-x/no-unnecessary-use-prefix */
import type { ReactElement } from 'react'; import type { ReactElement } from 'react';
import { DEBUG, DEBUG_MORE } from '../../config'; import { DEBUG, DEBUG_MORE } from '../../config';

View File

@ -147,7 +147,7 @@
max-width: 0 !important; max-width: 0 !important;
opacity: 0; opacity: 0;
clip: rect(0, 0, 0, 0); clip-path: inset(50%);
} }
&::-ms-clear, &::-ms-clear,

View File

@ -172,7 +172,7 @@ body.cursor-ew-resize {
width: 0; width: 0;
height: 0; height: 0;
clip: rect(0, 0, 0, 0); clip-path: inset(50%);
} }
.custom-scroll, .custom-scroll,

View File

@ -650,11 +650,11 @@ export type ConfettiParams = OptionalCombine<{
style?: ConfettiStyle; style?: ConfettiStyle;
withStars?: boolean; withStars?: boolean;
}, { }, {
top?: number; top?: number;
left?: number; left?: number;
width?: number; width?: number;
height?: number; height?: number;
}>; }>;
export interface Size { export interface Size {
width: number; width: number;

View File

@ -328,11 +328,11 @@ interface WebAppOutboundEventMap {
} }
export type WebAppInboundEvent = export type WebAppInboundEvent =
{ [K in keyof WebAppInboundEventMap]: { [K in keyof WebAppInboundEventMap]:
WebAppEvent<K, WebAppInboundEventMap[K]> WebAppEvent<K, WebAppInboundEventMap[K]>
}[keyof WebAppInboundEventMap]; }[keyof WebAppInboundEventMap];
export type WebAppOutboundEvent = export type WebAppOutboundEvent =
{ [K in keyof WebAppOutboundEventMap]: { [K in keyof WebAppOutboundEventMap]:
WebAppEvent<K, WebAppOutboundEventMap[K]> WebAppEvent<K, WebAppOutboundEventMap[K]>
}[keyof WebAppOutboundEventMap]; }[keyof WebAppOutboundEventMap];

View File

@ -14,7 +14,7 @@ export async function parseAudioMetadata(url: string): Promise<AudioMetadata> {
const { common: { title, artist, picture }, format: { duration } } = metadata; const { common: { title, artist, picture }, format: { duration } } = metadata;
const cover = selectCover(picture); const cover = selectCover(picture);
const coverBlob = cover ? new Blob([cover.data], { type: cover.format }) : undefined; const coverBlob = cover ? new Blob([cover.data as Uint8Array<ArrayBuffer>], { type: cover.format }) : undefined;
const coverUrl = coverBlob ? URL.createObjectURL(coverBlob) : undefined; const coverUrl = coverBlob ? URL.createObjectURL(coverBlob) : undefined;
return { return {

View File

@ -1,8 +1,8 @@
import { getActions, getGlobal } from '../global'; import { getActions, getGlobal } from '../../global';
import { selectCustomEmoji } from '../global/selectors'; import { selectCustomEmoji } from '../../global/selectors';
import { addCustomEmojiInputRenderCallback } from '../util/emoji/customEmojiManager'; import { throttle } from '../schedulers';
import { throttle } from '../util/schedulers'; import { addCustomEmojiInputRenderCallback } from './customEmojiManager';
let LOAD_QUEUE = new Set<string>(); let LOAD_QUEUE = new Set<string>();
const RENDER_HISTORY = new Set<string>(); const RENDER_HISTORY = new Set<string>();
@ -42,7 +42,7 @@ function notifyCustomEmojiRender(emojiId: string) {
addCustomEmojiInputRenderCallback(notifyCustomEmojiRender); addCustomEmojiInputRenderCallback(notifyCustomEmojiRender);
export default function useEnsureCustomEmoji(id?: string) { export default function ensureCustomEmoji(id?: string) {
if (!id) return; if (!id) return;
notifyCustomEmojiRender(id); notifyCustomEmojiRender(id);

View File

@ -31,7 +31,7 @@ export async function start(analyzerCallback: (volume: number) => void) {
const startedAt = Date.now(); const startedAt = Date.now();
let pausedAt: number; let pausedAt: number;
const chunks: Uint8Array[] = []; const chunks: Uint8Array<ArrayBuffer>[] = [];
const waveform: number[] = []; const waveform: number[] = [];
mediaRecorder.ondataavailable = (typedArray) => { mediaRecorder.ondataavailable = (typedArray) => {

1042
tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package] [package]
name = "telegram_air" name = "telegram_air"
version = "2.8.13" version = "2.8.14"
description = "Telegram Air" description = "Telegram Air"
authors = ["Alexander Zinchuk"] authors = ["Alexander Zinchuk"]
license = "GPLv3" license = "GPLv3"
@ -14,8 +14,8 @@ rust-version = "1.85"
tauri-build = { version = "2.4.1", features = [] } tauri-build = { version = "2.4.1", features = [] }
[dependencies] [dependencies]
serde = { version = "1.0.219", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.143" serde_json = "1.0.145"
tauri = { version = "2.8.5", features = [ "devtools", "unstable", "config-json5", "tray-icon", "image-png"] } tauri = { version = "2.8.5", features = [ "devtools", "unstable", "config-json5", "tray-icon", "image-png"] }
tauri-plugin-window-state = "2.4.0" tauri-plugin-window-state = "2.4.0"
tauri-plugin-shell = "2.3.1" tauri-plugin-shell = "2.3.1"
@ -24,17 +24,17 @@ tauri-plugin-notification = "2.3.1"
tauri-plugin-updater = "2.9.0" tauri-plugin-updater = "2.9.0"
tauri-plugin-process = "2.3.0" tauri-plugin-process = "2.3.0"
tauri-plugin-fs = "2.4.2" tauri-plugin-fs = "2.4.2"
tauri-plugin-deep-link = "2.4.2" tauri-plugin-deep-link = "2.4.3"
log = "0.4.27" log = "0.4.28"
uuid = { version = "1.18.0", features = ["v4"] } uuid = { version = "1.18.1", features = ["v4"] }
url = "2.5.7" url = "2.5.7"
image = "0.25.6" image = "0.25.8"
imageproc = "0.25.0" imageproc = "0.25.0"
ab_glyph = "0.2.31" ab_glyph = "0.2.32"
tauri-plugin-os = "2" tauri-plugin-os = "2.3.1"
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies] [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies]
tauri-plugin-single-instance = { version = "2.3.3", features = ["deep-link"] } tauri-plugin-single-instance = { version = "2.3.4", features = ["deep-link"] }
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.26.1" cocoa = "0.26.1"