diff --git a/packages/core/tests/msg-push-handler.test.ts b/packages/core/tests/msg-push-handler.test.ts index 3e7d9ab5..33606ecc 100644 --- a/packages/core/tests/msg-push-handler.test.ts +++ b/packages/core/tests/msg-push-handler.test.ts @@ -181,9 +181,20 @@ describe('parseMsgPush group member increase', () => { ), identity, ) as GroupMemberJoin[]; + const [unknownHighBits] = parseMsgPush( + makeGroupIncreasePacket( + member.uid, + operator.uid, + GROUP_ID, + Buffer.from(operator.uid, 'utf8'), + 0x103, + ), + identity, + ) as GroupMemberJoin[]; expect(approved.joinType).toBe('approve'); expect(invited.joinType).toBe('invite'); + expect(unknownHighBits.joinType).toBe('approve'); }); it('reports malformed raw operator bytes with bounded context', () => { diff --git a/packages/protocol/src/msg-push/decoders/group-member-change.ts b/packages/protocol/src/msg-push/decoders/group-member-change.ts index c94a5b1d..263de7ae 100644 --- a/packages/protocol/src/msg-push/decoders/group-member-change.ts +++ b/packages/protocol/src/msg-push/decoders/group-member-change.ts @@ -5,11 +5,12 @@ import { decodeNestedOperatorUid, decodeRawOperatorUid, resolveUidToUin } from ' import type { MsgPushDecoder } from '../registry'; function joinTypeFromOperationType(raw: number): NonNullable { - // QQ sets the high bit on the PkgType=33 operation code. After normalizing - // it, code 3 means an invitation; code 2 (and unknown/absent values) means - // approval. Do not use the nested `join_type`: that is an invitation-source - // enum rather than OneBot's approve/invite distinction. - return (raw & 0x7f) === 3 ? 'invite' : 'approve'; + // QQ uses bit 0x80 as a flag on the PkgType=33 operation code. Clear only + // that bit: other high bits remain significant in the native handler. The + // normalized code 3 means an invitation; all other values mean approval. + // Do not use the nested `join_type`: that is an invitation-source enum. + const normalized = raw - (raw & 0x80); + return normalized === 3 ? 'invite' : 'approve'; } export const decodeGroupMemberJoin: MsgPushDecoder = (ctx) => {