mirror of
https://github.com/k1tbyte/Wand-Enhancer.git
synced 2026-08-28 17:01:04 +00:00
a0b3968d33
Reorganize the panel around product capabilities and integrate the remote i18n feature from origin/master into the new structure. - Restructure src into capability features (app, trainer, library, remote-session, appearance, shared); move the bridge to bridge/src. - Add lingui-based UI localization and wrap remaining user-facing strings (Trans / msg macros); fix the 'END В·' mojibake. - Port WeMod cheat-metadata i18n: capture the access token from the snapshot's renderer in the bridge and fetch localized trainer_meta in remote-session.i18n; guarantee snapshot sync on token failure. - Wire vitest to the app's lingui/preact pipeline (mergeConfig).
98 lines
3.6 KiB
TypeScript
Vendored
98 lines
3.6 KiB
TypeScript
Vendored
import { PROTOCOL_VERSION } from './contract';
|
|
import type { IncomingMessage, OutgoingMessage } from './messages';
|
|
|
|
const INCOMING_TYPES = new Set<IncomingMessage['type']>([
|
|
'hello_ack',
|
|
'trainer_meta',
|
|
'trainer_values',
|
|
'game_status',
|
|
'installed_apps',
|
|
'value_changed',
|
|
'trainer_changed',
|
|
'set_value_result',
|
|
'remote_command_result',
|
|
'error',
|
|
]);
|
|
|
|
const OUTGOING_TYPES = new Set<OutgoingMessage['type']>(['hello', 'set_value', 'remote_command']);
|
|
|
|
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === 'object' && value !== null;
|
|
}
|
|
|
|
export function isIncomingMessage(value: unknown): value is IncomingMessage {
|
|
if (!isEnvelope(value) || !INCOMING_TYPES.has(value.type as IncomingMessage['type'])) {
|
|
return false;
|
|
}
|
|
|
|
const payload = value.payload;
|
|
switch (value.type) {
|
|
case 'hello_ack':
|
|
return hasString(payload, 'sessionId') && hasBoolean(payload, 'accepted') && hasString(payload, 'serverVersion')
|
|
&& hasNumber(payload, 'protocolVersion');
|
|
case 'trainer_meta':
|
|
return isRecord(payload.session) && hasString(payload.session, 'instanceId')
|
|
&& isRecord(payload.trainer) && hasString(payload.trainer, 'trainerId')
|
|
&& isRecord(payload.schema) && Array.isArray(payload.schema.categories) && Array.isArray(payload.schema.cheats);
|
|
case 'trainer_values':
|
|
return hasString(payload, 'trainerId') && isRecord(payload.values);
|
|
case 'installed_apps':
|
|
return hasString(payload, 'instanceId') && hasString(payload, 'updatedAt') && Array.isArray(payload.apps);
|
|
case 'game_status':
|
|
return hasString(payload, 'instanceId') && hasString(payload, 'updatedAt')
|
|
&& isRecord(payload.session) && isRecord(payload.trainer);
|
|
case 'value_changed':
|
|
return hasString(payload, 'trainerId') && hasString(payload, 'target') && 'value' in payload;
|
|
case 'trainer_changed':
|
|
return hasString(payload, 'trainerId');
|
|
case 'set_value_result':
|
|
return hasBoolean(payload, 'ok') && hasString(payload, 'trainerId') && hasString(payload, 'target');
|
|
case 'remote_command_result':
|
|
return hasBoolean(payload, 'ok') && (payload.action === 'launch' || payload.action === 'stop');
|
|
case 'error':
|
|
return hasString(payload, 'code') && hasString(payload, 'message');
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function isOutgoingMessage(value: unknown): value is OutgoingMessage {
|
|
if (!isEnvelope(value) || !OUTGOING_TYPES.has(value.type as OutgoingMessage['type'])) {
|
|
return false;
|
|
}
|
|
|
|
const payload = value.payload;
|
|
if (value.type === 'hello') {
|
|
return payload.client === 'mobile-web' && hasString(payload, 'clientVersion') && isRecord(payload.capabilities);
|
|
}
|
|
if (value.type === 'set_value') {
|
|
return hasString(payload, 'trainerId') && hasString(payload, 'target') && 'value' in payload;
|
|
}
|
|
return (payload.action === 'launch' || payload.action === 'stop');
|
|
}
|
|
|
|
function isEnvelope(value: unknown): value is Record<string, unknown> & {
|
|
type: string;
|
|
version: number;
|
|
requestId: string | null;
|
|
payload: Record<string, unknown>;
|
|
} {
|
|
return isRecord(value)
|
|
&& typeof value.type === 'string'
|
|
&& value.version === PROTOCOL_VERSION
|
|
&& (value.requestId === null || typeof value.requestId === 'string')
|
|
&& isRecord(value.payload);
|
|
}
|
|
|
|
function hasString(value: Record<string, unknown>, key: string): boolean {
|
|
return typeof value[key] === 'string';
|
|
}
|
|
|
|
function hasNumber(value: Record<string, unknown>, key: string): boolean {
|
|
return typeof value[key] === 'number';
|
|
}
|
|
|
|
function hasBoolean(value: Record<string, unknown>, key: string): boolean {
|
|
return typeof value[key] === 'boolean';
|
|
}
|