chore: dev-stack switches, shared e2e harness, and desktop shell rules

- `LIVE_RELOAD=false npm run dev` keeps the renderer alive across a machine
  suspend; the reload client otherwise destroys the session under test.
- `dev-peer.sh` plus a separate userdata dir runs a second local peer.
- `tools/voice-probe.js` samples peer state and RTP counters from a live
  window, persisting to localStorage so a renderer reload cannot erase it.
- e2e helpers for voice pairs, peer-role election, and a TURN relay.
- Electron single-instance and dev-client-load decisions move into rules
  files with colocated specs.
This commit is contained in:
2026-08-14 03:19:29 +02:00
parent d71e3a98da
commit e49b3ec112
41 changed files with 35947 additions and 50 deletions
+28 -7
View File
@@ -1,11 +1,11 @@
import { app } from 'electron';
import * as path from 'path';
import { createWindow, getMainWindow } from '../window/create-window';
import { resolveSecondInstanceAction } from './second-instance.rules';
const CUSTOM_PROTOCOL = 'toju';
const DEEP_LINK_PREFIX = `${CUSTOM_PROTOCOL}://`;
const DEV_SINGLE_INSTANCE_EXIT_CODE_ENV = 'METOYOU_SINGLE_INSTANCE_EXIT_CODE';
const DEV_RELOAD_EXISTING_ARG = '--metoyou-dev-reload-existing';
let pendingDeepLink: string | null = null;
@@ -42,6 +42,24 @@ function focusMainWindow(): void {
mainWindow.focus();
}
function reloadMainWindow(): void {
const mainWindow = getMainWindow();
if (!mainWindow || mainWindow.isDestroyed()) {
void createWindow();
return;
}
focusMainWindow();
if (mainWindow.webContents.isLoadingMainFrame()) {
return;
}
mainWindow.webContents.reloadIgnoringCache();
}
function forwardDeepLink(url: string): void {
const mainWindow = getMainWindow();
@@ -96,13 +114,16 @@ export function initializeDeepLinkHandling(): boolean {
}
app.on('second-instance', (_event, argv) => {
if (resolveDevSingleInstanceExitCode() != null && argv.includes(DEV_RELOAD_EXISTING_ARG)) {
app.relaunch();
app.exit(0);
return;
}
const action = resolveSecondInstanceAction({
argv,
devSingleInstanceExitCode: resolveDevSingleInstanceExitCode()
});
focusMainWindow();
if (action === 'reload-existing') {
reloadMainWindow();
} else {
focusMainWindow();
}
const deepLink = extractDeepLink(argv);
@@ -0,0 +1,44 @@
import {
describe,
expect,
it
} from 'vitest';
import { DEV_RELOAD_EXISTING_ARG, resolveSecondInstanceAction } from './second-instance.rules';
describe('resolveSecondInstanceAction', () => {
it('reloads the open window when a dev launch asks to reuse it', () => {
const action = resolveSecondInstanceAction({
argv: [
'electron',
'.',
DEV_RELOAD_EXISTING_ARG
],
devSingleInstanceExitCode: 23
});
expect(action).toBe('reload-existing');
});
it('never asks a packaged instance to reload, even with the dev argument', () => {
const action = resolveSecondInstanceAction({
argv: ['metoyou', DEV_RELOAD_EXISTING_ARG],
devSingleInstanceExitCode: null
});
expect(action).toBe('focus');
});
it('focuses the open window for an ordinary second launch', () => {
const action = resolveSecondInstanceAction({
argv: [
'electron',
'.',
'toju://invite/abc'
],
devSingleInstanceExitCode: 23
});
expect(action).toBe('focus');
});
});
+23
View File
@@ -0,0 +1,23 @@
export const DEV_RELOAD_EXISTING_ARG = '--metoyou-dev-reload-existing';
export type SecondInstanceAction = 'reload-existing' | 'focus';
export interface SecondInstanceInput {
argv: string[];
devSingleInstanceExitCode: number | null;
}
/**
* A dev launch always carries `--metoyou-dev-reload-existing`, so the running
* instance reloads in place. It must never answer by relaunching itself: the
* successor inherits the same argument and asks for the single-instance lock
* while the dying parent still holds it, so the refused successor fires
* `second-instance` again and the pair respawns forever.
*/
export function resolveSecondInstanceAction(input: SecondInstanceInput): SecondInstanceAction {
const isDevelopmentLaunch = input.devSingleInstanceExitCode != null;
return isDevelopmentLaunch && input.argv.includes(DEV_RELOAD_EXISTING_ARG)
? 'reload-existing'
: 'focus';
}