mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1876dd29ac | ||
![]() |
9944b53266 | ||
![]() |
9a791e3a21 | ||
![]() |
64c5eb6c04 | ||
![]() |
e5750786cb | ||
![]() |
18cb46ade5 | ||
![]() |
e39c89a441 |
@@ -4,7 +4,7 @@
|
|||||||
"name": "LLOneBot",
|
"name": "LLOneBot",
|
||||||
"slug": "LLOneBot",
|
"slug": "LLOneBot",
|
||||||
"description": "实现 OneBot 11 协议,用于 QQ 机器人开发",
|
"description": "实现 OneBot 11 协议,用于 QQ 机器人开发",
|
||||||
"version": "3.32.6",
|
"version": "3.32.8",
|
||||||
"icon": "./icon.webp",
|
"icon": "./icon.webp",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -91,17 +91,26 @@ interface FetchFileRes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchFile(url: string, headersInit?: Record<string, string>): Promise<FetchFileRes> {
|
export async function fetchFile(url: string, headersInit?: Record<string, string>): Promise<FetchFileRes> {
|
||||||
const headers: Record<string, string> = {
|
const headers = new Headers({
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
|
||||||
'Host': new URL(url).hostname,
|
'Host': new URL(url).hostname,
|
||||||
...headersInit
|
...headersInit
|
||||||
}
|
})
|
||||||
const raw = await fetch(url, { headers }).catch((err) => {
|
let raw = await fetch(url, { headers }).catch((err) => {
|
||||||
if (err.cause) {
|
if (err.cause) {
|
||||||
throw err.cause
|
throw err.cause
|
||||||
}
|
}
|
||||||
throw err
|
throw err
|
||||||
})
|
})
|
||||||
|
if (raw.status === 403 && !headers.has('Referer')) {
|
||||||
|
headers.set('Referer', url)
|
||||||
|
raw = await fetch(url, { headers }).catch((err) => {
|
||||||
|
if (err.cause) {
|
||||||
|
throw err.cause
|
||||||
|
}
|
||||||
|
throw err
|
||||||
|
})
|
||||||
|
}
|
||||||
if (!raw.ok) throw new Error(`statusText: ${raw.statusText}`)
|
if (!raw.ok) throw new Error(`statusText: ${raw.statusText}`)
|
||||||
return {
|
return {
|
||||||
data: Buffer.from(await raw.arrayBuffer()),
|
data: Buffer.from(await raw.arrayBuffer()),
|
||||||
@@ -133,7 +142,7 @@ export async function uri2local(uri: string, filename?: string, needExt?: boolea
|
|||||||
|
|
||||||
if (type === FileUriType.RemoteURL) {
|
if (type === FileUriType.RemoteURL) {
|
||||||
try {
|
try {
|
||||||
const res = await fetchFile(uri, { 'Referer': uri })
|
const res = await fetchFile(uri)
|
||||||
const match = res.url.match(/.+\/([^/?]*)(?=\?)?/)
|
const match = res.url.match(/.+\/([^/?]*)(?=\?)?/)
|
||||||
if (match?.[1]) {
|
if (match?.[1]) {
|
||||||
filename ??= match[1].replace(/[/\\:*?"<>|]/g, '_')
|
filename ??= match[1].replace(/[/\\:*?"<>|]/g, '_')
|
||||||
|
@@ -127,7 +127,6 @@ class MessageUniqueWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getShortIdByMsgId(msgId: string): number | undefined {
|
getShortIdByMsgId(msgId: string): number | undefined {
|
||||||
@@ -160,4 +159,4 @@ class MessageUniqueWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper()
|
export const MessageUnique: MessageUniqueWrapper = new MessageUniqueWrapper()
|
||||||
|
@@ -23,8 +23,7 @@ export default class Log {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const dateTime = new Date(record.timestamp).toLocaleString()
|
const dateTime = new Date(record.timestamp).toLocaleString()
|
||||||
const userInfo = selfInfo.uin ? `${selfInfo.nick}(${selfInfo.uin})` : ''
|
const content = `${dateTime} [${record.type}] ${selfInfo.nick}(${selfInfo.uin}) | ${record.name} ${record.content}\n\n`
|
||||||
const content = `${dateTime} [${record.type}] ${userInfo} | ${record.name} ${record.content}\n\n`
|
|
||||||
appendFile(file, content, noop)
|
appendFile(file, content, noop)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -183,7 +183,7 @@ export class NTQQMsgApi extends Service {
|
|||||||
if (!arkElement) {
|
if (!arkElement) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const forwardData = JSON.parse(arkElement.arkElement.bytesData)
|
const forwardData = JSON.parse(arkElement.arkElement!.bytesData)
|
||||||
if (forwardData.app != 'com.tencent.multimsg') {
|
if (forwardData.app != 'com.tencent.multimsg') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@@ -27,8 +27,8 @@ declare module 'cordis' {
|
|||||||
}
|
}
|
||||||
interface Events {
|
interface Events {
|
||||||
'nt/message-created': (input: RawMessage[]) => void
|
'nt/message-created': (input: RawMessage[]) => void
|
||||||
'nt/message-deleted': (input: RawMessage[]) => void
|
'nt/message-deleted': (input: RawMessage) => void
|
||||||
'nt/message-sent': (input: RawMessage[]) => void
|
'nt/message-sent': (input: RawMessage) => void
|
||||||
'nt/group-notify': (input: GroupNotify[]) => void
|
'nt/group-notify': (input: GroupNotify[]) => void
|
||||||
'nt/friend-request': (input: FriendRequest[]) => void
|
'nt/friend-request': (input: FriendRequest[]) => void
|
||||||
'nt/group-member-info-updated': (input: { groupCode: string, members: GroupMember[] }) => void
|
'nt/group-member-info-updated': (input: { groupCode: string, members: GroupMember[] }) => void
|
||||||
@@ -96,7 +96,7 @@ class Core extends Service {
|
|||||||
}
|
}
|
||||||
for (const path of pathList) {
|
for (const path of pathList) {
|
||||||
if (path) {
|
if (path) {
|
||||||
fs.unlink(picPath, () => {
|
fs.unlink(path, () => {
|
||||||
this.ctx.logger.info('删除文件成功', path)
|
this.ctx.logger.info('删除文件成功', path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -174,23 +174,26 @@ class Core extends Service {
|
|||||||
this.ctx.parallel('nt/message-created', payload.msgList)
|
this.ctx.parallel('nt/message-created', payload.msgList)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const sentMsgIds = new Map<string, boolean>()
|
||||||
const recallMsgIds: string[] = [] // 避免重复上报
|
const recallMsgIds: string[] = [] // 避免重复上报
|
||||||
|
|
||||||
registerReceiveHook<{ msgList: RawMessage[] }>([ReceiveCmdS.UPDATE_MSG], payload => {
|
registerReceiveHook<{ msgList: RawMessage[] }>([ReceiveCmdS.UPDATE_MSG], payload => {
|
||||||
const list = payload.msgList.filter(v => {
|
for (const msg of payload.msgList) {
|
||||||
if (recallMsgIds.includes(v.msgId)) {
|
if (msg.recallTime !== '0' && !recallMsgIds.includes(msg.msgId)) {
|
||||||
return false
|
recallMsgIds.push(msg.msgId)
|
||||||
|
this.ctx.parallel('nt/message-deleted', msg)
|
||||||
|
} else if (sentMsgIds.get(msg.msgId)) {
|
||||||
|
sentMsgIds.delete(msg.msgId)
|
||||||
|
this.ctx.parallel('nt/message-sent', msg)
|
||||||
}
|
}
|
||||||
recallMsgIds.push(v.msgId)
|
}
|
||||||
return true
|
|
||||||
})
|
|
||||||
this.ctx.parallel('nt/message-deleted', list)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmdS.SELF_SEND_MSG, payload => {
|
registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmdS.SELF_SEND_MSG, payload => {
|
||||||
if (!this.config.reportSelfMessage) {
|
if (!this.config.reportSelfMessage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.ctx.parallel('nt/message-sent', [payload.msgRecord])
|
sentMsgIds.set(payload.msgRecord.msgId, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
const groupNotifyFlags: string[] = []
|
const groupNotifyFlags: string[] = []
|
||||||
|
@@ -102,7 +102,7 @@ export interface SendPicElement {
|
|||||||
export interface SendReplyElement {
|
export interface SendReplyElement {
|
||||||
elementType: ElementType.REPLY
|
elementType: ElementType.REPLY
|
||||||
elementId: ''
|
elementId: ''
|
||||||
replyElement: ReplyElement
|
replyElement: Partial<ReplyElement>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendFaceElement {
|
export interface SendFaceElement {
|
||||||
@@ -129,6 +129,12 @@ export interface ReplyElement {
|
|||||||
replayMsgId: string
|
replayMsgId: string
|
||||||
senderUin: string
|
senderUin: string
|
||||||
senderUinStr: string
|
senderUinStr: string
|
||||||
|
sourceMsgIdInRecords: string
|
||||||
|
senderUid: string
|
||||||
|
senderUidStr: string
|
||||||
|
sourceMsgIsIncPic: boolean // 原消息是否有图片
|
||||||
|
sourceMsgText: string
|
||||||
|
replyMsgTime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileElement {
|
export interface FileElement {
|
||||||
@@ -303,7 +309,7 @@ export enum GrayTipElementSubType {
|
|||||||
|
|
||||||
export interface GrayTipElement {
|
export interface GrayTipElement {
|
||||||
subElementType: GrayTipElementSubType
|
subElementType: GrayTipElementSubType
|
||||||
revokeElement: {
|
revokeElement?: {
|
||||||
operatorRole: string
|
operatorRole: string
|
||||||
operatorUid: string
|
operatorUid: string
|
||||||
operatorNick: string
|
operatorNick: string
|
||||||
@@ -313,14 +319,14 @@ export interface GrayTipElement {
|
|||||||
isSelfOperate?: boolean
|
isSelfOperate?: boolean
|
||||||
wording: string // 自定义的撤回提示语
|
wording: string // 自定义的撤回提示语
|
||||||
}
|
}
|
||||||
aioOpGrayTipElement: TipAioOpGrayTipElement
|
aioOpGrayTipElement?: TipAioOpGrayTipElement
|
||||||
groupElement: TipGroupElement
|
groupElement?: TipGroupElement
|
||||||
xmlElement: {
|
xmlElement?: {
|
||||||
templId: string
|
templId: string
|
||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
jsonGrayTipElement: {
|
jsonGrayTipElement?: {
|
||||||
busiId: number
|
busiId: string
|
||||||
jsonStr: string
|
jsonStr: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -485,36 +491,7 @@ export interface RawMessage {
|
|||||||
sendStatus?: number // 消息状态,别人发的2是已撤回,自己发的2是已发送
|
sendStatus?: number // 消息状态,别人发的2是已撤回,自己发的2是已发送
|
||||||
recallTime: string // 撤回时间, "0"是没有撤回
|
recallTime: string // 撤回时间, "0"是没有撤回
|
||||||
records: RawMessage[]
|
records: RawMessage[]
|
||||||
elements: {
|
elements: MessageElement[]
|
||||||
elementId: string
|
|
||||||
elementType: ElementType
|
|
||||||
replyElement: {
|
|
||||||
sourceMsgIdInRecords: string
|
|
||||||
senderUid: string // 原消息发送者QQ号
|
|
||||||
sourceMsgIsIncPic: boolean // 原消息是否有图片
|
|
||||||
sourceMsgText: string
|
|
||||||
replayMsgSeq: string // 源消息的msgSeq,可以通过这个找到源消息的msgId
|
|
||||||
senderUidStr: string
|
|
||||||
replyMsgTime: string
|
|
||||||
}
|
|
||||||
textElement: {
|
|
||||||
atType: AtType
|
|
||||||
atUid: string // QQ号
|
|
||||||
content: string
|
|
||||||
atNtUid: string // uid号
|
|
||||||
}
|
|
||||||
picElement: PicElement
|
|
||||||
pttElement: PttElement
|
|
||||||
arkElement: ArkElement
|
|
||||||
grayTipElement: GrayTipElement
|
|
||||||
faceElement: FaceElement
|
|
||||||
videoElement: VideoElement
|
|
||||||
fileElement: FileElement
|
|
||||||
marketFaceElement: MarketFaceElement
|
|
||||||
inlineKeyboardElement: InlineKeyboardElement
|
|
||||||
markdownElement: MarkdownElement
|
|
||||||
multiForwardMsgElement: MultiForwardMsgElement
|
|
||||||
}[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Peer {
|
export interface Peer {
|
||||||
@@ -529,7 +506,7 @@ export interface MessageElement {
|
|||||||
extBufForUI: string //"0x"
|
extBufForUI: string //"0x"
|
||||||
textElement?: TextElement
|
textElement?: TextElement
|
||||||
faceElement?: FaceElement
|
faceElement?: FaceElement
|
||||||
marketFaceElement?: MarkdownElement
|
marketFaceElement?: MarketFaceElement
|
||||||
replyElement?: ReplyElement
|
replyElement?: ReplyElement
|
||||||
picElement?: PicElement
|
picElement?: PicElement
|
||||||
pttElement?: PttElement
|
pttElement?: PttElement
|
||||||
|
@@ -59,7 +59,7 @@ export abstract class GetFileBase extends BaseAction<GetFilePayload, GetFileResp
|
|||||||
if (!findEle) {
|
if (!findEle) {
|
||||||
throw new Error('element not found')
|
throw new Error('element not found')
|
||||||
}
|
}
|
||||||
res.url = await this.ctx.ntFileApi.getImageUrl(findEle.picElement)
|
res.url = await this.ctx.ntFileApi.getImageUrl(findEle.picElement!)
|
||||||
} else if (fileCache[0].elementType === ElementType.VIDEO) {
|
} else if (fileCache[0].elementType === ElementType.VIDEO) {
|
||||||
res.url = await this.ctx.ntFileApi.getVideoUrl(peer, fileCache[0].msgId, fileCache[0].elementId)
|
res.url = await this.ctx.ntFileApi.getVideoUrl(peer, fileCache[0].msgId, fileCache[0].elementId)
|
||||||
}
|
}
|
||||||
|
@@ -226,20 +226,16 @@ class OneBot11Adapter extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleRecallMsg(msgList: RawMessage[]) {
|
private handleRecallMsg(message: RawMessage) {
|
||||||
for (const message of msgList) {
|
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId)
|
||||||
if (message.recallTime != '0') {
|
if (!oriMessageId) {
|
||||||
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId)
|
return
|
||||||
if (!oriMessageId) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
OB11Entities.recallEvent(this.ctx, message, oriMessageId).then((recallEvent) => {
|
|
||||||
if (recallEvent) {
|
|
||||||
this.dispatch(recallEvent)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
OB11Entities.recallEvent(this.ctx, message, oriMessageId).then((recallEvent) => {
|
||||||
|
if (recallEvent) {
|
||||||
|
this.dispatch(recallEvent)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleFriendRequest(buddyReqs: FriendRequest[]) {
|
private async handleFriendRequest(buddyReqs: FriendRequest[]) {
|
||||||
@@ -404,7 +400,7 @@ class OneBot11Adapter extends Service {
|
|||||||
this.handleRecallMsg(input)
|
this.handleRecallMsg(input)
|
||||||
})
|
})
|
||||||
this.ctx.on('nt/message-sent', input => {
|
this.ctx.on('nt/message-sent', input => {
|
||||||
this.handleMsg(input)
|
this.handleMsg([input])
|
||||||
})
|
})
|
||||||
this.ctx.on('nt/group-notify', input => {
|
this.ctx.on('nt/group-notify', input => {
|
||||||
this.handleGroupNotify(input)
|
this.handleGroupNotify(input)
|
||||||
|
@@ -375,29 +375,25 @@ export namespace OB11Entities {
|
|||||||
for (const element of msg.elements) {
|
for (const element of msg.elements) {
|
||||||
if (element.grayTipElement) {
|
if (element.grayTipElement) {
|
||||||
const { grayTipElement } = element
|
const { grayTipElement } = element
|
||||||
if (grayTipElement.subElementType === GrayTipElementSubType.JSON) {
|
if (grayTipElement.jsonGrayTipElement?.busiId === '1061') {
|
||||||
const json = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr)
|
const json = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr)
|
||||||
if (grayTipElement.jsonGrayTipElement.busiId === 1061) {
|
const pokedetail: Dict[] = json.items
|
||||||
const pokedetail: Dict[] = json.items
|
//筛选item带有uid的元素
|
||||||
//筛选item带有uid的元素
|
const poke_uid = pokedetail.filter(item => item.uid)
|
||||||
const poke_uid = pokedetail.filter(item => item.uid)
|
if (poke_uid.length === 2) {
|
||||||
if (poke_uid.length == 2) {
|
return new OB11FriendPokeEvent(
|
||||||
return new OB11FriendPokeEvent(
|
Number(await ctx.ntUserApi.getUinByUid(poke_uid[0].uid)),
|
||||||
parseInt(await ctx.ntUserApi.getUinByUid(poke_uid[0].uid)),
|
Number(await ctx.ntUserApi.getUinByUid(poke_uid[1].uid)),
|
||||||
parseInt(await ctx.ntUserApi.getUinByUid(poke_uid[1].uid)),
|
pokedetail
|
||||||
pokedetail
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (grayTipElement.xmlElement?.templId === '10229') {
|
||||||
|
const uin = +msg.peerUin || +(await ctx.ntUserApi.getUinByUid(msg.peerUid))
|
||||||
|
return new OB11FriendAddNoticeEvent(uin)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 好友增加事件
|
|
||||||
if (msg.msgType === 5 && msg.subMsgType === 12) {
|
|
||||||
const uin = +msg.peerUin || +(await ctx.ntUserApi.getUinByUid(msg.peerUid))
|
|
||||||
const event = new OB11FriendAddNoticeEvent(uin)
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function groupEvent(ctx: Context, msg: RawMessage): Promise<OB11GroupNoticeEvent | void> {
|
export async function groupEvent(ctx: Context, msg: RawMessage): Promise<OB11GroupNoticeEvent | void> {
|
||||||
@@ -564,8 +560,8 @@ export namespace OB11Entities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (grayTipElement.subElementType == GrayTipElementSubType.JSON) {
|
else if (grayTipElement.subElementType == GrayTipElementSubType.JSON) {
|
||||||
const json = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr)
|
const json = JSON.parse(grayTipElement.jsonGrayTipElement!.jsonStr)
|
||||||
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
if (grayTipElement.jsonGrayTipElement?.busiId === '1061') {
|
||||||
const pokedetail: Dict[] = json.items
|
const pokedetail: Dict[] = json.items
|
||||||
//筛选item带有uid的元素
|
//筛选item带有uid的元素
|
||||||
const poke_uid = pokedetail.filter(item => item.uid)
|
const poke_uid = pokedetail.filter(item => item.uid)
|
||||||
@@ -578,7 +574,7 @@ export namespace OB11Entities {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (grayTipElement.jsonGrayTipElement.busiId == 2401) {
|
if (grayTipElement.jsonGrayTipElement?.busiId === '2401') {
|
||||||
ctx.logger.info('收到群精华消息', json)
|
ctx.logger.info('收到群精华消息', json)
|
||||||
const searchParams = new URL(json.items[0].jp).searchParams
|
const searchParams = new URL(json.items[0].jp).searchParams
|
||||||
const msgSeq = searchParams.get('msgSeq')!
|
const msgSeq = searchParams.get('msgSeq')!
|
||||||
@@ -605,7 +601,7 @@ export namespace OB11Entities {
|
|||||||
)
|
)
|
||||||
// 获取MsgSeq+Peer可获取具体消息
|
// 获取MsgSeq+Peer可获取具体消息
|
||||||
}
|
}
|
||||||
if (grayTipElement.jsonGrayTipElement.busiId == 2407) {
|
if (grayTipElement.jsonGrayTipElement?.busiId === '2407') {
|
||||||
const memberUin = json.items[1].param[0]
|
const memberUin = json.items[1].param[0]
|
||||||
const title = json.items[3].txt
|
const title = json.items[3].txt
|
||||||
ctx.logger.info('收到群成员新头衔消息', json)
|
ctx.logger.info('收到群成员新头衔消息', json)
|
||||||
@@ -632,9 +628,9 @@ export namespace OB11Entities {
|
|||||||
if (!msgElement) {
|
if (!msgElement) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const revokeElement = msgElement.grayTipElement.revokeElement
|
const revokeElement = msgElement.grayTipElement!.revokeElement
|
||||||
if (msg.chatType === ChatType.group) {
|
if (msg.chatType === ChatType.group) {
|
||||||
const operator = await ctx.ntGroupApi.getGroupMember(msg.peerUid, revokeElement.operatorUid)
|
const operator = await ctx.ntGroupApi.getGroupMember(msg.peerUid, revokeElement!.operatorUid)
|
||||||
return new OB11GroupRecallNoticeEvent(
|
return new OB11GroupRecallNoticeEvent(
|
||||||
parseInt(msg.peerUid),
|
parseInt(msg.peerUid),
|
||||||
parseInt(msg.senderUin!),
|
parseInt(msg.senderUin!),
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const version = '3.32.6'
|
export const version = '3.32.8'
|
||||||
|
Reference in New Issue
Block a user