SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run

This commit is contained in:
TanTan committed 2026-11-13 09:02:00 +08:00
commit fa9c73363d
1367 files changed
+355735

No files matched your search

@@ -0,0 +1,589 @@
import { getLogLevel, setLogLevel, subscribeLogs, type LogEntry } from '@snowluma/common/logger';
import type { PacketSender, SendPacketResult } from '@snowluma/common/packet-sender';
import type { PacketInfo } from '@snowluma/common/protocol-types';
import { IdentityService } from '@snowluma/protocol/identity-service';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { BridgeManager } from '../src/bridge/manager';
const previousLogLevel = getLogLevel();
const OK_RESULT: SendPacketResult = {
success: true,
gotResponse: true,
errorCode: 0,
errorMessage: '',
responseData: Buffer.alloc(0),
};
function makeSender() {
const sendPacket = vi.fn<PacketSender['sendPacket']>(async () => OK_RESULT);
return {
client: { sendPacket } satisfies PacketSender,
sendPacket,
};
}
function runtimeTrace(entries: LogEntry[]): LogEntry[] {
return entries.filter((entry) => entry.level === 'trace' && entry.scope === 'Bridge.Runtime');
}
function testSends(sendPacket: ReturnType<typeof vi.fn>): unknown[][] {
return sendPacket.mock.calls.filter(([cmd]) => String(cmd).startsWith('Test.'));
}
function ownershipSendTrace(entries: LogEntry[]): LogEntry[] {
return runtimeTrace(entries).filter((entry) => {
if (entry.message.startsWith('bridge_sender_fact ')) {
return true;
}
if (entry.message.startsWith('bridge_send_')) {
return entry.message.includes('serviceCmd="Test.');
}
return false;
});
}
function packet(pid: number, uin: string): PacketInfo {
return {
pid,
uin,
serviceCmd: 'Test.Unhandled',
seqId: 1,
retCode: 0,
fromClient: false,
body: Buffer.alloc(0),
};
}
describe('BridgeManager PID ownership', () => {
beforeEach(() => {
vi.spyOn(IdentityService, 'openForUin').mockImplementation((uin) =>
IdentityService.memory(uin),
);
});
afterEach(() => {
setLogLevel(previousLogLevel);
vi.restoreAllMocks();
});
it('traces binding, account replacement, detach, and session closure under semantic contexts', () => {
const manager = new BridgeManager();
const entries: LogEntry[] = [];
setLogLevel('trace');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onHookLogin(101, '10001', makeSender().client);
manager.onHookLogin(202, '10001', makeSender().client);
manager.onHookLogin(101, '20002', makeSender().client);
manager.onPidDisconnected(202);
manager.onPidDisconnected(101);
manager.onPidDisconnected(101);
const trace = runtimeTrace(entries).filter(
(entry) =>
entry.message.startsWith('bridge_binding_') ||
entry.message.startsWith('bridge_detach_'),
);
expect(trace.map((entry) => entry.message)).toEqual([
'bridge_binding_start pid=101 uin="10001" source=login previousUin=null',
'bridge_binding_branch pid=101 uin="10001" branch=session_created',
expect.stringMatching(
/^bridge_binding_terminal pid=101 uin="10001" source=login outcome=completed reason=bound created=true activePid=101 elapsedMs=\d+$/,
),
'bridge_binding_start pid=202 uin="10001" source=login previousUin=null',
expect.stringMatching(
/^bridge_binding_terminal pid=202 uin="10001" source=login outcome=completed reason=bound created=false activePid=202 elapsedMs=\d+$/,
),
'bridge_binding_start pid=101 uin="20002" source=login previousUin="10001"',
'bridge_binding_branch pid=101 uin="20002" branch=account_rebind previousUin="10001"',
'bridge_binding_branch pid=101 uin="20002" branch=previous_session_retained previousUin="10001" activePid=202',
'bridge_binding_branch pid=101 uin="20002" branch=session_created',
expect.stringMatching(
/^bridge_binding_terminal pid=101 uin="20002" source=login outcome=completed reason=rebound created=true activePid=101 elapsedMs=\d+$/,
),
'bridge_detach_start pid=202 uin="10001"',
'bridge_detach_branch pid=202 uin="10001" branch=session_closed',
expect.stringMatching(
/^bridge_detach_terminal pid=202 uin="10001" outcome=completed reason=session_closed activePid=null elapsedMs=\d+$/,
),
'bridge_detach_start pid=101 uin="20002"',
'bridge_detach_branch pid=101 uin="20002" branch=session_closed',
expect.stringMatching(
/^bridge_detach_terminal pid=101 uin="20002" outcome=completed reason=session_closed activePid=null elapsedMs=\d+$/,
),
]);
const starts = trace.filter((entry) => entry.message.includes('_start '));
const terminals = trace.filter((entry) => entry.message.includes('_terminal '));
expect(starts).toHaveLength(5);
expect(terminals).toHaveLength(5);
for (const start of starts) {
expect(terminals.some((terminal) => terminal.req === start.req)).toBe(true);
}
} finally {
unsubscribe();
}
});
it('records ownership invariant failures as the unique detach terminal', () => {
const manager = new BridgeManager();
const entries: LogEntry[] = [];
setLogLevel('trace');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onHookLogin(101, '10001', makeSender().client);
manager.getBridge('10001')!.detachPid(101);
expect(() => manager.onPidDisconnected(101)).toThrowError(
'BridgeManager invariant violated: PID=101 is mapped to UIN=10001, but Bridge does not own the PID',
);
const detach = runtimeTrace(entries).filter((entry) =>
entry.message.startsWith('bridge_detach_'),
);
expect(detach.map((entry) => entry.message)).toEqual([
'bridge_detach_start pid=101 uin="10001"',
expect.stringMatching(
/^bridge_detach_terminal pid=101 uin="10001" outcome=failed reason=invariant_violation error="BridgeManager invariant violated: PID=101 is mapped to UIN=10001, but Bridge does not own the PID" elapsedMs=\d+$/,
),
]);
expect(detach[0]!.req).toBe(detach[1]!.req);
} finally {
unsubscribe();
}
});
it('records complete incoming packet bytes under one top-level TRACE request', async () => {
const manager = new BridgeManager();
const entries: LogEntry[] = [];
const body = Buffer.from([
0x00,
0xff,
...Array.from({ length: 160 }, (_, index) => (159 - index) & 0xff),
]);
setLogLevel('trace');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onPacket({
pid: 101,
uin: '10001',
serviceCmd: 'Trace\nCommand',
seqId: 987,
retCode: -5,
fromClient: true,
body,
});
await new Promise((resolve) => setImmediate(resolve));
const packetEntries = entries.filter(
(entry) =>
entry.level === 'trace' &&
(entry.scope === 'Bridge.Packet' || entry.scope === 'Protocol.Packet'),
);
expect(packetEntries).toHaveLength(3);
expect(packetEntries.map((entry) => entry.req)).toEqual([
expect.any(Number),
packetEntries[0]!.req,
packetEntries[0]!.req,
]);
expect(packetEntries[0]!.message).toBe(
`packet_push serviceCmd="Trace\\nCommand" seqId=987 retCode=-5 fromClient=true pid=101 uin="10001" length=${body.length} body=${body.toString('hex')}`,
);
expect(packetEntries[1]!.message).toBe(
'packet_branch serviceCmd="Trace\\nCommand" seqId=987 branch=parser_unregistered',
);
expect(packetEntries[2]!.message).toMatch(
/^packet_terminal serviceCmd="Trace\\nCommand" seqId=987 outcome=dropped reason=parser_unregistered events=0 dispatched=0 elapsedMs=\d+$/,
);
for (const entry of packetEntries) {
expect(entry.message).not.toContain('...');
}
} finally {
unsubscribe();
}
});
it('records invalid UIN as a routed packet drop without creating a session', () => {
const manager = new BridgeManager();
const entries: LogEntry[] = [];
setLogLevel('trace');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onPacket({
...packet(101, '0'),
body: Buffer.from([0x00, 0xff]),
});
expect(entries.filter((entry) => entry.scope === 'Bridge.Packet')).toEqual(
expect.arrayContaining([
expect.objectContaining({
level: 'trace',
req: expect.any(Number),
message:
'packet_push serviceCmd="Test.Unhandled" seqId=1 retCode=0 fromClient=false pid=101 uin="0" length=2 body=00ff',
}),
expect.objectContaining({
level: 'trace',
req: expect.any(Number),
message: expect.stringMatching(
/^packet_terminal serviceCmd="Test\.Unhandled" seqId=1 outcome=dropped reason=invalid_uin events=0 dispatched=0 elapsedMs=\d+$/,
),
}),
]),
);
expect(manager.getBridge('0')).toBeNull();
} finally {
unsubscribe();
}
});
it('assigns distinct request ids to independent incoming packets', () => {
const manager = new BridgeManager();
const entries: LogEntry[] = [];
setLogLevel('trace');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onPacket(packet(101, '0'));
manager.onPacket(packet(202, '0'));
const packetEntries = entries.filter(
(entry) => entry.level === 'trace' && entry.scope === 'Bridge.Packet',
);
expect(packetEntries).toHaveLength(4);
expect(packetEntries[0]!.req).toEqual(expect.any(Number));
expect(packetEntries[1]!.req).toBe(packetEntries[0]!.req);
expect(packetEntries[2]!.req).toEqual(expect.any(Number));
expect(packetEntries[3]!.req).toBe(packetEntries[2]!.req);
expect(packetEntries[2]!.req).not.toBe(packetEntries[0]!.req);
} finally {
unsubscribe();
}
});
it('does not render incoming packet bytes or allocate request IDs while TRACE is disabled', () => {
const manager = new BridgeManager();
const entries: LogEntry[] = [];
setLogLevel('debug');
const hex = vi.spyOn(Buffer.prototype, 'toString');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onPacket({
...packet(0, '10001'),
body: Buffer.from([0x00, 0xff]),
});
expect(hex).not.toHaveBeenCalledWith('hex');
expect(entries.some((entry) => entry.req !== undefined)).toBe(false);
} finally {
unsubscribe();
hex.mockRestore();
}
});
it('detaches a PID from its old UIN before starting its replacement session', () => {
const manager = new BridgeManager();
const first = makeSender();
const second = makeSender();
const lifecycle: string[] = [];
manager.subscribeSessions({ started: (uin) => lifecycle.push(`started:${uin}`) });
manager.subscribeSessions({ closed: (uin) => lifecycle.push(`closed:${uin}`) });
manager.onHookLogin(101, '10001', first.client);
const oldBridge = manager.getBridge('10001')!;
const dispose = vi.spyOn(oldBridge, 'dispose');
manager.onHookLogin(101, '20002', second.client);
expect(lifecycle).toEqual(['started:10001', 'closed:10001', 'started:20002']);
expect(manager.getBridge('10001')).toBeNull();
expect(oldBridge.hasPid(101)).toBe(false);
expect(dispose).toHaveBeenCalledOnce();
expect(manager.getBridge('20002')!.hasPid(101)).toBe(true);
});
it('keeps a multi-PID UIN alive and falls back to the remaining sender', async () => {
const manager = new BridgeManager();
const first = makeSender();
const second = makeSender();
const closed = vi.fn();
manager.subscribeSessions({ closed: closed });
manager.onHookLogin(101, '10001', first.client);
manager.onHookLogin(202, '10001', second.client);
const bridge = manager.getBridge('10001')!;
expect(bridge.activePid).toBe(202);
await bridge.sendRawPacket('Test.BeforeDisconnect', new Uint8Array([1]));
expect(testSends(second.sendPacket)).toHaveLength(1);
expect(testSends(first.sendPacket)).toHaveLength(0);
manager.onPidDisconnected(202);
expect(manager.getBridge('10001')!).toBe(bridge);
expect(bridge.activePid).toBe(101);
expect(closed).not.toHaveBeenCalled();
await bridge.sendRawPacket('Test.AfterDisconnect', new Uint8Array([2]));
expect(testSends(first.sendPacket)).toHaveLength(1);
expect(testSends(second.sendPacket)).toHaveLength(1);
manager.onPidDisconnected(101);
expect(manager.getBridge('10001')).toBeNull();
expect(closed).toHaveBeenCalledOnce();
expect(closed).toHaveBeenCalledWith('10001', bridge, 101);
await expect(
bridge.sendRawPacket('Test.NoSender', new Uint8Array([3])),
).resolves.toMatchObject({
success: false,
gotResponse: false,
errorCode: -1,
errorMessage: 'no packet sender attached',
});
});
it('traces material sender selection, fallback, and no-sender drops without polling noise', async () => {
const manager = new BridgeManager();
const first = makeSender();
const second = makeSender();
const entries: LogEntry[] = [];
setLogLevel('trace');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onHookLogin(101, '10001', first.client);
manager.onHookLogin(202, '10001', second.client);
manager.onPacket(packet(202, '10001'));
manager.onPidDisconnected(202);
const bridge = manager.getBridge('10001')!;
manager.onPidDisconnected(101);
await bridge.sendRawPacket('Test.NoSender', new Uint8Array([0x00, 0xff]));
const sender = ownershipSendTrace(entries);
expect(sender.map((entry) => entry.message)).toEqual([
'bridge_sender_fact event=selected uin="10001" pid=101 previousPid=null',
'bridge_sender_fact event=selected uin="10001" pid=202 previousPid=101',
'bridge_sender_fact event=fallback uin="10001" detachedPid=202 fallbackPid=101',
'bridge_send_start serviceCmd="Test.NoSender" uin="10001" activePid=null timeoutMs=15000 length=2 body=00ff',
expect.stringMatching(
/^bridge_send_terminal serviceCmd="Test\.NoSender" uin="10001" activePid=null outcome=dropped reason=no_sender length=2 body=00ff elapsedMs=\d+$/,
),
]);
expect(sender[2]!.req).toBe(
runtimeTrace(entries).find((entry) =>
entry.message.startsWith('bridge_detach_start pid=202 '),
)!.req,
);
expect(sender[3]!.req).toEqual(expect.any(Number));
expect(sender[4]!.req).toBe(sender[3]!.req);
} finally {
unsubscribe();
}
});
it('reports an account healthy while any attached PID still receives packets', () => {
const manager = new BridgeManager();
manager.onHookLogin(101, '10001', makeSender().client);
manager.onHookLogin(202, '10001', makeSender().client);
const bridge = manager.getBridge('10001')!;
expect(bridge.receiveHealthy).toBe(true);
manager.onPidReceiveHealthChanged(101, false);
expect(bridge.receiveHealthy).toBe(true);
manager.onPidReceiveHealthChanged(202, false);
expect(bridge.receiveHealthy).toBe(false);
manager.onPidReceiveHealthChanged(101, true);
expect(bridge.receiveHealthy).toBe(true);
});
it('prefers the most recently rebound live PID, then falls back by recency', async () => {
const manager = new BridgeManager();
const first = makeSender();
const second = makeSender();
const third = makeSender();
const reboundFirst = makeSender();
const started = vi.fn();
manager.subscribeSessions({ started: started });
manager.onHookLogin(101, '10001', first.client);
manager.onHookLogin(202, '10001', second.client);
manager.onHookLogin(303, '10001', third.client);
manager.onHookLogin(101, '10001', reboundFirst.client);
const bridge = manager.getBridge('10001')!;
expect(started).toHaveBeenCalledOnce();
expect(bridge.activePid).toBe(101);
await bridge.sendRawPacket('Test.Rebound', new Uint8Array([1]));
expect(testSends(reboundFirst.sendPacket)).toHaveLength(1);
manager.onPidDisconnected(101);
expect(bridge.activePid).toBe(303);
await bridge.sendRawPacket('Test.Fallback', new Uint8Array([2]));
expect(testSends(third.sendPacket)).toHaveLength(1);
manager.onPidDisconnected(303);
expect(bridge.activePid).toBe(202);
await bridge.sendRawPacket('Test.SecondFallback', new Uint8Array([3]));
expect(testSends(second.sendPacket)).toHaveLength(1);
});
it('applies the same ownership transition when a packet reveals a new UIN', async () => {
const manager = new BridgeManager();
const sender = makeSender();
const lifecycle: string[] = [];
manager.subscribeSessions({ started: (uin) => lifecycle.push(`started:${uin}`) });
manager.subscribeSessions({ closed: (uin) => lifecycle.push(`closed:${uin}`) });
manager.onHookLogin(101, '10001', sender.client);
manager.onPacket(packet(101, '20002'));
expect(lifecycle).toEqual(['started:10001', 'closed:10001', 'started:20002']);
expect(manager.getBridge('10001')).toBeNull();
const replacement = manager.getBridge('20002')!;
expect(replacement.hasPid(101)).toBe(true);
await replacement.sendRawPacket('Test.AfterPacketRebind', new Uint8Array([1]));
expect(testSends(sender.sendPacket)).toHaveLength(1);
});
it('keeps the old UIN alive when its active PID moves and a fallback remains', async () => {
const manager = new BridgeManager();
const fallback = makeSender();
const moving = makeSender();
const rebound = makeSender();
const lifecycle: string[] = [];
manager.subscribeSessions({ started: (uin) => lifecycle.push(`started:${uin}`) });
manager.subscribeSessions({ closed: (uin) => lifecycle.push(`closed:${uin}`) });
manager.onHookLogin(101, '10001', fallback.client);
manager.onHookLogin(202, '10001', moving.client);
const oldBridge = manager.getBridge('10001')!;
expect(oldBridge.activePid).toBe(202);
manager.onHookLogin(202, '20002', rebound.client);
expect(lifecycle).toEqual(['started:10001', 'started:20002']);
expect(manager.getBridge('10001')!).toBe(oldBridge);
expect(oldBridge.hasPid(202)).toBe(false);
expect(oldBridge.activePid).toBe(101);
await oldBridge.sendRawPacket('Test.OldUinFallback', new Uint8Array([1]));
expect(testSends(fallback.sendPacket)).toHaveLength(1);
const newBridge = manager.getBridge('20002')!;
expect(newBridge.activePid).toBe(202);
await newBridge.sendRawPacket('Test.NewUinSender', new Uint8Array([2]));
expect(testSends(rebound.sendPacket)).toHaveLength(1);
manager.onPidDisconnected(202);
expect(lifecycle).toEqual(['started:10001', 'started:20002', 'closed:20002']);
manager.onPidDisconnected(101);
expect(lifecycle).toEqual([
'started:10001',
'started:20002',
'closed:20002',
'closed:10001',
]);
});
it('does not emit another started edge when a PID joins an existing UIN', async () => {
const manager = new BridgeManager();
const first = makeSender();
const second = makeSender();
const reboundFirst = makeSender();
const started = vi.fn();
const closed = vi.fn();
manager.subscribeSessions({ started: started });
manager.subscribeSessions({ closed: closed });
manager.onHookLogin(101, '10001', first.client);
manager.onHookLogin(202, '20002', second.client);
const targetBridge = manager.getBridge('20002')!;
manager.onHookLogin(101, '20002', reboundFirst.client);
expect(started).toHaveBeenCalledTimes(2);
expect(closed).toHaveBeenCalledOnce();
expect(closed).toHaveBeenCalledWith('10001', expect.anything(), 101);
expect(manager.getBridge('10001')).toBeNull();
expect(manager.getBridge('20002')!).toBe(targetBridge);
expect(targetBridge.activePid).toBe(101);
manager.onPidDisconnected(101);
expect(targetBridge.activePid).toBe(202);
await targetBridge.sendRawPacket('Test.ExistingTargetFallback', new Uint8Array([1]));
expect(testSends(second.sendPacket)).toHaveLength(1);
expect(closed).toHaveBeenCalledOnce();
manager.onPidDisconnected(202);
expect(closed).toHaveBeenCalledTimes(2);
});
it('emits exactly one started/closed pair per real lifecycle', () => {
const manager = new BridgeManager();
const sender = makeSender();
const started = vi.fn();
const closed = vi.fn();
manager.subscribeSessions({ started: started });
manager.subscribeSessions({ closed: closed });
manager.onHookLogin(101, '10001', sender.client);
manager.onHookLogin(101, '10001', sender.client);
manager.onPacket(packet(101, '10001'));
manager.onPacket(packet(101, '10001'));
expect(started).toHaveBeenCalledOnce();
manager.onPidDisconnected(101);
manager.onPidDisconnected(101);
expect(closed).toHaveBeenCalledOnce();
manager.onHookLogin(101, '10001', sender.client);
manager.onPidDisconnected(101);
expect(started).toHaveBeenCalledTimes(2);
expect(closed).toHaveBeenCalledTimes(2);
});
it('fails fast with a routing terminal when Manager ownership has no sender', () => {
const manager = new BridgeManager();
const sender = makeSender();
const entries: LogEntry[] = [];
setLogLevel('trace');
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
try {
manager.onHookLogin(101, '10001', sender.client);
// Remove the connection without updating the manager's ownership index.
manager.getBridge('10001')!.detachPid(101);
expect(() => manager.onPacket(packet(101, '10001'))).toThrowError(
'BridgeManager invariant violated: PID=101 has no sender in UIN=10001 session',
);
const packetEntries = entries.filter(
(entry) => entry.level === 'trace' && entry.scope === 'Bridge.Packet',
);
expect(packetEntries).toHaveLength(2);
expect(packetEntries[0]!.req).toEqual(expect.any(Number));
expect(packetEntries[1]).toMatchObject({
req: packetEntries[0]!.req,
message: expect.stringMatching(
/^packet_terminal serviceCmd="Test\.Unhandled" seqId=1 outcome=failed reason=routing_failed error="BridgeManager invariant violated: PID=101 has no sender in UIN=10001 session" events=0 dispatched=0 elapsedMs=\d+$/,
),
});
expect(() => manager.onPidDisconnected(101)).toThrowError(
'BridgeManager invariant violated: PID=101 is mapped to UIN=10001, but Bridge does not own the PID',
);
} finally {
unsubscribe();
}
});
});