- telemetry-client: createWebTelemetry() wraps createTelemetryClient() with web defaults - diagnostics-client: createWebDiagnostics() wraps DiagnosticsClient with install ID + web defaults - Eliminates ~70 lines of boilerplate per web app - 11/11 telemetry tests pass, 21/21 diagnostics tests pass
112 lines
3.2 KiB
TypeScript
112 lines
3.2 KiB
TypeScript
/**
|
|
* Convenience factory for web dashboard diagnostics.
|
|
*
|
|
* Eliminates ~40 lines of boilerplate per web app by wrapping
|
|
* DiagnosticsClient.getInstance() with sensible web defaults.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* import { createWebDiagnostics } from '@bytelyst/diagnostics-client';
|
|
*
|
|
* const { init, stop } = createWebDiagnostics({
|
|
* productId: 'nomgap',
|
|
* channel: 'nomgap_web',
|
|
* serverUrl: 'http://localhost:4003',
|
|
* getAuthToken: () => localStorage.getItem('nomgap_access_token') ?? '',
|
|
* });
|
|
* export { init as initDiagnostics, stop as stopDiagnostics };
|
|
* ```
|
|
*/
|
|
|
|
import { DiagnosticsClient } from './client.js';
|
|
|
|
export interface WebDiagnosticsConfig {
|
|
/** Product identifier (e.g. 'nomgap', 'chronomind'). */
|
|
productId: string;
|
|
/** Channel identifier (e.g. 'nomgap_web', 'pwa'). */
|
|
channel: string;
|
|
/** Platform-service origin URL (no trailing /api). */
|
|
serverUrl: string;
|
|
/** Function that returns the current auth token. */
|
|
getAuthToken: () => string;
|
|
/** App version string. Default: '0.1.0'. */
|
|
appVersion?: string;
|
|
/** Build number. Default: '1'. */
|
|
buildNumber?: string;
|
|
/** Release channel. Default: 'dev'. */
|
|
releaseChannel?: string;
|
|
/** OS family. Default: 'unknown'. */
|
|
osFamily?: string;
|
|
/** Poll interval in ms. Default: 30000. */
|
|
pollIntervalMs?: number;
|
|
/** Capture console logs. Default: false. */
|
|
captureConsole?: boolean;
|
|
/** Capture JS errors. Default: true. */
|
|
captureErrors?: boolean;
|
|
/** Capture network requests. Default: false. */
|
|
captureNetwork?: boolean;
|
|
}
|
|
|
|
export interface WebDiagnostics {
|
|
/** Initialize diagnostics. Safe to call on server (no-ops). Idempotent. */
|
|
init(): void;
|
|
/** Stop diagnostics polling. */
|
|
stop(): void;
|
|
}
|
|
|
|
function getOrCreateInstallId(productId: string): string {
|
|
const key = `${productId}_diag_install_id`;
|
|
let id = localStorage.getItem(key);
|
|
if (!id) {
|
|
id =
|
|
typeof crypto?.randomUUID === 'function'
|
|
? crypto.randomUUID()
|
|
: Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
localStorage.setItem(key, id);
|
|
}
|
|
return id;
|
|
}
|
|
|
|
export function createWebDiagnostics(config: WebDiagnosticsConfig): WebDiagnostics {
|
|
let started = false;
|
|
|
|
function init(): void {
|
|
if (typeof window === 'undefined') return;
|
|
if (started) return;
|
|
|
|
DiagnosticsClient.getInstance({
|
|
productId: config.productId,
|
|
anonymousInstallId: getOrCreateInstallId(config.productId),
|
|
platform: 'web',
|
|
channel: config.channel,
|
|
osFamily: config.osFamily ?? 'unknown',
|
|
appVersion: config.appVersion ?? '0.1.0',
|
|
buildNumber: config.buildNumber ?? '1',
|
|
releaseChannel: config.releaseChannel ?? 'dev',
|
|
serverUrl: config.serverUrl,
|
|
getAuthToken: config.getAuthToken,
|
|
pollIntervalMs: config.pollIntervalMs ?? 30_000,
|
|
captureConsole: config.captureConsole ?? false,
|
|
captureErrors: config.captureErrors ?? true,
|
|
captureNetwork: config.captureNetwork ?? false,
|
|
});
|
|
|
|
DiagnosticsClient.getInstance()
|
|
.start()
|
|
.catch(() => {
|
|
// Diagnostics is best-effort
|
|
});
|
|
started = true;
|
|
}
|
|
|
|
function stop(): void {
|
|
try {
|
|
DiagnosticsClient.getInstance().stop();
|
|
} catch {
|
|
// not initialized
|
|
}
|
|
}
|
|
|
|
return { init, stop };
|
|
}
|