From 7df831b252c0c64c40b17c860f09c908fec9a153 Mon Sep 17 00:00:00 2001 From: Javier Cuevas Date: Fri, 29 Dec 2023 19:30:33 +0100 Subject: [PATCH] Update to typeorm 0.3.x (#45) * Bump typeorm deps from 0.2.41 to 0.3.17 * Rename Connection to DataSource * * Rename `findOne({ id })` to `findOneBy({ id })` and `findOneOrFail({ id })` to `findOneByOrFail({ id })` * Add missing `where` key to `find()` args * Use findOne with a (mandatory) where clause * Replace db.close with ds.destroy * wait for dataSource initialization * Missing renames of Connection to Datasource * Remove unnecessary if (finOneOrFail would already throw an error) * Replace `connect` with `initialize` and `close` with `destroy` * Send retry request for CIPHERTEXT msgs on getMessages (#47) * Add `node` to `FullBaileysMessage` (message.original`) * When calling `fetchMessages` send a retry request for any message that was not decrypted before * Bump baileys --- package.json | 2 +- src/api.ts | 38 ++-- src/entities/DBMessage-util.ts | 2 +- src/tests/db.test.ts | 24 +-- src/types.ts | 7 +- src/utils/db-get-earliest-msg-order-key.ts | 6 +- src/utils/db-get-latest-msg-order-key.ts | 6 +- src/utils/db-key-store.ts | 14 +- src/utils/db-mutex-all-transactions.ts | 14 +- src/utils/download-message.ts | 10 +- src/utils/drop-database.ts | 6 +- src/utils/fetch-messages.ts | 14 +- src/utils/generics.ts | 4 +- .../{get-connection.ts => get-data-source.ts} | 15 +- src/utils/get-ephemeral-options.ts | 6 +- src/utils/get-group-participants-from-db.ts | 6 +- src/utils/get-last-messages-of-thread.ts | 4 +- src/utils/get-message-compose.ts | 12 +- src/utils/has-some-cached-data.ts | 4 +- src/utils/make-texts-baileys-store.ts | 12 +- src/utils/read-chat.ts | 6 +- src/utils/register-db-subscribers.ts | 4 +- src/utils/resync-history.ts | 4 +- src/utils/set-participant-users.ts | 6 +- yarn.lock | 186 +++++++++++------- 25 files changed, 238 insertions(+), 174 deletions(-) rename src/utils/{get-connection.ts => get-data-source.ts} (66%) diff --git a/package.json b/package.json index ba73b7ff..c5fc36ba 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "pino": "^7.8.0", "react": "https://github.com/TextsHQ/react-global-shim#main", "sanitize-filename": "^1.6.3", - "typeorm": "^0.2.41", + "typeorm": "^0.3.17", "typeorm-naming-strategies": "^2.0.0" }, "devDependencies": { diff --git a/src/api.ts b/src/api.ts index b5ebaaa1..0d5159c7 100644 --- a/src/api.ts +++ b/src/api.ts @@ -4,10 +4,10 @@ import makeWASocket, { Browsers, ChatModification, ConnectionState, delay, Socke import { texts, StickerPack, PlatformAPI, OnServerEventCallback, MessageSendOptions, InboxName, LoginResult, OnConnStateChangeCallback, ReAuthError, CurrentUser, MessageContent, ConnectionError, PaginationArg, ClientContext, ActivityType, Thread, Paginated, User, PhoneNumber, ServerEvent, ConnectionStatus, ServerEventType, GetAssetOptions, AssetInfo, MessageLink, Attachment, ThreadFolderName, UserID, PaginatedWithCursors } from '@textshq/platform-sdk' import { smartJSONStringify } from '@textshq/platform-sdk/dist/json' import type { Logger } from 'pino' -import { LessThanOrEqual, type Connection } from 'typeorm' +import type { DataSource } from 'typeorm' import { PassThrough } from 'stream' import NodeCache from 'node-cache' -import getConnection from './utils/get-connection' +import getDataSource from './utils/get-data-source' import DBUser from './entities/DBUser' import { canReconnect, CONNECTION_STATE_MAP, generateInstanceId, isLoggedIn, LOGGED_OUT_CODES, makeMutex, mapMessageID, numberFromJid, PARTICIPANT_ACTION_MAP, PRESENCE_MAP, profilePictureUrl, waitForAllEventsToBeHandled } from './utils/generics' import DBMessage from './entities/DBMessage' @@ -113,7 +113,7 @@ export default class WhatsAppAPI implements PlatformAPI { logger: Logger - db: Connection + db: DataSource get meID(): string | undefined { if (!this.client) return @@ -170,7 +170,7 @@ export default class WhatsAppAPI implements PlatformAPI { this.logger.info({ dbPath, waVersion: this.latestWAVersion }, 'platform whatsapp init') - this.db = await getConnection(this.accountID, dbPath, this.logger) + this.db = await getDataSource(this.accountID, dbPath, this.logger) this.dataStore = makeTextsBaileysStore( this.publishEvent, @@ -233,7 +233,7 @@ export default class WhatsAppAPI implements PlatformAPI { } await this.dataStore?.wait() - await this.db?.close() + await this.db?.destroy() this.logger?.info('disposed') } @@ -336,7 +336,7 @@ export default class WhatsAppAPI implements PlatformAPI { } getCurrentUser = async (): Promise => { - let user: User | undefined = await this.db.getRepository(DBUser).findOne({ where: { isSelf: true } }) + let user: User | null = await this.db.getRepository(DBUser).findOne({ where: { isSelf: true } }) if (!user) { const id = this.meID if (!id) { @@ -423,7 +423,7 @@ export default class WhatsAppAPI implements PlatformAPI { private loadWAMessageFromDB = async (threadID: string, messageID: string) => { const repo = this.db.getRepository(DBMessage) - const dbmsg = await repo.findOne({ id: messageID, threadID }) + const dbmsg = await repo.findOneBy({ id: messageID, threadID }) if (dbmsg) { await remapMessagesAndSave(repo, [dbmsg], this) } @@ -647,7 +647,7 @@ export default class WhatsAppAPI implements PlatformAPI { }, ) } else { - const user = await this.db.getRepository(DBUser).findOne({ id: thread.id }) + const user = await this.db.getRepository(DBUser).findOneBy({ id: thread.id }) thread.user = user || null } @@ -657,7 +657,7 @@ export default class WhatsAppAPI implements PlatformAPI { deleteThread = async (threadID: string) => { // thread deletes are local on WA multi-device const repo = this.db.getRepository(DBThread) - const item = await repo.findOne({ id: threadID }) + const item = await repo.findOneBy({ id: threadID }) if (item) { await repo.remove(item) } @@ -703,10 +703,20 @@ export default class WhatsAppAPI implements PlatformAPI { await delay(50) } - const result = await fetchMessages(this, threadID, pagination) + const result = await fetchMessages(this, threadID, pagination, this.senderRetryRequest) + return result } + senderRetryRequest = async (message: DBMessage) => { + if (!this.client) { + throw new Error('client not initialized') + } + if (message.original.node) { + this.client.sendRetryRequest(message.original.node) + } + } + getUser = async (ids: { userID: UserID } | { username: string } | { phoneNumber: PhoneNumber } | { email: string }): Promise => { if (!('phoneNumber' in ids)) return const { phoneNumber } = ids @@ -729,7 +739,7 @@ export default class WhatsAppAPI implements PlatformAPI { getOriginalObject = async (objName: 'thread' | 'message', objectID: string) => { const repo = this.db.getRepository(objName === 'thread' ? DBThread : DBMessage) - const item = await repo.findOne({ id: objectID }) + const item = await repo.findOneBy({ id: objectID }) return smartJSONStringify(item?.original) } @@ -839,7 +849,7 @@ export default class WhatsAppAPI implements PlatformAPI { getMessage = async (threadID: string, messageID: string) => { const repo = this.db.getRepository(DBMessage) - const msg = await repo.findOne({ threadID, id: messageID }) + const msg = await repo.findOneBy({ threadID, id: messageID }) if (msg) { await remapMessagesAndSave(repo, [msg], this) } @@ -869,7 +879,7 @@ export default class WhatsAppAPI implements PlatformAPI { forwardMessage = async (threadID: string, messageID: string, threadIDs?: string[]) => { await this.waitForConnectionOpen() - const { original: { message } } = await this.db.getRepository(DBMessage).findOneOrFail({ + const { original: { message } } = await this.db.getRepository(DBMessage).findOneByOrFail({ id: messageID, threadID, }) @@ -1104,7 +1114,7 @@ export default class WhatsAppAPI implements PlatformAPI { private getChat = (threadID: string) => { const repo = this.db.getRepository(DBThread) - return repo.findOne({ id: threadID }) + return repo.findOneBy({ id: threadID }) } getStickerPacks = async (): Promise> => { diff --git a/src/entities/DBMessage-util.ts b/src/entities/DBMessage-util.ts index 66081efa..ee634280 100644 --- a/src/entities/DBMessage-util.ts +++ b/src/entities/DBMessage-util.ts @@ -755,7 +755,7 @@ export const MessageTransformer: ValueTransformer = { }, to: (item: FullBaileysMessage | null) => { if (item) { - return serialize({ ...item, message: WAProto.WebMessageInfo.encode(item.message).finish() }) + return serialize({ ...item, node: item.message.node, message: WAProto.WebMessageInfo.encode(item.message).finish() }) } return null }, diff --git a/src/tests/db.test.ts b/src/tests/db.test.ts index fe82468e..fb229406 100644 --- a/src/tests/db.test.ts +++ b/src/tests/db.test.ts @@ -1,9 +1,9 @@ // eslint-disable-next-line import/order -import getConnection from '../utils/get-connection' +import getDataSource from '../utils/get-data-source' import { Chat, delay, generateMessageID, makeEventBuffer, unixTimestampSeconds, WAMessageStubType, WAProto } from 'baileys' import { unlink, stat } from 'fs/promises' -import type { Connection } from 'typeorm' +import type { DataSource } from 'typeorm' import DBMessage from '../entities/DBMessage' import DBThread from '../entities/DBThread' import type { MappingContextWithDB } from '../types' @@ -20,7 +20,7 @@ logger.level = 'trace' jest.setTimeout(30_000) describe('Database Sync Tests', () => { - let db: Connection + let db: DataSource let store: ReturnType const mappingCtx: MappingContextWithDB = { @@ -38,7 +38,7 @@ describe('Database Sync Tests', () => { logger.info('removing existing DB') await unlink(DB_PATH) } - db = await getConnection('default', DB_PATH, logger) + db = await getDataSource('default', DB_PATH, logger) mappingCtx.db = db store = makeTextsBaileysStore(() => { }, () => { throw new Error('no') }, mappingCtx) ev.process(events => store.process(events).then(() => { })) @@ -67,13 +67,13 @@ describe('Database Sync Tests', () => { await delay(500) expect( - await db.getRepository(DBThread).findOne({ + await db.getRepository(DBThread).findOneBy({ id: msg.key.remoteJid!, }), ).toBeTruthy() expect( - await db.getRepository(DBMessage).findOne({ + await db.getRepository(DBMessage).findOneBy({ id: mapMessageID(msg.key), }), ).toBeTruthy() @@ -124,7 +124,7 @@ describe('Database Sync Tests', () => { await delay(200) const repo = db.getRepository(DBThread) - const thread = await repo.findOne({ id: jid }) + const thread = await repo.findOneBy({ id: jid }) expect(thread?.unreadCount).toEqual(1) expect(thread?.timestamp).toEqual(new Date(ogTimstamp * 1000)) }) @@ -163,7 +163,7 @@ describe('Database Sync Tests', () => { await delay(200) const repo = db.getRepository(DBThread) - const thread = await repo.findOne({ id: jid }) + const thread = await repo.findOneBy({ id: jid }) expect(thread?.original?.chat?.ephemeralExpiration).toEqual(60 * 60 * 24) }) @@ -237,7 +237,7 @@ describe('Database Sync Tests', () => { }) const repo = db.getRepository(DBMessage) - const messages = await repo.find({ threadID: jid }) + const messages = await repo.find({ where: { threadID: jid }}) expect(messages).toHaveLength(3) }) @@ -341,13 +341,13 @@ describe('Database Sync Tests', () => { ) await store.wait() - await db.close() + await db.destroy() await tasks - await db.connect() + await db.initialize() const repo = db.getRepository(DBMessage) - const dbMessages = await repo.find({ threadID: jid }) + const dbMessages = await repo.find({ where: { threadID: jid }}) expect(dbMessages).toHaveLength(3) }) }) diff --git a/src/types.ts b/src/types.ts index f99a93cb..88b44f0a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,6 @@ -import type { Chat, Contact, GroupMetadata, GroupParticipant, WAMessage } from 'baileys' +import type { BinaryNode, Chat, Contact, GroupMetadata, GroupParticipant, WAMessage } from 'baileys' import type { Logger } from 'pino' -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' export type FullBaileysChat = { chat: Partial & { @@ -14,6 +14,7 @@ export type FullBaileysChat = { export type FullBaileysMessage = { message: WAMessage + node?: BinaryNode seenByMe?: boolean // the last version of platform-whatsapp the message was mapped on lastMappedVersion: number | undefined @@ -30,7 +31,7 @@ export type MappingContext = { logger: Logger } -export type MappingContextWithDB = MappingContext & { db: Connection | EntityManager } +export type MappingContextWithDB = MappingContext & { db: DataSource | EntityManager } export type Transaction = any diff --git a/src/utils/db-get-earliest-msg-order-key.ts b/src/utils/db-get-earliest-msg-order-key.ts index d0e7ccb2..aa5343e5 100644 --- a/src/utils/db-get-earliest-msg-order-key.ts +++ b/src/utils/db-get-earliest-msg-order-key.ts @@ -1,8 +1,8 @@ -import type { Connection, EntityManager } from 'typeorm' +import { Not, type DataSource, type EntityManager, IsNull } from 'typeorm' import DBMessage from '../entities/DBMessage' -export default async (db: EntityManager | Connection) => { +export default async (db: EntityManager | DataSource) => { const msg = await db.getRepository(DBMessage) - .findOne({ order: { orderKey: 'ASC' }, select: ['orderKey'] }) + .findOne({ where: { id: Not(IsNull()) }, order: { orderKey: 'ASC' }, select: ['orderKey'] }) return msg?.orderKey } diff --git a/src/utils/db-get-latest-msg-order-key.ts b/src/utils/db-get-latest-msg-order-key.ts index d83dddb5..721873e6 100644 --- a/src/utils/db-get-latest-msg-order-key.ts +++ b/src/utils/db-get-latest-msg-order-key.ts @@ -1,8 +1,8 @@ -import type { Connection, EntityManager } from 'typeorm' +import { Not, type DataSource, type EntityManager, IsNull } from 'typeorm' import DBMessage from '../entities/DBMessage' -export default async (db: EntityManager | Connection) => { +export default async (db: EntityManager | DataSource) => { const msg = await db.getRepository(DBMessage) - .findOne({ order: { orderKey: 'DESC' }, select: ['orderKey'] }) + .findOne({ where: { id: Not(IsNull()) }, order: { orderKey: 'DESC' }, select: ['orderKey'] }) return msg?.orderKey } diff --git a/src/utils/db-key-store.ts b/src/utils/db-key-store.ts index 8039f3c1..ed15b32c 100644 --- a/src/utils/db-key-store.ts +++ b/src/utils/db-key-store.ts @@ -1,4 +1,4 @@ -import type { Connection } from 'typeorm' +import type { DataSource } from 'typeorm' import type { Logger } from 'pino' import { SignalKeyStore, SignalDataTypeMap, makeCacheableSignalKeyStore } from 'baileys' import AccountKeyValue from '../entities/AccountKeyValue' @@ -16,12 +16,12 @@ const KEY_MAP: { [T in keyof SignalDataTypeMap]: string } = { * Key store required for baileys. * Stores all keys in the sqlite database */ -const _makeDBKeyStore = (db: Connection): SignalKeyStore => { - const repo = db.getRepository(AccountKeyValue) +const _makeDBKeyStore = (ds: DataSource): SignalKeyStore => { + const repo = ds.getRepository(AccountKeyValue) return { get: async (type, ids) => { - const items = await db + const items = await ds .createQueryBuilder(AccountKeyValue, 'acc') .where('category = :category AND id IN (:...ids)', { category: KEY_MAP[type], @@ -51,7 +51,7 @@ const _makeDBKeyStore = (db: Connection): SignalKeyStore => { } } - await db.transaction( + await ds.transaction( async db => { const repo = db.getRepository(AccountKeyValue) @@ -75,8 +75,8 @@ const _makeDBKeyStore = (db: Connection): SignalKeyStore => { } } -export const makeDBKeyStore = (db: Connection, logger: Logger) => { - const store = _makeDBKeyStore(db) +export const makeDBKeyStore = (ds: DataSource, logger: Logger) => { + const store = _makeDBKeyStore(ds) return makeCacheableSignalKeyStore( store, logger, diff --git a/src/utils/db-mutex-all-transactions.ts b/src/utils/db-mutex-all-transactions.ts index 913a1812..b026ea0e 100644 --- a/src/utils/db-mutex-all-transactions.ts +++ b/src/utils/db-mutex-all-transactions.ts @@ -1,6 +1,6 @@ /* eslint-disable no-param-reassign */ import type { Logger } from 'pino' -import type { Connection } from 'typeorm' +import type { DataSource } from 'typeorm' import { makeMutex } from './generics' /** @@ -9,17 +9,17 @@ import { makeMutex } from './generics' * * to prevent that, we queue each transaction with this wrapper */ -const dbMutexAllTransactions = (db: Connection, logger: Logger) => { +const dbMutexAllTransactions = (ds: DataSource, logger: Logger) => { logger = logger.child({ class: 'transactions' }) const { mutex } = makeMutex() - const { transaction, close } = db + const { transaction, destroy } = ds - db.transaction = (...args: any) => { + ds.transaction = (...args: any) => { if (logger.level === 'trace') logger.trace('called transaction') return mutex(async () => { try { - const result = await transaction.apply(db, args) + const result = await transaction.apply(ds, args) return result } catch (error) { logger.error({ trace: error?.stack }, `error in transaction: ${error}`) @@ -30,8 +30,8 @@ const dbMutexAllTransactions = (db: Connection, logger: Logger) => { }) } - db.close = async () => { - await mutex(() => close.apply(db)) + ds.destroy = async () => { + await mutex(() => destroy.apply(ds)) } } diff --git a/src/utils/download-message.ts b/src/utils/download-message.ts index c8b6dd8f..e379bd6f 100644 --- a/src/utils/download-message.ts +++ b/src/utils/download-message.ts @@ -1,18 +1,18 @@ import { WASocket, downloadMediaMessage, MediaDownloadOptions } from 'baileys' import type { Asset } from '@textshq/platform-sdk' import type { Logger } from 'pino' -import type { Connection } from 'typeorm' +import type { DataSource } from 'typeorm' import DBMessage from '../entities/DBMessage' const downloadMessage = async ( - db: Connection, + ds: DataSource, sock: WASocket, threadID: string, messageID: string, opts: MediaDownloadOptions, logger: Logger, ): Promise => { - const m = await db.getRepository(DBMessage).findOneOrFail({ + const m = await ds.getRepository(DBMessage).findOneByOrFail({ id: messageID, threadID, }) @@ -32,8 +32,8 @@ const downloadMessage = async ( data: result, } } -export const getAttachmentInfo = async (db: Connection, threadID: string, messageID: string): Promise> => { - const m = await db.getRepository(DBMessage).findOneOrFail({ +export const getAttachmentInfo = async (ds: DataSource, threadID: string, messageID: string): Promise> => { + const m = await ds.getRepository(DBMessage).findOneByOrFail({ id: messageID, threadID, }) diff --git a/src/utils/drop-database.ts b/src/utils/drop-database.ts index 0a6e4511..0dc8f82b 100644 --- a/src/utils/drop-database.ts +++ b/src/utils/drop-database.ts @@ -1,12 +1,12 @@ -import type { Connection } from 'typeorm' +import type { DataSource } from 'typeorm' import AccountKeyValue from '../entities/AccountKeyValue' import DBMessage from '../entities/DBMessage' import DBParticipant from '../entities/DBParticipant' import DBThread from '../entities/DBThread' import DBUser from '../entities/DBUser' -export async function dropDatabase(db: Connection) { - await db.transaction(async db => { +export async function dropDatabase(ds: DataSource) { + await ds.transaction(async db => { await db.getRepository(DBThread).clear() await db.getRepository(DBParticipant).clear() await db.getRepository(DBUser).clear() diff --git a/src/utils/fetch-messages.ts b/src/utils/fetch-messages.ts index 842c4fbb..ac47abb1 100644 --- a/src/utils/fetch-messages.ts +++ b/src/utils/fetch-messages.ts @@ -1,4 +1,5 @@ import type { PaginationArg } from '@textshq/platform-sdk' +import { WAMessageStubType } from 'baileys' import DBMessage from '../entities/DBMessage' import DBThread from '../entities/DBThread' import type { MappingContextWithDB } from '../types' @@ -12,6 +13,7 @@ const fetchMessages = async ( mappingCtx: MappingContextWithDB, threadID: string, pagination?: PaginationArg, + senderRetryRequest?: (message: DBMessage) => Promise, ) => { const { db } = mappingCtx const { direction = 'before', cursor } = pagination || {} @@ -40,7 +42,7 @@ const fetchMessages = async ( hasMore = hasMore || items.length >= MESSAGE_PAGE_SIZE if (!hasMore) { - const thread = await db.getRepository(DBThread).findOne({ id: threadID }) + const thread = await db.getRepository(DBThread).findOneBy({ id: threadID }) if (thread?.hasMoreMessageHistory) { items.unshift(getEotMessage(threadID, items[0]?.orderKey || 0, items[0]?.timestamp)) } @@ -49,9 +51,13 @@ const fetchMessages = async ( await remapMessagesAndSave(repo, items, mappingCtx) return { - items: items.map(item => ( - DBMessage.prepareForSending(item, mappingCtx.accountID) - )), + items: items.map(item => { + if (senderRetryRequest && item.original.message.messageStubType === WAMessageStubType.CIPHERTEXT) { + // If there is any message that previously failed to be decrypted, send a retry request now + senderRetryRequest(item) + } + return DBMessage.prepareForSending(item, mappingCtx.accountID) + }), hasMore, oldestCursor: items[0]?.orderKey?.toString(), } diff --git a/src/utils/generics.ts b/src/utils/generics.ts index 3997f35d..b47a0b60 100644 --- a/src/utils/generics.ts +++ b/src/utils/generics.ts @@ -1,7 +1,7 @@ import { ActivityType, Awaitable, ConnectionStatus, Message, ThreadType } from '@textshq/platform-sdk' import { makeEventBuffer, DisconnectReason, extractMessageContent, WAPresence, WAConnectionState, WAGenericMediaMessage, WAMessage, WAMessageKey, jidNormalizedUser, jidDecode, WAProto, isJidBroadcast, normalizeMessageContent, isJidGroup, getContentType, AuthenticationCreds, WAMessageStubType, delay } from 'baileys' import { randomBytes } from 'crypto' -import { In, Repository } from 'typeorm' +import { FindOptionsWhere, In, Repository } from 'typeorm' import type { Logger } from 'pino' import type { MappingContext } from '../types' import type DBThread from '../entities/DBThread' @@ -141,7 +141,7 @@ export async function updateItems< const map: { [jid: string]: D } = { } const jids = updates.map(c => jidNormalizedUser(c.id!)) const dbItems = await repo.find({ - where: { id: In(jids) }, + where: { id: In(jids) } as FindOptionsWhere, }) for (const dbItem of dbItems) { diff --git a/src/utils/get-connection.ts b/src/utils/get-data-source.ts similarity index 66% rename from src/utils/get-connection.ts rename to src/utils/get-data-source.ts index 5daf4ad1..a6f861a0 100644 --- a/src/utils/get-connection.ts +++ b/src/utils/get-data-source.ts @@ -1,14 +1,14 @@ import { texts } from '@textshq/platform-sdk' import type { Logger } from 'pino' -import { ConnectionOptions, createConnection } from 'typeorm' +import { DataSource, DataSourceOptions } from 'typeorm' import { SnakeNamingStrategy } from 'typeorm-naming-strategies' import entities from '../entities' import dbMutexAllTransactions from './db-mutex-all-transactions' const logSql = process.env.LOG_SQL === '1' -const getConnection = async (name: string, sqlitePath: string, logger: Logger) => { - const connection = await createConnection( +const getDataSource = async (name: string, sqlitePath: string, logger: Logger) => { + const dataSource = new DataSource( { name, database: sqlitePath, @@ -19,9 +19,10 @@ const getConnection = async (name: string, sqlitePath: string, logger: Logger) = migrations: [], cli: { migrationsDir: 'src/migrations' }, namingStrategy: new SnakeNamingStrategy(), - } as ConnectionOptions, + } as DataSourceOptions, ) - dbMutexAllTransactions(connection, logger) - return connection + await dataSource.initialize() + dbMutexAllTransactions(dataSource, logger) + return dataSource } -export default getConnection +export default getDataSource diff --git a/src/utils/get-ephemeral-options.ts b/src/utils/get-ephemeral-options.ts index a6b36f27..c2190d73 100644 --- a/src/utils/get-ephemeral-options.ts +++ b/src/utils/get-ephemeral-options.ts @@ -1,7 +1,7 @@ -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' import DBThread from '../entities/DBThread' -export default async (db: Connection | EntityManager, threadID: string) => { - const item = await db.getRepository(DBThread).findOne({ id: threadID }) +export default async (db: DataSource | EntityManager, threadID: string) => { + const item = await db.getRepository(DBThread).findOneBy({ id: threadID }) return item ? { ephemeralExpiration: item.messageExpirySeconds } : undefined } diff --git a/src/utils/get-group-participants-from-db.ts b/src/utils/get-group-participants-from-db.ts index bdee0d73..ecfac521 100644 --- a/src/utils/get-group-participants-from-db.ts +++ b/src/utils/get-group-participants-from-db.ts @@ -1,9 +1,9 @@ -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' import DBThread from '../entities/DBThread' -const getGroupParticipantsFromDB = async (db: Connection | EntityManager, id: string) => { +const getGroupParticipantsFromDB = async (db: DataSource | EntityManager, id: string) => { const repo = db.getRepository(DBThread) - const item = await repo.findOne({ id }) + const item = await repo.findOneBy({ id }) return item?.original.metadata! } diff --git a/src/utils/get-last-messages-of-thread.ts b/src/utils/get-last-messages-of-thread.ts index ef2b65a9..5a4d3374 100644 --- a/src/utils/get-last-messages-of-thread.ts +++ b/src/utils/get-last-messages-of-thread.ts @@ -1,12 +1,12 @@ import { LastMessageList, toNumber } from 'baileys' -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' import DBMessage from '../entities/DBMessage' /** * fetches the last messages of a thread. Required for chat updates + reading chats * The function also ensures that the earliest message returned in the list must be from the other party in the chat (I don't know why, ask WA) */ -const getLastMessagesOfThread = async (db: Connection | EntityManager, threadID: string): Promise => ( +const getLastMessagesOfThread = async (db: DataSource | EntityManager, threadID: string): Promise => ( db.transaction( async em => { const repo = em.getRepository(DBMessage) diff --git a/src/utils/get-message-compose.ts b/src/utils/get-message-compose.ts index 026c15a7..28f09aa4 100644 --- a/src/utils/get-message-compose.ts +++ b/src/utils/get-message-compose.ts @@ -2,14 +2,14 @@ import fsp from 'fs/promises' import { AccountSettings, AnyMediaMessageContent, AnyMessageContent, AnyRegularMessageContent, jidDecode, MiscMessageGenerationOptions, WAMessage } from 'baileys' import { parseVCard } from '@textshq/platform-sdk/dist/vcard' import type { MessageContent, MessageSendOptions } from '@textshq/platform-sdk' -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' import generateMessageID from './generate-message-id' import DBMessage from '../entities/DBMessage' import getEphemeralOptions from './get-ephemeral-options' const getMessageCompose = async ( - db: Connection | EntityManager, + db: DataSource | EntityManager, threadID: string, msgContent: MessageContent, defaultMode: AccountSettings['defaultDisappearingMode'], @@ -80,15 +80,11 @@ const getMessageCompose = async ( let quotedMsg: WAMessage | undefined if (options?.quotedMessageID) { - const msg = await db.getRepository(DBMessage).findOneOrFail({ + const msg = await db.getRepository(DBMessage).findOneByOrFail({ id: options!.quotedMessageID, threadID: options!.quotedMessageThreadID || threadID, }) - if (msg) { - quotedMsg = msg.original.message - } else { - throw new Error('could not find message to quote') - } + quotedMsg = msg.original.message } const ephemeralOpts = await getEphemeralOptions(db, threadID) diff --git a/src/utils/has-some-cached-data.ts b/src/utils/has-some-cached-data.ts index 1d50844b..b166eba0 100644 --- a/src/utils/has-some-cached-data.ts +++ b/src/utils/has-some-cached-data.ts @@ -1,8 +1,8 @@ -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' import DBMessage from '../entities/DBMessage' import DBThread from '../entities/DBThread' -export default async (db: Connection | EntityManager) => ({ +export default async (db: DataSource | EntityManager) => ({ hasChats: !!(await db.getRepository(DBThread).count({ take: 1 })), hasMessages: !!(await db.getRepository(DBMessage).count({ take: 1 })), }) diff --git a/src/utils/make-texts-baileys-store.ts b/src/utils/make-texts-baileys-store.ts index c3e6403c..a1e3572a 100644 --- a/src/utils/make-texts-baileys-store.ts +++ b/src/utils/make-texts-baileys-store.ts @@ -1,6 +1,6 @@ import { WASocket, BaileysEvent, BaileysEventMap, Chat, Contact, GroupMetadata, isJidGroup, isJidUser, jidNormalizedUser, toNumber, unixTimestampSeconds, WAMessageKey, WAMessageStubType, WAMessageStatus, isJidStatusBroadcast, getChatId } from 'baileys' import { Awaitable, MessageBehavior, ServerEvent, ServerEventType, texts } from '@textshq/platform-sdk' -import { Connection, EntityManager, EntityTarget, In, IsNull, MoreThan } from 'typeorm' +import { DataSource, EntityManager, EntityTarget, In, IsNull, MoreThan } from 'typeorm' import DBMessage from '../entities/DBMessage' import DBParticipant from '../entities/DBParticipant' import DBThread from '../entities/DBThread' @@ -454,7 +454,7 @@ async function handleMessagesDelete( if ('all' in item) { // isn't supported yet } else { - const msgs = await repo.find({ id: In(item.keys.map(mapMessageID)) }) + const msgs = await repo.find({ where: { id: In(item.keys.map(mapMessageID)) } }) if (excludeEvent) { for (const msg of msgs) { msg.shouldFireEvent = false @@ -544,7 +544,7 @@ async function updateMessages( // execute those updates const threadIds = Object.keys(readMsgsUpdateMap) if (threadIds.length) { - const chats = await chatRepo.find({ id: In(threadIds), unreadCount: MoreThan(0) }) + const chats = await chatRepo.find({ where: { id: In(threadIds), unreadCount: MoreThan(0) } }) for (const chat of chats) { // if the chat had unread messages chat.updateWithDecrementingUnreadCount(readMsgsUpdateMap[chat.id], ctx) @@ -592,7 +592,7 @@ async function handleMessagesSync( logger.info({ messages: dbMessages.length }, 'saved message history') } -export const fetchMessagesInDB = async (db: Connection | EntityManager, keys: { key: WAMessageKey }[]) => { +export const fetchMessagesInDB = async (db: DataSource | EntityManager, keys: { key: WAMessageKey }[]) => { const repo = db.getRepository(DBMessage) const uqIds = keys.map(({ key }) => { const msgId = mapMessageID(key) @@ -616,7 +616,7 @@ async function handleGroupParticipantsUpdate( const threadRepo = db.getRepository(DBThread) const participantRepo = db.getRepository(DBParticipant) - const thread = await threadRepo.findOne({ id: threadID }) + const thread = await threadRepo.findOneBy({ id: threadID }) logger.debug({ threadID, participants, action }, 'updating participants') if (thread) { @@ -672,7 +672,7 @@ async function handleChatsDelete( ) { const repo = db.getRepository(DBThread) const msgRepo = db.getRepository(DBMessage) - const chats = await repo.find({ id: In(ids) }) + const chats = await repo.find({ where: { id: In(ids) } }) if (excludeEvent) { for (const chat of chats) { chat.shouldFireEvent = false diff --git a/src/utils/read-chat.ts b/src/utils/read-chat.ts index 09afd3aa..59fb76e5 100644 --- a/src/utils/read-chat.ts +++ b/src/utils/read-chat.ts @@ -1,5 +1,5 @@ import type { WASocket } from 'baileys' -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' import DBMessage from '../entities/DBMessage' import DBThread from '../entities/DBThread' import type { MappingContext } from '../types' @@ -8,9 +8,9 @@ import getLastMessagesOfThread from './get-last-messages-of-thread' /** * utility function to mark a chat read */ -const readChat = async (db: Connection | EntityManager, sock: WASocket, ctx: MappingContext, threadID: string, messageID?: string) => { +const readChat = async (db: DataSource | EntityManager, sock: WASocket, ctx: MappingContext, threadID: string, messageID?: string) => { const repo = db.getRepository(DBThread) - const item = await repo.findOne({ id: threadID }) + const item = await repo.findOneBy({ id: threadID }) if (item) { if (item.unreadCount > 0) { diff --git a/src/utils/register-db-subscribers.ts b/src/utils/register-db-subscribers.ts index 3e8c8859..af6bc5ab 100644 --- a/src/utils/register-db-subscribers.ts +++ b/src/utils/register-db-subscribers.ts @@ -1,5 +1,5 @@ import { ServerEvent, ServerEventType } from '@textshq/platform-sdk' -import type { Connection } from 'typeorm' +import type { DataSource } from 'typeorm' import DBMessage from '../entities/DBMessage' import DBParticipant from '../entities/DBParticipant' import DBThread from '../entities/DBThread' @@ -15,7 +15,7 @@ const registerDBSubscribers = ( publishEvent: (event: ServerEvent) => void, ctx: MappingContextWithDB, ) => { - const db = ctx.db as Connection + const db = ctx.db as DataSource const { logger } = ctx db.subscribers.push( new DBEventsPublisher(DBThread, { diff --git a/src/utils/resync-history.ts b/src/utils/resync-history.ts index 0bd2e2f5..649b08bb 100644 --- a/src/utils/resync-history.ts +++ b/src/utils/resync-history.ts @@ -1,10 +1,10 @@ import { texts } from '@textshq/platform-sdk' -import type { Connection, EntityManager } from 'typeorm' +import type { DataSource, EntityManager } from 'typeorm' import DBMessage from '../entities/DBMessage' /// runs history sync using the stored history messages in the DB /// only for dev usage -const resyncHistory = async (db: Connection | EntityManager) => { +const resyncHistory = async (db: DataSource | EntityManager) => { const repo = db.getRepository(DBMessage) const msgs = await repo.find({ where: { diff --git a/src/utils/set-participant-users.ts b/src/utils/set-participant-users.ts index 45673a77..f0d86255 100644 --- a/src/utils/set-participant-users.ts +++ b/src/utils/set-participant-users.ts @@ -1,9 +1,9 @@ -import { Connection, EntityManager, In } from 'typeorm' +import { DataSource, EntityManager, In } from 'typeorm' import type DBParticipant from '../entities/DBParticipant' import DBUser from '../entities/DBUser' -const setParticipantUsers = async (db: Connection | EntityManager, participants: DBParticipant[]) => { - const users = await db.getRepository(DBUser).find({ id: In(participants.map(p => p.id)) }) +const setParticipantUsers = async (db: DataSource | EntityManager, participants: DBParticipant[]) => { + const users = await db.getRepository(DBUser).find({ where: { id: In(participants.map(p => p.id)) } }) const userMap = users.reduce((dict, user) => { dict[user.id] = user return dict diff --git a/yarn.lock b/yarn.lock index 64360145..3f0c1c1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1445,6 +1445,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.21.0": + version: 7.23.6 + resolution: "@babel/runtime@npm:7.23.6" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: 1a8eaf3d3a103ef5227b60ca7ab5c589118c36ca65ef2d64e65380b32a98a3f3b5b3ef96660fa0471b079a18b619a8317f3e7f03ab2b930c45282a8b69ed9a16 + languageName: node + linkType: hard + "@babel/template@npm:^7.18.10, @babel/template@npm:^7.3.3": version: 7.18.10 resolution: "@babel/template@npm:7.18.10" @@ -2500,7 +2509,7 @@ __metadata: languageName: node linkType: hard -"@sqltools/formatter@npm:^1.2.2": +"@sqltools/formatter@npm:^1.2.5": version: 1.2.5 resolution: "@sqltools/formatter@npm:1.2.5" checksum: 9b8354e715467d660daa5afe044860b5686bbb1a5cb67a60866b932effafbf5e8b429f19a8ae67cd412065a4f067161f227e182f3664a0245339d5eb1e26e355 @@ -2559,7 +2568,7 @@ __metadata: sanitize-filename: ^1.6.3 ts-jest: ^29.0.5 ts-node: ^10.9.1 - typeorm: ^0.2.41 + typeorm: ^0.3.17 typeorm-naming-strategies: ^2.0.0 typescript: ^5.0.2 languageName: unknown @@ -3166,7 +3175,7 @@ __metadata: languageName: node linkType: hard -"app-root-path@npm:^3.0.0": +"app-root-path@npm:^3.1.0": version: 3.1.0 resolution: "app-root-path@npm:3.1.0" checksum: e3db3957aee197143a0f6c75e39fe89b19e7244f28b4f2944f7276a9c526d2a7ab2d115b4b2d70a51a65a9a3ca17506690e5b36f75a068a7e5a13f8c092389ba @@ -3508,7 +3517,7 @@ __metadata: "baileys@https://github.com/TextsHQ/baileys#master": version: 6.5.0 - resolution: "baileys@https://github.com/TextsHQ/baileys.git#commit=965823e7739f5d8fb9c9b99c67951a7101febe81" + resolution: "baileys@https://github.com/TextsHQ/baileys.git#commit=d138eee19b08cbc4e02f8256e8461af0d1c235e9" dependencies: "@adiwajshing/keyed-db": ^0.2.4 "@hapi/boom": ^9.1.3 @@ -3538,7 +3547,7 @@ __metadata: optional: true sharp: optional: true - checksum: 3cfd76369298cc2e5d39908d00e66490db8d57359c11764925d2db76d5356ff8a3add24ae659564900609c177ef76071927fbc073c777317a6e13790c03381e6 + checksum: e15cea21f31d567d553e4d35aa0fcd7368801ca084cc59ce124dcd7314879763a8337496300069a2d44d559fe30af8a0add9fe53fe13e1a7d801fb336f243236 languageName: node linkType: hard @@ -3780,7 +3789,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0, chalk@npm:^4.1.0": +"chalk@npm:^4.0.0, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: @@ -4108,7 +4117,16 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": +"date-fns@npm:^2.29.3": + version: 2.30.0 + resolution: "date-fns@npm:2.30.0" + dependencies: + "@babel/runtime": ^7.21.0 + checksum: f7be01523282e9bb06c0cd2693d34f245247a29098527d4420628966a2d9aad154bd0e90a6b1cf66d37adcb769cd108cf8a7bd49d76db0fb119af5cdd13644f4 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -4306,10 +4324,10 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:^8.2.0": - version: 8.6.0 - resolution: "dotenv@npm:8.6.0" - checksum: 38e902c80b0666ab59e9310a3d24ed237029a7ce34d976796349765ac96b8d769f6df19090f1f471b77a25ca391971efde8a1ea63bb83111bd8bec8e5cc9b2cd +"dotenv@npm:^16.0.3": + version: 16.3.1 + resolution: "dotenv@npm:16.3.1" + checksum: 15d75e7279018f4bafd0ee9706593dd14455ddb71b3bcba9c52574460b7ccaf67d5cf8b2c08a5af1a9da6db36c956a04a1192b101ee102a3e0cf8817bbcf3dfd languageName: node linkType: hard @@ -5286,7 +5304,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^7.1.3, glob@npm:^7.1.4": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -5313,6 +5331,19 @@ __metadata: languageName: node linkType: hard +"glob@npm:^8.1.0": + version: 8.1.0 + resolution: "glob@npm:8.1.0" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^5.0.1 + once: ^1.3.0 + checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 + languageName: node + linkType: hard + "global@npm:~4.4.0": version: 4.4.0 resolution: "global@npm:4.4.0" @@ -6355,7 +6386,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^4.0.0, js-yaml@npm:^4.1.0": +"js-yaml@npm:^4.1.0": version: 4.1.0 resolution: "js-yaml@npm:4.1.0" dependencies: @@ -6916,6 +6947,15 @@ __metadata: languageName: node linkType: hard +"mkdirp@npm:^2.1.3": + version: 2.1.6 + resolution: "mkdirp@npm:2.1.6" + bin: + mkdirp: dist/cjs/src/bin.js + checksum: 8a1d09ffac585e55f41c54f445051f5bc33a7de99b952bb04c576cafdf1a67bb4bae8cb93736f7da6838771fbf75bc630430a3a59e1252047d2278690bd150ee + languageName: node + linkType: hard + "mpg123-decoder@npm:^0.4.8": version: 0.4.8 resolution: "mpg123-decoder@npm:0.4.8" @@ -7905,6 +7945,13 @@ __metadata: languageName: node linkType: hard +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 9f57c93277b5585d3c83b0cf76be47b473ae8c6d9142a46ce8b0291a04bb2cf902059f0f8445dcabb3fb7378e5fe4bb4ea1e008876343d42e46d3b484534ce38 + languageName: node + linkType: hard + "regenerator-transform@npm:^0.15.0": version: 0.15.0 resolution: "regenerator-transform@npm:0.15.0" @@ -8758,13 +8805,20 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.2.0": +"tslib@npm:^2.2.0": version: 2.4.0 resolution: "tslib@npm:2.4.0" checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 languageName: node linkType: hard +"tslib@npm:^2.5.0": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -8824,44 +8878,46 @@ __metadata: languageName: node linkType: hard -"typeorm@npm:^0.2.41": - version: 0.2.45 - resolution: "typeorm@npm:0.2.45" +"typeorm@npm:^0.3.17": + version: 0.3.17 + resolution: "typeorm@npm:0.3.17" dependencies: - "@sqltools/formatter": ^1.2.2 - app-root-path: ^3.0.0 + "@sqltools/formatter": ^1.2.5 + app-root-path: ^3.1.0 buffer: ^6.0.3 - chalk: ^4.1.0 + chalk: ^4.1.2 cli-highlight: ^2.1.11 - debug: ^4.3.1 - dotenv: ^8.2.0 - glob: ^7.1.6 - js-yaml: ^4.0.0 - mkdirp: ^1.0.4 + date-fns: ^2.29.3 + debug: ^4.3.4 + dotenv: ^16.0.3 + glob: ^8.1.0 + mkdirp: ^2.1.3 reflect-metadata: ^0.1.13 sha.js: ^2.4.11 - tslib: ^2.1.0 - uuid: ^8.3.2 - xml2js: ^0.4.23 - yargs: ^17.0.1 - zen-observable-ts: ^1.0.0 - peerDependencies: - "@sap/hana-client": ^2.11.14 - better-sqlite3: ^7.1.2 + tslib: ^2.5.0 + uuid: ^9.0.0 + yargs: ^17.6.2 + peerDependencies: + "@google-cloud/spanner": ^5.18.0 + "@sap/hana-client": ^2.12.25 + better-sqlite3: ^7.1.2 || ^8.0.0 hdb-pool: ^0.1.6 - ioredis: ^4.28.3 - mongodb: ^3.6.0 - mssql: ^6.3.1 - mysql2: ^2.2.5 + ioredis: ^5.0.4 + mongodb: ^5.2.0 + mssql: ^9.1.1 + mysql2: ^2.2.5 || ^3.0.1 oracledb: ^5.1.0 pg: ^8.5.1 pg-native: ^3.0.0 pg-query-stream: ^4.0.0 - redis: ^3.1.1 + redis: ^3.1.1 || ^4.0.0 sql.js: ^1.4.0 - sqlite3: ^5.0.2 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 typeorm-aurora-data-api-driver: ^2.0.0 peerDependenciesMeta: + "@google-cloud/spanner": + optional: true "@sap/hana-client": optional: true better-sqlite3: @@ -8890,11 +8946,15 @@ __metadata: optional: true sqlite3: optional: true + ts-node: + optional: true typeorm-aurora-data-api-driver: optional: true bin: typeorm: cli.js - checksum: b7684a52c8ba3b796fb9f7d9ea6223edd9256dbeec67c4befe39515ce684dd684d82a2d53158b738555f5c964efaf09144bdd3ced046638e89aa46483d9a696b + typeorm-ts-node-commonjs: cli-ts-node-commonjs.js + typeorm-ts-node-esm: cli-ts-node-esm.js + checksum: 71fcb2b2e889c759b24add6c6ab7938c9a52f7c206b055f3a2abd77725acfec125b8f303e263381258ee03e52f7d3eb88c1fb893b15750b5237c8fc9db31ed78 languageName: node linkType: hard @@ -9035,15 +9095,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df - languageName: node - linkType: hard - "uuid@npm:^9.0.0": version: 9.0.1 resolution: "uuid@npm:9.0.1" @@ -9199,7 +9250,7 @@ __metadata: languageName: node linkType: hard -"xml2js@npm:^0.4.23, xml2js@npm:^0.4.5": +"xml2js@npm:^0.4.5": version: 0.4.23 resolution: "xml2js@npm:0.4.23" dependencies: @@ -9251,7 +9302,7 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.0.0, yargs-parser@npm:^21.0.1": +"yargs-parser@npm:^21.0.0, yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c @@ -9273,7 +9324,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.0.1, yargs@npm:^17.3.1": +"yargs@npm:^17.3.1": version: 17.6.0 resolution: "yargs@npm:17.6.0" dependencies: @@ -9288,6 +9339,21 @@ __metadata: languageName: node linkType: hard +"yargs@npm:^17.6.2": + version: 17.7.2 + resolution: "yargs@npm:17.7.2" + dependencies: + cliui: ^8.0.1 + escalade: ^3.1.1 + get-caller-file: ^2.0.5 + require-directory: ^2.1.1 + string-width: ^4.2.3 + y18n: ^5.0.5 + yargs-parser: ^21.1.1 + checksum: 73b572e863aa4a8cbef323dd911d79d193b772defd5a51aab0aca2d446655216f5002c42c5306033968193bdbf892a7a4c110b0d77954a7fdf563e653967b56a + languageName: node + linkType: hard + "yn@npm:3.1.1": version: 3.1.1 resolution: "yn@npm:3.1.1" @@ -9301,19 +9367,3 @@ __metadata: checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard - -"zen-observable-ts@npm:^1.0.0": - version: 1.2.5 - resolution: "zen-observable-ts@npm:1.2.5" - dependencies: - zen-observable: 0.8.15 - checksum: 3b707b7a0239a9bc40f73ba71b27733a689a957c1f364fabb9fa9cbd7d04b7c2faf0d517bf17004e3ed3f4330ac613e84c0d32313e450ddaa046f3350af44541 - languageName: node - linkType: hard - -"zen-observable@npm:0.8.15": - version: 0.8.15 - resolution: "zen-observable@npm:0.8.15" - checksum: b7289084bc1fc74a559b7259faa23d3214b14b538a8843d2b001a35e27147833f4107590b1b44bf5bc7f6dfe6f488660d3a3725f268e09b3925b3476153b7821 - languageName: node - linkType: hard