diff --git a/app/attachment_channel.ts b/app/attachment_channel.ts index 9bc651cdbd9..01cccd1bdb4 100644 --- a/app/attachment_channel.ts +++ b/app/attachment_channel.ts @@ -6,7 +6,7 @@ import { DigestingPassThrough, ValidatingPassThrough, inferChunkSize, -} from '@signalapp/libsignal-client/dist/incremental_mac'; +} from '@signalapp/libsignal-client/dist/incremental_mac.js'; import { ipcMain, protocol } from 'electron'; import { LRUCache } from 'lru-cache'; import { randomBytes } from 'node:crypto'; @@ -17,7 +17,7 @@ import { PassThrough, type Writable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; import z from 'zod'; import GrowingFile from 'growing-file'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { type DecryptAttachmentToSinkOptionsType, @@ -65,6 +65,8 @@ import { getTempPath, } from './attachments.js'; +const { isNumber } = lodash; + const log = createLogger('attachment_channel'); let initialized = false; diff --git a/app/attachments.ts b/app/attachments.ts index 8c0be8a886e..f9cf94481f9 100644 --- a/app/attachments.ts +++ b/app/attachments.ts @@ -7,7 +7,7 @@ import { join, relative, normalize } from 'node:path'; import pMap from 'p-map'; import fastGlob from 'fast-glob'; import fse from 'fs-extra'; -import { map, isString } from 'lodash'; +import lodash from 'lodash'; import normalizePath from 'normalize-path'; import { isPathInside } from '../ts/util/isPathInside.js'; import { DAY } from '../ts/util/durations/index.js'; @@ -22,6 +22,8 @@ import type { LocalAttachmentV2Type } from '../ts/types/Attachment.js'; import * as Errors from '../ts/types/errors.js'; import { createLogger } from '../ts/logging/log.js'; +const { map, isString } = lodash; + const log = createLogger('attachments'); const PATH = 'attachments.noindex'; diff --git a/app/base_config.ts b/app/base_config.ts index 23694b29705..ffcaff6320c 100644 --- a/app/base_config.ts +++ b/app/base_config.ts @@ -4,11 +4,15 @@ import { readFileSync, unlinkSync } from 'node:fs'; import { sync as writeFileSync } from 'write-file-atomic'; -import { get } from 'lodash'; -import { set } from 'lodash/fp'; +import lodash from 'lodash'; +import lodashFp from 'lodash/fp.js'; import { strictAssert } from '../ts/util/assert.js'; import { createLogger } from '../ts/logging/log.js'; +const { set } = lodashFp; + +const { get } = lodash; + const log = createLogger('base_config'); const ENCODING = 'utf8'; diff --git a/app/crashReports.ts b/app/crashReports.ts index 573dbec71c2..e43b86b063e 100644 --- a/app/crashReports.ts +++ b/app/crashReports.ts @@ -2,9 +2,9 @@ // SPDX-License-Identifier: AGPL-3.0-only import { app, crashReporter, ipcMain as ipc } from 'electron'; -import { realpath, readdir, readFile, unlink, stat } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { basename, join } from 'node:path'; -import { toJSONString as dumpToJSONString } from '@signalapp/libsignal-client/dist/Minidump'; +import { toJSONString as dumpToJSONString } from '@signalapp/libsignal-client/dist/Minidump.js'; import z from 'zod'; import type { LoggerType } from '../ts/types/Logging.js'; @@ -14,6 +14,8 @@ import { isNotNil } from '../ts/util/isNotNil.js'; import OS from '../ts/util/os/osMain.js'; import { parseUnknown } from '../ts/util/schemas.js'; +const { realpath, readdir, readFile, unlink, stat } = fsExtra; + // See https://github.com/rust-minidump/rust-minidump/blob/main/minidump-processor/json-schema.md const dumpString = z.string().or(z.null()).optional(); const dumpNumber = z.number().or(z.null()).optional(); diff --git a/app/locale.ts b/app/locale.ts index 3f0eab454cc..576bf821697 100644 --- a/app/locale.ts +++ b/app/locale.ts @@ -4,7 +4,7 @@ import { join } from 'node:path'; import { readFileSync } from 'node:fs'; import { app } from 'electron'; -import { merge } from 'lodash'; +import lodash from 'lodash'; import * as LocaleMatcher from '@formatjs/intl-localematcher'; import { z } from 'zod'; import { setupI18n } from '../ts/util/setupI18nMain.js'; @@ -19,6 +19,8 @@ import type { LocalizerType } from '../ts/types/Util.js'; import * as Errors from '../ts/types/errors.js'; import { parseUnknown } from '../ts/util/schemas.js'; +const { merge } = lodash; + type CompactLocaleMessagesType = ReadonlyArray; type CompactLocaleKeysType = ReadonlyArray; diff --git a/app/main.ts b/app/main.ts index 2a654bb75b8..b2cf69d52e4 100644 --- a/app/main.ts +++ b/app/main.ts @@ -4,13 +4,13 @@ import { join, normalize, extname, dirname, basename } from 'node:path'; import { pathToFileURL } from 'node:url'; import * as os from 'node:os'; -import { chmod, realpath, writeFile } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { randomBytes } from 'node:crypto'; import { createParser } from 'dashdash'; import fastGlob from 'fast-glob'; import PQueue from 'p-queue'; -import { get, pick, isNumber, isBoolean, some, debounce, noop } from 'lodash'; +import lodash from 'lodash'; import { app, BrowserWindow, @@ -32,7 +32,10 @@ import { import type { MenuItemConstructorOptions, Settings } from 'electron'; import { z } from 'zod'; -import packageJson from '../package.json'; +import { + version as packageVersion, + productName, +} from '../ts/util/packageJson.js'; import * as GlobalErrors from './global_errors.js'; import { setup as setupCrashReports } from './crashReports.js'; import { setup as setupSpellChecker } from './spell_check.js'; @@ -126,6 +129,9 @@ import { safeParseLoose, safeParseUnknown } from '../ts/util/schemas.js'; import { getAppErrorIcon } from '../ts/util/getAppErrorIcon.js'; import { promptOSAuth } from '../ts/util/os/promptOSAuthMain.js'; +const { chmod, realpath, writeFile } = fsExtra; +const { get, pick, isNumber, isBoolean, some, debounce, noop } = lodash; + const log = createLogger('app/main'); const updaterLog = log.child('updater'); @@ -2119,7 +2125,7 @@ app.on('ready', async () => { } log.info('app ready'); - log.info(`starting version ${packageJson.version}`); + log.info(`starting version ${packageVersion}`); // This logging helps us debug user reports about broken devices. { @@ -2695,7 +2701,7 @@ ipc.on('get-config', async event => { } const parsed = safeParseLoose(rendererConfigSchema, { - name: packageJson.productName, + name: productName, availableLocales: getResolvedMessagesLocale().availableLocales, resolvedTranslationsLocale: getResolvedMessagesLocale().name, resolvedTranslationsLocaleDirection: getResolvedMessagesLocale().direction, diff --git a/app/menu.ts b/app/menu.ts index 9d2c3a67f03..4c4281db128 100644 --- a/app/menu.ts +++ b/app/menu.ts @@ -1,7 +1,7 @@ // Copyright 2017 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isString } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../ts/types/I18N.js'; import type { @@ -10,6 +10,8 @@ import type { MenuActionsType, } from '../ts/types/menu.js'; +const { isString } = lodash; + export type CreateTemplateOptionsType = MenuOptionsType & MenuActionsType; export const createTemplate = ( diff --git a/app/startup_config.ts b/app/startup_config.ts index 336d3c9219f..f8170eece56 100644 --- a/app/startup_config.ts +++ b/app/startup_config.ts @@ -3,7 +3,7 @@ import { app } from 'electron'; -import packageJson from '../package.json'; +import { name } from '../ts/util/packageJson.js'; import { createLogger } from '../ts/logging/log.js'; import * as GlobalErrors from './global_errors.js'; @@ -15,7 +15,7 @@ GlobalErrors.addHandler(); // set such that only we have read access to our files process.umask(0o077); -export const AUMID = `org.whispersystems.${packageJson.name}`; +export const AUMID = `org.whispersystems.${name}`; log.info('Set Windows Application User Model ID (AUMID)', { AUMID, }); diff --git a/scripts/generate-acknowledgments.js b/scripts/generate-acknowledgments.js index 32edef1cbd6..0bc9bb4e8f4 100644 --- a/scripts/generate-acknowledgments.js +++ b/scripts/generate-acknowledgments.js @@ -7,15 +7,14 @@ const { join } = require('node:path'); const pMap = require('p-map'); const prettier = require('prettier'); +const { default: packageJson } = require('./packageJson.js'); + // During development, you might use local versions of dependencies which are missing // acknowledgment files. In this case we'll skip rebuilding the acknowledgment files. // Enable this flag to throw an error. const REQUIRE_SIGNAL_LIB_FILES = Boolean(process.env.REQUIRE_SIGNAL_LIB_FILES); -const { - dependencies = {}, - optionalDependencies = {}, -} = require('../package.json'); +const { dependencies = {}, optionalDependencies = {} } = packageJson; const SIGNAL_LIBS = ['@signalapp/libsignal-client', '@signalapp/ringrtc']; diff --git a/scripts/packageJson.js b/scripts/packageJson.js new file mode 100644 index 00000000000..47e12066f2a --- /dev/null +++ b/scripts/packageJson.js @@ -0,0 +1,15 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +const { readFileSync } = require('node:fs'); +const { join } = require('node:path'); + +const PACKAGE_JSON_PATH = join(__dirname, '..', 'package.json'); + +const json = JSON.parse(readFileSync(PACKAGE_JSON_PATH, 'utf8')); + +exports.default = json; +exports.name = json.name; +exports.version = json.version; +exports.productName = json.productName; +exports.build = json.build; diff --git a/scripts/prepare_adhoc_build.js b/scripts/prepare_adhoc_build.js index 3d195b6a719..774c649bb0f 100644 --- a/scripts/prepare_adhoc_build.js +++ b/scripts/prepare_adhoc_build.js @@ -4,11 +4,8 @@ const fs = require('node:fs'); const _ = require('lodash'); const { execSync } = require('node:child_process'); - -const packageJson = require('../package.json'); const { isAdhoc } = require('../ts/util/version.js'); - -const { version } = packageJson; +const { default: packageJson, version } = require('./packageJson.js'); // You might be wondering why this file is necessary. It comes down to our desire to allow // side-by-side installation of production and adhoc builds. Electron-Builder uses diff --git a/scripts/prepare_alpha_build.js b/scripts/prepare_alpha_build.js index bd28ae713d6..abd0160d284 100644 --- a/scripts/prepare_alpha_build.js +++ b/scripts/prepare_alpha_build.js @@ -4,10 +4,8 @@ const fs = require('node:fs'); const _ = require('lodash'); -const packageJson = require('../package.json'); const { isAlpha } = require('../ts/util/version.js'); - -const { version } = packageJson; +const { default: packageJson, version } = require('./packageJson.js'); // You might be wondering why this file is necessary. It comes down to our desire to allow // side-by-side installation of production and alpha builds. Electron-Builder uses diff --git a/scripts/prepare_axolotl_build.js b/scripts/prepare_axolotl_build.js index 4fd16e5ef6a..d9938a300f7 100644 --- a/scripts/prepare_axolotl_build.js +++ b/scripts/prepare_axolotl_build.js @@ -4,10 +4,8 @@ const fs = require('node:fs'); const _ = require('lodash'); -const packageJson = require('../package.json'); const { isAxolotl } = require('../ts/util/version.js'); - -const { version } = packageJson; +const { default: packageJson, version } = require('./packageJson.js'); // You might be wondering why this file is necessary. It comes down to our desire to allow // side-by-side installation of production and alpha builds. Electron-Builder uses diff --git a/scripts/prepare_beta_build.js b/scripts/prepare_beta_build.js index 6366d93225e..26a90527d14 100644 --- a/scripts/prepare_beta_build.js +++ b/scripts/prepare_beta_build.js @@ -4,10 +4,8 @@ const fs = require('node:fs'); const _ = require('lodash'); -const packageJson = require('../package.json'); const { isBeta } = require('../ts/util/version.js'); - -const { version } = packageJson; +const { default: packageJson, version } = require('./packageJson.js'); // You might be wondering why this file is necessary. It comes down to our desire to allow // side-by-side installation of production and beta builds. Electron-Builder uses diff --git a/scripts/prepare_staging_build.js b/scripts/prepare_staging_build.js index 981a6fd37d9..2e74ae5deba 100644 --- a/scripts/prepare_staging_build.js +++ b/scripts/prepare_staging_build.js @@ -1,13 +1,11 @@ -// Copyright 2022 Signal Messenger, LLC +// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only const fs = require('node:fs'); const _ = require('lodash'); -const packageJson = require('../package.json'); const { isAlpha } = require('../ts/util/version.js'); - -const { version } = packageJson; +const { default: packageJson, version } = require('./packageJson.js'); // You might be wondering why this file is necessary. It comes down to our desire to allow // side-by-side installation of production and staging builds. Electron-Builder uses diff --git a/scripts/prepare_tagged_version.js b/scripts/prepare_tagged_version.js index b3a493d1396..9e2e7dbe56f 100644 --- a/scripts/prepare_tagged_version.js +++ b/scripts/prepare_tagged_version.js @@ -5,6 +5,10 @@ const fs = require('node:fs'); const { execSync } = require('node:child_process'); const _ = require('lodash'); +const { + default: packageJson, + version: currentVersion, +} = require('./packageJson.js'); const release = process.argv[2]; if (release !== 'alpha' && release !== 'axolotl' && release !== 'adhoc') { @@ -14,10 +18,6 @@ if (release !== 'alpha' && release !== 'axolotl' && release !== 'adhoc') { const { generateTaggedVersion } = require('../ts/util/version.js'); -const packageJson = require('../package.json'); - -const { version: currentVersion } = packageJson; - const shortSha = execSync('git rev-parse --short HEAD') .toString('utf8') .replace(/[\n\r]/g, ''); diff --git a/ts/AttachmentCrypto.ts b/ts/AttachmentCrypto.ts index 3a95a98c593..5551e9e0bf5 100644 --- a/ts/AttachmentCrypto.ts +++ b/ts/AttachmentCrypto.ts @@ -14,16 +14,16 @@ import type { Hash } from 'node:crypto'; import { PassThrough, Transform, type Writable, Readable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; -import { isNumber } from 'lodash'; -import { ensureFile } from 'fs-extra'; +import lodash from 'lodash'; +import fsExtra from 'fs-extra'; import { chunkSizeInBytes, DigestingPassThrough, everyNthByte, inferChunkSize, ValidatingPassThrough, -} from '@signalapp/libsignal-client/dist/incremental_mac'; -import type { ChunkSizeChoice } from '@signalapp/libsignal-client/dist/incremental_mac'; +} from '@signalapp/libsignal-client/dist/incremental_mac.js'; +import type { ChunkSizeChoice } from '@signalapp/libsignal-client/dist/incremental_mac.js'; import { isAbsolute } from 'node:path'; import { createLogger } from './logging/log.js'; @@ -53,6 +53,10 @@ import { getEnvironment, Environment } from './environment.js'; import { isNotEmpty, toBase64, toHex } from './Bytes.js'; import { decipherWithAesKey } from './util/decipherWithAesKey.js'; +const { ensureFile } = fsExtra; + +const { isNumber } = lodash; + const log = createLogger('AttachmentCrypto'); // This file was split from ts/Crypto.ts because it pulls things in from node, and diff --git a/ts/ConversationController.ts b/ts/ConversationController.ts index a441bfebdd1..f046b6beeae 100644 --- a/ts/ConversationController.ts +++ b/ts/ConversationController.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { debounce, pick, uniq, without } from 'lodash'; +import lodash from 'lodash'; import PQueue from 'p-queue'; import { v4 as generateUuid } from 'uuid'; @@ -54,6 +54,8 @@ import type { PniString, } from './types/ServiceId.js'; +const { debounce, pick, uniq, without } = lodash; + const log = createLogger('ConversationController'); type ConvoMatchType = diff --git a/ts/Crypto.ts b/ts/Crypto.ts index 62536bf52a1..2fccd940fe6 100644 --- a/ts/Crypto.ts +++ b/ts/Crypto.ts @@ -2,10 +2,10 @@ // SPDX-License-Identifier: AGPL-3.0-only import Long from 'long'; -import { sample } from 'lodash'; +import lodash from 'lodash'; import { Aci, Pni, hkdf } from '@signalapp/libsignal-client'; import type { PublicKey, PrivateKey } from '@signalapp/libsignal-client'; -import { AccountEntropyPool } from '@signalapp/libsignal-client/dist/AccountKeys'; +import { AccountEntropyPool } from '@signalapp/libsignal-client/dist/AccountKeys.js'; import * as Bytes from './Bytes.js'; import { Crypto } from './context/Crypto.js'; @@ -20,6 +20,8 @@ import { toWebSafeBase64 } from './util/webSafeBase64.js'; import type { AciString, PniString } from './types/ServiceId.js'; +const { sample } = lodash; + export { HashType, CipherType }; const PROFILE_IV_LENGTH = 12; // bytes diff --git a/ts/LibSignalStores.ts b/ts/LibSignalStores.ts index c30b80796ae..bf8f1dd62c0 100644 --- a/ts/LibSignalStores.ts +++ b/ts/LibSignalStores.ts @@ -3,7 +3,7 @@ /* eslint-disable max-classes-per-file */ -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import type { Direction, @@ -33,6 +33,8 @@ import { normalizeServiceId } from './types/ServiceId.js'; import type { Zone } from './util/Zone.js'; +const { isNumber } = lodash; + function encodeAddress(address: ProtocolAddress): Address { const name = address.name(); const deviceId = address.deviceId(); diff --git a/ts/RemoteConfig.ts b/ts/RemoteConfig.ts index 6fa5b8a4978..5adaec1f27f 100644 --- a/ts/RemoteConfig.ts +++ b/ts/RemoteConfig.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { get, throttle } from 'lodash'; +import lodash from 'lodash'; import type { WebAPIType } from './textsecure/WebAPI.js'; import { createLogger } from './logging/log.js'; @@ -14,6 +14,8 @@ import { HashType } from './types/Crypto.js'; import { getCountryCode } from './types/PhoneNumber.js'; import { parseRemoteClientExpiration } from './util/parseRemoteClientExpiration.js'; +const { get, throttle } = lodash; + const log = createLogger('RemoteConfig'); const KnownConfigKeys = [ diff --git a/ts/SignalProtocolStore.ts b/ts/SignalProtocolStore.ts index 9d9f1350d54..563405f0f8d 100644 --- a/ts/SignalProtocolStore.ts +++ b/ts/SignalProtocolStore.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import PQueue from 'p-queue'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import { z } from 'zod'; import { EventEmitter } from 'node:events'; @@ -69,6 +69,8 @@ import { import { formatGroups, groupWhile } from './util/groupWhile.js'; import { parseUnknown } from './util/schemas.js'; +const { omit } = lodash; + const log = createLogger('SignalProtocolStore'); const TIMESTAMP_THRESHOLD = 5 * 1000; // 5 seconds diff --git a/ts/background.ts b/ts/background.ts index 667ebc7e1dd..3084e7f29f5 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber, throttle } from 'lodash'; +import lodash from 'lodash'; import { createRoot } from 'react-dom/client'; import PQueue from 'p-queue'; import pMap from 'p-map'; @@ -228,6 +228,8 @@ import { NavTab, SettingsPage, ProfileEditorPage } from './types/Nav.js'; import { initialize as initializeDonationService } from './services/donations.js'; import { MessageRequestResponseSource } from './types/MessageRequestResponseEvent.js'; +const { isNumber, throttle } = lodash; + const log = createLogger('background'); export function isOverHourIntoPast(timestamp: number): boolean { diff --git a/ts/badges/getBadgeImageFileLocalPath.ts b/ts/badges/getBadgeImageFileLocalPath.ts index 8254a70d346..cb88d7929b5 100644 --- a/ts/badges/getBadgeImageFileLocalPath.ts +++ b/ts/badges/getBadgeImageFileLocalPath.ts @@ -1,10 +1,12 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { find, findLast, first, last } from 'lodash'; +import lodash from 'lodash'; import type { BadgeType } from './types.js'; import { BadgeImageTheme } from './BadgeImageTheme.js'; +const { find, findLast, first, last } = lodash; + export function getBadgeImageFileLocalPath( badge: Readonly, size: number, diff --git a/ts/badges/parseBadgesFromServer.ts b/ts/badges/parseBadgesFromServer.ts index ffb932e07aa..1228a08fd6c 100644 --- a/ts/badges/parseBadgesFromServer.ts +++ b/ts/badges/parseBadgesFromServer.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as z from 'zod'; -import { isEmpty } from 'lodash'; +import lodash from 'lodash'; import { isRecord } from '../util/isRecord.js'; import { isNormalNumber } from '../util/isNormalNumber.js'; import { createLogger } from '../logging/log.js'; @@ -11,6 +11,8 @@ import { parseBadgeCategory } from './BadgeCategory.js'; import { BadgeImageTheme, parseBadgeImageTheme } from './BadgeImageTheme.js'; import { safeParseUnknown } from '../util/schemas.js'; +const { isEmpty } = lodash; + const log = createLogger('parseBadgesFromServer'); const MAX_BADGES = 1000; diff --git a/ts/components/AddUserToAnotherGroupModal.tsx b/ts/components/AddUserToAnotherGroupModal.tsx index ef2adb13429..7bbf9f311ff 100644 --- a/ts/components/AddUserToAnotherGroupModal.tsx +++ b/ts/components/AddUserToAnotherGroupModal.tsx @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { pick } from 'lodash'; +import lodash from 'lodash'; import React, { useCallback } from 'react'; import type { ListRowProps } from 'react-virtualized'; @@ -23,6 +23,8 @@ import { ListTile } from './ListTile.js'; import type { ShowToastAction } from '../state/ducks/toast.js'; import { SizeObserver } from '../hooks/useSizeObserver.js'; +const { pick } = lodash; + type OwnProps = { i18n: LocalizerType; contact: Pick; diff --git a/ts/components/AnimatedEmojiGalore.tsx b/ts/components/AnimatedEmojiGalore.tsx index 869f5ed4708..cc0015aceda 100644 --- a/ts/components/AnimatedEmojiGalore.tsx +++ b/ts/components/AnimatedEmojiGalore.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { animated, to as interpolate, useSprings } from '@react-spring/web'; -import { random } from 'lodash'; +import lodash from 'lodash'; import { useReducedMotion } from '../hooks/useReducedMotion.js'; import { FunStaticEmoji } from './fun/FunEmoji.js'; import { strictAssert } from '../util/assert.js'; @@ -13,6 +13,8 @@ import { isEmojiVariantValue, } from './fun/data/emojis.js'; +const { random } = lodash; + export type PropsType = { emoji: string; onAnimationEnd: () => unknown; diff --git a/ts/components/AnnouncementsOnlyGroupBanner.tsx b/ts/components/AnnouncementsOnlyGroupBanner.tsx index 7eb229c5731..269e5efe6d6 100644 --- a/ts/components/AnnouncementsOnlyGroupBanner.tsx +++ b/ts/components/AnnouncementsOnlyGroupBanner.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useState } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { ConversationType, ShowConversationType, @@ -12,6 +12,8 @@ import type { LocalizerType, ThemeType } from '../types/Util.js'; import { Modal } from './Modal.js'; import { ConversationListItem } from './conversationList/ConversationListItem.js'; +const { noop } = lodash; + type PropsType = { groupAdmins: Array; i18n: LocalizerType; diff --git a/ts/components/Avatar.tsx b/ts/components/Avatar.tsx index 8144eff1e14..a78cb954166 100644 --- a/ts/components/Avatar.tsx +++ b/ts/components/Avatar.tsx @@ -10,7 +10,7 @@ import type { } from 'react'; import React, { useEffect, useState } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { filterDOMProps } from '@react-aria/utils'; import type { AvatarColorType } from '../types/Colors.js'; @@ -28,6 +28,8 @@ import { isBadgeVisible } from '../badges/isBadgeVisible.js'; import { SIGNAL_AVATAR_PATH } from '../types/SignalConversation.js'; import { getAvatarPlaceholderGradient } from '../utils/getAvatarPlaceholderGradient.js'; +const { noop } = lodash; + const log = createLogger('Avatar'); export enum AvatarBlur { diff --git a/ts/components/AvatarEditor.tsx b/ts/components/AvatarEditor.tsx index 2b45a611c29..fa0ddd7580c 100644 --- a/ts/components/AvatarEditor.tsx +++ b/ts/components/AvatarEditor.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { isEqual } from 'lodash'; +import lodash from 'lodash'; import type { AvatarColorType } from '../types/Colors.js'; import type { @@ -24,6 +24,8 @@ import { isSameAvatarData } from '../util/isSameAvatarData.js'; import { missingCaseError } from '../util/missingCaseError.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.js'; +const { isEqual } = lodash; + export type PropsType = { avatarColor?: AvatarColorType; avatarUrl?: string; diff --git a/ts/components/AvatarLightbox.tsx b/ts/components/AvatarLightbox.tsx index 2413e537d48..d2809574f5c 100644 --- a/ts/components/AvatarLightbox.tsx +++ b/ts/components/AvatarLightbox.tsx @@ -2,13 +2,15 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { AvatarColorType } from '../types/Colors.js'; import { AvatarPreview } from './AvatarPreview.js'; import { Lightbox } from './Lightbox.js'; import type { LocalizerType } from '../types/Util.js'; +const { noop } = lodash; + export type PropsType = { avatarPlaceholderGradient?: Readonly<[string, string]>; avatarColor?: AvatarColorType; diff --git a/ts/components/AvatarPreview.stories.tsx b/ts/components/AvatarPreview.stories.tsx index 4b2f9eb7df2..ed0d8288ad9 100644 --- a/ts/components/AvatarPreview.stories.tsx +++ b/ts/components/AvatarPreview.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { chunk } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; @@ -11,6 +11,8 @@ import type { PropsType } from './AvatarPreview.js'; import { AvatarPreview } from './AvatarPreview.js'; import { AvatarColors } from '../types/Colors.js'; +const { chunk } = lodash; + const { i18n } = window.SignalContext; const TEST_IMAGE = new Uint8Array( diff --git a/ts/components/AvatarPreview.tsx b/ts/components/AvatarPreview.tsx index cbf5203979a..d0333c5f631 100644 --- a/ts/components/AvatarPreview.tsx +++ b/ts/components/AvatarPreview.tsx @@ -3,7 +3,7 @@ import type { CSSProperties } from 'react'; import React, { useEffect, useState } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import type { LocalizerType } from '../types/Util.js'; @@ -14,6 +14,8 @@ import { getInitials } from '../util/getInitials.js'; import { imagePathToBytes } from '../util/imagePathToBytes.js'; import { type ConversationType } from '../state/ducks/conversations.js'; +const { noop } = lodash; + const log = createLogger('AvatarPreview'); export type PropsType = { diff --git a/ts/components/AvatarTextEditor.tsx b/ts/components/AvatarTextEditor.tsx index 52063701a53..ee984925c24 100644 --- a/ts/components/AvatarTextEditor.tsx +++ b/ts/components/AvatarTextEditor.tsx @@ -9,7 +9,7 @@ import React, { useRef, useState, } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import * as grapheme from '../util/grapheme.js'; import { AvatarColorPicker } from './AvatarColorPicker.js'; @@ -25,6 +25,8 @@ import { getFontSizes, } from '../util/avatarTextSizeCalculator.js'; +const { noop } = lodash; + type DoneHandleType = ( avatarBuffer: Uint8Array, avatarData: AvatarDataType diff --git a/ts/components/AvatarUploadButton.tsx b/ts/components/AvatarUploadButton.tsx index 72e62259cc5..d243d9383b2 100644 --- a/ts/components/AvatarUploadButton.tsx +++ b/ts/components/AvatarUploadButton.tsx @@ -3,11 +3,13 @@ import type { ChangeEventHandler } from 'react'; import React, { useEffect, useRef, useState } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../types/Util.js'; import { processImageFile } from '../util/processImageFile.js'; +const { noop } = lodash; + export type PropsType = { className: string; i18n: LocalizerType; diff --git a/ts/components/BadgeCarouselIndex.tsx b/ts/components/BadgeCarouselIndex.tsx index bd8f31d9a22..d8332350ac6 100644 --- a/ts/components/BadgeCarouselIndex.tsx +++ b/ts/components/BadgeCarouselIndex.tsx @@ -3,10 +3,12 @@ import React from 'react'; import classNames from 'classnames'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { strictAssert } from '../util/assert.js'; +const { times } = lodash; + export function BadgeCarouselIndex({ currentIndex, totalCount, diff --git a/ts/components/BetterAvatar.tsx b/ts/components/BetterAvatar.tsx index 3fe1b0b23c5..5bfc3b51376 100644 --- a/ts/components/BetterAvatar.tsx +++ b/ts/components/BetterAvatar.tsx @@ -3,13 +3,15 @@ import type { MouseEvent } from 'react'; import React, { useEffect, useState } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { AvatarDataType } from '../types/Avatar.js'; import { BetterAvatarBubble } from './BetterAvatarBubble.js'; import type { LocalizerType } from '../types/Util.js'; import { Spinner } from './Spinner.js'; import { avatarDataToBytes } from '../util/avatarDataToBytes.js'; +const { noop } = lodash; + type AvatarSize = 48 | 80; export type PropsType = { diff --git a/ts/components/CallManager.tsx b/ts/components/CallManager.tsx index c70650def5e..6fe4ae4e2ec 100644 --- a/ts/components/CallManager.tsx +++ b/ts/components/CallManager.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useCallback, useEffect } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { VideoFrameSource } from '@signalapp/ringrtc'; import { CallNeedPermissionScreen } from './CallNeedPermissionScreen.js'; import { CallScreen } from './CallScreen.js'; @@ -61,6 +61,8 @@ import { import type { NotificationProfileType } from '../types/NotificationProfile.js'; import { strictAssert } from '../util/assert.js'; +const { noop } = lodash; + const log = createLogger('CallManager'); const GROUP_CALL_RING_DURATION = 60 * 1000; diff --git a/ts/components/CallReactionBurstEmoji.tsx b/ts/components/CallReactionBurstEmoji.tsx index a5b9b82bb14..91d16648f6c 100644 --- a/ts/components/CallReactionBurstEmoji.tsx +++ b/ts/components/CallReactionBurstEmoji.tsx @@ -3,11 +3,13 @@ import React from 'react'; import { animated, useSpring } from '@react-spring/web'; -import { random } from 'lodash'; +import lodash from 'lodash'; import { v4 as uuid } from 'uuid'; import { Emojify } from './conversation/Emojify.js'; import { useReducedMotion } from '../hooks/useReducedMotion.js'; +const { random } = lodash; + export type PropsType = { values: Array; onAnimationEnd?: () => unknown; diff --git a/ts/components/CallScreen.stories.tsx b/ts/components/CallScreen.stories.tsx index dabb74c05e9..84920578a37 100644 --- a/ts/components/CallScreen.stories.tsx +++ b/ts/components/CallScreen.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { sample, shuffle, times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; @@ -36,6 +36,8 @@ import { CallingToastProvider, useCallingToasts } from './CallingToast.js'; import type { CallingImageDataCache } from './CallManager.js'; import { MINUTE } from '../util/durations/index.js'; +const { sample, shuffle, times } = lodash; + const MAX_PARTICIPANTS = 75; const LOCAL_DEMUX_ID = 1; diff --git a/ts/components/CallScreen.tsx b/ts/components/CallScreen.tsx index 30a9d73bceb..c2cf0f6a5f8 100644 --- a/ts/components/CallScreen.tsx +++ b/ts/components/CallScreen.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from 'react'; import React, { useState, useRef, useEffect, useCallback } from 'react'; -import { isEqual, noop } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import type { VideoFrameSource } from '@signalapp/ringrtc'; import type { @@ -99,6 +99,8 @@ import { import { useFunEmojiLocalizer } from './fun/useFunEmojiLocalizer.js'; import { BeforeNavigateResponse } from '../services/BeforeNavigate.js'; +const { isEqual, noop } = lodash; + export type PropsType = { activeCall: ActiveCallType; approveUser: (payload: PendingUserActionPayloadType) => void; diff --git a/ts/components/CallingAdhocCallInfo.stories.tsx b/ts/components/CallingAdhocCallInfo.stories.tsx index 5c2b063c0e2..8055c205cc2 100644 --- a/ts/components/CallingAdhocCallInfo.stories.tsx +++ b/ts/components/CallingAdhocCallInfo.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { sample } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; @@ -15,6 +15,8 @@ import { getDefaultConversation } from '../test-helpers/getDefaultConversation.j import type { CallLinkType } from '../types/CallLink.js'; import { CallLinkRestrictions } from '../types/CallLink.js'; +const { sample } = lodash; + const { i18n } = window.SignalContext; const OUR_ACI = generateAci(); diff --git a/ts/components/CallingAdhocCallInfo.tsx b/ts/components/CallingAdhocCallInfo.tsx index ffaa9aae872..73846f3031a 100644 --- a/ts/components/CallingAdhocCallInfo.tsx +++ b/ts/components/CallingAdhocCallInfo.tsx @@ -4,7 +4,7 @@ import React from 'react'; import classNames from 'classnames'; -import { partition } from 'lodash'; +import lodash from 'lodash'; import { Avatar, AvatarSize } from './Avatar.js'; import { ContactName } from './conversation/ContactName.js'; import { InContactsIcon } from './InContactsIcon.js'; @@ -22,6 +22,8 @@ import { Modal } from './Modal.js'; import { Theme } from '../util/theme.js'; import { ConfirmationDialog } from './ConfirmationDialog.js'; +const { partition } = lodash; + const MAX_UNKNOWN_AVATARS_COUNT = 3; type ParticipantType = ConversationType & { diff --git a/ts/components/CallingLobby.stories.tsx b/ts/components/CallingLobby.stories.tsx index 0421e936b93..2800e15adac 100644 --- a/ts/components/CallingLobby.stories.tsx +++ b/ts/components/CallingLobby.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import { v4 as generateUuid } from 'uuid'; @@ -20,6 +20,8 @@ import { CallingToastProvider } from './CallingToast.js'; import { CallMode } from '../types/CallDisposition.js'; import { getDefaultCallLinkConversation } from '../test-helpers/fakeCallLink.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; const camera = { diff --git a/ts/components/CallingLobbyJoinButton.tsx b/ts/components/CallingLobbyJoinButton.tsx index 73fc780e0dc..9b83911daca 100644 --- a/ts/components/CallingLobbyJoinButton.tsx +++ b/ts/components/CallingLobbyJoinButton.tsx @@ -3,12 +3,14 @@ import type { ReactChild } from 'react'; import React, { useState } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../types/Util.js'; import { Button, ButtonVariant } from './Button.js'; import { Spinner } from './Spinner.js'; +const { noop } = lodash; + export enum CallingLobbyJoinButtonVariant { CallIsFull = 'CallIsFull', Join = 'Join', diff --git a/ts/components/CallingPendingParticipants.tsx b/ts/components/CallingPendingParticipants.tsx index d380d10fd24..def82be56fa 100644 --- a/ts/components/CallingPendingParticipants.tsx +++ b/ts/components/CallingPendingParticipants.tsx @@ -4,7 +4,7 @@ /* eslint-disable react/no-array-index-key */ import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import { animated, useSpring } from '@react-spring/web'; import { Avatar, AvatarSize } from './Avatar.js'; @@ -26,6 +26,8 @@ import { usePrevious } from '../hooks/usePrevious.js'; import { useReducedMotion } from '../hooks/useReducedMotion.js'; import { drop } from '../util/drop.js'; +const { noop } = lodash; + enum ConfirmDialogState { None = 'None', ApproveAll = 'ApproveAll', diff --git a/ts/components/CallingPip.stories.tsx b/ts/components/CallingPip.stories.tsx index b06b19a63bf..a1576bd24b5 100644 --- a/ts/components/CallingPip.stories.tsx +++ b/ts/components/CallingPip.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import { AvatarColors } from '../types/Colors.js'; @@ -23,6 +23,8 @@ import { MINUTE } from '../util/durations/index.js'; import type { SetRendererCanvasType } from '../state/ducks/calling.js'; import { createCallParticipant } from '../test-helpers/createCallParticipant.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; const videoScreenshot = new Image(300, 400); diff --git a/ts/components/CallingPip.tsx b/ts/components/CallingPip.tsx index 1375ac8f109..1d6808d5bd5 100644 --- a/ts/components/CallingPip.tsx +++ b/ts/components/CallingPip.tsx @@ -3,7 +3,7 @@ import React from 'react'; import classNames from 'classnames'; -import { minBy, debounce, noop } from 'lodash'; +import lodash from 'lodash'; import type { VideoFrameSource } from '@signalapp/ringrtc'; @@ -27,6 +27,8 @@ import type { ConversationType } from '../state/ducks/conversations.js'; import { Avatar, AvatarSize } from './Avatar.js'; import { AvatarColors } from '../types/Colors.js'; +const { minBy, debounce, noop } = lodash; + enum PositionMode { BeingDragged, SnapToBottom, diff --git a/ts/components/CallingPipRemoteVideo.tsx b/ts/components/CallingPipRemoteVideo.tsx index 3ff4cdb57a1..92b97e0ab19 100644 --- a/ts/components/CallingPipRemoteVideo.tsx +++ b/ts/components/CallingPipRemoteVideo.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useEffect } from 'react'; -import { clamp, isNumber, maxBy } from 'lodash'; +import lodash from 'lodash'; import type { VideoFrameSource } from '@signalapp/ringrtc'; import { Avatar, AvatarSize } from './Avatar.js'; import { CallBackgroundBlur } from './CallBackgroundBlur.js'; @@ -33,6 +33,8 @@ import { PIP_WIDTH_NORMAL, } from './CallingPip.js'; +const { clamp, isNumber, maxBy } = lodash; + function BlurredBackground({ activeCall, activeGroupCallSpeaker, diff --git a/ts/components/CallingPreCallInfo.stories.tsx b/ts/components/CallingPreCallInfo.stories.tsx index 3bbd978d040..00829f89b3b 100644 --- a/ts/components/CallingPreCallInfo.stories.tsx +++ b/ts/components/CallingPreCallInfo.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import type { Meta } from '@storybook/react'; import { getDefaultConversation } from '../test-helpers/getDefaultConversation.js'; import type { PropsType } from './CallingPreCallInfo.js'; @@ -13,6 +13,8 @@ import { generateAci } from '../types/ServiceId.js'; import { FAKE_CALL_LINK } from '../test-helpers/fakeCallLink.js'; import { callLinkToConversation } from '../util/callLinks.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; const getDefaultGroupConversation = () => getDefaultConversation({ diff --git a/ts/components/CallingPreCallInfo.tsx b/ts/components/CallingPreCallInfo.tsx index d7b0cd5b51a..a027e80074f 100644 --- a/ts/components/CallingPreCallInfo.tsx +++ b/ts/components/CallingPreCallInfo.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { partition } from 'lodash'; +import lodash from 'lodash'; import type { ConversationType } from '../state/ducks/conversations.js'; import type { CallingConversationType } from '../types/Calling.js'; import type { LocalizerType } from '../types/Util.js'; @@ -11,6 +11,8 @@ import { getParticipantName } from '../util/callingGetParticipantName.js'; import { missingCaseError } from '../util/missingCaseError.js'; import { UserText } from './UserText.js'; +const { partition } = lodash; + export enum RingMode { WillNotRing, WillRing, diff --git a/ts/components/CallingRaisedHandsList.stories.tsx b/ts/components/CallingRaisedHandsList.stories.tsx index e1450d52204..2e00b5d8b19 100644 --- a/ts/components/CallingRaisedHandsList.stories.tsx +++ b/ts/components/CallingRaisedHandsList.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; @@ -18,6 +18,8 @@ import type { ConversationType } from '../state/ducks/conversations.js'; import { AvatarColors } from '../types/Colors.js'; import { getDefaultConversationWithServiceId } from '../test-helpers/getDefaultConversation.js'; +const { times } = lodash; + const MAX_HANDS = 20; const LOCAL_DEMUX_ID = 1; const NAMES = [ diff --git a/ts/components/CallingSelectPresentingSourcesModal.tsx b/ts/components/CallingSelectPresentingSourcesModal.tsx index 6a7a27b8dde..26e8d182951 100644 --- a/ts/components/CallingSelectPresentingSourcesModal.tsx +++ b/ts/components/CallingSelectPresentingSourcesModal.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import classNames from 'classnames'; -import { groupBy } from 'lodash'; +import lodash from 'lodash'; import { Button, ButtonVariant } from './Button.js'; import type { LocalizerType } from '../types/Util.js'; import { Modal } from './Modal.js'; @@ -11,6 +11,8 @@ import type { PresentedSource, PresentableSource } from '../types/Calling.js'; import { Theme } from '../util/theme.js'; import { strictAssert } from '../util/assert.js'; +const { groupBy } = lodash; + export type PropsType = { i18n: LocalizerType; presentingSourcesAvailable: ReadonlyArray; diff --git a/ts/components/CallsNewCallButton.tsx b/ts/components/CallsNewCallButton.tsx index e70831ca657..13651eca525 100644 --- a/ts/components/CallsNewCallButton.tsx +++ b/ts/components/CallsNewCallButton.tsx @@ -3,7 +3,7 @@ import type { ChangeEvent } from 'react'; import React, { useCallback, useMemo, useState } from 'react'; -import { partition } from 'lodash'; +import lodash from 'lodash'; import type { ListRowProps } from 'react-virtualized'; import { List } from 'react-virtualized'; import classNames from 'classnames'; @@ -25,6 +25,8 @@ import { getTooltipContent, } from './conversation/InAnotherCallTooltip.js'; +const { partition } = lodash; + type CallsNewCallProps = Readonly<{ hasActiveCall: boolean; allConversations: ReadonlyArray; diff --git a/ts/components/CompositionInput.tsx b/ts/components/CompositionInput.tsx index bf3e83d05e0..c7d5e227c3f 100644 --- a/ts/components/CompositionInput.tsx +++ b/ts/components/CompositionInput.tsx @@ -10,9 +10,9 @@ import { matchText, matchNewline, matchBreak, -} from '@signalapp/quill-cjs/modules/clipboard'; -import Emitter from '@signalapp/quill-cjs/core/emitter'; -import type { Context } from '@signalapp/quill-cjs/modules/keyboard'; +} from '@signalapp/quill-cjs/modules/clipboard.js'; +import Emitter from '@signalapp/quill-cjs/core/emitter.js'; +import type { Context } from '@signalapp/quill-cjs/modules/keyboard.js'; import type { Range as RangeStatic } from '@signalapp/quill-cjs'; import { MentionCompletion } from '../quill/mentions/completion.js'; diff --git a/ts/components/CompositionRecording.tsx b/ts/components/CompositionRecording.tsx index 06e76a51009..0fafafd5db0 100644 --- a/ts/components/CompositionRecording.tsx +++ b/ts/components/CompositionRecording.tsx @@ -1,7 +1,7 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop } from 'lodash'; +import lodash from 'lodash'; import React, { useEffect, useRef, useState } from 'react'; import { useEscapeHandling } from '../hooks/useEscapeHandling.js'; import type { HideToastAction, ShowToastAction } from '../state/ducks/toast.js'; @@ -15,6 +15,8 @@ import { durationToPlaybackText } from '../util/durationToPlaybackText.js'; import { ConfirmationDialog } from './ConfirmationDialog.js'; import { RecordingComposer } from './RecordingComposer.js'; +const { noop } = lodash; + export type Props = { i18n: LocalizerType; onCancel: () => void; diff --git a/ts/components/ContactPills.stories.tsx b/ts/components/ContactPills.stories.tsx index 1133d8b086f..b64879230b2 100644 --- a/ts/components/ContactPills.stories.tsx +++ b/ts/components/ContactPills.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; @@ -13,6 +13,8 @@ import { ContactPill } from './ContactPill.js'; import { gifUrl } from '../storybook/Fixtures.js'; import { getDefaultConversation } from '../test-helpers/getDefaultConversation.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/ContextMenu.tsx b/ts/components/ContextMenu.tsx index f2c7ff1919b..f0ee1025ec4 100644 --- a/ts/components/ContextMenu.tsx +++ b/ts/components/ContextMenu.tsx @@ -7,7 +7,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import classNames from 'classnames'; import { usePopper } from 'react-popper'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { Theme } from '../util/theme.js'; import type { LocalizerType } from '../types/Util.js'; @@ -15,6 +15,8 @@ import { getClassNamesFor } from '../util/getClassNamesFor.js'; import { themeClassName } from '../util/theme.js'; import { handleOutsideClick } from '../util/handleOutsideClick.js'; +const { noop } = lodash; + export type ContextMenuOptionType = Readonly<{ description?: string; icon?: string; diff --git a/ts/components/ConversationList.stories.tsx b/ts/components/ConversationList.stories.tsx index c024c044a96..3b56d5a6a9a 100644 --- a/ts/components/ConversationList.stories.tsx +++ b/ts/components/ConversationList.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useContext } from 'react'; -import { times, omit } from 'lodash'; +import lodash from 'lodash'; import { v4 as generateUuid } from 'uuid'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; @@ -17,6 +17,8 @@ import { ThemeType } from '../types/Util.js'; import { StorybookThemeContext } from '../../.storybook/StorybookThemeContext.js'; import { makeFakeLookupConversationWithoutServiceId } from '../test-helpers/fakeLookupConversationWithoutServiceId.js'; +const { times, omit } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/ConversationList.tsx b/ts/components/ConversationList.tsx index 079caf16e3a..342270818f0 100644 --- a/ts/components/ConversationList.tsx +++ b/ts/components/ConversationList.tsx @@ -5,7 +5,7 @@ import type { ReactNode } from 'react'; import React, { useCallback } from 'react'; import type { ListRowRenderer } from 'react-virtualized'; import classNames from 'classnames'; -import { get, pick } from 'lodash'; +import lodash from 'lodash'; import { missingCaseError } from '../util/missingCaseError.js'; import { assertDev } from '../util/assert.js'; @@ -39,6 +39,8 @@ import { ListView } from './ListView.js'; import { Button, ButtonVariant } from './Button.js'; import { ListTile } from './ListTile.js'; +const { get, pick } = lodash; + export enum RowType { ArchiveButton = 'ArchiveButton', Blank = 'Blank', diff --git a/ts/components/CustomizingPreferredReactionsModal.tsx b/ts/components/CustomizingPreferredReactionsModal.tsx index b2e07e168c3..94fc6fe4568 100644 --- a/ts/components/CustomizingPreferredReactionsModal.tsx +++ b/ts/components/CustomizingPreferredReactionsModal.tsx @@ -3,7 +3,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import { usePopper } from 'react-popper'; -import { isEqual, noop } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../types/Util.js'; import { Modal } from './Modal.js'; @@ -23,6 +23,8 @@ import { FunEmojiPicker } from './fun/FunEmojiPicker.js'; import type { FunEmojiSelection } from './fun/panels/FunPanelEmojis.js'; import { isFunPickerEnabled } from './fun/isFunPickerEnabled.js'; +const { isEqual, noop } = lodash; + export type PropsType = { draftPreferredReactions: ReadonlyArray; hadSaveError: boolean; diff --git a/ts/components/EditHistoryMessagesModal.tsx b/ts/components/EditHistoryMessagesModal.tsx index 4109eb41108..861fada49cc 100644 --- a/ts/components/EditHistoryMessagesModal.tsx +++ b/ts/components/EditHistoryMessagesModal.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useCallback, useState, useRef } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { AttachmentType } from '../types/Attachment.js'; import type { LocalizerType } from '../types/Util.js'; @@ -17,6 +17,8 @@ import { isSameDay } from '../util/timestamp.js'; import { TimelineDateHeader } from './conversation/TimelineDateHeader.js'; import { drop } from '../util/drop.js'; +const { noop } = lodash; + export type PropsType = { closeEditHistoryModal: () => unknown; editHistoryMessages: Array; diff --git a/ts/components/GroupCallOverflowArea.stories.tsx b/ts/components/GroupCallOverflowArea.stories.tsx index ce3f26c8813..67cba7ec487 100644 --- a/ts/components/GroupCallOverflowArea.stories.tsx +++ b/ts/components/GroupCallOverflowArea.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { memoize, times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import type { PropsType } from './GroupCallOverflowArea.js'; @@ -14,6 +14,8 @@ import { generateAci } from '../types/ServiceId.js'; import type { CallingImageDataCache } from './CallManager.js'; import { MINUTE } from '../util/durations/index.js'; +const { memoize, times } = lodash; + const MAX_PARTICIPANTS = 32; const { i18n } = window.SignalContext; diff --git a/ts/components/GroupCallRemoteParticipant.stories.tsx b/ts/components/GroupCallRemoteParticipant.stories.tsx index bb0e43fbcf0..d71bf8f4dfe 100644 --- a/ts/components/GroupCallRemoteParticipant.stories.tsx +++ b/ts/components/GroupCallRemoteParticipant.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { memoize } from 'lodash'; +import lodash from 'lodash'; import type { Meta } from '@storybook/react'; import type { PropsType } from './GroupCallRemoteParticipant.js'; import { GroupCallRemoteParticipant } from './GroupCallRemoteParticipant.js'; @@ -12,6 +12,8 @@ import { generateAci } from '../types/ServiceId.js'; import type { CallingImageDataCache } from './CallManager.js'; import { MINUTE } from '../util/durations/index.js'; +const { memoize } = lodash; + const { i18n } = window.SignalContext; type OverridePropsType = { diff --git a/ts/components/GroupCallRemoteParticipant.tsx b/ts/components/GroupCallRemoteParticipant.tsx index 4c6e9cbcb7e..9f68f516f34 100644 --- a/ts/components/GroupCallRemoteParticipant.tsx +++ b/ts/components/GroupCallRemoteParticipant.tsx @@ -10,7 +10,7 @@ import React, { useEffect, } from 'react'; import classNames from 'classnames'; -import { debounce, noop } from 'lodash'; +import lodash from 'lodash'; import type { VideoFrameSource } from '@signalapp/ringrtc'; import type { GroupCallRemoteParticipantType } from '../types/Calling.js'; import type { LocalizerType } from '../types/Util.js'; @@ -32,6 +32,8 @@ import { isOlderThan } from '../util/timestamp.js'; import type { CallingImageDataCache } from './CallManager.js'; import { usePrevious } from '../hooks/usePrevious.js'; +const { debounce, noop } = lodash; + const MAX_TIME_TO_SHOW_STALE_VIDEO_FRAMES = 10000; const MAX_TIME_TO_SHOW_STALE_SCREENSHARE_FRAMES = 60000; const DELAY_TO_SHOW_MISSING_MEDIA_KEYS = 5000; diff --git a/ts/components/GroupCallRemoteParticipants.tsx b/ts/components/GroupCallRemoteParticipants.tsx index b6bbb3c06ff..fcfcbb16949 100644 --- a/ts/components/GroupCallRemoteParticipants.tsx +++ b/ts/components/GroupCallRemoteParticipants.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useCallback, useState, useMemo, useEffect } from 'react'; -import { clamp, chunk, maxBy, flatten, noop } from 'lodash'; +import lodash from 'lodash'; import type { VideoFrameSource } from '@signalapp/ringrtc'; import { GroupCallRemoteParticipant } from './GroupCallRemoteParticipant.js'; import { @@ -29,6 +29,8 @@ import { SizeObserver } from '../hooks/useSizeObserver.js'; import { strictAssert } from '../util/assert.js'; import type { CallingImageDataCache } from './CallManager.js'; +const { clamp, chunk, maxBy, flatten, noop } = lodash; + const log = createLogger('GroupCallRemoteParticipants'); const SMALL_TILES_MIN_HEIGHT = 80; diff --git a/ts/components/GroupMembersNames.tsx b/ts/components/GroupMembersNames.tsx index b9da9bce3be..daa6282b6ca 100644 --- a/ts/components/GroupMembersNames.tsx +++ b/ts/components/GroupMembersNames.tsx @@ -3,13 +3,15 @@ import React, { useMemo } from 'react'; import type { ReactNode } from 'react'; -import { take } from 'lodash'; +import lodash from 'lodash'; import { I18n } from './I18n.js'; import type { LocalizerType } from '../types/Util.js'; import { UserText } from './UserText.js'; import type { GroupV2Membership } from './conversation/conversation-details/ConversationDetailsMembershipList.js'; +const { take } = lodash; + type PropsType = { i18n: LocalizerType; nameClassName?: string; diff --git a/ts/components/Inbox.stories.tsx b/ts/components/Inbox.stories.tsx index 2634effc9b1..1dc529b1e70 100644 --- a/ts/components/Inbox.stories.tsx +++ b/ts/components/Inbox.stories.tsx @@ -3,12 +3,14 @@ import React, { useState, useEffect, useMemo } from 'react'; import type { Meta, StoryFn } from '@storybook/react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { Inbox } from './Inbox.js'; import type { PropsType } from './Inbox.js'; import { DAY, SECOND } from '../util/durations/index.js'; +const { noop } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/LeftPane.tsx b/ts/components/LeftPane.tsx index 87fcb8a27ab..3e6ad305524 100644 --- a/ts/components/LeftPane.tsx +++ b/ts/components/LeftPane.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useCallback, useMemo, useRef } from 'react'; import classNames from 'classnames'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import type { LeftPaneHelper, ToFindType } from './leftPane/LeftPaneHelper.js'; import { FindDirection } from './leftPane/LeftPaneHelper.js'; @@ -61,6 +61,8 @@ import { getServerAlertDialog } from './ServerAlerts.js'; import { NavTab, SettingsPage, ProfileEditorPage } from '../types/Nav.js'; import type { Location } from '../types/Nav.js'; +const { isNumber } = lodash; + export type PropsType = { backupMediaDownloadProgress: { isBackupMediaEnabled: boolean; diff --git a/ts/components/Lightbox.stories.tsx b/ts/components/Lightbox.stories.tsx index b3d2218fcc8..9c0fa24e9e2 100644 --- a/ts/components/Lightbox.stories.tsx +++ b/ts/components/Lightbox.stories.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { action } from '@storybook/addon-actions'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { Meta } from '@storybook/react'; import type { PropsType } from './Lightbox.js'; import { Lightbox } from './Lightbox.js'; @@ -19,6 +19,8 @@ import { import { fakeAttachment } from '../test-helpers/fakeAttachment.js'; +const { noop } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/Lightbox.tsx b/ts/components/Lightbox.tsx index 79a06dc69b4..3444029fdf5 100644 --- a/ts/components/Lightbox.tsx +++ b/ts/components/Lightbox.tsx @@ -5,7 +5,7 @@ import type { ReactNode } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; import { createPortal } from 'react-dom'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { useSpring, animated, to } from '@react-spring/web'; import type { ReadonlyDeep } from 'type-fest'; @@ -36,6 +36,8 @@ import { SECOND } from '../util/durations/index.js'; import { Toast } from './Toast.js'; import { isAbortError } from '../util/isAbortError.js'; +const { noop } = lodash; + const log = createLogger('Lightbox'); export type PropsType = { diff --git a/ts/components/MediaEditor.tsx b/ts/components/MediaEditor.tsx index 6bb9cef83ef..6f84b616451 100644 --- a/ts/components/MediaEditor.tsx +++ b/ts/components/MediaEditor.tsx @@ -13,7 +13,7 @@ import classNames from 'classnames'; import { createPortal } from 'react-dom'; import { fabric } from 'fabric'; import { useSelector } from 'react-redux'; -import { get, has, noop } from 'lodash'; +import lodash from 'lodash'; import type { EmojiPickDataType, Props as EmojiPickerProps, @@ -73,6 +73,8 @@ import { drop } from '../util/drop.js'; import type { FunTimeStickerStyle } from './fun/constants.js'; import * as Errors from '../types/errors.js'; +const { get, has, noop } = lodash; + const log = createLogger('MediaEditor'); export type MediaEditorResultType = Readonly<{ diff --git a/ts/components/MediaQualitySelector.tsx b/ts/components/MediaQualitySelector.tsx index 1694f30542e..cc1cb794f0c 100644 --- a/ts/components/MediaQualitySelector.tsx +++ b/ts/components/MediaQualitySelector.tsx @@ -3,7 +3,7 @@ import type { KeyboardEvent } from 'react'; import React, { useCallback, useEffect, useState } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { createPortal } from 'react-dom'; import classNames from 'classnames'; import { Manager, Popper, Reference } from 'react-popper'; @@ -11,6 +11,8 @@ import type { LocalizerType } from '../types/Util.js'; import { useRefMerger } from '../hooks/useRefMerger.js'; import { handleOutsideClick } from '../util/handleOutsideClick.js'; +const { noop } = lodash; + export type PropsType = { conversationId: string; i18n: LocalizerType; diff --git a/ts/components/Modal.stories.tsx b/ts/components/Modal.stories.tsx index 69121b46386..eb3d24a3f37 100644 --- a/ts/components/Modal.stories.tsx +++ b/ts/components/Modal.stories.tsx @@ -2,13 +2,15 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import { Button } from './Button.js'; import type { ModalPropsType } from './Modal.js'; import { Modal } from './Modal.js'; +const { noop } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/Modal.tsx b/ts/components/Modal.tsx index 03635ef502b..d7900dd06eb 100644 --- a/ts/components/Modal.tsx +++ b/ts/components/Modal.tsx @@ -4,7 +4,7 @@ import type { ReactElement, ReactNode } from 'react'; import React, { useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { animated } from '@react-spring/web'; import { v4 as uuid } from 'uuid'; @@ -23,6 +23,8 @@ import { useScrollObserver, } from '../hooks/useSizeObserver.js'; +const { noop } = lodash; + const log = createLogger('Modal'); type PropsType = { diff --git a/ts/components/ModalHost.tsx b/ts/components/ModalHost.tsx index 7fc6ffa49af..19feb650c94 100644 --- a/ts/components/ModalHost.tsx +++ b/ts/components/ModalHost.tsx @@ -6,7 +6,7 @@ import { createPortal } from 'react-dom'; import type { SpringValues } from '@react-spring/web'; import { animated } from '@react-spring/web'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { FocusScope } from 'react-aria'; import type { ModalConfigType } from '../hooks/useAnimated.js'; import type { Theme } from '../util/theme.js'; @@ -18,6 +18,8 @@ import { usePrevious } from '../hooks/usePrevious.js'; import { handleOutsideClick } from '../util/handleOutsideClick.js'; import { createLogger } from '../logging/log.js'; +const { noop } = lodash; + const log = createLogger('ModalHost'); export const ModalContainerContext = React.createContext( diff --git a/ts/components/Preferences.stories.tsx b/ts/components/Preferences.stories.tsx index 4ad0bd666ec..42a56beb32d 100644 --- a/ts/components/Preferences.stories.tsx +++ b/ts/components/Preferences.stories.tsx @@ -6,7 +6,7 @@ import React, { useState } from 'react'; import type { MutableRefObject } from 'react'; import { action } from '@storybook/addon-actions'; -import { shuffle } from 'lodash'; +import lodash from 'lodash'; import { Preferences } from './Preferences.js'; import { DEFAULT_CONVERSATION_COLOR } from '../types/Colors.js'; import { PhoneNumberSharingMode } from '../util/phoneNumberSharingMode.js'; @@ -45,6 +45,8 @@ import type { SmartPreferencesEditChatFolderPageProps } from '../state/smart/Pre import { PreferencesEditChatFolderPage } from './preferences/chatFolders/PreferencesEditChatFoldersPage.js'; import { CHAT_FOLDER_DEFAULTS } from '../types/ChatFolder.js'; +const { shuffle } = lodash; + const { i18n } = window.SignalContext; const me = { diff --git a/ts/components/Preferences.tsx b/ts/components/Preferences.tsx index a24e67e16e1..4be93668ecc 100644 --- a/ts/components/Preferences.tsx +++ b/ts/components/Preferences.tsx @@ -10,7 +10,7 @@ import React, { useState, useId, } from 'react'; -import { isNumber, noop, partition } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import * as LocaleMatcher from '@formatjs/intl-localematcher'; import type { MutableRefObject, ReactNode } from 'react'; @@ -99,6 +99,8 @@ import { isChatFoldersEnabled } from '../types/ChatFolder.js'; import type { SmartPreferencesEditChatFolderPageProps } from '../state/smart/PreferencesEditChatFolderPage.js'; import type { SmartPreferencesChatFoldersPageProps } from '../state/smart/PreferencesChatFoldersPage.js'; +const { isNumber, noop, partition } = lodash; + type CheckboxChangeHandlerType = (value: boolean) => unknown; type SelectChangeHandlerType = (value: T) => unknown; diff --git a/ts/components/PreferencesDonations.tsx b/ts/components/PreferencesDonations.tsx index fcbeb333161..ff441b7d469 100644 --- a/ts/components/PreferencesDonations.tsx +++ b/ts/components/PreferencesDonations.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { groupBy, sortBy } from 'lodash'; +import lodash from 'lodash'; import type { MutableRefObject, ReactNode } from 'react'; import { ListBox, ListBoxItem } from 'react-aria-components'; @@ -55,6 +55,8 @@ import { drop } from '../util/drop.js'; import { DonationsOfflineTooltip } from './conversation/DonationsOfflineTooltip.js'; import { getInProgressDonation } from '../util/donations.js'; +const { groupBy, sortBy } = lodash; + const log = createLogger('PreferencesDonations'); type PropsExternalType = { diff --git a/ts/components/PreferencesLocalBackups.tsx b/ts/components/PreferencesLocalBackups.tsx index 2a750f820e0..0eaac75abfd 100644 --- a/ts/components/PreferencesLocalBackups.tsx +++ b/ts/components/PreferencesLocalBackups.tsx @@ -9,7 +9,7 @@ import React, { useState, useRef, } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import type { LocalizerType } from '../types/I18N.js'; @@ -35,6 +35,8 @@ import type { } from '../util/os/promptOSAuthMain.js'; import { ConfirmationDialog } from './ConfirmationDialog.js'; +const { noop } = lodash; + export function PreferencesLocalBackups({ accountEntropyPool, backupKeyViewed, diff --git a/ts/components/PreferencesUtil.tsx b/ts/components/PreferencesUtil.tsx index d7d9d5d9f9a..e0f8047ec6a 100644 --- a/ts/components/PreferencesUtil.tsx +++ b/ts/components/PreferencesUtil.tsx @@ -4,12 +4,14 @@ import classNames from 'classnames'; import React, { type ReactNode, useMemo } from 'react'; import { v4 as uuid } from 'uuid'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { CircleCheckbox, Variant as CircleCheckboxVariant, } from './CircleCheckbox.js'; +const { noop } = lodash; + export function SettingsRow({ children, title, diff --git a/ts/components/SafetyNumberChangeDialog.tsx b/ts/components/SafetyNumberChangeDialog.tsx index d2d7ec32f37..b377bf026aa 100644 --- a/ts/components/SafetyNumberChangeDialog.tsx +++ b/ts/components/SafetyNumberChangeDialog.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import { Avatar, AvatarSize } from './Avatar.js'; @@ -25,6 +25,8 @@ import type { ServiceIdString } from '../types/ServiceId.js'; import type { StoryDistributionIdString } from '../types/StoryDistributionId.js'; import { UserText } from './UserText.js'; +const { noop } = lodash; + export enum SafetyNumberChangeSource { InitiateCall = 'InitiateCall', JoinCall = 'JoinCall', diff --git a/ts/components/SendStoryModal.tsx b/ts/components/SendStoryModal.tsx index 899430a58e9..5b4b5943316 100644 --- a/ts/components/SendStoryModal.tsx +++ b/ts/components/SendStoryModal.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { noop, sortBy } from 'lodash'; +import lodash from 'lodash'; import { SearchInput } from './SearchInput.js'; import { filterAndSortConversations } from '../util/filterAndSortConversations.js'; @@ -44,6 +44,8 @@ import { makeObjectUrl, revokeObjectUrl } from '../types/VisualAttachment.js'; import { UserText } from './UserText.js'; import { Theme } from '../util/theme.js'; +const { noop, sortBy } = lodash; + export type PropsType = { draftAttachment: AttachmentType; candidateConversations: Array; diff --git a/ts/components/SharedGroupNames.tsx b/ts/components/SharedGroupNames.tsx index 3498db5ce18..2c2fc87ca40 100644 --- a/ts/components/SharedGroupNames.tsx +++ b/ts/components/SharedGroupNames.tsx @@ -2,12 +2,14 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { take } from 'lodash'; +import lodash from 'lodash'; import { I18n } from './I18n.js'; import type { LocalizerType } from '../types/Util.js'; import { UserText } from './UserText.js'; +const { take } = lodash; + type PropsType = { i18n: LocalizerType; nameClassName?: string; diff --git a/ts/components/SimpleQuillWrapper.tsx b/ts/components/SimpleQuillWrapper.tsx index 1544b4fc2a0..f5c5297e34f 100644 --- a/ts/components/SimpleQuillWrapper.tsx +++ b/ts/components/SimpleQuillWrapper.tsx @@ -3,7 +3,7 @@ import React, { createRef } from 'react'; import Quill from '@signalapp/quill-cjs'; -import Emitter from '@signalapp/quill-cjs/core/emitter'; +import Emitter from '@signalapp/quill-cjs/core/emitter.js'; import type { Delta } from '@signalapp/quill-cjs'; export type Props = { diff --git a/ts/components/StoriesSettingsModal.tsx b/ts/components/StoriesSettingsModal.tsx index 8a3390092ac..4b25466fedd 100644 --- a/ts/components/StoriesSettingsModal.tsx +++ b/ts/components/StoriesSettingsModal.tsx @@ -9,7 +9,7 @@ import React, { useRef, useState, } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { ConversationType } from '../state/ducks/conversations.js'; import type { ConversationWithStoriesType } from '../state/selectors/conversations.js'; @@ -45,6 +45,8 @@ import { strictAssert } from '../util/assert.js'; import { UserText } from './UserText.js'; import { SizeObserver } from '../hooks/useSizeObserver.js'; +const { noop } = lodash; + export type PropsType = { candidateConversations: Array; distributionLists: Array; diff --git a/ts/components/StoryCreator.tsx b/ts/components/StoryCreator.tsx index ad2ab62b7a5..efd299b91c5 100644 --- a/ts/components/StoryCreator.tsx +++ b/ts/components/StoryCreator.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useEffect, useState } from 'react'; -import { get, has } from 'lodash'; +import lodash from 'lodash'; import { createPortal } from 'react-dom'; import type { AttachmentType } from '../types/Attachment.js'; @@ -25,6 +25,8 @@ import { TextStoryCreator } from './TextStoryCreator.js'; import type { DraftBodyRanges } from '../types/BodyRange.js'; import type { processAttachment } from '../util/processAttachment.js'; +const { get, has } = lodash; + function usePortalElement(testid: string): HTMLDivElement | null { const [element, setElement] = useState(null); diff --git a/ts/components/StoryImage.stories.tsx b/ts/components/StoryImage.stories.tsx index bbf8653d81e..a5eee3a0c07 100644 --- a/ts/components/StoryImage.stories.tsx +++ b/ts/components/StoryImage.stories.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { v4 as uuid } from 'uuid'; import { action } from '@storybook/addon-actions'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { Meta } from '@storybook/react'; import type { PropsType } from './StoryImage.js'; @@ -15,6 +15,8 @@ import { } from '../test-helpers/fakeAttachment.js'; import { VIDEO_MP4 } from '../types/MIME.js'; +const { noop } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/StoryLinkPreview.tsx b/ts/components/StoryLinkPreview.tsx index 044a963b9c0..04430db65d3 100644 --- a/ts/components/StoryLinkPreview.tsx +++ b/ts/components/StoryLinkPreview.tsx @@ -3,7 +3,7 @@ import React from 'react'; import classNames from 'classnames'; -import { unescape } from 'lodash'; +import lodash from 'lodash'; import type { LinkPreviewForUIType } from '../types/message/LinkPreviews.js'; import type { LocalizerType } from '../types/Util.js'; @@ -11,6 +11,8 @@ import { CurveType, Image } from './conversation/Image.js'; import { isImageAttachment } from '../types/Attachment.js'; import { getSafeDomain } from '../types/LinkPreview.js'; +const { unescape } = lodash; + export type Props = LinkPreviewForUIType & { forceCompactMode?: boolean; i18n: LocalizerType; diff --git a/ts/components/StoryViewsNRepliesModal.tsx b/ts/components/StoryViewsNRepliesModal.tsx index 4e517b8eeef..19cc87a8fe2 100644 --- a/ts/components/StoryViewsNRepliesModal.tsx +++ b/ts/components/StoryViewsNRepliesModal.tsx @@ -9,7 +9,7 @@ import React, { useState, } from 'react'; import classNames from 'classnames'; -import { noop, orderBy } from 'lodash'; +import lodash from 'lodash'; import type { DraftBodyRanges } from '../types/BodyRange.js'; import type { LocalizerType } from '../types/Util.js'; import type { ConversationType } from '../state/ducks/conversations.js'; @@ -43,6 +43,8 @@ import { FunEmojiPickerButton } from './fun/FunButton.js'; import type { FunEmojiSelection } from './fun/panels/FunPanelEmojis.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.js'; +const { noop, orderBy } = lodash; + // Menu is disabled so these actions are inaccessible. We also don't support // link previews, tap to view messages, attachments, or gifts. Just regular // text messages and reactions. diff --git a/ts/components/TextStoryCreator.tsx b/ts/components/TextStoryCreator.tsx index dad13ca6837..2e3f70cf378 100644 --- a/ts/components/TextStoryCreator.tsx +++ b/ts/components/TextStoryCreator.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useCallback, useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { usePopper } from 'react-popper'; import { FocusScope } from 'react-aria'; import type { EmojiPickDataType } from './emoji/EmojiPicker.js'; @@ -37,6 +37,8 @@ import { FunEmojiPickerButton } from './fun/FunButton.js'; import { isFunPickerEnabled } from './fun/isFunPickerEnabled.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.js'; +const { noop } = lodash; + export type PropsType = { debouncedMaybeGrabLinkPreview: ( message: string, diff --git a/ts/components/Tooltip.tsx b/ts/components/Tooltip.tsx index 20881381cc2..50b6453873d 100644 --- a/ts/components/Tooltip.tsx +++ b/ts/components/Tooltip.tsx @@ -3,7 +3,7 @@ import React, { useRef } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { Manager, Reference, Popper } from 'react-popper'; import type { StrictModifiers } from '@popperjs/core'; import { createPortal } from 'react-dom'; @@ -13,6 +13,8 @@ import { refMerger } from '../util/refMerger.js'; import { offsetDistanceModifier } from '../util/popperUtil.js'; import { getInteractionMode } from '../services/InteractionMode.js'; +const { noop } = lodash; + type EventWrapperPropsType = { className?: string; children: React.ReactNode; diff --git a/ts/components/UsernameEditor.tsx b/ts/components/UsernameEditor.tsx index 47b20957c94..eab530bb388 100644 --- a/ts/components/UsernameEditor.tsx +++ b/ts/components/UsernameEditor.tsx @@ -9,7 +9,7 @@ import React, { useRef, } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../types/Util.js'; import type { UsernameReservationType } from '../types/Username.js'; @@ -35,6 +35,8 @@ import { Modal } from './Modal.js'; import { Button, ButtonVariant } from './Button.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.js'; +const { noop } = lodash; + export type PropsDataType = Readonly<{ i18n: LocalizerType; currentUsername?: string; diff --git a/ts/components/UsernameLinkEditor.tsx b/ts/components/UsernameLinkEditor.tsx index 0f5c75f10ce..f15a6afa305 100644 --- a/ts/components/UsernameLinkEditor.tsx +++ b/ts/components/UsernameLinkEditor.tsx @@ -5,7 +5,7 @@ import React, { useCallback, useState, useEffect, useRef } from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import classnames from 'classnames'; import { changeDpiBlob } from 'changedpi'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { SignalService as Proto } from '../protobuf/index.js'; import type { SaveAttachmentActionCreatorType } from '../state/ducks/conversations.js'; @@ -24,6 +24,8 @@ import { Spinner } from './Spinner.js'; import { BrandedQRCode } from './BrandedQRCode.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.js'; +const { noop } = lodash; + export type PropsType = Readonly<{ i18n: LocalizerType; link?: string; diff --git a/ts/components/conversation/AtMentionify.tsx b/ts/components/conversation/AtMentionify.tsx index c8acd68a5b4..5dec7d8628b 100644 --- a/ts/components/conversation/AtMentionify.tsx +++ b/ts/components/conversation/AtMentionify.tsx @@ -2,13 +2,15 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { sortBy } from 'lodash'; +import lodash from 'lodash'; import type { HydratedBodyRangeMention, BodyRange, } from '../../types/BodyRange.js'; import { AtMention } from './AtMention.js'; +const { sortBy } = lodash; + export type Props = { mentions?: ReadonlyArray; direction?: 'incoming' | 'outgoing'; diff --git a/ts/components/conversation/CallingNotification.tsx b/ts/components/conversation/CallingNotification.tsx index d3bd5ea4a33..a44f0dae97a 100644 --- a/ts/components/conversation/CallingNotification.tsx +++ b/ts/components/conversation/CallingNotification.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from 'react'; import React from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { ContextMenuTrigger } from 'react-contextmenu'; import { SystemMessage, SystemMessageKind } from './SystemMessage.js'; @@ -40,6 +40,8 @@ import { isMoreRecentThan } from '../../util/timestamp.js'; import { InAnotherCallTooltip } from './InAnotherCallTooltip.js'; import type { InteractionModeType } from '../../state/ducks/conversations.js'; +const { noop } = lodash; + const log = createLogger('CallingNotification'); export type PropsActionsType = { diff --git a/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx b/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx index f03259304b6..7b1192ccc15 100644 --- a/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx +++ b/ts/components/conversation/ContactSpoofingReviewDialog.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import { getDefaultConversation } from '../../test-helpers/getDefaultConversation.js'; @@ -11,6 +11,8 @@ import { ContactSpoofingReviewDialog } from './ContactSpoofingReviewDialog.js'; import { ContactSpoofingType } from '../../util/contactSpoofing.js'; import { ThemeType } from '../../types/Util.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/conversation/GroupNotification.tsx b/ts/components/conversation/GroupNotification.tsx index 7acef32e428..01dfc3c5b84 100644 --- a/ts/components/conversation/GroupNotification.tsx +++ b/ts/components/conversation/GroupNotification.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from 'react'; import React from 'react'; -import { compact, flatten } from 'lodash'; +import lodash from 'lodash'; import { ContactName } from './ContactName.js'; import { SystemMessage } from './SystemMessage.js'; @@ -13,6 +13,8 @@ import type { LocalizerType } from '../../types/Util.js'; import { missingCaseError } from '../../util/missingCaseError.js'; import type { ConversationType } from '../../state/ducks/conversations.js'; +const { compact, flatten } = lodash; + export type ChangeType = 'add' | 'remove' | 'name' | 'avatar' | 'general'; type Change = { diff --git a/ts/components/conversation/GroupV2Change.tsx b/ts/components/conversation/GroupV2Change.tsx index 20e61668e18..5b8523a800c 100644 --- a/ts/components/conversation/GroupV2Change.tsx +++ b/ts/components/conversation/GroupV2Change.tsx @@ -3,7 +3,7 @@ import type { ReactElement, ReactNode } from 'react'; import React, { useState } from 'react'; -import { get } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { createLogger } from '../../logging/log.js'; @@ -31,6 +31,8 @@ import { renderChange } from '../../groupChange.js'; import { Modal } from '../Modal.js'; import { ConfirmationDialog } from '../ConfirmationDialog.js'; +const { get } = lodash; + const log = createLogger('GroupV2Change'); export type PropsDataType = ReadonlyDeep<{ diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 4597622fddb..675bd084f8b 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -13,9 +13,9 @@ import React, { forwardRef, useRef } from 'react'; import { createPortal } from 'react-dom'; import classNames from 'classnames'; import getDirection from 'direction'; -import { drop, take, unescape } from 'lodash'; +import lodash from 'lodash'; import { Manager, Popper, Reference } from 'react-popper'; -import type { PreventOverflowModifier } from '@popperjs/core/lib/modifiers/preventOverflow'; +import type { PreventOverflowModifier } from '@popperjs/core/lib/modifiers/preventOverflow.js'; import type { ReadonlyDeep } from 'type-fest'; import type { ConversationType, @@ -124,6 +124,8 @@ import { } from '../fun/data/emojis.js'; import { useGroupedAndOrderedReactions } from '../../util/groupAndOrderReactions.js'; +const { drop, take, unescape } = lodash; + const log = createLogger('Message'); const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 16; diff --git a/ts/components/conversation/MessageAudio.tsx b/ts/components/conversation/MessageAudio.tsx index 0091dbe8518..df26a75a834 100644 --- a/ts/components/conversation/MessageAudio.tsx +++ b/ts/components/conversation/MessageAudio.tsx @@ -4,7 +4,7 @@ import React, { useCallback } from 'react'; import type { RefObject } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { animated, useSpring } from '@react-spring/web'; import type { LocalizerType } from '../../types/Util.js'; @@ -25,6 +25,8 @@ import { durationToPlaybackText } from '../../util/durationToPlaybackText.js'; import { shouldNeverBeCalled } from '../../util/shouldNeverBeCalled.js'; import { formatFileSize } from '../../util/formatFileSize.js'; +const { noop } = lodash; + const log = createLogger('MessageAudio'); export type OwnProps = Readonly<{ diff --git a/ts/components/conversation/MessageDetail.tsx b/ts/components/conversation/MessageDetail.tsx index 6f05540d978..600c8f85d9c 100644 --- a/ts/components/conversation/MessageDetail.tsx +++ b/ts/components/conversation/MessageDetail.tsx @@ -4,7 +4,7 @@ import type { ReactChild, ReactNode } from 'react'; import React, { useRef } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { Avatar, AvatarSize } from '../Avatar.js'; import { ContactName } from './ContactName.js'; @@ -37,6 +37,8 @@ import { IconType, } from './conversation-details/ConversationDetailsIcon.js'; +const { noop } = lodash; + const log = createLogger('MessageDetail'); export type Contact = Pick< diff --git a/ts/components/conversation/MessageTextRenderer.tsx b/ts/components/conversation/MessageTextRenderer.tsx index b89c5ade2e7..b922126e889 100644 --- a/ts/components/conversation/MessageTextRenderer.tsx +++ b/ts/components/conversation/MessageTextRenderer.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { ReactElement } from 'react'; import classNames from 'classnames'; import emojiRegex from 'emoji-regex'; -import { sortBy } from 'lodash'; +import lodash from 'lodash'; import { linkify, SUPPORTED_PROTOCOLS } from './Linkify.js'; import type { @@ -27,6 +27,8 @@ import { AddNewLines } from './AddNewLines.js'; import type { LocalizerType } from '../../types/Util.js'; import type { FunJumboEmojiSize } from '../fun/FunEmoji.js'; +const { sortBy } = lodash; + const EMOJI_REGEXP = emojiRegex(); export enum RenderLocation { ConversationList = 'ConversationList', diff --git a/ts/components/conversation/ProfileNameWarningModal.stories.tsx b/ts/components/conversation/ProfileNameWarningModal.stories.tsx index 7be347fe6be..53be5530436 100644 --- a/ts/components/conversation/ProfileNameWarningModal.stories.tsx +++ b/ts/components/conversation/ProfileNameWarningModal.stories.tsx @@ -6,10 +6,8 @@ import { action } from '@storybook/addon-actions'; import type { PropsType } from './ProfileNameWarningModal.js'; import { ProfileNameWarningModal } from './ProfileNameWarningModal.js'; import { type ComponentMeta } from '../../storybook/types.js'; -import { setupI18n } from '../../util/setupI18n.js'; -import enMessages from '../../../_locales/en/messages.json'; -const i18n = setupI18n('en', enMessages); +const { i18n } = window.SignalContext; export default { title: 'Components/Conversation/ProfileNameWarningModal', diff --git a/ts/components/conversation/Quote.tsx b/ts/components/conversation/Quote.tsx index a39c882a202..a34a6c29fd4 100644 --- a/ts/components/conversation/Quote.tsx +++ b/ts/components/conversation/Quote.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from 'react'; import React, { useRef, useState, useEffect } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import * as MIME from '../../types/MIME.js'; @@ -31,6 +31,8 @@ import { import { RenderLocation } from './MessageTextRenderer.js'; import type { QuotedAttachmentType } from '../../model-types.js'; +const { noop } = lodash; + const EMPTY_OBJECT = Object.freeze(Object.create(null)); export type QuotedAttachmentForUIType = Pick< diff --git a/ts/components/conversation/ReactionViewer.tsx b/ts/components/conversation/ReactionViewer.tsx index f46af3aaa21..8dbd83e551c 100644 --- a/ts/components/conversation/ReactionViewer.tsx +++ b/ts/components/conversation/ReactionViewer.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { groupBy, mapValues, orderBy } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import { ContactName } from './ContactName.js'; import type { Props as AvatarProps } from '../Avatar.js'; @@ -23,6 +23,8 @@ import { strictAssert } from '../../util/assert.js'; import { FunStaticEmoji } from '../fun/FunEmoji.js'; import { useFunEmojiLocalizer } from '../fun/useFunEmojiLocalizer.js'; +const { groupBy, mapValues, orderBy } = lodash; + export type Reaction = { emoji: string; timestamp: number; diff --git a/ts/components/conversation/StagedLinkPreview.tsx b/ts/components/conversation/StagedLinkPreview.tsx index bcf91f21502..0346a56677a 100644 --- a/ts/components/conversation/StagedLinkPreview.tsx +++ b/ts/components/conversation/StagedLinkPreview.tsx @@ -3,7 +3,7 @@ import React from 'react'; import classNames from 'classnames'; -import { unescape } from 'lodash'; +import lodash from 'lodash'; import { CurveType, Image } from './Image.js'; import { LinkPreviewDate } from './LinkPreviewDate.js'; @@ -17,6 +17,8 @@ import { Avatar } from '../Avatar.js'; import { getColorForCallLink } from '../../util/getColorForCallLink.js'; import { getKeyFromCallLink } from '../../util/callLinks.js'; +const { unescape } = lodash; + export type Props = LinkPreviewForUIType & { i18n: LocalizerType; imageSize?: number; diff --git a/ts/components/conversation/Timeline.stories.tsx b/ts/components/conversation/Timeline.stories.tsx index 733251b738b..0cf728f632b 100644 --- a/ts/components/conversation/Timeline.stories.tsx +++ b/ts/components/conversation/Timeline.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { v4 as uuid } from 'uuid'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; @@ -24,6 +24,8 @@ import { PaymentEventKind } from '../../types/Payment.js'; import type { PropsData as TimelineMessageProps } from './TimelineMessage.js'; import { CollidingAvatars } from '../CollidingAvatars.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; const alice = getDefaultConversation(); diff --git a/ts/components/conversation/Timeline.tsx b/ts/components/conversation/Timeline.tsx index d50206d8bb1..ff0e0cf04a1 100644 --- a/ts/components/conversation/Timeline.tsx +++ b/ts/components/conversation/Timeline.tsx @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { first, get, isNumber, last, throttle } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import type { ReactChild, ReactNode, RefObject, UIEvent } from 'react'; import React from 'react'; @@ -50,6 +50,8 @@ import { ScrollerLockContext, } from '../../hooks/useScrollLock.js'; +const { first, get, isNumber, last, throttle } = lodash; + const AT_BOTTOM_THRESHOLD = 15; const AT_BOTTOM_DETECTOR_STYLE = { height: AT_BOTTOM_THRESHOLD }; diff --git a/ts/components/conversation/TimelineMessage.stories.tsx b/ts/components/conversation/TimelineMessage.stories.tsx index 59cc6f341cd..4b84c65dd2c 100644 --- a/ts/components/conversation/TimelineMessage.stories.tsx +++ b/ts/components/conversation/TimelineMessage.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { isBoolean, noop } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta, StoryFn } from '@storybook/react'; @@ -45,6 +45,8 @@ import { BadgeCategory } from '../../badges/BadgeCategory.js'; import { PaymentEventKind } from '../../types/Payment.js'; import { EmojiSkinTone } from '../fun/data/emojis.js'; +const { isBoolean, noop } = lodash; + const { i18n } = window.SignalContext; const quoteOptions = { diff --git a/ts/components/conversation/TimelineMessage.tsx b/ts/components/conversation/TimelineMessage.tsx index 8ee7a8eee80..52b4fad4128 100644 --- a/ts/components/conversation/TimelineMessage.tsx +++ b/ts/components/conversation/TimelineMessage.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import React, { useCallback, useEffect, @@ -14,7 +14,7 @@ import type { Ref } from 'react'; import { ContextMenuTrigger } from 'react-contextmenu'; import { createPortal } from 'react-dom'; import { Manager, Popper, Reference } from 'react-popper'; -import type { PreventOverflowModifier } from '@popperjs/core/lib/modifiers/preventOverflow'; +import type { PreventOverflowModifier } from '@popperjs/core/lib/modifiers/preventOverflow.js'; import { isDownloaded } from '../../types/Attachment.js'; import type { LocalizerType } from '../../types/I18N.js'; import { handleOutsideClick } from '../../util/handleOutsideClick.js'; @@ -52,6 +52,8 @@ import { ForwardMessagesModalType } from '../ForwardMessagesModal.js'; import { useGroupedAndOrderedReactions } from '../../util/groupAndOrderReactions.js'; import { isNotNil } from '../../util/isNotNil.js'; +const { noop } = lodash; + export type PropsData = { canDownload: boolean; canCopy: boolean; diff --git a/ts/components/conversation/TypingBubble.stories.tsx b/ts/components/conversation/TypingBubble.stories.tsx index a8108b6511b..882b0c861fc 100644 --- a/ts/components/conversation/TypingBubble.stories.tsx +++ b/ts/components/conversation/TypingBubble.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useEffect, useState } from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import { getDefaultConversation } from '../../test-helpers/getDefaultConversation.js'; @@ -12,6 +12,8 @@ import { AvatarColors } from '../../types/Colors.js'; import { getFakeBadge } from '../../test-helpers/getFakeBadge.js'; import { ThemeType } from '../../types/Util.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/conversation/conversation-details/AddGroupMembersModal.stories.tsx b/ts/components/conversation/conversation-details/AddGroupMembersModal.stories.tsx index fa45112a7ca..a52a34c0079 100644 --- a/ts/components/conversation/conversation-details/AddGroupMembersModal.stories.tsx +++ b/ts/components/conversation/conversation-details/AddGroupMembersModal.stories.tsx @@ -3,7 +3,7 @@ import type { ComponentProps } from 'react'; import React, { useState } from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import { sleep } from '../../../util/sleep.js'; @@ -18,6 +18,8 @@ import { RequestState } from './util.js'; import { ThemeType } from '../../../types/Util.js'; import { makeFakeLookupConversationWithoutServiceId } from '../../../test-helpers/fakeLookupConversationWithoutServiceId.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/conversation/conversation-details/AddGroupMembersModal.tsx b/ts/components/conversation/conversation-details/AddGroupMembersModal.tsx index fce4b53c3cc..3d87ebe85fc 100644 --- a/ts/components/conversation/conversation-details/AddGroupMembersModal.tsx +++ b/ts/components/conversation/conversation-details/AddGroupMembersModal.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { useReducer } from 'react'; -import { without } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../../../types/Util.js'; import { @@ -18,6 +18,8 @@ import { import { missingCaseError } from '../../../util/missingCaseError.js'; import type { RequestState } from './util.js'; +const { without } = lodash; + type PropsType = { clearRequestError: () => void; conversationIdsAlreadyInGroup: Set; diff --git a/ts/components/conversation/conversation-details/AddGroupMembersModal/ChooseGroupMembersModal.tsx b/ts/components/conversation/conversation-details/AddGroupMembersModal/ChooseGroupMembersModal.tsx index 0e83b7d915e..265c8c4964f 100644 --- a/ts/components/conversation/conversation-details/AddGroupMembersModal/ChooseGroupMembersModal.tsx +++ b/ts/components/conversation/conversation-details/AddGroupMembersModal/ChooseGroupMembersModal.tsx @@ -8,7 +8,7 @@ import React, { useRef, useCallback, } from 'react'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { ListRowProps } from 'react-virtualized'; import type { LocalizerType, ThemeType } from '../../../../types/Util.js'; @@ -45,6 +45,8 @@ import { UsernameCheckbox } from '../../../conversationList/UsernameCheckbox.js' import { PhoneNumberCheckbox } from '../../../conversationList/PhoneNumberCheckbox.js'; import { SizeObserver } from '../../../../hooks/useSizeObserver.js'; +const { omit } = lodash; + export type StatePropsType = { regionCode: string | undefined; candidateContacts: ReadonlyArray; diff --git a/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx b/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx index 0447fca798a..e771372369c 100644 --- a/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx +++ b/ts/components/conversation/conversation-details/ConversationDetails.stories.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { action } from '@storybook/addon-actions'; -import { times } from 'lodash'; +import lodash from 'lodash'; import type { Meta } from '@storybook/react'; import type { Props } from './ConversationDetails.js'; @@ -19,6 +19,8 @@ import { DurationInSeconds } from '../../../util/durations/index.js'; import { NavTab } from '../../../types/Nav.js'; import { getFakeCallHistoryGroup } from '../../../test-helpers/getFakeCallHistoryGroup.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/conversation/conversation-details/ConversationDetailsActions.stories.tsx b/ts/components/conversation/conversation-details/ConversationDetailsActions.stories.tsx index c2206245aa3..abd38b7008d 100644 --- a/ts/components/conversation/conversation-details/ConversationDetailsActions.stories.tsx +++ b/ts/components/conversation/conversation-details/ConversationDetailsActions.stories.tsx @@ -2,12 +2,14 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { isBoolean } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import type { Props } from './ConversationDetailsActions.js'; import { ConversationDetailsActions } from './ConversationDetailsActions.js'; +const { isBoolean } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/conversation/conversation-details/PendingInvites.stories.tsx b/ts/components/conversation/conversation-details/PendingInvites.stories.tsx index 4a3f2832e30..0784bd8768e 100644 --- a/ts/components/conversation/conversation-details/PendingInvites.stories.tsx +++ b/ts/components/conversation/conversation-details/PendingInvites.stories.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import { generateAci } from '../../../types/ServiceId.js'; @@ -14,6 +14,8 @@ import { getDefaultConversation } from '../../../test-helpers/getDefaultConversa import { getFakeBadge } from '../../../test-helpers/getFakeBadge.js'; import { StorybookThemeContext } from '../../../../.storybook/StorybookThemeContext.js'; +const { times } = lodash; + const { i18n } = window.SignalContext; export default { diff --git a/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts b/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts index e8e79fea849..872596d9793 100644 --- a/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts +++ b/ts/components/conversation/media-gallery/groupMediaItemsByDate.ts @@ -2,10 +2,12 @@ // SPDX-License-Identifier: AGPL-3.0-only import moment from 'moment'; -import { compact, groupBy, sortBy } from 'lodash'; +import lodash from 'lodash'; import type { MediaItemType } from '../../../types/MediaItem.js'; import { missingCaseError } from '../../../util/missingCaseError.js'; +const { compact, groupBy, sortBy } = lodash; + type StaticSectionType = 'today' | 'yesterday' | 'thisWeek' | 'thisMonth'; type YearMonthSectionType = 'yearMonth'; diff --git a/ts/components/conversation/media-gallery/utils/mocks.ts b/ts/components/conversation/media-gallery/utils/mocks.ts index 0df20fbc6b2..6d4f2724bb9 100644 --- a/ts/components/conversation/media-gallery/utils/mocks.ts +++ b/ts/components/conversation/media-gallery/utils/mocks.ts @@ -1,12 +1,14 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { random, range, sample, sortBy } from 'lodash'; +import lodash from 'lodash'; import { type MIMEType, IMAGE_JPEG } from '../../../../types/MIME.js'; import type { MediaItemType } from '../../../../types/MediaItem.js'; import { randomBlurHash } from '../../../../util/randomBlurHash.js'; import { SignalService } from '../../../../protobuf/index.js'; +const { random, range, sample, sortBy } = lodash; + const DAY_MS = 24 * 60 * 60 * 1000; export const days = (n: number): number => n * DAY_MS; const tokens = ['foo', 'bar', 'baz', 'qux', 'quux']; diff --git a/ts/components/conversationList/BaseConversationListItem.tsx b/ts/components/conversationList/BaseConversationListItem.tsx index 32637e20a9c..350fa163527 100644 --- a/ts/components/conversationList/BaseConversationListItem.tsx +++ b/ts/components/conversationList/BaseConversationListItem.tsx @@ -4,7 +4,7 @@ import type { ReactNode, FunctionComponent } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import classNames from 'classnames'; -import { isBoolean, isNumber } from 'lodash'; +import lodash from 'lodash'; import { v4 as generateUuid } from 'uuid'; import { Avatar, AvatarSize } from '../Avatar.js'; @@ -18,6 +18,8 @@ import { Time } from '../Time.js'; import { formatDateTimeShort } from '../../util/timestamp.js'; import * as durations from '../../util/durations/index.js'; +const { isBoolean, isNumber } = lodash; + const BASE_CLASS_NAME = 'module-conversation-list__item--contact-or-conversation'; const AVATAR_CONTAINER_CLASS_NAME = `${BASE_CLASS_NAME}__avatar-container`; diff --git a/ts/components/conversationList/MessageSearchResult.tsx b/ts/components/conversationList/MessageSearchResult.tsx index 4b1ff6e70ee..77dccf1cc8e 100644 --- a/ts/components/conversationList/MessageSearchResult.tsx +++ b/ts/components/conversationList/MessageSearchResult.tsx @@ -3,7 +3,7 @@ import type { FunctionComponent, ReactNode } from 'react'; import React, { useCallback } from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { ContactName } from '../conversation/ContactName.js'; @@ -22,6 +22,8 @@ import { RenderLocation, } from '../conversation/MessageTextRenderer.js'; +const { noop } = lodash; + const EMPTY_OBJECT = Object.freeze(Object.create(null)); export type PropsDataType = { diff --git a/ts/components/emoji/EmojiButton.tsx b/ts/components/emoji/EmojiButton.tsx index f82a2bbcbc0..1057677584c 100644 --- a/ts/components/emoji/EmojiButton.tsx +++ b/ts/components/emoji/EmojiButton.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import type { MutableRefObject } from 'react'; import classNames from 'classnames'; -import { get, noop } from 'lodash'; +import lodash from 'lodash'; import { Manager, Popper, Reference } from 'react-popper'; import type { Props as EmojiPickerProps } from './EmojiPicker.js'; import { EmojiPicker } from './EmojiPicker.js'; @@ -20,6 +20,8 @@ import { isEmojiVariantValue, } from '../fun/data/emojis.js'; +const { get, noop } = lodash; + export enum EmojiButtonVariant { Normal, ProfileEditor, diff --git a/ts/components/emoji/EmojiPicker.tsx b/ts/components/emoji/EmojiPicker.tsx index ece2c8a11b1..793e2dd12fe 100644 --- a/ts/components/emoji/EmojiPicker.tsx +++ b/ts/components/emoji/EmojiPicker.tsx @@ -8,16 +8,7 @@ import type { SectionRenderedParams, } from 'react-virtualized'; import { AutoSizer, Grid } from 'react-virtualized'; -import { - chunk, - clamp, - debounce, - findLast, - flatMap, - initial, - last, - zipObject, -} from 'lodash'; +import lodash from 'lodash'; import { FocusScope } from 'react-aria'; import { dataByCategory } from './lib.js'; import type { LocalizerType } from '../../types/Util.js'; @@ -38,6 +29,9 @@ import { } from '../fun/data/emojis.js'; import { useFunEmojiSearch } from '../fun/useFunEmojiSearch.js'; +const { chunk, clamp, debounce, findLast, flatMap, initial, last, zipObject } = + lodash; + export type EmojiPickDataType = { skinTone: EmojiSkinTone; shortName: string; diff --git a/ts/components/emoji/lib.ts b/ts/components/emoji/lib.ts index 405260d4153..321fe6c714e 100644 --- a/ts/components/emoji/lib.ts +++ b/ts/components/emoji/lib.ts @@ -3,7 +3,7 @@ // Camelcase disabled due to emoji-datasource using snake_case /* eslint-disable camelcase */ -import { groupBy, keyBy, mapValues, sortBy } from 'lodash'; +import lodash from 'lodash'; import { getOwn } from '../../util/getOwn.js'; import { EMOJI_SKIN_TONE_TO_KEY, @@ -12,6 +12,8 @@ import { } from '../fun/data/emojis.js'; import { strictAssert } from '../../util/assert.js'; +const { groupBy, keyBy, mapValues, sortBy } = lodash; + // Import emoji-datasource dynamically to avoid costly typechecking. // eslint-disable-next-line import/no-dynamic-require, @typescript-eslint/no-var-requires const untypedData = require('emoji-datasource' as string); diff --git a/ts/components/fun/FunEmoji.stories.tsx b/ts/components/fun/FunEmoji.stories.tsx index 34db0a18bee..d97b6b4098a 100644 --- a/ts/components/fun/FunEmoji.stories.tsx +++ b/ts/components/fun/FunEmoji.stories.tsx @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { useVirtualizer } from '@tanstack/react-virtual'; -import { chunk } from 'lodash'; +import lodash from 'lodash'; import React, { useCallback, useEffect, useRef } from 'react'; import { type ComponentMeta } from '../../storybook/types.js'; import type { FunStaticEmojiProps } from './FunEmoji.js'; @@ -14,6 +14,8 @@ import { getEmojiVariantByKey, } from './data/emojis.js'; +const { chunk } = lodash; + export default { title: 'Components/Fun/FunEmoji', component: All, diff --git a/ts/components/fun/FunStickerPicker.stories.tsx b/ts/components/fun/FunStickerPicker.stories.tsx index 07e76aa1277..15a8673b580 100644 --- a/ts/components/fun/FunStickerPicker.stories.tsx +++ b/ts/components/fun/FunStickerPicker.stories.tsx @@ -3,9 +3,7 @@ import React, { useCallback, useState } from 'react'; import { Button } from 'react-aria-components'; import { action } from '@storybook/addon-actions'; -import enMessages from '../../../_locales/en/messages.json'; import { type ComponentMeta } from '../../storybook/types.js'; -import { setupI18n } from '../../util/setupI18n.js'; import type { FunStickerPickerProps } from './FunStickerPicker.js'; import { FunStickerPicker } from './FunStickerPicker.js'; import { MOCK_RECENT_EMOJIS } from './mocks.js'; @@ -13,7 +11,7 @@ import { FunProvider } from './FunProvider.js'; import { packs, recentStickers } from '../stickers/mocks.js'; import { EmojiSkinTone } from './data/emojis.js'; -const i18n = setupI18n('en', enMessages); +const { i18n } = window.SignalContext; type TemplateProps = Omit< FunStickerPickerProps, diff --git a/ts/components/fun/base/FunScroller.tsx b/ts/components/fun/base/FunScroller.tsx index 304228959c8..c4acad7d6b2 100644 --- a/ts/components/fun/base/FunScroller.tsx +++ b/ts/components/fun/base/FunScroller.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { mergeRefs } from '@react-aria/utils'; import classNames from 'classnames'; -import { maxBy } from 'lodash'; +import lodash from 'lodash'; import type { CSSProperties, ReactNode, Ref } from 'react'; import React, { createContext, @@ -21,6 +21,8 @@ import { } from '../../../hooks/useSizeObserver.js'; import { strictAssert } from '../../../util/assert.js'; +const { maxBy } = lodash; + export type FunScrollerProps = Readonly<{ sectionGap: number; onScrollSectionChange?: (id: string) => void; diff --git a/ts/components/fun/keyboard/GridKeyboardDelegate.tsx b/ts/components/fun/keyboard/GridKeyboardDelegate.tsx index d67b49dfe95..4f3bacd35f7 100644 --- a/ts/components/fun/keyboard/GridKeyboardDelegate.tsx +++ b/ts/components/fun/keyboard/GridKeyboardDelegate.tsx @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { VirtualItem, Virtualizer } from '@tanstack/react-virtual'; -import { findLast, sortBy } from 'lodash'; +import lodash from 'lodash'; import { strictAssert } from '../../../util/assert.js'; import type { CellKey, @@ -11,6 +11,8 @@ import type { } from '../virtual/useFunVirtualGrid.js'; import { KeyboardDelegate } from './FunKeyboard.js'; +const { findLast, sortBy } = lodash; + const PAGE_MARGIN = 0.25; // % of scroll height type Cell = Readonly<{ diff --git a/ts/components/fun/keyboard/WaterfallKeyboardDelegate.tsx b/ts/components/fun/keyboard/WaterfallKeyboardDelegate.tsx index e442442097c..197b788658a 100644 --- a/ts/components/fun/keyboard/WaterfallKeyboardDelegate.tsx +++ b/ts/components/fun/keyboard/WaterfallKeyboardDelegate.tsx @@ -1,10 +1,12 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { VirtualItem, Virtualizer } from '@tanstack/react-virtual'; -import { findLast, maxBy } from 'lodash'; +import lodash from 'lodash'; import { strictAssert } from '../../../util/assert.js'; import { KeyboardDelegate } from './FunKeyboard.js'; +const { findLast, maxBy } = lodash; + const PAGE_MARGIN = 0.25; // % of scroll height enum Mode { diff --git a/ts/components/fun/useFunEmojiSearch.tsx b/ts/components/fun/useFunEmojiSearch.tsx index 677da2bb9c0..8b129110614 100644 --- a/ts/components/fun/useFunEmojiSearch.tsx +++ b/ts/components/fun/useFunEmojiSearch.tsx @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import Fuse from 'fuse.js'; -import { sortBy } from 'lodash'; +import lodash from 'lodash'; import { useMemo } from 'react'; import type { EmojiParentKey } from './data/emojis.js'; import { @@ -14,6 +14,8 @@ import { import type { LocaleEmojiListType } from '../../types/emoji.js'; import { useFunEmojiLocalization } from './FunEmojiLocalizationProvider.js'; +const { sortBy } = lodash; + export type FunEmojiSearchIndexEntry = Readonly<{ key: EmojiParentKey; rank: number | null; diff --git a/ts/components/fun/virtual/useFunVirtualGrid.tsx b/ts/components/fun/virtual/useFunVirtualGrid.tsx index 92dcc443a63..b65b0589d50 100644 --- a/ts/components/fun/virtual/useFunVirtualGrid.tsx +++ b/ts/components/fun/virtual/useFunVirtualGrid.tsx @@ -6,12 +6,14 @@ import { type VirtualItem, type Virtualizer, } from '@tanstack/react-virtual'; -import { chunk, groupBy } from 'lodash'; +import lodash from 'lodash'; import type { RefObject } from 'react'; import { useCallback, useMemo } from 'react'; import { strictAssert } from '../../../util/assert.js'; import { missingCaseError } from '../../../util/missingCaseError.js'; +const { chunk, groupBy } = lodash; + export type SectionKey = `section-${string}`; export type HeaderKey = `header-${string}`; export type RowKey = `row-${string}`; diff --git a/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx b/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx index a191d72552f..4942107b370 100644 --- a/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx +++ b/ts/components/installScreen/InstallScreenQrCodeNotScannedStep.tsx @@ -4,7 +4,7 @@ import type { ReactElement, ReactNode } from 'react'; import React, { useCallback, useState, useEffect } from 'react'; import classNames from 'classnames'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../../types/Util.js'; import { @@ -26,6 +26,8 @@ import { InstallScreenUpdateDialog } from './InstallScreenUpdateDialog.js'; import { getClassNamesFor } from '../../util/getClassNamesFor.js'; import type { UpdatesStateType } from '../../state/ducks/updates.js'; +const { noop } = lodash; + // We can't always use destructuring assignment because of the complexity of this props // type. diff --git a/ts/components/installScreen/InstallScreenUpdateDialog.tsx b/ts/components/installScreen/InstallScreenUpdateDialog.tsx index c18546d1ea0..d81a18ff81e 100644 --- a/ts/components/installScreen/InstallScreenUpdateDialog.tsx +++ b/ts/components/installScreen/InstallScreenUpdateDialog.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { DialogType } from '../../types/Dialogs.js'; import { InstallScreenStep } from '../../types/InstallScreen.js'; @@ -21,6 +21,8 @@ import { Modal } from '../Modal.js'; import { I18n } from '../I18n.js'; import { formatFileSize } from '../../util/formatFileSize.js'; +const { noop } = lodash; + export type PropsType = UpdatesStateType & Readonly<{ i18n: LocalizerType; diff --git a/ts/components/leftPane/LeftPaneArchiveHelper.tsx b/ts/components/leftPane/LeftPaneArchiveHelper.tsx index c51940b6773..8a653d3d56e 100644 --- a/ts/components/leftPane/LeftPaneArchiveHelper.tsx +++ b/ts/components/leftPane/LeftPaneArchiveHelper.tsx @@ -3,7 +3,7 @@ import type { ReactChild } from 'react'; import React from 'react'; -import { last } from 'lodash'; +import lodash from 'lodash'; import type { ToFindType } from './LeftPaneHelper.js'; import { LeftPaneHelper } from './LeftPaneHelper.js'; @@ -21,6 +21,8 @@ import type { LeftPaneSearchPropsType } from './LeftPaneSearchHelper.js'; import { LeftPaneSearchHelper } from './LeftPaneSearchHelper.js'; import * as KeyboardLayout from '../../services/keyboardLayout.js'; +const { last } = lodash; + type LeftPaneArchiveBasePropsType = { archivedConversations: ReadonlyArray; isSearchingGlobally: boolean; diff --git a/ts/components/leftPane/LeftPaneInboxHelper.tsx b/ts/components/leftPane/LeftPaneInboxHelper.tsx index ae17071ebc4..f1702df0854 100644 --- a/ts/components/leftPane/LeftPaneInboxHelper.tsx +++ b/ts/components/leftPane/LeftPaneInboxHelper.tsx @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { last } from 'lodash'; +import lodash from 'lodash'; import type { ReactChild } from 'react'; import React from 'react'; @@ -20,6 +20,8 @@ import type { LocalizerType } from '../../types/Util.js'; import { handleKeydownForSearch } from './handleKeydownForSearch.js'; import { LeftPaneSearchInput } from '../LeftPaneSearchInput.js'; +const { last } = lodash; + export type LeftPaneInboxPropsType = { conversations: ReadonlyArray; archivedConversations: ReadonlyArray; diff --git a/ts/components/leftPane/getConversationInDirection.ts b/ts/components/leftPane/getConversationInDirection.ts index 73924762ecf..ff7cd85170b 100644 --- a/ts/components/leftPane/getConversationInDirection.ts +++ b/ts/components/leftPane/getConversationInDirection.ts @@ -1,13 +1,15 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { find as findFirst, findLast, first, last } from 'lodash'; +import lodash from 'lodash'; import type { PropsData as ConversationListItemPropsType } from '../conversationList/ConversationListItem.js'; import { isConversationUnread } from '../../util/isConversationUnread.js'; import type { ToFindType } from './LeftPaneHelper.js'; import { FindDirection } from './LeftPaneHelper.js'; +const { find: findFirst, findLast, first, last } = lodash; + /** * This will look up or down in an array of conversations for the next one to select. * Refer to the tests for the intended behavior. diff --git a/ts/components/stickers/StickerButton.tsx b/ts/components/stickers/StickerButton.tsx index d1420f321ef..8207744ec6e 100644 --- a/ts/components/stickers/StickerButton.tsx +++ b/ts/components/stickers/StickerButton.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import classNames from 'classnames'; -import { get, noop } from 'lodash'; +import lodash from 'lodash'; import { Manager, Popper, Reference } from 'react-popper'; import { createPortal } from 'react-dom'; @@ -22,6 +22,8 @@ import * as KeyboardLayout from '../../services/keyboardLayout.js'; import { useRefMerger } from '../../hooks/useRefMerger.js'; import { UserText } from '../UserText.js'; +const { get, noop } = lodash; + export type OwnProps = { readonly className?: string; readonly i18n: LocalizerType; diff --git a/ts/components/stickers/StickerPreviewModal.tsx b/ts/components/stickers/StickerPreviewModal.tsx index 0c328af2576..42ff5ec27e2 100644 --- a/ts/components/stickers/StickerPreviewModal.tsx +++ b/ts/components/stickers/StickerPreviewModal.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import * as React from 'react'; -import { isNumber, range } from 'lodash'; +import lodash from 'lodash'; import classNames from 'classnames'; import { ConfirmationDialog } from '../ConfirmationDialog.js'; import type { LocalizerType } from '../../types/Util.js'; @@ -13,6 +13,8 @@ import { Modal } from '../Modal.js'; import { Button, ButtonVariant } from '../Button.js'; import { UserText } from '../UserText.js'; +const { isNumber, range } = lodash; + export type OwnProps = { readonly onClose?: () => unknown; readonly closeStickerPackPreview: () => unknown; diff --git a/ts/components/stickers/mocks.ts b/ts/components/stickers/mocks.ts index 0a5af585260..771d58d5380 100644 --- a/ts/components/stickers/mocks.ts +++ b/ts/components/stickers/mocks.ts @@ -1,12 +1,14 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { sample } from 'lodash'; +import lodash from 'lodash'; import type { StickerPackType, StickerType, } from '../../state/ducks/stickers.js'; +const { sample } = lodash; + export const sticker1: StickerType = { id: 1, url: '/fixtures/kitten-1-64-64.jpg', diff --git a/ts/groups.ts b/ts/groups.ts index 1feece2ec40..de824451d3f 100644 --- a/ts/groups.ts +++ b/ts/groups.ts @@ -1,17 +1,9 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { - compact, - difference, - flatten, - fromPairs, - isNumber, - omit, - values, -} from 'lodash'; +import lodash from 'lodash'; import Long from 'long'; -import type { ClientZkGroupCipher } from '@signalapp/libsignal-client/zkgroup'; +import type { ClientZkGroupCipher } from '@signalapp/libsignal-client/zkgroup.js'; import { LRUCache } from 'lru-cache'; import { createLogger } from './logging/log.js'; import { @@ -114,6 +106,9 @@ import { isTrustedContact, } from './util/isConversationAccepted.js'; +const { compact, difference, flatten, fromPairs, isNumber, omit, values } = + lodash; + const log = createLogger('groups'); type AccessRequiredEnum = Proto.AccessControl.AccessRequired; diff --git a/ts/groups/limits.ts b/ts/groups/limits.ts index 1c0848e3c20..d982a80eab3 100644 --- a/ts/groups/limits.ts +++ b/ts/groups/limits.ts @@ -1,11 +1,13 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { parseIntOrThrow } from '../util/parseIntOrThrow.js'; import type { ConfigKeyType } from '../RemoteConfig.js'; import { getValue } from '../RemoteConfig.js'; +const { isNumber } = lodash; + function makeGetter(configKey: ConfigKeyType): (fallback?: number) => number { return fallback => { try { diff --git a/ts/groups/toggleSelectedContactForGroupAddition.ts b/ts/groups/toggleSelectedContactForGroupAddition.ts index d338e817637..f5ce59898cc 100644 --- a/ts/groups/toggleSelectedContactForGroupAddition.ts +++ b/ts/groups/toggleSelectedContactForGroupAddition.ts @@ -1,7 +1,9 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { without } from 'lodash'; +import lodash from 'lodash'; + +const { without } = lodash; export enum OneTimeModalState { NeverShown, diff --git a/ts/hooks/useComputePeaks.ts b/ts/hooks/useComputePeaks.ts index f8f126e1937..8fab4078430 100644 --- a/ts/hooks/useComputePeaks.ts +++ b/ts/hooks/useComputePeaks.ts @@ -1,11 +1,13 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop } from 'lodash'; +import lodash from 'lodash'; import { useEffect, useState } from 'react'; import { computePeaks } from '../components/VoiceNotesPlaybackContext.js'; import { createLogger } from '../logging/log.js'; +const { noop } = lodash; + const log = createLogger('useComputePeaks'); type WaveformData = { diff --git a/ts/hooks/useHasWrapped.ts b/ts/hooks/useHasWrapped.ts index d5a9cab1952..16b1432dd28 100644 --- a/ts/hooks/useHasWrapped.ts +++ b/ts/hooks/useHasWrapped.ts @@ -3,7 +3,9 @@ import type { Ref } from 'react'; import { useEffect, useState } from 'react'; -import { first, last, noop } from 'lodash'; +import lodash from 'lodash'; + +const { first, last, noop } = lodash; function getBottom(element: Readonly): number { return element.getBoundingClientRect().bottom; diff --git a/ts/hooks/useKeyboardShortcuts.tsx b/ts/hooks/useKeyboardShortcuts.tsx index d06edcb3bb9..ed47d9d658e 100644 --- a/ts/hooks/useKeyboardShortcuts.tsx +++ b/ts/hooks/useKeyboardShortcuts.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { useCallback, useEffect } from 'react'; -import { get } from 'lodash'; +import lodash from 'lodash'; import { useSelector } from 'react-redux'; import * as KeyboardLayout from '../services/keyboardLayout.js'; import { getHasPanelOpen } from '../state/selectors/conversations.js'; @@ -10,6 +10,8 @@ import { isInFullScreenCall } from '../state/selectors/calling.js'; import { isShowingAnyModal } from '../state/selectors/globalModals.js'; import type { ContextMenuTriggerType } from '../components/conversation/MessageContextMenu.js'; +const { get } = lodash; + type KeyboardShortcutHandlerType = (ev: KeyboardEvent) => boolean; export function isCmdOrCtrl(ev: KeyboardEvent): boolean { diff --git a/ts/jobs/AttachmentDownloadManager.ts b/ts/jobs/AttachmentDownloadManager.ts index 3ecc465d135..5124ed2725c 100644 --- a/ts/jobs/AttachmentDownloadManager.ts +++ b/ts/jobs/AttachmentDownloadManager.ts @@ -1,6 +1,6 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop, omit, throttle } from 'lodash'; +import lodash from 'lodash'; import { statfs } from 'node:fs/promises'; import * as durations from '../util/durations/index.js'; @@ -72,6 +72,8 @@ import { HTTPError } from '../textsecure/Errors.js'; import { isOlderThan } from '../util/timestamp.js'; import { getMessageQueueTime as doGetMessageQueueTime } from '../util/getMessageQueueTime.js'; +const { noop, omit, throttle } = lodash; + const log = createLogger('AttachmentDownloadManager'); export { isPermanentlyUndownloadable }; diff --git a/ts/jobs/JobQueue.ts b/ts/jobs/JobQueue.ts index 2154a381053..76e42ea8d7a 100644 --- a/ts/jobs/JobQueue.ts +++ b/ts/jobs/JobQueue.ts @@ -3,7 +3,7 @@ import PQueue from 'p-queue'; import { v7 as uuid } from 'uuid'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { Job } from './Job.js'; import { JobError } from './JobError.js'; @@ -17,6 +17,8 @@ import { drop } from '../util/drop.js'; import { sleep } from '../util/sleep.js'; import { SECOND } from '../util/durations/index.js'; +const { noop } = lodash; + const log = createLogger('JobQueue'); const noopOnCompleteCallbacks = { diff --git a/ts/jobs/JobQueueDatabaseStore.ts b/ts/jobs/JobQueueDatabaseStore.ts index fbec4f77645..2360a42e7fc 100644 --- a/ts/jobs/JobQueueDatabaseStore.ts +++ b/ts/jobs/JobQueueDatabaseStore.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop } from 'lodash'; +import lodash from 'lodash'; import { AsyncQueue } from '../util/AsyncQueue.js'; import { concat, wrapPromise } from '../util/asyncIterables.js'; import type { JobQueueStore, StoredJob } from './types.js'; @@ -9,6 +9,8 @@ import { formatJobForInsert } from './formatJobForInsert.js'; import { DataReader, DataWriter } from '../sql/Client.js'; import { createLogger } from '../logging/log.js'; +const { noop } = lodash; + const log = createLogger('JobQueueDatabaseStore'); type Database = { diff --git a/ts/jobs/deleteDownloadsJobQueue.ts b/ts/jobs/deleteDownloadsJobQueue.ts index 8da0cdc8bc2..75dab28a810 100644 --- a/ts/jobs/deleteDownloadsJobQueue.ts +++ b/ts/jobs/deleteDownloadsJobQueue.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { z } from 'zod'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import { JobQueue } from './JobQueue.js'; import { jobQueueDatabaseStore } from './JobQueueDatabaseStore.js'; @@ -15,6 +15,8 @@ import { commonShouldJobContinue } from './helpers/commonShouldJobContinue.js'; import { DAY } from '../util/durations/index.js'; import { exponentialBackoffMaxAttempts } from '../util/exponentialBackoff.js'; +const { omit } = lodash; + const deleteDownloadsJobDataSchema = z.object({ digest: z.string().optional(), downloadPath: z.string(), diff --git a/ts/jobs/helpers/sendDeleteForEveryone.ts b/ts/jobs/helpers/sendDeleteForEveryone.ts index 47bf56cd959..44323a9a8f0 100644 --- a/ts/jobs/helpers/sendDeleteForEveryone.ts +++ b/ts/jobs/helpers/sendDeleteForEveryone.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { ContentHint } from '@signalapp/libsignal-client'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import * as Errors from '../../types/errors.js'; import { getSendOptions } from '../../util/getSendOptions.js'; @@ -39,6 +39,8 @@ import type { ServiceIdString } from '../../types/ServiceId.js'; import { isStory } from '../../messages/helpers.js'; import { sendToGroup } from '../../util/sendToGroup.js'; +const { isNumber } = lodash; + export async function sendDeleteForEveryone( conversation: ConversationModel, { diff --git a/ts/jobs/helpers/sendNormalMessage.ts b/ts/jobs/helpers/sendNormalMessage.ts index ccf636319cb..8f0cf4b13b5 100644 --- a/ts/jobs/helpers/sendNormalMessage.ts +++ b/ts/jobs/helpers/sendNormalMessage.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import PQueue from 'p-queue'; import { ContentHint } from '@signalapp/libsignal-client'; @@ -67,6 +67,8 @@ import { import { getMessageIdForLogging } from '../../util/idForLogging.js'; import { send, sendSyncMessageOnly } from '../../messages/send.js'; +const { isNumber } = lodash; + const MAX_CONCURRENT_ATTACHMENT_UPLOADS = 5; export async function sendNormalMessage( diff --git a/ts/jobs/helpers/sendProfileKey.ts b/ts/jobs/helpers/sendProfileKey.ts index 33e8aaf5dc5..0fb3175d46b 100644 --- a/ts/jobs/helpers/sendProfileKey.ts +++ b/ts/jobs/helpers/sendProfileKey.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { ContentHint } from '@signalapp/libsignal-client'; import { handleMessageSend } from '../../util/handleMessageSend.js'; @@ -35,6 +35,8 @@ import { import { shouldSendToConversation } from './shouldSendToConversation.js'; import { sendToGroup } from '../../util/sendToGroup.js'; +const { isNumber } = lodash; + export function canAllErrorsBeIgnored( conversation: ConversationAttributesType, error: unknown diff --git a/ts/jobs/helpers/sendReaction.ts b/ts/jobs/helpers/sendReaction.ts index d398b0730ab..58f2edbbf55 100644 --- a/ts/jobs/helpers/sendReaction.ts +++ b/ts/jobs/helpers/sendReaction.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { ContentHint } from '@signalapp/libsignal-client'; import * as Errors from '../../types/errors.js'; @@ -43,6 +43,8 @@ import { sendToGroup } from '../../util/sendToGroup.js'; import { hydrateStoryContext } from '../../util/hydrateStoryContext.js'; import { send, sendSyncMessageOnly } from '../../messages/send.js'; +const { isNumber } = lodash; + export async function sendReaction( conversation: ConversationModel, { diff --git a/ts/jobs/helpers/sendStory.ts b/ts/jobs/helpers/sendStory.ts index f14c5c099eb..0dc69a18b1f 100644 --- a/ts/jobs/helpers/sendStory.ts +++ b/ts/jobs/helpers/sendStory.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isEqual } from 'lodash'; +import lodash from 'lodash'; import { ContentHint } from '@signalapp/libsignal-client'; import type { UploadedAttachmentType } from '../../types/Attachment.js'; @@ -48,6 +48,8 @@ import { } from '../../test-node/util/messageFailures.js'; import { send } from '../../messages/send.js'; +const { isEqual } = lodash; + export async function sendStory( conversation: ConversationModel, { diff --git a/ts/jobs/helpers/syncHelpers.ts b/ts/jobs/helpers/syncHelpers.ts index a57d4b7e5a1..f8070416744 100644 --- a/ts/jobs/helpers/syncHelpers.ts +++ b/ts/jobs/helpers/syncHelpers.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { chunk } from 'lodash'; +import lodash from 'lodash'; import type { LoggerType } from '../../types/Logging.js'; import type { AciString } from '../../types/ServiceId.js'; import { normalizeAci } from '../../util/normalizeAci.js'; @@ -17,6 +17,8 @@ import { handleCommonJobRequestError } from './handleCommonJobRequestError.js'; import { missingCaseError } from '../../util/missingCaseError.js'; import type SendMessage from '../../textsecure/SendMessage.js'; +const { chunk } = lodash; + const CHUNK_SIZE = 100; export type SyncType = { diff --git a/ts/jobs/singleProtoJobQueue.ts b/ts/jobs/singleProtoJobQueue.ts index 7ab4a18e405..7a48763fa77 100644 --- a/ts/jobs/singleProtoJobQueue.ts +++ b/ts/jobs/singleProtoJobQueue.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import PQueue from 'p-queue'; -import { isBoolean } from 'lodash'; +import lodash from 'lodash'; import * as Bytes from '../Bytes.js'; import type { LoggerType } from '../types/Logging.js'; @@ -26,6 +26,8 @@ import { isConversationUnregistered } from '../util/isConversationUnregistered.j import { isConversationAccepted } from '../util/isConversationAccepted.js'; import { parseUnknown } from '../util/schemas.js'; +const { isBoolean } = lodash; + const MAX_RETRY_TIME = DAY; const MAX_PARALLEL_JOBS = 5; const MAX_ATTEMPTS = exponentialBackoffMaxAttempts(MAX_RETRY_TIME); diff --git a/ts/logging/debuglogs.ts b/ts/logging/debuglogs.ts index c591197264d..922a00da695 100644 --- a/ts/logging/debuglogs.ts +++ b/ts/logging/debuglogs.ts @@ -1,7 +1,7 @@ // Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { memoize, sortBy } from 'lodash'; +import lodash from 'lodash'; import { reallyJsonStringify } from '../util/reallyJsonStringify.js'; import type { FetchLogIpcData, LogEntryType } from './shared.js'; import { @@ -14,6 +14,8 @@ import { import { redactAll } from '../util/privacy.js'; import { getEnvironment } from '../environment.js'; +const { memoize, sortBy } = lodash; + // The mechanics of preparing a log for publish const headerSectionTitle = (title: string) => `========= ${title} =========`; diff --git a/ts/logging/main_process_logging.ts b/ts/logging/main_process_logging.ts index 8d2d61ce212..f6d112e3388 100644 --- a/ts/logging/main_process_logging.ts +++ b/ts/logging/main_process_logging.ts @@ -9,7 +9,7 @@ import { CircularBuffer } from 'cirbuf'; import type { BrowserWindow } from 'electron'; import { app, ipcMain as ipc } from 'electron'; import readFirstLine from 'firstline'; -import { filter, flatten, map, pick, sortBy } from 'lodash'; +import lodash from 'lodash'; import { createReadStream, mkdirSync, @@ -32,6 +32,8 @@ import { setPinoDestination, log } from './log.js'; import type { FetchLogIpcData, LogEntryType } from './shared.js'; import { LogLevel, isLogEntry } from './shared.js'; +const { filter, flatten, map, pick, sortBy } = lodash; + const MAX_LOG_LINES = 10_000_000; let isInitialized = false; diff --git a/ts/mediaEditor/MediaEditorFabricAnalogTimeSticker.ts b/ts/mediaEditor/MediaEditorFabricAnalogTimeSticker.ts index 0f4653c45d5..894017cc09c 100644 --- a/ts/mediaEditor/MediaEditorFabricAnalogTimeSticker.ts +++ b/ts/mediaEditor/MediaEditorFabricAnalogTimeSticker.ts @@ -1,13 +1,15 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { get } from 'lodash'; +import lodash from 'lodash'; import { fabric } from 'fabric'; import { customFabricObjectControls } from './util/customFabricObjectControls.js'; import { getAnalogTime } from '../util/getAnalogTime.js'; import { strictAssert } from '../util/assert.js'; import { moreStyles } from './util/moreStyles.js'; +const { get } = lodash; + export enum AnalogClockStickerStyle { Arabic = 'Arabic', Baton = 'Baton', diff --git a/ts/mediaEditor/MediaEditorFabricCropRect.ts b/ts/mediaEditor/MediaEditorFabricCropRect.ts index 8f89748ae25..4adfd936b7f 100644 --- a/ts/mediaEditor/MediaEditorFabricCropRect.ts +++ b/ts/mediaEditor/MediaEditorFabricCropRect.ts @@ -2,9 +2,11 @@ // SPDX-License-Identifier: AGPL-3.0-only import { fabric } from 'fabric'; -import { clamp } from 'lodash'; +import lodash from 'lodash'; import { strictAssert } from '../util/assert.js'; +const { clamp } = lodash; + export class MediaEditorFabricCropRect extends fabric.Rect { static PADDING = 4; diff --git a/ts/messageModifiers/AttachmentDownloads.ts b/ts/messageModifiers/AttachmentDownloads.ts index b33a9fc0454..fd92c92796a 100644 --- a/ts/messageModifiers/AttachmentDownloads.ts +++ b/ts/messageModifiers/AttachmentDownloads.ts @@ -1,6 +1,6 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import * as Bytes from '../Bytes.js'; import type { AttachmentDownloadJobTypeType } from '../types/AttachmentDownload.js'; @@ -13,6 +13,8 @@ import { import { getMessageById } from '../messages/getMessageById.js'; import { trimMessageWhitespace } from '../types/BodyRange.js'; +const { omit } = lodash; + const log = createLogger('AttachmentDownloads'); export async function markAttachmentAsCorrupted( diff --git a/ts/messageModifiers/MessageReceipts.ts b/ts/messageModifiers/MessageReceipts.ts index 1f598d022a1..d8b3d7f559b 100644 --- a/ts/messageModifiers/MessageReceipts.ts +++ b/ts/messageModifiers/MessageReceipts.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { z } from 'zod'; -import { groupBy } from 'lodash'; +import lodash from 'lodash'; import type { MessageAttributesType, @@ -36,6 +36,8 @@ import { getMessageById } from '../messages/getMessageById.js'; import { MessageModel } from '../models/messages.js'; import { areStoryViewReceiptsEnabled } from '../types/Stories.js'; +const { groupBy } = lodash; + const log = createLogger('MessageReceipts'); const { deleteSentProtoRecipient, removeSyncTasks, removeSyncTaskById } = diff --git a/ts/messageModifiers/Reactions.ts b/ts/messageModifiers/Reactions.ts index 98b7a31e1d2..5ec905fe117 100644 --- a/ts/messageModifiers/Reactions.ts +++ b/ts/messageModifiers/Reactions.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { maxBy } from 'lodash'; +import lodash from 'lodash'; import type { AciString } from '../types/ServiceId.js'; import type { @@ -46,6 +46,8 @@ import { } from '../jobs/conversationJobQueue.js'; import { maybeNotify } from '../messages/maybeNotify.js'; +const { maxBy } = lodash; + const log = createLogger('Reactions'); export type ReactionAttributesType = { diff --git a/ts/messages/copyQuote.ts b/ts/messages/copyQuote.ts index d7e9a8306a7..3c3707c9bee 100644 --- a/ts/messages/copyQuote.ts +++ b/ts/messages/copyQuote.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import type { QuotedMessageType } from '../model-types.js'; @@ -16,6 +16,8 @@ import * as Errors from '../types/errors.js'; import type { MessageModel } from '../models/messages.js'; import { isDownloadable } from '../types/Attachment.js'; +const { omit } = lodash; + const log = createLogger('copyQuote'); export type MinimalMessageCache = Readonly<{ diff --git a/ts/messages/handleDataMessage.ts b/ts/messages/handleDataMessage.ts index 374a8c7ea97..9e096f814c1 100644 --- a/ts/messages/handleDataMessage.ts +++ b/ts/messages/handleDataMessage.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import type { z } from 'zod'; import { createLogger } from '../logging/log.js'; @@ -69,6 +69,8 @@ import type { ServiceIdString } from '../types/ServiceId.js'; import type { LinkPreviewType } from '../types/message/LinkPreviews.js'; import { getCachedSubscriptionConfiguration } from '../util/subscriptionConfiguration.js'; +const { isNumber } = lodash; + const log = createLogger('handleDataMessage'); const CURRENT_PROTOCOL_VERSION = Proto.DataMessage.ProtocolVersion.CURRENT; diff --git a/ts/messages/migrateLegacySendAttributes.ts b/ts/messages/migrateLegacySendAttributes.ts index 20c7653fd70..f731a73e940 100644 --- a/ts/messages/migrateLegacySendAttributes.ts +++ b/ts/messages/migrateLegacySendAttributes.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { get, isEmpty } from 'lodash'; +import lodash from 'lodash'; import { getOwn } from '../util/getOwn.js'; import { map, concat, repeat, zipObject } from '../util/iterables.js'; import { isOutgoing } from '../state/selectors/message.js'; @@ -16,6 +16,8 @@ import { SendStatus, } from './MessageSendState.js'; +const { get, isEmpty } = lodash; + type LegacyCustomError = Error & { identifier?: string; number?: string; diff --git a/ts/messages/migrateMessageData.ts b/ts/messages/migrateMessageData.ts index b213a3246c3..e5ee85fc483 100644 --- a/ts/messages/migrateMessageData.ts +++ b/ts/messages/migrateMessageData.ts @@ -1,7 +1,7 @@ // Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isFunction, isNumber } from 'lodash'; +import lodash from 'lodash'; import pMap from 'p-map'; import PQueue from 'p-queue'; @@ -15,6 +15,8 @@ import { DataReader, DataWriter } from '../sql/Client.js'; import { postSaveUpdates } from '../util/cleanup.js'; import { createLogger } from '../logging/log.js'; +const { isFunction, isNumber } = lodash; + const log = createLogger('migrateMessageData'); const MAX_CONCURRENCY = 5; diff --git a/ts/messages/send.ts b/ts/messages/send.ts index a3cf79eb282..abf17a4392e 100644 --- a/ts/messages/send.ts +++ b/ts/messages/send.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop, union } from 'lodash'; +import lodash from 'lodash'; import { filter, map } from '../util/iterables.js'; import { isNotNil } from '../util/isNotNil.js'; @@ -33,6 +33,8 @@ import type { MessageModel } from '../models/messages.js'; import type { ServiceIdString } from '../types/ServiceId.js'; import type { SendStateByConversationId } from './MessageSendState.js'; +const { noop, union } = lodash; + const log = createLogger('send'); /* eslint-disable more/no-then */ diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 9eed5aec3b0..87d746fe495 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { compact, isNumber, throttle, debounce } from 'lodash'; +import lodash from 'lodash'; import { v4 as generateGuid } from 'uuid'; import PQueue from 'p-queue'; import { ContentHint } from '@signalapp/libsignal-client'; @@ -205,6 +205,8 @@ import { maybeNotify } from '../messages/maybeNotify.js'; import { missingCaseError } from '../util/missingCaseError.js'; import * as Message from '../types/Message2.js'; +const { compact, isNumber, throttle, debounce } = lodash; + const log = createLogger('conversations'); const { diff --git a/ts/quill/auto-substitute-ascii-emojis/index.tsx b/ts/quill/auto-substitute-ascii-emojis/index.tsx index 784c478de21..0d8205993e8 100644 --- a/ts/quill/auto-substitute-ascii-emojis/index.tsx +++ b/ts/quill/auto-substitute-ascii-emojis/index.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { Delta } from '@signalapp/quill-cjs'; -import Emitter from '@signalapp/quill-cjs/core/emitter'; +import Emitter from '@signalapp/quill-cjs/core/emitter.js'; import type Quill from '@signalapp/quill-cjs'; import { createLogger } from '../../logging/log.js'; diff --git a/ts/quill/block/blot.tsx b/ts/quill/block/blot.tsx index 0d171cc9545..b646ebf8836 100644 --- a/ts/quill/block/blot.tsx +++ b/ts/quill/block/blot.tsx @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import BlockBlot from '@signalapp/quill-cjs/blots/block'; +import BlockBlot from '@signalapp/quill-cjs/blots/block.js'; export class DirectionalBlot extends BlockBlot { static override tagName = 'div'; diff --git a/ts/quill/emoji/blot.tsx b/ts/quill/emoji/blot.tsx index aa6b02cfd8c..481cec96738 100644 --- a/ts/quill/emoji/blot.tsx +++ b/ts/quill/emoji/blot.tsx @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import EmbedBlot from '@signalapp/quill-cjs/blots/embed'; +import EmbedBlot from '@signalapp/quill-cjs/blots/embed.js'; import { strictAssert } from '../../util/assert.js'; import { getEmojiVariantByKey, diff --git a/ts/quill/emoji/completion.tsx b/ts/quill/emoji/completion.tsx index b5d22f1f654..95eb375f804 100644 --- a/ts/quill/emoji/completion.tsx +++ b/ts/quill/emoji/completion.tsx @@ -2,9 +2,9 @@ // SPDX-License-Identifier: AGPL-3.0-only import { Delta } from '@signalapp/quill-cjs'; -import Emitter from '@signalapp/quill-cjs/core/emitter'; +import Emitter from '@signalapp/quill-cjs/core/emitter.js'; import React from 'react'; -import _, { isNumber } from 'lodash'; +import lodash from 'lodash'; import type Quill from '@signalapp/quill-cjs'; import { Popper } from 'react-popper'; import classNames from 'classnames'; @@ -28,6 +28,8 @@ import type { } from '../../components/fun/useFunEmojiSearch.js'; import { type FunEmojiLocalizer } from '../../components/fun/useFunEmojiLocalizer.js'; +const { isNumber, debounce } = lodash; + const log = createLogger('completion'); export type EmojiCompletionOptions = { @@ -103,7 +105,7 @@ export class EmojiCompletion { () => this.onTextChange(true) ); - const debouncedOnTextChange = _.debounce(() => this.onTextChange(), 100); + const debouncedOnTextChange = debounce(() => this.onTextChange(), 100); this.quill.on(Emitter.events.TEXT_CHANGE, (_now, _before, source) => { if (source === 'user') { diff --git a/ts/quill/formatting/menu.tsx b/ts/quill/formatting/menu.tsx index da44300e75e..10078deaf24 100644 --- a/ts/quill/formatting/menu.tsx +++ b/ts/quill/formatting/menu.tsx @@ -5,11 +5,11 @@ import React from 'react'; import classNames from 'classnames'; import { Popper } from 'react-popper'; import { createPortal } from 'react-dom'; -import { isString } from 'lodash'; -import Emitter from '@signalapp/quill-cjs/core/emitter'; +import lodash from 'lodash'; +import Emitter from '@signalapp/quill-cjs/core/emitter.js'; import type Quill from '@signalapp/quill-cjs'; import type { Op } from '@signalapp/quill-cjs'; -import type { Context as KeyboardContext } from '@signalapp/quill-cjs/modules/keyboard'; +import type { Context as KeyboardContext } from '@signalapp/quill-cjs/modules/keyboard.js'; import type { VirtualElement } from '@popperjs/core'; import { createLogger } from '../../logging/log.js'; @@ -17,6 +17,8 @@ import * as Errors from '../../types/errors.js'; import type { LocalizerType } from '../../types/Util.js'; import { handleOutsideClick } from '../../util/handleOutsideClick.js'; +const { isString } = lodash; + const log = createLogger('menu'); const MENU_FADE_OUT_MS = 200; diff --git a/ts/quill/formatting/monospaceBlot.ts b/ts/quill/formatting/monospaceBlot.ts index cac82894dad..78a0f25787b 100644 --- a/ts/quill/formatting/monospaceBlot.ts +++ b/ts/quill/formatting/monospaceBlot.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import InlineBlot from '@signalapp/quill-cjs/blots/inline'; +import InlineBlot from '@signalapp/quill-cjs/blots/inline.js'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type AnyRecord = Record; diff --git a/ts/quill/formatting/spoilerBlot.ts b/ts/quill/formatting/spoilerBlot.ts index 4c9ad3bb85d..9c6931d9289 100644 --- a/ts/quill/formatting/spoilerBlot.ts +++ b/ts/quill/formatting/spoilerBlot.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import InlineBlot from '@signalapp/quill-cjs/blots/inline'; +import InlineBlot from '@signalapp/quill-cjs/blots/inline.js'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type AnyRecord = Record; diff --git a/ts/quill/memberRepository.ts b/ts/quill/memberRepository.ts index 095ea1b3214..98e894122e2 100644 --- a/ts/quill/memberRepository.ts +++ b/ts/quill/memberRepository.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import Fuse from 'fuse.js'; -import { get } from 'lodash'; +import lodash from 'lodash'; import type { ConversationType } from '../state/ducks/conversations.js'; import type { AciString } from '../types/ServiceId.js'; @@ -11,6 +11,8 @@ import { filter, map } from '../util/iterables.js'; import { removeDiacritics } from '../util/removeDiacritics.js'; import { isNotNil } from '../util/isNotNil.js'; +const { get } = lodash; + export type MemberType = Omit & Readonly<{ aci: AciString; diff --git a/ts/quill/mentions/blot.tsx b/ts/quill/mentions/blot.tsx index 342fe461faf..74953111b8f 100644 --- a/ts/quill/mentions/blot.tsx +++ b/ts/quill/mentions/blot.tsx @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React, { StrictMode } from 'react'; -import EmbedBlot from '@signalapp/quill-cjs/blots/embed'; +import EmbedBlot from '@signalapp/quill-cjs/blots/embed.js'; import { createRoot } from 'react-dom/client'; import { Emojify } from '../../components/conversation/Emojify.js'; diff --git a/ts/quill/mentions/completion.tsx b/ts/quill/mentions/completion.tsx index 2493c4534b4..67af88be8a3 100644 --- a/ts/quill/mentions/completion.tsx +++ b/ts/quill/mentions/completion.tsx @@ -4,7 +4,7 @@ import React from 'react'; import _ from 'lodash'; import { Delta } from '@signalapp/quill-cjs'; -import Emitter from '@signalapp/quill-cjs/core/emitter'; +import Emitter from '@signalapp/quill-cjs/core/emitter.js'; import type Quill from '@signalapp/quill-cjs'; import type { RefObject } from 'react'; import { Popper } from 'react-popper'; diff --git a/ts/quill/signal-clipboard/index.ts b/ts/quill/signal-clipboard/index.ts index df959f0adc9..ec95d6d9977 100644 --- a/ts/quill/signal-clipboard/index.ts +++ b/ts/quill/signal-clipboard/index.ts @@ -3,7 +3,7 @@ import type Quill from '@signalapp/quill-cjs'; import { Delta } from '@signalapp/quill-cjs'; -import { deleteRange } from '@signalapp/quill-cjs/modules/keyboard'; +import { deleteRange } from '@signalapp/quill-cjs/modules/keyboard.js'; import { FormattingMenu, QuillFormattingStyle } from '../formatting/menu.js'; import { insertEmojiOps } from '../util.js'; diff --git a/ts/reactions/enqueueReactionForSend.ts b/ts/reactions/enqueueReactionForSend.ts index 8a410beeedc..76893f9fe44 100644 --- a/ts/reactions/enqueueReactionForSend.ts +++ b/ts/reactions/enqueueReactionForSend.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import noop from 'lodash/noop'; +import noop from 'lodash/noop.js'; import { v7 as generateUuid } from 'uuid'; import { DataWriter } from '../sql/Client.js'; diff --git a/ts/reactions/preferredReactionEmoji.ts b/ts/reactions/preferredReactionEmoji.ts index 822d480ebe6..e4a5ae16eff 100644 --- a/ts/reactions/preferredReactionEmoji.ts +++ b/ts/reactions/preferredReactionEmoji.ts @@ -1,13 +1,15 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { times } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import { DEFAULT_PREFERRED_REACTION_EMOJI_SHORT_NAMES } from './constants.js'; import { convertShortName } from '../components/emoji/lib.js'; import { isValidReactionEmoji } from './isValidReactionEmoji.js'; import type { EmojiSkinTone } from '../components/fun/data/emojis.js'; +const { times } = lodash; + const log = createLogger('preferredReactionEmoji'); const MAX_STORED_LENGTH = 20; diff --git a/ts/reactions/util.ts b/ts/reactions/util.ts index fdb11667ea3..89dc8bed9c8 100644 --- a/ts/reactions/util.ts +++ b/ts/reactions/util.ts @@ -1,10 +1,12 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { findLastIndex, has, identity, omit, negate } from 'lodash'; +import lodash from 'lodash'; import type { MessageReactionType } from '../model-types.d.ts'; import { areObjectEntriesEqual } from '../util/areObjectEntriesEqual.js'; +const { findLastIndex, has, identity, omit, negate } = lodash; + const isReactionEqual = ( a: undefined | Readonly, b: undefined | Readonly diff --git a/ts/routineProfileRefresh.ts b/ts/routineProfileRefresh.ts index 611ca2ed734..4319978b3e5 100644 --- a/ts/routineProfileRefresh.ts +++ b/ts/routineProfileRefresh.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNil, sortBy } from 'lodash'; +import lodash from 'lodash'; import PQueue from 'p-queue'; import { createLogger } from './logging/log.js'; @@ -17,6 +17,8 @@ import { drop } from './util/drop.js'; import { MINUTE, HOUR, DAY, WEEK } from './util/durations/index.js'; import { isDirectConversation } from './util/whatTypeOfConversation.js'; +const { isNil, sortBy } = lodash; + const log = createLogger('routineProfileRefresh'); const STORAGE_KEY = 'lastAttemptedToRefreshProfilesAt'; diff --git a/ts/scripts/dd-installer-size.ts b/ts/scripts/dd-installer-size.ts index eef964d1bc2..59d5408c946 100644 --- a/ts/scripts/dd-installer-size.ts +++ b/ts/scripts/dd-installer-size.ts @@ -4,7 +4,7 @@ import { stat } from 'node:fs/promises'; import { join } from 'node:path'; -import { name as NAME, version as VERSION } from '../../package.json'; +import { name as NAME, version as VERSION } from '../util/packageJson.js'; const SUPPORT_CONFIG = new Set([ 'linux', diff --git a/ts/scripts/get-expire-time.ts b/ts/scripts/get-expire-time.ts index 4d38ce4cfc2..d6f6cc8616e 100644 --- a/ts/scripts/get-expire-time.ts +++ b/ts/scripts/get-expire-time.ts @@ -6,7 +6,7 @@ import { execSync } from 'node:child_process'; import { writeFileSync } from 'node:fs'; import { DAY } from '../util/durations/index.js'; -import { version } from '../../package.json'; +import { version } from '../util/packageJson.js'; import { isNotUpdatable } from '../util/version.js'; const unixTimestamp = parseInt( diff --git a/ts/scripts/notarize-universal-dmg.ts b/ts/scripts/notarize-universal-dmg.ts index 00a7be358e7..b96600e404d 100644 --- a/ts/scripts/notarize-universal-dmg.ts +++ b/ts/scripts/notarize-universal-dmg.ts @@ -5,7 +5,7 @@ import type { BuildResult } from 'electron-builder'; import { notarize } from '@electron/notarize'; -import * as packageJson from '../../package.json'; +import { build } from '../util/packageJson.js'; export async function afterAllArtifactBuild({ platformToTargets, @@ -24,7 +24,7 @@ export async function afterAllArtifactBuild({ return; } - const appBundleId = packageJson.build.appId; + const appBundleId = build.appId; if (!appBundleId) { throw new Error( 'appBundleId must be provided in package.json: build.appId' diff --git a/ts/scripts/notarize.ts b/ts/scripts/notarize.ts index 15745a4c923..733522b614c 100644 --- a/ts/scripts/notarize.ts +++ b/ts/scripts/notarize.ts @@ -6,7 +6,7 @@ import type { AfterPackContext } from 'electron-builder'; import { notarize } from '@electron/notarize'; -import * as packageJson from '../../package.json'; +import { build } from '../util/packageJson.js'; export async function afterSign({ appOutDir, @@ -22,7 +22,7 @@ export async function afterSign({ const appPath = path.join(appOutDir, `${productFilename}.app`); - const appBundleId = packageJson.build.appId; + const appBundleId = build.appId; if (!appBundleId) { throw new Error( 'appBundleId must be provided in package.json: build.appId' diff --git a/ts/scripts/sign-macos.ts b/ts/scripts/sign-macos.ts index 0256897ca92..ca166167d5f 100644 --- a/ts/scripts/sign-macos.ts +++ b/ts/scripts/sign-macos.ts @@ -3,7 +3,9 @@ import { execSync } from 'node:child_process'; -import { realpath } from 'fs-extra'; +import fsExtra from 'fs-extra'; + +const { realpath } = fsExtra; // eslint-disable-next-line max-len // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any diff --git a/ts/scripts/sign-windows.ts b/ts/scripts/sign-windows.ts index 96b304defb6..e14b3f72886 100644 --- a/ts/scripts/sign-windows.ts +++ b/ts/scripts/sign-windows.ts @@ -3,10 +3,12 @@ import { execSync } from 'node:child_process'; -import { realpath } from 'fs-extra'; +import fsExtra from 'fs-extra'; import type { CustomWindowsSignTaskConfiguration } from 'electron-builder'; +const { realpath } = fsExtra; + export async function sign( configuration: CustomWindowsSignTaskConfiguration ): Promise { diff --git a/ts/scripts/test-release.ts b/ts/scripts/test-release.ts index 552c338d324..49ebb498e34 100644 --- a/ts/scripts/test-release.ts +++ b/ts/scripts/test-release.ts @@ -6,7 +6,7 @@ import assert from 'node:assert'; import { join } from 'node:path'; import { _electron as electron } from 'playwright'; -import packageJson from '../../package.json'; +import { productName, name } from '../util/packageJson.js'; const ENVIRONMENT = 'production'; const RELEASE_DIR = join(__dirname, '..', '..', 'release'); @@ -16,24 +16,24 @@ let exe: string; if (process.platform === 'darwin') { archive = join( 'mac-arm64', - `${packageJson.productName}.app`, + `${productName}.app`, 'Contents', 'Resources', 'app.asar' ); exe = join( 'mac-arm64', - `${packageJson.productName}.app`, + `${productName}.app`, 'Contents', 'MacOS', - packageJson.productName + productName ); } else if (process.platform === 'win32') { archive = join('win-unpacked', 'resources', 'app.asar'); - exe = join('win-unpacked', `${packageJson.productName}.exe`); + exe = join('win-unpacked', `${productName}.exe`); } else if (process.platform === 'linux') { archive = join('linux-unpacked', 'resources', 'app.asar'); - exe = join('linux-unpacked', packageJson.name); + exe = join('linux-unpacked', name); } else { throw new Error(`Unsupported platform: ${process.platform}`); } @@ -72,7 +72,7 @@ const main = async () => { ); console.log('Checking window title'); - assert.strictEqual(await window.title(), packageJson.productName); + assert.strictEqual(await window.title(), productName); await app.close(); }; diff --git a/ts/services/LinkPreview.ts b/ts/services/LinkPreview.ts index ff8826de590..b87f08eb9cb 100644 --- a/ts/services/LinkPreview.ts +++ b/ts/services/LinkPreview.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { debounce, omit } from 'lodash'; +import lodash from 'lodash'; import { CallLinkRootKey, CallLinkEpoch } from '@signalapp/ringrtc'; import type { LinkPreviewWithHydratedData } from '../types/message/LinkPreviews.js'; @@ -35,6 +35,8 @@ import { calling } from './calling.js'; import { getKeyAndEpochFromCallLink } from '../util/callLinks.js'; import { getRoomIdFromCallLink } from '../util/callLinksRingrtc.js'; +const { debounce, omit } = lodash; + const log = createLogger('LinkPreview'); const LINK_PREVIEW_TIMEOUT = 60 * SECOND; diff --git a/ts/services/MessageCache.ts b/ts/services/MessageCache.ts index dd914af857f..38d228c9696 100644 --- a/ts/services/MessageCache.ts +++ b/ts/services/MessageCache.ts @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { throttle } from 'lodash'; +import lodash from 'lodash'; import { LRUCache } from 'lru-cache'; import { createLogger } from '../logging/log.js'; @@ -18,6 +18,8 @@ import type { MessageAttributesType } from '../model-types.d.ts'; import type { SendStateByConversationId } from '../messages/MessageSendState.js'; import type { StoredJob } from '../jobs/types.js'; +const { throttle } = lodash; + const log = createLogger('MessageCache'); const MAX_THROTTLED_REDUX_UPDATERS = 200; diff --git a/ts/services/backups/credentials.ts b/ts/services/backups/credentials.ts index 2fc52bef7b5..f7ce0227ac0 100644 --- a/ts/services/backups/credentials.ts +++ b/ts/services/backups/credentials.ts @@ -8,9 +8,9 @@ import { BackupAuthCredentialResponse, type BackupLevel, GenericServerPublicParams, -} from '@signalapp/libsignal-client/zkgroup'; -import { type BackupKey } from '@signalapp/libsignal-client/dist/AccountKeys'; -import { throttle } from 'lodash/fp'; +} from '@signalapp/libsignal-client/zkgroup.js'; +import { type BackupKey } from '@signalapp/libsignal-client/dist/AccountKeys.js'; +import lodashFp from 'lodash/fp.js'; import * as Bytes from '../../Bytes.js'; import { createLogger } from '../../logging/log.js'; @@ -50,6 +50,8 @@ import { canAttemptRemoteBackupDownload, } from '../../util/isBackupEnabled.js'; +const { throttle } = lodashFp; + const log = createLogger('Backup.Credentials'); const FETCH_INTERVAL = 3 * DAY; diff --git a/ts/services/backups/crypto.ts b/ts/services/backups/crypto.ts index b05af4a8474..d43472e4358 100644 --- a/ts/services/backups/crypto.ts +++ b/ts/services/backups/crypto.ts @@ -6,8 +6,8 @@ import type { PrivateKey } from '@signalapp/libsignal-client'; import { AccountEntropyPool, BackupKey, -} from '@signalapp/libsignal-client/dist/AccountKeys'; -import { MessageBackupKey } from '@signalapp/libsignal-client/dist/MessageBackup'; +} from '@signalapp/libsignal-client/dist/AccountKeys.js'; +import { MessageBackupKey } from '@signalapp/libsignal-client/dist/MessageBackup.js'; import { strictAssert } from '../../util/assert.js'; import type { AciString } from '../../types/ServiceId.js'; diff --git a/ts/services/backups/export.ts b/ts/services/backups/export.ts index 9be374afce6..bd838f4fce8 100644 --- a/ts/services/backups/export.ts +++ b/ts/services/backups/export.ts @@ -3,12 +3,12 @@ import Long from 'long'; import { Aci, Pni, ServiceId } from '@signalapp/libsignal-client'; -import type { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; +import type { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; import { dirname } from 'node:path'; import pMap from 'p-map'; import pTimeout from 'p-timeout'; import { Readable } from 'node:stream'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { CallLinkRootKey } from '@signalapp/ringrtc'; import { Backups, SignalService } from '../../protobuf/index.js'; @@ -168,6 +168,8 @@ import { getLinkPreviewSetting } from '../../types/LinkPreview.js'; import { getTypingIndicatorSetting } from '../../types/Util.js'; import { KIBIBYTE } from '../../types/AttachmentSize.js'; +const { isNumber } = lodash; + const log = createLogger('export'); // Temporarily limited to preserve the received_at order diff --git a/ts/services/backups/import.ts b/ts/services/backups/import.ts index 77282424f5e..25b9b6aa10e 100644 --- a/ts/services/backups/import.ts +++ b/ts/services/backups/import.ts @@ -5,11 +5,11 @@ import { Aci, Pni, ServiceId } from '@signalapp/libsignal-client'; import { BackupLevel, ReceiptCredentialPresentation, -} from '@signalapp/libsignal-client/zkgroup'; +} from '@signalapp/libsignal-client/zkgroup.js'; import { v7 as generateUuid } from 'uuid'; import pMap from 'p-map'; import { Writable } from 'node:stream'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { CallLinkRootKey } from '@signalapp/ringrtc'; import type Long from 'long'; @@ -157,6 +157,8 @@ import { import { normalizeNotificationProfileId } from '../../types/NotificationProfile-node.js'; import { updateBackupMediaDownloadProgress } from '../../util/updateBackupMediaDownloadProgress.js'; +const { isNumber } = lodash; + const log = createLogger('import'); const MAX_CONCURRENCY = 10; diff --git a/ts/services/backups/index.ts b/ts/services/backups/index.ts index 71858ccd7ce..4d1bc69580d 100644 --- a/ts/services/backups/index.ts +++ b/ts/services/backups/index.ts @@ -6,14 +6,14 @@ import { PassThrough } from 'node:stream'; import type { Readable, Writable } from 'node:stream'; import { createReadStream, createWriteStream } from 'node:fs'; import { mkdir, stat, unlink } from 'node:fs/promises'; -import { ensureFile } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { join } from 'node:path'; import { createGzip, createGunzip } from 'node:zlib'; import { createCipheriv, createHmac, randomBytes } from 'node:crypto'; -import { isEqual, noop } from 'lodash'; -import { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; -import { BackupKey } from '@signalapp/libsignal-client/dist/AccountKeys'; -import { throttle } from 'lodash/fp'; +import lodash from 'lodash'; +import { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; +import { BackupKey } from '@signalapp/libsignal-client/dist/AccountKeys.js'; +import lodashFp from 'lodash/fp.js'; import { ipcRenderer } from 'electron'; import { DataReader, DataWriter } from '../../sql/Client.js'; @@ -86,6 +86,12 @@ import { AttachmentLocalBackupManager } from '../../jobs/AttachmentLocalBackupMa import { decipherWithAesKey } from '../../util/decipherWithAesKey.js'; import { areRemoteBackupsTurnedOn } from '../../util/isBackupEnabled.js'; +const { ensureFile } = fsExtra; + +const { throttle } = lodashFp; + +const { isEqual, noop } = lodash; + const log = createLogger('backupsService'); export { BackupType }; diff --git a/ts/services/backups/util/FileStream.ts b/ts/services/backups/util/FileStream.ts index 99d794e5a51..f642e034b33 100644 --- a/ts/services/backups/util/FileStream.ts +++ b/ts/services/backups/util/FileStream.ts @@ -3,7 +3,7 @@ import { type FileHandle, open } from 'node:fs/promises'; import { Buffer } from 'node:buffer'; -import { InputStream } from '@signalapp/libsignal-client/dist/io'; +import { InputStream } from '@signalapp/libsignal-client/dist/io.js'; export class FileStream extends InputStream { #file: FileHandle | undefined; diff --git a/ts/services/backups/util/MemoryStream.ts b/ts/services/backups/util/MemoryStream.ts index 220412a94ae..260dbe788dd 100644 --- a/ts/services/backups/util/MemoryStream.ts +++ b/ts/services/backups/util/MemoryStream.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { type Buffer } from 'node:buffer'; -import { InputStream } from '@signalapp/libsignal-client/dist/io'; +import { InputStream } from '@signalapp/libsignal-client/dist/io.js'; export class MemoryStream extends InputStream { #offset = 0; diff --git a/ts/services/backups/util/filePointers.ts b/ts/services/backups/util/filePointers.ts index bc9e232ce9b..0bf5fc3cca9 100644 --- a/ts/services/backups/util/filePointers.ts +++ b/ts/services/backups/util/filePointers.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { existsSync } from 'node:fs'; -import { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; +import { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; import { APPLICATION_OCTET_STREAM, diff --git a/ts/services/backups/validator.ts b/ts/services/backups/validator.ts index e3b09b7eaf8..34684820a57 100644 --- a/ts/services/backups/validator.ts +++ b/ts/services/backups/validator.ts @@ -3,14 +3,16 @@ import type { Readable } from 'node:stream'; import { once } from 'node:events'; -import * as libsignal from '@signalapp/libsignal-client/dist/MessageBackup'; -import type { InputStream } from '@signalapp/libsignal-client/dist/io'; -import { Reader } from 'protobufjs'; +import * as libsignal from '@signalapp/libsignal-client/dist/MessageBackup.js'; +import type { InputStream } from '@signalapp/libsignal-client/dist/io.js'; +import protobufjs from 'protobufjs'; import { strictAssert } from '../../util/assert.js'; import { toAciObject } from '../../util/ServiceId.js'; import { missingCaseError } from '../../util/missingCaseError.js'; +const { Reader } = protobufjs; + export enum ValidationType { Export = 'Export', Internal = 'Internal', diff --git a/ts/services/calling.ts b/ts/services/calling.ts index 3e5582c813e..eb9a241cf44 100644 --- a/ts/services/calling.ts +++ b/ts/services/calling.ts @@ -39,16 +39,16 @@ import { GroupCallKind, SpeechEvent, } from '@signalapp/ringrtc'; -import { uniqBy, noop, compact } from 'lodash'; +import lodash from 'lodash'; import Long from 'long'; -import type { CallLinkAuthCredentialPresentation } from '@signalapp/libsignal-client/zkgroup'; +import type { CallLinkAuthCredentialPresentation } from '@signalapp/libsignal-client/zkgroup.js'; import { CallLinkSecretParams, CreateCallLinkCredentialRequestContext, CreateCallLinkCredentialResponse, GenericServerPublicParams, ServerPublicParams, -} from '@signalapp/libsignal-client/zkgroup'; +} from '@signalapp/libsignal-client/zkgroup.js'; import { Aci } from '@signalapp/libsignal-client'; import { CanvasVideoRenderer, @@ -166,6 +166,8 @@ import { getColorForCallLink } from '../util/getColorForCallLink.js'; import OS from '../util/os/osMain.js'; import { sleep } from '../util/sleep.js'; +const { uniqBy, noop, compact } = lodash; + const log = createLogger('calling'); const ringrtcLog = createLogger('@signalapp/ringrtc'); diff --git a/ts/services/contactSync.ts b/ts/services/contactSync.ts index 02cbbfc77e9..9ebd414de32 100644 --- a/ts/services/contactSync.ts +++ b/ts/services/contactSync.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import PQueue from 'p-queue'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { DataWriter } from '../sql/Client.js'; import type { ContactSyncEvent } from '../textsecure/messageReceiverEvents.js'; @@ -27,6 +27,8 @@ import { AttachmentVariant } from '../types/Attachment.js'; import { MediaTier } from '../types/AttachmentDownload.js'; import { waitForOnline } from '../util/waitForOnline.js'; +const { noop } = lodash; + const log = createLogger('contactSync'); // When true - we are running the very first storage and contact sync after diff --git a/ts/services/donations.ts b/ts/services/donations.ts index 535a2f6f574..49170ee2ea5 100644 --- a/ts/services/donations.ts +++ b/ts/services/donations.ts @@ -11,7 +11,7 @@ import { ReceiptCredentialResponse, ReceiptSerial, ServerPublicParams, -} from '@signalapp/libsignal-client/zkgroup'; +} from '@signalapp/libsignal-client/zkgroup.js'; import * as countryCodes from 'country-codes-list'; import * as Bytes from '../Bytes.js'; diff --git a/ts/services/expiringMessagesDeletion.ts b/ts/services/expiringMessagesDeletion.ts index 3c7cec0c64b..41a1a23cad2 100644 --- a/ts/services/expiringMessagesDeletion.ts +++ b/ts/services/expiringMessagesDeletion.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { batch } from 'react-redux'; -import { debounce } from 'lodash'; +import lodash from 'lodash'; import * as Errors from '../types/errors.js'; import { createLogger } from '../logging/log.js'; @@ -14,6 +14,8 @@ import { MessageModel } from '../models/messages.js'; import { cleanupMessages } from '../util/cleanup.js'; import { drop } from '../util/drop.js'; +const { debounce } = lodash; + const log = createLogger('expiringMessagesDeletion'); class ExpiringMessagesDeletionService { diff --git a/ts/services/globalMessageAudio.ts b/ts/services/globalMessageAudio.ts index 201f003686f..041b642d25c 100644 --- a/ts/services/globalMessageAudio.ts +++ b/ts/services/globalMessageAudio.ts @@ -1,9 +1,11 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop } from 'lodash'; +import lodash from 'lodash'; import { isAbortError } from '../util/isAbortError.js'; +const { noop } = lodash; + /** * Wrapper around a global HTMLAudioElement that can update the * source and callbacks without requiring removeEventListener diff --git a/ts/services/groupCredentialFetcher.ts b/ts/services/groupCredentialFetcher.ts index 2f815ba490b..1a76e7df476 100644 --- a/ts/services/groupCredentialFetcher.ts +++ b/ts/services/groupCredentialFetcher.ts @@ -1,12 +1,12 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { first, last, sortBy } from 'lodash'; +import lodash from 'lodash'; import { AuthCredentialWithPniResponse, CallLinkAuthCredentialResponse, GenericServerPublicParams, -} from '@signalapp/libsignal-client/zkgroup'; +} from '@signalapp/libsignal-client/zkgroup.js'; import { getClientZkAuthOperations } from '../util/zkgroup.js'; @@ -21,6 +21,8 @@ import { toPniObject, toAciObject } from '../util/ServiceId.js'; import { createLogger } from '../logging/log.js'; import * as Bytes from '../Bytes.js'; +const { first, last, sortBy } = lodash; + const log = createLogger('groupCredentialFetcher'); export const GROUP_CREDENTIALS_KEY = 'groupCredentials'; diff --git a/ts/services/notificationProfilesService.ts b/ts/services/notificationProfilesService.ts index 353368fea80..c816d06d069 100644 --- a/ts/services/notificationProfilesService.ts +++ b/ts/services/notificationProfilesService.ts @@ -1,7 +1,7 @@ // Copyright 2016 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { debounce, isEqual, isNumber } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; @@ -23,6 +23,8 @@ import { } from '../state/selectors/notificationProfiles.js'; import { safeSetTimeout } from '../util/timeout.js'; +const { debounce, isEqual, isNumber } = lodash; + const log = createLogger('notificationProfilesService'); export class NotificationProfilesService { diff --git a/ts/services/notifications.ts b/ts/services/notifications.ts index 8ac1240c6b9..97a7c213064 100644 --- a/ts/services/notifications.ts +++ b/ts/services/notifications.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import os from 'node:os'; -import { debounce } from 'lodash'; +import lodash from 'lodash'; import EventEmitter from 'node:events'; import { v4 as getGuid } from 'uuid'; @@ -17,6 +17,8 @@ import type { StorageInterface } from '../types/Storage.d.ts'; import type { LocalizerType } from '../types/Util.js'; import { drop } from '../util/drop.js'; +const { debounce } = lodash; + const log = createLogger('notifications'); type NotificationDataType = Readonly<{ diff --git a/ts/services/profiles.ts b/ts/services/profiles.ts index f4ab8a3772c..846bbcadb30 100644 --- a/ts/services/profiles.ts +++ b/ts/services/profiles.ts @@ -4,7 +4,7 @@ import type { ClientZkProfileOperations, ProfileKeyCredentialRequestContext, -} from '@signalapp/libsignal-client/zkgroup'; +} from '@signalapp/libsignal-client/zkgroup.js'; import PQueue from 'p-queue'; import { IdentityChange } from '@signalapp/libsignal-client'; diff --git a/ts/services/releaseNotesFetcher.ts b/ts/services/releaseNotesFetcher.ts index 7ac9fe0072d..a26a6e28fa4 100644 --- a/ts/services/releaseNotesFetcher.ts +++ b/ts/services/releaseNotesFetcher.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import semver from 'semver'; -import { last } from 'lodash'; +import lodash from 'lodash'; import * as durations from '../util/durations/index.js'; import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary.js'; @@ -29,6 +29,8 @@ import { MessageModel } from '../models/messages.js'; import { stringToMIMEType } from '../types/MIME.js'; import { isNotNil } from '../util/isNotNil.js'; +const { last } = lodash; + const log = createLogger('releaseNotesFetcher'); const FETCH_INTERVAL = 3 * durations.DAY; diff --git a/ts/services/storage.ts b/ts/services/storage.ts index dd9b18296aa..30c2b57f8eb 100644 --- a/ts/services/storage.ts +++ b/ts/services/storage.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { debounce, isNumber, chunk } from 'lodash'; +import lodash from 'lodash'; import pMap from 'p-map'; import Long from 'long'; @@ -90,6 +90,8 @@ import { isMockEnvironment } from '../environment.js'; import { validateConversation } from '../util/validateConversation.js'; import type { ChatFolder } from '../types/ChatFolder.js'; +const { debounce, isNumber, chunk } = lodash; + const log = createLogger('storage'); type IManifestRecordIdentifier = Proto.ManifestRecord.IIdentifier; diff --git a/ts/services/storageRecordOps.ts b/ts/services/storageRecordOps.ts index 3343c59776b..25991a89b2b 100644 --- a/ts/services/storageRecordOps.ts +++ b/ts/services/storageRecordOps.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isEqual } from 'lodash'; +import lodash from 'lodash'; import Long from 'long'; import { ServiceId } from '@signalapp/libsignal-client'; @@ -112,6 +112,8 @@ import { import { deriveGroupID, deriveGroupSecretParams } from '../util/zkgroup.js'; import { chatFolderCleanupService } from './expiring/chatFolderCleanupService.js'; +const { isEqual } = lodash; + const log = createLogger('storageRecordOps'); const MY_STORY_BYTES = uuidToBytes(MY_STORY_ID); diff --git a/ts/services/storyLoader.ts b/ts/services/storyLoader.ts index f13571afdf4..af4b9eda15d 100644 --- a/ts/services/storyLoader.ts +++ b/ts/services/storyLoader.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { pick } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyMessageAttributesType } from '../model-types.d.ts'; import type { StoryDataType } from '../state/ducks/stories.js'; import * as durations from '../util/durations/index.js'; @@ -19,6 +19,8 @@ import { dropNull } from '../util/dropNull.js'; import { DurationInSeconds } from '../util/durations/index.js'; import { SIGNAL_ACI } from '../types/SignalConversation.js'; +const { pick } = lodash; + const log = createLogger('storyLoader'); let storyData: GetAllStoriesResultType | undefined; diff --git a/ts/services/tapToViewMessagesDeletionService.ts b/ts/services/tapToViewMessagesDeletionService.ts index bb7e6a9e173..7b70e2b681f 100644 --- a/ts/services/tapToViewMessagesDeletionService.ts +++ b/ts/services/tapToViewMessagesDeletionService.ts @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { debounce } from 'lodash'; +import lodash from 'lodash'; import { DataReader } from '../sql/Client.js'; import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary.js'; import { getMessageQueueTime } from '../util/getMessageQueueTime.js'; @@ -14,6 +14,8 @@ import { drop } from '../util/drop.js'; import { MessageModel } from '../models/messages.js'; import { createLogger } from '../logging/log.js'; +const { debounce } = lodash; + const log = createLogger('tapToViewMessagesDeletionService'); async function eraseTapToViewMessages() { diff --git a/ts/sql/Client.ts b/ts/sql/Client.ts index d3da45d09dc..08dd857cfcf 100644 --- a/ts/sql/Client.ts +++ b/ts/sql/Client.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { ipcRenderer as ipc } from 'electron'; -import { groupBy, isTypedArray, last, map, omit } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; @@ -69,6 +69,8 @@ import { updateBackupMediaDownloadProgress, } from '../util/updateBackupMediaDownloadProgress.js'; +const { groupBy, isTypedArray, last, map, omit } = lodash; + const log = createLogger('Client'); const ERASE_SQL_KEY = 'erase-sql-key'; diff --git a/ts/sql/Server.ts b/ts/sql/Server.ts index 8dccd542682..b38475754e4 100644 --- a/ts/sql/Server.ts +++ b/ts/sql/Server.ts @@ -13,22 +13,7 @@ import type { ReadonlyDeep } from 'type-fest'; import { z } from 'zod'; import type { Dictionary } from 'lodash'; -import { - forEach, - fromPairs, - groupBy, - isBoolean, - isNil, - isNumber, - isString, - last, - map, - mapValues, - noop, - omit, - partition, - pick, -} from 'lodash'; +import lodash from 'lodash'; import { parseBadgeCategory } from '../badges/BadgeCategory.js'; import { @@ -277,6 +262,23 @@ import type { import { sqlLogger } from './sqlLogger.js'; import { permissiveMessageAttachmentSchema } from './server/messageAttachments.js'; +const { + forEach, + fromPairs, + groupBy, + isBoolean, + isNil, + isNumber, + isString, + last, + map, + mapValues, + noop, + omit, + partition, + pick, +} = lodash; + type ConversationRow = Readonly<{ json: string; profileLastFetchedAt: null | number; diff --git a/ts/sql/cleanDataForIpc.ts b/ts/sql/cleanDataForIpc.ts index 0739a59282f..7f65cbc2cfe 100644 --- a/ts/sql/cleanDataForIpc.ts +++ b/ts/sql/cleanDataForIpc.ts @@ -1,11 +1,13 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isPlainObject } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import { isIterable } from '../util/iterables.js'; +const { isPlainObject } = lodash; + const log = createLogger('cleanDataForIpc'); /** diff --git a/ts/sql/hydration.ts b/ts/sql/hydration.ts index 371b92b8891..a396b430fed 100644 --- a/ts/sql/hydration.ts +++ b/ts/sql/hydration.ts @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { groupBy } from 'lodash'; +import lodash from 'lodash'; import type { ReadStatus } from '../messages/MessageReadStatus.js'; import type { SeenStatus } from '../MessageSeenStatus.js'; import type { ServiceIdString } from '../types/ServiceId.js'; @@ -34,6 +34,8 @@ import { strictAssert } from '../util/assert.js'; import type { MessageAttributesType } from '../model-types.js'; import { createLogger } from '../logging/log.js'; +const { groupBy } = lodash; + export const ROOT_MESSAGE_ATTACHMENT_EDIT_HISTORY_INDEX = -1; const log = createLogger('hydrateMessage'); diff --git a/ts/sql/migrations/43-gv2-uuid.ts b/ts/sql/migrations/43-gv2-uuid.ts index cd93ab073a6..1f9be56f5e8 100644 --- a/ts/sql/migrations/43-gv2-uuid.ts +++ b/ts/sql/migrations/43-gv2-uuid.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { LoggerType } from '../../types/Logging.js'; import type { AciString, ServiceIdString } from '../../types/ServiceId.js'; @@ -16,6 +16,8 @@ import { } from '../util.js'; import type { WritableDB } from '../Interface.js'; +const { omit } = lodash; + type MessageType = Readonly<{ id: string; sourceUuid: string; diff --git a/ts/sql/migrations/88-service-ids.ts b/ts/sql/migrations/88-service-ids.ts index 46a273599f9..c737b83fb92 100644 --- a/ts/sql/migrations/88-service-ids.ts +++ b/ts/sql/migrations/88-service-ids.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { Database } from '@signalapp/sqlcipher'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { LoggerType } from '../../types/Logging.js'; import type { @@ -15,6 +15,8 @@ import { normalizeAci } from '../../util/normalizeAci.js'; import type { JSONWithUnknownFields } from '../../types/Util.js'; import { isNotNil } from '../../util/isNotNil.js'; +const { omit } = lodash; + // // Main migration function that does the following: // diff --git a/ts/sql/migrations/89-call-history.ts b/ts/sql/migrations/89-call-history.ts index 2eaee0da174..cbf17e611c1 100644 --- a/ts/sql/migrations/89-call-history.ts +++ b/ts/sql/migrations/89-call-history.ts @@ -4,7 +4,7 @@ import { callIdFromEra } from '@signalapp/ringrtc'; import Long from 'long'; import { v4 as generateUuid } from 'uuid'; -import { isObject } from 'lodash'; +import lodash from 'lodash'; import type { SetOptional } from 'type-fest'; import type { LoggerType } from '../../types/Logging.js'; @@ -29,6 +29,8 @@ import { missingCaseError } from '../../util/missingCaseError.js'; import { isAciString } from '../../util/isAciString.js'; import { safeParseStrict } from '../../util/schemas.js'; +const { isObject } = lodash; + // Legacy type for calls that never had a call id type DirectCallHistoryDetailsType = { callId?: string; diff --git a/ts/sql/migrations/index.ts b/ts/sql/migrations/index.ts index 9872a52927d..b4d44b51f07 100644 --- a/ts/sql/migrations/index.ts +++ b/ts/sql/migrations/index.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { Database } from '@signalapp/sqlcipher'; -import { keyBy } from 'lodash'; +import lodash from 'lodash'; import { v4 as generateUuid } from 'uuid'; import type { LoggerType } from '../../types/Logging.js'; @@ -125,6 +125,8 @@ import updateToSchemaVersion1460 from './1460-attachment-duration.js'; import { DataWriter } from '../Server.js'; +const { keyBy } = lodash; + function updateToSchemaVersion1(db: Database): void { db.exec(` CREATE TABLE messages( diff --git a/ts/sql/util.ts b/ts/sql/util.ts index 910eadfe9e9..6ef9f7b87ec 100644 --- a/ts/sql/util.ts +++ b/ts/sql/util.ts @@ -2,11 +2,13 @@ // SPDX-License-Identifier: AGPL-3.0-only /* eslint-disable max-classes-per-file */ -import { isNumber, last } from 'lodash'; +import lodash from 'lodash'; import type { ReadableDB, WritableDB } from './Interface.js'; import type { LoggerType } from '../types/Logging.js'; +const { isNumber, last } = lodash; + export type JSONRow = Readonly<{ json: string }>; export type JSONRows = Array; diff --git a/ts/state/ducks/badges.ts b/ts/state/ducks/badges.ts index c17a16916b0..b7ac2d685fc 100644 --- a/ts/state/ducks/badges.ts +++ b/ts/state/ducks/badges.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ThunkAction } from 'redux-thunk'; -import { isEqual, mapValues } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { DataWriter } from '../../sql/Client.js'; import type { StateType as RootStateType } from '../reducer.js'; @@ -12,6 +12,8 @@ import { badgeImageFileDownloader } from '../../badges/badgeImageFileDownloader. import { useBoundActions } from '../../hooks/useBoundActions.js'; import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions.js'; +const { isEqual, mapValues } = lodash; + /** * This duck deals with badge data. Some assumptions it makes: * diff --git a/ts/state/ducks/callHistory.ts b/ts/state/ducks/callHistory.ts index 7909b2a5850..a9eb06d03b5 100644 --- a/ts/state/ducks/callHistory.ts +++ b/ts/state/ducks/callHistory.ts @@ -3,7 +3,7 @@ import type { ReadonlyDeep } from 'type-fest'; import type { ThunkAction, ThunkDispatch } from 'redux-thunk'; -import { debounce, omit } from 'lodash'; +import lodash from 'lodash'; import type { StateType as RootStateType } from '../reducer.js'; import { clearCallHistoryDataAndSync, @@ -37,6 +37,8 @@ import { ButtonVariant } from '../../components/Button.js'; import type { ShowErrorModalActionType } from './globalModals.js'; import { SHOW_ERROR_MODAL } from './globalModals.js'; +const { debounce, omit } = lodash; + const log = createLogger('callHistory'); export type CallHistoryState = ReadonlyDeep<{ diff --git a/ts/state/ducks/calling.ts b/ts/state/ducks/calling.ts index 26532522de4..be4a4d658f8 100644 --- a/ts/state/ducks/calling.ts +++ b/ts/state/ducks/calling.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ThunkAction, ThunkDispatch } from 'redux-thunk'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { CallLinkEpoch, @@ -113,6 +113,8 @@ import { storageServiceUploadJob } from '../../services/storage.js'; import { CallLinkFinalizeDeleteManager } from '../../jobs/CallLinkFinalizeDeleteManager.js'; import { callLinkRefreshJobQueue } from '../../jobs/callLinkRefreshJobQueue.js'; +const { omit } = lodash; + const log = createLogger('calling'); // State diff --git a/ts/state/ducks/composer.ts b/ts/state/ducks/composer.ts index b4ca5fedcc4..632c16aa797 100644 --- a/ts/state/ducks/composer.ts +++ b/ts/state/ducks/composer.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import path from 'node:path'; -import { debounce, isEqual } from 'lodash'; +import lodash from 'lodash'; import type { ThunkAction, ThunkDispatch } from 'redux-thunk'; import { v4 as generateUuid } from 'uuid'; import { webUtils } from 'electron'; @@ -96,6 +96,8 @@ import { isVideoTypeSupported, } from '../../util/GoogleChrome.js'; +const { debounce, isEqual } = lodash; + const log = createLogger('composer'); // State diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 9a031bbf17f..be63000f293 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -2,18 +2,8 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ThunkAction } from 'redux-thunk'; -import { - chunk, - difference, - fromPairs, - isEqual, - omit, - orderBy, - pick, - values, - without, -} from 'lodash'; -import type { PhoneNumber } from 'google-libphonenumber'; +import lodash from 'lodash'; +import { type PhoneNumber } from 'google-libphonenumber'; import { clipboard, ipcRenderer } from 'electron'; import type { ReadonlyDeep } from 'type-fest'; @@ -225,6 +215,18 @@ import { cleanupMessages } from '../../util/cleanup.js'; import type { ConversationModel } from '../../models/conversations.js'; import { MessageRequestResponseSource } from '../../types/MessageRequestResponseEvent.js'; +const { + chunk, + difference, + fromPairs, + isEqual, + omit, + orderBy, + pick, + values, + without, +} = lodash; + const log = createLogger('conversations'); // State diff --git a/ts/state/ducks/emojis.ts b/ts/state/ducks/emojis.ts index 6e9fce075e0..a104c1e8020 100644 --- a/ts/state/ducks/emojis.ts +++ b/ts/state/ducks/emojis.ts @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { take, uniq } from 'lodash'; +import lodash from 'lodash'; import type { ThunkAction } from 'redux-thunk'; import type { ReadonlyDeep } from 'type-fest'; import type { EmojiPickDataType } from '../../components/emoji/EmojiPicker.js'; @@ -9,6 +9,8 @@ import { DataWriter } from '../../sql/Client.js'; import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions.js'; import { useBoundActions } from '../../hooks/useBoundActions.js'; +const { take, uniq } = lodash; + const { updateEmojiUsage } = DataWriter; // State diff --git a/ts/state/ducks/gifs.ts b/ts/state/ducks/gifs.ts index ca7de8472df..a6e4bab54a7 100644 --- a/ts/state/ducks/gifs.ts +++ b/ts/state/ducks/gifs.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ReadonlyDeep } from 'type-fest'; import type { ThunkAction } from 'redux-thunk'; -import { take } from 'lodash'; +import lodash from 'lodash'; import type { GifType } from '../../components/fun/panels/FunPanelGifs.js'; import { DataWriter } from '../../sql/Client.js'; import { @@ -10,6 +10,8 @@ import { useBoundActions, } from '../../hooks/useBoundActions.js'; +const { take } = lodash; + const { addRecentGif, removeRecentGif } = DataWriter; export const MAX_RECENT_GIFS = 64; diff --git a/ts/state/ducks/items.ts b/ts/state/ducks/items.ts index aaaeb948145..db46dee32f3 100644 --- a/ts/state/ducks/items.ts +++ b/ts/state/ducks/items.ts @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import { v4 as getGuid } from 'uuid'; import type { ThunkAction } from 'redux-thunk'; import type { ReadonlyDeep } from 'type-fest'; @@ -21,6 +21,8 @@ import { actions as conversationActions } from './conversations.js'; import type { ConfigMapType as RemoteConfigType } from '../../RemoteConfig.js'; import type { EmojiSkinTone } from '../../components/fun/data/emojis.js'; +const { omit } = lodash; + // State export type ItemsStateType = ReadonlyDeep< diff --git a/ts/state/ducks/mediaGallery.ts b/ts/state/ducks/mediaGallery.ts index e8504cc081b..84d6e72b69e 100644 --- a/ts/state/ducks/mediaGallery.ts +++ b/ts/state/ducks/mediaGallery.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { orderBy } from 'lodash'; +import lodash from 'lodash'; import type { ThunkAction } from 'redux-thunk'; import type { ReadonlyDeep } from 'type-fest'; @@ -29,6 +29,8 @@ import type { StateType as RootStateType } from '../reducer.js'; import type { MessageAttributesType, MessageType } from '../../model-types.js'; import { isTapToView, getPropsForAttachment } from '../selectors/message.js'; +const { orderBy } = lodash; + const log = createLogger('mediaGallery'); type MediaItemMessage = ReadonlyDeep<{ diff --git a/ts/state/ducks/preferredReactions.ts b/ts/state/ducks/preferredReactions.ts index 703c93dba28..8b7941cbfea 100644 --- a/ts/state/ducks/preferredReactions.ts +++ b/ts/state/ducks/preferredReactions.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ThunkAction } from 'redux-thunk'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { createLogger } from '../../logging/log.js'; import * as Errors from '../../types/errors.js'; @@ -16,6 +16,8 @@ import { getEmojiSkinToneDefault } from '../selectors/items.js'; import { convertShortName } from '../../components/emoji/lib.js'; import { EmojiSkinTone } from '../../components/fun/data/emojis.js'; +const { omit } = lodash; + const log = createLogger('preferredReactions'); // State diff --git a/ts/state/ducks/safetyNumber.ts b/ts/state/ducks/safetyNumber.ts index d3b3036aa4d..ec96d008aad 100644 --- a/ts/state/ducks/safetyNumber.ts +++ b/ts/state/ducks/safetyNumber.ts @@ -3,7 +3,7 @@ import type { ReadonlyDeep } from 'type-fest'; import type { ThunkAction } from 'redux-thunk'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import { generateSafetyNumber } from '../../util/safetyNumber.js'; import type { SafetyNumberType } from '../../types/safetyNumber.js'; @@ -18,6 +18,8 @@ import type { StateType as RootStateType } from '../reducer.js'; import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions.js'; import { useBoundActions } from '../../hooks/useBoundActions.js'; +const { omit } = lodash; + const log = createLogger('safetyNumber'); export type SafetyNumberContactType = ReadonlyDeep<{ diff --git a/ts/state/ducks/search.ts b/ts/state/ducks/search.ts index bf45b7be6f1..e163530fd59 100644 --- a/ts/state/ducks/search.ts +++ b/ts/state/ducks/search.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ThunkAction, ThunkDispatch } from 'redux-thunk'; -import { debounce, omit, reject } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import type { StateType as RootStateType } from '../reducer.js'; @@ -52,6 +52,8 @@ import { hasUnread, } from '../../util/countUnreadStats.js'; +const { debounce, omit, reject } = lodash; + const log = createLogger('search'); const { searchMessages: dataSearchMessages } = DataReader; diff --git a/ts/state/ducks/stickers.ts b/ts/state/ducks/stickers.ts index 973aae8dcb0..ba16988725e 100644 --- a/ts/state/ducks/stickers.ts +++ b/ts/state/ducks/stickers.ts @@ -1,8 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import type { Dictionary } from 'lodash'; -import { omit, reject } from 'lodash'; +import lodash, { type Dictionary } from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import type { StickerPackStatusType, @@ -29,6 +28,8 @@ import type { NoopActionType } from './noop.js'; import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions.js'; import { useBoundActions } from '../../hooks/useBoundActions.js'; +const { omit, reject } = lodash; + const { getRecentStickers } = DataReader; const { updateStickerLastUsed } = DataWriter; diff --git a/ts/state/ducks/stories.ts b/ts/state/ducks/stories.ts index 9bc7ac48312..4b274970a08 100644 --- a/ts/state/ducks/stories.ts +++ b/ts/state/ducks/stories.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { ThunkAction, ThunkDispatch } from 'redux-thunk'; -import { isEqual, pick } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import * as Errors from '../../types/errors.js'; @@ -84,6 +84,8 @@ import { ReceiptType } from '../../types/Receipt.js'; import { cleanupMessages } from '../../util/cleanup.js'; import { AttachmentDownloadUrgency } from '../../types/AttachmentDownload.js'; +const { isEqual, pick } = lodash; + const log = createLogger('stories'); export type StoryDataType = ReadonlyDeep< diff --git a/ts/state/ducks/storyDistributionLists.ts b/ts/state/ducks/storyDistributionLists.ts index 7aa4d76207e..fbd0dcd2d15 100644 --- a/ts/state/ducks/storyDistributionLists.ts +++ b/ts/state/ducks/storyDistributionLists.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { ThunkAction } from 'redux-thunk'; import type { ReadonlyDeep } from 'type-fest'; @@ -19,6 +19,8 @@ import { storageServiceUploadJob } from '../../services/storage.js'; import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions.js'; import { useBoundActions } from '../../hooks/useBoundActions.js'; +const { omit } = lodash; + const log = createLogger('storyDistributionLists'); // State diff --git a/ts/state/selectors/badges.ts b/ts/state/selectors/badges.ts index 3e2406cdd81..554f0bed751 100644 --- a/ts/state/selectors/badges.ts +++ b/ts/state/selectors/badges.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { createSelector } from 'reselect'; -import { mapValues } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../../logging/log.js'; import type { StateType } from '../reducer.js'; import type { BadgesStateType } from '../ducks/badges.js'; @@ -10,6 +10,8 @@ import type { BadgeType } from '../../badges/types.js'; import { getOwn } from '../../util/getOwn.js'; import type { ConversationType } from '../ducks/conversations.js'; +const { mapValues } = lodash; + const log = createLogger('badges'); const getBadgeState = (state: Readonly): BadgesStateType => diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index 3025a2517f4..f06ee83d3c9 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import memoizee from 'memoizee'; -import { isNumber, pick } from 'lodash'; +import lodash from 'lodash'; import { createSelector } from 'reselect'; import type { StateType } from '../reducer.js'; @@ -69,6 +69,8 @@ import { type UnreadStats, } from '../../util/countUnreadStats.js'; +const { isNumber, pick } = lodash; + const log = createLogger('conversations'); export type ConversationWithStoriesType = ConversationType & { diff --git a/ts/state/selectors/message.ts b/ts/state/selectors/message.ts index c595b036f18..2067d6e77ba 100644 --- a/ts/state/selectors/message.ts +++ b/ts/state/selectors/message.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { groupBy, isEmpty, isNumber, isObject, map } from 'lodash'; +import lodash from 'lodash'; import { createSelector } from 'reselect'; import getDirection from 'direction'; import emojiRegex from 'emoji-regex'; @@ -158,6 +158,8 @@ import { getCallIdFromEra } from '../../util/callDisposition.js'; import { LONG_MESSAGE } from '../../types/MIME.js'; import type { MessageRequestResponseNotificationData } from '../../components/conversation/MessageRequestResponseNotification.js'; +const { groupBy, isEmpty, isNumber, isObject, map } = lodash; + const log = createLogger('message'); export { isIncoming, isOutgoing, isStory }; diff --git a/ts/state/selectors/stickers.ts b/ts/state/selectors/stickers.ts index 479c8fd043d..9ee842b2fb7 100644 --- a/ts/state/selectors/stickers.ts +++ b/ts/state/selectors/stickers.ts @@ -1,8 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import type { Dictionary } from 'lodash'; -import { compact, filter, map, orderBy, reject, sortBy, values } from 'lodash'; +import lodash, { type Dictionary } from 'lodash'; import { createSelector } from 'reselect'; import type { RecentStickerType } from '../../types/Stickers.js'; @@ -21,6 +20,8 @@ import type { StickerType, } from '../ducks/stickers.js'; +const { compact, filter, map, orderBy, reject, sortBy, values } = lodash; + const getSticker = ( packs: Dictionary, packId: string, diff --git a/ts/state/selectors/stories.ts b/ts/state/selectors/stories.ts index e541e7481be..cf0abfe5a69 100644 --- a/ts/state/selectors/stories.ts +++ b/ts/state/selectors/stories.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { createSelector } from 'reselect'; -import { pick } from 'lodash'; +import lodash from 'lodash'; import type { GetConversationByIdType } from './conversations.js'; import type { ConversationType } from '../ducks/conversations.js'; @@ -46,6 +46,8 @@ import { import { BodyRange, hydrateRanges } from '../../types/BodyRange.js'; import { getStoriesEnabled } from './items.js'; +const { pick } = lodash; + const log = createLogger('stories'); export const getStoriesState = (state: StateType): StoriesStateType => diff --git a/ts/state/smart/CallManager.tsx b/ts/state/smart/CallManager.tsx index ac2adaf803e..dbca2911a59 100644 --- a/ts/state/smart/CallManager.tsx +++ b/ts/state/smart/CallManager.tsx @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { memoize } from 'lodash'; +import lodash from 'lodash'; import React, { memo } from 'react'; import { useSelector } from 'react-redux'; import type { @@ -53,6 +53,8 @@ import { useGlobalModalActions } from '../ducks/globalModals.js'; import { isLonelyGroup } from '../ducks/callingHelpers.js'; import { getActiveProfile } from '../selectors/notificationProfiles.js'; +const { memoize } = lodash; + const log = createLogger('CallManager'); function renderDeviceSelection(): JSX.Element { diff --git a/ts/state/smart/ContactSpoofingReviewDialog.tsx b/ts/state/smart/ContactSpoofingReviewDialog.tsx index 1d14609e84e..ba2f0250495 100644 --- a/ts/state/smart/ContactSpoofingReviewDialog.tsx +++ b/ts/state/smart/ContactSpoofingReviewDialog.tsx @@ -3,7 +3,7 @@ import React, { memo, useCallback } from 'react'; import { useSelector } from 'react-redux'; -import { mapValues } from 'lodash'; +import lodash from 'lodash'; import type { StateType } from '../reducer.js'; import { ContactSpoofingReviewDialog } from '../../components/conversation/ContactSpoofingReviewDialog.js'; import { useConversationsActions } from '../ducks/conversations.js'; @@ -25,6 +25,8 @@ import { useGlobalModalActions } from '../ducks/globalModals.js'; import { getPreferredBadgeSelector } from '../selectors/badges.js'; import { getIntl, getTheme } from '../selectors/user.js'; +const { mapValues } = lodash; + export type PropsType = Readonly<{ conversationId: string; onClose: () => void; diff --git a/ts/state/smart/ConversationDetails.tsx b/ts/state/smart/ConversationDetails.tsx index 595c19e6a68..e47a61293c8 100644 --- a/ts/state/smart/ConversationDetails.tsx +++ b/ts/state/smart/ConversationDetails.tsx @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { sortBy } from 'lodash'; +import lodash from 'lodash'; import React, { memo, useCallback, useState, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { ConversationDetails } from '../../components/conversation/conversation-details/ConversationDetails.js'; @@ -44,6 +44,8 @@ import { isSignalConversation } from '../../util/isSignalConversation.js'; import { drop } from '../../util/drop.js'; import { DataReader } from '../../sql/Client.js'; +const { sortBy } = lodash; + export type SmartConversationDetailsProps = { conversationId: string; callHistoryGroup?: CallHistoryGroup | null; diff --git a/ts/state/smart/Timeline.tsx b/ts/state/smart/Timeline.tsx index dec46d2d824..5f1088d9d2c 100644 --- a/ts/state/smart/Timeline.tsx +++ b/ts/state/smart/Timeline.tsx @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isEmpty } from 'lodash'; +import lodash from 'lodash'; import React, { memo, useCallback } from 'react'; import { useSelector } from 'react-redux'; import type { ReadonlyDeep } from 'type-fest'; @@ -48,6 +48,8 @@ import { SmartTypingBubble } from './TypingBubble.js'; import { AttachmentDownloadManager } from '../../jobs/AttachmentDownloadManager.js'; import { isInFullScreenCall as getIsInFullScreenCall } from '../selectors/calling.js'; +const { isEmpty } = lodash; + type ExternalProps = { id: string; }; diff --git a/ts/state/smart/TypingBubble.tsx b/ts/state/smart/TypingBubble.tsx index 0ab9fd35ada..f1724c89fc3 100644 --- a/ts/state/smart/TypingBubble.tsx +++ b/ts/state/smart/TypingBubble.tsx @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { last } from 'lodash'; +import lodash from 'lodash'; import React, { memo } from 'react'; import { useSelector } from 'react-redux'; import { TypingBubble } from '../../components/conversation/TypingBubble.js'; @@ -14,6 +14,8 @@ import { } from '../selectors/conversations.js'; import { getPreferredBadgeSelector } from '../selectors/badges.js'; +const { last } = lodash; + type ExternalProps = { conversationId: string; }; diff --git a/ts/state/smart/Waveform.tsx b/ts/state/smart/Waveform.tsx index 09fd9e6ca5e..13d86e47e22 100644 --- a/ts/state/smart/Waveform.tsx +++ b/ts/state/smart/Waveform.tsx @@ -1,13 +1,15 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop } from 'lodash'; +import lodash from 'lodash'; import React, { memo, useEffect, useState } from 'react'; import { Waveform } from '../../components/conversation/Waveform.js'; import type { ComputePeaksResult } from '../../components/VoiceNotesPlaybackContext.js'; import { VoiceNotesPlaybackContext } from '../../components/VoiceNotesPlaybackContext.js'; import { createLogger } from '../../logging/log.js'; +const { noop } = lodash; + const log = createLogger('Waveform'); const BAR_COUNT = 47; diff --git a/ts/test-electron/Crypto_test.ts b/ts/test-electron/Crypto_test.ts index ab6b872556d..a814bb8a601 100644 --- a/ts/test-electron/Crypto_test.ts +++ b/ts/test-electron/Crypto_test.ts @@ -5,9 +5,9 @@ import { readFileSync, unlinkSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { createCipheriv } from 'node:crypto'; import { PassThrough } from 'node:stream'; -import { emptyDir } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { assert } from 'chai'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import * as Bytes from '../Bytes.js'; @@ -56,6 +56,10 @@ import { createTempDir, deleteTempDir } from '../updater/common.js'; import { uuidToBytes, bytesToUuid } from '../util/uuidToBytes.js'; import { getPath } from '../windows/main/attachments.js'; +const { emptyDir } = fsExtra; + +const { isNumber } = lodash; + const log = createLogger('Crypto_test'); const GHOST_KITTY_HASH = diff --git a/ts/test-electron/SignalProtocolStore_test.ts b/ts/test-electron/SignalProtocolStore_test.ts index 1218a5b7d85..a274ce4875f 100644 --- a/ts/test-electron/SignalProtocolStore_test.ts +++ b/ts/test-electron/SignalProtocolStore_test.ts @@ -4,7 +4,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { assert } from 'chai'; -import { clone } from 'lodash'; +import lodash from 'lodash'; import { Direction, IdentityKeyPair, @@ -35,6 +35,8 @@ import { QualifiedAddress } from '../types/QualifiedAddress.js'; import { generateAci, generatePni } from '../types/ServiceId.js'; import type { IdentityKeyType, KeyPairType } from '../textsecure/Types.d.ts'; +const { clone } = lodash; + const { RecordStructure, SessionStructure, diff --git a/ts/test-electron/background_test.ts b/ts/test-electron/background_test.ts index 73f358ba5d5..53ead4aaaba 100644 --- a/ts/test-electron/background_test.ts +++ b/ts/test-electron/background_test.ts @@ -2,11 +2,13 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { pick } from 'lodash'; +import lodash from 'lodash'; import { isOverHourIntoPast, cleanupSessionResets } from '../background.js'; import { DataWriter } from '../sql/Client.js'; +const { pick } = lodash; + describe('#isOverHourIntoPast', () => { it('returns false for now', () => { assert.isFalse(isOverHourIntoPast(Date.now())); diff --git a/ts/test-electron/backup/attachments_test.ts b/ts/test-electron/backup/attachments_test.ts index 31d6a16ac7f..54d872c5bce 100644 --- a/ts/test-electron/backup/attachments_test.ts +++ b/ts/test-electron/backup/attachments_test.ts @@ -2,8 +2,8 @@ // SPDX-License-Identifier: AGPL-3.0-only import { v4 as generateGuid } from 'uuid'; -import { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; -import { omit } from 'lodash'; +import { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; +import lodash from 'lodash'; import * as sinon from 'sinon'; import { join } from 'node:path'; import { assert } from 'chai'; @@ -43,6 +43,8 @@ import { } from '../../AttachmentCrypto.js'; import { KIBIBYTE } from '../../types/AttachmentSize.js'; +const { omit } = lodash; + const CONTACT_A = generateAci(); const NON_ROUNDTRIPPED_FIELDS = ['path', 'thumbnail', 'screenshot', 'localKey']; diff --git a/ts/test-electron/backup/filePointer_test.ts b/ts/test-electron/backup/filePointer_test.ts index 26358ef1b83..9dd6e9ea3d2 100644 --- a/ts/test-electron/backup/filePointer_test.ts +++ b/ts/test-electron/backup/filePointer_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import Long from 'long'; import * as sinon from 'sinon'; -import { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; +import { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; import { randomBytes } from 'node:crypto'; import { join } from 'node:path'; diff --git a/ts/test-electron/backup/helpers.ts b/ts/test-electron/backup/helpers.ts index 9f0b4740346..8a877a0c26d 100644 --- a/ts/test-electron/backup/helpers.ts +++ b/ts/test-electron/backup/helpers.ts @@ -4,12 +4,12 @@ import { assert } from 'chai'; import path from 'node:path'; import { tmpdir } from 'node:os'; -import { omit, sortBy } from 'lodash'; +import lodash from 'lodash'; import { createReadStream } from 'node:fs'; import { mkdtemp, rm } from 'node:fs/promises'; import * as sinon from 'sinon'; -import { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; -import { AccountEntropyPool } from '@signalapp/libsignal-client/dist/AccountKeys'; +import { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; +import { AccountEntropyPool } from '@signalapp/libsignal-client/dist/AccountKeys.js'; import type { EditHistoryType, @@ -29,6 +29,8 @@ import { getRandomBytes } from '../../Crypto.js'; import * as Bytes from '../../Bytes.js'; import { postSaveUpdates } from '../../util/cleanup.js'; +const { omit, sortBy } = lodash; + export const OUR_ACI = generateAci(); export const OUR_PNI = generatePni(); export const MASTER_KEY = Bytes.toBase64(getRandomBytes(32)); diff --git a/ts/test-electron/backup/integration_test.ts b/ts/test-electron/backup/integration_test.ts index e77902467d6..d2d5eccca49 100644 --- a/ts/test-electron/backup/integration_test.ts +++ b/ts/test-electron/backup/integration_test.ts @@ -5,11 +5,11 @@ import { readdirSync } from 'node:fs'; import { readFile } from 'node:fs/promises'; import { basename, join } from 'node:path'; import { Readable } from 'node:stream'; -import { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; +import { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; import { ComparableBackup, Purpose, -} from '@signalapp/libsignal-client/dist/MessageBackup'; +} from '@signalapp/libsignal-client/dist/MessageBackup.js'; import { assert } from 'chai'; import { clearData } from './helpers.js'; diff --git a/ts/test-electron/cleanupOrphanedAttachments_test.ts b/ts/test-electron/cleanupOrphanedAttachments_test.ts index cbea215eb0c..32fe6e68f32 100644 --- a/ts/test-electron/cleanupOrphanedAttachments_test.ts +++ b/ts/test-electron/cleanupOrphanedAttachments_test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { emptyDir, ensureFile } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { v4 as generateUuid } from 'uuid'; import { readdirSync } from 'node:fs'; import { dirname } from 'node:path'; @@ -18,6 +18,8 @@ import { import { generateAci } from '../types/ServiceId.js'; import { IMAGE_JPEG, LONG_MESSAGE } from '../types/MIME.js'; +const { emptyDir, ensureFile } = fsExtra; + function getAbsolutePath( path: string, type: 'attachment' | 'download' | 'draft' diff --git a/ts/test-electron/quill/mentions/completion_test.tsx b/ts/test-electron/quill/mentions/completion_test.tsx index 5a4cfb7658e..7a45e1ac68e 100644 --- a/ts/test-electron/quill/mentions/completion_test.tsx +++ b/ts/test-electron/quill/mentions/completion_test.tsx @@ -6,7 +6,7 @@ import { Delta } from '@signalapp/quill-cjs'; import type { SinonStub } from 'sinon'; import sinon from 'sinon'; import type Quill from '@signalapp/quill-cjs'; -import type Keyboard from '@signalapp/quill-cjs/modules/keyboard'; +import type Keyboard from '@signalapp/quill-cjs/modules/keyboard.js'; import type { MutableRefObject } from 'react'; import type { MentionCompletionOptions } from '../../../quill/mentions/completion.js'; diff --git a/ts/test-electron/routineProfileRefresh_test.ts b/ts/test-electron/routineProfileRefresh_test.ts index e2a93070433..6ba093ef725 100644 --- a/ts/test-electron/routineProfileRefresh_test.ts +++ b/ts/test-electron/routineProfileRefresh_test.ts @@ -4,7 +4,7 @@ import * as sinon from 'sinon'; import { v4 as generateUuid } from 'uuid'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { ConversationModel } from '../models/conversations.js'; import type { ConversationAttributesType } from '../model-types.d.ts'; import { generateAci } from '../types/ServiceId.js'; @@ -13,6 +13,8 @@ import { DAY, HOUR, MINUTE, MONTH } from '../util/durations/index.js'; import { routineProfileRefresh } from '../routineProfileRefresh.js'; import type { getProfile } from '../util/getProfile.js'; +const { times } = lodash; + describe('routineProfileRefresh', () => { let sinonSandbox: sinon.SinonSandbox; let getProfileFn: sinon.SinonStub< diff --git a/ts/test-electron/services/AttachmentBackupManager_test.ts b/ts/test-electron/services/AttachmentBackupManager_test.ts index d5594a0a034..b3edfc46ed0 100644 --- a/ts/test-electron/services/AttachmentBackupManager_test.ts +++ b/ts/test-electron/services/AttachmentBackupManager_test.ts @@ -5,7 +5,7 @@ import * as sinon from 'sinon'; import { assert } from 'chai'; import { join } from 'node:path'; import { createWriteStream } from 'node:fs'; -import { ensureFile } from 'fs-extra'; +import fsExtra from 'fs-extra'; import * as Bytes from '../../Bytes.js'; import { @@ -27,6 +27,8 @@ import { encryptAttachmentV2, generateKeys } from '../../AttachmentCrypto.js'; import { SECOND } from '../../util/durations/index.js'; import { HTTPError } from '../../textsecure/Errors.js'; +const { ensureFile } = fsExtra; + const TRANSIT_CDN = 2; const TRANSIT_CDN_FOR_NEW_UPLOAD = 42; const BACKUP_CDN = 3; diff --git a/ts/test-electron/services/AttachmentDownloadManager_test.ts b/ts/test-electron/services/AttachmentDownloadManager_test.ts index 8ce54f46b54..d73d17c8158 100644 --- a/ts/test-electron/services/AttachmentDownloadManager_test.ts +++ b/ts/test-electron/services/AttachmentDownloadManager_test.ts @@ -5,7 +5,7 @@ /* eslint-disable @typescript-eslint/no-floating-promises */ import * as sinon from 'sinon'; import { assert } from 'chai'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { StatsFs } from 'node:fs'; import * as MIME from '../../types/MIME.js'; @@ -36,6 +36,8 @@ import { generateAci } from '../../types/ServiceId.js'; import { toBase64, toHex } from '../../Bytes.js'; import { getRandomBytes } from '../../Crypto.js'; +const { omit } = lodash; + function composeJob({ messageId, receivedAt, diff --git a/ts/test-electron/sql/getRecentStaleRingsAndMarkOlderMissed_test.ts b/ts/test-electron/sql/getRecentStaleRingsAndMarkOlderMissed_test.ts index 864fe875725..bd285a349ad 100644 --- a/ts/test-electron/sql/getRecentStaleRingsAndMarkOlderMissed_test.ts +++ b/ts/test-electron/sql/getRecentStaleRingsAndMarkOlderMissed_test.ts @@ -4,7 +4,7 @@ import { assert } from 'chai'; import { v4 as generateUuid } from 'uuid'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { DataReader, DataWriter } from '../../sql/Client.js'; import { @@ -17,6 +17,8 @@ import { generateAci } from '../../types/ServiceId.js'; import type { CallHistoryDetails } from '../../types/CallDisposition.js'; import type { MaybeStaleCallHistory } from '../../sql/Server.js'; +const { times } = lodash; + const { getAllCallHistory } = DataReader; const { getRecentStaleRingsAndMarkOlderMissed, removeAll, saveCallHistory } = DataWriter; diff --git a/ts/test-electron/state/ducks/calling_test.ts b/ts/test-electron/state/ducks/calling_test.ts index f2d8e9463cb..4ef31dc5c4c 100644 --- a/ts/test-electron/state/ducks/calling_test.ts +++ b/ts/test-electron/state/ducks/calling_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { cloneDeep, noop } from 'lodash'; +import lodash from 'lodash'; import type { PeekInfo } from '@signalapp/ringrtc'; import type { StateType as RootStateType, @@ -52,6 +52,8 @@ import { callLinkRefreshJobQueue } from '../../../jobs/callLinkRefreshJobQueue.j import { CALL_LINK_DEFAULT_STATE } from '../../../util/callLinks.js'; import { DataWriter } from '../../../sql/Client.js'; +const { cloneDeep, noop } = lodash; + const ACI_1 = generateAci(); const NOW = new Date('2020-01-23T04:56:00.000'); diff --git a/ts/test-electron/state/ducks/conversations_test.ts b/ts/test-electron/state/ducks/conversations_test.ts index 7bf25e0bc6c..77087c8f985 100644 --- a/ts/test-electron/state/ducks/conversations_test.ts +++ b/ts/test-electron/state/ducks/conversations_test.ts @@ -4,7 +4,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; import { v4 as generateUuid } from 'uuid'; -import { times } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { reducer as rootReducer } from '../../../state/reducer.js'; @@ -70,6 +70,8 @@ import { MY_STORY_ID } from '../../../types/Stories.js'; import type { ReadonlyMessageAttributesType } from '../../../model-types.d.ts'; import { strictAssert } from '../../../util/assert.js'; +const { times } = lodash; + const { clearGroupCreationError, clearInvitedServiceIdsForNewlyCreatedGroup, diff --git a/ts/test-electron/textsecure/AccountManager_test.ts b/ts/test-electron/textsecure/AccountManager_test.ts index f99f9ee6c1f..9310afe6e2b 100644 --- a/ts/test-electron/textsecure/AccountManager_test.ts +++ b/ts/test-electron/textsecure/AccountManager_test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { range } from 'lodash'; +import lodash from 'lodash'; import * as sinon from 'sinon'; import { getRandomBytes } from '../../Crypto.js'; @@ -19,6 +19,8 @@ import { } from '../../types/ServiceId.js'; import { DAY } from '../../util/durations/index.js'; +const { range } = lodash; + /* eslint-disable @typescript-eslint/no-explicit-any */ describe('AccountManager', () => { diff --git a/ts/test-electron/util/downloadAttachment_test.ts b/ts/test-electron/util/downloadAttachment_test.ts index f29916d57ab..2ed8a4e6652 100644 --- a/ts/test-electron/util/downloadAttachment_test.ts +++ b/ts/test-electron/util/downloadAttachment_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { DataWriter } from '../../sql/Client.js'; import { IMAGE_PNG } from '../../types/MIME.js'; @@ -26,6 +26,8 @@ import { toHex, toBase64 } from '../../Bytes.js'; import { generateAttachmentKeys } from '../../AttachmentCrypto.js'; import { getRandomBytes } from '../../Crypto.js'; +const { noop } = lodash; + describe('utils/downloadAttachment', () => { const baseAttachment = { size: 100, diff --git a/ts/test-helpers/createCallParticipant.ts b/ts/test-helpers/createCallParticipant.ts index af803f8b387..2873a877642 100644 --- a/ts/test-helpers/createCallParticipant.ts +++ b/ts/test-helpers/createCallParticipant.ts @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { sample } from 'lodash'; +import lodash from 'lodash'; import { AvatarColors } from '../types/Colors.js'; import type { GroupCallRemoteParticipantType } from '../types/Calling.js'; @@ -9,6 +9,8 @@ import { generateAci } from '../types/ServiceId.js'; import { getDefaultConversationWithServiceId } from './getDefaultConversation.js'; +const { sample } = lodash; + export function createCallParticipant( participantProps: Partial ): GroupCallRemoteParticipantType { diff --git a/ts/test-helpers/generateBackup.ts b/ts/test-helpers/generateBackup.ts index 71a887307aa..d4b4bd7f155 100644 --- a/ts/test-helpers/generateBackup.ts +++ b/ts/test-helpers/generateBackup.ts @@ -9,8 +9,8 @@ import Long from 'long'; import { AccountEntropyPool, BackupKey, -} from '@signalapp/libsignal-client/dist/AccountKeys'; -import { MessageBackupKey } from '@signalapp/libsignal-client/dist/MessageBackup'; +} from '@signalapp/libsignal-client/dist/AccountKeys.js'; +import { MessageBackupKey } from '@signalapp/libsignal-client/dist/MessageBackup.js'; import type { AciString } from '../types/ServiceId.js'; import { generateAci } from '../types/ServiceId.js'; diff --git a/ts/test-helpers/getDefaultConversation.ts b/ts/test-helpers/getDefaultConversation.ts index f4419da1d1f..323c29cc054 100644 --- a/ts/test-helpers/getDefaultConversation.ts +++ b/ts/test-helpers/getDefaultConversation.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import casual from 'casual'; -import { sample } from 'lodash'; +import lodash from 'lodash'; import { v4 as generateUuid } from 'uuid'; import type { ConversationType } from '../state/ducks/conversations.js'; @@ -14,6 +14,8 @@ import { ConversationColors } from '../types/Colors.js'; import { StorySendMode } from '../types/Stories.js'; import { getAvatarPlaceholderGradient } from '../utils/getAvatarPlaceholderGradient.js'; +const { sample } = lodash; + export const getAvatarPath = (): string => sample([ '/fixtures/kitten-1-64-64.jpg', diff --git a/ts/test-helpers/getFakeBadge.ts b/ts/test-helpers/getFakeBadge.ts index 29312c504c9..34548d1c49a 100644 --- a/ts/test-helpers/getFakeBadge.ts +++ b/ts/test-helpers/getFakeBadge.ts @@ -1,12 +1,14 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { times } from 'lodash'; +import lodash from 'lodash'; import type { BadgeType } from '../badges/types.js'; import { BadgeCategory } from '../badges/BadgeCategory.js'; import { BadgeImageTheme } from '../badges/BadgeImageTheme.js'; import { repeat, zipObject } from '../util/iterables.js'; +const { times } = lodash; + export function getFakeBadge({ alternate = false, id = 'test-badge', diff --git a/ts/test-helpers/getRandomColor.ts b/ts/test-helpers/getRandomColor.ts index 47ddaa4b794..1f2b2cc29db 100644 --- a/ts/test-helpers/getRandomColor.ts +++ b/ts/test-helpers/getRandomColor.ts @@ -1,10 +1,12 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { sample } from 'lodash'; +import lodash from 'lodash'; import type { AvatarColorType } from '../types/Colors.js'; import { AvatarColors } from '../types/Colors.js'; +const { sample } = lodash; + export function getRandomColor(): AvatarColorType { return sample(AvatarColors) || AvatarColors[0]; } diff --git a/ts/test-mock/benchmarks/call_history_search_bench.ts b/ts/test-mock/benchmarks/call_history_search_bench.ts index 76c2f0b1149..d90454c3419 100644 --- a/ts/test-mock/benchmarks/call_history_search_bench.ts +++ b/ts/test-mock/benchmarks/call_history_search_bench.ts @@ -5,7 +5,7 @@ import type { PrimaryDevice } from '@signalapp/mock-server'; import { Proto, StorageState } from '@signalapp/mock-server'; import Long from 'long'; -import { sample } from 'lodash'; +import lodash from 'lodash'; import { expect } from 'playwright/test'; import { Bootstrap, debug, RUN_COUNT, DISCARD_COUNT } from './fixtures.js'; import { stats } from '../../util/benchmark/stats.js'; @@ -13,6 +13,8 @@ import { uuidToBytes } from '../../util/uuidToBytes.js'; import { strictAssert } from '../../util/assert.js'; import { typeIntoInput } from '../helpers.js'; +const { sample } = lodash; + const CALL_HISTORY_COUNT = 1000; function rand(values: ReadonlyArray): T { diff --git a/ts/test-mock/benchmarks/startup_bench.ts b/ts/test-mock/benchmarks/startup_bench.ts index 6f67af501d1..6b12eb2ec5a 100644 --- a/ts/test-mock/benchmarks/startup_bench.ts +++ b/ts/test-mock/benchmarks/startup_bench.ts @@ -2,11 +2,13 @@ // SPDX-License-Identifier: AGPL-3.0-only import { ReceiptType } from '@signalapp/mock-server'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import { debug, Bootstrap, MAX_CYCLES } from './fixtures.js'; import { type RegressionSample } from '../bootstrap.js'; +const { omit } = lodash; + const INITIAL_MESSAGE_COUNT = 1000; const FINAL_MESSAGE_COUNT = 5000; diff --git a/ts/test-mock/storage/fixtures.ts b/ts/test-mock/storage/fixtures.ts index 294ad7ffe0a..875ff68b6b6 100644 --- a/ts/test-mock/storage/fixtures.ts +++ b/ts/test-mock/storage/fixtures.ts @@ -11,7 +11,7 @@ import type { import { StorageState, Proto } from '@signalapp/mock-server'; import path from 'node:path'; import fs from 'node:fs/promises'; -import { range } from 'lodash'; +import lodash from 'lodash'; import { CallLinkRootKey } from '@signalapp/ringrtc'; import { App } from '../playwright.js'; import { Bootstrap } from '../bootstrap.js'; @@ -21,6 +21,8 @@ import { uuidToBytes } from '../../util/uuidToBytes.js'; import { artAddStickersRoute } from '../../util/signalRoutes.js'; import { getRoomIdFromRootKey } from '../../util/callLinksRingrtc.js'; +const { range } = lodash; + export const debug = createDebug('mock:test:storage'); export { App, Bootstrap }; diff --git a/ts/test-node/.eslintrc.js b/ts/test-node/.eslintrc.js deleted file mode 100644 index 13565dfeb31..00000000000 --- a/ts/test-node/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2021 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -const { update } = require('lodash/fp'); -const topLevelEslintrc = require('../../.eslintrc'); - -const typescriptRules = topLevelEslintrc.overrides.find(override => - override.files.some(glob => glob.endsWith('.ts')) -).rules; -const noRestrictedImportsRule = - typescriptRules['@typescript-eslint/no-restricted-imports']; - -module.exports = { - rules: { - '@typescript-eslint/no-restricted-imports': update( - [1, 'paths'], - (paths = []) => paths.filter(path => path.name !== 'electron'), - noRestrictedImportsRule - ), - }, -}; diff --git a/ts/test-node/RemoteConfig_test.ts b/ts/test-node/RemoteConfig_test.ts index eb1e04d18de..6789a498acf 100644 --- a/ts/test-node/RemoteConfig_test.ts +++ b/ts/test-node/RemoteConfig_test.ts @@ -4,7 +4,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import { normalizeAci } from '../util/normalizeAci.js'; import type { ConfigKeyType, ConfigListenerType } from '../RemoteConfig.js'; import { @@ -17,6 +17,8 @@ import { } from '../RemoteConfig.js'; import { updateRemoteConfig } from '../test-helpers/RemoteConfigStub.js'; +const { omit } = lodash; + describe('RemoteConfig', () => { const aci = normalizeAci('95b9729c-51ea-4ddb-b516-652befe78062', 'test'); diff --git a/ts/test-node/app/SystemTrayService_test.ts b/ts/test-node/app/SystemTrayService_test.ts index 0d4b1bb880a..0fadbb3e48d 100644 --- a/ts/test-node/app/SystemTrayService_test.ts +++ b/ts/test-node/app/SystemTrayService_test.ts @@ -9,11 +9,7 @@ import { MINUTE } from '../../util/durations/index.js'; import type { SystemTrayServiceOptionsType } from '../../../app/SystemTrayService.js'; import { SystemTrayService } from '../../../app/SystemTrayService.js'; -import { setupI18n } from '../../util/setupI18n.js'; - -import enMessages from '../../../_locales/en/messages.json'; - -const i18n = setupI18n('en', enMessages); +import i18n from '../util/i18n.js'; describe('SystemTrayService', function (this: Mocha.Suite) { // These tests take more time on CI in some cases, so we increase the timeout. diff --git a/ts/test-node/app/base_config_test.ts b/ts/test-node/app/base_config_test.ts index 691150e0349..74b39ac025f 100644 --- a/ts/test-node/app/base_config_test.ts +++ b/ts/test-node/app/base_config_test.ts @@ -4,7 +4,7 @@ import * as path from 'node:path'; import { tmpdir } from 'node:os'; import { chmodSync, rmSync, writeFileSync, mkdtempSync } from 'node:fs'; -import { pathExists, readJsonSync } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { v4 as generateGuid } from 'uuid'; import { assert } from 'chai'; @@ -12,6 +12,8 @@ import { assert } from 'chai'; import type { ConfigType } from '../../../app/base_config.js'; import { start } from '../../../app/base_config.js'; +const { pathExists, readJsonSync } = fsExtra; + describe('base_config', () => { let targetDir: string; let targetPath: string; diff --git a/ts/test-node/badges/parseBadgesFromServer_test.ts b/ts/test-node/badges/parseBadgesFromServer_test.ts index e80305d4cc9..478fabc34c7 100644 --- a/ts/test-node/badges/parseBadgesFromServer_test.ts +++ b/ts/test-node/badges/parseBadgesFromServer_test.ts @@ -2,12 +2,14 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import { BadgeCategory } from '../../badges/BadgeCategory.js'; import { BadgeImageTheme } from '../../badges/BadgeImageTheme.js'; import { parseBadgesFromServer } from '../../badges/parseBadgesFromServer.js'; +const { omit } = lodash; + describe('parseBadgesFromServer', () => { const UPDATES_URL = 'https://updates2.signal.org/desktop'; diff --git a/ts/test-node/challenge_test.ts b/ts/test-node/challenge_test.ts index e42dd043404..6b7840f19aa 100644 --- a/ts/test-node/challenge_test.ts +++ b/ts/test-node/challenge_test.ts @@ -4,13 +4,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { assert } from 'chai'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import * as sinon from 'sinon'; import { STORAGE_KEY, ChallengeHandler } from '../challenge.js'; import type { RegisteredChallengeType } from '../challenge.js'; import { DAY, SECOND } from '../util/durations/index.js'; +const { noop } = lodash; + type CreateHandlerOptions = { readonly autoSolve?: boolean; readonly challengeError?: Error; diff --git a/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts b/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts index 6d36675ad46..018617967b0 100644 --- a/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts +++ b/ts/test-node/components/leftPane/LeftPaneChooseGroupMembersHelper_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { RowType, _testHeaderText, @@ -13,6 +13,8 @@ import { getDefaultConversation } from '../../../test-helpers/getDefaultConversa import { LeftPaneChooseGroupMembersHelper } from '../../../components/leftPane/LeftPaneChooseGroupMembersHelper.js'; +const { times } = lodash; + describe('LeftPaneChooseGroupMembersHelper', () => { const defaults = { uuidFetchState: {}, diff --git a/ts/test-node/components/media-gallery/groupMediaItemsByDate.ts b/ts/test-node/components/media-gallery/groupMediaItemsByDate.ts index 0ebf8f69b89..ad84c8eeb3e 100644 --- a/ts/test-node/components/media-gallery/groupMediaItemsByDate.ts +++ b/ts/test-node/components/media-gallery/groupMediaItemsByDate.ts @@ -2,13 +2,15 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { shuffle } from 'lodash'; +import lodash from 'lodash'; import { IMAGE_JPEG } from '../../../types/MIME.js'; import { groupMediaItemsByDate } from '../../../components/conversation/media-gallery/groupMediaItemsByDate.js'; import type { MediaItemType } from '../../../types/MediaItem.js'; import { fakeAttachment } from '../../../test-helpers/fakeAttachment.js'; +const { shuffle } = lodash; + const testDate = ( year: number, month: number, diff --git a/ts/test-node/conversations/isConversationTooBigToRing_test.ts b/ts/test-node/conversations/isConversationTooBigToRing_test.ts index 7b463a0683c..c5faca731a5 100644 --- a/ts/test-node/conversations/isConversationTooBigToRing_test.ts +++ b/ts/test-node/conversations/isConversationTooBigToRing_test.ts @@ -2,12 +2,14 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { updateRemoteConfig } from '../../test-helpers/RemoteConfigStub.js'; import { generateAci } from '../../types/ServiceId.js'; import { isConversationTooBigToRing } from '../../conversations/isConversationTooBigToRing.js'; +const { times } = lodash; + const CONFIG_KEY = 'global.calling.maxGroupCallRingSize'; describe('isConversationTooBigToRing', () => { diff --git a/ts/test-node/jobs/JobQueueDatabaseStore_test.ts b/ts/test-node/jobs/JobQueueDatabaseStore_test.ts index 3e34241e478..e54a0ce560a 100644 --- a/ts/test-node/jobs/JobQueueDatabaseStore_test.ts +++ b/ts/test-node/jobs/JobQueueDatabaseStore_test.ts @@ -4,11 +4,13 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { StoredJob } from '../../jobs/types.js'; import { JobQueueDatabaseStore } from '../../jobs/JobQueueDatabaseStore.js'; +const { noop } = lodash; + describe('JobQueueDatabaseStore', () => { let fakeDatabase: { getJobsInQueue: sinon.SinonStub; diff --git a/ts/test-node/jobs/JobQueue_test.ts b/ts/test-node/jobs/JobQueue_test.ts index 89533cab4b4..8c524982f65 100644 --- a/ts/test-node/jobs/JobQueue_test.ts +++ b/ts/test-node/jobs/JobQueue_test.ts @@ -7,7 +7,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; import EventEmitter, { once } from 'node:events'; import { z } from 'zod'; -import { noop, groupBy } from 'lodash'; +import lodash from 'lodash'; import { v4 as uuid } from 'uuid'; import PQueue from 'p-queue'; import { JobError } from '../../jobs/JobError.js'; @@ -22,6 +22,8 @@ import type { ParsedJob, StoredJob, JobQueueStore } from '../../jobs/types.js'; import { sleep } from '../../util/sleep.js'; import { parseUnknown } from '../../util/schemas.js'; +const { noop, groupBy } = lodash; + describe('JobQueue', () => { describe('end-to-end tests', () => { it('writes jobs to the database, processes them, and then deletes them', async () => { diff --git a/ts/test-node/jobs/helpers/handleMultipleSendErrors_test.ts b/ts/test-node/jobs/helpers/handleMultipleSendErrors_test.ts index 31438d8f4ba..7fd15466ef2 100644 --- a/ts/test-node/jobs/helpers/handleMultipleSendErrors_test.ts +++ b/ts/test-node/jobs/helpers/handleMultipleSendErrors_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { noop, omit } from 'lodash'; +import lodash from 'lodash'; import { HTTPError, SendMessageProtoError, @@ -15,6 +15,8 @@ import { maybeExpandErrors, } from '../../../jobs/helpers/handleMultipleSendErrors.js'; +const { noop, omit } = lodash; + describe('maybeExpandErrors', () => { // This returns a readonly array, but Chai wants a mutable one. const expand = (input: unknown) => maybeExpandErrors(input) as Array; diff --git a/ts/test-node/messages/MessageSendState_test.ts b/ts/test-node/messages/MessageSendState_test.ts index cf74a9af047..4d4c6e08064 100644 --- a/ts/test-node/messages/MessageSendState_test.ts +++ b/ts/test-node/messages/MessageSendState_test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { sampleSize, times } from 'lodash'; +import lodash from 'lodash'; import { v4 as uuid } from 'uuid'; import type { @@ -26,6 +26,8 @@ import { someSendStatus, } from '../../messages/MessageSendState.js'; +const { sampleSize, times } = lodash; + describe('message send state utilities', () => { describe('maxStatus', () => { const expectedOrder = [ diff --git a/ts/test-node/reactions/util_test.ts b/ts/test-node/reactions/util_test.ts index d8246313fd2..7c87d9fee74 100644 --- a/ts/test-node/reactions/util_test.ts +++ b/ts/test-node/reactions/util_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import { v4 as uuid } from 'uuid'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { MessageReactionType } from '../../model-types.d.ts'; import { isEmpty } from '../../util/iterables.js'; @@ -15,6 +15,8 @@ import { markOutgoingReactionSent, } from '../../reactions/util.js'; +const { omit } = lodash; + describe('reaction utilities', () => { const OUR_CONVO_ID = uuid(); diff --git a/ts/test-node/services/ourProfileKey_test.ts b/ts/test-node/services/ourProfileKey_test.ts index fb99b5199e1..eb1b1738961 100644 --- a/ts/test-node/services/ourProfileKey_test.ts +++ b/ts/test-node/services/ourProfileKey_test.ts @@ -3,12 +3,14 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { sleep } from '../../util/sleep.js'; import { constantTimeEqual } from '../../Crypto.js'; import { OurProfileKeyService } from '../../services/ourProfileKey.js'; +const { noop } = lodash; + describe('"our profile key" service', () => { const createFakeStorage = () => ({ get: sinon.stub(), diff --git a/ts/test-node/sql/cleanDataForIpc_test.ts b/ts/test-node/sql/cleanDataForIpc_test.ts index a618a16c2f7..79e3c59e749 100644 --- a/ts/test-node/sql/cleanDataForIpc_test.ts +++ b/ts/test-node/sql/cleanDataForIpc_test.ts @@ -2,10 +2,12 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { cleanDataForIpc } from '../../sql/cleanDataForIpc.js'; +const { noop } = lodash; + describe('cleanDataForIpc', () => { it('does nothing to JSON primitives', () => { ['', 'foo bar', 0, 123, true, false, null].forEach(value => { diff --git a/ts/test-node/sql/helpers.ts b/ts/test-node/sql/helpers.ts index 64bf36d564a..5db021edfa4 100644 --- a/ts/test-node/sql/helpers.ts +++ b/ts/test-node/sql/helpers.ts @@ -1,7 +1,7 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop } from 'lodash'; +import lodash from 'lodash'; import SQL from '@signalapp/sqlcipher'; import type { ReadableDB, WritableDB } from '../../sql/Interface.js'; @@ -9,6 +9,8 @@ import type { QueryTemplate } from '../../sql/util.js'; import { SCHEMA_VERSIONS } from '../../sql/migrations/index.js'; import { consoleLogger } from '../../util/consoleLogger.js'; +const { noop } = lodash; + export function createDB(): WritableDB { const db = new SQL(':memory:') as WritableDB; db.initTokenizer(); diff --git a/ts/test-node/sql/migration_1040_test.ts b/ts/test-node/sql/migration_1040_test.ts index e0be6ea5e6f..22cb5fceaf9 100644 --- a/ts/test-node/sql/migration_1040_test.ts +++ b/ts/test-node/sql/migration_1040_test.ts @@ -1,6 +1,6 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import { assert } from 'chai'; import type { ReadableDB, WritableDB } from '../../sql/Interface.js'; @@ -13,6 +13,8 @@ import type { import type { AttachmentType } from '../../types/Attachment.js'; import { IMAGE_JPEG } from '../../types/MIME.js'; +const { omit } = lodash; + function getAttachmentDownloadJobs( db: ReadableDB ): Array> { diff --git a/ts/test-node/sql/migration_1100_test.ts b/ts/test-node/sql/migration_1100_test.ts index 00781ff09dd..7d74028435a 100644 --- a/ts/test-node/sql/migration_1100_test.ts +++ b/ts/test-node/sql/migration_1100_test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { findLast } from 'lodash'; +import lodash from 'lodash'; import type { WritableDB } from '../../sql/Interface.js'; import { markAllCallHistoryRead } from '../../sql/Server.js'; import { SeenStatus } from '../../MessageSeenStatus.js'; @@ -15,6 +15,8 @@ import { import { strictAssert } from '../../util/assert.js'; import { createDB, insertData, updateToVersion } from './helpers.js'; +const { findLast } = lodash; + describe('SQL/updateToSchemaVersion1100', () => { let db: WritableDB; beforeEach(() => { diff --git a/ts/test-node/sql/migration_1180_test.ts b/ts/test-node/sql/migration_1180_test.ts index adec264fe9e..6ad88034ddb 100644 --- a/ts/test-node/sql/migration_1180_test.ts +++ b/ts/test-node/sql/migration_1180_test.ts @@ -2,13 +2,15 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { WritableDB } from '../../sql/Interface.js'; import { createDB, updateToVersion, explain } from './helpers.js'; import { jsonToObject, objectToJSON, sql } from '../../sql/util.js'; import { IMAGE_BMP } from '../../types/MIME.js'; import type { _AttachmentDownloadJobTypeV1040 } from '../../sql/migrations/1040-undownloaded-backed-up-media.js'; +const { omit } = lodash; + function insertOldJob( db: WritableDB, job: Omit<_AttachmentDownloadJobTypeV1040, 'source' | 'ciphertextSize'>, diff --git a/ts/test-node/sql/migration_87_test.ts b/ts/test-node/sql/migration_87_test.ts index cabf922be9e..d0f6b2b5eb6 100644 --- a/ts/test-node/sql/migration_87_test.ts +++ b/ts/test-node/sql/migration_87_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import { v4 as generateGuid } from 'uuid'; -import { range } from 'lodash'; +import lodash from 'lodash'; import { createDB, insertData, updateToVersion } from './helpers.js'; import type { @@ -20,6 +20,8 @@ import type { SignedPreKeyType, } from '../../sql/Interface.js'; +const { range } = lodash; + type TestingKyberKey = Omit< KyberPreKeyType, 'data' | 'isLastResort' | 'isConfirmed' | 'createdAt' | 'ourServiceId' diff --git a/ts/test-node/sql/migration_91_test.ts b/ts/test-node/sql/migration_91_test.ts index a4c1302756d..7e4aee2f26e 100644 --- a/ts/test-node/sql/migration_91_test.ts +++ b/ts/test-node/sql/migration_91_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import { v4 as generateGuid } from 'uuid'; -import { range } from 'lodash'; +import lodash from 'lodash'; import { createDB, @@ -16,6 +16,8 @@ import { normalizePni } from '../../types/ServiceId.js'; import { normalizeAci } from '../../util/normalizeAci.js'; import type { WritableDB, PreKeyType } from '../../sql/Interface.js'; +const { range } = lodash; + type TestingPreKey = Omit< PreKeyType, 'privateKey' | 'publicKey' | 'createdAt' diff --git a/ts/test-node/sql/migration_920_test.ts b/ts/test-node/sql/migration_920_test.ts index 32288f40803..794e520e461 100644 --- a/ts/test-node/sql/migration_920_test.ts +++ b/ts/test-node/sql/migration_920_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import { v4 as generateGuid } from 'uuid'; -import { range } from 'lodash'; +import lodash from 'lodash'; import { createDB, insertData, updateToVersion } from './helpers.js'; import type { ServiceIdString } from '../../types/ServiceId.js'; @@ -15,6 +15,8 @@ import type { SignedPreKeyType, } from '../../sql/Interface.js'; +const { range } = lodash; + type TestingKyberKey = Omit< KyberPreKeyType, 'data' | 'isLastResort' | 'isConfirmed' | 'createdAt' diff --git a/ts/test-node/state/ducks/composer_test.ts b/ts/test-node/state/ducks/composer_test.ts index 91bb69b17ad..507f7cc5251 100644 --- a/ts/test-node/state/ducks/composer_test.ts +++ b/ts/test-node/state/ducks/composer_test.ts @@ -3,7 +3,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { v4 as generateUuid } from 'uuid'; import type { ReduxActions } from '../../../state/types.js'; @@ -20,6 +20,8 @@ import { IMAGE_JPEG } from '../../../types/MIME.js'; import type { AttachmentDraftType } from '../../../types/Attachment.js'; import { fakeDraftAttachment } from '../../../test-helpers/fakeAttachment.js'; +const { noop } = lodash; + describe('both/state/ducks/composer', () => { const QUOTED_MESSAGE = { conversationId: '123', diff --git a/ts/test-node/state/selectors/conversations_test.ts b/ts/test-node/state/selectors/conversations_test.ts index 7d5d4e31e5f..b5b5b6ff912 100644 --- a/ts/test-node/state/selectors/conversations_test.ts +++ b/ts/test-node/state/selectors/conversations_test.ts @@ -46,10 +46,9 @@ import { import { noopAction } from '../../../state/ducks/noop.js'; import type { StateType } from '../../../state/reducer.js'; import { reducer as rootReducer } from '../../../state/reducer.js'; -import { setupI18n } from '../../../util/setupI18n.js'; +import i18n from '../../util/i18n.js'; import type { ServiceIdString } from '../../../types/ServiceId.js'; import { generateAci, getAciFromPrefix } from '../../../types/ServiceId.js'; -import enMessages from '../../../../_locales/en/messages.json'; import { getDefaultConversation, getDefaultGroup, @@ -105,8 +104,6 @@ describe('both/state/selectors/conversations-extra', () => { ); } - const i18n = setupI18n('en', enMessages); - describe('#getConversationByIdSelector', () => { const state = { ...getEmptyRootState(), diff --git a/ts/test-node/types/setupI18n_test.ts b/ts/test-node/types/setupI18n_test.ts index 4271aed77ab..abc99680f42 100644 --- a/ts/test-node/types/setupI18n_test.ts +++ b/ts/test-node/types/setupI18n_test.ts @@ -4,7 +4,7 @@ import { assert } from 'chai'; import type { LocalizerType } from '../../types/Util.js'; import { setupI18n } from '../../util/setupI18n.js'; -import * as enMessages from '../../../_locales/en/messages.json'; +import { enMessages } from '../util/i18n.js'; describe('setupI18n', () => { let i18n: LocalizerType; diff --git a/ts/test-node/updater/common_test.ts b/ts/test-node/updater/common_test.ts index bbcd024f5b3..8c4fa7e47c3 100644 --- a/ts/test-node/updater/common_test.ts +++ b/ts/test-node/updater/common_test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { pathExists } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { stat, mkdir } from 'node:fs/promises'; import { join } from 'node:path'; @@ -19,6 +19,8 @@ import { } from '../../updater/common.js'; import { createLogger } from '../../logging/log.js'; +const { pathExists } = fsExtra; + const log = createLogger('common_test'); describe('updater/signatures', () => { diff --git a/ts/test-node/updater/signature_test.ts b/ts/test-node/updater/signature_test.ts index daafaa23665..2ce71bffa91 100644 --- a/ts/test-node/updater/signature_test.ts +++ b/ts/test-node/updater/signature_test.ts @@ -5,7 +5,7 @@ import { existsSync } from 'node:fs'; import { join } from 'node:path'; import { assert } from 'chai'; -import { copy } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { _getFileHash, @@ -19,6 +19,8 @@ import { createTempDir, deleteTempDir } from '../../updater/common.js'; import { keyPair } from '../../updater/curve.js'; import { createLogger } from '../../logging/log.js'; +const { copy } = fsExtra; + const log = createLogger('signature_test'); describe('updater/signatures', () => { diff --git a/ts/test-node/util/AbortableProcess_test.ts b/ts/test-node/util/AbortableProcess_test.ts index a3e465a93b0..6abb894b801 100644 --- a/ts/test-node/util/AbortableProcess_test.ts +++ b/ts/test-node/util/AbortableProcess_test.ts @@ -2,10 +2,12 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { AbortableProcess } from '../../util/AbortableProcess.js'; +const { noop } = lodash; + describe('AbortableProcess', () => { it('resolves the result normally', async () => { const process = new AbortableProcess( diff --git a/ts/test-node/util/callingNotification_test.ts b/ts/test-node/util/callingNotification_test.ts index df1b63a2994..66c2efba9e6 100644 --- a/ts/test-node/util/callingNotification_test.ts +++ b/ts/test-node/util/callingNotification_test.ts @@ -9,8 +9,7 @@ import { CallType, GroupCallStatus, } from '../../types/CallDisposition.js'; -import { setupI18n } from '../../util/setupI18n.js'; -import enMessages from '../../../_locales/en/messages.json'; +import i18n from './i18n.js'; import { getDefaultConversation, getDefaultGroup, @@ -19,8 +18,6 @@ import { getPeerIdFromConversation } from '../../util/callDisposition.js'; import { HOUR } from '../../util/durations/index.js'; describe('calling notification helpers', () => { - const i18n = setupI18n('en', enMessages); - describe('getCallingNotificationText', () => { // Direct call behavior is not tested here. diff --git a/ts/test-node/util/filterAndSortConversations_test.ts b/ts/test-node/util/filterAndSortConversations_test.ts index 165b0f74bcf..71468b56a0e 100644 --- a/ts/test-node/util/filterAndSortConversations_test.ts +++ b/ts/test-node/util/filterAndSortConversations_test.ts @@ -2,11 +2,13 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { pick } from 'lodash'; +import lodash from 'lodash'; import { getDefaultConversation } from '../../test-helpers/getDefaultConversation.js'; import { filterAndSortConversations } from '../../util/filterAndSortConversations.js'; import type { ConversationType } from '../../state/ducks/conversations.js'; +const { pick } = lodash; + type CheckProps = Pick; function check({ diff --git a/ts/test-node/util/getMuteOptions_test.ts b/ts/test-node/util/getMuteOptions_test.ts index 9ca69668fce..715b1e730c8 100644 --- a/ts/test-node/util/getMuteOptions_test.ts +++ b/ts/test-node/util/getMuteOptions_test.ts @@ -3,8 +3,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { setupI18n } from '../../util/setupI18n.js'; -import enMessages from '../../../_locales/en/messages.json'; +import i18n from './i18n.js'; import { getMuteOptions } from '../../util/getMuteOptions.js'; @@ -35,8 +34,6 @@ describe('getMuteOptions', () => { }, ]; - const i18n = setupI18n('en', enMessages); - describe('when not muted', () => { it('returns the 5 default options', () => { assert.deepStrictEqual( diff --git a/ts/test-node/util/getMutedUntilText_test.ts b/ts/test-node/util/getMutedUntilText_test.ts index 4ab0a8838eb..448709e0f86 100644 --- a/ts/test-node/util/getMutedUntilText_test.ts +++ b/ts/test-node/util/getMutedUntilText_test.ts @@ -3,14 +3,11 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; -import { setupI18n } from '../../util/setupI18n.js'; -import enMessages from '../../../_locales/en/messages.json'; +import i18n from './i18n.js'; import { getMutedUntilText } from '../../util/getMutedUntilText.js'; describe('getMutedUntilText', () => { - const i18n = setupI18n('en', enMessages); - let sandbox: sinon.SinonSandbox; beforeEach(() => { diff --git a/ts/test-node/util/getStreamWithTimeout_test.ts b/ts/test-node/util/getStreamWithTimeout_test.ts index b35c7bbfa8a..4178ba2c255 100644 --- a/ts/test-node/util/getStreamWithTimeout_test.ts +++ b/ts/test-node/util/getStreamWithTimeout_test.ts @@ -4,11 +4,13 @@ import { assert } from 'chai'; import { Readable } from 'node:stream'; import * as sinon from 'sinon'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import { once } from 'node:events'; import { getStreamWithTimeout } from '../../util/getStreamWithTimeout.js'; +const { noop } = lodash; + describe('getStreamWithTimeout', () => { let sandbox: sinon.SinonSandbox; let clock: sinon.SinonFakeTimers; diff --git a/ts/test-node/util/i18n.ts b/ts/test-node/util/i18n.ts new file mode 100644 index 00000000000..60447ed7594 --- /dev/null +++ b/ts/test-node/util/i18n.ts @@ -0,0 +1,21 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +import { setupI18n } from '../../util/setupI18n.js'; + +const PATH = join( + __dirname, + '..', + '..', + '..', + '_locales', + 'en', + 'messages.json' +); + +export const enMessages = JSON.parse(readFileSync(PATH, 'utf8')); + +export default setupI18n('en', enMessages); diff --git a/ts/test-node/util/messageFailures.ts b/ts/test-node/util/messageFailures.ts index 285091caf79..2626346a5fc 100644 --- a/ts/test-node/util/messageFailures.ts +++ b/ts/test-node/util/messageFailures.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { mapValues, pick } from 'lodash'; +import lodash from 'lodash'; import type { CustomError } from '../../textsecure/Types.js'; @@ -25,6 +25,8 @@ import { } from '../../services/notifications.js'; import type { MessageModel } from '../../models/messages.js'; +const { mapValues, pick } = lodash; + const log = createLogger('messageFailures'); export async function saveErrorsOnMessage( diff --git a/ts/test-node/util/timelineUtil_test.ts b/ts/test-node/util/timelineUtil_test.ts index f1bc31ac41a..2d8bce01258 100644 --- a/ts/test-node/util/timelineUtil_test.ts +++ b/ts/test-node/util/timelineUtil_test.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; -import { times } from 'lodash'; +import lodash from 'lodash'; import { v4 as uuid } from 'uuid'; import type { LastMessageStatus } from '../../model-types.d.ts'; import { MINUTE, SECOND } from '../../util/durations/index.js'; @@ -15,6 +15,8 @@ import { TimelineMessageLoadingState, } from '../../util/timelineUtil.js'; +const { times } = lodash; + describe(' utilities', () => { describe('areMessagesInSameGroup', () => { const defaultNewer: MaybeMessageTimelineItemType = { diff --git a/ts/test-node/util/timestamp_test.ts b/ts/test-node/util/timestamp_test.ts index f6bde1a3060..98a8972fa45 100644 --- a/ts/test-node/util/timestamp_test.ts +++ b/ts/test-node/util/timestamp_test.ts @@ -5,8 +5,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; import moment from 'moment'; import { HOUR, DAY } from '../../util/durations/index.js'; -import { setupI18n } from '../../util/setupI18n.js'; -import enMessages from '../../../_locales/en/messages.json'; +import i18n from './i18n.js'; import { formatDate, @@ -36,8 +35,6 @@ describe('timestamp', () => { }); } - const i18n = setupI18n('en', enMessages); - describe('formatDate', () => { useFakeTimers(); diff --git a/ts/test-node/util/zkgroup_test.ts b/ts/test-node/util/zkgroup_test.ts index f17a6a36566..a03538cabe7 100644 --- a/ts/test-node/util/zkgroup_test.ts +++ b/ts/test-node/util/zkgroup_test.ts @@ -4,7 +4,7 @@ import { assert } from 'chai'; import * as fs from 'node:fs'; import path from 'node:path'; -import { ServerPublicParams } from '@signalapp/libsignal-client/zkgroup'; +import { ServerPublicParams } from '@signalapp/libsignal-client/zkgroup.js'; describe('zkgroup', () => { describe('serverPublicParams', () => { diff --git a/ts/textsecure/AccountManager.ts b/ts/textsecure/AccountManager.ts index 24499836603..460c0062176 100644 --- a/ts/textsecure/AccountManager.ts +++ b/ts/textsecure/AccountManager.ts @@ -2,12 +2,12 @@ // SPDX-License-Identifier: AGPL-3.0-only import PQueue from 'p-queue'; -import { isNumber, omit, orderBy } from 'lodash'; +import lodash from 'lodash'; import { PublicKey, type KyberPreKeyRecord } from '@signalapp/libsignal-client'; import { AccountEntropyPool, BackupKey, -} from '@signalapp/libsignal-client/dist/AccountKeys'; +} from '@signalapp/libsignal-client/dist/AccountKeys.js'; import { Readable } from 'node:stream'; import EventTarget from './EventTarget.js'; @@ -73,6 +73,8 @@ import { isLinkAndSyncEnabled } from '../util/isLinkAndSyncEnabled.js'; import { getMessageQueueTime } from '../util/getMessageQueueTime.js'; import { canAttemptRemoteBackupDownload } from '../util/isBackupEnabled.js'; +const { isNumber, omit, orderBy } = lodash; + const log = createLogger('AccountManager'); type StorageKeyByServiceIdKind = { diff --git a/ts/textsecure/MessageReceiver.ts b/ts/textsecure/MessageReceiver.ts index 92f06412607..841d180b74f 100644 --- a/ts/textsecure/MessageReceiver.ts +++ b/ts/textsecure/MessageReceiver.ts @@ -3,7 +3,7 @@ /* eslint-disable no-bitwise */ -import { isBoolean, isNumber, isString, noop, omit } from 'lodash'; +import lodash from 'lodash'; import PQueue from 'p-queue'; import { v7 as getGuid } from 'uuid'; @@ -170,6 +170,8 @@ import { MessageRequestResponseSource, } from '../types/MessageRequestResponseEvent.js'; +const { isBoolean, isNumber, isString, noop, omit } = lodash; + const log = createLogger('MessageReceiver'); const GROUPV2_ID_LENGTH = 32; diff --git a/ts/textsecure/OutgoingMessage.ts b/ts/textsecure/OutgoingMessage.ts index 20e8a5ef56c..fd1a70cca20 100644 --- a/ts/textsecure/OutgoingMessage.ts +++ b/ts/textsecure/OutgoingMessage.ts @@ -5,7 +5,7 @@ /* eslint-disable more/no-then */ /* eslint-disable no-param-reassign */ -import { reject } from 'lodash'; +import lodash from 'lodash'; import { z } from 'zod'; import type { @@ -46,6 +46,8 @@ import type { GroupSendToken } from '../types/GroupSendEndorsements.js'; import { isSignalServiceId } from '../util/isSignalConversation.js'; import * as Bytes from '../Bytes.js'; +const { reject } = lodash; + const log = createLogger('OutgoingMessage'); export const enum SenderCertificateMode { diff --git a/ts/textsecure/Types.d.ts b/ts/textsecure/Types.d.ts index 6a36b253dad..528e03d918c 100644 --- a/ts/textsecure/Types.d.ts +++ b/ts/textsecure/Types.d.ts @@ -30,7 +30,7 @@ export { SignedPreKeyIdType, SignedPreKeyType, UnprocessedType, -} from '../sql/Interface.js'; +} from '../sql/Interface.ts'; export type StorageServiceCallOptionsType = { credentials?: StorageServiceCredentials; diff --git a/ts/textsecure/WebAPI.ts b/ts/textsecure/WebAPI.ts index 3cfab630fed..d5d30f27aea 100644 --- a/ts/textsecure/WebAPI.ts +++ b/ts/textsecure/WebAPI.ts @@ -9,7 +9,7 @@ import type { RequestInit, Response } from 'node-fetch'; import fetch from 'node-fetch'; import type { Agent } from 'node:https'; -import { escapeRegExp, isNumber, isString, isObject, throttle } from 'lodash'; +import lodash from 'lodash'; import PQueue from 'p-queue'; import { v4 as getGuid } from 'uuid'; import { z } from 'zod'; @@ -21,7 +21,7 @@ import type { Aci, Pni, } from '@signalapp/libsignal-client'; -import { AccountAttributes } from '@signalapp/libsignal-client/dist/net'; +import { AccountAttributes } from '@signalapp/libsignal-client/dist/net.js'; import { assertDev, strictAssert } from '../util/assert.js'; import * as durations from '../util/durations/index.js'; @@ -101,6 +101,8 @@ import type { StripeDonationAmount, CardDetail } from '../types/Donations.js'; import { badgeFromServerSchema } from '../badges/parseBadgesFromServer.js'; import { ZERO_DECIMAL_CURRENCIES } from '../util/currency.js'; +const { escapeRegExp, isNumber, isString, isObject, throttle } = lodash; + const log = createLogger('WebAPI'); // Note: this will break some code that expects to be able to use err.response when a diff --git a/ts/textsecure/WebSocket.ts b/ts/textsecure/WebSocket.ts index c533621505e..8cce5d5fe34 100644 --- a/ts/textsecure/WebSocket.ts +++ b/ts/textsecure/WebSocket.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { client as WebSocketClient } from 'websocket'; +import ws from 'websocket'; import type { connection as WebSocket } from 'websocket'; import type { IncomingMessage } from 'node:http'; @@ -17,6 +17,8 @@ import * as Timers from '../Timers.js'; import { ConnectTimeoutError, HTTPError } from './Errors.js'; import { handleStatusCode, translateError } from './Utils.js'; +const { client: WebSocketClient } = ws; + const log = createLogger('WebSocket'); const TEN_SECONDS = 10 * durations.SECOND; diff --git a/ts/textsecure/WebsocketResources.ts b/ts/textsecure/WebsocketResources.ts index d18391da783..0d51b7c7966 100644 --- a/ts/textsecure/WebsocketResources.ts +++ b/ts/textsecure/WebsocketResources.ts @@ -40,7 +40,7 @@ import type { ChatServerMessageAck, ChatServiceListener, ConnectionEventsListener, -} from '@signalapp/libsignal-client/dist/net/Chat'; +} from '@signalapp/libsignal-client/dist/net/Chat.js'; import type { EventHandler } from './EventTarget.js'; import EventTarget from './EventTarget.js'; diff --git a/ts/textsecure/cds/CDSSocketBase.ts b/ts/textsecure/cds/CDSSocketBase.ts index 77057f14343..cb7f6a8502e 100644 --- a/ts/textsecure/cds/CDSSocketBase.ts +++ b/ts/textsecure/cds/CDSSocketBase.ts @@ -3,7 +3,7 @@ import { EventEmitter } from 'node:events'; import { Readable } from 'node:stream'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { connection as WebSocket } from 'websocket'; import Long from 'long'; @@ -22,6 +22,8 @@ import type { } from './Types.d.ts'; import { RateLimitedError } from './RateLimitedError.js'; +const { noop } = lodash; + export type CDSSocketBaseOptionsType = Readonly<{ logger: LoggerType; socket: WebSocket; diff --git a/ts/textsecure/downloadAttachment.ts b/ts/textsecure/downloadAttachment.ts index b35cc001a74..64389d392a0 100644 --- a/ts/textsecure/downloadAttachment.ts +++ b/ts/textsecure/downloadAttachment.ts @@ -3,11 +3,11 @@ import { createWriteStream } from 'node:fs'; import { stat } from 'node:fs/promises'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import type { Readable, Writable } from 'node:stream'; import { Transform } from 'node:stream'; import { pipeline } from 'node:stream/promises'; -import { ensureFile } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { createLogger } from '../logging/log.js'; import * as Errors from '../types/errors.js'; @@ -53,6 +53,10 @@ import { getValue } from '../RemoteConfig.js'; import { parseIntOrThrow } from '../util/parseIntOrThrow.js'; import { HTTPError } from './Errors.js'; +const { ensureFile } = fsExtra; + +const { isNumber } = lodash; + const log = createLogger('downloadAttachment'); export function getCdnKey(attachment: ProcessedAttachment): string { diff --git a/ts/textsecure/processDataMessage.ts b/ts/textsecure/processDataMessage.ts index 3087fceb09c..7fc6ee1410f 100644 --- a/ts/textsecure/processDataMessage.ts +++ b/ts/textsecure/processDataMessage.ts @@ -2,8 +2,8 @@ // SPDX-License-Identifier: AGPL-3.0-only import Long from 'long'; -import { ReceiptCredentialPresentation } from '@signalapp/libsignal-client/zkgroup'; -import { isNumber } from 'lodash'; +import { ReceiptCredentialPresentation } from '@signalapp/libsignal-client/zkgroup.js'; +import lodash from 'lodash'; import { assertDev, strictAssert } from '../util/assert.js'; import { dropNull, shallowDropNull } from '../util/dropNull.js'; @@ -40,6 +40,8 @@ import { createName } from '../util/attachmentPath.js'; import { partitionBodyAndNormalAttachments } from '../types/Attachment.js'; import { isNotNil } from '../util/isNotNil.js'; +const { isNumber } = lodash; + const FLAGS = Proto.DataMessage.Flags; export const ATTACHMENT_MAX = 32; diff --git a/ts/textsecure/storage/Blocked.ts b/ts/textsecure/storage/Blocked.ts index 677b087626e..49c3a37fd31 100644 --- a/ts/textsecure/storage/Blocked.ts +++ b/ts/textsecure/storage/Blocked.ts @@ -1,7 +1,7 @@ // Copyright 2016 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { without } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../../logging/log.js'; import * as Bytes from '../../Bytes.js'; @@ -9,6 +9,8 @@ import { isAciString } from '../../util/isAciString.js'; import type { StorageInterface } from '../../types/Storage.d.ts'; import type { AciString, ServiceIdString } from '../../types/ServiceId.js'; +const { without } = lodash; + const log = createLogger('Blocked'); export const BLOCKED_NUMBERS_ID = 'blocked'; diff --git a/ts/types/Attachment.ts b/ts/types/Attachment.ts index 4add74bcce3..780319f730f 100644 --- a/ts/types/Attachment.ts +++ b/ts/types/Attachment.ts @@ -3,15 +3,7 @@ /* eslint-disable max-classes-per-file */ import moment from 'moment'; -import { - isNumber, - padStart, - isFunction, - isUndefined, - isString, - omit, - partition, -} from 'lodash'; +import lodash from 'lodash'; import { blobToArrayBuffer } from 'blob-util'; import type { LinkPreviewForUIType } from './message/LinkPreviews.js'; @@ -46,6 +38,16 @@ import { import { missingCaseError } from '../util/missingCaseError.js'; import type { MakeVideoScreenshotResultType } from './VisualAttachment.js'; +const { + isNumber, + padStart, + isFunction, + isUndefined, + isString, + omit, + partition, +} = lodash; + const logging = createLogger('Attachment'); const MAX_TIMELINE_IMAGE_WIDTH = 300; diff --git a/ts/types/BodyRange.ts b/ts/types/BodyRange.ts index 37d6ad16d68..010ffcb8527 100644 --- a/ts/types/BodyRange.ts +++ b/ts/types/BodyRange.ts @@ -3,7 +3,7 @@ /* eslint-disable @typescript-eslint/no-namespace */ -import { isEqual, isNumber, omit, orderBy, partition } from 'lodash'; +import lodash from 'lodash'; import { SignalService as Proto } from '../protobuf/index.js'; import { createLogger } from '../logging/log.js'; @@ -19,6 +19,8 @@ import { assertDev } from '../util/assert.js'; import type { AciString } from './ServiceId.js'; import { normalizeAci } from '../util/normalizeAci.js'; +const { isEqual, isNumber, omit, orderBy, partition } = lodash; + const log = createLogger('BodyRange'); // Cold storage of body ranges diff --git a/ts/types/EmbeddedContact.ts b/ts/types/EmbeddedContact.ts index 4d5abb76050..76d44e351f7 100644 --- a/ts/types/EmbeddedContact.ts +++ b/ts/types/EmbeddedContact.ts @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { SignalService as Proto } from '../protobuf/index.js'; @@ -25,6 +25,8 @@ import type { ServiceIdString } from './ServiceId.js'; import type { migrateDataToFileSystem } from '../util/attachments/migrateDataToFilesystem.js'; import { getLocalAttachmentUrl } from '../util/getLocalAttachmentUrl.js'; +const { omit } = lodash; + type GenericEmbeddedContactType = { name?: Name; number?: ReadonlyArray; diff --git a/ts/types/ForwardDraft.ts b/ts/types/ForwardDraft.ts index 7345c241dde..1bd6d3d46a8 100644 --- a/ts/types/ForwardDraft.ts +++ b/ts/types/ForwardDraft.ts @@ -1,7 +1,7 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { orderBy } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyMessageAttributesType } from '../model-types.js'; import { isVoiceMessage, @@ -11,6 +11,8 @@ import { import type { HydratedBodyRangesType } from './BodyRange.js'; import type { LinkPreviewForUIType } from './message/LinkPreviews.js'; +const { orderBy } = lodash; + export type MessageForwardDraft = Readonly<{ attachments?: ReadonlyArray; bodyRanges?: HydratedBodyRangesType; diff --git a/ts/types/LinkPreview.ts b/ts/types/LinkPreview.ts index fa44a48254e..4c3b199e639 100644 --- a/ts/types/LinkPreview.ts +++ b/ts/types/LinkPreview.ts @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber, compact, isEmpty, range } from 'lodash'; +import lodash from 'lodash'; // This file gets imported into renderer that does not have access to Node.js // builtins, use an `npm` package. // eslint-disable-next-line import/enforce-node-protocol-usage @@ -20,6 +20,8 @@ import { import type { Backups } from '../protobuf/index.js'; import type { LinkPreviewType } from './message/LinkPreviews.js'; +const { isNumber, compact, isEmpty, range } = lodash; + export type LinkPreviewImage = AttachmentWithHydratedData; export type LinkPreviewResult = { diff --git a/ts/types/Message2.ts b/ts/types/Message2.ts index 0d0b13565a9..fed9b53f92b 100644 --- a/ts/types/Message2.ts +++ b/ts/types/Message2.ts @@ -1,7 +1,7 @@ // Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isFunction, isObject, identity } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import * as Contact from './EmbeddedContact.js'; @@ -49,6 +49,8 @@ import { deepClone } from '../util/deepClone.js'; import * as Bytes from '../Bytes.js'; import { isBodyTooLong } from '../util/longAttachment.js'; +const { isFunction, isObject, identity } = lodash; + export const GROUP = 'group'; export const PRIVATE = 'private'; diff --git a/ts/types/NotificationProfile.ts b/ts/types/NotificationProfile.ts index a1cce43cd24..318402499d2 100644 --- a/ts/types/NotificationProfile.ts +++ b/ts/types/NotificationProfile.ts @@ -1,13 +1,15 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber, orderBy } from 'lodash'; +import lodash from 'lodash'; import { DAY, HOUR, MINUTE } from '../util/durations/index.js'; import { strictAssert } from '../util/assert.js'; import type { StorageServiceFieldsType } from '../sql/Interface.js'; +const { isNumber, orderBy } = lodash; + // Note: this must match the Backup and Storage Service protos for NotificationProfile // This variable is separate so we aren't forced to add it to ScheduleDays object below export const DayOfWeekUnknown = 0; diff --git a/ts/types/SchemaVersion.ts b/ts/types/SchemaVersion.ts index ca2437e8008..3ebff0983c5 100644 --- a/ts/types/SchemaVersion.ts +++ b/ts/types/SchemaVersion.ts @@ -1,7 +1,9 @@ // Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; + +const { isNumber } = lodash; export const isValid = (value: unknown): value is number => { return Boolean(isNumber(value) && value >= 0); diff --git a/ts/types/Stickers.ts b/ts/types/Stickers.ts index 35389a86a70..b711db67a1e 100644 --- a/ts/types/Stickers.ts +++ b/ts/types/Stickers.ts @@ -1,7 +1,7 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber, reject, groupBy, values, chunk } from 'lodash'; +import lodash from 'lodash'; import pMap from 'p-map'; import Queue from 'p-queue'; @@ -36,6 +36,8 @@ import { encryptLegacyAttachment } from '../util/encryptLegacyAttachment.js'; import { AttachmentDisposition } from '../util/getLocalAttachmentUrl.js'; import { getPlaintextHashForInMemoryAttachment } from '../AttachmentCrypto.js'; +const { isNumber, reject, groupBy, values, chunk } = lodash; + const log = createLogger('Stickers'); export type ActionSourceType = diff --git a/ts/types/backups.ts b/ts/types/backups.ts index 95c7633a0df..e3c522efb2a 100644 --- a/ts/types/backups.ts +++ b/ts/types/backups.ts @@ -1,8 +1,8 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import type { BackupLevel } from '@signalapp/libsignal-client/zkgroup'; -import { BackupCredentialType } from '@signalapp/libsignal-client/dist/zkgroup'; +import type { BackupLevel } from '@signalapp/libsignal-client/dist/zkgroup/index.js'; +import { BackupCredentialType } from '@signalapp/libsignal-client/dist/zkgroup/index.js'; import type { GetBackupCDNCredentialsResponseType } from '../textsecure/WebAPI.js'; export { BackupCredentialType }; diff --git a/ts/updater/common.ts b/ts/updater/common.ts index a36d4591e0f..3c29e1d1f6d 100644 --- a/ts/updater/common.ts +++ b/ts/updater/common.ts @@ -3,9 +3,9 @@ /* eslint-disable no-console */ import { createWriteStream } from 'node:fs'; -import { pathExists } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { mkdir, readdir, stat, writeFile } from 'node:fs/promises'; -import { throttle } from 'lodash'; +import lodash from 'lodash'; import { release as osRelease, tmpdir } from 'node:os'; import { extname, join, normalize } from 'node:path'; @@ -36,7 +36,7 @@ import { } from '../util/version.js'; import { isPathInside } from '../util/isPathInside.js'; -import * as packageJson from '../../package.json'; +import { version as packageVersion } from '../util/packageJson.js'; import { getSignatureFileName, @@ -61,6 +61,10 @@ import type { LoggerType } from '../types/Logging.js'; import type { PrepareDownloadResultType as DifferentialDownloadDataType } from './differential.js'; import type { MainSQL } from '../sql/main.js'; +const { pathExists } = fsExtra; + +const { throttle } = lodash; + const POLL_INTERVAL = 30 * durations.MINUTE; type JSONVendorSchema = { @@ -543,7 +547,7 @@ export abstract class Updater { async #checkForUpdates( checkType: CheckType ): Promise { - if (isNotUpdatable(packageJson.version)) { + if (isNotUpdatable(packageVersion)) { this.logger.info( 'checkForUpdates: not checking for updates, this is not an updatable build' ); @@ -589,7 +593,7 @@ export abstract class Updater { if (checkType === CheckType.Normal && !isVersionNewer(version)) { this.logger.info( - `checkForUpdates: ${version} is not newer than ${packageJson.version}; ` + + `checkForUpdates: ${version} is not newer than ${packageVersion}; ` + 'no new update available' ); @@ -987,30 +991,27 @@ export function getUpdatesFileName(): string { } function getChannel(): string { - const { version } = packageJson; - if (isNotUpdatable(version)) { + if (isNotUpdatable(packageVersion)) { // we don't want ad hoc versions to update - return version; + return packageVersion; } - if (isStaging(version)) { + if (isStaging(packageVersion)) { return 'staging'; } - if (isAlpha(version)) { + if (isAlpha(packageVersion)) { return 'alpha'; } - if (isAxolotl(version)) { + if (isAxolotl(packageVersion)) { return 'axolotl'; } - if (isBeta(version)) { + if (isBeta(packageVersion)) { return 'beta'; } return 'latest'; } function isVersionNewer(newVersion: string): boolean { - const { version } = packageJson; - - return gt(newVersion, version); + return gt(newVersion, packageVersion); } export function getVersion(info: JSONUpdateSchema): string | null { diff --git a/ts/updater/differential.ts b/ts/updater/differential.ts index 0636ef7c537..d4ecc913ba5 100644 --- a/ts/updater/differential.ts +++ b/ts/updater/differential.ts @@ -8,7 +8,7 @@ import { pipeline } from 'node:stream/promises'; import { promisify } from 'node:util'; import { gunzip as nativeGunzip } from 'node:zlib'; import got from 'got'; -import { chunk as lodashChunk, noop } from 'lodash'; +import lodash from 'lodash'; import pMap from 'p-map'; import Dicer from '@indutny/dicer'; @@ -19,6 +19,8 @@ import { getGotOptions } from './got.js'; import type { GotOptions } from './got.js'; import { checkIntegrity } from './util.js'; +const { chunk: lodashChunk, noop } = lodash; + const gunzip = promisify(nativeGunzip); const SUPPORTED_VERSION = '2'; diff --git a/ts/updater/generateSignature.ts b/ts/updater/generateSignature.ts index b64c457ceae..e0241f9e813 100644 --- a/ts/updater/generateSignature.ts +++ b/ts/updater/generateSignature.ts @@ -10,7 +10,7 @@ import pify from 'pify'; import * as Errors from '../types/errors.js'; import { getCliOptions } from './common.js'; import { writeSignature } from './signature.js'; -import * as packageJson from '../../package.json'; +import { version as packageVersion } from '../util/packageJson.js'; const readdir = pify(readdirCallback); @@ -34,8 +34,8 @@ const OPTIONS = [ { names: ['version', 'v'], type: 'string', - help: `Version number of this package (default: ${packageJson.version})`, - default: packageJson.version, + help: `Version number of this package (default: ${packageVersion})`, + default: packageVersion, }, ]; diff --git a/ts/updater/got.ts b/ts/updater/got.ts index 31b3571d8ea..1ec07de5922 100644 --- a/ts/updater/got.ts +++ b/ts/updater/got.ts @@ -5,7 +5,7 @@ import type { StrictOptions as GotOptions } from 'got'; import config from 'config'; import { Agent as HTTPAgent } from 'node:http'; -import * as packageJson from '../../package.json'; +import { version } from '../util/packageJson.js'; import { getUserAgent } from '../util/getUserAgent.js'; import * as durations from '../util/durations/index.js'; import { createHTTPSAgent } from '../util/createHTTPSAgent.js'; @@ -46,7 +46,7 @@ export async function getGotOptions(): Promise { }, headers: { 'Cache-Control': 'no-cache', - 'User-Agent': getUserAgent(packageJson.version), + 'User-Agent': getUserAgent(version), }, timeout: { connect: GOT_CONNECT_TIMEOUT, diff --git a/ts/util/AsyncQueue.ts b/ts/util/AsyncQueue.ts index 5a525c47f9a..e489ce735c3 100644 --- a/ts/util/AsyncQueue.ts +++ b/ts/util/AsyncQueue.ts @@ -1,7 +1,9 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { once, noop } from 'lodash'; +import lodash from 'lodash'; + +const { once, noop } = lodash; /** * You can do two things with an async queue: diff --git a/ts/util/assignWithNoUnnecessaryAllocation.ts b/ts/util/assignWithNoUnnecessaryAllocation.ts index 9e6337dc834..57631e5bcf1 100644 --- a/ts/util/assignWithNoUnnecessaryAllocation.ts +++ b/ts/util/assignWithNoUnnecessaryAllocation.ts @@ -1,7 +1,9 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { has } from 'lodash'; +import lodash from 'lodash'; + +const { has } = lodash; /** * This function is like `Object.assign` but won't create a new object if we don't need diff --git a/ts/util/attachmentPath.ts b/ts/util/attachmentPath.ts index c3d4a97af2c..708a681c574 100644 --- a/ts/util/attachmentPath.ts +++ b/ts/util/attachmentPath.ts @@ -2,11 +2,13 @@ // SPDX-License-Identifier: AGPL-3.0-only import { join } from 'node:path'; -import { isString } from 'lodash'; +import lodash from 'lodash'; import { getRandomBytes } from '../Crypto.js'; import * as Bytes from '../Bytes.js'; +const { isString } = lodash; + export const getRelativePath = (name: string): string => { if (!isString(name)) { throw new TypeError("'name' must be a string"); diff --git a/ts/util/attachments/markAttachmentAsPermanentlyErrored.ts b/ts/util/attachments/markAttachmentAsPermanentlyErrored.ts index 1c812bb8ead..76dac613f06 100644 --- a/ts/util/attachments/markAttachmentAsPermanentlyErrored.ts +++ b/ts/util/attachments/markAttachmentAsPermanentlyErrored.ts @@ -1,10 +1,12 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import { type AttachmentType } from '../../types/Attachment.js'; +const { omit } = lodash; + export function markAttachmentAsPermanentlyErrored( attachment: AttachmentType, { backfillError }: { backfillError: boolean } diff --git a/ts/util/attachments/migrateDataToFilesystem.ts b/ts/util/attachments/migrateDataToFilesystem.ts index bcae78c1c38..b9b8122850a 100644 --- a/ts/util/attachments/migrateDataToFilesystem.ts +++ b/ts/util/attachments/migrateDataToFilesystem.ts @@ -1,13 +1,15 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isFunction, isTypedArray, isUndefined, omit } from 'lodash'; +import lodash from 'lodash'; import type { AttachmentType, LocalAttachmentV2Type, } from '../../types/Attachment.js'; import type { LoggerType } from '../../types/Logging.js'; +const { isFunction, isTypedArray, isUndefined, omit } = lodash; + export async function migrateDataToFileSystem( attachment: AttachmentType, { diff --git a/ts/util/callDisposition.ts b/ts/util/callDisposition.ts index 4514e1c5043..562ece78ffe 100644 --- a/ts/util/callDisposition.ts +++ b/ts/util/callDisposition.ts @@ -12,7 +12,7 @@ import { RingUpdate, } from '@signalapp/ringrtc'; import { ContentHint } from '@signalapp/libsignal-client'; -import { isEqual } from 'lodash'; +import lodash from 'lodash'; import { strictAssert } from './assert.js'; import { DataReader, DataWriter } from '../sql/Client.js'; import { SignalService as Proto } from '../protobuf/index.js'; @@ -72,6 +72,8 @@ import { calling } from '../services/calling.js'; import { cleanupMessages } from './cleanup.js'; import { MessageModel } from '../models/messages.js'; +const { isEqual } = lodash; + const log = createLogger('callDisposition'); // utils diff --git a/ts/util/checkFirstEnvelope.ts b/ts/util/checkFirstEnvelope.ts index 72daaa9b546..025e669cb7a 100644 --- a/ts/util/checkFirstEnvelope.ts +++ b/ts/util/checkFirstEnvelope.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import { SignalService as Proto } from '../protobuf/index.js'; @@ -12,6 +12,8 @@ import { isProduction } from './version.js'; import type { IncomingWebSocketRequest } from '../textsecure/WebsocketResources.js'; +const { isNumber } = lodash; + const log = createLogger('checkFirstEnvelope'); const FIRST_ENVELOPE_COUNT = 5; diff --git a/ts/util/createIPCEvents.ts b/ts/util/createIPCEvents.ts index 0336894e58e..ed17a6a0c0c 100644 --- a/ts/util/createIPCEvents.ts +++ b/ts/util/createIPCEvents.ts @@ -3,7 +3,7 @@ import { ipcRenderer } from 'electron'; import type { SystemPreferences } from 'electron'; -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { ZoomFactorType } from '../types/Storage.d.ts'; import * as Errors from '../types/errors.js'; @@ -33,6 +33,8 @@ import type { import { SystemTraySetting } from '../types/SystemTraySetting.js'; import OS from './os/osPreload.js'; +const { noop } = lodash; + const log = createLogger('createIPCEvents'); export type IPCEventsValuesType = { diff --git a/ts/util/deleteForMe.ts b/ts/util/deleteForMe.ts index da68090a5cb..766e63e6f68 100644 --- a/ts/util/deleteForMe.ts +++ b/ts/util/deleteForMe.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { last, sortBy } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import { DataReader, DataWriter, deleteAndCleanup } from '../sql/Client.js'; @@ -18,6 +18,8 @@ import { getMessageQueryFromTarget, } from './syncIdentifiers.js'; +const { last, sortBy } = lodash; + const log = createLogger('deleteForMe'); const { getMostRecentAddressableMessages } = DataReader; diff --git a/ts/util/deleteStoryForEveryone.ts b/ts/util/deleteStoryForEveryone.ts index 138d737fe42..5f83a385595 100644 --- a/ts/util/deleteStoryForEveryone.ts +++ b/ts/util/deleteStoryForEveryone.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { noop } from 'lodash'; +import lodash from 'lodash'; import type { ConversationQueueJobData } from '../jobs/conversationJobQueue.js'; import type { StoryDataType } from '../state/ducks/stories.js'; @@ -24,6 +24,8 @@ import { strictAssert } from './assert.js'; import { repeat, zipObject } from './iterables.js'; import { isOlderThan } from './timestamp.js'; +const { noop } = lodash; + const log = createLogger('deleteStoryForEveryone'); export async function deleteStoryForEveryone( diff --git a/ts/util/dns.ts b/ts/util/dns.ts index bb951a18bbd..8395ae7317f 100644 --- a/ts/util/dns.ts +++ b/ts/util/dns.ts @@ -7,7 +7,7 @@ import type { LookupAddress, lookup as nodeLookup, } from 'node:dns'; -import { ipcRenderer, net } from 'electron'; +import * as electron from 'electron'; import type { ResolvedHost, ResolvedEndpoint } from 'electron'; import pTimeout from 'p-timeout'; @@ -56,10 +56,10 @@ function lookupAll( } try { - if (net) { + if (electron.net) { // Main process result = await pTimeout( - net.resolveHost(hostname, { + electron.net.resolveHost(hostname, { queryType, }), LOOKUP_TIMEOUT_MS, @@ -68,7 +68,7 @@ function lookupAll( } else { // Renderer result = await pTimeout( - ipcRenderer.invoke('net.resolveHost', hostname, queryType), + electron.ipcRenderer.invoke('net.resolveHost', hostname, queryType), LOOKUP_TIMEOUT_MS, 'lookupAll: Electron lookup timed out' ); diff --git a/ts/util/downloadAttachmentFromLocalBackup.ts b/ts/util/downloadAttachmentFromLocalBackup.ts index 3df592f049d..54331ff9e6b 100644 --- a/ts/util/downloadAttachmentFromLocalBackup.ts +++ b/ts/util/downloadAttachmentFromLocalBackup.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { existsSync } from 'node:fs'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { type BackupableAttachmentType } from '../types/Attachment.js'; import { decryptAndReencryptLocally, @@ -10,6 +10,8 @@ import { } from '../AttachmentCrypto.js'; import { strictAssert } from './assert.js'; +const { isNumber } = lodash; + export class AttachmentPermanentlyUndownloadableError extends Error {} export async function downloadAttachmentFromLocalBackup( diff --git a/ts/util/dropZero.ts b/ts/util/dropZero.ts index cac14e47415..a92cbf0c470 100644 --- a/ts/util/dropZero.ts +++ b/ts/util/dropZero.ts @@ -1,7 +1,9 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; + +const { isNumber } = lodash; export function dropZero(value: number | null | undefined): number | undefined { if (isNumber(value) && value !== 0) { diff --git a/ts/util/editHelpers.ts b/ts/util/editHelpers.ts index f4ce8dec683..2114e686362 100644 --- a/ts/util/editHelpers.ts +++ b/ts/util/editHelpers.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber, sortBy } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { strictAssert } from './assert.js'; @@ -13,6 +13,8 @@ import type { } from '../model-types.js'; import type { LoggerType } from '../types/Logging.js'; +const { isNumber, sortBy } = lodash; + // The tricky bit for this function is if we are on our second+ attempt to send a given // edit, we're still sending that edit. export function getTargetOfThisEditTimestamp({ diff --git a/ts/util/expirationTimer.ts b/ts/util/expirationTimer.ts index 522cbf8c7a2..5db50b2fcd2 100644 --- a/ts/util/expirationTimer.ts +++ b/ts/util/expirationTimer.ts @@ -3,10 +3,12 @@ import humanizeDuration from 'humanize-duration'; import type { Unit } from 'humanize-duration'; -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import type { LocalizerType } from '../types/Util.js'; import { SECOND, DurationInSeconds } from './durations/index.js'; +const { isNumber } = lodash; + export const INITIAL_EXPIRE_TIMER_VERSION = 1; const SECONDS_PER_WEEK = 604800; diff --git a/ts/util/getConversation.ts b/ts/util/getConversation.ts index 9a428949c46..9fc3f37365a 100644 --- a/ts/util/getConversation.ts +++ b/ts/util/getConversation.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import memoizee from 'memoizee'; -import { sortBy } from 'lodash'; +import lodash from 'lodash'; import type { ConversationModel } from '../models/conversations.js'; import type { ConversationType } from '../state/ducks/conversations.js'; import type { ConversationAttributesType } from '../model-types.js'; @@ -59,6 +59,8 @@ import { isNotNil } from './isNotNil.js'; import { getIdentifierHash } from '../Crypto.js'; import { getAvatarPlaceholderGradient } from '../utils/getAvatarPlaceholderGradient.js'; +const { sortBy } = lodash; + const EMPTY_ARRAY: Readonly<[]> = []; const EMPTY_GROUP_COLLISIONS: GroupNameCollisionsWithIdsByTitle = {}; diff --git a/ts/util/getConversationMembers.ts b/ts/util/getConversationMembers.ts index cc7b5034837..3c48e2a47f0 100644 --- a/ts/util/getConversationMembers.ts +++ b/ts/util/getConversationMembers.ts @@ -1,11 +1,13 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { compact } from 'lodash'; +import lodash from 'lodash'; import type { ConversationAttributesType } from '../model-types.d.ts'; import type { ServiceIdString } from '../types/ServiceId.js'; import { isDirectConversation } from './whatTypeOfConversation.js'; +const { compact } = lodash; + export function getConversationMembers( conversationAttrs: ConversationAttributesType, options: { includePendingMembers?: boolean } = {} diff --git a/ts/util/getLocalAttachmentUrl.ts b/ts/util/getLocalAttachmentUrl.ts index cfde98e83d0..e446366fd9b 100644 --- a/ts/util/getLocalAttachmentUrl.ts +++ b/ts/util/getLocalAttachmentUrl.ts @@ -1,11 +1,13 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { strictAssert } from './assert.js'; import type { AttachmentType } from '../types/Attachment.js'; +const { isNumber } = lodash; + export enum AttachmentDisposition { Attachment = 'attachment', AvatarData = 'avatarData', diff --git a/ts/util/getRecipients.ts b/ts/util/getRecipients.ts index 0aa1a3d11ac..9646bf36c8f 100644 --- a/ts/util/getRecipients.ts +++ b/ts/util/getRecipients.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { compact, uniq } from 'lodash'; +import lodash from 'lodash'; import type { ConversationAttributesType } from '../model-types.d.ts'; @@ -11,6 +11,8 @@ import { getSendTarget } from './getSendTarget.js'; import { isDirectConversation, isMe } from './whatTypeOfConversation.js'; import { isNotNil } from './isNotNil.js'; +const { compact, uniq } = lodash; + export function getRecipients( conversationAttributes: ConversationAttributesType, { diff --git a/ts/util/groupAndOrderReactions.ts b/ts/util/groupAndOrderReactions.ts index 0d096a222de..4183a3bde7b 100644 --- a/ts/util/groupAndOrderReactions.ts +++ b/ts/util/groupAndOrderReactions.ts @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { groupBy, orderBy } from 'lodash'; +import lodash from 'lodash'; import { useMemo } from 'react'; import type { Reaction } from '../components/conversation/ReactionViewer.js'; @@ -16,6 +16,8 @@ import { import { isNotNil } from './isNotNil.js'; import { useFunEmojiLocalizer } from '../components/fun/useFunEmojiLocalizer.js'; +const { groupBy, orderBy } = lodash; + type ReactionWithEmojiData = Reaction & { short_name: string | undefined; short_names: Array; diff --git a/ts/util/groupMemberNameCollisions.ts b/ts/util/groupMemberNameCollisions.ts index 57b3de75508..b221509291e 100644 --- a/ts/util/groupMemberNameCollisions.ts +++ b/ts/util/groupMemberNameCollisions.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { mapValues, pickBy } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyDeep } from 'type-fest'; import { groupBy, map, filter } from './iterables.js'; import { getOwn } from './getOwn.js'; @@ -9,6 +9,8 @@ import type { ConversationType } from '../state/ducks/conversations.js'; import { isConversationNameKnown } from './isConversationNameKnown.js'; import { isInSystemContacts } from './isInSystemContacts.js'; +const { mapValues, pickBy } = lodash; + export type GroupNameCollisionsWithIdsByTitle = Readonly< Record> >; diff --git a/ts/util/groupMembershipUtils.ts b/ts/util/groupMembershipUtils.ts index 338d9b557be..14aa3823000 100644 --- a/ts/util/groupMembershipUtils.ts +++ b/ts/util/groupMembershipUtils.ts @@ -1,7 +1,7 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import isNumber from 'lodash/isNumber'; +import isNumber from 'lodash/isNumber.js'; import type { ConversationAttributesType } from '../model-types.d.ts'; import type { ServiceIdString, AciString } from '../types/ServiceId.js'; import { SignalService as Proto } from '../protobuf/index.js'; diff --git a/ts/util/groupSendEndorsements.ts b/ts/util/groupSendEndorsements.ts index ac7650d6d4a..ca9f83ec261 100644 --- a/ts/util/groupSendEndorsements.ts +++ b/ts/util/groupSendEndorsements.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { Aci } from '@signalapp/libsignal-client'; -import { throttle } from 'lodash'; +import lodash from 'lodash'; import { groupSendEndorsementsDataSchema, toGroupSendToken, @@ -34,6 +34,8 @@ import { maybeUpdateGroup } from '../groups.js'; import * as Bytes from '../Bytes.js'; import { isGroupV2 } from './whatTypeOfConversation.js'; +const { throttle } = lodash; + const log = createLogger('groupSendEndorsements'); export function decodeGroupSendEndorsementResponse({ diff --git a/ts/util/handleMessageSend.ts b/ts/util/handleMessageSend.ts index 6ee80419d4c..101ff3fd662 100644 --- a/ts/util/handleMessageSend.ts +++ b/ts/util/handleMessageSend.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { z } from 'zod'; -import { isBoolean, isNumber } from 'lodash'; +import lodash from 'lodash'; import type { CallbackResultType } from '../textsecure/Types.d.ts'; import { DataWriter } from '../sql/Client.js'; import { createLogger } from '../logging/log.js'; @@ -16,6 +16,8 @@ import { SEALED_SENDER } from '../types/SealedSender.js'; import type { ServiceIdString } from '../types/ServiceId.js'; import { drop } from './drop.js'; +const { isBoolean, isNumber } = lodash; + const log = createLogger('handleMessageSend'); const { insertSentProto, updateConversation } = DataWriter; diff --git a/ts/util/handleRetry.ts b/ts/util/handleRetry.ts index aea864689ca..04a2d9f10c8 100644 --- a/ts/util/handleRetry.ts +++ b/ts/util/handleRetry.ts @@ -5,7 +5,7 @@ import { DecryptionErrorMessage, PlaintextContent, } from '@signalapp/libsignal-client'; -import { isNumber, random } from 'lodash'; +import lodash from 'lodash'; import type PQueue from 'p-queue'; import * as Bytes from '../Bytes.js'; @@ -42,6 +42,8 @@ import { incrementMessageCounter } from './incrementMessageCounter.js'; import { SECOND } from './durations/index.js'; import { sleep } from './sleep.js'; +const { isNumber, random } = lodash; + const log = createLogger('handleRetry'); const RETRY_LIMIT = 5; diff --git a/ts/util/hasAttachmentDownloads.ts b/ts/util/hasAttachmentDownloads.ts index 98e8bb84a3b..1d1959976e2 100644 --- a/ts/util/hasAttachmentDownloads.ts +++ b/ts/util/hasAttachmentDownloads.ts @@ -1,10 +1,12 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { partition } from 'lodash'; +import lodash from 'lodash'; import type { ReadonlyMessageAttributesType } from '../model-types.d.ts'; import { isLongMessage } from '../types/MIME.js'; +const { partition } = lodash; + // NOTE: If you're modifying this function then you'll likely also need // to modify ./queueAttachmentDownloads export function hasAttachmentDownloads( diff --git a/ts/util/hydrateStoryContext.ts b/ts/util/hydrateStoryContext.ts index e6bd81669fc..530a988c4b6 100644 --- a/ts/util/hydrateStoryContext.ts +++ b/ts/util/hydrateStoryContext.ts @@ -1,7 +1,7 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import omit from 'lodash/omit'; +import omit from 'lodash/omit.js'; import { createLogger } from '../logging/log.js'; import type { AttachmentType } from '../types/Attachment.js'; import type { MessageAttributesType } from '../model-types.d.ts'; diff --git a/ts/util/incrementMessageCounter.ts b/ts/util/incrementMessageCounter.ts index 881e4ba76ff..1e2d09210db 100644 --- a/ts/util/incrementMessageCounter.ts +++ b/ts/util/incrementMessageCounter.ts @@ -1,13 +1,15 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { debounce, isNumber } from 'lodash'; +import lodash from 'lodash'; import { strictAssert } from './assert.js'; import { safeParseInteger } from './numbers.js'; import { DataReader } from '../sql/Client.js'; import { createLogger } from '../logging/log.js'; +const { debounce, isNumber } = lodash; + const log = createLogger('incrementMessageCounter'); let receivedAtCounter: number | undefined; diff --git a/ts/util/inspectProtobufs.ts b/ts/util/inspectProtobufs.ts index 43820da326b..3de91194c36 100644 --- a/ts/util/inspectProtobufs.ts +++ b/ts/util/inspectProtobufs.ts @@ -1,7 +1,9 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { Reader } from 'protobufjs'; +import protobufjs from 'protobufjs'; + +const { Reader } = protobufjs; type MessageWithUnknownFields = { $unknownFields?: ReadonlyArray; diff --git a/ts/util/isConversationUnread.ts b/ts/util/isConversationUnread.ts index a4a64225030..67b4f01786c 100644 --- a/ts/util/isConversationUnread.ts +++ b/ts/util/isConversationUnread.ts @@ -1,7 +1,9 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; + +const { isNumber } = lodash; export const isConversationUnread = ({ markedUnread, diff --git a/ts/util/leftPaneWidth.ts b/ts/util/leftPaneWidth.ts index d6719ff3208..e3d15f8c65f 100644 --- a/ts/util/leftPaneWidth.ts +++ b/ts/util/leftPaneWidth.ts @@ -1,10 +1,12 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { clamp } from 'lodash'; +import lodash from 'lodash'; import { isSorted } from './isSorted.js'; import { strictAssert } from './assert.js'; +const { clamp } = lodash; + export const MIN_WIDTH = 97; export const SNAP_WIDTH = 200; export const MIN_FULL_WIDTH = 280; diff --git a/ts/util/libphonenumberInstance.ts b/ts/util/libphonenumberInstance.ts index 174b5a02efc..8465595e27a 100644 --- a/ts/util/libphonenumberInstance.ts +++ b/ts/util/libphonenumberInstance.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import libphonenumber from 'google-libphonenumber'; -import type { PhoneNumber } from 'google-libphonenumber'; +import { type PhoneNumber } from 'google-libphonenumber'; const instance = libphonenumber.PhoneNumberUtil.getInstance(); const { PhoneNumberFormat } = libphonenumber; diff --git a/ts/util/lint/analyze_exceptions.ts b/ts/util/lint/analyze_exceptions.ts index cc102ec2c0c..c5c2b6d555e 100644 --- a/ts/util/lint/analyze_exceptions.ts +++ b/ts/util/lint/analyze_exceptions.ts @@ -1,13 +1,14 @@ // Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +import lodash from 'lodash'; import { join } from 'node:path'; -import { fromPairs, groupBy, map } from 'lodash'; - import type { ExceptionType } from './types.js'; import { loadJSON } from './util.js'; +const { fromPairs, groupBy, map } = lodash; + const exceptionsPath = join(__dirname, 'exceptions.json'); const exceptions: Array = loadJSON(exceptionsPath); const byRule = groupBy(exceptions, 'rule'); diff --git a/ts/util/lint/util.ts b/ts/util/lint/util.ts index 9fa0ceb94a3..5c46293f5d4 100644 --- a/ts/util/lint/util.ts +++ b/ts/util/lint/util.ts @@ -1,12 +1,16 @@ // Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { readJsonSync, writeJsonSync } from 'fs-extra'; +import fsExtra from 'fs-extra'; -import { orderBy } from 'lodash'; +import lodash from 'lodash'; import type { ExceptionType } from './types.js'; +const { readJsonSync, writeJsonSync } = fsExtra; + +const { orderBy } = lodash; + export const ENCODING = 'utf8'; export const loadJSON = (path: string): T => readJsonSync(path); diff --git a/ts/util/loadRecentEmojis.ts b/ts/util/loadRecentEmojis.ts index f88d37dba19..be121da0695 100644 --- a/ts/util/loadRecentEmojis.ts +++ b/ts/util/loadRecentEmojis.ts @@ -1,9 +1,11 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { take } from 'lodash'; +import lodash from 'lodash'; import { DataReader } from '../sql/Client.js'; +const { take } = lodash; + export type RecentEmojiObjectType = { recents: Array; }; diff --git a/ts/util/mapObjectWithSpec.ts b/ts/util/mapObjectWithSpec.ts index 9738115cda5..9996259d635 100644 --- a/ts/util/mapObjectWithSpec.ts +++ b/ts/util/mapObjectWithSpec.ts @@ -2,7 +2,9 @@ // SPDX-License-Identifier: AGPL-3.0-only /* eslint-disable @typescript-eslint/no-explicit-any */ -import { cloneDeep, get, set } from 'lodash'; +import lodash from 'lodash'; + +const { cloneDeep, get, set } = lodash; export type ObjectMappingSpecType = | string diff --git a/ts/util/markConversationRead.ts b/ts/util/markConversationRead.ts index be6edb9cdb9..3a03e61e8e0 100644 --- a/ts/util/markConversationRead.ts +++ b/ts/util/markConversationRead.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber, pick } from 'lodash'; +import lodash from 'lodash'; import type { ConversationAttributesType } from '../model-types.d.ts'; import { DataWriter } from '../sql/Client.js'; @@ -28,6 +28,8 @@ import { isAciString } from './isAciString.js'; import type { MessageModel } from '../models/messages.js'; import { postSaveUpdates } from './cleanup.js'; +const { isNumber, pick } = lodash; + const log = createLogger('markConversationRead'); export async function markConversationRead( diff --git a/ts/util/modifyTargetMessage.ts b/ts/util/modifyTargetMessage.ts index 12aaeebbf0e..025016152a2 100644 --- a/ts/util/modifyTargetMessage.ts +++ b/ts/util/modifyTargetMessage.ts @@ -1,7 +1,7 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isEqual } from 'lodash'; +import lodash from 'lodash'; import PQueue from 'p-queue'; import type { ConversationModel } from '../models/conversations.js'; import type { MessageModel } from '../models/messages.js'; @@ -47,6 +47,8 @@ import { handlePollVote, } from '../messageModifiers/Polls.js'; +const { isEqual } = lodash; + const log = createLogger('modifyTargetMessage'); export enum ModifyTargetMessageResult { diff --git a/ts/util/onStoryRecipientUpdate.ts b/ts/util/onStoryRecipientUpdate.ts index e794d9d86de..4032da72813 100644 --- a/ts/util/onStoryRecipientUpdate.ts +++ b/ts/util/onStoryRecipientUpdate.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isEqual } from 'lodash'; +import lodash from 'lodash'; import { DataReader } from '../sql/Client.js'; import type { StoryRecipientUpdateEvent } from '../textsecure/messageReceiverEvents.js'; import { normalizeStoryDistributionId } from '../types/StoryDistributionId.js'; @@ -16,6 +16,8 @@ import { fromServiceIdBinaryOrString } from './ServiceId.js'; import { handleDeleteForEveryone } from './deleteForEveryone.js'; import { MessageModel } from '../models/messages.js'; +const { isEqual } = lodash; + const log = createLogger('onStoryRecipientUpdate'); export async function onStoryRecipientUpdate( diff --git a/ts/util/os/osMain.ts b/ts/util/os/osMain.ts index 5aaebec1935..fa19438bf0f 100644 --- a/ts/util/os/osMain.ts +++ b/ts/util/os/osMain.ts @@ -2,9 +2,11 @@ // SPDX-License-Identifier: AGPL-3.0-only import os from 'node:os'; -import { readFileSync } from 'fs-extra'; +import fsExtra from 'fs-extra'; import { getOSFunctions } from './shared.js'; +const { readFileSync } = fsExtra; + function getLinuxName(): string | undefined { if (os.platform() !== 'linux') { return undefined; diff --git a/ts/util/packageJson.ts b/ts/util/packageJson.ts new file mode 100644 index 00000000000..7bf55076bd5 --- /dev/null +++ b/ts/util/packageJson.ts @@ -0,0 +1,23 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +const PACKAGE_JSON_PATH = join(__dirname, '..', '..', 'package.json'); + +const json: { + name: string; + version: string; + productName: string; + build: { + appId: string; + }; +} = JSON.parse(readFileSync(PACKAGE_JSON_PATH, 'utf8')); + +export default json; + +export const { name } = json; +export const { version } = json; +export const { productName } = json; +export const { build } = json; diff --git a/ts/util/popperUtil.ts b/ts/util/popperUtil.ts index 3de634c8960..f16c81366b1 100644 --- a/ts/util/popperUtil.ts +++ b/ts/util/popperUtil.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { Modifier } from '@popperjs/core'; -import type { OffsetModifier } from '@popperjs/core/lib/modifiers/offset'; +import type { OffsetModifier } from '@popperjs/core/lib/modifiers/offset.js'; /** * Shorthand for the [offset modifier][0] when you just wanna set the distance. diff --git a/ts/util/privacy.ts b/ts/util/privacy.ts index 43a3be5f829..69809160a9e 100644 --- a/ts/util/privacy.ts +++ b/ts/util/privacy.ts @@ -5,13 +5,16 @@ import path from 'node:path'; -import { compose } from 'lodash/fp'; -import { escapeRegExp, isString, isRegExp } from 'lodash'; +import lodashFp from 'lodash/fp.js'; +import lodash from 'lodash'; import type { ExtendedStorageID } from '../types/StorageService.d.ts'; import type { ConversationModel } from '../models/conversations.js'; export const APP_ROOT_PATH = path.join(__dirname, '..', '..'); +const { escapeRegExp, isString, isRegExp } = lodash; + +const { compose } = lodashFp; const PHONE_NUMBER_PATTERN = /\+\d{7,12}(\d{3})/g; // The additional 0 in [0-8] and [089AB] are to include MY_STORY_ID diff --git a/ts/util/retryPlaceholders.ts b/ts/util/retryPlaceholders.ts index 62712adcad0..436d75aef19 100644 --- a/ts/util/retryPlaceholders.ts +++ b/ts/util/retryPlaceholders.ts @@ -2,11 +2,13 @@ // SPDX-License-Identifier: AGPL-3.0-only import { z } from 'zod'; -import { groupBy } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import { aciSchema } from '../types/ServiceId.js'; import { safeParseStrict } from './schemas.js'; +const { groupBy } = lodash; + const log = createLogger('retryPlaceholders'); const retryItemSchema = z diff --git a/ts/util/sendReceipts.ts b/ts/util/sendReceipts.ts index 7b1dc57a9e6..2f66d5dc483 100644 --- a/ts/util/sendReceipts.ts +++ b/ts/util/sendReceipts.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { chunk, map } from 'lodash'; +import lodash from 'lodash'; import type { LoggerType } from '../types/Logging.js'; import type { Receipt } from '../types/Receipt.js'; import { ReceiptType } from '../types/Receipt.js'; @@ -14,6 +14,8 @@ import type { ConversationModel } from '../models/conversations.js'; import { mapEmplace } from './mapEmplace.js'; import { isSignalConversation } from './isSignalConversation.js'; +const { chunk, map } = lodash; + const CHUNK_SIZE = 100; export async function sendReceipts({ diff --git a/ts/util/sendToGroup.ts b/ts/util/sendToGroup.ts index 34ae3bf540d..db8c11f4196 100644 --- a/ts/util/sendToGroup.ts +++ b/ts/util/sendToGroup.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { differenceWith, omit } from 'lodash'; +import lodash from 'lodash'; import { v4 as generateUuid } from 'uuid'; import { @@ -76,6 +76,8 @@ import type { GroupSendToken } from '../types/GroupSendEndorsements.js'; import { isAciString } from './isAciString.js'; import { safeParseStrict, safeParseUnknown } from './schemas.js'; +const { differenceWith, omit } = lodash; + const log = createLogger('sendToGroup'); const UNKNOWN_RECIPIENT = 404; diff --git a/ts/util/sessionTranslation.ts b/ts/util/sessionTranslation.ts index 873e8b4dd50..c737d6e6a31 100644 --- a/ts/util/sessionTranslation.ts +++ b/ts/util/sessionTranslation.ts @@ -1,12 +1,14 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { get, isFinite, isInteger, isString } from 'lodash'; +import lodash from 'lodash'; import { signal } from '../protobuf/compiled.js'; import * as Bytes from '../Bytes.js'; import { deriveSecrets } from '../Crypto.js'; +const { get, isFinite, isInteger, isString } = lodash; + const { RecordStructure, SessionStructure } = signal.proto.storage; const { Chain } = SessionStructure; diff --git a/ts/util/smartling.ts b/ts/util/smartling.ts index 3e2b9c97f7e..496ddfc822c 100644 --- a/ts/util/smartling.ts +++ b/ts/util/smartling.ts @@ -1,7 +1,7 @@ // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import * as packageJson from '../../package.json'; +import { version } from './packageJson.js'; import { getUserAgent } from './getUserAgent.js'; type AuthenticateOptionsType = Readonly<{ @@ -36,6 +36,6 @@ export async function authenticate({ return new Headers({ authorization: `${auth.tokenType} ${auth.accessToken}`, - 'user-agent': getUserAgent(packageJson.version), + 'user-agent': getUserAgent(version), }); } diff --git a/ts/util/timelineUtil.ts b/ts/util/timelineUtil.ts index 5ab37f2aade..7db27faa9c4 100644 --- a/ts/util/timelineUtil.ts +++ b/ts/util/timelineUtil.ts @@ -1,7 +1,7 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { isNumber } from 'lodash'; +import lodash from 'lodash'; import { createLogger } from '../logging/log.js'; import type { PropsType as TimelinePropsType } from '../components/conversation/Timeline.js'; import type { TimelineItemType } from '../components/conversation/TimelineItem.js'; @@ -12,6 +12,8 @@ import { missingCaseError } from './missingCaseError.js'; import { isSameDay } from './timestamp.js'; import type { LastMessageStatus } from '../model-types.d.ts'; +const { isNumber } = lodash; + const log = createLogger('timelineUtil'); const COLLAPSE_WITHIN = 3 * MINUTE; diff --git a/ts/util/timer.ts b/ts/util/timer.ts index db3dcf9f344..7c36bbea2bd 100644 --- a/ts/util/timer.ts +++ b/ts/util/timer.ts @@ -1,7 +1,9 @@ // Copyright 2019 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { padStart } from 'lodash'; +import lodash from 'lodash'; + +const { padStart } = lodash; export function getIncrement(length: number): number { if (length < 0) { diff --git a/ts/util/updateBackupMediaDownloadProgress.ts b/ts/util/updateBackupMediaDownloadProgress.ts index c62003f5055..0c23f4191c2 100644 --- a/ts/util/updateBackupMediaDownloadProgress.ts +++ b/ts/util/updateBackupMediaDownloadProgress.ts @@ -1,9 +1,11 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { throttle } from 'lodash'; +import lodash from 'lodash'; import type { BackupAttachmentDownloadProgress } from '../sql/Interface.js'; +const { throttle } = lodash; + export async function updateBackupMediaDownloadProgress( getBackupAttachmentDownloadProgress: () => Promise ): Promise { diff --git a/ts/util/uuidToBytes.ts b/ts/util/uuidToBytes.ts index d54e5aa9360..5a8d931a941 100644 --- a/ts/util/uuidToBytes.ts +++ b/ts/util/uuidToBytes.ts @@ -1,11 +1,13 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { chunk } from 'lodash'; +import lodash from 'lodash'; import { UUID_BYTE_SIZE } from '../types/Crypto.js'; import { createLogger } from '../logging/log.js'; import * as Bytes from '../Bytes.js'; +const { chunk } = lodash; + const log = createLogger('uuidToBytes'); export function getBytesSubarray( diff --git a/ts/util/writeDraftAttachment.ts b/ts/util/writeDraftAttachment.ts index cb219e80de0..f3b564949e3 100644 --- a/ts/util/writeDraftAttachment.ts +++ b/ts/util/writeDraftAttachment.ts @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { omit } from 'lodash'; +import lodash from 'lodash'; import type { InMemoryAttachmentDraftType, AttachmentDraftType, @@ -16,6 +16,8 @@ import { } from './getLocalAttachmentUrl.js'; import { createLogger } from '../logging/log.js'; +const { omit } = lodash; + const logger = createLogger('writeDraftAttachment'); export async function writeDraftAttachment( diff --git a/ts/util/zkgroup.ts b/ts/util/zkgroup.ts index d07138e21e0..b54fc6742e8 100644 --- a/ts/util/zkgroup.ts +++ b/ts/util/zkgroup.ts @@ -1,7 +1,7 @@ // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import type { ProfileKeyCredentialRequestContext } from '@signalapp/libsignal-client/zkgroup'; +import type { ProfileKeyCredentialRequestContext } from '@signalapp/libsignal-client/zkgroup.js'; import { AuthCredentialWithPni, ClientZkAuthOperations, @@ -17,7 +17,7 @@ import { ServerPublicParams, UuidCiphertext, NotarySignature, -} from '@signalapp/libsignal-client/zkgroup'; +} from '@signalapp/libsignal-client/zkgroup.js'; import { Aci, Pni, type ServiceId } from '@signalapp/libsignal-client'; import type { ServiceIdString, @@ -33,7 +33,7 @@ import * as Bytes from '../Bytes.js'; import { toServiceIdObject } from './ServiceId.js'; import { strictAssert } from './assert.js'; -export * from '@signalapp/libsignal-client/zkgroup'; +export * from '@signalapp/libsignal-client/zkgroup.js'; // Scenarios diff --git a/ts/window.d.ts b/ts/window.d.ts index 1e524226b2e..6488334d569 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -6,9 +6,9 @@ import type EventEmitter from 'node:events'; import type { Store } from 'redux'; import type { SystemPreferences } from 'electron'; -import type PQueue from 'p-queue/dist'; +import type PQueue from 'p-queue/dist.js'; import type { assert } from 'chai'; -import type { PhoneNumber, PhoneNumberFormat } from 'google-libphonenumber'; +import googleLibphonenumber from 'google-libphonenumber'; import type { MochaOptions } from 'mocha'; import type { textsecure } from './textsecure/index.js'; @@ -58,6 +58,8 @@ import type { QueryStatsOptions } from './sql/main.js'; import type { SocketStatuses } from './textsecure/SocketManager.js'; import type { BeforeNavigateService } from './services/BeforeNavigate.js'; +const { PhoneNumber, PhoneNumberFormat } = googleLibphonenumber; + export { Long } from 'long'; export type IPCType = { diff --git a/ts/windows/main/attachments.ts b/ts/windows/main/attachments.ts index 3c34b36af52..69c1c864a5e 100644 --- a/ts/windows/main/attachments.ts +++ b/ts/windows/main/attachments.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import { ipcRenderer } from 'electron'; -import { isString, isTypedArray } from 'lodash'; +import lodash from 'lodash'; import { join, normalize, basename, parse as pathParse } from 'node:path'; import { existsSync } from 'node:fs'; import fse from 'fs-extra'; @@ -16,6 +16,8 @@ import { toHex } from '../../Bytes.js'; import { getRandomBytes } from '../../Crypto.js'; import { createLogger } from '../../logging/log.js'; +const { isString, isTypedArray } = lodash; + const log = createLogger('attachments'); export * from '../../../app/attachments.js'; diff --git a/ts/windows/main/phase1-ipc.ts b/ts/windows/main/phase1-ipc.ts index 19e6d87fbba..07d1f636066 100644 --- a/ts/windows/main/phase1-ipc.ts +++ b/ts/windows/main/phase1-ipc.ts @@ -4,7 +4,7 @@ import EventEmitter from 'node:events'; import { ipcRenderer as ipc } from 'electron'; import * as semver from 'semver'; -import { groupBy, mapValues } from 'lodash'; +import lodash from 'lodash'; import PQueue from 'p-queue'; import type { IPCType } from '../../window.d.ts'; @@ -36,6 +36,8 @@ import { conversationQueueJobEnum, } from '../../jobs/conversationJobQueue.js'; +const { groupBy, mapValues } = lodash; + const log = createLogger('phase1-ipc'); // It is important to call this as early as possible diff --git a/ts/windows/main/phase2-dependencies.ts b/ts/windows/main/phase2-dependencies.ts index cb64df7ca6d..65d68e75bfe 100644 --- a/ts/windows/main/phase2-dependencies.ts +++ b/ts/windows/main/phase2-dependencies.ts @@ -1,10 +1,10 @@ // Copyright 2022 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber'; +import googleLibphonenumber from 'google-libphonenumber'; import * as moment from 'moment'; // @ts-expect-error -- no types -import 'moment/min/locales.min'; +import 'moment/min/locales.min.js'; import { textsecure } from '../../textsecure/index.js'; import { initialize as initializeLogging } from '../../logging/set_up_renderer_logging.js'; @@ -15,6 +15,8 @@ import { createLogger } from '../../logging/log.js'; import { SignalContext } from '../context.js'; import * as Attachments from './attachments.js'; +const { PhoneNumberUtil, PhoneNumberFormat } = googleLibphonenumber; + const log = createLogger('phase2-dependencies'); initializeLogging(); diff --git a/ts/windows/main/phase4-test.ts b/ts/windows/main/phase4-test.ts index a77a0c71b84..2a563e6a0be 100644 --- a/ts/windows/main/phase4-test.ts +++ b/ts/windows/main/phase4-test.ts @@ -7,6 +7,8 @@ const { config } = window.SignalContext; +export {}; + if (config.environment === 'test') { console.log('Importing test infrastructure...'); require('./preload_test.js'); diff --git a/ts/windows/main/start.ts b/ts/windows/main/start.ts index 6a0a22df886..8deffacd7bc 100644 --- a/ts/windows/main/start.ts +++ b/ts/windows/main/start.ts @@ -1,7 +1,7 @@ // Copyright 2017 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { has } from 'lodash'; +import lodash from 'lodash'; import { contextBridge } from 'electron'; import { createLogger } from '../../logging/log.js'; @@ -29,6 +29,8 @@ import { Environment, getEnvironment } from '../../environment.js'; import { isProduction } from '../../util/version.js'; import { benchmarkConversationOpen } from '../../CI/benchmarkConversationOpen.js'; +const { has } = lodash; + const log = createLogger('start'); window.addEventListener('contextmenu', e => {