Merge branch 'master' of github.com:mtcute/mtcute into fuman-net
This commit is contained in:
commit
439f50bc50
31 changed files with 499 additions and 97 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "mtcute-workspace",
|
||||
"type": "module",
|
||||
"version": "0.17.0",
|
||||
"version": "0.17.2",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.0.6",
|
||||
"description": "Type-safe library for MTProto (Telegram API) for browser and NodeJS",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@mtcute/core",
|
||||
"type": "module",
|
||||
"version": "0.17.0",
|
||||
"version": "0.17.1",
|
||||
"private": true,
|
||||
"description": "Type-safe library for MTProto (Telegram API)",
|
||||
"author": "alina sireneva <alina@tei.su>",
|
||||
|
|
|
@ -202,6 +202,7 @@ export { verifyPasswordEmail } from './methods/password/password-email.js'
|
|||
export { resendPasswordEmail } from './methods/password/password-email.js'
|
||||
export { cancelPasswordEmail } from './methods/password/password-email.js'
|
||||
export { removeCloudPassword } from './methods/password/remove-cloud-password.js'
|
||||
export { acceptStarGift } from './methods/premium/accept-star-gift.js'
|
||||
export { applyBoost } from './methods/premium/apply-boost.js'
|
||||
export { canApplyBoost } from './methods/premium/can-apply-boost.js'
|
||||
export type { CanApplyBoostResult } from './methods/premium/can-apply-boost.js'
|
||||
|
@ -213,9 +214,13 @@ export { getBoosts } from './methods/premium/get-boosts.js'
|
|||
export { getBusinessChatLinks } from './methods/premium/get-business-chat-links.js'
|
||||
export { getBusinessConnection } from './methods/premium/get-business-connection.js'
|
||||
export { getMyBoostSlots } from './methods/premium/get-my-boost-slots.js'
|
||||
export { getStarGiftOptions } from './methods/premium/get-star-gift-options.js'
|
||||
export { getStarGifts } from './methods/premium/get-star-gifts.js'
|
||||
export { getStarsTransactions } from './methods/premium/get-stars-transactions.js'
|
||||
export { iterBoosters } from './methods/premium/iter-boosters.js'
|
||||
export { iterStarGifts } from './methods/premium/iter-star-gifts.js'
|
||||
export { iterStarsTransactions } from './methods/premium/iter-stars-transactions.js'
|
||||
export { sendStarGift } from './methods/premium/send-star-gift.js'
|
||||
export { setBusinessIntro } from './methods/premium/set-business-intro.js'
|
||||
export { setBusinessWorkHours } from './methods/premium/set-business-work-hours.js'
|
||||
export { addStickerToSet } from './methods/stickers/add-sticker-to-set.js'
|
||||
|
@ -247,7 +252,6 @@ export { iterAllStories } from './methods/stories/iter-all-stories.js'
|
|||
export { iterProfileStories } from './methods/stories/iter-profile-stories.js'
|
||||
export { iterStoryViewers } from './methods/stories/iter-story-viewers.js'
|
||||
export { readStories } from './methods/stories/read-stories.js'
|
||||
export { reportStory } from './methods/stories/report-story.js'
|
||||
export { sendStoryReaction } from './methods/stories/send-story-reaction.js'
|
||||
export { sendStory } from './methods/stories/send-story.js'
|
||||
export { togglePeerStoriesArchived } from './methods/stories/toggle-peer-stories-archived.js'
|
||||
|
|
|
@ -89,6 +89,7 @@ import {
|
|||
RawDocument,
|
||||
ReplyMarkup,
|
||||
SentCode,
|
||||
StarGift,
|
||||
StarsStatus,
|
||||
StarsTransaction,
|
||||
Sticker,
|
||||
|
@ -107,6 +108,7 @@ import {
|
|||
UploadFileLike,
|
||||
UploadedFile,
|
||||
User,
|
||||
UserStarGift,
|
||||
UserStatusUpdate,
|
||||
UserTypingUpdate,
|
||||
} from '../types/index.js'
|
||||
|
|
|
@ -55,23 +55,21 @@ export async function findDialogs(client: ITelegramClient, peers: MaybeArray<str
|
|||
foundIdxToOriginalIdx.set(foundInputPeers.length - 1, i)
|
||||
}
|
||||
|
||||
if (foundInputPeers.length === 0) {
|
||||
// we didn't find anything, we can't even fetch the dialogs
|
||||
throw new MtPeerNotFoundError(`Could not find dialogs with peers: ${peers.join(', ')}`)
|
||||
}
|
||||
const ret: Dialog[] = Array.from({ length: peers.length })
|
||||
|
||||
if (foundInputPeers.length !== 0) {
|
||||
// we have some input peers, try to fetch them
|
||||
const dialogs = await getPeerDialogs(client, foundInputPeers)
|
||||
|
||||
if (foundInputPeers.length === peers.length) {
|
||||
return dialogs
|
||||
}
|
||||
|
||||
const ret: Dialog[] = Array.from({ length: peers.length })
|
||||
|
||||
// populate found dialogs
|
||||
for (const [idx, origIdx] of foundIdxToOriginalIdx) {
|
||||
ret[origIdx] = dialogs[idx]
|
||||
}
|
||||
}
|
||||
|
||||
// now we need to iterate over all dialogs and try to find the rest
|
||||
for await (const dialog of iterDialogs(client, {
|
||||
|
|
|
@ -257,6 +257,7 @@ export async function _normalizeInputMedia(
|
|||
fileMime: sendMime,
|
||||
fileSize: media.fileSize,
|
||||
requireFileSize: media.type === 'photo',
|
||||
requireExtension: media.type === 'photo',
|
||||
})
|
||||
inputFile = uploaded.inputFile
|
||||
mime = uploaded.mime
|
||||
|
|
|
@ -102,6 +102,15 @@ export async function uploadFile(
|
|||
* the stream will be buffered in memory and the file size will be inferred from the buffer.
|
||||
*/
|
||||
requireFileSize?: boolean
|
||||
|
||||
/**
|
||||
* When using `inputMediaUploadedPhoto` (e.g. when sending an uploaded photo) require
|
||||
* the file extension to be known beforehand.
|
||||
*
|
||||
* This will make the library try to guess the file extension from the file mime type,
|
||||
* or throw an error if it cannot be guessed.
|
||||
*/
|
||||
requireExtension?: boolean
|
||||
},
|
||||
): Promise<UploadedFile> {
|
||||
// normalize params
|
||||
|
@ -128,6 +137,7 @@ export async function uploadFile(
|
|||
if (HAS_FILE && file instanceof File) {
|
||||
fileName = file.name
|
||||
fileSize = file.size
|
||||
fileMime = file.type
|
||||
file = file.stream()
|
||||
}
|
||||
|
||||
|
@ -312,6 +322,21 @@ export async function uploadFile(
|
|||
// telegram requires us to specify the file extension
|
||||
const ext = MIME_TO_EXTENSION[fileMime!]
|
||||
fileName = ext ? `${DEFAULT_FILE_NAME}.${ext}` : DEFAULT_FILE_NAME
|
||||
} else if (params.requireExtension) {
|
||||
const extFromMime = MIME_TO_EXTENSION[fileMime!]
|
||||
|
||||
const idx = fileName.lastIndexOf('.')
|
||||
const extFromName = idx === -1 ? undefined : fileName.slice(idx + 1)
|
||||
|
||||
if (!extFromName) {
|
||||
if (!extFromMime) {
|
||||
throw new MtArgumentError(`File name does not have an extension, and we cannot guess it from the mime type (${fileMime})`)
|
||||
}
|
||||
|
||||
fileName = `${fileName}.${extFromMime}`
|
||||
} else if (extFromMime && extFromName !== extFromMime) {
|
||||
throw new MtArgumentError(`File name has ${extFromName} extension (${fileName}), but the mime type (${fileMime}) expects it to be ${extFromMime}`)
|
||||
}
|
||||
}
|
||||
|
||||
let inputFile: tl.TypeInputFile
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import type { ITelegramClient } from '../../client.types.js'
|
||||
import { type InputMessageId, normalizeInputMessageId } from '../../types/messages/input-message-id.js'
|
||||
import { resolveUser } from '../users/resolve-peer.js'
|
||||
|
||||
// @available=user
|
||||
/**
|
||||
* Accept, hide or convert a star gift.
|
||||
*
|
||||
* @returns Whether the action was successful
|
||||
*/
|
||||
export async function acceptStarGift(
|
||||
client: ITelegramClient,
|
||||
params: InputMessageId & {
|
||||
/**
|
||||
* Action to perform on the gift.
|
||||
* - `save` - save the gift to your profile
|
||||
* - `hide` - hide the gift from your profile
|
||||
* - `convert` - convert the gift to stars (can't be undone)
|
||||
*/
|
||||
action: 'save' | 'hide' | 'convert'
|
||||
},
|
||||
): Promise<boolean> {
|
||||
const { action } = params
|
||||
const { chatId, message } = normalizeInputMessageId(params)
|
||||
const userId = await resolveUser(client, chatId)
|
||||
|
||||
return client.call(
|
||||
action === 'convert'
|
||||
? {
|
||||
_: 'payments.convertStarGift',
|
||||
userId,
|
||||
msgId: message,
|
||||
}
|
||||
: {
|
||||
_: 'payments.saveStarGift',
|
||||
unsave: action === 'hide',
|
||||
userId,
|
||||
msgId: message,
|
||||
},
|
||||
)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { assertTypeIsNot } from '../../../utils/type-assertions.js'
|
||||
import type { ITelegramClient } from '../../client.types.js'
|
||||
import { StarGift } from '../../types/premium/stars-gift.js'
|
||||
|
||||
// @available=user
|
||||
/**
|
||||
* Get the list of available star gifts.
|
||||
*/
|
||||
export async function getStarGiftOptions(client: ITelegramClient): Promise<StarGift[]> {
|
||||
const res = await client.call({
|
||||
_: 'payments.getStarGifts',
|
||||
hash: 0,
|
||||
})
|
||||
|
||||
assertTypeIsNot('payments.getStarGifts', res, 'payments.starGiftsNotModified')
|
||||
|
||||
return res.gifts.map(gift => new StarGift(gift))
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
import type { ITelegramClient } from '../../client.types.js'
|
||||
import type { InputPeerLike } from '../../types/peers/peer.js'
|
||||
import { PeersIndex } from '../../types/peers/peers-index.js'
|
||||
import { UserStarGift } from '../../types/premium/stars-gift.js'
|
||||
import type { ArrayPaginated } from '../../types/utils.js'
|
||||
import { makeArrayPaginated } from '../../utils/misc-utils.js'
|
||||
import { resolveUser } from '../users/resolve-peer.js'
|
||||
|
||||
// @available=user
|
||||
/**
|
||||
* Get a list of gifts sent to a user.
|
||||
*
|
||||
* @param userId User whose gifts to fetch
|
||||
* @returns Gifts sent to the user
|
||||
*/
|
||||
export async function getStarGifts(
|
||||
client: ITelegramClient,
|
||||
userId: InputPeerLike,
|
||||
params?: {
|
||||
/**
|
||||
* Offset for pagination.
|
||||
*/
|
||||
offset?: string
|
||||
|
||||
/**
|
||||
* Maximum number of gifts to fetch.
|
||||
*
|
||||
* @default 100
|
||||
*/
|
||||
limit?: number
|
||||
},
|
||||
): Promise<ArrayPaginated<UserStarGift, string>> {
|
||||
const { offset = '', limit = 100 } = params ?? {}
|
||||
|
||||
const res = await client.call({
|
||||
_: 'payments.getUserStarGifts',
|
||||
userId: await resolveUser(client, userId),
|
||||
offset,
|
||||
limit,
|
||||
})
|
||||
|
||||
const peers = PeersIndex.from(res)
|
||||
const gifts = res.gifts.map(gift => new UserStarGift(gift, peers))
|
||||
|
||||
return makeArrayPaginated(gifts, res.count, offset)
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import type { ITelegramClient } from '../../client.types.js'
|
||||
import type { InputPeerLike, UserStarGift } from '../../types/index.js'
|
||||
import { resolvePeer } from '../users/resolve-peer.js'
|
||||
|
||||
import { getStarGifts } from './get-star-gifts.js'
|
||||
|
||||
// @available=user
|
||||
/**
|
||||
* Iterate over gifts sent to a given user.
|
||||
*
|
||||
* Wrapper over {@link getStarGifts}
|
||||
*
|
||||
* @param peerId Peer ID
|
||||
* @param params Additional parameters
|
||||
*/
|
||||
export async function* iterStarGifts(
|
||||
client: ITelegramClient,
|
||||
peerId: InputPeerLike,
|
||||
params?: Parameters<typeof getStarGifts>[2] & {
|
||||
/**
|
||||
* Total number of gifts to fetch
|
||||
*
|
||||
* @default Infinity, i.e. fetch all gifts
|
||||
*/
|
||||
limit?: number
|
||||
|
||||
/**
|
||||
* Number of gifts to fetch per request
|
||||
* Usually you don't need to change this
|
||||
*
|
||||
* @default 100
|
||||
*/
|
||||
chunkSize?: number
|
||||
},
|
||||
): AsyncIterableIterator<UserStarGift> {
|
||||
if (!params) params = {}
|
||||
const { limit = Infinity, chunkSize = 100 } = params
|
||||
|
||||
let { offset } = params
|
||||
let current = 0
|
||||
|
||||
const peer = await resolvePeer(client, peerId)
|
||||
|
||||
for (;;) {
|
||||
const res = await getStarGifts(client, peer, {
|
||||
offset,
|
||||
limit: Math.min(limit - current, chunkSize),
|
||||
})
|
||||
|
||||
for (const gift of res) {
|
||||
yield gift
|
||||
|
||||
if (++current >= limit) return
|
||||
}
|
||||
|
||||
if (!res.next) return
|
||||
offset = res.next
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
import Long from 'long'
|
||||
import type { tl } from '@mtcute/tl'
|
||||
|
||||
import type { InputPeerLike } from '../../types/peers/peer.js'
|
||||
import type { StarGift } from '../../types/premium/stars-gift.js'
|
||||
import { type InputText, inputTextToTl } from '../../types/misc/entities.js'
|
||||
import type { ITelegramClient } from '../../client.types.js'
|
||||
import { resolveUser } from '../users/resolve-peer.js'
|
||||
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||
import { _findMessageInUpdate } from '../messages/find-in-update.js'
|
||||
import type { Message } from '../../types/messages/message.js'
|
||||
|
||||
/**
|
||||
* Send a star gift to a user.
|
||||
*
|
||||
* > **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 sent gift
|
||||
*/
|
||||
export async function sendStarGift(
|
||||
client: ITelegramClient,
|
||||
params: {
|
||||
/** ID of the user to send the gift to */
|
||||
userId: InputPeerLike
|
||||
|
||||
/** ID of the gift to send */
|
||||
gift: Long | StarGift
|
||||
|
||||
/**
|
||||
* Whether to send the gift anonymously
|
||||
* (i.e. if the recipient chooses to display the gift
|
||||
* on their profile, your name won't be visible)
|
||||
*/
|
||||
anonymous?: boolean
|
||||
|
||||
/** Message to send along with the gift */
|
||||
message?: InputText
|
||||
|
||||
/**
|
||||
* Whether to dispatch the new message event
|
||||
* to the client's update handler.
|
||||
*/
|
||||
shouldDispatch?: true
|
||||
},
|
||||
): Promise<Message> {
|
||||
const { userId, gift, anonymous, message, shouldDispatch } = params
|
||||
|
||||
const invoice: tl.TypeInputInvoice = {
|
||||
_: 'inputInvoiceStarGift',
|
||||
hideName: anonymous,
|
||||
userId: await resolveUser(client, userId),
|
||||
giftId: Long.isLong(gift) ? gift : gift.id,
|
||||
message: message ? inputTextToTl(message) : undefined,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
|
@ -5,7 +5,6 @@ import type {
|
|||
InputFileLike,
|
||||
InputPeerLike,
|
||||
InputStickerSetItem,
|
||||
StickerSourceType,
|
||||
StickerType,
|
||||
} from '../../types/index.js'
|
||||
import {
|
||||
|
@ -54,13 +53,6 @@ export async function createStickerSet(
|
|||
*/
|
||||
type?: StickerType
|
||||
|
||||
/**
|
||||
* File source type for the stickers in this set.
|
||||
*
|
||||
* @default `static`, i.e. regular WEBP stickers.
|
||||
*/
|
||||
sourceType?: StickerSourceType
|
||||
|
||||
/**
|
||||
* Whether to create "adaptive" emoji set.
|
||||
*
|
||||
|
@ -113,8 +105,6 @@ export async function createStickerSet(
|
|||
|
||||
const res = await client.call({
|
||||
_: 'stickers.createStickerSet',
|
||||
animated: params.sourceType === 'animated',
|
||||
videos: params.sourceType === 'video',
|
||||
masks: params.type === 'mask',
|
||||
emojis: params.type === 'emoji',
|
||||
textColor: params.adaptive,
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import type { tl } from '@mtcute/tl'
|
||||
|
||||
import type { MaybeArray } from '../../../types/utils.js'
|
||||
import { assertTrue } from '../../../utils/type-assertions.js'
|
||||
import type { ITelegramClient } from '../../client.types.js'
|
||||
import type { InputPeerLike } from '../../types/index.js'
|
||||
import { resolvePeer } from '../users/resolve-peer.js'
|
||||
|
||||
/**
|
||||
* Report a story (or multiple stories) to the moderation team
|
||||
*/
|
||||
export async function reportStory(
|
||||
client: ITelegramClient,
|
||||
peerId: InputPeerLike,
|
||||
storyIds: MaybeArray<number>,
|
||||
params?: {
|
||||
/**
|
||||
* Reason for reporting
|
||||
*
|
||||
* @default inputReportReasonSpam
|
||||
*/
|
||||
reason?: tl.TypeReportReason
|
||||
|
||||
/**
|
||||
* Additional comment to the report
|
||||
*/
|
||||
message?: string
|
||||
},
|
||||
): Promise<void> {
|
||||
const { reason = { _: 'inputReportReasonSpam' }, message = '' } = params ?? {}
|
||||
|
||||
const r = await client.call({
|
||||
_: 'stories.report',
|
||||
peer: await resolvePeer(client, peerId),
|
||||
id: Array.isArray(storyIds) ? storyIds : [storyIds],
|
||||
message,
|
||||
reason,
|
||||
})
|
||||
|
||||
assertTrue('stories.report', r)
|
||||
}
|
|
@ -333,6 +333,20 @@ export function requestPeer(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Button to copy text to the user's clipboard
|
||||
*/
|
||||
export function copy(params: {
|
||||
text: string
|
||||
copyText?: string
|
||||
}): tl.RawKeyboardButtonCopy {
|
||||
return {
|
||||
_: 'keyboardButtonCopy',
|
||||
text: params.text,
|
||||
copyText: params?.copyText ?? params.text,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a button in the keyboard by its text or by predicate
|
||||
*
|
||||
|
|
|
@ -90,6 +90,10 @@ export class Video extends RawDocument {
|
|||
get videoStartTs(): number | null {
|
||||
return this.attr._ === 'documentAttributeVideo' ? this.attr.videoStartTs ?? null : null
|
||||
}
|
||||
|
||||
get codec(): string | null {
|
||||
return this.attr._ === 'documentAttributeVideo' ? this.attr.videoCodec ?? null : null
|
||||
}
|
||||
}
|
||||
|
||||
memoizeGetters(Video, ['fileName', 'thumbnails', 'fileId', 'uniqueFileId', 'isAnimation'])
|
||||
|
|
|
@ -6,6 +6,8 @@ import { _callDiscardReasonFromTl } from '../calls/index.js'
|
|||
import { Photo } from '../media/photo.js'
|
||||
import type { Peer } from '../peers/peer.js'
|
||||
import { parsePeer } from '../peers/peer.js'
|
||||
import { StarGift } from '../premium/stars-gift.js'
|
||||
import type { TextWithEntities } from '../misc/entities.js'
|
||||
|
||||
import type { Message } from './message.js'
|
||||
|
||||
|
@ -478,7 +480,7 @@ export interface ActionPaymentRefunded {
|
|||
}
|
||||
|
||||
/** Telegram Stars were gifted by the other chat participant */
|
||||
export interface ActionStarsGifted {
|
||||
export interface ActionStarGifted {
|
||||
readonly type: 'stars_gifted'
|
||||
|
||||
/** Whether `currency` is a cryptocurrency */
|
||||
|
@ -512,12 +514,30 @@ export interface ActionStarsPrize {
|
|||
/** Transaction ID */
|
||||
transactionId: string
|
||||
|
||||
// todo: what does this mean?
|
||||
boostPeer: Peer
|
||||
|
||||
/** Message ID containing the giveaway */
|
||||
giveawayMessageId: number
|
||||
}
|
||||
|
||||
export interface ActionStarGift {
|
||||
readonly type: 'stars_gift'
|
||||
|
||||
/** Whether the sender chose to send the gift anonymously */
|
||||
nameHidden: boolean
|
||||
/** Whether this gift was saved to the recipient's profile */
|
||||
saved: boolean
|
||||
/** Whether this gift was converted to stars */
|
||||
converted: boolean
|
||||
/** Amount of stars the gift can be converted to by the recipient */
|
||||
convertStars: tl.Long
|
||||
/** The gift itself */
|
||||
gift: StarGift
|
||||
/** Message attached to the gift */
|
||||
message: TextWithEntities | null
|
||||
}
|
||||
|
||||
export type MessageAction =
|
||||
| ActionChatCreated
|
||||
| ActionChannelCreated
|
||||
|
@ -562,8 +582,9 @@ export type MessageAction =
|
|||
| ActionGiveawayEnded
|
||||
| ActionBoostApply
|
||||
| ActionPaymentRefunded
|
||||
| ActionStarsGifted
|
||||
| ActionStarGifted
|
||||
| ActionStarsPrize
|
||||
| ActionStarGift
|
||||
| null
|
||||
|
||||
/** @internal */
|
||||
|
@ -848,6 +869,16 @@ export function _messageActionFromTl(this: Message, act: tl.TypeMessageAction):
|
|||
boostPeer: parsePeer(act.boostPeer, this._peers),
|
||||
giveawayMessageId: act.giveawayMsgId,
|
||||
}
|
||||
case 'messageActionStarGift':
|
||||
return {
|
||||
type: 'stars_gift',
|
||||
nameHidden: act.nameHidden!,
|
||||
saved: act.saved!,
|
||||
converted: act.converted!,
|
||||
convertStars: act.convertStars,
|
||||
gift: new StarGift(act.gift),
|
||||
message: act.message ?? null,
|
||||
}
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { memoizeGetters } from '../../utils/memoize.js'
|
|||
import { MtEmptyError } from '../errors.js'
|
||||
import type { InputFileLike } from '../files/index.js'
|
||||
import { parseSticker } from '../media/document-utils.js'
|
||||
import type { MaskPosition, Sticker, StickerSourceType, StickerType } from '../media/index.js'
|
||||
import type { MaskPosition, Sticker, StickerType } from '../media/index.js'
|
||||
import { Thumbnail } from '../media/index.js'
|
||||
|
||||
/**
|
||||
|
@ -175,21 +175,6 @@ export class StickerSet {
|
|||
return 'sticker'
|
||||
}
|
||||
|
||||
/**
|
||||
* Source file type of the stickers in this set
|
||||
*/
|
||||
get sourceType(): StickerSourceType {
|
||||
if (this.brief.animated) {
|
||||
return 'animated'
|
||||
}
|
||||
|
||||
if (this.brief.videos) {
|
||||
return 'video'
|
||||
}
|
||||
|
||||
return 'static'
|
||||
}
|
||||
|
||||
/**
|
||||
* Date when this sticker set was installed
|
||||
*/
|
||||
|
|
|
@ -8,3 +8,4 @@ export * from './business-intro.js'
|
|||
export * from './business-work-hours.js'
|
||||
export * from './stars-transaction.js'
|
||||
export * from './stars-status.js'
|
||||
export * from './stars-gift.js'
|
||||
|
|
123
packages/core/src/highlevel/types/premium/stars-gift.ts
Normal file
123
packages/core/src/highlevel/types/premium/stars-gift.ts
Normal file
|
@ -0,0 +1,123 @@
|
|||
import type { tl } from '@mtcute/tl'
|
||||
|
||||
import type { Sticker } from '../media/sticker.js'
|
||||
import { parseDocument } from '../media/document-utils.js'
|
||||
import { assertTypeIs } from '../../../utils/type-assertions.js'
|
||||
import { MtTypeAssertionError } from '../../../types/errors.js'
|
||||
import { makeInspectable } from '../../utils/inspectable.js'
|
||||
import { memoizeGetters } from '../../utils/memoize.js'
|
||||
import type { PeersIndex } from '../peers/peers-index.js'
|
||||
import { User } from '../peers/user.js'
|
||||
import type { TextWithEntities } from '../misc/entities.js'
|
||||
|
||||
/**
|
||||
* A gift with stars attached to it.
|
||||
*/
|
||||
export class StarGift {
|
||||
constructor(
|
||||
readonly raw: tl.TypeStarGift,
|
||||
) {}
|
||||
|
||||
/** ID of the gift */
|
||||
get id(): tl.Long {
|
||||
return this.raw.id
|
||||
}
|
||||
|
||||
/** Sticker associated with the gift */
|
||||
get sticker(): Sticker {
|
||||
assertTypeIs('StarGift#sticker', this.raw.sticker, 'document')
|
||||
const parsed = parseDocument(this.raw.sticker)
|
||||
|
||||
if (parsed.type !== 'sticker') {
|
||||
throw new MtTypeAssertionError('StarGift#sticker', 'sticker', parsed.type)
|
||||
}
|
||||
|
||||
return parsed
|
||||
}
|
||||
|
||||
/** Amount of stars the gift was purchased for */
|
||||
get purchaseStars(): tl.Long {
|
||||
return this.raw.stars
|
||||
}
|
||||
|
||||
/**
|
||||
* Amount of stars the gift can be converted to by the recipient
|
||||
*/
|
||||
get convertStars(): tl.Long {
|
||||
return this.raw.convertStars
|
||||
}
|
||||
|
||||
/**
|
||||
* For limited availability gifts,
|
||||
* the number of remaining and total gifts available
|
||||
*/
|
||||
get availability(): { remains: number, total: number } | null {
|
||||
if (!this.raw.availabilityRemains || !this.raw.availabilityTotal) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
remains: this.raw.availabilityRemains,
|
||||
total: this.raw.availabilityTotal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
makeInspectable(StarGift)
|
||||
memoizeGetters(StarGift, ['sticker'])
|
||||
|
||||
/**
|
||||
* Information about a certain user's {@link StarGift}.
|
||||
*/
|
||||
export class UserStarGift {
|
||||
constructor(
|
||||
readonly raw: tl.RawUserStarGift,
|
||||
readonly peers: PeersIndex,
|
||||
) {}
|
||||
|
||||
/** Whether the sender chose to appear anonymously */
|
||||
get nameHidden(): boolean {
|
||||
return this.raw.nameHidden!
|
||||
}
|
||||
|
||||
/** Whether this gift is not visible on the recipient's profile */
|
||||
get hidden(): boolean {
|
||||
return this.raw.unsaved!
|
||||
}
|
||||
|
||||
/** Sender of the gift, if available */
|
||||
get sender(): User | null {
|
||||
return this.raw.fromId ? new User(this.peers.user(this.raw.fromId)) : null
|
||||
}
|
||||
|
||||
/** Message ID where the gift was sent, if available */
|
||||
get messageId(): number | null {
|
||||
return this.raw.msgId ?? null
|
||||
}
|
||||
|
||||
/** Date the gift was sent */
|
||||
get date(): Date {
|
||||
return new Date(this.raw.date * 1000)
|
||||
}
|
||||
|
||||
/** The gift itself */
|
||||
get gift(): StarGift {
|
||||
return new StarGift(this.raw.gift)
|
||||
}
|
||||
|
||||
/** Text attached to the gift */
|
||||
get text(): TextWithEntities | null {
|
||||
return this.raw.message ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
* If the gift was converted to stars, the amount of stars
|
||||
* it was converted to
|
||||
*/
|
||||
get convertStars(): tl.Long | null {
|
||||
return this.raw.convertStars ?? null
|
||||
}
|
||||
}
|
||||
|
||||
makeInspectable(UserStarGift)
|
||||
memoizeGetters(UserStarGift, ['sender', 'gift'])
|
|
@ -9,6 +9,8 @@ import type { User } from '../peers/user.js'
|
|||
import { type MessageMedia, _messageMediaFromTl } from '../messages/message-media.js'
|
||||
import { WebDocument } from '../files/web-document.js'
|
||||
|
||||
import { StarGift } from './stars-gift.js'
|
||||
|
||||
// ref: https://github.com/tdlib/td/blob/master/td/telegram/StarManager.cpp#L223
|
||||
|
||||
/**
|
||||
|
@ -23,6 +25,7 @@ import { WebDocument } from '../files/web-document.js'
|
|||
* - `gift`: This transaction is a gift from a user
|
||||
* - `bot_purchase`: This transaction is a purchase at a bot-operated store
|
||||
* - `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)
|
||||
*/
|
||||
export type StarsTransactionType =
|
||||
| { type: 'unsupported' }
|
||||
|
@ -113,6 +116,13 @@ export type StarsTransactionType =
|
|||
/** ID of the message containing the giveaway where the stars were given */
|
||||
messageId: number
|
||||
}
|
||||
| {
|
||||
type: 'star_gift'
|
||||
/** Related peer */
|
||||
peer: Peer
|
||||
/** The gift */
|
||||
gift: StarGift
|
||||
}
|
||||
|
||||
export class StarsTransaction {
|
||||
constructor(
|
||||
|
@ -201,6 +211,14 @@ export class StarsTransaction {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.raw.stargift) {
|
||||
return {
|
||||
type: 'star_gift',
|
||||
peer,
|
||||
gift: new StarGift(this.raw.stargift),
|
||||
}
|
||||
}
|
||||
|
||||
if (this.raw.msgId) {
|
||||
if (this.raw.reaction) {
|
||||
return {
|
||||
|
|
|
@ -5,10 +5,10 @@ import type { Logger } from './logger.js'
|
|||
export function reportUnknownError(log: Logger, error: tl.RpcError, method: string): void {
|
||||
if (typeof fetch !== 'function') return
|
||||
|
||||
fetch(`https://rpc.pwrtelegram.xyz/?code=${error.code}&method=${method}&error=${error.text}`)
|
||||
fetch(`https://report-rpc-error.madelineproto.xyz/?code=${error.code}&method=${method}&error=${error.text}`)
|
||||
.then(r => r.json())
|
||||
.then((r) => {
|
||||
if (r.ok) {
|
||||
if (r.result) {
|
||||
log.info('telerpc responded with error info for %s: %s', error.text, r.result)
|
||||
} else {
|
||||
log.info(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@mtcute/dispatcher",
|
||||
"type": "module",
|
||||
"version": "0.17.0",
|
||||
"version": "0.17.2",
|
||||
"private": true,
|
||||
"description": "Updates dispatcher and bot framework for @mtcute/client",
|
||||
"author": "alina sireneva <alina@tei.su>",
|
||||
|
|
|
@ -66,7 +66,7 @@ export class WizardScene<State extends object> extends Dispatcher<State & Wizard
|
|||
if (step >= this._steps) {
|
||||
await state.exit()
|
||||
} else {
|
||||
await state.merge({ $step: step }, this._defaultState)
|
||||
await state.merge({ $step: step }, { fallback: this._defaultState })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@mtcute/html-parser",
|
||||
"type": "module",
|
||||
"version": "0.17.0",
|
||||
"version": "0.17.1",
|
||||
"private": true,
|
||||
"description": "HTML entities parser for mtcute",
|
||||
"author": "alina sireneva <alina@tei.su>",
|
||||
|
|
|
@ -361,6 +361,14 @@ describe('HtmlMessageEntityParser', () => {
|
|||
test(htm`hewwo ${htm`<br>`} world`, [], 'hewwo \nworld')
|
||||
})
|
||||
|
||||
it('should keep whitespaces in raw strings', () => {
|
||||
const dot = ' ∙ '
|
||||
const lf = '\n'
|
||||
test(htm`this is${dot}some text${lf}xd`, [], 'this is ∙ some text\nxd')
|
||||
|
||||
test(htm`hewwo ${htm`<br>`} world`, [], 'hewwo \nworld')
|
||||
})
|
||||
|
||||
it('should not ignore newlines and indentation in pre', () => {
|
||||
test(
|
||||
htm`<pre>this is some text\n\nwith newlines</pre>`,
|
||||
|
|
|
@ -262,9 +262,11 @@ function parse(
|
|||
return
|
||||
}
|
||||
|
||||
if (typeof it === 'string' || typeof it === 'number') {
|
||||
if (typeof it === 'string') {
|
||||
processPendingText()
|
||||
pendingText += it
|
||||
} else if (Long.isLong(it)) {
|
||||
processPendingText(false, true)
|
||||
} else if (Long.isLong(it) || typeof it === 'number') {
|
||||
pendingText += it.toString(10)
|
||||
} else {
|
||||
// TextWithEntities or MessageEntity
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
TL schema and related utils used for mtcute.
|
||||
|
||||
Generated from TL layer **187** (last updated on 07.09.2024).
|
||||
Generated from TL layer **189** (last updated on 05.10.2024).
|
||||
|
||||
## About
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -138,7 +138,6 @@
|
|||
"updateChatUserTyping": ["chat_id"],
|
||||
"updateDeleteChannelMessages": ["channel_id"],
|
||||
"updateGroupCall": ["chat_id"],
|
||||
"updateGroupInvitePrivacyForbidden": ["user_id"],
|
||||
"updateInlineBotCallbackQuery": ["user_id"],
|
||||
"updatePinnedChannelMessages": ["channel_id"],
|
||||
"updateReadChannelDiscussionInbox": ["channel_id", "broadcast_id"],
|
||||
|
@ -157,6 +156,7 @@
|
|||
"user": ["id"],
|
||||
"userEmpty": ["id"],
|
||||
"userFull": ["id", "personal_channel_id"],
|
||||
"userStarGift": ["from_id"],
|
||||
"userStories": ["user_id"],
|
||||
"webAuthorization": ["bot_id"],
|
||||
"_": "Dummy line teehee~"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@mtcute/tl",
|
||||
"version": "187.0.0",
|
||||
"version": "189.0.0",
|
||||
"description": "TL schema used for mtcute",
|
||||
"author": "alina sireneva <alina@tei.su>",
|
||||
"license": "MIT",
|
||||
|
|
Loading…
Reference in a new issue