Files
SCOPENET-MC/launcher/src/lib/tauri.ts
T
Claude 50eb1a0cac Add Tauri launcher with Svelte UI
- Accounts: panel login/sign-up, Microsoft device-code sign-in, offline
  play; tokens encrypted with a key kept in the OS credential store
- Home: instance rail, live server status, news feed, social links,
  Play button with download progress, speed and ETA
- Full settings: accounts, memory/resolution/after-launch behaviour,
  Java and GC presets, Minecraft keybind editor applied to options.txt,
  theme overrides, storage manager, self-update via GitHub releases
- Game console, crash dialog with hints, per-instance overrides
- Live admin branding (colours, fonts, backgrounds, custom CSS)
- Online install tests for vanilla/Fabric/Quilt/Forge/NeoForge (CI)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ARcGWxLx21FwXJ3yfGriS
2026-09-28 05:00:30 +00:00

58 lines
2.2 KiB
TypeScript

// Thin wrapper over Tauri IPC. When the UI runs in a normal browser
// (vite dev / screenshots), calls go to an in-memory mock instead.
import { invoke as tauriInvoke } from '@tauri-apps/api/core';
import { listen as tauriListen, type UnlistenFn } from '@tauri-apps/api/event';
export const inTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window;
type Handler = (payload: any) => void;
const mockListeners = new Map<string, Set<Handler>>();
export function mockEmit(event: string, payload: unknown) {
mockListeners.get(event)?.forEach((h) => h(payload));
}
export async function invoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T> {
if (inTauri) return tauriInvoke<T>(cmd, args);
const { mockInvoke } = await import('./mock');
return mockInvoke(cmd, args ?? {}) as Promise<T>;
}
export async function listen<T>(event: string, handler: (payload: T) => void): Promise<UnlistenFn> {
if (inTauri) return tauriListen<T>(event, (e) => handler(e.payload));
const set = mockListeners.get(event) ?? new Set();
set.add(handler as Handler);
mockListeners.set(event, set);
return () => set.delete(handler as Handler);
}
export async function windowAction(action: 'minimize' | 'maximize' | 'close' | 'drag') {
if (!inTauri) return;
const { getCurrentWindow } = await import('@tauri-apps/api/window');
const w = getCurrentWindow();
if (action === 'minimize') await w.minimize();
else if (action === 'maximize') await w.toggleMaximize();
else if (action === 'close') await w.close();
else await w.startDragging();
}
export async function openUrl(url: string) {
if (!inTauri) {
window.open(url, '_blank');
return;
}
const { openUrl } = await import('@tauri-apps/plugin-opener');
await openUrl(url);
}
export async function pickFile(title: string, filters?: { name: string; extensions: string[] }[]): Promise<string | null> {
if (!inTauri) return null;
const { open } = await import('@tauri-apps/plugin-dialog');
const r = await open({ title, multiple: false, directory: false, filters });
return typeof r === 'string' ? r : null;
}
export function errorText(e: unknown): string {
return typeof e === 'string' ? e : e instanceof Error ? e.message : JSON.stringify(e);
}