From 46823597699a853310961f1241602ce817706372 Mon Sep 17 00:00:00 2001 From: alina sireneva Date: Fri, 22 Nov 2024 01:13:09 +0300 Subject: [PATCH] feat(core)!: timers! breaking: setOffline renamed to sendOnline --- package.json | 4 +- packages/bun/package.json | 8 +- packages/convert/package.json | 4 +- packages/core/package.json | 6 +- packages/core/src/highlevel/base.ts | 7 +- packages/core/src/highlevel/client.ts | 66 ++++++- packages/core/src/highlevel/client.types.ts | 2 + .../core/src/highlevel/managers/timers.ts | 50 +++++ packages/core/src/highlevel/methods.ts | 4 +- .../methods/messages/forward-messages.ts | 3 + .../highlevel/methods/messages/send-common.ts | 3 + .../highlevel/methods/messages/send-typing.ts | 96 +++++----- .../highlevel/methods/messages/set-typing.ts | 91 +++++++++ .../highlevel/methods/users/set-offline.ts | 13 -- .../src/highlevel/methods/users/set-online.ts | 45 +++++ packages/core/src/highlevel/worker/port.ts | 11 +- .../core/src/network/persistent-connection.ts | 1 + .../core/src/network/session-connection.ts | 1 + packages/deno/package.json | 6 +- packages/dispatcher/package.json | 2 +- packages/file-id/package.json | 2 +- packages/node/package.json | 6 +- packages/test/package.json | 4 +- packages/tl-runtime/package.json | 2 +- packages/tl/package.json | 4 +- packages/wasm/package.json | 2 +- packages/web/package.json | 2 +- pnpm-lock.yaml | 174 +++++++++--------- 28 files changed, 435 insertions(+), 184 deletions(-) create mode 100644 packages/core/src/highlevel/managers/timers.ts create mode 100644 packages/core/src/highlevel/methods/messages/set-typing.ts delete mode 100644 packages/core/src/highlevel/methods/users/set-offline.ts create mode 100644 packages/core/src/highlevel/methods/users/set-online.ts diff --git a/package.json b/package.json index 70f4c901..42752970 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,8 @@ }, "devDependencies": { "@antfu/eslint-config": "2.26.0", - "@fuman/build": "https://pkg.pr.new/teidesu/fuman/@fuman/build@a3f52dc", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", + "@fuman/build": "https://pkg.pr.new/teidesu/fuman/@fuman/build@6017eb4", + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", "@types/deno": "npm:@teidesu/deno-types@1.46.3", "@types/node": "20.10.0", "@types/ws": "8.5.4", diff --git a/packages/bun/package.json b/packages/bun/package.json index cdfcfd17..f22954e0 100644 --- a/packages/bun/package.json +++ b/packages/bun/package.json @@ -17,10 +17,10 @@ "@mtcute/html-parser": "workspace:^", "@mtcute/markdown-parser": "workspace:^", "@mtcute/wasm": "workspace:^", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", - "@fuman/bun": "https://pkg.pr.new/teidesu/fuman/@fuman/bun@a3f52dc", - "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc", - "@fuman/io": "https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc" + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", + "@fuman/bun": "https://pkg.pr.new/teidesu/fuman/@fuman/bun@6017eb4", + "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4", + "@fuman/io": "https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4" }, "devDependencies": { "@mtcute/test": "workspace:^" diff --git a/packages/convert/package.json b/packages/convert/package.json index 2232b448..9b0fb642 100644 --- a/packages/convert/package.json +++ b/packages/convert/package.json @@ -10,8 +10,8 @@ "exports": "./src/index.ts", "dependencies": { "@mtcute/core": "workspace:^", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", - "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc" + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", + "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4" }, "devDependencies": { "@mtcute/test": "workspace:^" diff --git a/packages/core/package.json b/packages/core/package.json index e0d77ad3..9fb39bf1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -19,9 +19,9 @@ "gen-updates": "node ./scripts/generate-updates.cjs" }, "dependencies": { - "@fuman/io": "https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc", - "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", + "@fuman/io": "https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4", + "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4", + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", "@mtcute/file-id": "workspace:^", "@mtcute/tl": "workspace:^", "@mtcute/tl-runtime": "workspace:^", diff --git a/packages/core/src/highlevel/base.ts b/packages/core/src/highlevel/base.ts index ffb8904a..7cb8995a 100644 --- a/packages/core/src/highlevel/base.ts +++ b/packages/core/src/highlevel/base.ts @@ -1,7 +1,7 @@ import type { mtp } from '@mtcute/tl' import { tl } from '@mtcute/tl' import type Long from 'long' -import { Emitter } from '@fuman/utils' +import { Emitter, unknownToError } from '@fuman/utils' import type { MtClientOptions } from '../network/client.js' import { MtClient } from '../network/client.js' @@ -32,6 +32,7 @@ import type { TelegramStorageManagerExtraOptions } from './storage/storage.js' import { TelegramStorageManager } from './storage/storage.js' import { UpdatesManager } from './updates/manager.js' import type { RawUpdateInfo, UpdatesManagerParams } from './updates/types.js' +import { TimersManager } from './managers/timers.js' export interface BaseTelegramClientOptions extends MtClientOptions { storage: ITelegramStorageProvider @@ -57,6 +58,7 @@ export class BaseTelegramClient implements ITelegramClient { readonly crypto: ICryptoProvider readonly storage: TelegramStorageManager readonly platform: ICorePlatform + readonly timers: TimersManager readonly onServerUpdate: Emitter = new Emitter() readonly onRawUpdate: Emitter = new Emitter() @@ -92,6 +94,8 @@ export class BaseTelegramClient implements ITelegramClient { provider: this.params.storage, ...this.params.storageOptions, }) + this.timers = new TimersManager() + this.timers.onError(err => this.onError.emit(unknownToError(err))) } readonly appConfig: AppConfigManager = new AppConfigManager(this) @@ -142,6 +146,7 @@ export class BaseTelegramClient implements ITelegramClient { } async close(): Promise { + this.timers.destroy() this._connected = false await this.mt.close() this.updates?.stopLoop() diff --git a/packages/core/src/highlevel/client.ts b/packages/core/src/highlevel/client.ts index 055ef912..87b29f82 100644 --- a/packages/core/src/highlevel/client.ts +++ b/packages/core/src/highlevel/client.ts @@ -197,6 +197,7 @@ import { sendScheduled } from './methods/messages/send-scheduled.js' import { sendText } from './methods/messages/send-text.js' import { sendTyping } from './methods/messages/send-typing.js' import { sendVote } from './methods/messages/send-vote.js' +import { setTyping } from './methods/messages/set-typing.js' import { translateMessage } from './methods/messages/translate-message.js' import { translateText } from './methods/messages/translate-text.js' import { unpinAllMessages } from './methods/messages/unpin-all-messages.js' @@ -279,7 +280,7 @@ import { setGlobalTtl } from './methods/users/set-global-ttl.js' import { setMyBirthday } from './methods/users/set-my-birthday.js' import { setMyProfilePhoto } from './methods/users/set-my-profile-photo.js' import { setMyUsername } from './methods/users/set-my-username.js' -import { setOffline } from './methods/users/set-offline.js' +import { setOffline, setOnline } from './methods/users/set-online.js' import { unblockUser } from './methods/users/unblock-user.js' import { updateProfile } from './methods/users/update-profile.js' import { withParams } from './methods/misc/with-params.js' @@ -995,6 +996,13 @@ export interface TelegramClient extends ITelegramClient { params: { userId: InputPeerLike result: InputInlineResult + + /** + * Filters for the client to use when prompting the user for the + * chat to send the inline message to. + * + * Note that this is just a hint for the client, and the client is free to ignore it. + */ filter?: tl.TypeInlineQueryPeerType[] | { /** private chat with the bot itself */ botSelf?: boolean @@ -1002,8 +1010,11 @@ export interface TelegramClient extends ITelegramClient { private?: boolean /** private chats with other bots */ bots?: boolean + /** "basic" chats */ chats?: boolean + /** supergroups */ supergroups?: boolean + /** broadcast channels */ channels?: boolean } }): Promise @@ -4200,6 +4211,7 @@ export interface TelegramClient extends ITelegramClient { * @param chatId Chat ID * @param [status='typing'] Typing status * @param params + * @deprecated - use {@link setTyping} instead */ sendTyping( chatId: InputPeerLike, status?: Exclude | tl.TypeSendMessageAction, @@ -4234,6 +4246,40 @@ export interface TelegramClient extends ITelegramClient { */ options: null | MaybeArray }): Promise + /** + * Sets whether a user is typing in a specific chat + * + * This status is automatically renewed by mtcute until a further + * call with `sendMessageCancelAction` is made, or a message is sent to the chat. + * **Available**: ✅ both users and bots + * + */ + setTyping( + params: { + /** Chat ID where the user is currently typing */ + peerId: InputPeerLike + /** + * Typing status to send (false is a shortcut for `{ _: 'sendMessageCancelAction' }`) + * + * @default `{ _: 'sendMessageTypingAction' }` + */ + status?: tl.TypeSendMessageAction | false + + /** + * For `upload_*` and history import actions, progress of the upload + */ + progress?: number + + /** + * Unique identifier of the business connection on behalf of which the action will be sent + */ + businessConnectionId?: string + + /** + * For comment threads, ID of the thread (i.e. top message) + */ + threadId?: number + }): Promise /** * Translate message text to a given language. * @@ -5709,8 +5755,20 @@ export interface TelegramClient extends ITelegramClient { * **Available**: 👤 users only * * @param [offline=true] Whether the user is currently offline + * @deprecated - use {@link setOnline} instead */ setOffline(offline?: boolean): Promise + /** + * Change user status to online or offline + * + * Once called with `true`, mtcute will keep notifying the server + * that the user is still online until a further call with `false` is made. + * + * **Available**: 👤 users only + * + * @param [online=true] + */ + setOnline(online?: boolean): Promise /** * Unblock a user * @@ -6452,6 +6510,9 @@ TelegramClient.prototype.sendTyping = function (...args) { TelegramClient.prototype.sendVote = function (...args) { return sendVote(this._client, ...args) } +TelegramClient.prototype.setTyping = function (...args) { + return setTyping(this._client, ...args) +} TelegramClient.prototype.translateMessage = function (...args) { return translateMessage(this._client, ...args) } @@ -6721,6 +6782,9 @@ TelegramClient.prototype.setMyUsername = function (...args) { TelegramClient.prototype.setOffline = function (...args) { return setOffline(this._client, ...args) } +TelegramClient.prototype.setOnline = function (...args) { + return setOnline(this._client, ...args) +} TelegramClient.prototype.unblockUser = function (...args) { return unblockUser(this._client, ...args) } diff --git a/packages/core/src/highlevel/client.types.ts b/packages/core/src/highlevel/client.types.ts index 531451e4..f1a5808d 100644 --- a/packages/core/src/highlevel/client.types.ts +++ b/packages/core/src/highlevel/client.types.ts @@ -11,6 +11,7 @@ import type { AppConfigManager } from './managers/app-config-manager.js' import type { TelegramStorageManager } from './storage/storage.js' import type { StringSessionData } from './utils/string-session.js' import type { RawUpdateInfo } from './updates/types.js' +import type { TimersManager } from './managers/timers.js' /** * Connection state of the client @@ -34,6 +35,7 @@ export interface ITelegramClient { readonly log: Logger readonly storage: PublicPart readonly appConfig: PublicPart + readonly timers: Pick readonly stopSignal: AbortSignal readonly platform: ICorePlatform diff --git a/packages/core/src/highlevel/managers/timers.ts b/packages/core/src/highlevel/managers/timers.ts new file mode 100644 index 00000000..0a5da3c9 --- /dev/null +++ b/packages/core/src/highlevel/managers/timers.ts @@ -0,0 +1,50 @@ +import { AsyncInterval } from '@fuman/utils' + +export class TimersManager { + private _timers: Map = new Map() + private _errorHandler?: (err: unknown) => void + + constructor() {} + + exists(key: string): boolean { + return this._timers.has(key) + } + + create( + key: string, + handler: (abortSignal: AbortSignal) => Promise, + interval: number, + startNow = false, + ): void { + if (this._timers.has(key)) { + return + } + + const timer = new AsyncInterval(handler, interval) + if (this._errorHandler) timer.onError(this._errorHandler) + this._timers.set(key, timer) + + if (startNow) timer.startNow() + else timer.start() + } + + cancel(key: string): void { + const timer = this._timers.get(key) + + if (!timer) return + + timer.stop() + this._timers.delete(key) + } + + onError(handler: (err: unknown) => void): void { + this._errorHandler = handler + } + + destroy(): void { + for (const timer of this._timers.values()) { + timer.stop() + } + this._timers.clear() + } +} diff --git a/packages/core/src/highlevel/methods.ts b/packages/core/src/highlevel/methods.ts index 122f6074..d658df57 100644 --- a/packages/core/src/highlevel/methods.ts +++ b/packages/core/src/highlevel/methods.ts @@ -191,6 +191,7 @@ export { sendScheduled } from './methods/messages/send-scheduled.js' export { sendText } from './methods/messages/send-text.js' export { sendTyping } from './methods/messages/send-typing.js' export { sendVote } from './methods/messages/send-vote.js' +export { setTyping } from './methods/messages/set-typing.js' export { translateMessage } from './methods/messages/translate-message.js' export { translateText } from './methods/messages/translate-text.js' export { unpinAllMessages } from './methods/messages/unpin-all-messages.js' @@ -281,6 +282,7 @@ export { setGlobalTtl } from './methods/users/set-global-ttl.js' export { setMyBirthday } from './methods/users/set-my-birthday.js' export { setMyProfilePhoto } from './methods/users/set-my-profile-photo.js' export { setMyUsername } from './methods/users/set-my-username.js' -export { setOffline } from './methods/users/set-offline.js' +export { setOffline } from './methods/users/set-online.js' +export { setOnline } from './methods/users/set-online.js' export { unblockUser } from './methods/users/unblock-user.js' export { updateProfile } from './methods/users/update-profile.js' diff --git a/packages/core/src/highlevel/methods/messages/forward-messages.ts b/packages/core/src/highlevel/methods/messages/forward-messages.ts index 8fd81a8f..498959a6 100644 --- a/packages/core/src/highlevel/methods/messages/forward-messages.ts +++ b/packages/core/src/highlevel/methods/messages/forward-messages.ts @@ -8,6 +8,7 @@ import { normalizeDate } from '../../utils/misc-utils.js' import { resolvePeer } from '../users/resolve-peer.js' import { _normalizeQuickReplyShortcut } from './send-common.js' +import { _getTypingTimerId } from './set-typing.js' // @exported export interface ForwardMessageOptions { @@ -120,6 +121,8 @@ export async function forwardMessagesById( const toPeer = await resolvePeer(client, toChatId) + client.timers.cancel(_getTypingTimerId(toPeer)) + const res = await client.call({ _: 'messages.forwardMessages', toPeer, diff --git a/packages/core/src/highlevel/methods/messages/send-common.ts b/packages/core/src/highlevel/methods/messages/send-common.ts index f3fd3e09..b2f36eec 100644 --- a/packages/core/src/highlevel/methods/messages/send-common.ts +++ b/packages/core/src/highlevel/methods/messages/send-common.ts @@ -13,6 +13,7 @@ import { resolvePeer } from '../users/resolve-peer.js' import { _getDiscussionMessage } from './get-discussion-message.js' import { getMessages } from './get-messages.js' +import { _getTypingTimerId } from './set-typing.js' // @exported export interface CommonSendParams { @@ -172,6 +173,8 @@ export async function _processCommonSendParameters( }> { let peer = await resolvePeer(client, chatId) + client.timers.cancel(_getTypingTimerId(peer, params.businessConnectionId)) + let replyTo = normalizeMessageId(params.replyTo) const replyToPeer = typeof params.replyTo === 'number' ? undefined : params.replyTo?.chat.inputPeer diff --git a/packages/core/src/highlevel/methods/messages/send-typing.ts b/packages/core/src/highlevel/methods/messages/send-typing.ts index 86b9a108..072ffe17 100644 --- a/packages/core/src/highlevel/methods/messages/send-typing.ts +++ b/packages/core/src/highlevel/methods/messages/send-typing.ts @@ -8,6 +8,45 @@ import { resolvePeer } from '../users/resolve-peer.js' import { _maybeInvokeWithBusinessConnection } from './_business-connection.js' +export function _mapTypingStatus(status: Exclude, progress: number = 0): tl.TypeSendMessageAction { + switch (status) { + case 'typing': + return { _: 'sendMessageTypingAction' } + case 'cancel': + return { _: 'sendMessageCancelAction' } + case 'record_video': + return { _: 'sendMessageRecordVideoAction' } + case 'upload_video': + return { _: 'sendMessageUploadVideoAction', progress } + case 'record_voice': + return { _: 'sendMessageRecordAudioAction' } + case 'upload_voice': + return { _: 'sendMessageUploadAudioAction', progress } + case 'upload_photo': + return { _: 'sendMessageUploadPhotoAction', progress } + case 'upload_document': + return { _: 'sendMessageUploadDocumentAction', progress } + case 'geo': + return { _: 'sendMessageGeoLocationAction' } + case 'contact': + return { _: 'sendMessageChooseContactAction' } + case 'game': + return { _: 'sendMessageGamePlayAction' } + case 'record_round': + return { _: 'sendMessageRecordRoundAction' } + case 'upload_round': + return { _: 'sendMessageUploadRoundAction', progress } + case 'speak_call': + return { _: 'speakingInGroupCallAction' } + case 'history_import': + return { _: 'sendMessageHistoryImportAction', progress } + case 'sticker': + return { _: 'sendMessageChooseStickerAction' } + default: + assertNever(status) + } +} + /** * Sends a current user/bot typing event * to a conversation partner or group. @@ -16,6 +55,8 @@ import { _maybeInvokeWithBusinessConnection } from './_business-connection.js' * automatically cancelled if you send a * message. * + * If you need a continuous typing status, use {@link setTyping} instead. + * * @param chatId Chat ID * @param status Typing status * @param params @@ -42,60 +83,7 @@ export async function sendTyping( }, ): Promise { if (typeof status === 'string') { - const progress = params?.progress ?? 0 - - switch (status) { - case 'typing': - status = { _: 'sendMessageTypingAction' } - break - case 'cancel': - status = { _: 'sendMessageCancelAction' } - break - case 'record_video': - status = { _: 'sendMessageRecordVideoAction' } - break - case 'upload_video': - status = { _: 'sendMessageUploadVideoAction', progress } - break - case 'record_voice': - status = { _: 'sendMessageRecordAudioAction' } - break - case 'upload_voice': - status = { _: 'sendMessageUploadAudioAction', progress } - break - case 'upload_photo': - status = { _: 'sendMessageUploadPhotoAction', progress } - break - case 'upload_document': - status = { _: 'sendMessageUploadDocumentAction', progress } - break - case 'geo': - status = { _: 'sendMessageGeoLocationAction' } - break - case 'contact': - status = { _: 'sendMessageChooseContactAction' } - break - case 'game': - status = { _: 'sendMessageGamePlayAction' } - break - case 'record_round': - status = { _: 'sendMessageRecordRoundAction' } - break - case 'upload_round': - status = { _: 'sendMessageUploadRoundAction', progress } - break - case 'speak_call': - status = { _: 'speakingInGroupCallAction' } - break - case 'history_import': - status = { _: 'sendMessageHistoryImportAction', progress } - break - case 'sticker': - status = { _: 'sendMessageChooseStickerAction' } - break - default: - assertNever(status) - } + status = _mapTypingStatus(status, params?.progress ?? 0) } const r = await _maybeInvokeWithBusinessConnection(client, params?.businessConnectionId, { diff --git a/packages/core/src/highlevel/methods/messages/set-typing.ts b/packages/core/src/highlevel/methods/messages/set-typing.ts new file mode 100644 index 00000000..4054fa2f --- /dev/null +++ b/packages/core/src/highlevel/methods/messages/set-typing.ts @@ -0,0 +1,91 @@ +import type { tl } from '@mtcute/tl' + +import { getMarkedPeerId } from '../../../utils/peer-utils.js' +import type { ITelegramClient } from '../../client.types.js' +import type { InputPeerLike } from '../../types/peers/peer.js' +import { resolvePeer } from '../users/resolve-peer.js' +import type { TypingStatus } from '../../types/peers/typing-status.js' + +import { _maybeInvokeWithBusinessConnection } from './_business-connection.js' +import { _mapTypingStatus } from './send-typing.js' + +export function _getTypingTimerId(peer: tl.TypeInputPeer, businessId?: string): string { + let base = `typing:${getMarkedPeerId(peer)}` + if (businessId) base += `:b${businessId}` + + return base +} + +const TIMER_INTERVAL = 5_000 // 5 seconds + +/** + * Sets whether a user is typing in a specific chat + * + * This status is automatically renewed by mtcute until a further + * call with `cancel` is made, or a message is sent to the chat. + */ +export async function setTyping( + client: ITelegramClient, + params: { + /** Chat ID where the user is currently typing */ + peerId: InputPeerLike + + /** + * Typing status to send + * + * @default `typing` + */ + status?: Exclude | tl.TypeSendMessageAction + + /** + * For `upload_*` and history import actions, progress of the upload + */ + progress?: number + + /** + * Unique identifier of the business connection on behalf of which the action will be sent + */ + businessConnectionId?: string + + /** + * For comment threads, ID of the thread (i.e. top message) + */ + threadId?: number + }, +): Promise { + const { + peerId, + businessConnectionId, + threadId, + } = params + + let status = params.status ?? 'typing' + if (typeof status === 'string') status = _mapTypingStatus(status) + + const peer = await resolvePeer(client, peerId) + const timerId = _getTypingTimerId(peer, businessConnectionId) + + if (client.timers.exists(timerId)) { + client.timers.cancel(timerId) + } + + if (status._ === 'sendMessageCancelAction') { + await client.call({ + _: 'messages.setTyping', + peer, + action: status, + topMsgId: threadId, + }) + + return + } + + client.timers.create(timerId, async (abortSignal) => { + await _maybeInvokeWithBusinessConnection(client, params?.businessConnectionId, { + _: 'messages.setTyping', + peer, + action: status, + topMsgId: threadId, + }, { abortSignal }) + }, TIMER_INTERVAL, true) +} diff --git a/packages/core/src/highlevel/methods/users/set-offline.ts b/packages/core/src/highlevel/methods/users/set-offline.ts deleted file mode 100644 index eac75ee9..00000000 --- a/packages/core/src/highlevel/methods/users/set-offline.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ITelegramClient } from '../../client.types.js' - -/** - * Change user status to offline or online - * - * @param offline Whether the user is currently offline - */ -export async function setOffline(client: ITelegramClient, offline = true): Promise { - await client.call({ - _: 'account.updateStatus', - offline, - }) -} diff --git a/packages/core/src/highlevel/methods/users/set-online.ts b/packages/core/src/highlevel/methods/users/set-online.ts new file mode 100644 index 00000000..85f01914 --- /dev/null +++ b/packages/core/src/highlevel/methods/users/set-online.ts @@ -0,0 +1,45 @@ +import type { ITelegramClient } from '../../client.types.js' + +/** + * Change user status to offline or online once, + * which will expire after a while (currently ~5 minutes) + * + * For continuously sending online/offline status, use {@link setOnline} + * + * @param online Whether the user is currently online + */ +export async function sendOnline(client: ITelegramClient, online: boolean): Promise { + await client.call({ + _: 'account.updateStatus', + offline: !online, + }) +} + +const TIMER_ID = 'online' +const TIMER_INTERVAL = 240_000 // 4 minutes + +/** + * Change user status to online or offline + * + * Once called with `true`, mtcute will keep notifying the server + * that the user is still online until a further call with `false` is made. + * + * @param online + */ +export async function setOnline(client: ITelegramClient, online = true): Promise { + if (online) { + client.timers.create(TIMER_ID, async (abortSignal) => { + await client.call({ + _: 'account.updateStatus', + offline: false, + }, { abortSignal }) + }, TIMER_INTERVAL, true) + } else { + client.timers.cancel(TIMER_ID) + + await client.call({ + _: 'account.updateStatus', + offline: true, + }) + } +} diff --git a/packages/core/src/highlevel/worker/port.ts b/packages/core/src/highlevel/worker/port.ts index 3b321eb4..9a0a7b53 100644 --- a/packages/core/src/highlevel/worker/port.ts +++ b/packages/core/src/highlevel/worker/port.ts @@ -1,5 +1,5 @@ import type { tl } from '@mtcute/tl' -import { Emitter } from '@fuman/utils' +import { Emitter, unknownToError } from '@fuman/utils' import type { RpcCallOptions } from '../../network/network-manager.js' import type { MustEqual } from '../../types/utils.js' @@ -8,6 +8,7 @@ import type { ConnectionState, ITelegramClient } from '../client.types.js' import { PeersIndex } from '../types/peers/peers-index.js' import type { ICorePlatform } from '../../types/platform' import type { RawUpdateInfo } from '../updates/types.js' +import { TimersManager } from '../managers/timers.js' import { AppConfigManagerProxy } from './app-config.js' import { WorkerInvoker } from './invoker.js' @@ -30,6 +31,10 @@ export abstract class TelegramWorkerPort imp readonly storage: TelegramStorageProxy readonly appConfig: AppConfigManagerProxy + // todo: ideally timers should be handled on the worker side, + // but i'm not sure yet of the best way to handle multiple clients (e.g. in SharedWorker-s) + // (with one worker client it's not that big of a deal) + readonly timers: TimersManager // bound methods readonly prepare: ITelegramClient['prepare'] @@ -87,6 +92,9 @@ export abstract class TelegramWorkerPort imp this.startUpdatesLoop = bind('startUpdatesLoop') this.stopUpdatesLoop = bind('stopUpdatesLoop') this.getMtprotoMessageId = bind('getMtprotoMessageId') + + this.timers = new TimersManager() + this.timers.onError(err => this.onError.emit(unknownToError(err))) } call( @@ -143,6 +151,7 @@ export abstract class TelegramWorkerPort imp private _destroyed = false destroy(terminate = false): void { if (this._destroyed) return + this.timers.destroy() this._connection[1]() this._destroyed = true diff --git a/packages/core/src/network/persistent-connection.ts b/packages/core/src/network/persistent-connection.ts index 80c9c5fe..cce33a6c 100644 --- a/packages/core/src/network/persistent-connection.ts +++ b/packages/core/src/network/persistent-connection.ts @@ -177,6 +177,7 @@ export abstract class PersistentConnection { } async destroy(): Promise { + this._destroyed = true await this._fuman.close() } diff --git a/packages/core/src/network/session-connection.ts b/packages/core/src/network/session-connection.ts index d39b804e..29f31594 100644 --- a/packages/core/src/network/session-connection.ts +++ b/packages/core/src/network/session-connection.ts @@ -2026,6 +2026,7 @@ export class SessionConnection extends PersistentConnection { const enc = this._session.encryptMessage(result) const promise = this.send(enc).catch((err: Error) => { + if (this._destroyed) return this.log.error('error while sending pending messages (root msg_id = %l): %e', rootMsgId, err) // put acks in the front so they are the first to be sent diff --git a/packages/deno/package.json b/packages/deno/package.json index d1ade5e0..048bb3dd 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -14,9 +14,9 @@ }, "dependencies": { "@db/sqlite": "npm:@jsr/db__sqlite@0.12.0", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", - "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc", - "@fuman/io": "https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc", + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", + "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4", + "@fuman/io": "https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4", "@mtcute/core": "workspace:^", "@mtcute/html-parser": "workspace:^", "@mtcute/markdown-parser": "workspace:^", diff --git a/packages/dispatcher/package.json b/packages/dispatcher/package.json index ceff30b1..08c18215 100644 --- a/packages/dispatcher/package.json +++ b/packages/dispatcher/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@mtcute/core": "workspace:^", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", "events": "3.2.0" }, "devDependencies": { diff --git a/packages/file-id/package.json b/packages/file-id/package.json index f5f755f1..189900cf 100644 --- a/packages/file-id/package.json +++ b/packages/file-id/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@mtcute/tl-runtime": "workspace:^", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", "long": "5.2.3" } } diff --git a/packages/node/package.json b/packages/node/package.json index 79f8c153..3899d47a 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -17,9 +17,9 @@ "@mtcute/html-parser": "workspace:^", "@mtcute/markdown-parser": "workspace:^", "@mtcute/wasm": "workspace:^", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", - "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc", - "@fuman/node": "https://pkg.pr.new/teidesu/fuman/@fuman/node@a3f52dc", + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", + "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4", + "@fuman/node": "https://pkg.pr.new/teidesu/fuman/@fuman/node@6017eb4", "better-sqlite3": "11.3.0" }, "devDependencies": { diff --git a/packages/test/package.json b/packages/test/package.json index 097dc848..5b8c7e4a 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -25,8 +25,8 @@ }, "dependencies": { "long": "5.2.3", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", - "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc" + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", + "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4" }, "devDependencies": { "@mtcute/tl-utils": "workspace:^" diff --git a/packages/tl-runtime/package.json b/packages/tl-runtime/package.json index 0a41fe3d..010a9028 100644 --- a/packages/tl-runtime/package.json +++ b/packages/tl-runtime/package.json @@ -12,6 +12,6 @@ }, "dependencies": { "long": "5.2.3", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc" + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4" } } diff --git a/packages/tl/package.json b/packages/tl/package.json index 64c8dcf8..41a43eb0 100644 --- a/packages/tl/package.json +++ b/packages/tl/package.json @@ -23,8 +23,8 @@ "@mtcute/core": "workspace:^", "@mtcute/node": "workspace:^", "@mtcute/tl-utils": "workspace:^", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc", - "@fuman/fetch": "https://pkg.pr.new/teidesu/fuman/@fuman/fetch@a3f52dc", + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4", + "@fuman/fetch": "https://pkg.pr.new/teidesu/fuman/@fuman/fetch@6017eb4", "@types/js-yaml": "^4.0.5", "cheerio": "1.0.0-rc.12", "csv-parse": "^5.5.0", diff --git a/packages/wasm/package.json b/packages/wasm/package.json index 4147a713..bace326c 100644 --- a/packages/wasm/package.json +++ b/packages/wasm/package.json @@ -18,6 +18,6 @@ "@mtcute/core": "workspace:^", "@mtcute/node": "workspace:^", "@mtcute/web": "workspace:^", - "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc" + "@fuman/utils": "https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4" } } diff --git a/packages/web/package.json b/packages/web/package.json index e730629d..a3d578d9 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -15,7 +15,7 @@ "dependencies": { "@mtcute/core": "workspace:^", "@mtcute/wasm": "workspace:^", - "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc", + "@fuman/net": "https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4", "events": "3.2.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f26557a..1619f251 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,11 +15,11 @@ importers: specifier: 2.26.0 version: 2.26.0(@typescript-eslint/utils@8.14.0(eslint@9.9.0)(typescript@5.5.4))(@vue/compiler-sfc@3.5.13)(eslint@9.9.0)(typescript@5.5.4)(vitest@2.0.5(@types/node@20.10.0)(@vitest/browser@2.0.5)(@vitest/ui@2.0.5)) '@fuman/build': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/build@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/build@a3f52dc(tough-cookie@4.1.4)(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0)) + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/build@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/build@6017eb4(tough-cookie@4.1.4)(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0)) '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@types/deno': specifier: npm:@teidesu/deno-types@1.46.3 version: '@teidesu/deno-types@1.46.3' @@ -105,17 +105,17 @@ importers: packages/bun: dependencies: '@fuman/bun': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/bun@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/bun@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/bun@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/bun@6017eb4 '@fuman/io': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 '@fuman/net': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -136,11 +136,11 @@ importers: packages/convert: dependencies: '@fuman/net': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -152,14 +152,14 @@ importers: packages/core: dependencies: '@fuman/io': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 '@fuman/net': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/file-id': specifier: workspace:^ version: link:../file-id @@ -239,14 +239,14 @@ importers: specifier: npm:@jsr/db__sqlite@0.12.0 version: '@jsr/db__sqlite@0.12.0' '@fuman/io': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 '@fuman/net': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -270,8 +270,8 @@ importers: packages/dispatcher: dependencies: '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -286,8 +286,8 @@ importers: packages/file-id: dependencies: '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/tl-runtime': specifier: workspace:^ version: link:../tl-runtime @@ -328,14 +328,14 @@ importers: packages/node: dependencies: '@fuman/net': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 '@fuman/node': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/node@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/node@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/node@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/node@6017eb4 '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -362,11 +362,11 @@ importers: packages/test: dependencies: '@fuman/net': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -397,11 +397,11 @@ importers: version: 5.2.3 devDependencies: '@fuman/fetch': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/fetch@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/fetch@a3f52dc(tough-cookie@4.1.4)(zod@3.23.8) + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/fetch@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/fetch@6017eb4(tough-cookie@4.1.4)(zod@3.23.8) '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -427,8 +427,8 @@ importers: packages/tl-runtime: dependencies: '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 long: specifier: 5.2.3 version: 5.2.3 @@ -445,8 +445,8 @@ importers: packages/wasm: devDependencies: '@fuman/utils': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -460,8 +460,8 @@ importers: packages/web: dependencies: '@fuman/net': - specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - version: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc + specifier: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + version: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 '@mtcute/core': specifier: workspace:^ version: link:../core @@ -904,20 +904,20 @@ packages: resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@fuman/build@https://pkg.pr.new/teidesu/fuman/@fuman/build@a3f52dc': - resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/build@a3f52dc} + '@fuman/build@https://pkg.pr.new/teidesu/fuman/@fuman/build@6017eb4': + resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/build@6017eb4} version: 0.0.1 hasBin: true peerDependencies: typescript: 5.5.4 vite: ^5.4.0 - '@fuman/bun@https://pkg.pr.new/teidesu/fuman/@fuman/bun@a3f52dc': - resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/bun@a3f52dc} + '@fuman/bun@https://pkg.pr.new/teidesu/fuman/@fuman/bun@6017eb4': + resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/bun@6017eb4} version: 0.0.1 - '@fuman/fetch@https://pkg.pr.new/teidesu/fuman/@fuman/fetch@a3f52dc': - resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/fetch@a3f52dc} + '@fuman/fetch@https://pkg.pr.new/teidesu/fuman/@fuman/fetch@6017eb4': + resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/fetch@6017eb4} version: 0.0.1 peerDependencies: tough-cookie: ^5.0.0 || ^4.0.0 @@ -934,20 +934,20 @@ packages: zod: optional: true - '@fuman/io@https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc': - resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc} + '@fuman/io@https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4': + resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4} version: 0.0.1 - '@fuman/net@https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc': - resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc} + '@fuman/net@https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4': + resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4} version: 0.0.1 - '@fuman/node@https://pkg.pr.new/teidesu/fuman/@fuman/node@a3f52dc': - resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/node@a3f52dc} + '@fuman/node@https://pkg.pr.new/teidesu/fuman/@fuman/node@6017eb4': + resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/node@6017eb4} version: 0.0.1 - '@fuman/utils@https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc': - resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc} + '@fuman/utils@https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4': + resolution: {tarball: https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4} version: 0.0.1 '@humanwhocodes/module-importer@1.0.1': @@ -4253,13 +4253,13 @@ snapshots: '@eslint/object-schema@2.1.4': {} - '@fuman/build@https://pkg.pr.new/teidesu/fuman/@fuman/build@a3f52dc(tough-cookie@4.1.4)(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0))': + '@fuman/build@https://pkg.pr.new/teidesu/fuman/@fuman/build@6017eb4(tough-cookie@4.1.4)(typescript@5.5.4)(vite@5.4.2(@types/node@20.10.0))': dependencies: '@drizzle-team/brocli': 0.10.2 - '@fuman/fetch': https://pkg.pr.new/teidesu/fuman/@fuman/fetch@a3f52dc(tough-cookie@4.1.4)(zod@3.23.8) - '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc - '@fuman/node': https://pkg.pr.new/teidesu/fuman/@fuman/node@a3f52dc - '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + '@fuman/fetch': https://pkg.pr.new/teidesu/fuman/@fuman/fetch@6017eb4(tough-cookie@4.1.4)(zod@3.23.8) + '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 + '@fuman/node': https://pkg.pr.new/teidesu/fuman/@fuman/node@6017eb4 + '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 cross-spawn: 7.0.3 detect-indent: 7.0.1 js-yaml: 4.1.0 @@ -4274,35 +4274,35 @@ snapshots: - valibot - yup - '@fuman/bun@https://pkg.pr.new/teidesu/fuman/@fuman/bun@a3f52dc': + '@fuman/bun@https://pkg.pr.new/teidesu/fuman/@fuman/bun@6017eb4': dependencies: - '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc - '@fuman/net': https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 + '@fuman/net': https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 - '@fuman/fetch@https://pkg.pr.new/teidesu/fuman/@fuman/fetch@a3f52dc(tough-cookie@4.1.4)(zod@3.23.8)': + '@fuman/fetch@https://pkg.pr.new/teidesu/fuman/@fuman/fetch@6017eb4(tough-cookie@4.1.4)(zod@3.23.8)': dependencies: - '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 optionalDependencies: tough-cookie: 4.1.4 zod: 3.23.8 - '@fuman/io@https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc': + '@fuman/io@https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4': dependencies: - '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 - '@fuman/net@https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc': + '@fuman/net@https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4': dependencies: - '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc - '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 + '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 - '@fuman/node@https://pkg.pr.new/teidesu/fuman/@fuman/node@a3f52dc': + '@fuman/node@https://pkg.pr.new/teidesu/fuman/@fuman/node@6017eb4': dependencies: - '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@a3f52dc - '@fuman/net': https://pkg.pr.new/teidesu/fuman/@fuman/net@a3f52dc - '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc + '@fuman/io': https://pkg.pr.new/teidesu/fuman/@fuman/io@6017eb4 + '@fuman/net': https://pkg.pr.new/teidesu/fuman/@fuman/net@6017eb4 + '@fuman/utils': https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4 - '@fuman/utils@https://pkg.pr.new/teidesu/fuman/@fuman/utils@a3f52dc': {} + '@fuman/utils@https://pkg.pr.new/teidesu/fuman/@fuman/utils@6017eb4': {} '@humanwhocodes/module-importer@1.0.1': {}