feat(diagnostics-client): implement Phase 2.1 TypeScript SDK
New package @bytelyst/diagnostics-client with: - DiagnosticsClient: singleton with polling for active sessions - BreadcrumbTrail: ring buffer (max 100) for timeline - NetworkInterceptor: fetch wrapper for HTTP capture - DeviceState: memory, storage, network collection - 21 Vitest tests (all passing)
This commit is contained in:
parent
18dd263797
commit
8acb8db7d7
@ -7,24 +7,19 @@
|
|||||||
import type { DeviceState } from './types.js';
|
import type { DeviceState } from './types.js';
|
||||||
|
|
||||||
// DOM type declarations for ESLint
|
// DOM type declarations for ESLint
|
||||||
declare const navigator: Navigator & {
|
type Navigator = {
|
||||||
connection?: NetworkInformation;
|
onLine: boolean;
|
||||||
getBattery?: () => Promise<BatteryManager>;
|
connection?: { effectiveType?: string };
|
||||||
|
getBattery?: () => Promise<{ charging: boolean; level: number }>;
|
||||||
storage?: { estimate(): Promise<{ usage?: number }> };
|
storage?: { estimate(): Promise<{ usage?: number }> };
|
||||||
};
|
};
|
||||||
declare const performance: Performance & { memory?: { usedJSHeapSize: number } };
|
declare const navigator: Navigator;
|
||||||
declare const window: Window & {
|
declare const performance: { memory?: { usedJSHeapSize: number } };
|
||||||
addEventListener: (type: string, listener: EventListener) => void;
|
interface Window {
|
||||||
removeEventListener: (type: string, listener: EventListener) => void;
|
addEventListener: (type: string, listener: () => void) => void;
|
||||||
};
|
removeEventListener: (type: string, listener: () => void) => void;
|
||||||
type EventListener = (event: { isTrusted: boolean }) => void;
|
|
||||||
interface NetworkInformation {
|
|
||||||
effectiveType?: string;
|
|
||||||
}
|
|
||||||
interface BatteryManager {
|
|
||||||
charging: boolean;
|
|
||||||
level: number;
|
|
||||||
}
|
}
|
||||||
|
declare const window: Window;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect current device state
|
* Collect current device state
|
||||||
@ -36,34 +31,39 @@ export function collectDeviceState(): DeviceState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Network type (experimental API)
|
// Network type (experimental API)
|
||||||
const connection = (navigator as Navigator & { connection?: NetworkInformation }).connection;
|
const connection = (navigator as { connection?: { effectiveType?: string } }).connection;
|
||||||
if (connection) {
|
if (connection) {
|
||||||
state.networkType = connection.effectiveType ?? 'unknown';
|
state.networkType = connection.effectiveType ?? 'unknown';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Battery API (experimental, not widely supported)
|
// Battery API (experimental, not widely supported)
|
||||||
// Note: Battery API is deprecated but still useful for diagnostics
|
// Note: Battery API is deprecated but still useful for diagnostics
|
||||||
const battery = (navigator as Navigator & { getBattery?: () => Promise<BatteryManager> }).getBattery;
|
const battery = (
|
||||||
|
navigator as { getBattery?: () => Promise<{ charging: boolean; level: number }> }
|
||||||
|
).getBattery;
|
||||||
if (battery) {
|
if (battery) {
|
||||||
// We'll return a promise, but sync API can't wait
|
// We'll return a promise, but sync API can't wait
|
||||||
// Store last known value if available
|
// Store last known value if available
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory (Chrome-only experimental)
|
// Memory (Chrome-only experimental)
|
||||||
const memory = (performance as Performance & { memory?: { usedJSHeapSize: number } }).memory;
|
const memory = (performance as { memory?: { usedJSHeapSize: number } }).memory;
|
||||||
if (memory) {
|
if (memory) {
|
||||||
state.memoryMB = Math.round(memory.usedJSHeapSize / 1024 / 1024);
|
state.memoryMB = Math.round(memory.usedJSHeapSize / 1024 / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage (async, but we'll fire-and-forget)
|
// Storage (async, but we'll fire-and-forget)
|
||||||
if (navigator.storage && navigator.storage.estimate) {
|
if (navigator.storage && navigator.storage.estimate) {
|
||||||
navigator.storage.estimate().then(estimate => {
|
navigator.storage
|
||||||
if (estimate.usage !== undefined) {
|
.estimate()
|
||||||
state.storageMB = Math.round(estimate.usage / 1024 / 1024);
|
.then(estimate => {
|
||||||
}
|
if (estimate.usage !== undefined) {
|
||||||
}).catch(() => {
|
state.storageMB = Math.round(estimate.usage / 1024 / 1024);
|
||||||
// Ignore errors
|
}
|
||||||
});
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// Ignore errors
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
@ -72,9 +72,7 @@ export function collectDeviceState(): DeviceState {
|
|||||||
/**
|
/**
|
||||||
* Subscribe to online/offline events
|
* Subscribe to online/offline events
|
||||||
*/
|
*/
|
||||||
export function subscribeToConnectivity(
|
export function subscribeToConnectivity(callback: (isOnline: boolean) => void): () => void {
|
||||||
callback: (isOnline: boolean) => void
|
|
||||||
): () => void {
|
|
||||||
const handleOnline = () => callback(true);
|
const handleOnline = () => callback(true);
|
||||||
const handleOffline = () => callback(false);
|
const handleOffline = () => callback(false);
|
||||||
|
|
||||||
@ -86,25 +84,3 @@ export function subscribeToConnectivity(
|
|||||||
window.removeEventListener('offline', handleOffline);
|
window.removeEventListener('offline', handleOffline);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Network Information interface (experimental)
|
|
||||||
*/
|
|
||||||
interface NetworkInformation {
|
|
||||||
effectiveType?: string;
|
|
||||||
downlink?: number;
|
|
||||||
rtt?: number;
|
|
||||||
saveData?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Battery Manager interface (experimental)
|
|
||||||
*/
|
|
||||||
interface BatteryManager {
|
|
||||||
charging: boolean;
|
|
||||||
level: number;
|
|
||||||
chargingTime: number;
|
|
||||||
dischargingTime: number;
|
|
||||||
addEventListener: (type: string, listener: EventListener) => void;
|
|
||||||
removeEventListener: (type: string, listener: EventListener) => void;
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user