Backend (src/server, runs on Bun): - GibbzHttpServer (health, /api/ice, /api/rooms, static, keepalive tuning) - SignalingServer with Peer/Room/RoomRegistry classes and typed messages - IceConfigProvider (env STUN/TURN + coturn HMAC ephemeral creds) - StaticFileServer (dist/ with public/ fallback, traversal guard) - Tracing (OpenTelemetry SDK), AppConfig; createApp() factory for tests Frontend (src/client, built by Vite): - VoiceApp orchestrator implementing VoiceAppContext - WebRtcManager + PeerSession (perfect negotiation, pc rebuild, quality monitor) - SignalingClient + ReconnectController, AudioManager, SpatialAudio, Microphone/ScreenShare controllers, ScreensUi/RosterUi/SpatialMap/ SpeakingMonitor, Settings/Welcome dialogs, LayoutManager, MatrixChat Tooling: bun scripts (dev/start/test/typecheck), vite.config.ts root src/client with publicDir public/static, vitest-config for CI-less runs, bun-based Dockerfile (oven/bun:1), Makefile + README updated, legacy server.js/tracing.js/test.js/public js removed. Verified locally: tsc --noEmit clean, vitest run 6/6 green, vite build ok, server smoke-tested serving dist + signaling endpoints under Node. Local bun binary segfaults (SIGILL) on this host, so 'bun test' itself was not executable here; tests are vitest-API compatible which bun test maps.
42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
// RUM issue capture: forwards client-side errors into the OpenTelemetry RUM
|
|
// pipeline (window.OtelRUM is loaded from otel.k6n.net in index.html).
|
|
|
|
export function captureRumIssue(
|
|
message: string,
|
|
severity = 'ERROR',
|
|
extra: Record<string, unknown> = {},
|
|
): void {
|
|
const rum = (globalThis as Record<string, any>).OtelRUM?.last;
|
|
if (!rum || typeof rum.captureMessage !== 'function') return;
|
|
try {
|
|
rum.captureMessage(message, severity, extra);
|
|
} catch (err) {
|
|
console.warn('RUM capture failed', err);
|
|
}
|
|
}
|
|
|
|
export function installGlobalErrorHandlers(): void {
|
|
window.addEventListener('error', (event) => {
|
|
captureRumIssue(event.message || 'Unhandled browser error', 'ERROR', {
|
|
source: event.filename,
|
|
line: event.lineno,
|
|
column: event.colno,
|
|
});
|
|
});
|
|
|
|
window.addEventListener('unhandledrejection', (event) => {
|
|
const reason = (event as PromiseRejectionEvent).reason;
|
|
captureRumIssue(`Unhandled promise rejection: ${reason?.message || reason || 'unknown error'}`, 'ERROR', {
|
|
name: reason?.name,
|
|
stack: reason?.stack,
|
|
});
|
|
});
|
|
}
|
|
|
|
/** Trace headers for fetches so server spans link to the browser trace. */
|
|
export function rumTraceHeaders(): Record<string, string> {
|
|
const rum = (window as Record<string, any>).rum;
|
|
if (rum && typeof rum.traceHeaders === 'function') return rum.traceHeaders() || {};
|
|
return {};
|
|
}
|