From 2cbed9b8836af7e9a57d6985bc87c025e4ecc120 Mon Sep 17 00:00:00 2001 From: alina sireneva Date: Tue, 26 Nov 2024 01:37:30 +0300 Subject: [PATCH] feat(core): openWebview/closeWebview closes #74 --- packages/core/src/highlevel/client.ts | 123 ++++++++- packages/core/src/highlevel/methods.ts | 4 +- .../core/src/highlevel/methods/_imports.ts | 2 + .../highlevel/methods/bots/open-webview.ts | 245 ++++++++++++++++++ .../core/src/highlevel/types/bots/index.ts | 1 + .../core/src/highlevel/types/bots/webview.ts | 153 +++++++++++ 6 files changed, 514 insertions(+), 14 deletions(-) create mode 100644 packages/core/src/highlevel/methods/bots/open-webview.ts create mode 100644 packages/core/src/highlevel/types/bots/webview.ts diff --git a/packages/core/src/highlevel/client.ts b/packages/core/src/highlevel/client.ts index 87b29f82..13aafc80 100644 --- a/packages/core/src/highlevel/client.ts +++ b/packages/core/src/highlevel/client.ts @@ -13,7 +13,7 @@ import type { BaseTelegramClientOptions } from './base.js' import { BaseTelegramClient } from './base.js' import type { ITelegramClient } from './client.types.js' import type { RawUpdateInfo } from './updates/types.js' -import type { AllStories, ArrayPaginated, ArrayWithTotal, Boost, BoostSlot, BoostStats, BotChatJoinRequestUpdate, BotCommands, BotReactionCountUpdate, BotReactionUpdate, BotStoppedUpdate, BusinessCallbackQuery, BusinessChatLink, BusinessConnection, BusinessMessage, BusinessWorkHoursDay, CallbackQuery, Chat, ChatEvent, ChatInviteLink, ChatInviteLinkMember, ChatJoinRequestUpdate, ChatMember, ChatMemberUpdate, ChatPreview, ChatlistPreview, ChosenInlineResult, CollectibleInfo, DeleteBusinessMessageUpdate, DeleteMessageUpdate, DeleteStoryUpdate, Dialog, FactCheck, FileDownloadLocation, FileDownloadParameters, ForumTopic, FullChat, GameHighScore, HistoryReadUpdate, InlineCallbackQuery, InlineQuery, InputChatEventFilters, InputDialogFolder, InputFileLike, InputInlineResult, InputMediaLike, InputMediaSticker, InputMessageId, InputPeerLike, InputPrivacyRule, InputReaction, InputStickerSet, InputStickerSetItem, InputText, MaybeDynamic, Message, MessageEffect, MessageMedia, MessageReactions, ParametersSkip2, ParsedUpdate, PeerReaction, PeerStories, Photo, Poll, PollUpdate, PollVoteUpdate, PreCheckoutQuery, RawDocument, ReplyMarkup, SentCode, StarGift, StarsStatus, StarsTransaction, Sticker, StickerSet, StickerType, StoriesStealthMode, Story, StoryInteractions, StoryUpdate, StoryViewer, StoryViewersList, TakeoutSession, TextWithEntities, TypingStatus, UploadFileLike, UploadedFile, User, UserStarGift, UserStatusUpdate, UserTypingUpdate } from './types/index.js' +import type { AllStories, ArrayPaginated, ArrayWithTotal, Boost, BoostSlot, BoostStats, BotChatJoinRequestUpdate, BotCommands, BotReactionCountUpdate, BotReactionUpdate, BotStoppedUpdate, BusinessCallbackQuery, BusinessChatLink, BusinessConnection, BusinessMessage, BusinessWorkHoursDay, CallbackQuery, Chat, ChatEvent, ChatInviteLink, ChatInviteLinkMember, ChatJoinRequestUpdate, ChatMember, ChatMemberUpdate, ChatPreview, ChatlistPreview, ChosenInlineResult, CollectibleInfo, DeleteBusinessMessageUpdate, DeleteMessageUpdate, DeleteStoryUpdate, Dialog, FactCheck, FileDownloadLocation, FileDownloadParameters, ForumTopic, FullChat, GameHighScore, HistoryReadUpdate, InlineCallbackQuery, InlineQuery, InputChatEventFilters, InputDialogFolder, InputFileLike, InputInlineResult, InputMediaLike, InputMediaSticker, InputMessageId, InputPeerLike, InputPrivacyRule, InputReaction, InputStickerSet, InputStickerSetItem, InputText, InputWebview, MaybeDynamic, Message, MessageEffect, MessageMedia, MessageReactions, ParametersSkip2, ParsedUpdate, PeerReaction, PeerStories, Photo, Poll, PollUpdate, PollVoteUpdate, PreCheckoutQuery, RawDocument, ReplyMarkup, SentCode, StarGift, StarsStatus, StarsTransaction, Sticker, StickerSet, StickerType, StoriesStealthMode, Story, StoryInteractions, StoryUpdate, StoryViewer, StoryViewersList, TakeoutSession, TextWithEntities, TypingStatus, UploadFileLike, UploadedFile, User, UserStarGift, UserStatusUpdate, UserTypingUpdate, WebviewResult } from './types/index.js' import type { StringSessionData } from './utils/string-session.js' import type { ITelegramStorageProvider } from './storage/provider.js' import { Conversation } from './types/conversation.js' @@ -43,6 +43,7 @@ import { getBotMenuButton } from './methods/bots/get-bot-menu-button.js' import { getCallbackAnswer } from './methods/bots/get-callback-answer.js' import { getGameHighScores, getInlineGameHighScores } from './methods/bots/get-game-high-scores.js' import { getMyCommands } from './methods/bots/get-my-commands.js' +import { closeWebview, openWebview } from './methods/bots/open-webview.js' import { prepareInlineMessage } from './methods/bots/prepare-inline-message.js' import { setBotInfo } from './methods/bots/set-bot-info.js' import { setBotMenuButton } from './methods/bots/set-bot-menu-button.js' @@ -280,7 +281,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, setOnline } from './methods/users/set-online.js' +import { sendOnline, 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' @@ -988,6 +989,92 @@ export interface TelegramClient extends ITelegramClient { */ langCode?: string }): Promise + /** + * Open a webview. + * **Available**: 👤 users only + * + */ + openWebview( + params: { + /** Information about the webview to open */ + webview: InputWebview + + /** + * Bot whose webview to open + */ + bot: InputPeerLike + + /** + * Chat to report to the server as the "currently open chat", + * also the chat to which the message will be sent in case of + * `from_inline_keyboard`, `from_bot_menu` and `from_attach_menu` webviews + */ + chat?: InputPeerLike + + /** + * Theme parameters to pass to the mini app + * + * Each value should be a string (hex-encoded RGB, no alpha) + */ + theme?: tl.TypeDataJSON | { + // https://corefork.telegram.org/api/bots/webapps#theme-parameters + /** Background color */ + bg_color?: string + /** Secondary background color */ + secondary_bg_color?: string + /** Text color */ + text_color?: string + /** Hint text color */ + hint_color?: string + /** Link color */ + link_color?: string + /** Button color */ + button_color?: string + /** Button text color */ + button_text_color?: string + /** Header background color */ + header_bg_color?: string + /** Accent text color */ + accent_text_color?: string + /** Section background color */ + section_bg_color?: string + /** Section header text color */ + section_header_text_color?: string + /** Section separator color */ + section_separator_color?: string + /** Sub title text color */ + subtitle_text_color?: string + /** Text color for destructive action buttons in prompts */ + destructive_text_color?: string + } + + /** + * Webview platform to use in the init data + * + * Some of the known values: + * - `android` - Android clients + * - `ios` - iOS clients + * - `tdesktop` - Telegram Desktop + * - `macos` - Telegram for macOS + * - `unigram` - Unigram + */ + platform: + | 'android' + | 'ios' + | 'tdesktop' + | 'macos' + | 'unigram' + | (string & {}) + }): Promise + /** + * Close a webview previously opened by {@link openWebview} method. + * + * **Available**: ✅ both users and bots + * + * @param webview Webview result returned by {@link openWebview}, or its `.queryId` + */ + closeWebview( + webview: WebviewResult | tl.Long): Promise /** * Prepare an inline message result to be sent later via the * `shareMessage` [mini-app api method](https://core.telegram.org/bots/webapps#initializing-mini-apps). @@ -4206,12 +4293,13 @@ export interface TelegramClient extends ITelegramClient { * automatically cancelled if you send a * message. * + * If you need a continuous typing status, use {@link setTyping} instead. + * * **Available**: ✅ both users and bots * * @param chatId Chat ID * @param [status='typing'] Typing status * @param params - * @deprecated - use {@link setTyping} instead */ sendTyping( chatId: InputPeerLike, status?: Exclude | tl.TypeSendMessageAction, @@ -4250,7 +4338,7 @@ export interface TelegramClient extends ITelegramClient { * 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. + * call with `cancel` is made, or a message is sent to the chat. * **Available**: ✅ both users and bots * */ @@ -4258,12 +4346,13 @@ export interface TelegramClient extends ITelegramClient { params: { /** Chat ID where the user is currently typing */ peerId: InputPeerLike + /** - * Typing status to send (false is a shortcut for `{ _: 'sendMessageCancelAction' }`) + * Typing status to send * - * @default `{ _: 'sendMessageTypingAction' }` + * @default `typing` */ - status?: tl.TypeSendMessageAction | false + status?: Exclude | tl.TypeSendMessageAction /** * For `upload_*` and history import actions, progress of the upload @@ -5750,14 +5839,16 @@ export interface TelegramClient extends ITelegramClient { */ setMyUsername(username: string | null): Promise /** - * Change user status to offline or online + * 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} * * **Available**: 👤 users only * - * @param [offline=true] Whether the user is currently offline - * @deprecated - use {@link setOnline} instead + * @param online Whether the user is currently online */ - setOffline(offline?: boolean): Promise + sendOnline(online: boolean): Promise /** * Change user status to online or offline * @@ -6042,6 +6133,12 @@ TelegramClient.prototype.getInlineGameHighScores = function (...args) { TelegramClient.prototype.getMyCommands = function (...args) { return getMyCommands(this._client, ...args) } +TelegramClient.prototype.openWebview = function (...args) { + return openWebview(this._client, ...args) +} +TelegramClient.prototype.closeWebview = function (...args) { + return closeWebview(this._client, ...args) +} TelegramClient.prototype.prepareInlineMessage = function (...args) { return prepareInlineMessage(this._client, ...args) } @@ -6779,8 +6876,8 @@ TelegramClient.prototype.setMyProfilePhoto = function (...args) { TelegramClient.prototype.setMyUsername = function (...args) { return setMyUsername(this._client, ...args) } -TelegramClient.prototype.setOffline = function (...args) { - return setOffline(this._client, ...args) +TelegramClient.prototype.sendOnline = function (...args) { + return sendOnline(this._client, ...args) } TelegramClient.prototype.setOnline = function (...args) { return setOnline(this._client, ...args) diff --git a/packages/core/src/highlevel/methods.ts b/packages/core/src/highlevel/methods.ts index d658df57..88ca02bc 100644 --- a/packages/core/src/highlevel/methods.ts +++ b/packages/core/src/highlevel/methods.ts @@ -24,6 +24,8 @@ export { getCallbackAnswer } from './methods/bots/get-callback-answer.js' export { getGameHighScores } from './methods/bots/get-game-high-scores.js' export { getInlineGameHighScores } from './methods/bots/get-game-high-scores.js' export { getMyCommands } from './methods/bots/get-my-commands.js' +export { openWebview } from './methods/bots/open-webview.js' +export { closeWebview } from './methods/bots/open-webview.js' export { prepareInlineMessage } from './methods/bots/prepare-inline-message.js' export { setBotInfo } from './methods/bots/set-bot-info.js' export { setBotMenuButton } from './methods/bots/set-bot-menu-button.js' @@ -282,7 +284,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-online.js' +export { sendOnline } 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/_imports.ts b/packages/core/src/highlevel/methods/_imports.ts index 792f9249..4e79210b 100644 --- a/packages/core/src/highlevel/methods/_imports.ts +++ b/packages/core/src/highlevel/methods/_imports.ts @@ -71,6 +71,7 @@ import { InputStickerSet, InputStickerSetItem, InputText, + InputWebview, MaybeDynamic, Message, MessageEffect, @@ -111,6 +112,7 @@ import { UserStarGift, UserStatusUpdate, UserTypingUpdate, + WebviewResult, } from '../types/index.js' // @copy import { StringSessionData } from '../utils/string-session.js' diff --git a/packages/core/src/highlevel/methods/bots/open-webview.ts b/packages/core/src/highlevel/methods/bots/open-webview.ts new file mode 100644 index 00000000..a3e097c9 --- /dev/null +++ b/packages/core/src/highlevel/methods/bots/open-webview.ts @@ -0,0 +1,245 @@ +import type { tl } from '@mtcute/tl' +import { asNonNull } from '@fuman/utils' +import Long from 'long' + +import type { ITelegramClient } from '../../client.types.js' +import type { InputPeerLike } from '../../types/index.js' +import { type InputWebview, WebviewResult } from '../../types/bots/webview.js' +import { resolvePeer, resolveUser } from '../users/resolve-peer.js' +import { longToFastString } from '../../../utils/long-utils.js' +import { toInputPeer } from '../../utils/peer-utils.js' +import { assertNever } from '../../../types/utils.js' + +const _getWebviewTimerId = (queryId: tl.Long) => `webview:${longToFastString(queryId)}` + +/** + * Open a webview. + */ +export async function openWebview( + client: ITelegramClient, + params: { + /** Information about the webview to open */ + webview: InputWebview + + /** + * Bot whose webview to open + */ + bot: InputPeerLike + + /** + * Chat to report to the server as the "currently open chat", + * also the chat to which the message will be sent in case of + * `from_inline_keyboard`, `from_bot_menu` and `from_attach_menu` webviews + */ + chat?: InputPeerLike + + /** + * Theme parameters to pass to the mini app + * + * Each value should be a string (hex-encoded RGB, no alpha) + */ + theme?: tl.TypeDataJSON | { + // https://corefork.telegram.org/api/bots/webapps#theme-parameters + /** Background color */ + bg_color?: string + /** Secondary background color */ + secondary_bg_color?: string + /** Text color */ + text_color?: string + /** Hint text color */ + hint_color?: string + /** Link color */ + link_color?: string + /** Button color */ + button_color?: string + /** Button text color */ + button_text_color?: string + /** Header background color */ + header_bg_color?: string + /** Accent text color */ + accent_text_color?: string + /** Section background color */ + section_bg_color?: string + /** Section header text color */ + section_header_text_color?: string + /** Section separator color */ + section_separator_color?: string + /** Sub title text color */ + subtitle_text_color?: string + /** Text color for destructive action buttons in prompts */ + destructive_text_color?: string + } + + /** + * Webview platform to use in the init data + * + * Some of the known values: + * - `android` - Android clients + * - `ios` - iOS clients + * - `tdesktop` - Telegram Desktop + * - `macos` - Telegram for macOS + * - `unigram` - Unigram + */ + platform: + | 'android' + | 'ios' + | 'tdesktop' + | 'macos' + | 'unigram' + | (string & {}) + }, +): Promise { + const { + webview, + bot, + chat, + theme, + platform, + } = params + + const botPeer = await resolveUser(client, bot) + + let themeObj: tl.TypeDataJSON | undefined + if (theme) { + if ('_' in theme) { + themeObj = theme + } else { + themeObj = { + _: 'dataJSON', + data: JSON.stringify(theme), + } + } + } + + switch (webview.type) { + case 'main': { + const chatPeer = chat != null ? await resolvePeer(client, chat) : { _: 'inputPeerEmpty' as const } + + const res = await client.call({ + _: 'messages.requestMainWebView', + compact: webview.compact, + peer: chatPeer, + bot: botPeer, + startParam: webview.startParam, + themeParams: themeObj, + platform, + }) + + return new WebviewResult(res) + } + case 'from_reply_keyboard': + case 'from_switch_inline': + case 'from_side_menu': { + const res = await client.call({ + _: 'messages.requestSimpleWebView', + bot: botPeer, + url: webview.type === 'from_side_menu' ? undefined : webview.url, + themeParams: themeObj, + platform, + }) + + return new WebviewResult(res) + } + case 'from_inline_keyboard': + case 'from_bot_menu': + case 'from_attach_menu': { + const chatPeer = chat != null ? await resolvePeer(client, chat) : toInputPeer(botPeer) + + const tlReplyTo = typeof webview.replyTo === 'number' + ? { + _: 'inputReplyToMessage' as const, + replyToMsgId: webview.replyTo, + } + : webview.replyTo + const tlSendAs = webview.sendAs !== undefined ? await resolvePeer(client, webview.sendAs) : undefined + + const res = await client.call({ + _: 'messages.requestWebView', + bot: botPeer, + peer: chatPeer, + url: webview.type === 'from_attach_menu' ? undefined : webview.url, + compact: webview.compact, + themeParams: themeObj, + platform, + replyTo: tlReplyTo, + sendAs: tlSendAs, + silent: webview.silent, + }) + + const withTimer = res.queryId != null && !webview.fireAndForget + + const result = new WebviewResult(res, withTimer) + + if (withTimer) { + const queryId = asNonNull(result.queryId) + const timerId = _getWebviewTimerId(queryId) + + client.timers.create(timerId, async (abortSignal) => { + await client.call({ + _: 'messages.prolongWebView', + silent: webview.silent, + peer: chatPeer, + bot: botPeer, + queryId, + replyTo: tlReplyTo, + sendAs: tlSendAs, + }, { abortSignal }) + }, 60_000) + } + + return result + } + case 'from_link': { + const chatPeer = chat != null ? await resolvePeer(client, chat) : toInputPeer(botPeer) + + const res = await client.call({ + _: 'messages.requestAppWebView', + writeAllowed: webview.allowWrite, + compact: webview.compact, + peer: chatPeer, + app: { + _: 'inputBotAppShortName', + botId: botPeer, + shortName: webview.shortName, + }, + startParam: webview.startParam, + themeParams: themeObj, + platform, + }) + + const withTimer = res.queryId != null && !webview.fireAndForget + const result = new WebviewResult(res, withTimer) + + if (withTimer) { + const queryId = asNonNull(result.queryId) + const timerId = _getWebviewTimerId(queryId) + + client.timers.create(timerId, async (abortSignal) => { + await client.call({ + _: 'messages.prolongWebView', + peer: chatPeer, + bot: botPeer, + queryId, + }, { abortSignal }) + }, 60_000) + } + + return result + } + default: + assertNever(webview) + } +} + +/** + * Close a webview previously opened by {@link openWebview} method. + * + * @param webview Webview result returned by {@link openWebview}, or its `.queryId` + */ +export async function closeWebview( + client: ITelegramClient, + webview: WebviewResult | tl.Long, +): Promise { + const timerId = _getWebviewTimerId(Long.isLong(webview) ? webview : asNonNull(webview.queryId)) + client.timers.cancel(timerId) +} diff --git a/packages/core/src/highlevel/types/bots/index.ts b/packages/core/src/highlevel/types/bots/index.ts index 72c17dce..e8ca924f 100644 --- a/packages/core/src/highlevel/types/bots/index.ts +++ b/packages/core/src/highlevel/types/bots/index.ts @@ -3,3 +3,4 @@ export * from './game-high-score.js' export * from './inline-message/index.js' export * from './inline-result/index.js' export * from './keyboards/index.js' +export * from './webview.js' diff --git a/packages/core/src/highlevel/types/bots/webview.ts b/packages/core/src/highlevel/types/bots/webview.ts new file mode 100644 index 00000000..0c4ab03a --- /dev/null +++ b/packages/core/src/highlevel/types/bots/webview.ts @@ -0,0 +1,153 @@ +import type { tl } from '@mtcute/tl' + +import type { InputPeerLike } from '../peers/peer.js' +import { makeInspectable } from '../../utils/inspectable.js' + +/** + * Information about the mini app for {@link openWebview} method + * + * - `main` - the ["main"](https://corefork.telegram.org/api/bots/webapps#main-mini-apps) mini-app, configured via BotFather + * - `from_reply_keyboard` - webview button found in [reply keyboards](https://corefork.telegram.org/api/bots/webapps#keyboard-button-mini-apps) + * - `from_switch_inline` - webview button found [at the top of inline results](https://corefork.telegram.org/api/bots/webapps#inline-mode-mini-apps) + * - `from_side_menu` - webview button found in the [side menu](https://corefork.telegram.org/api/bots/webapps#side-menu-mini-apps) + * - `from_inline_keyboard` - webview button found in [inline keyboards](https://corefork.telegram.org/api/bots/webapps#inline-button-mini-apps) + * - `from_bot_menu` - webview button found in [bot menus](https://corefork.telegram.org/api/bots/webapps#menu-button-mini-apps) + * - `from_attach_menu` - webview button found in [attachment menus](https://corefork.telegram.org/api/bots/webapps#attachment-menu-mini-apps) + * - `from_link` - webview opened via [direct links](https://corefork.telegram.org/api/bots/webapps#direct-link-mini-apps) + */ +export type InputWebview = + | { + type: 'main' + + /** + * If set, requests to open the mini app in compact mode (as opposed to fullview mode). + * Must be set if the `mode` parameter of the Main Mini App link is equal to `compact`. + */ + compact?: boolean + + /** Start parameter from the deep link for the mini app */ + startParam?: string + } + | { + type: 'from_reply_keyboard' | 'from_switch_inline' + + /** URL of the mini app found in the button */ + url: string + } + | { type: 'from_side_menu' } + | { + type: 'from_inline_keyboard' | 'from_bot_menu' + + /** URL of the mini app found in the button */ + url: string + + /** + * If set, requests to open the mini app in compact mode (as opposed to fullview mode). + * Must be set if the `mode` parameter of the Main Mini App link is equal to `compact`. + */ + compact?: boolean + + /** ID of the message to which we should reply if the mini app asks to do so */ + replyTo?: number | tl.TypeInputReplyTo + /** + * Peer to use when sending the message. + */ + sendAs?: InputPeerLike + + /** If the mini app asks to send a message, whether to send it silently */ + silent?: boolean + + /** + * Telegram asks us to keep sending `messages.prolongWebView` requests every minute until the webview is closed. + * If this parameter is set to `true`, the timer will not be started, and the webview will never be prolonged. + */ + fireAndForget?: boolean + } + | { + type: 'from_attach_menu' + + /** + * If set, requests to open the mini app in compact mode (as opposed to fullview mode). + * Must be set if the `mode` parameter of the Main Mini App link is equal to `compact`. + */ + compact?: boolean + + /** ID of the message to which we should reply if the mini app asks to do so */ + replyTo?: number | tl.TypeInputReplyTo + + /** + * Peer to use when sending the message. + */ + sendAs?: InputPeerLike + + /** If the mini app asks to send a message, whether to send it silently */ + silent?: boolean + + /** + * Telegram asks us to keep sending `messages.prolongWebView` requests every minute until the webview is closed. + * If this parameter is set to `true`, the timer will not be started, and the webview will never be prolonged. + */ + fireAndForget?: boolean + } + | { + type: 'from_link' + + /** Short name of the app (from the link) */ + shortName: string + + /** + * If the bot is asking permission to send messages to the user, + * whether to allow it to do so + */ + allowWrite?: boolean + + /** + * If set, requests to open the mini app in compact mode (as opposed to fullview mode). + * Must be set if the `mode` parameter of the Main Mini App link is equal to `compact`. + */ + compact?: boolean + + /** Start parameter from the deep link for the mini app */ + startParam?: string + + /** + * Telegram asks us to keep sending `messages.prolongWebView` requests every minute until the webview is closed. + * If this parameter is set to `true`, the timer will not be started, and the webview will never be prolonged. + */ + fireAndForget?: boolean + } + +/** + * Result of {@link openWebview} method call + */ +export class WebviewResult { + constructor( + readonly raw: tl.RawWebViewResultUrl, + /** If true, the caller should use `closeWebview` method eventually to close the webview */ + readonly shouldBeClosed: boolean = false, + ) {} + + /** Whether the webview should be opened as a landscape fullscreen app */ + get isFullscreen(): boolean { + return this.raw.fullscreen! + } + + /** Whether the webview should be opened in "compact" mode */ + get isCompact(): boolean { + return !this.raw.fullsize + } + + /** + * Webview session ID (only returned by inline button mini apps, menu button mini apps, attachment menu mini apps). + */ + get queryId(): tl.Long | null { + return this.raw.queryId ?? null + } + + /** Actual URL to open */ + get url(): string { + return this.raw.url + } +} + +makeInspectable(WebviewResult, ['shouldBeClosed'])