feat: updated to 196 layer

This commit is contained in:
alina 🌸 2025-01-02 01:24:27 +03:00
parent 486b8ecd51
commit c60a19f79b
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
33 changed files with 612 additions and 95 deletions

View file

@ -230,6 +230,8 @@ import { iterStarsTransactions } from './methods/premium/iter-stars-transactions
import { sendStarGift } from './methods/premium/send-star-gift.js' import { sendStarGift } from './methods/premium/send-star-gift.js'
import { setBusinessIntro } from './methods/premium/set-business-intro.js' import { setBusinessIntro } from './methods/premium/set-business-intro.js'
import { setBusinessWorkHours } from './methods/premium/set-business-work-hours.js' import { setBusinessWorkHours } from './methods/premium/set-business-work-hours.js'
import { transferStarGift } from './methods/premium/transfer-star-gift.js'
import { upgradeStarGift } from './methods/premium/upgrade-star-gift.js'
import { addStickerToSet } from './methods/stickers/add-sticker-to-set.js' import { addStickerToSet } from './methods/stickers/add-sticker-to-set.js'
import { createStickerSet } from './methods/stickers/create-sticker-set.js' import { createStickerSet } from './methods/stickers/create-sticker-set.js'
import { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js' import { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js'
@ -1078,6 +1080,8 @@ export interface TelegramClient extends ITelegramClient {
/** /**
* Prepare an inline message result to be sent later via the * 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). * `shareMessage` [mini-app api method](https://core.telegram.org/bots/webapps#initializing-mini-apps).
* **Available**: 🤖 bots only
*
*/ */
prepareInlineMessage( prepareInlineMessage(
params: { params: {
@ -1245,6 +1249,8 @@ export interface TelegramClient extends ITelegramClient {
}): Promise<void> }): Promise<void>
/** /**
* Give or revoke permission for a bot to update emoji status for your account * Give or revoke permission for a bot to update emoji status for your account
* **Available**: 👤 users only
*
*/ */
toggleEmojiStatusPermission( toggleEmojiStatusPermission(
params: { params: {
@ -4844,6 +4850,9 @@ export interface TelegramClient extends ITelegramClient {
/** Message to send along with the gift */ /** Message to send along with the gift */
message?: InputText message?: InputText
/** Whether to automatically upgrade the gift to a unique star gift */
withUpgrade?: boolean
/** /**
* Whether to dispatch the new message event * Whether to dispatch the new message event
* to the client's update handler. * to the client's update handler.
@ -4899,6 +4908,61 @@ export interface TelegramClient extends ITelegramClient {
} }
)) ))
| null): Promise<void> | null): Promise<void>
/**
* Transfer a unique star gift.
*
* > **Note**: this method is not indended to be used by full-fledged clients,
* > as this method hides the actual invoice and payment form from the user.
* > For GUI clients, you should refer to the method's source code and
* > present the payment form to the user.
*
* **Available**: 👤 users only
*
* @returns Service message about the transferred gift
*/
transferStarGift(
params: {
/** ID of the message containing the gift */
message: number | Message
/** ID of the user to transfer the gift to */
recepient: InputPeerLike
/**
* Whether to dispatch the new message event
* to the client's update handler.
*/
shouldDispatch?: true
}): Promise<Message>
/**
* Upgrades a star gift to a unique gift.
*
* > **Note**: this method is not indended to be used by full-fledged clients,
* > as this method hides the actual invoice and payment form from the user.
* > For GUI clients, you should refer to the method's source code and
* > present the payment form to the user.
*
* **Available**: 👤 users only
*
* @returns Service message about the upgraded gift
*/
upgradeStarGift(
params: {
/** ID of the message containing the gift */
message: number | Message
/**
* Whether to retain the original details of the gift
* (like sender, recipient, date, message)
*/
keepOriginalDetails?: boolean
/**
* Whether to dispatch the new message event
* to the client's update handler.
*/
shouldDispatch?: true
}): Promise<Message>
/** /**
* Add a sticker to a sticker set. * Add a sticker to a sticker set.
* *
@ -6731,6 +6795,12 @@ TelegramClient.prototype.setBusinessIntro = function (...args) {
TelegramClient.prototype.setBusinessWorkHours = function (...args) { TelegramClient.prototype.setBusinessWorkHours = function (...args) {
return setBusinessWorkHours(this._client, ...args) return setBusinessWorkHours(this._client, ...args)
} }
TelegramClient.prototype.transferStarGift = function (...args) {
return transferStarGift(this._client, ...args)
}
TelegramClient.prototype.upgradeStarGift = function (...args) {
return upgradeStarGift(this._client, ...args)
}
TelegramClient.prototype.addStickerToSet = function (...args) { TelegramClient.prototype.addStickerToSet = function (...args) {
return addStickerToSet(this._client, ...args) return addStickerToSet(this._client, ...args)
} }

View file

@ -230,6 +230,8 @@ export { iterStarsTransactions } from './methods/premium/iter-stars-transactions
export { sendStarGift } from './methods/premium/send-star-gift.js' export { sendStarGift } from './methods/premium/send-star-gift.js'
export { setBusinessIntro } from './methods/premium/set-business-intro.js' export { setBusinessIntro } from './methods/premium/set-business-intro.js'
export { setBusinessWorkHours } from './methods/premium/set-business-work-hours.js' export { setBusinessWorkHours } from './methods/premium/set-business-work-hours.js'
export { transferStarGift } from './methods/premium/transfer-star-gift.js'
export { upgradeStarGift } from './methods/premium/upgrade-star-gift.js'
export { addStickerToSet } from './methods/stickers/add-sticker-to-set.js' export { addStickerToSet } from './methods/stickers/add-sticker-to-set.js'
export { createStickerSet } from './methods/stickers/create-sticker-set.js' export { createStickerSet } from './methods/stickers/create-sticker-set.js'
export { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js' export { deleteStickerFromSet } from './methods/stickers/delete-sticker-from-set.js'

View file

@ -34,7 +34,7 @@ export async function editFolder(
} }
if (typeof folder === 'number' || typeof folder === 'string') { if (typeof folder === 'number' || typeof folder === 'string') {
const old = await getFolders(client) const old = await getFolders(client)
const found = old.filters.find(it => it._ === 'dialogFilter' && (it.id === folder || it.title === folder)) const found = old.filters.find(it => it._ === 'dialogFilter' && (it.id === folder || it.title.text === folder))
if (!found) { if (!found) {
throw new MtArgumentError(`Could not find a folder ${folder}`) throw new MtArgumentError(`Could not find a folder ${folder}`)

View file

@ -35,7 +35,7 @@ export async function findFolder(
(folders.filters.find((it) => { (folders.filters.find((it) => {
if (it._ === 'dialogFilterDefault') return false if (it._ === 'dialogFilterDefault') return false
if (params.id && it.id !== params.id) return false if (params.id && it.id !== params.id) return false
if (params.title && it.title !== params.title) return false if (params.title && it.title.text !== params.title) return false
if (params.emoji && it.emoticon !== params.emoji) return false if (params.emoji && it.emoticon !== params.emoji) return false
return true return true

View file

@ -25,7 +25,7 @@ export async function _normalizeInputFolder(
return folder === 0 return folder === 0
} }
return it.id === folder || it.title === folder return it.id === folder || it.title.text === folder
}) })
if (!found) { if (!found) {

View file

@ -144,7 +144,7 @@ export async function* iterDialogs(
localFilters_ = { localFilters_ = {
_: 'dialogFilter', _: 'dialogFilter',
id: 0, id: 0,
title: '', title: { _: 'textWithEntities', text: '', entities: [] },
pinnedPeers: [], pinnedPeers: [],
includePeers: [], includePeers: [],
excludePeers: [], excludePeers: [],

View file

@ -1,6 +1,5 @@
import type { ITelegramClient } from '../../client.types.js' import type { ITelegramClient } from '../../client.types.js'
import { type InputMessageId, normalizeInputMessageId } from '../../types/messages/input-message-id.js' import type { Message } from '../../types/messages/message.js'
import { resolveUser } from '../users/resolve-peer.js'
// @available=user // @available=user
/** /**
@ -10,7 +9,9 @@ import { resolveUser } from '../users/resolve-peer.js'
*/ */
export async function acceptStarGift( export async function acceptStarGift(
client: ITelegramClient, client: ITelegramClient,
params: InputMessageId & { params: {
/** ID of the message containing the gift */
message: number | Message
/** /**
* Action to perform on the gift. * Action to perform on the gift.
* - `save` - save the gift to your profile * - `save` - save the gift to your profile
@ -21,20 +22,17 @@ export async function acceptStarGift(
}, },
): Promise<boolean> { ): Promise<boolean> {
const { action } = params const { action } = params
const { chatId, message } = normalizeInputMessageId(params) const message = typeof params.message === 'number' ? params.message : params.message.id
const userId = await resolveUser(client, chatId)
return client.call( return client.call(
action === 'convert' action === 'convert'
? { ? {
_: 'payments.convertStarGift', _: 'payments.convertStarGift',
userId,
msgId: message, msgId: message,
} }
: { : {
_: 'payments.saveStarGift', _: 'payments.saveStarGift',
unsave: action === 'hide', unsave: action === 'hide',
userId,
msgId: message, msgId: message,
}, },
) )

View file

@ -14,5 +14,12 @@ export async function getStarGiftOptions(client: ITelegramClient): Promise<StarG
assertTypeIsNot('payments.getStarGifts', res, 'payments.starGiftsNotModified') assertTypeIsNot('payments.getStarGifts', res, 'payments.starGiftsNotModified')
return res.gifts.map(gift => new StarGift(gift)) const ret: StarGift[] = []
for (const gift of res.gifts) {
if (gift._ === 'starGift') {
ret.push(new StarGift(gift))
}
}
return ret
} }

View file

@ -39,6 +39,9 @@ export async function sendStarGift(
/** Message to send along with the gift */ /** Message to send along with the gift */
message?: InputText message?: InputText
/** Whether to automatically upgrade the gift to a unique star gift */
withUpgrade?: boolean
/** /**
* Whether to dispatch the new message event * Whether to dispatch the new message event
* to the client's update handler. * to the client's update handler.
@ -46,7 +49,14 @@ export async function sendStarGift(
shouldDispatch?: true shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
const { userId, gift, anonymous, message, shouldDispatch } = params const {
userId,
gift,
anonymous,
message,
shouldDispatch,
withUpgrade,
} = params
const invoice: tl.TypeInputInvoice = { const invoice: tl.TypeInputInvoice = {
_: 'inputInvoiceStarGift', _: 'inputInvoiceStarGift',
@ -54,6 +64,7 @@ export async function sendStarGift(
userId: await resolveUser(client, userId), userId: await resolveUser(client, userId),
giftId: Long.isLong(gift) ? gift : gift.id, giftId: Long.isLong(gift) ? gift : gift.id,
message: message ? inputTextToTl(message) : undefined, message: message ? inputTextToTl(message) : undefined,
includeUpgrade: withUpgrade,
} }
const form = await client.call({ const form = await client.call({

View file

@ -0,0 +1,59 @@
import type { tl } from '@mtcute/tl'
import type { ITelegramClient } from '../../client.types.js'
import type { InputPeerLike } from '../../types/index.js'
import type { Message } from '../../types/messages/message.js'
import { assertTypeIs } from '../../../utils/type-assertions.js'
import { _findMessageInUpdate } from '../messages/find-in-update.js'
import { resolveUser } from '../users/resolve-peer.js'
/**
* Transfer a unique star gift.
*
* > **Note**: this method is not indended to be used by full-fledged clients,
* > as this method hides the actual invoice and payment form from the user.
* > For GUI clients, you should refer to the method's source code and
* > present the payment form to the user.
*
* @returns Service message about the transferred gift
*/
export async function transferStarGift(
client: ITelegramClient,
params: {
/** ID of the message containing the gift */
message: number | Message
/** ID of the user to transfer the gift to */
recepient: InputPeerLike
/**
* Whether to dispatch the new message event
* to the client's update handler.
*/
shouldDispatch?: true
},
): Promise<Message> {
const { message, recepient, shouldDispatch } = params
const msgId = typeof message === 'number' ? message : message.id
const invoice: tl.TypeInputInvoice = {
_: 'inputInvoiceStarGiftTransfer',
msgId,
toId: await resolveUser(client, recepient),
}
const form = await client.call({
_: 'payments.getPaymentForm',
invoice,
})
const res = await client.call({
_: 'payments.sendStarsForm',
invoice,
formId: form.formId,
})
assertTypeIs('payments.sendStarsForm', res, 'payments.paymentResult')
return _findMessageInUpdate(client, res.updates, false, !shouldDispatch)
}

View file

@ -0,0 +1,60 @@
import type { tl } from '@mtcute/tl'
import type { ITelegramClient } from '../../client.types.js'
import type { Message } from '../../types/messages/message.js'
import { assertTypeIs } from '../../../utils/type-assertions.js'
import { _findMessageInUpdate } from '../messages/find-in-update.js'
/**
* Upgrades a star gift to a unique gift.
*
* > **Note**: this method is not indended to be used by full-fledged clients,
* > as this method hides the actual invoice and payment form from the user.
* > For GUI clients, you should refer to the method's source code and
* > present the payment form to the user.
*
* @returns Service message about the upgraded gift
*/
export async function upgradeStarGift(
client: ITelegramClient,
params: {
/** ID of the message containing the gift */
message: number | Message
/**
* Whether to retain the original details of the gift
* (like sender, recipient, date, message)
*/
keepOriginalDetails?: boolean
/**
* Whether to dispatch the new message event
* to the client's update handler.
*/
shouldDispatch?: true
},
): Promise<Message> {
const { message, keepOriginalDetails, shouldDispatch } = params
const msgId = typeof message === 'number' ? message : message.id
const invoice: tl.TypeInputInvoice = {
_: 'inputInvoiceStarGiftUpgrade',
msgId,
keepOriginalDetails,
}
const form = await client.call({
_: 'payments.getPaymentForm',
invoice,
})
const res = await client.call({
_: 'payments.sendStarsForm',
invoice,
formId: form.formId,
})
assertTypeIs('payments.sendStarsForm', res, 'payments.paymentResult')
return _findMessageInUpdate(client, res.updates, false, !shouldDispatch)
}

View file

@ -1,44 +0,0 @@
import type { tl } from '@mtcute/tl'
import { assertNever } from '../../../types/utils.js'
/**
* Phone call discard reason. Can be:
* - `missed`: The call was missed
* - `disconnect`: The connection has interrupted
* - `hangup`: The call was ended normally
* - `busy`: The call was discarded because the user is in another call
*/
export type CallDiscardReason = 'missed' | 'disconnect' | 'hangup' | 'busy'
/** @internal */
export function _callDiscardReasonFromTl(raw: tl.TypePhoneCallDiscardReason): CallDiscardReason {
switch (raw._) {
case 'phoneCallDiscardReasonMissed':
return 'missed'
case 'phoneCallDiscardReasonDisconnect':
return 'disconnect'
case 'phoneCallDiscardReasonHangup':
return 'hangup'
case 'phoneCallDiscardReasonBusy':
return 'busy'
default:
assertNever(raw)
}
}
/** @internal */
export function _callDiscardReasonToTl(r: CallDiscardReason): tl.TypePhoneCallDiscardReason {
switch (r) {
case 'missed':
return { _: 'phoneCallDiscardReasonMissed' }
case 'disconnect':
return { _: 'phoneCallDiscardReasonDisconnect' }
case 'hangup':
return { _: 'phoneCallDiscardReasonHangup' }
case 'busy':
return { _: 'phoneCallDiscardReasonBusy' }
default:
assertNever(r)
}
}

View file

@ -1 +0,0 @@
export * from './discard-reason.js'

View file

@ -1,6 +1,5 @@
export * from './auth/index.js' export * from './auth/index.js'
export * from './bots/index.js' export * from './bots/index.js'
export * from './calls/index.js'
export * from './conversation.js' export * from './conversation.js'
export * from './errors.js' export * from './errors.js'
export * from './files/index.js' export * from './files/index.js'

View file

@ -1,15 +1,14 @@
import type { tl } from '@mtcute/tl' import type { tl } from '@mtcute/tl'
import type { CallDiscardReason } from '../calls/index.js'
import type { TextWithEntities } from '../misc/entities.js' import type { TextWithEntities } from '../misc/entities.js'
import type { Peer } from '../peers/peer.js' import type { Peer } from '../peers/peer.js'
import type { Message } from './message.js' import type { Message } from './message.js'
import Long from 'long' import Long from 'long'
import { getMarkedPeerId } from '../../../utils/peer-utils.js' import { getMarkedPeerId } from '../../../utils/peer-utils.js'
import { _callDiscardReasonFromTl } from '../calls/index.js'
import { Photo } from '../media/photo.js' import { Photo } from '../media/photo.js'
import { parsePeer } from '../peers/peer.js'
import { parsePeer } from '../peers/peer.js'
import { StarGiftUnique } from '../premium/stars-gift-unique.js'
import { StarGift } from '../premium/stars-gift.js' import { StarGift } from '../premium/stars-gift.js'
/** Group was created */ /** Group was created */
@ -200,7 +199,7 @@ export interface ActionCall {
readonly duration: number readonly duration: number
/** Call discard reason, if available */ /** Call discard reason, if available */
readonly reason?: CallDiscardReason readonly reason?: tl.TypePhoneCallDiscardReason
} }
/** A screenshot was taken */ /** A screenshot was taken */
@ -534,6 +533,7 @@ export interface ActionStarsPrize {
giveawayMessageId: number giveawayMessageId: number
} }
/** A star gift was sent */
export interface ActionStarGift { export interface ActionStarGift {
readonly type: 'stars_gift' readonly type: 'stars_gift'
@ -541,6 +541,9 @@ export interface ActionStarGift {
nameHidden: boolean nameHidden: boolean
/** Whether this gift was saved to the recipient's profile */ /** Whether this gift was saved to the recipient's profile */
saved: boolean saved: boolean
/** Whether this gift was refunded */
refunded: boolean
/** Whether this gift was converted to stars */ /** Whether this gift was converted to stars */
converted: boolean converted: boolean
/** /**
@ -548,8 +551,18 @@ export interface ActionStarGift {
* (0 if the gift cannot be converted) * (0 if the gift cannot be converted)
*/ */
convertStars: tl.Long convertStars: tl.Long
/** Whether this gift can be upgraded to a unique gift */
canUpgrade: boolean
/** Whether this gift was upgraded to a unique gift */
upgraded: boolean
/** Number of stars to upgrade the gift to a unique gift (may be 0) */
upgradeStars: tl.Long
/** If the gift was upgraded, ID of the message where this happened */
upgradeMsgId: number | null
/** The gift itself */ /** The gift itself */
gift: StarGift gift: StarGift | StarGiftUnique
/** Message attached to the gift */ /** Message attached to the gift */
message: TextWithEntities | null message: TextWithEntities | null
} }
@ -715,7 +728,7 @@ export function _messageActionFromTl(this: Message, act: tl.TypeMessageAction):
type: 'call', type: 'call',
id: act.callId, id: act.callId,
isVideo: Boolean(act.video), isVideo: Boolean(act.video),
reason: act.reason ? _callDiscardReasonFromTl(act.reason) : undefined, reason: act.reason,
duration: act.duration ?? 0, duration: act.duration ?? 0,
} }
case 'messageActionScreenshotTaken': case 'messageActionScreenshotTaken':
@ -902,8 +915,15 @@ export function _messageActionFromTl(this: Message, act: tl.TypeMessageAction):
saved: act.saved!, saved: act.saved!,
converted: act.converted!, converted: act.converted!,
convertStars: act.convertStars ?? Long.ZERO, convertStars: act.convertStars ?? Long.ZERO,
gift: new StarGift(act.gift), refunded: act.refunded!,
gift: act.gift._ === 'starGift'
? new StarGift(act.gift)
: new StarGiftUnique(act.gift, this._peers),
message: act.message ?? null, message: act.message ?? null,
canUpgrade: act.canUpgrade!,
upgraded: act.upgraded!,
upgradeStars: act.upgradeStars ?? Long.ZERO,
upgradeMsgId: act.upgradeMsgId ?? null,
} }
default: default:
return null return null

View file

@ -469,11 +469,22 @@ export class Message {
return this.raw._ === 'message' && !this.raw.noforwards return this.raw._ === 'message' && !this.raw.noforwards
} }
/**
* Whether reactions are possible on this message
*
* > **Note**: for non-service message this is always `true`,
* > regardless if the message can actually be reacted to.
*/
get canBeReacted(): boolean {
if (this.raw._ === 'message') return true
return this.raw.reactionsArePossible!
}
/** /**
* Reactions added to this message, if any * Reactions added to this message, if any
*/ */
get reactions(): MessageReactions | null { get reactions(): MessageReactions | null {
if (this.raw._ === 'messageService' || !this.raw.reactions) { if (!this.raw.reactions) {
return null return null
} }

View file

@ -53,6 +53,10 @@ export class BotInfo {
get privacyPolicyUrl(): string | null { get privacyPolicyUrl(): string | null {
return this.raw.privacyPolicyUrl ?? null return this.raw.privacyPolicyUrl ?? null
} }
get verifierSettings(): tl.TypeBotVerifierSettings | null {
return this.raw.verifierSettings ?? null
}
} }
makeInspectable(BotInfo) makeInspectable(BotInfo)

View file

@ -0,0 +1,24 @@
import type { tl } from '@mtcute/tl'
import { makeInspectable } from '../../utils/inspectable.js'
/** Information about a bot-issued verification */
export class BotVerification {
constructor(readonly raw: tl.RawBotVerification) {}
/** ID of the bot which has verified this user */
get botId(): number {
return this.raw.botId
}
/** ID of the custom emoji to display */
get emojiId(): tl.Long {
return this.raw.icon
}
/** Description of the verification */
get description(): string {
return this.raw.description
}
}
makeInspectable(BotVerification)

View file

@ -4,6 +4,7 @@ import { makeInspectable } from '../../utils/index.js'
import { memoizeGetters } from '../../utils/memoize.js' import { memoizeGetters } from '../../utils/memoize.js'
import { Photo } from '../media/photo.js' import { Photo } from '../media/photo.js'
import { BotVerification } from './bot-verification.js'
import { User } from './user.js' import { User } from './user.js'
/** /**
@ -81,6 +82,14 @@ export class ChatPreview {
get withApproval(): boolean { get withApproval(): boolean {
return this.invite.requestNeeded! return this.invite.requestNeeded!
} }
/**
* If non-null, this user was verified by a bot, and this field contains
* the ID of the custom emoji to display as the verification icon.
*/
get customVerification(): BotVerification | null {
return this.invite.botVerification ? new BotVerification(this.invite.botVerification) : null
}
} }
memoizeGetters(ChatPreview, ['photo', 'someMembers']) memoizeGetters(ChatPreview, ['photo', 'someMembers'])

View file

@ -409,6 +409,15 @@ export class Chat {
return new EmojiStatus(this.raw.emojiStatus) return new EmojiStatus(this.raw.emojiStatus)
} }
/**
* If non-null, this user was verified by a bot, and this field contains
* the ID of the custom emoji to display as the verification icon.
*/
get customVerificationEmojiId(): tl.Long | null {
if (this.raw._ !== 'channel') return null
return this.raw.botVerificationIcon ?? null
}
/** /**
* Color that should be used when rendering the header of * Color that should be used when rendering the header of
* the user's profile * the user's profile

View file

@ -1,8 +1,9 @@
import type { tl } from '@mtcute/tl' import type { tl } from '@mtcute/tl'
import type { TextWithEntities } from '../misc/entities.js'
import type { Peer } from './peer.js' import type { Peer } from './peer.js'
import { makeInspectable } from '../../utils/inspectable.js'
import { makeInspectable } from '../../utils/inspectable.js'
import { memoizeGetters } from '../../utils/memoize.js' import { memoizeGetters } from '../../utils/memoize.js'
import { parsePeer } from './peer.js' import { parsePeer } from './peer.js'
import { PeersIndex } from './peers-index.js' import { PeersIndex } from './peers-index.js'
@ -27,8 +28,8 @@ export class ChatlistPreview {
} }
/** Title of the chatlist (only available for non-joined chatlists) */ /** Title of the chatlist (only available for non-joined chatlists) */
get title(): string { get title(): TextWithEntities {
return this.raw._ === 'chatlists.chatlistInvite' ? this.raw.title : '' return this.raw._ === 'chatlists.chatlistInvite' ? this.raw.title : { text: '', entities: [] }
} }
/** Emoji representing an icon of the chatlist (may only be available for non-joined chatlists) */ /** Emoji representing an icon of the chatlist (may only be available for non-joined chatlists) */

View file

@ -7,6 +7,7 @@ import { StickerSet } from '../misc/sticker-set.js'
import { PeerStories } from '../stories/peer-stories.js' import { PeerStories } from '../stories/peer-stories.js'
import { BotInfo } from './bot-info.js' import { BotInfo } from './bot-info.js'
import { BotVerification } from './bot-verification.js'
import { ChatInviteLink } from './chat-invite-link.js' import { ChatInviteLink } from './chat-invite-link.js'
import { ChatLocation } from './chat-location.js' import { ChatLocation } from './chat-location.js'
import { Chat } from './chat.js' import { Chat } from './chat.js'
@ -356,6 +357,13 @@ export class FullChat extends Chat {
return new PeerStories(this.full.stories, this.peers) return new PeerStories(this.full.stories, this.peers)
} }
/** Information about a bot-issued verification (if any) */
get botVerification(): BotVerification | null {
if (this.full._ !== 'channelFull' || !this.full.botVerification) return null
return new BotVerification(this.full.botVerification)
}
} }
memoizeGetters(FullChat, [ memoizeGetters(FullChat, [
@ -368,5 +376,6 @@ memoizeGetters(FullChat, [
'linkedChat', 'linkedChat',
'recentRequesters', 'recentRequesters',
'stories', 'stories',
'botVerification',
]) ])
makeInspectable(FullChat) makeInspectable(FullChat)

View file

@ -6,6 +6,7 @@ import { Photo } from '../media/photo.js'
import { BusinessAccount } from '../premium/business-account.js' import { BusinessAccount } from '../premium/business-account.js'
import { BotVerification } from './bot-verification.js'
import { Chat } from './chat.js' import { Chat } from './chat.js'
import { PeersIndex } from './peers-index.js' import { PeersIndex } from './peers-index.js'
import { User } from './user.js' import { User } from './user.js'
@ -251,6 +252,13 @@ export class FullUser extends User {
} }
return null return null
} }
/** Information about a bot-issued verification (if any) */
get botVerification(): BotVerification | null {
if (!this.full.botVerification) return null
return new BotVerification(this.full.botVerification)
}
} }
memoizeGetters(FullUser, [ memoizeGetters(FullUser, [
@ -260,5 +268,6 @@ memoizeGetters(FullUser, [
'publicPhoto', 'publicPhoto',
'personalChannel', 'personalChannel',
'business', 'business',
'botVerification',
]) ])
makeInspectable(FullUser) makeInspectable(FullUser)

View file

@ -1,4 +1,5 @@
export * from './bot-info.js' export * from './bot-info.js'
export * from './bot-verification.js'
export * from './chat-colors.js' export * from './chat-colors.js'
export * from './chat-event/index.js' export * from './chat-event/index.js'
export * from './chat-invite-link-member.js' export * from './chat-invite-link-member.js'

View file

@ -148,6 +148,14 @@ export class User {
return this.raw.verified! return this.raw.verified!
} }
/**
* If non-null, this user was verified by a bot, and this field contains
* the ID of the custom emoji to display as the verification icon.
*/
get customVerificationEmojiId(): tl.Long | null {
return this.raw.botVerificationIcon ?? null
}
/** /**
* Whether this user has been restricted. Bots only. * Whether this user has been restricted. Bots only.
* See {@link restrictionReason} for details * See {@link restrictionReason} for details

View file

@ -7,6 +7,7 @@ export * from './business-connection.js'
export * from './business-intro.js' export * from './business-intro.js'
export * from './business-location.js' export * from './business-location.js'
export * from './business-work-hours.js' export * from './business-work-hours.js'
export * from './stars-gift-unique.js'
export * from './stars-gift.js' export * from './stars-gift.js'
export * from './stars-status.js' export * from './stars-status.js'
export * from './stars-transaction.js' export * from './stars-transaction.js'

View file

@ -0,0 +1,178 @@
import type { tl } from '@mtcute/tl'
import type { Sticker } from '../media/sticker.js'
import type { TextWithEntities } from '../misc/entities.js'
import type { PeersIndex } from '../peers/peers-index.js'
import { assert } from '@fuman/utils'
import { makeInspectable } from '../../utils/inspectable.js'
import { memoizeGetters } from '../../utils/memoize.js'
import { parseDocument } from '../media/document-utils.js'
import { User } from '../peers/user.js'
/** An attribute of a unique star gift containing a sticker */
export class StarGiftUniqueAttribute {
constructor(
readonly raw: tl.RawStarGiftAttributeModel | tl.RawStarGiftAttributePattern,
) {}
/** Rarity permille of the attribute */
get permille(): number {
return this.raw.rarityPermille
}
/** Display name of the attribute */
get name(): string {
return this.raw.name
}
get sticker(): Sticker {
assert(this.raw.document._ === 'document')
const parsed = parseDocument(this.raw.document)
assert(parsed.type === 'sticker')
return parsed
}
}
makeInspectable(StarGiftUniqueAttribute)
memoizeGetters(StarGiftUniqueAttribute, ['sticker'])
/** Information about a unique star gift's backdrop */
export class StarGiftUniqueBackdrop {
constructor(
readonly raw: tl.RawStarGiftAttributeBackdrop,
) {}
/** Rarity permille of the attribute */
get permille(): number {
return this.raw.rarityPermille
}
/** Display name of the attribute */
get name(): string {
return this.raw.name
}
get centerColor(): number {
return this.raw.centerColor
}
get edgeColor(): number {
return this.raw.edgeColor
}
get patternColor(): number {
return this.raw.patternColor
}
get textColor(): number {
return this.raw.textColor
}
}
makeInspectable(StarGiftUniqueBackdrop)
/** Details about the original star gift */
export class StarGiftUniqueOriginalDetails {
constructor(
readonly raw: tl.RawStarGiftAttributeOriginalDetails,
readonly _peers: PeersIndex,
) {}
/** ID of the user who sent the original star gift */
get sender(): User | null {
return this.raw.senderId ? new User(this._peers.user(this.raw.senderId)) : null
}
/** ID of the user who received the original star gift */
get recipient(): User {
return new User(this._peers.user(this.raw.recipientId))
}
/** Date when the original star gift was sent */
get date(): Date {
return new Date(this.raw.date * 1000)
}
/** Message attached to the original star gift */
get message(): TextWithEntities | null {
return this.raw.message ?? null
}
}
/** A unique star gift */
export class StarGiftUnique {
readonly _model!: tl.RawStarGiftAttributeModel
readonly _pattern!: tl.RawStarGiftAttributePattern
readonly _backdrop!: tl.RawStarGiftAttributeBackdrop
readonly _originalDetails: tl.RawStarGiftAttributeOriginalDetails | undefined
/** Whether this gift is a unique gift */
readonly isUnique = true as const
constructor(
readonly raw: tl.RawStarGiftUnique,
readonly _peers: PeersIndex,
) {
for (const attr of this.raw.attributes) {
if (attr._ === 'starGiftAttributeModel') {
this._model = attr
} else if (attr._ === 'starGiftAttributePattern') {
this._pattern = attr
} else if (attr._ === 'starGiftAttributeBackdrop') {
this._backdrop = attr
} else if (attr._ === 'starGiftAttributeOriginalDetails') {
this._originalDetails = attr
}
}
assert(this._model !== undefined)
assert(this._pattern !== undefined)
assert(this._backdrop !== undefined)
}
/** Number of the NFT */
get num(): number {
return this.raw.num
}
/** Title of the NFT */
get title(): string {
return this.raw.title
}
/** ID of the user who owns this gift */
get owner(): User {
return new User(this._peers.user(this.raw.ownerId))
}
get availabilityIssued(): number {
return this.raw.availabilityIssued
}
get availabilityTotal(): number {
return this.raw.availabilityTotal
}
/** Model (i.e. the gift itself) of the unique star gift */
get model(): StarGiftUniqueAttribute {
return new StarGiftUniqueAttribute(this._model)
}
/** Pattern of the unique star gift */
get pattern(): StarGiftUniqueAttribute {
return new StarGiftUniqueAttribute(this._pattern)
}
/** Backdrop of the unique star gift */
get backdrop(): StarGiftUniqueBackdrop {
return new StarGiftUniqueBackdrop(this._backdrop)
}
/** Details about the original star gift (if they were retained when minting) */
get originalDetails(): StarGiftUniqueOriginalDetails | null {
if (!this._originalDetails) return null
return new StarGiftUniqueOriginalDetails(this._originalDetails, this._peers)
}
}
makeInspectable(StarGiftUnique)
memoizeGetters(StarGiftUnique, ['model', 'pattern', 'backdrop', 'originalDetails'])

View file

@ -3,20 +3,20 @@ import type { tl } from '@mtcute/tl'
import type { Sticker } from '../media/sticker.js' import type { Sticker } from '../media/sticker.js'
import type { TextWithEntities } from '../misc/entities.js' import type { TextWithEntities } from '../misc/entities.js'
import type { PeersIndex } from '../peers/peers-index.js' import type { PeersIndex } from '../peers/peers-index.js'
import Long from 'long'
import { MtTypeAssertionError } from '../../../types/errors.js' import { MtTypeAssertionError } from '../../../types/errors.js'
import { assertTypeIs } from '../../../utils/type-assertions.js' import { assertTypeIs } from '../../../utils/type-assertions.js'
import { makeInspectable } from '../../utils/inspectable.js' import { makeInspectable } from '../../utils/inspectable.js'
import { memoizeGetters } from '../../utils/memoize.js' import { memoizeGetters } from '../../utils/memoize.js'
import { parseDocument } from '../media/document-utils.js' import { parseDocument } from '../media/document-utils.js'
import { User } from '../peers/user.js' import { User } from '../peers/user.js'
import { StarGiftUnique } from './stars-gift-unique.js'
/** /**
* A gift with stars attached to it. * A gift with stars attached to it.
*/ */
export class StarGift { export class StarGift {
constructor( constructor(readonly raw: tl.RawStarGift) {}
readonly raw: tl.TypeStarGift,
) {}
/** ID of the gift */ /** ID of the gift */
get id(): tl.Long { get id(): tl.Long {
@ -33,6 +33,9 @@ export class StarGift {
return this.raw.limited! return this.raw.limited!
} }
/** Whether this gift is a unique gift */
readonly isUnique = true as const
/** Additional information for sold-out gifts */ /** Additional information for sold-out gifts */
get soldOutInfo(): { get soldOutInfo(): {
/** Date when the first gift was bought */ /** Date when the first gift was bought */
@ -74,6 +77,13 @@ export class StarGift {
return this.raw.convertStars return this.raw.convertStars
} }
/**
* Amount of stars the gift can be upgraded for
*/
get upgradeStars(): tl.Long | null {
return this.raw.upgradeStars ?? null
}
/** /**
* For limited availability gifts, * For limited availability gifts,
* the number of remaining and total gifts available * the number of remaining and total gifts available
@ -112,6 +122,10 @@ export class UserStarGift {
return this.raw.unsaved! return this.raw.unsaved!
} }
get isRefunded(): boolean {
return this.raw.refunded!
}
/** Sender of the gift, if available */ /** Sender of the gift, if available */
get sender(): User | null { get sender(): User | null {
return this.raw.fromId ? new User(this.peers.user(this.raw.fromId)) : null return this.raw.fromId ? new User(this.peers.user(this.raw.fromId)) : null
@ -122,14 +136,27 @@ export class UserStarGift {
return this.raw.msgId ?? null return this.raw.msgId ?? null
} }
/** Date the gift was sent */ /** Date the gift was sent or minted */
get date(): Date { get date(): Date {
return new Date(this.raw.date * 1000) return new Date(this.raw.date * 1000)
} }
/** Whether the gift can be upgraded to a unique gift */
get canUpgrade(): boolean {
return this.raw.canUpgrade!
}
/** Number of stars to upgrade the gift to a unique gift (may be 0) */
get upgradeStars(): tl.Long | null {
if (!this.raw.canUpgrade) return null
return this.raw.upgradeStars ?? Long.ZERO
}
/** The gift itself */ /** The gift itself */
get gift(): StarGift { get gift(): StarGift | StarGiftUnique {
return new StarGift(this.raw.gift) return this.raw.gift._ === 'starGift'
? new StarGift(this.raw.gift)
: new StarGiftUnique(this.raw.gift, this.peers)
} }
/** Text attached to the gift */ /** Text attached to the gift */
@ -144,6 +171,15 @@ export class UserStarGift {
get convertStars(): tl.Long | null { get convertStars(): tl.Long | null {
return this.raw.convertStars ?? null return this.raw.convertStars ?? null
} }
get canExportAt(): Date | null {
return this.raw.canExportAt ? new Date(this.raw.canExportAt * 1000) : null
}
/** Number of stars this gift can be transferred for */
get transferStars(): tl.Long | null {
return this.raw.transferStars ?? null
}
} }
makeInspectable(UserStarGift) makeInspectable(UserStarGift)

View file

@ -9,6 +9,7 @@ import { WebDocument } from '../files/web-document.js'
import { _messageMediaFromTl, type MessageMedia } from '../messages/message-media.js' import { _messageMediaFromTl, type MessageMedia } from '../messages/message-media.js'
import { parsePeer } from '../peers/peer.js' import { parsePeer } from '../peers/peer.js'
import { StarGiftUnique } from './stars-gift-unique.js'
import { StarGift } from './stars-gift.js' import { StarGift } from './stars-gift.js'
// ref: https://github.com/tdlib/td/blob/master/td/telegram/StarManager.cpp#L223 // ref: https://github.com/tdlib/td/blob/master/td/telegram/StarManager.cpp#L223
@ -26,6 +27,8 @@ import { StarGift } from './stars-gift.js'
* - `bot_purchase`: This transaction is a purchase at a bot-operated store * - `bot_purchase`: This transaction is a purchase at a bot-operated store
* - `channel_subscription`: This transaction is a subscription to a channel * - `channel_subscription`: This transaction is a subscription to a channel
* - `star_gift`: This transaction is either a star gift to a user (if outgoing), or converting a star gift to stars (if incoming) * - `star_gift`: This transaction is either a star gift to a user (if outgoing), or converting a star gift to stars (if incoming)
* - `star_gift_upgrade`: This transaction is for a star gift upgrade
* - `star_gift_transfer`: This transaction is for a star gift transfer
* - `api_*`: This transaction is a payment for paid API features * - `api_*`: This transaction is a payment for paid API features
* - `api_floodskip`: This transaction is a payment for a paid bot broadcast * - `api_floodskip`: This transaction is a payment for a paid bot broadcast
*/ */
@ -125,6 +128,20 @@ export type StarsTransactionType =
/** The gift */ /** The gift */
gift: StarGift gift: StarGift
} }
| {
type: 'star_gift_upgrade'
/** Related peer */
peer: Peer
/** The upgraded gift */
gift: StarGiftUnique
}
| {
type: 'star_gift_transfer'
/** Recepient peer */
recepient: Peer
/** The upgraded gift */
gift: StarGiftUnique
}
| { | {
type: 'api_floodskip' type: 'api_floodskip'
/** The number of billed API calls */ /** The number of billed API calls */
@ -232,13 +249,28 @@ export class StarsTransaction {
} }
if (this.raw.stargift) { if (this.raw.stargift) {
if (this.raw.stargift._ === 'starGift') {
return { return {
type: 'star_gift', type: 'star_gift',
peer, peer,
gift: new StarGift(this.raw.stargift), gift: new StarGift(this.raw.stargift),
} }
} else if (this.raw.stargiftUpgrade) {
return {
type: 'star_gift_upgrade',
peer,
gift: new StarGiftUnique(this.raw.stargift, this.peers),
}
} else {
return {
type: 'star_gift_transfer',
recepient: peer,
gift: new StarGiftUnique(this.raw.stargift, this.peers),
}
}
} }
if (this.raw.stargiftUpgrade) {
if (this.raw.msgId) { if (this.raw.msgId) {
if (this.raw.reaction) { if (this.raw.reaction) {
return { return {
@ -257,6 +289,7 @@ export class StarsTransaction {
: undefined, : undefined,
} }
} }
}
if (this.raw.subscriptionPeriod) { if (this.raw.subscriptionPeriod) {
return { return {

View file

@ -2,7 +2,7 @@
TL schema and related utils used for mtcute. TL schema and related utils used for mtcute.
Generated from TL layer **195** (last updated on 30.12.2024). Generated from TL layer **196** (last updated on 01.01.2025).
## About ## About

File diff suppressed because one or more lines are too long

View file

@ -10,6 +10,7 @@
"attachMenuBot": ["bot_id"], "attachMenuBot": ["bot_id"],
"autoDownloadSettings": ["video_size_max", "file_size_max"], "autoDownloadSettings": ["video_size_max", "file_size_max"],
"botInfo": ["user_id"], "botInfo": ["user_id"],
"botVerification": ["bot_id"],
"boost": ["user_id"], "boost": ["user_id"],
"botBusinessConnection": ["user_id"], "botBusinessConnection": ["user_id"],
"businessRecipients": ["users"], "businessRecipients": ["users"],
@ -102,6 +103,8 @@
"requestedPeerChat": ["chat_id"], "requestedPeerChat": ["chat_id"],
"requestedPeerUser": ["user_id"], "requestedPeerUser": ["user_id"],
"starRefProgram": ["bot_id"], "starRefProgram": ["bot_id"],
"starGiftUnique": ["owner_id"],
"starGiftAttributeOriginalDetails": ["sender_id", "recipient_id"],
"secureFile": ["size"], "secureFile": ["size"],
"statsGroupTopAdmin": ["user_id"], "statsGroupTopAdmin": ["user_id"],
"statsGroupTopInviter": ["user_id"], "statsGroupTopInviter": ["user_id"],

View file

@ -1,6 +1,6 @@
{ {
"name": "@mtcute/tl", "name": "@mtcute/tl",
"version": "195.0.0", "version": "196.0.0",
"description": "TL schema used for mtcute", "description": "TL schema used for mtcute",
"author": "alina sireneva <alina@tei.su>", "author": "alina sireneva <alina@tei.su>",
"license": "MIT", "license": "MIT",