Two small cleanups that came out of the round-2 architecture review and are sub-five-minutes each — bundled because each one is too small to justify its own commit. #5 — flatten single-file directories packages/core/src/bridge/builders/element-builder.ts -> packages/core/src/bridge/element-builder.ts packages/core/src/bridge/handlers/msg-push-handler.ts -> packages/core/src/bridge/msg-push-handler.ts Both dirs had exactly one file in them — a smell that says "planned a sibling that never landed". Moving up one level removes the wrapper directory. Touch list: - bridge.ts: 2 import paths - bridge/actions/forward.ts: 2 import paths - msg-push-handler.ts: internal ../X -> ./X for events, proto/element, proto/message (the dynamic-import-typeof references too) - element-builder.ts: internal ../X -> ./X for bridge, events, highway/* - 4 test files: import paths (2 regular, 2 vi.mock) #6 — drop IdentityService.hasWriteFailure identity-service.ts had a `private writeFailed = false` field set by the runWrite catch block and exposed via `get hasWriteFailure()`, but a full-repo grep showed zero callers of the getter. It was a public API stub for a feature that hadn't been wired (a webui health indicator, presumably). Removed: - the field - the getter - the assignment in runWrite's catch block (the error log on the next line is the actual observable behavior; nothing else reads the flag) If we want a "did any write fail this session" surface later, it's trivial to add back with an explicit consumer in mind. Behavior preserved end-to-end. No public API change outside the moved files. 369 tests pass (unchanged). 3 stability runs.
96 lines
2.9 KiB
TypeScript
96 lines
2.9 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { parseMsgPush, MSG_PUSH_CMD } from '../src/bridge/msg-push-handler';
|
|
import { QQInfo, type GroupMemberInfo, type QQGroupInfo } from '../src/bridge/qq-info';
|
|
import { PushMsgSchema } from '../src/bridge/proto/message';
|
|
import { GroupChangeSchema, OperatorInfoSchema } from '../src/bridge/proto/notify';
|
|
import type { GroupMemberJoin } from '../src/bridge/events';
|
|
import type { PacketInfo } from '../src/protocol/types';
|
|
import { protoEncode } from '../src/protobuf/decode';
|
|
|
|
const SELF_UIN = '10001';
|
|
const GROUP_ID = 123456789;
|
|
|
|
function makeGroupMember(uin: number, uid: string): GroupMemberInfo {
|
|
return {
|
|
uin,
|
|
uid,
|
|
nickname: '',
|
|
card: '',
|
|
role: 'member',
|
|
level: 0,
|
|
title: '',
|
|
joinTime: 0,
|
|
lastSentTime: 0,
|
|
shutUpTime: 0,
|
|
};
|
|
}
|
|
|
|
function makeGroup(members: GroupMemberInfo[] = []): QQGroupInfo {
|
|
return {
|
|
groupId: GROUP_ID,
|
|
groupName: '',
|
|
remark: '',
|
|
memberCount: members.length,
|
|
memberMax: 500,
|
|
members: new Map(members.map((member) => [member.uin, member])),
|
|
};
|
|
}
|
|
|
|
function makeQqInfo(members: GroupMemberInfo[] = []): QQInfo {
|
|
const qqInfo = new QQInfo(SELF_UIN);
|
|
qqInfo.setGroups([makeGroup(members)]);
|
|
return qqInfo;
|
|
}
|
|
|
|
function makeGroupIncreasePacket(memberUid: string, operatorUid = '', fromUin = GROUP_ID): PacketInfo {
|
|
const operatorBytes = operatorUid
|
|
? protoEncode({ operatorField: { uid: operatorUid } } as any, OperatorInfoSchema)
|
|
: new Uint8Array(0);
|
|
const content = protoEncode({
|
|
groupUin: GROUP_ID,
|
|
memberUid,
|
|
operatorBytes,
|
|
} as any, GroupChangeSchema);
|
|
const body = protoEncode({
|
|
message: {
|
|
responseHead: { fromUin },
|
|
contentHead: { msgType: 33, timestamp: 1710000000 },
|
|
body: { msgContent: content },
|
|
},
|
|
status: 0,
|
|
} as any, PushMsgSchema);
|
|
|
|
return {
|
|
pid: 1,
|
|
uin: SELF_UIN,
|
|
serviceCmd: MSG_PUSH_CMD,
|
|
seqId: 1,
|
|
retCode: 0,
|
|
fromClient: false,
|
|
body,
|
|
};
|
|
}
|
|
|
|
describe('parseMsgPush group member increase', () => {
|
|
it('does not fall back to the group id when a joining uid is unresolved', () => {
|
|
const [event] = parseMsgPush(makeGroupIncreasePacket('u_new_member'), makeQqInfo()) as GroupMemberJoin[];
|
|
|
|
expect(event.kind).toBe('group_member_join');
|
|
expect(event.groupId).toBe(GROUP_ID);
|
|
expect(event.userUin).toBe(0);
|
|
expect(event.operatorUin).toBe(0);
|
|
expect(event.userUid).toBe('u_new_member');
|
|
});
|
|
|
|
it('resolves joining uid and operator uid from the member cache when available', () => {
|
|
const member = makeGroupMember(22222, 'u_member');
|
|
const operator = makeGroupMember(33333, 'u_operator');
|
|
const [event] = parseMsgPush(makeGroupIncreasePacket(member.uid, operator.uid), makeQqInfo([member, operator])) as GroupMemberJoin[];
|
|
|
|
expect(event.userUin).toBe(member.uin);
|
|
expect(event.operatorUin).toBe(operator.uin);
|
|
expect(event.userUid).toBe(member.uid);
|
|
expect(event.operatorUid).toBe(operator.uid);
|
|
});
|
|
});
|