.//ui/ReactiveUI.ts import { VirtualDOM, VNode, Patch } from '../utils/VirtualDOM'; import { EventEmitter } from '../utils/EventEmitter'; import { Component } from '../core/Component'; type EventHandler = (event: Event) => void; interface LifecycleHooks { beforeUpdate?: () => void; afterUpdate?: () => void; } export class ReactiveUI extends EventEmitter { private rootElement: HTMLElement | null = null; private virtualDOM: VirtualDOM; private components: Map> = new Map(); private eventDelegator: EventDelegator; private errorBoundary: ErrorBoundary; constructor() { super(); this.virtualDOM = new VirtualDOM(); this.eventDelegator = new EventDelegator(this); this.errorBoundary = new ErrorBoundary(); } mount(element: HTMLElement): void { this.rootElement = element; this.eventDelegator.attachToRoot(element); this.emit('mounted', element); } unmount(): void { if (this.rootElement) { this.eventDelegator.detachFromRoot(); this.emit('unmounted', this.rootElement); this.rootElement = null; } this.virtualDOM.clear(); this.components.clear(); } update(newVDOM: VNode): void { if (this.rootElement) { this.errorBoundary.tryExecute(() => { this.triggerLifecycleHook('beforeUpdate'); const patches = this.virtualDOM.diff(this.virtualDOM.getRootNode(), newVDOM); this.applyPatches(patches); this.triggerLifecycleHook('afterUpdate'); this.emit('updated', patches); }); } } private applyPatches(patches: Patch[]): void { if (!this.rootElement) return; patches.forEach(patch => { switch (patch.type) { case 'CREATE': this.createNode(patch.node as any); break; case 'REMOVE': this.removeNode(patch.index as any); break; case 'REPLACE': this.replaceNode(patch.index as any, patch.node as any); break; case 'UPDATE': this.updateNode(patch.index as any, patch.props); break; } }); } private createNode(vnode: VNode): void { if (!this.rootElement) return; const element = this.renderVNode(vnode); if (Array.isArray(element)) { element.forEach(el => this.rootElement!.appendChild(el)); } else { this.rootElement.appendChild(element); } } private removeNode(index: number): void { if (!this.rootElement) return; const node = this.rootElement.childNodes[index]; if (node) { this.rootElement.removeChild(node); } } private replaceNode(index: number, vnode: VNode): void { if (!this.rootElement) return; const oldNode = this.rootElement.childNodes[index]; const newNode = this.renderVNode(vnode); if (oldNode) { if (Array.isArray(newNode)) { const fragment = document.createDocumentFragment(); newNode.forEach(el => fragment.appendChild(el)); this.rootElement.replaceChild(fragment, oldNode); } else { this.rootElement.replaceChild(newNode, oldNode); } } } private updateNode(index: number, props: any): void { if (!this.rootElement) return; const node = this.rootElement.childNodes[index] as HTMLElement; if (node) { Object.entries(props).forEach(([key, value]) => { if (key === 'style' && typeof value === 'object') { Object.assign(node.style, value); } else if (key.startsWith('on') && typeof value === 'function') { const eventName = key.slice(2).toLowerCase(); this.eventDelegator.addListener(node, eventName, value as EventHandler); } else { node.setAttribute(key, value as string); } }); } } private renderVNode(vnode: VNode): HTMLElement | Text | (HTMLElement | Text)[] { if (typeof vnode === 'string') { return document.createTextNode(vnode); } if (vnode.tag === 'fragment') { return vnode.children.map(child => this.renderVNode(child as VNode)).flat(); } const element = document.createElement(vnode.tag as string); Object.entries(vnode.props || {}).forEach(([key, value]) => { if (key === 'style' && typeof value === 'object') { Object.assign(element.style, value); } else if (key.startsWith('on') && typeof value === 'function') { const eventName = key.slice(2).toLowerCase(); this.eventDelegator.addListener(element, eventName, value as EventHandler); } else { element.setAttribute(key, value as string); } }); (vnode.children || []).forEach((value: string | VNode, index: number, array: (string | VNode)[]) => { const child = this.renderVNode(value as VNode); if (Array.isArray(child)) { child.forEach(c => element.appendChild(c)); } else { element.appendChild(child); } }); if (vnode.component) { const componentInstance = vnode.component(vnode.props); this.components.set(element.id, componentInstance); componentInstance.mount(element); } return element; } getComponentInstance(id: string): Component | undefined { return this.components.get(id); } updateComponentProps(id: string, newProps: any): void { const component = this.components.get(id); if (component) { const propsChanged = this.hasPropsChanged(component.props, newProps); if (propsChanged) { component.updateProps(newProps); } } } private hasPropsChanged(oldProps: any, newProps: any): boolean { const keys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]); for (const key of keys) { if (!Object.is(oldProps[key], newProps[key])) { return true; } } return false; } private triggerLifecycleHook(hook: keyof LifecycleHooks): void { this.components.forEach((component: any) => { if (component[hook]) { (component[hook] as Function)(); } }); } setErrorHandler(handler: (error: Error) => void): void { this.errorBoundary.setErrorHandler(handler); } } class EventDelegator { private root: HTMLElement | null = null; private listeners: Map> = new Map(); constructor(private reactiveUI: ReactiveUI) {} attachToRoot(root: HTMLElement): void { this.root = root; this.addRootListeners(); } detachFromRoot(): void { if (this.root) { this.removeRootListeners(); this.root = null; } this.listeners.clear(); } addListener(element: HTMLElement, eventName: string, handler: EventHandler): void { const key = this.getEventKey(element, eventName); if (!this.listeners.has(key)) { this.listeners.set(key, new Set()); } this.listeners.get(key)!.add(handler); } removeListener(element: HTMLElement, eventName: string, handler: EventHandler): void { const key = this.getEventKey(element, eventName); const handlers = this.listeners.get(key); if (handlers) { handlers.delete(handler); if (handlers.size === 0) { this.listeners.delete(key); } } } private addRootListeners(): void { if (!this.root) return; const eventNames = ['click', 'input', 'change', 'submit', 'keydown', 'keyup', 'mousedown', 'mouseup', 'mousemove']; eventNames.forEach(eventName => { this.root!.addEventListener(eventName, this.handleEvent); }); } private removeRootListeners(): void { if (!this.root) return; const eventNames = ['click', 'input', 'change', 'submit', 'keydown', 'keyup', 'mousedown', 'mouseup', 'mousemove']; eventNames.forEach(eventName => { this.root!.removeEventListener(eventName, this.handleEvent); }); } private handleEvent = (event: Event): void => { let target = event.target as HTMLElement | null; while (target && target !== this.root) { const key = this.getEventKey(target, event.type); const handlers = this.listeners.get(key); if (handlers) { handlers.forEach(handler => handler(event)); } target = target.parentElement; } }; private getEventKey(element: HTMLElement, eventName: string): string { return `${element.id || element.tagName.toLowerCase()}:${eventName}`; } } class ErrorBoundary { private errorHandler: ((error: Error) => void) | null = null; setErrorHandler(handler: (error: Error) => void): void { this.errorHandler = handler; } tryExecute(fn: () => void): void { try { fn(); } catch (error) { if (this.errorHandler) { this.errorHandler(error as Error); } else { console.error('Unhandled error in ReactiveUI:', error); } } } }.//ui/ErrorHandler.tsx import { ErrorInfo, ErrorCategory, ErrorHandlingStrategy, ErrorReportingConfig } from '../Types'; import { Logger } from '../Logger'; // ErrorCategory, ErrorHandlingStrategy, ErrorReportingConfig class NetworkError extends Error { constructor(message: string) { super(message); this.name = 'NetworkError'; } } export class ErrorHandler { private static instance: ErrorHandler; private logger: Logger; private strategies: Map = new Map(); private reportingConfig: ErrorReportingConfig | null = null; private constructor() { this.logger = Logger.getInstance(); } /** * Get the singleton instance of ErrorHandler */ static getInstance(): ErrorHandler { if (!ErrorHandler.instance) { ErrorHandler.instance = new ErrorHandler(); } return ErrorHandler.instance; } /** * Handle an error with optional context * @param error The error object * @param context Optional context information */ handleError(error: Error, context?: string): void { const errorInfo: ErrorInfo = { code: error.name, message: error.message, stack: error.stack, context: context }; this.logger.error(`Error occurred: ${error.message}`, context, errorInfo); const category = this.categorizeError(error); const strategy = this.strategies.get(category); if (strategy) { strategy(error, errorInfo); } this.reportError(errorInfo); } /** * Handle an asynchronous error * @param promise The promise that might throw an error * @param context Optional context information */ async handleAsyncError(promise: Promise, context?: string): Promise { try { return await promise; } catch (error) { this.handleError(error as Error, context); throw error; } } /** * Register global error handlers */ registerGlobalErrorHandlers(): void { window.addEventListener('error', (event: ErrorEvent) => { this.handleError(event.error, 'Global Error'); }); window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => { this.handleError(event.reason, 'Unhandled Promise Rejection'); }); } /** * Set a handling strategy for a specific error category * @param category The error category * @param strategy The handling strategy function */ setStrategy(category: ErrorCategory, strategy: ErrorHandlingStrategy): void { this.strategies.set(category, strategy); } /** * Categorize an error * @param error The error to categorize */ private categorizeError(error: Error): ErrorCategory { // Implement your categorization logic here // This is a simple example; you might want to use more sophisticated logic if (error instanceof TypeError) { return 'TYPE_ERROR'; } else if (error instanceof ReferenceError) { return 'REFERENCE_ERROR'; } else if (error instanceof NetworkError) { return 'NETWORK_ERROR'; } return 'UNKNOWN_ERROR'; } /** * Configure error reporting * @param config The error reporting configuration */ configureErrorReporting(config: ErrorReportingConfig): void { this.reportingConfig = config; } /** * Report an error based on the current configuration * @param errorInfo The error information to report */ private reportError(errorInfo: ErrorInfo): void { if (this.reportingConfig && this.reportingConfig.endpoint) { // Implement the logic to send the error to the configured endpoint fetch(this.reportingConfig.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(errorInfo) }).catch(error => { this.logger.error('Failed to report error', 'ErrorReporting', error); }); } } /** * Attempt to recover from an error * @param error The error to recover from * @returns A boolean indicating whether recovery was successful */ attemptErrorRecovery(error: Error): boolean { // Implement your error recovery logic here // This is a placeholder implementation this.logger.info(`Attempting to recover from error: ${error.message}`, 'ErrorRecovery'); return false; } } .//ui/BrowserContext.ts import { Context } from '../Types'; export const BROWSER_CONTEXT: Context = 'browser'; export function isBrowserContext(): boolean { return typeof window !== 'undefined' && typeof document !== 'undefined'; } export function executeInBrowserContext(func: Function): any { if (isBrowserContext()) { return func(); } else { throw new Error('Attempted to execute browser-specific code in a non-browser environment'); } } export function getBrowserInfo(): {name: string, version: string} { const ua = navigator.userAgent; let browserName = "Unknown"; let browserVersion = "Unknown"; if (ua.indexOf("Firefox") > -1) { browserName = "Firefox"; browserVersion = ua.match(/Firefox\/(\d+\.\d+)/)?.[1] || "Unknown"; } else if (ua.indexOf("Chrome") > -1) { browserName = "Chrome"; browserVersion = ua.match(/Chrome\/(\d+\.\d+)/)?.[1] || "Unknown"; } else if (ua.indexOf("Safari") > -1) { browserName = "Safari"; browserVersion = ua.match(/Version\/(\d+\.\d+)/)?.[1] || "Unknown"; } else if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident/") > -1) { browserName = "Internet Explorer"; browserVersion = ua.match(/(?:MSIE |rv:)(\d+\.\d+)/)?.[1] || "Unknown"; } else if (ua.indexOf("Edge") > -1) { browserName = "Edge"; browserVersion = ua.match(/Edge\/(\d+\.\d+)/)?.[1] || "Unknown"; } return { name: browserName, version: browserVersion }; } export function isLocalStorageAvailable(): boolean { try { const testKey = '__test__'; localStorage.setItem(testKey, testKey); localStorage.removeItem(testKey); return true; } catch (e) { return false; } } export function isServiceWorkerSupported(): boolean { return 'serviceWorker' in navigator; } export function isWebSocketSupported(): boolean { return 'WebSocket' in window; } export function isTouchDevice(): boolean { return 'ontouchstart' in window || navigator.maxTouchPoints > 0; } export function getScreenSize(): {width: number, height: number} { return { width: window.screen.width, height: window.screen.height }; } export function getBrowserLanguage(): string { return navigator.language || (navigator as any).userLanguage; } export function isOnline(): boolean { return navigator.onLine; }.//net/SyncManager.ts import { EventEmitter } from '../utils/EventEmitter'; import { GunDataProvider } from '../data/GunDataProvider'; import { SyncStatus, SyncPriority, SchemaDefinition } from '../Types'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; import { DistributedState } from '../data/DistributedState'; const priorityValues: { [key in SyncPriority]: number } = { [SyncPriority.Low]: 0, [SyncPriority.Normal]: 1, [SyncPriority.High]: 2 }; const priorityLabels: { [key: number]: SyncPriority } = { 0: SyncPriority.Low, 1: SyncPriority.Normal, 2: SyncPriority.High }; // PriorityQueue implementation class PriorityQueue { private elements: { priority: SyncPriority, value: T }[] = []; enqueue(value: T, priority: SyncPriority): void { this.elements.push({ priority, value }); this.elements.sort((a, b) => priorityValues[a.priority] - priorityValues[b.priority]); } dequeue(): T | undefined { return this.elements.shift()?.value; } updatePriority(value: T, priority: SyncPriority): void { const index = this.elements.findIndex((element) => element.value === value); if (index !== -1) { this.elements[index].priority = priority; this.elements.sort((a, b) => priorityValues[a.priority] - priorityValues[b.priority]); } } remove(value: T): void { this.elements = this.elements.filter((element) => element.value !== value); } isEmpty(): boolean { return this.elements.length === 0; } } export class SyncManager extends EventEmitter { private gunDataProvider: GunDataProvider; private syncStatus: Map = new Map(); private logger: Logger; private errorHandler: ErrorHandler; private distributedStates: Map> = new Map(); private syncQueue: PriorityQueue = new PriorityQueue(); private isSyncing: boolean = false; private maxRetries: number = 3; constructor(gunDataProvider: GunDataProvider) { super(); this.gunDataProvider = gunDataProvider; this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); } /** * Starts synchronization for a given path * @param path The path to synchronize * @param priority The priority of the sync operation */ startSync(path: string, priority: SyncPriority = SyncPriority.Normal): void { if (this.syncStatus.has(path)) { this.logger.warn('Sync already started for path', 'SyncManager', { path }); return; } const status: SyncStatus = { lastSyncTime: Date.now(), pendingChanges: 0, priority, isPaused: false }; this.syncStatus.set(path, status); this.syncQueue.enqueue(path, priority); this.gunDataProvider.onUpdate(path, (data) => { this.handleUpdate(path, data); }); this.logger.info('Sync started for path', 'SyncManager', { path, priority }); this.emit('syncStarted', { path, priority }); this.processSyncQueue(); } /** * Stops synchronization for a given path * @param path The path to stop synchronizing */ stopSync(path: string): void { if (!this.syncStatus.has(path)) { this.logger.warn('Sync not started for path', 'SyncManager', { path }); return; } this.gunDataProvider.offUpdate(path, this.handleUpdate.bind(this) as any); this.syncStatus.delete(path); this.syncQueue.remove(path); this.logger.info('Sync stopped for path', 'SyncManager', { path }); this.emit('syncStopped', { path }); } getSyncedPaths(): string[] { return Array.from(this.syncStatus.keys()); } /** * Gets the sync status for a given path * @param path The path to get the status for * @returns The sync status or undefined if not found */ getSyncStatus(path: string): SyncStatus | undefined { return this.syncStatus.get(path); } /** * Gets the distributed state for a given path * @param path The path to get the state for * @returns The distributed state or null if not found */ getDistributedState(path: string): DistributedState | null { return this.distributedStates.get(path) || null; } /** * Handles updates from the GunDataProvider * @param path The path that was updated * @param data The updated data */ private handleUpdate(path: string, data: any): void { const status = this.syncStatus.get(path); if (!status || status.isPaused) return; status.lastSyncTime = Date.now(); status.pendingChanges++; this.emit('dataUpdated', { path, data }); this.syncQueue.updatePriority(path, status.priority); this.processSyncQueue(); this.logger.debug('Data updated', 'SyncManager', { path, pendingChanges: status.pendingChanges }); } /** * Processes the sync queue */ private async processSyncQueue(): Promise { if (this.isSyncing) return; this.isSyncing = true; while (!this.syncQueue.isEmpty()) { const path = this.syncQueue.dequeue(); if (path) { await this.processPendingChanges(path); } } this.isSyncing = false; } /** * Processes pending changes for a given path * @param path The path to process changes for */ private async processPendingChanges(path: string): Promise { const status = this.syncStatus.get(path); if (!status) return; let retries = 0; while (retries < this.maxRetries) { try { const data = await this.gunDataProvider.get(path); const state = this.getDistributedState(path); if (state) { await state.update(data); } status.pendingChanges--; status.lastSyncTime = Date.now(); this.syncStatus.set(path, status); this.emit('syncCompleted', { path, status }); break; } catch (error) { retries++; this.logger.warn(`Sync failed for path, retrying (${retries}/${this.maxRetries})`, 'SyncManager', { path, error }); if (retries >= this.maxRetries) { this.errorHandler.handleError(error as Error, 'SyncManager.processPendingChanges'); this.emit('syncError', { path, error }); } } } } fetchStateFromPeers(path: string): Promise { return this.gunDataProvider.get(path); } syncState(path: string, schema: SchemaDefinition): DistributedState { if (this.distributedStates.has(path)) { throw new Error(`State already synced for path: ${path}`); } const state = new DistributedState(this.gunDataProvider, path, schema); this.distributedStates.set(path, state); this.startSync(path); return state; } persistState(path: string, schema: SchemaDefinition): DistributedState { if (this.distributedStates.has(path)) { throw new Error(`State already synced for path: ${path}`); } const state = new DistributedState(this.gunDataProvider, path, schema); this.distributedStates.set(path, state); return state; } loadPersistedState(path: string): Promise { return this.gunDataProvider.get(path); } /** * Forces synchronization for all paths */ async forceSyncAll(): Promise { const paths = Array.from(this.syncStatus.keys()); for (const path of paths) { await this.forceSync(path); } this.logger.info('Forced sync completed for all paths', 'SyncManager'); this.emit('forceSyncAllCompleted'); } /** * Forces synchronization for a given path * @param path The path to force sync */ async forceSync(path: string): Promise { if (!this.syncStatus.has(path)) { throw new Error(`Sync not started for path: ${path}`); } try { const data = await this.gunDataProvider.get(path); const state = this.getDistributedState(path); if (state) { await state.update(data); } const status = this.syncStatus.get(path)!; status.lastSyncTime = Date.now(); status.pendingChanges = 0; this.syncStatus.set(path, status); this.emit('syncCompleted', { path, status }); this.logger.info('Forced sync completed for path', 'SyncManager', { path }); } catch (error) { this.errorHandler.handleError(error as Error, 'SyncManager.forceSync'); this.emit('syncError', { path, error }); throw error; } } /** * Gets the total count of pending changes across all paths * @returns The total count of pending changes */ getPendingChangesCount(): number { let totalPendingChanges = 0; for (const status of this.syncStatus.values()) { totalPendingChanges += status.pendingChanges; } return totalPendingChanges; } /** * Checks if any sync operation is in progress * @returns True if any sync is in progress, false otherwise */ isSyncInProgress(): boolean { return this.isSyncing; } /** * Pauses synchronization for a given path * @param path The path to pause synchronization for */ pauseSync(path: string): void { const status = this.syncStatus.get(path); if (status) { status.isPaused = true; this.syncStatus.set(path, status); this.logger.info('Sync paused for path', 'SyncManager', { path }); this.emit('syncPaused', { path }); } } /** * Resumes synchronization for a given path * @param path The path to resume synchronization for */ resumeSync(path: string): void { const status = this.syncStatus.get(path); if (status) { status.isPaused = false; this.syncStatus.set(path, status); this.logger.info('Sync resumed for path', 'SyncManager', { path }); this.emit('syncResumed', { path }); } } stop(): void { for (const path of this.syncStatus.keys()) { this.stopSync(path); this.distributedStates.delete(path); this.logger.info('Sync stopped for path', 'SyncManager', { path }); this.syncStatus.clear(); this.syncQueue = new PriorityQueue(); this.isSyncing = false; this.logger.info('SyncManager stopped', 'SyncManager'); this.emit('stopped'); this.removeAllListeners(); this.logger.info('SyncManager destroyed', 'SyncManager'); } } }.//net/NetworkMonitor.ts import { EventEmitter } from '../utils/EventEmitter'; import { NetworkStats, PeerInfo } from '../Types'; import { Logger } from '../Logger'; import { GunDataProvider } from '../data/GunDataProvider'; export class NetworkMonitor extends EventEmitter { private isOnline: boolean; private stats: NetworkStats; private checkInterval: number; private baseInterval: number; private maxInterval: number; private currentInterval: number; private intervalId: NodeJS.Timeout | null = null; private logger: Logger; private gunDataProvider: GunDataProvider; private lastInboundBytes: number = 0; private lastOutboundBytes: number = 0; private lastCheckTime: number = Date.now(); private latencyHistory: number[] = []; private pingEndpoint: string; private bandwidthLimit: number | null = null; /** * Creates a new NetworkMonitor instance * @param gunDataProvider The GunDataProvider instance * @param checkInterval The initial check interval in milliseconds * @param pingEndpoint The endpoint to use for ping checks */ constructor(gunDataProvider: GunDataProvider, checkInterval: number = 5000, pingEndpoint: string = '/ping') { super(); this.isOnline = navigator.onLine; this.stats = { peers: 0, inbound: 0, outbound: 0, latency: 0 }; this.baseInterval = checkInterval; this.maxInterval = checkInterval * 60; // Max interval of 5 minutes this.currentInterval = checkInterval; this.checkInterval = checkInterval; this.logger = Logger.getInstance(); this.gunDataProvider = gunDataProvider; this.pingEndpoint = pingEndpoint; this.init(); } private init(): void { window.addEventListener('online', this.handleOnline); window.addEventListener('offline', this.handleOffline); this.startMonitoring(); } private handleOnline = (): void => { this.isOnline = true; this.currentInterval = this.baseInterval; // Reset to base interval when online this.emit('connectionChange', true); this.logger.info('Network connection established', 'NetworkMonitor'); }; private handleOffline = (): void => { this.isOnline = false; this.emit('connectionChange', false); this.logger.warn('Network connection lost', 'NetworkMonitor'); }; private startMonitoring(): void { if (this.intervalId) { clearInterval(this.intervalId); } this.intervalId = setInterval(this.checkNetwork, this.currentInterval); } private checkNetwork = async (): Promise => { try { const start = Date.now(); const response = await fetch(this.pingEndpoint, { method: 'GET' }); const latency = Date.now() - start; if (response.ok) { this.updateStats({ latency: this.calculateRollingAverageLatency(latency), peers: this.getPeerCount(), inbound: this.getInboundTraffic(), outbound: this.getOutboundTraffic() }); this.currentInterval = this.baseInterval; // Reset interval on successful check } else { throw new Error('Network check failed'); } } catch (error) { this.logger.error('Network check error', 'NetworkMonitor', error); this.emit('error', error); this.incrementCheckInterval(); // Increase interval on failure } this.startMonitoring(); // Restart monitoring with potentially new interval }; private incrementCheckInterval(): void { this.currentInterval = Math.min(this.currentInterval * 2, this.maxInterval); this.logger.debug(`Check interval increased to ${this.currentInterval}ms`, 'NetworkMonitor'); } private calculateRollingAverageLatency(newLatency: number): number { this.latencyHistory.push(newLatency); if (this.latencyHistory.length > 10) { this.latencyHistory.shift(); } return Math.round(this.latencyHistory.reduce((a, b) => a + b) / this.latencyHistory.length); } private updateStats(newStats: NetworkStats): void { this.stats = newStats; this.emit('statsUpdate', this.stats); this.logger.debug('Network stats updated', 'NetworkMonitor', this.stats); } private getPeerCount(): number { // Get the number of connected peers from Gun const peers = this.gunDataProvider.gun._.opt.peers; return Object.keys(peers).length; } private getInboundTraffic(): number { const currentBytes = this.gunDataProvider.gun._.graph['>'] || 0; const bytesReceived = currentBytes - this.lastInboundBytes; this.lastInboundBytes = currentBytes; const elapsedTime = (Date.now() - this.lastCheckTime) / 1000; // Convert to seconds this.lastCheckTime = Date.now(); // Calculate bytes per second return Math.round(bytesReceived / elapsedTime); } private getOutboundTraffic(): number { const currentBytes = this.gunDataProvider.gun._.graph['<'] || 0; const bytesSent = currentBytes - this.lastOutboundBytes; this.lastOutboundBytes = currentBytes; const elapsedTime = (Date.now() - this.lastCheckTime) / 1000; // Convert to seconds this.lastCheckTime = Date.now(); // Calculate bytes per second return Math.round(bytesSent / elapsedTime); } /** * Gets the current network stats * @returns The current NetworkStats */ public getStats(): NetworkStats { return { ...this.stats }; } /** * Checks if the network is currently online * @returns True if online, false otherwise */ public isNetworkOnline(): boolean { return this.isOnline; } /** * Sets the check interval * @param interval The new check interval in milliseconds */ public setCheckInterval(interval: number): void { this.baseInterval = interval; this.currentInterval = interval; this.maxInterval = interval * 60; this.startMonitoring(); } /** * Stops the network monitoring */ public stopMonitoring(): void { if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; } } /** * Cleans up the NetworkMonitor instance */ public destroy(): void { this.stopMonitoring(); window.removeEventListener('online', this.handleOnline); window.removeEventListener('offline', this.handleOffline); this.logger.info('NetworkMonitor destroyed', 'NetworkMonitor'); } /** * Simulates network latency * @param latency The latency to simulate in milliseconds */ public simulateLatency(latency: number): void { this.updateStats({ ...this.stats, latency }); } /** * Sets a bandwidth limit for simulation purposes * @param limit The bandwidth limit in bytes per second, or null to remove the limit */ public setBandwidthLimit(limit: number | null): void { this.bandwidthLimit = limit; this.logger.info(`Bandwidth limit set to ${limit ? limit + ' bytes/s' : 'unlimited'}`, 'NetworkMonitor'); } /** * Gets detailed information about connected peers * @returns An array of PeerInfo objects */ public getPeerInfo(): PeerInfo[] { const gunPeers = this.gunDataProvider.gun._.opt.peers; return Object.entries(gunPeers).map(([id, peer]: [string, any]) => ({ id, url: peer.url, lastSeen: peer.lastSeen || Date.now() })); } /** * Sets a custom ping endpoint * @param endpoint The new ping endpoint */ public setPingEndpoint(endpoint: string): void { this.pingEndpoint = endpoint; this.logger.info(`Ping endpoint set to ${endpoint}`, 'NetworkMonitor'); } }.//net/PeerManager.ts import { EventEmitter } from '../utils/EventEmitter'; import { GunDataProvider } from '../data/GunDataProvider'; import { NetworkGraph, PeerInfo, TopologyAnalysis } from '../Types'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; export class PeerManager extends EventEmitter { private gunDataProvider: GunDataProvider; private peers: Map = new Map(); private logger: Logger; private errorHandler: ErrorHandler; constructor(gunDataProvider: GunDataProvider) { super(); this.gunDataProvider = gunDataProvider; this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); this.setupGunListeners(); } generateNetworkGraph(): NetworkGraph { const graph: NetworkGraph = { nodes: [], edges: [] }; this.peers.forEach((peer, peerId) => { graph.nodes.push({ id: peerId, data: peer }); }); // For simplicity, we're assuming all peers are connected to each other // In a real implementation, you'd need to determine actual connections this.peers.forEach((peer, peerId) => { this.peers.forEach((otherPeer, otherPeerId) => { if (peerId !== otherPeerId) { graph.edges.push({ source: peerId, target: otherPeerId }); } }); }); return graph; } analyzeTopology(): TopologyAnalysis { const graph = this.generateNetworkGraph(); const analysis: TopologyAnalysis = { totalPeers: graph.nodes.length, totalConnections: graph.edges.length, averageConnections: graph.edges.length / graph.nodes.length, centralPeers: this.findCentralPeers(graph) }; return analysis; } private findCentralPeers(graph: NetworkGraph): string[] { // This is a simple implementation. In a real-world scenario, // you might want to use more sophisticated network analysis algorithms. const connectionCounts = new Map(); graph.edges.forEach(edge => { connectionCounts.set(edge.source, (connectionCounts.get(edge.source) || 0) + 1); connectionCounts.set(edge.target, (connectionCounts.get(edge.target) || 0) + 1); }); const averageConnections = graph.edges.length / graph.nodes.length; return Array.from(connectionCounts.entries()) .filter(([_, count]) => count > averageConnections) .map(([peerId, _]) => peerId); } async measureLatency(peerId: string): Promise { const startTime = Date.now(); try { await this.sendToPeer(peerId, { type: 'PING' }); const endTime = Date.now(); return endTime - startTime; } catch (error) { this.logger.error('Failed to measure latency', 'PeerManager', { peerId, error }); return -1; } } connectToPeer(peerId: string, peerUrl: string): void { // Gun doesn't provide a direct method to connect to a specific peer // Instead, we'll just add the peer to our local list and start listening to it this.addPeer(peerId, peerUrl); this.gunDataProvider.gun.get(`messages/${peerId}`).on(() => {}); this.emit('peerConnected', { id: peerId, url: peerUrl }); } disconnectFromPeer(peerId: string): void { // Gun doesn't provide a direct method to disconnect from a specific peer // Instead, we'll remove the peer from our local list and stop listening to it this.removePeer(peerId); this.gunDataProvider.gun.get(`messages/${peerId}`).off(); this.emit('peerDisconnected', { id: peerId }); } sendToPeer(peerId: string, message: any): void { this.sendMessage(peerId, message); } broadcast(message: any): void { this.broadcastMessage(message); } getCurrentPeerId(): string { const publicKey = this.getCurrentPeerPublicKey(); return publicKey || 'anonymous'; } executeInPeerContext(peerId: string, callback: (peer: any) => void): void { const peer = this.peers.get(peerId); if (peer) { try { callback(peer); } catch (error) { this.errorHandler.handleError(error as Error, 'PeerManager.executeInPeerContext'); } } else { this.logger.warn('Peer not found', 'PeerManager', { peerId }); } } private setupGunListeners(): void { this.gunDataProvider.gun.on('hi', this.handlePeerConnected.bind(this)); this.gunDataProvider.gun.on('bye', this.handlePeerDisconnected.bind(this)); } /** * Handles a new peer connection * @param peer The connected peer */ private handlePeerConnected(peer: any): void { const peerId = peer.id; const peerUrl = peer.url; this.addPeer(peerId, peerUrl); this.logger.info('Peer connected', 'PeerManager', { peerId, peerUrl }); this.emit('peerConnected', { id: peerId, url: peerUrl }); } /** * Handles a peer disconnection * @param peer The disconnected peer */ private handlePeerDisconnected(peer: any): void { const peerId = peer.id; this.removePeer(peerId); this.logger.info('Peer disconnected', 'PeerManager', { peerId }); this.emit('peerDisconnected', { id: peerId }); } /** * Adds a new peer to the connected peers list * @param peerId The ID of the peer * @param peerUrl The URL of the peer */ private addPeer(peerId: string, peerUrl: string): void { this.peers.set(peerId, { id: peerId, url: peerUrl, lastSeen: Date.now() }); this.logger.info('Peer added', 'PeerManager', { peerId, peerUrl }); } /** * Removes a peer from the connected peers list * @param peerId The ID of the peer to remove */ private removePeer(peerId: string): void { this.peers.delete(peerId); this.logger.info('Peer removed', 'PeerManager', { peerId }); } /** * Gets the latency for a specific peer * @param peerId The ID of the peer * @returns The latency in milliseconds, or -1 if the peer is not found */ getPeerLatency(peerId: string): number { const peer = this.peers.get(peerId); if (peer) { return Date.now() - peer.lastSeen; } return -1; } /** * Gets the IDs of all connected peers * @returns An array of peer IDs */ getConnectedPeerIds(): string[] { return Array.from(this.peers.keys()); } /** * Gets information about all connected peers * @returns An array of PeerInfo objects */ getPeers(): PeerInfo[] { return Array.from(this.peers.values()); } /** * Sends a message to a specific peer * @param peerId The ID of the peer * @param message The message to send */ sendMessage(peerId: string, message: any): void { try { this.gunDataProvider.gun.get(`messages/${peerId}`).set(message); this.logger.debug('Message sent to peer', 'PeerManager', { peerId, message }); } catch (error) { this.errorHandler.handleError(error as Error, 'PeerManager.sendMessage'); } } /** * Broadcasts a message to all connected peers * @param message The message to broadcast */ broadcastMessage(message: any): void { this.gunDataProvider.gun.get('broadcast').set(message); this.logger.debug('Message broadcasted', 'PeerManager', { message }); } /** * Listens for messages from a specific peer * @param peerId The ID of the peer to listen to * @param callback The function to call when a message is received */ listenToPeer(peerId: string, callback: (message: any) => void): void { this.gunDataProvider.gun.get(`messages/${peerId}`).on(callback); } /** * Listens for broadcast messages * @param callback The function to call when a broadcast message is received */ listenToBroadcasts(callback: (message: any) => void): void { this.gunDataProvider.gun.get('broadcast').on(callback); } /** * Authenticates the current peer * @param alias The alias for the peer * @param password The password for authentication * @returns A promise that resolves when authentication is complete */ async authenticate(alias: string, password: string): Promise { return new Promise((resolve, reject) => { this.gunDataProvider.gun.user().auth(alias, password, (ack: any) => { if (ack.err) { this.logger.error('Authentication failed', 'PeerManager', ack.err); reject(new Error(ack.err)); } else { this.logger.info('Authentication successful', 'PeerManager', { alias }); resolve(); } }); }); } /** * Creates a new peer account * @param alias The alias for the new peer * @param password The password for the new peer * @returns A promise that resolves when account creation is complete */ async createAccount(alias: string, password: string): Promise { return new Promise((resolve, reject) => { this.gunDataProvider.gun.user().create(alias, password, (ack: any) => { if (ack.err) { this.logger.error('Account creation failed', 'PeerManager', ack.err); reject(new Error(ack.err)); } else { this.logger.info('Account created successfully', 'PeerManager', { alias }); resolve(); } }); }); } /** * Gets the current authenticated peer's public key * @returns The public key of the current peer, or null if not authenticated */ getCurrentPeerPublicKey(): string | null { const user = this.gunDataProvider.gun.user(); return user.is ? user.is.pub : null; } /** * Stops the PeerManager and cleans up resources */ stop(): void { // Gun will automatically handle peer disconnections this.peers.clear(); this.logger.info('PeerManager stopped', 'PeerManager'); this.emit('stopped'); } }.//net/WebRTCAdapter.ts import { EventEmitter } from '../utils/EventEmitter'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; import { GunDataProvider } from '../data/GunDataProvider'; interface PeerConnection { connection: RTCPeerConnection; dataChannel: RTCDataChannel; } export class WebRTCAdapter extends EventEmitter { private peerConnections: Map = new Map(); private logger: Logger; private errorHandler: ErrorHandler; private gunDataProvider: GunDataProvider; constructor(gunDataProvider: GunDataProvider) { super(); this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); this.gunDataProvider = gunDataProvider; this.setupGunListeners(); } private setupGunListeners(): void { this.gunDataProvider.gun.on('hi', this.handleNewPeer.bind(this)); this.gunDataProvider.gun.on('bye', this.handlePeerDisconnect.bind(this)); } private async handleNewPeer(peer: any): Promise { try { const peerId = peer.id; if (!this.peerConnections.has(peerId)) { const offer = await this.createOffer(peerId); // Send offer through Gun this.gunDataProvider.gun.get(`webrtc/${peerId}/offer`).put(JSON.stringify(offer)); } } catch (error) { this.errorHandler.handleError(error as Error, 'WebRTCAdapter.handleNewPeer'); } } private handlePeerDisconnect(peer: any): void { const peerId = peer.id; this.close(peerId); } async createOffer(peerId: string): Promise { const peerConnection = this.createPeerConnection(peerId); const offer = await peerConnection.connection.createOffer(); await peerConnection.connection.setLocalDescription(offer); this.logger.debug('Offer created', 'WebRTCAdapter', { peerId }); return offer; } async getCurrentPeerIds(): Promise { return Array.from(this.peerConnections.keys()); } async getCurrentPeerId(): Promise { return this.gunDataProvider.gun.user().is?.pub || ''; } async handleOffer(peerId: string, offer: RTCSessionDescriptionInit): Promise { const peerConnection = this.createPeerConnection(peerId); await peerConnection.connection.setRemoteDescription(new RTCSessionDescription(offer)); const answer = await peerConnection.connection.createAnswer(); await peerConnection.connection.setLocalDescription(answer); this.logger.debug('Offer handled and answer created', 'WebRTCAdapter', { peerId }); return answer; } async handleAnswer(peerId: string, answer: RTCSessionDescriptionInit): Promise { const peerConnection = this.peerConnections.get(peerId); if (peerConnection) { await peerConnection.connection.setRemoteDescription(new RTCSessionDescription(answer)); this.logger.debug('Answer handled', 'WebRTCAdapter', { peerId }); } else { throw new Error(`No peer connection found for peer ${peerId}`); } } async addIceCandidate(peerId: string, candidate: RTCIceCandidateInit): Promise { const peerConnection = this.peerConnections.get(peerId); if (peerConnection) { await peerConnection.connection.addIceCandidate(new RTCIceCandidate(candidate)); this.logger.debug('ICE candidate added', 'WebRTCAdapter', { peerId }); } else { throw new Error(`No peer connection found for peer ${peerId}`); } } sendMessage(peerId: string, message: string): void { const peerConnection = this.peerConnections.get(peerId); if (peerConnection && peerConnection.dataChannel.readyState === 'open') { peerConnection.dataChannel.send(message); this.logger.debug('Message sent via WebRTC', 'WebRTCAdapter', { peerId, message }); } else { // Fallback to Gun if WebRTC is not available this.gunDataProvider.gun.get(`messages/${peerId}`).set(message); this.logger.debug('Message sent via Gun', 'WebRTCAdapter', { peerId, message }); } } close(peerId: string): void { const peerConnection = this.peerConnections.get(peerId); if (peerConnection) { peerConnection.dataChannel.close(); peerConnection.connection.close(); this.peerConnections.delete(peerId); this.logger.debug('Peer connection closed', 'WebRTCAdapter', { peerId }); } } private createPeerConnection(peerId: string): PeerConnection { const connection = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }); const dataChannel = connection.createDataChannel('dataChannel'); connection.onicecandidate = (event) => { if (event.candidate) { // Send ICE candidate through Gun this.gunDataProvider.gun.get(`webrtc/${peerId}/ice`).set(JSON.stringify(event.candidate)); } }; connection.onconnectionstatechange = () => { this.logger.debug('Connection state changed', 'WebRTCAdapter', { peerId, state: connection.connectionState }); this.emit('connectionStateChange', { peerId, state: connection.connectionState }); }; dataChannel.onopen = () => { this.logger.debug('Data channel opened', 'WebRTCAdapter', { peerId }); this.emit('dataChannelOpen', { peerId }); }; dataChannel.onclose = () => { this.logger.debug('Data channel closed', 'WebRTCAdapter', { peerId }); this.emit('dataChannelClose', { peerId }); }; dataChannel.onmessage = (event) => { this.logger.debug('Message received via WebRTC', 'WebRTCAdapter', { peerId, message: event.data }); this.emit('message', { peerId, message: event.data }); }; const peerConnection: PeerConnection = { connection, dataChannel }; this.peerConnections.set(peerId, peerConnection); return peerConnection; } stop(): void { for (const peerId of this.peerConnections.keys()) { this.close(peerId); } } // Listen for WebRTC signaling messages from Gun listenForSignaling(): void { const currentPeerId = this.gunDataProvider.gun.user().is?.pub; if (!currentPeerId) { this.logger.error('No current peer ID available', 'WebRTCAdapter'); return; } this.gunDataProvider.gun.get(`webrtc/${currentPeerId}/offer`).on(async (offerData: any) => { if (offerData) { const offer = JSON.parse(offerData); const peerId = offer.peerId; // Assume peerId is included in the offer const answer = await this.handleOffer(peerId, offer); this.gunDataProvider.gun.get(`webrtc/${peerId}/answer`).put(JSON.stringify(answer)); } }); this.gunDataProvider.gun.get(`webrtc/${currentPeerId}/answer`).on(async (answerData: any) => { if (answerData) { const answer = JSON.parse(answerData); const peerId = answer.peerId; // Assume peerId is included in the answer await this.handleAnswer(peerId, answer); } }); this.gunDataProvider.gun.get(`webrtc/${currentPeerId}/ice`).on(async (iceData: any) => { if (iceData) { const ice = JSON.parse(iceData); const peerId = ice.peerId; // Assume peerId is included in the ICE candidate await this.addIceCandidate(peerId, ice); } }); } // Method to initiate WebRTC connection async initiateWebRTCConnection(peerId: string): Promise { try { const offer = await this.createOffer(peerId); this.gunDataProvider.gun.get(`webrtc/${peerId}/offer`).put(JSON.stringify({...offer, peerId: this.getCurrentPeerId()})); } catch (error) { this.errorHandler.handleError(error as Error, 'WebRTCAdapter.initiateWebRTCConnection'); } } // Method to check if WebRTC is supported in the current environment isWebRTCSupported(): boolean { return 'RTCPeerConnection' in window; } // Method to get WebRTC connection state for a peer getConnectionState(peerId: string): RTCPeerConnectionState | null { const peerConnection = this.peerConnections.get(peerId); return peerConnection ? peerConnection.connection.connectionState : null; } // Method to restart ICE for a peer connection async restartIce(peerId: string): Promise { const peerConnection = this.peerConnections.get(peerId); if (peerConnection) { try { const offer = await peerConnection.connection.createOffer({ iceRestart: true }); await peerConnection.connection.setLocalDescription(offer); this.gunDataProvider.gun.get(`webrtc/${peerId}/offer`).put(JSON.stringify({...offer, peerId: this.getCurrentPeerId()})); } catch (error) { this.errorHandler.handleError(error as Error, 'WebRTCAdapter.restartIce'); } } else { throw new Error(`No peer connection found for peer ${peerId}`); } } // Method to add a new data channel to an existing peer connection addDataChannel(peerId: string, label: string): RTCDataChannel | null { const peerConnection = this.peerConnections.get(peerId); if (peerConnection) { const dataChannel = peerConnection.connection.createDataChannel(label); this.setupDataChannelListeners(dataChannel, peerId); return dataChannel; } return null; } private setupDataChannelListeners(dataChannel: RTCDataChannel, peerId: string): void { dataChannel.onopen = () => { this.logger.debug(`Data channel ${dataChannel.label} opened`, 'WebRTCAdapter', { peerId }); this.emit('dataChannelOpen', { peerId, label: dataChannel.label }); }; dataChannel.onclose = () => { this.logger.debug(`Data channel ${dataChannel.label} closed`, 'WebRTCAdapter', { peerId }); this.emit('dataChannelClose', { peerId, label: dataChannel.label }); }; dataChannel.onmessage = (event) => { this.logger.debug(`Message received on channel ${dataChannel.label}`, 'WebRTCAdapter', { peerId, message: event.data }); this.emit('message', { peerId, message: event.data, channel: dataChannel.label }); }; } // Method to get all active data channels for a peer getDataChannels(peerId: string): RTCDataChannel[] { const peerConnection = this.peerConnections.get(peerId); if (peerConnection) { return (peerConnection.connection.sctp?.transport as any).dataChannels || []; } return []; } // Method to send a file over WebRTC async sendFile(peerId: string, file: File): Promise { const peerConnection = this.peerConnections.get(peerId); if (peerConnection && peerConnection.dataChannel.readyState === 'open') { const fileReader = new FileReader(); fileReader.onload = (event) => { peerConnection.dataChannel.send(JSON.stringify({ type: 'file', name: file.name, data: event.target?.result })); }; fileReader.readAsArrayBuffer(file); } else { throw new Error(`Unable to send file to peer ${peerId}`); } } // Method to handle received file data private handleFileReceive(peerId: string, fileData: any): void { const blob = new Blob([fileData.data], { type: 'application/octet-stream' }); const url = URL.createObjectURL(blob); this.emit('fileReceived', { peerId, fileName: fileData.name, url }); } }.//net/ServerContext.ts import { Context } from '../Types'; export const SERVER_CONTEXT: Context = 'server'; export function isServerContext(): boolean { return !!(typeof process !== 'undefined' && process.versions && process.versions.node); } export function executeInServerContext(func: Function): any { if (isServerContext()) { return func(); } else { throw new Error('Attempted to execute server-specific code in a non-server environment'); } } export function getServerInfo(): {nodeVersion: string, platform: string} { if (!isServerContext()) { throw new Error('Not in a server context'); } return { nodeVersion: process.version, platform: process.platform }; } export function getEnvironmentVariables(): {[key: string]: string | undefined} { if (!isServerContext()) { throw new Error('Not in a server context'); } return process.env; } export function getServerMemoryUsage(): {rss: number, heapTotal: number, heapUsed: number, external: number} { if (!isServerContext()) { throw new Error('Not in a server context'); } return process.memoryUsage(); } export function getServerUptime(): number { if (!isServerContext()) { throw new Error('Not in a server context'); } return process.uptime(); } export function isProductionMode(): boolean { if (!isServerContext()) { throw new Error('Not in a server context'); } return process.env.NODE_ENV === 'production'; } export function getCPUUsage(): {user: number, system: number} { if (!isServerContext()) { throw new Error('Not in a server context'); } return process.cpuUsage(); } export function getServerArguments(): string[] { if (!isServerContext()) { throw new Error('Not in a server context'); } return process.argv; } export function exitServer(code: number = 0): void { if (!isServerContext()) { throw new Error('Not in a server context'); } process.exit(code); }.//net/PeerContext.ts import { Context } from '../Types'; import { PeerManager } from './PeerManager'; export const PEER_CONTEXT: Context = 'peer'; let peerManager: PeerManager | null = null; export function initializePeerContext(manager: PeerManager): void { peerManager = manager; } export function isPeerContext(): boolean { return peerManager !== null; } export function executeInPeerContext(func: Function): any { if (isPeerContext()) { return func(peerManager); } else { throw new Error('Attempted to execute peer-specific code without an initialized PeerManager'); } } export function getPeerId(): Promise { if (!isPeerContext()) { throw new Error('Not in a peer context'); } // Assuming PeerManager has a method to get the current peer's ID return Promise.resolve((peerManager as PeerManager).getCurrentPeerId()); } export function getPeerConnections(): string[] { if (!isPeerContext()) { throw new Error('Not in a peer context'); } // Assuming PeerManager has a method to get connected peer IDs return (peerManager as PeerManager).getConnectedPeerIds(); } export function sendToPeer(peerId: string, data: any): void { if (!isPeerContext()) { throw new Error('Not in a peer context'); } (peerManager as PeerManager).sendMessage(peerId, JSON.stringify(data)); } export function broadcastToPeers(data: any): void { if (!isPeerContext()) { throw new Error('Not in a peer context'); } (peerManager as PeerManager).broadcastMessage(JSON.stringify(data)); } export function onPeerMessage(callback: (peerId: string, data: any) => void): void { if (!isPeerContext()) { throw new Error('Not in a peer context'); } (peerManager as PeerManager).on('message', ({ peerId, message }) => { callback(peerId, JSON.parse(message)); }); } export function connectToPeer(peerId: string, peerUrl: string): void { if (!isPeerContext()) { throw new Error('Not in a peer context'); } (peerManager as PeerManager).connectToPeer(peerId, peerUrl); } export function disconnectFromPeer(peerId: string): void { if (!isPeerContext()) { throw new Error('Not in a peer context'); } (peerManager as PeerManager).disconnectFromPeer(peerId); } export function getPeerLatency(peerId: string): number { if (!isPeerContext()) { throw new Error('Not in a peer context'); } return (peerManager as PeerManager).getPeerLatency(peerId); }.//PUBLISHING.md Component Publishing and Discovery System Design 1. Component Addressing Scheme: - Format: `user/component-name/version` - Example: `alice@example.com/cool-widget/1.0.0` 2. Component Metadata: - Name - Version - Author - Description - Tags - Dependencies - Access Control List (ACL) - Encryption Key (for private components) 3. Gun Graph Structure: ``` components/ ├── public/ │ └── [user-id]/ │ └── [component-name]/ │ └── [version]/ │ ├── metadata │ └── code └── private/ └── [user-id]/ └── [component-name]/ └── [version]/ ├── metadata (encrypted) └── code (encrypted) ``` 4. Publishing Process: a. User creates a component b. User sets metadata and access controls c. System encrypts private components d. System publishes to the appropriate Gun graph location 5. Discovery Mechanism: - Public component registry - Search by tags, author, or component name - Filtered results based on user's access rights 6. Access Control: - Public: Anyone can access - Private: Only specified users can access - Shared: List of user public keys with access 7. Encryption: - Use SEA for encryption/decryption - Encrypt private components with a symmetric key - Encrypt the symmetric key with authorized users' public keys 8. Component Loading: - Fetch component metadata and code from Gun graph - Decrypt if necessary - Validate dependencies - Load and instantiate component 9. Version Management: - Semantic versioning for components - Support for specifying version ranges in dependencies 10. Integration with Existing System: - Extend Component class with publishing methods - Add component discovery and loading to DecentralizedApp - Integrate with DevTools for debugging published components 11. User Interface: - Component publishing interface in DevTools - Component discovery and installation UI - Access control management interface 12. Security Considerations: - Code signing for integrity verification - Sandboxing for running untrusted components - Rate limiting for publishing and discovery requests 13. Offline Support: - Local cache of installed components - Sync updates when online 14. Collaboration Features: - Fork and modify existing components - Pull requests for component updates - Comments and ratings on public components.//core/Component.ts import { ReactiveUI } from '../ui/ReactiveUI'; import { MultiContextObject } from './MultiContextObject'; import { Context, ComponentState, ComponentProps, PeerMessage, ComponentInstance, ComponentPackage, SchemaDefinition } from '../Types'; import { DistributedState } from '../data/DistributedState'; import { PeerManager } from '../net/PeerManager'; import { SyncManager } from '../net/SyncManager'; import { Logger } from '../Logger'; import { EventEmitter } from '../utils/EventEmitter'; import { ComponentRegistry } from './ComponentRegistry'; import { GunDataProvider } from '../data/GunDataProvider'; import { SandboxedEnvironment } from '../env/SandboxedEnvironment'; export abstract class Component extends MultiContextObject { protected ui: ReactiveUI; protected state: DistributedState; public props: P; protected peerManager: PeerManager; protected syncManager: SyncManager; protected logger: Logger; private eventEmitter: EventEmitter; private childComponents: Map> = new Map(); private metadata: any = {}; private stateUnsubscribe: (() => void) | null = null; constructor( contexts: Context[], dataProvider: GunDataProvider, schema: SchemaDefinition, initialState: S, props: P, peerManager: PeerManager, syncManager: SyncManager ) { super(contexts); this.ui = new ReactiveUI(); this.props = props; this.peerManager = peerManager; this.syncManager = syncManager; this.state = new DistributedState(dataProvider, this.getPath(), schema); this.state.set(initialState); this.logger = Logger.getInstance(); this.eventEmitter = new EventEmitter(); this.setupStateSubscription(); this.setupPeerMessageHandler(); } private getPath(): string { return `${this.constructor.name}/${this.state.getId()}`; } private setupStateSubscription(): void { this.stateUnsubscribe = this.state.subscribe(this.handleStateChange.bind(this)); } private setupPeerMessageHandler(): void { this.peerManager.on('message', this.handlePeerMessage.bind(this)); } abstract render(): string; async publish(registry: ComponentRegistry, currentUserPair: any, schema: SchemaDefinition): Promise { const code = this.serialize(); const componentPackage: ComponentPackage = { metadata: this.metadata, code, state: await this.state.get(), schema }; await registry.publishComponent(componentPackage, currentUserPair); } static async load( address: string, registry: ComponentRegistry, userPair: any, dataProvider: GunDataProvider, syncManager: SyncManager, schema: SchemaDefinition ): Promise { const componentPackage = await registry.getComponent(address, userPair); if (!componentPackage) return null; const { metadata, code, state, schema: componentSchema } = componentPackage; const parsed = JSON.parse(code); const sandboxedEnv = new SandboxedEnvironment(); const componentClass = sandboxedEnv.evaluate(` (class extends Component { constructor(metadata, state) { super(metadata, state); ${Object.entries(parsed.methods).map(([name, func]) => `this.${name} = ${func};`).join('\n')} } render() { return (${parsed.render})(); } }) `); const component = new componentClass(metadata, state); const distributedState = new DistributedState(dataProvider, `${address}/state`, componentSchema || schema); await distributedState.set(state); return { component, state: distributedState }; } private serialize(): string { return JSON.stringify({ metadata: this.metadata, render: this.render.toString(), methods: Object.getOwnPropertyNames(Object.getPrototypeOf(this)) .filter(name => name !== 'constructor' && typeof (this as any)[name] === 'function') .reduce((acc, name) => ({ ...acc, [name]: (this as any)[name].toString() }), {}) }); } // Add methods for component lifecycle management onMount() {} onUnmount() {} onUpdate(prevProps: any, prevState: any) {} protected setState(newState: Partial, broadcast: boolean = true): void { this.state.update( (state: S) => ({ ...state, ...newState }), ); } private handleStateChange(newState: S): void { this.update(); this.eventEmitter.emit('stateChanged', newState); } protected handlePeerMessage(message: PeerMessage): void { // Override this method in subclasses to handle peer messages } update(): void { this.ui.update(this.render() as any); } mount(element: HTMLElement): void { this.ui.mount(element); this.update(); this.onMount(); } unmount(): void { this.ui.unmount(); if (this.stateUnsubscribe) { this.stateUnsubscribe(); } this.peerManager.off('message', this.handlePeerMessage); this.onUnmount(); } updateProps(newProps: Partial

): void { const oldProps = { ...this.props }; this.props = { ...this.props, ...newProps }; this.update(); this.onUpdate(oldProps, this.state.getCurrentState()); } // Child component management protected registerChildComponent(key: string, component: Component): void { this.childComponents.set(key, component); } protected getChildComponent(key: string): Component | undefined { return this.childComponents.get(key); } protected removeChildComponent(key: string): void { const component = this.childComponents.get(key); if (component) { component.unmount(); this.childComponents.delete(key); } } // Event handling public on(event: string, listener: (...args: any[]) => void): void { this.eventEmitter.on(event, listener); } public off(event: string, listener: (...args: any[]) => void): void { this.eventEmitter.off(event, listener); } public emit(event: string, ...args: any[]): void { this.eventEmitter.emit(event, ...args); } // Peer-to-peer methods public sendToPeer(peerId: string, message: any): void { this.peerManager.sendToPeer(peerId, message); } public broadcastToPeers(message: any): void { this.peerManager.broadcast(message); } // Distributed state methods public syncState(): void { this.syncManager.syncState(this.state.getId(), this.state.getCurrentState()); } public async fetchStateFromPeers(): Promise { const peerState = await this.syncManager.fetchStateFromPeers(this.state.getId()); if (peerState) { await this.state.set(peerState); } } // Context-aware method execution public executeInContext(context: Context, method: () => any): Promise { return super.executeInContext(context, method.bind(this)); } // Utility methods protected log(level: 'debug' | 'info' | 'warn' | 'error', message: string, data?: any): void { this.logger[level](message, this.constructor.name, data); } // State persistence protected async saveState(): Promise { const currentState = await this.state.get(); await this.syncManager.persistState(this.state.getId(), currentState); } protected async loadState(): Promise { const loadedState = await this.syncManager.loadPersistedState(this.state.getId()); if (loadedState) { await this.state.set(loadedState as S); } } // Dynamic imports for code splitting protected async importComponent(path: string): Promise { return import(path).then(module => module.default); } // Error boundary protected catchError(error: Error): void { this.log('error', 'Error caught in component', error); // Implement error handling logic here } }.//core/MultiContextObject.ts import { Context, ContextSwitch, ContextState, ContextTransition } from '../Types'; import { BROWSER_CONTEXT, SERVER_CONTEXT, PEER_CONTEXT } from '../utils/Constants'; import { EventEmitter } from '../utils/EventEmitter'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; export class MultiContextObject extends EventEmitter { protected contexts: Map; protected currentContext: Context; protected transitionInProgress: boolean = false; protected logger: Logger; protected errorHandler: ErrorHandler; constructor(contexts: Context[]) { super(); this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); this.contexts = new Map(contexts.map(context => [context, { active: false, data: {}, context }])); this.currentContext = this.detectContext(); this.activateContext(this.currentContext); this.setupContextListeners(); } private detectContext(): Context { if (typeof window !== 'undefined' && typeof document !== 'undefined') { return BROWSER_CONTEXT; } else if (typeof process !== 'undefined' && process.versions && process.versions.node) { return SERVER_CONTEXT; } else { return PEER_CONTEXT; } } private setupContextListeners(): void { this.on('beforeContextSwitch', this.handleBeforeContextSwitch.bind(this)); this.on('afterContextSwitch', this.handleAfterContextSwitch.bind(this)); this.on('contextError', this.handleContextError.bind(this)); } private async handleBeforeContextSwitch(transition: ContextTransition): Promise { this.logger.debug('Preparing for context switch', 'MultiContextObject', transition); // Perform any necessary cleanup or state saving for the current context await this.deactivateContext(transition.from); } private async handleAfterContextSwitch(transition: ContextTransition): Promise { this.logger.debug('Finalizing context switch', 'MultiContextObject', transition); // Perform any necessary setup for the new context await this.activateContext(transition.to); } private handleContextError(error: Error, context: Context): void { this.errorHandler.handleError(error, `MultiContextObject (${context})`); } private async activateContext(context: Context): Promise { const contextState = this.contexts.get(context); if (contextState) { contextState.active = true; // Perform any necessary initialization for the context this.emit('contextActivated', context); } } private async deactivateContext(context: Context): Promise { const contextState = this.contexts.get(context); if (contextState) { contextState.active = false; // Perform any necessary cleanup for the context this.emit('contextDeactivated', context); } } isValidContext(context: Context): boolean { return this.contexts.has(context); } getCurrentContext(): Context { return this.currentContext; } getContextState(context: Context): ContextState | undefined { return this.contexts.get(context); } setContextData(context: Context, key: string, value: any): void { const contextState = this.contexts.get(context); if (contextState) { contextState.data[key] = value; } } getContextData(context: Context, key: string): any { const contextState = this.contexts.get(context); return contextState ? contextState.data[key] : undefined; } async switchContext(newContext: Context): Promise { if (!this.isValidContext(newContext)) { throw new Error(`Invalid context: ${newContext}`); } if (this.currentContext === newContext) { return; } if (this.transitionInProgress) { throw new Error('Context switch already in progress'); } this.transitionInProgress = true; try { const transition: ContextTransition = { from: this.currentContext, to: newContext }; await this.emit('beforeContextSwitch', transition); const prevContext = this.currentContext; this.currentContext = newContext; await this.emit('afterContextSwitch', { ...transition, success: true }); } catch (error) { this.emit('contextError', error, newContext); throw error; } finally { this.transitionInProgress = false; } } async executeInContext(context: Context, func: () => Promise | T): Promise { const originalContext = this.currentContext; if (originalContext !== context) { await this.switchContext(context); } try { return await func(); } finally { if (originalContext !== context) { await this.switchContext(originalContext); } } } async executeInAllContexts(func: (context: Context) => Promise | T): Promise> { const results = new Map(); for (const context of this.contexts.keys()) { results.set(context, await this.executeInContext(context, () => func(context))); } return results; } async executeInMultipleContexts(contexts: Context[], func: (context: Context) => Promise | T): Promise> { const results = new Map(); for (const context of contexts) { if (this.isValidContext(context)) { results.set(context, await this.executeInContext(context, () => func(context))); } } return results; } onContextActivated(callback: (context: Context) => void): void { this.on('contextActivated', callback); } onContextDeactivated(callback: (context: Context) => void): void { this.on('contextDeactivated', callback); } onBeforeContextSwitch(callback: (transition: ContextTransition) => void): void { this.on('beforeContextSwitch', callback); } onAfterContextSwitch(callback: (transition: ContextTransition) => void): void { this.on('afterContextSwitch', callback); } async withContext(context: Context, func: () => Promise | T): Promise { return this.executeInContext(context, func); } isContextActive(context: Context): boolean { const contextState = this.contexts.get(context); return contextState ? contextState.active : false; } getActiveContexts(): Context[] { return Array.from(this.contexts.entries()) .filter(([_, state]) => state.active) .map(([context, _]) => context); } async broadcastToActiveContexts(func: (context: Context) => Promise | T): Promise> { const activeContexts = this.getActiveContexts(); return this.executeInMultipleContexts(activeContexts, func); } }.//core/DecentralizedApp.ts import { GunDataProvider } from '../data/GunDataProvider'; import { AuthManager } from '../auth/AuthManager'; import { SyncManager } from '../net/SyncManager'; import { PeerManager } from '../net/PeerManager'; import { PluginSystem } from './PluginSystem'; import { ContextRouter } from './ContextRouter'; import { DevTools } from '../dev/DevTools'; import { Logger } from '../Logger'; import { NetworkMonitor } from '../net/NetworkMonitor'; import { MultiContextObject } from './MultiContextObject'; import { BROWSER_CONTEXT, SERVER_CONTEXT, PEER_CONTEXT } from '../utils/Constants'; import { DistributedState } from '../data/DistributedState'; import { Component } from './Component'; import { ComponentRegistry } from './ComponentRegistry'; import { ComponentMetadata, ComponentInstance, ComponentUpdateEvent, SchemaDefinition } from '../Types'; export class DecentralizedApp extends MultiContextObject { private gunDataProvider: GunDataProvider; private authManager: AuthManager; private syncManager: SyncManager; private peerManager: PeerManager; private pluginSystem: PluginSystem; private contextRouter: ContextRouter; private devTools: DevTools; public logger: Logger; private networkMonitor: NetworkMonitor; private componentRegistry: ComponentRegistry; private loadedComponents: Map = new Map(); constructor(gun: GunDataProvider) { super([BROWSER_CONTEXT, SERVER_CONTEXT, PEER_CONTEXT]); this.logger = Logger.getInstance(); this.gunDataProvider = gun; this.authManager = new AuthManager(this.gunDataProvider); this.syncManager = new SyncManager(this.gunDataProvider); this.peerManager = new PeerManager(this.gunDataProvider); this.pluginSystem = new PluginSystem(); this.contextRouter = new ContextRouter(this.peerManager); this.networkMonitor = new NetworkMonitor(this.gunDataProvider); this.devTools = new DevTools(this.logger, this.networkMonitor, this.peerManager, this.syncManager, this.pluginSystem, this.gunDataProvider, this.authManager, this.contextRouter); this.componentRegistry = new ComponentRegistry(this.gunDataProvider); this.setupUpdateListeners(); } getCurrentUserPair(): any { return this.authManager.getCurrentUser(); } async publishComponent(component: Component, schema: SchemaDefinition): Promise { const currentUserPair = this.getCurrentUserPair(); await component.publish(this.componentRegistry, currentUserPair, schema); } async loadComponent(address: string, schema: SchemaDefinition): Promise { const userPair = this.getCurrentUserPair(); const componentInstance = await Component.load(address, this.componentRegistry, userPair, this.gunDataProvider, this.syncManager, schema); if (componentInstance) { this.loadedComponents.set(address, componentInstance); await componentInstance.component.onMount(); } return componentInstance; } async searchComponents(query: string, limit: number = 10): Promise { return this.componentRegistry.searchComponents(query, limit); } getLoadedComponent(address: string): ComponentInstance | undefined { return this.loadedComponents.get(address); } async unloadComponent(address: string): Promise { const componentInstance = this.loadedComponents.get(address); if (componentInstance) { await componentInstance.component.onUnmount(); this.loadedComponents.delete(address); } } private setupUpdateListeners(): void { this.componentRegistry.on('componentUpdate', this.handleComponentUpdate.bind(this)); } private async handleComponentUpdate(event: ComponentUpdateEvent): Promise { const loadedComponent = this.loadedComponents.get(event.id); if (loadedComponent) { const userPair = this.getCurrentUserPair(); const updatedComponent = await Component.load(event.id, this.componentRegistry, userPair, this.gunDataProvider, this.syncManager, loadedComponent.state.getSchema()); if (updatedComponent) { const prevProps = loadedComponent.component.props; const prevState = await loadedComponent.state.get(); await this.unloadComponent(event.id); this.loadedComponents.set(event.id, updatedComponent); await updatedComponent.component.onUpdate(prevProps, prevState); } } } async initialize(): Promise { await this.executeInAllContexts(async () => { await this.pluginSystem.broadcastToPlugins('onAppInitialize', this); }); } async start(): Promise { await this.initialize(); this.logger.info('DecentralizedApp started', 'DecentralizedApp'); this.emit('appStarted'); } async stop(): Promise { await this.executeInAllContexts(async () => { await this.peerManager.stop(); await this.syncManager.stop(); await this.pluginSystem.broadcastToPlugins('onAppStop', this); }); this.logger.info('DecentralizedApp stopped', 'DecentralizedApp'); this.emit('appStopped'); } getAuthManager(): AuthManager { return this.authManager; } getSyncManager(): SyncManager { return this.syncManager; } getPeerManager(): PeerManager { return this.peerManager; } getPluginSystem(): PluginSystem { return this.pluginSystem; } getContextRouter(): ContextRouter { return this.contextRouter; } getDevTools(): DevTools { return this.devTools; } createDistributedState(initialState: T, path: string, schema: SchemaDefinition): DistributedState { return new DistributedState(this.gunDataProvider, path, schema, initialState); } async route(path: string, data?: any): Promise { return this.contextRouter.route(path, this, data); } async broadcastRoute(path: string, data?: any): Promise { return this.contextRouter.broadcastRoute(path, this, data); } async executeInPeer(peerId: string, func: Function): Promise { return this.peerManager.executeInPeerContext(peerId, func as any); } onPeerMessage(callback: (peerId: string, message: any) => void): void { this.peerManager.on('message', callback); } broadcastToPeers(message: any): void { this.peerManager.broadcast(message); } }.//core/PluginSystem.ts import EventEmitter from "events"; import { ErrorHandler } from "src"; import { Logger } from "src/Logger"; import { PluginMetadata } from "src/Types"; interface Plugin { metadata: PluginMetadata; initialize?(): Promise; destroy?(): Promise; } export class PluginSystem extends EventEmitter { private plugins: Map = new Map(); private hooks: Map> = new Map(); private logger: Logger; private errorHandler: ErrorHandler; constructor() { super(); this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); } async registerPlugin(plugin: Plugin): Promise { if (this.plugins.has(plugin.metadata.name)) { throw new Error(`Plugin ${plugin.metadata.name} is already registered`); } try { if(plugin.initialize) await plugin.initialize(); this.plugins.set(plugin.metadata.name, plugin); this.logger.info('Plugin registered', 'PluginSystem', { plugin: plugin.metadata.name }); this.emit('pluginRegistered', plugin.metadata); } catch (error) { this.errorHandler.handleError(error as Error, 'PluginSystem.registerPlugin'); throw error; } } async unregisterPlugin(pluginName: string): Promise { const plugin = this.plugins.get(pluginName); if (!plugin) { throw new Error(`Plugin ${pluginName} is not registered`); } try { if(plugin.destroy) await plugin.destroy(); this.plugins.delete(pluginName); this.logger.info('Plugin unregistered', 'PluginSystem', { plugin: pluginName }); this.emit('pluginUnregistered', plugin.metadata); } catch (error) { this.errorHandler.handleError(error as Error, 'PluginSystem.unregisterPlugin'); throw error; } } getPlugin(pluginName: string): Plugin | undefined { return this.plugins.get(pluginName); } getAllPlugins(): Plugin[] { return Array.from(this.plugins.values()); } registerHook(hookName: string, callback: Function): void { if (!this.hooks.has(hookName)) { this.hooks.set(hookName, new Set()); } this.hooks.get(hookName)!.add(callback); this.logger.debug('Hook registered', 'PluginSystem', { hook: hookName }); } unregisterHook(hookName: string, callback: Function): void { const hookSet = this.hooks.get(hookName); if (hookSet) { hookSet.delete(callback); if (hookSet.size === 0) { this.hooks.delete(hookName); } this.logger.debug('Hook unregistered', 'PluginSystem', { hook: hookName }); } } broadcastToPlugins(event: string, ...args: any[]): void { for (const plugin of this.plugins.values()) { if ((plugin as any)[event]) { try { (plugin as any)[event](...args); } catch (error) { this.errorHandler.handleError(error as Error, 'PluginSystem.broadcastToPlugins'); } } } } async executeHook(hookName: string, ...args: any[]): Promise { const hookSet = this.hooks.get(hookName); if (!hookSet) { return []; } const results: any[] = []; for (const callback of hookSet) { try { const result = await callback(...args); results.push(result); } catch (error) { this.errorHandler.handleError(error as Error, 'PluginSystem.executeHook'); } } return results; } async initializeAllPlugins(): Promise { for (const [pluginName, plugin] of this.plugins) { try { if(plugin.initialize) await plugin.initialize(); this.logger.info('Plugin initialized', 'PluginSystem', { plugin: pluginName }); } catch (error) { this.errorHandler.handleError(error as Error, 'PluginSystem.initializeAllPlugins'); } } } async destroyAllPlugins(): Promise { for (const [pluginName, plugin] of this.plugins) { try { if(plugin.destroy) await plugin.destroy(); this.logger.info('Plugin destroyed', 'PluginSystem', { plugin: pluginName }); } catch (error) { this.errorHandler.handleError(error as Error, 'PluginSystem.destroyAllPlugins'); } } this.plugins.clear(); this.hooks.clear(); } isPluginRegistered(pluginName: string): boolean { return this.plugins.has(pluginName); } getPluginMetadata(pluginName: string): PluginMetadata | undefined { const plugin = this.plugins.get(pluginName); return plugin ? plugin.metadata : undefined; } getAllPluginMetadata(): PluginMetadata[] { return Array.from(this.plugins.values()).map(plugin => plugin.metadata); } async reloadPlugin(pluginName: string): Promise { const plugin = this.plugins.get(pluginName); if (!plugin) { throw new Error(`Plugin ${pluginName} is not registered`); } try { if(plugin.destroy) await plugin.destroy(); if(plugin.initialize) await plugin.initialize(); this.logger.info('Plugin reloaded', 'PluginSystem', { plugin: pluginName }); this.emit('pluginReloaded', plugin.metadata); } catch (error) { this.errorHandler.handleError(error as Error, 'PluginSystem.reloadPlugin'); throw error; } } getHooks(): string[] { return Array.from(this.hooks.keys()); } clearHooks(): void { this.hooks.clear(); this.logger.info('All hooks cleared', 'PluginSystem'); } } // Singleton instance export const pluginSystem = new PluginSystem(); // Decorator for creating plugins export function Plugin(metadata: PluginMetadata) { return function ; destroy?(): Promise; } }>(constructor: T) { return class extends constructor implements Plugin { metadata = metadata; async initialize(): Promise { if (super.initialize) { await super.initialize(); } } async destroy(): Promise { if (super.destroy) { await super.destroy(); } } } } } // Helper function to create and register a plugin export async function createAndRegisterPlugin( PluginClass: new () => T ): Promise { const plugin = new PluginClass(); await pluginSystem.registerPlugin(plugin); return plugin; }.//core/ContextRouter.ts import { Context, RouteHandler, Middleware, RouteMatch, RouteParams, RouteContext } from '../Types'; import { MultiContextObject } from './MultiContextObject'; import { EventEmitter } from '../utils/EventEmitter'; import { PeerManager } from '../net/PeerManager'; import { Logger } from '../Logger'; export class ContextRouter extends EventEmitter { private routes: Map>; private middleware: Middleware[]; private peerManager: PeerManager; private logger: Logger; constructor(peerManager: PeerManager) { super(); this.routes = new Map(); this.middleware = []; this.peerManager = peerManager; this.logger = Logger.getInstance(); } addRoute(path: string, context: Context, handler: RouteHandler, options: RouteOptions = {}): void { if (!this.routes.has(path)) { this.routes.set(path, new Map()); } this.routes.get(path)!.set(context, { handler, options }); this.logger.debug(`Route added: ${path} for context ${context}`, 'ContextRouter'); } use(middleware: Middleware): void { this.middleware.push(middleware); this.logger.debug('Middleware added', 'ContextRouter'); } async route(path: string, multiContextObject: MultiContextObject, data?: any): Promise { const match = this.findRouteMatch(path); if (!match) { throw new Error(`No route found for path: ${path}`); } const { routeConfig, params } = match; const currentContext = multiContextObject.getCurrentContext(); if (!routeConfig.has(currentContext)) { throw new Error(`No handler found for context ${currentContext} on path ${path}`); } const { handler, options } = routeConfig.get(currentContext)!; const routeContext: RouteContext = { path, params, data, context: currentContext, peerManager: this.peerManager }; // Run middleware for (const mw of this.middleware) { await mw(routeContext); } // Run context-specific middleware if (options.middleware) { for (const mw of options.middleware) { await mw(routeContext); } } return multiContextObject.executeInContext(currentContext, () => handler(routeContext)); } async broadcastRoute(path: string, multiContextObject: MultiContextObject, data?: any): Promise { const match = this.findRouteMatch(path); if (!match) { throw new Error(`No route found for path: ${path}`); } const { routeConfig, params } = match; const results = []; for (const [context, { handler, options }] of routeConfig.entries()) { const routeContext: RouteContext = { path, params, data, context, peerManager: this.peerManager }; // Run middleware for (const mw of this.middleware) { await mw(routeContext); } // Run context-specific middleware if (options.middleware) { for (const mw of options.middleware) { await mw(routeContext); } } const result = await multiContextObject.executeInContext(context, () => handler(routeContext)); results.push(result); } return results; } async routeToPeer(peerId: string, path: string, data?: any): Promise { return this.peerManager.executeInPeerContext(peerId, (peer: any) => { return peer.route(path, data); }); } private findRouteMatch(path: string): RouteMatch | null { for (const [routePath, routeConfig] of this.routes.entries()) { const params = this.matchRoute(routePath, path); if (params !== null) { return { routeConfig, params }; } } return null; } private matchRoute(routePath: string, path: string): RouteParams | null { const routeParts = routePath.split('/'); const pathParts = path.split('/'); if (routeParts.length !== pathParts.length) { return null; } const params: RouteParams = {}; for (let i = 0; i < routeParts.length; i++) { if (routeParts[i].startsWith(':')) { params[routeParts[i].slice(1)] = pathParts[i]; } else if (routeParts[i] !== pathParts[i]) { return null; } } return params; } getRoutes(): Map> { return new Map(this.routes); } clearRoutes(): void { this.routes.clear(); this.logger.debug('All routes cleared', 'ContextRouter'); } removeRoute(path: string, context?: Context): void { if (context) { const routeConfig = this.routes.get(path); if (routeConfig) { routeConfig.delete(context); if (routeConfig.size === 0) { this.routes.delete(path); } } } else { this.routes.delete(path); } this.logger.debug(`Route removed: ${path}${context ? ` for context ${context}` : ''}`, 'ContextRouter'); } } interface RouteOptions { middleware?: Middleware[]; } interface RouteConfig { handler: RouteHandler; options: RouteOptions; }.//core/ComponentRegistry.ts // ComponentRegistry.ts import { GunDataProvider } from '../data/GunDataProvider'; import { SEA } from '../auth/SEA'; import { ComponentMetadata, ComponentPackage, EncryptedComponentPackage, AccessControlList, ComponentUpdateEvent } from '../Types'; import { EventEmitter } from '../utils/EventEmitter'; import Fuse from 'fuse.js'; export class ComponentRegistry extends EventEmitter { private gun: GunDataProvider; private componentIndex: Fuse; private indexedComponents: ComponentMetadata[] = []; constructor(gun: GunDataProvider) { super(); this.gun = gun; this.setupUpdateListeners().then(() => { this.initializeSearchIndex(); }); this.componentIndex = new Fuse([], { keys: [] }); } async getComponent(address: string, userPair: any): Promise { const path = this.getComponentPath(this.parseAddress(address)); const data = await this.gun.get(path); if (!data) return null; if (data.metadata && typeof data.metadata !== 'string') { // Public component if (!await this.verifyComponentSignature(data)) { throw new Error('Component signature verification failed'); } return data as ComponentPackage; } else { // Private or shared component const decrypted = await this.decryptComponent(data as EncryptedComponentPackage, userPair); if (!decrypted) return null; if (!await this.verifyComponentSignature(decrypted)) { throw new Error('Component signature verification failed'); } return decrypted; } } getComponentSchema(address: string, userPair: any): Promise { const path = this.getComponentPath(this.parseAddress(address)); return this.gun.get(path); } private async initializeSearchIndex() { // Fetch all public components and index them const publicComponents = await this.fetchAllPublicComponents(); this.indexedComponents = publicComponents; const options = { keys: ['name', 'description', 'tags', 'author'], threshold: 0.3, includeScore: true }; this.componentIndex = new Fuse(this.indexedComponents, options); } private async fetchAllPublicComponents(): Promise { return new Promise(async (resolve) => { const components: ComponentMetadata[] = []; (await this.gun.get('components/public')).map().on((component: ComponentPackage, key: string) => { components.push(component.metadata); }).once(() => { resolve(components); }); }); } async searchComponents(query: string, limit: number = 10): Promise { const results = this.componentIndex.search(query); return results .slice(0, limit) .map(result => result.item); } async publishComponent(component: ComponentPackage, currentUserPair: any): Promise { const { metadata, code, state } = component; const path = this.getComponentPath(metadata); // Sign the component metadata.signature = await SEA.sign(JSON.stringify({ metadata, code }), currentUserPair); if (metadata.acl.type === 'public') { await this.gun.put(path, { metadata, code, state }); } else { const encryptedPackage = await this.encryptComponent(component, metadata.acl, currentUserPair); await this.gun.put(path, encryptedPackage); } // Notify about the new version this.notifyComponentUpdate(metadata); this.updateSearchIndex(component.metadata); } private updateSearchIndex(metadata: ComponentMetadata) { const existingIndex = this.indexedComponents.findIndex(c => c.id === metadata.id); if (existingIndex !== -1) { // Update existing component in the index this.indexedComponents[existingIndex] = metadata; } else { // Add new component to the index this.indexedComponents.push(metadata); } const options = { keys: ['name', 'description', 'tags', 'author'], threshold: 0.3, includeScore: true }; this.componentIndex = new Fuse(this.indexedComponents, options); } private async setupUpdateListeners() { (await this.gun.get('components')).map().on((component: ComponentPackage, key: string) => { this.updateSearchIndex(component.metadata); this.notifyComponentUpdate(component.metadata); }); } async updateComponentAccess(componentId: string, newAcl: AccessControlList, currentUserPair: any): Promise { const component = await this.getComponent(componentId, currentUserPair); if (!component) throw new Error('Component not found'); component.metadata.acl = newAcl; await this.publishComponent(component, currentUserPair); } private notifyComponentUpdate(metadata: ComponentMetadata): void { const updateEvent: ComponentUpdateEvent = { id: metadata.id, version: metadata.version, changes: [], // You would need to implement a way to track changes between versions }; this.emit('componentUpdate', updateEvent); } private getComponentPath(metadata: ComponentMetadata): string { const baseType = metadata.acl.type === 'public' ? 'public' : 'private'; return `components/${baseType}/${metadata.author}/${metadata.id}/${metadata.version}`; } private parseAddress(address: string): ComponentMetadata { const [author, id, version] = address.split('/'); return { author, id, version } as ComponentMetadata; } private async encryptComponent( component: ComponentPackage, acl: AccessControlList, currentUserPair: any ): Promise { function generateRandom(length: number): string { return Math.random().toString(36).substring(2, 2 + length); } const symmetricKey = generateRandom(16); const encryptedMetadata = await SEA.encrypt(JSON.stringify(component.metadata), symmetricKey); const encryptedCode = await SEA.encrypt(component.code, symmetricKey); const encryptedState = component.state ? await SEA.encrypt(JSON.stringify(component.state), symmetricKey) : undefined; const encryptedKey: { [key: string]: string } = {}; for (const userPubKey of acl.allowedUsers || []) { encryptedKey[userPubKey] = await SEA.encrypt(symmetricKey, await SEA.secret(userPubKey, currentUserPair)); } return { metadata: encryptedMetadata, code: encryptedCode, state: encryptedState, encryptedKey }; } private async decryptComponent( encryptedPackage: EncryptedComponentPackage, userPair: any ): Promise { const symmetricKey = await SEA.decrypt(encryptedPackage.encryptedKey[userPair.pub], userPair); if (!symmetricKey) return null; const metadata = JSON.parse(await SEA.decrypt(encryptedPackage.metadata, symmetricKey) as string); const code = await SEA.decrypt(encryptedPackage.code, symmetricKey) as string; const state = encryptedPackage.state ? JSON.parse(await SEA.decrypt(encryptedPackage.state, symmetricKey) as string) : undefined; return { metadata, code, state }; } private async verifyComponentSignature(component: ComponentPackage): Promise { const { metadata, code } = component; const signedData = JSON.stringify({ metadata: { ...metadata, signature: undefined }, code }); return await SEA.verify(signedData, metadata.signature); // TODO: check if this is correct } }.//auth/CryptoUtils.ts import { EncryptedData } from 'src/Types'; import { CRYPTO_ALGORITHM, CRYPTO_KEY_LENGTH } from '../utils/Constants'; export class CryptoUtils { private static async generateKey(): Promise { return await window.crypto.subtle.generateKey( { name: CRYPTO_ALGORITHM, length: CRYPTO_KEY_LENGTH }, true, ['encrypt', 'decrypt'] ); } private static async exportKey(key: CryptoKey): Promise { const exported = await window.crypto.subtle.exportKey('raw', key); return btoa(String.fromCharCode(...new Uint8Array(exported))); } private static async importKey(keyData: string): Promise { const keyDataBinary = Uint8Array.from(atob(keyData), c => c.charCodeAt(0)); return await window.crypto.subtle.importKey( 'raw', keyDataBinary, CRYPTO_ALGORITHM, true, ['encrypt', 'decrypt'] ); } static async encrypt(data: string, key?: string): Promise { const cryptoKey = key ? await this.importKey(key) : await this.generateKey(); const iv = window.crypto.getRandomValues(new Uint8Array(12)); const encodedData = new TextEncoder().encode(data); const encryptedContent = await window.crypto.subtle.encrypt( { name: CRYPTO_ALGORITHM, iv: iv }, cryptoKey, encodedData ); const exportedKey = key || await this.exportKey(cryptoKey); return { ct: btoa(String.fromCharCode(...new Uint8Array(encryptedContent))), iv: btoa(String.fromCharCode(...iv)), s: exportedKey }; } static async decrypt(encryptedData: EncryptedData): Promise { const cryptoKey = await this.importKey(encryptedData.s); const iv = Uint8Array.from(atob(encryptedData.iv), c => c.charCodeAt(0)); const encryptedContent = Uint8Array.from(atob(encryptedData.ct), c => c.charCodeAt(0)); const decryptedContent = await window.crypto.subtle.decrypt( { name: CRYPTO_ALGORITHM, iv: iv }, cryptoKey, encryptedContent ); return new TextDecoder().decode(decryptedContent); } static async hash(data: string): Promise { const encodedData = new TextEncoder().encode(data); const hashBuffer = await window.crypto.subtle.digest('SHA-256', encodedData); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); } static generateRandomId(length: number = 32): string { const array = new Uint8Array(length / 2); window.crypto.getRandomValues(array); return Array.from(array, dec => dec.toString(16).padStart(2, "0")).join(''); } }.//auth/AuthManager.ts import { EventEmitter } from '../utils/EventEmitter'; import { GunDataProvider } from '../data/GunDataProvider'; import { SEA } from '../auth/SEA'; import { User, AuthCredentials } from '../Types'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; export class AuthManager extends EventEmitter { private gunDataProvider: GunDataProvider; private currentUser: User | null = null; private logger: Logger; private errorHandler: ErrorHandler; constructor(gunDataProvider: GunDataProvider) { super(); this.gunDataProvider = gunDataProvider; this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); } async register(credentials: AuthCredentials): Promise { try { const result = await SEA.createUser(credentials.username, credentials.password); const user: User = { alias: credentials.username, pub: result.pub }; this.currentUser = user; this.emit('userRegistered', user); this.logger.info('User registered', 'AuthManager', { username: credentials.username }); return user; } catch (error) { this.errorHandler.handleError(error as Error, 'AuthManager.register'); throw error; } } async login(credentials: AuthCredentials): Promise { try { const result = await SEA.authenticateUser(credentials.username, credentials.password); const user: User = { alias: credentials.username, pub: result.pub }; this.currentUser = user; this.emit('userLoggedIn', user); this.logger.info('User logged in', 'AuthManager', { username: credentials.username }); return user; } catch (error) { this.errorHandler.handleError(error as Error, 'AuthManager.login'); throw error; } } logout(): void { this.gunDataProvider.logout(); this.currentUser = null; this.emit('userLoggedOut'); this.logger.info('User logged out', 'AuthManager'); } getCurrentUser(): User | null { return this.currentUser; } isAuthenticated(): boolean { return this.gunDataProvider.isAuthenticated(); } async changePassword(currentPassword: string, newPassword: string): Promise { if (!this.currentUser) { throw new Error('No user is currently logged in'); } try { // Verify current password await SEA.authenticateUser(this.currentUser.alias, currentPassword); // Change password await (await this.gunDataProvider.get(`~@${this.currentUser.alias}`)).put({ auth: newPassword }); this.logger.info('Password changed successfully', 'AuthManager'); } catch (error) { this.errorHandler.handleError(error as Error, 'AuthManager.changePassword'); throw error; } } async resetPassword(username: string, resetToken: string, newPassword: string): Promise { try { // Verify reset token const isValidToken = await this.verifyResetToken(username, resetToken); if (!isValidToken) { throw new Error('Invalid or expired reset token'); } // Change password await (await this.gunDataProvider.get(`~@${username}`)).put({ auth: newPassword }); // Invalidate reset token await this.invalidateResetToken(username); this.logger.info('Password reset successfully', 'AuthManager', { username }); } catch (error) { this.errorHandler.handleError(error as Error, 'AuthManager.resetPassword'); throw error; } } private async verifyResetToken(username: string, resetToken: string): Promise { // Implement token verification logic here // This is a placeholder implementation return true; } private async invalidateResetToken(username: string): Promise { // Implement token invalidation logic here // This is a placeholder implementation } async requestPasswordReset(username: string): Promise { try { // Generate reset token const resetToken = await SEA.work(username, username, { name: 'SHA-256' }); // Store reset token (you might want to store this more securely and with an expiration) await (await this.gunDataProvider.get(`~@${username}`)).get('resetToken').put(resetToken); // In a real-world scenario, you would send this token to the user via email this.logger.info('Password reset requested', 'AuthManager', { username, resetToken }); } catch (error) { this.errorHandler.handleError(error as Error, 'AuthManager.requestPasswordReset'); throw error; } } }.//auth/SEA.ts import Gun from 'gun'; import 'gun/sea'; import { EncryptedData } from '../Types'; const gun = Gun(); export class SEA { static async pair(): Promise { return await Gun.SEA.pair(); } static async encrypt(data: any, pair: any): Promise { return await Gun.SEA.encrypt(data, pair); } static async decrypt(encryptedData: string, pair: any): Promise { return await Gun.SEA.decrypt(encryptedData, pair); } static async sign(data: any, pair: any): Promise { return await Gun.SEA.sign(data, pair); } static async verify(signedData: string, pair: any): Promise { return await Gun.SEA.verify(signedData, pair); } static async work(data: string, salt: any, options?: any): Promise { return await Gun.SEA.work(data, salt, null, options); } static async certify(certificants: string | string[], policy: any, authority: any, expiry?: any, cb?: any): Promise { return await Gun.SEA.certify(certificants, policy, authority, expiry, cb); } static async recall(props: any, cb?: any): Promise { const user = gun.user(); return await user.recall(props, cb); } static async secret(key: any, pair: any, cb?: any): Promise { return await Gun.SEA.secret(key, pair, cb); } static async derive(passphrase: string, salt?: any, options?: any): Promise<{ epriv: string; epub: string }> { const { epriv, epub } = await Gun.SEA.pair(); const proof: any = await Gun.SEA.work(passphrase, salt, null, options); return { epriv: await Gun.SEA.encrypt(epriv, proof), epub }; } static async authenticateUser(alias: string, password: string): Promise { return new Promise((resolve, reject) => { Gun.SEA.pair().then(async (pair: any) => { const user = gun.user(); user.auth(alias, password, (ack: any) => { if(ack.err) { reject(ack.err); } else { resolve(ack.sea); } }); }); }); } static async createUser(alias: string, password: string): Promise { return new Promise((resolve, reject) => { Gun.SEA.pair().then(async (pair: any) => { const user = gun.user(); user.create(alias, password, (ack: any) => { if(ack.err) { reject(ack.err); } else { resolve(ack.sea); } }); }); }); } }.//utils/Decorators.ts import { MultiContextObject } from 'src/core/MultiContextObject'; import { DecoratorOptions, Context } from '../Types'; import { BROWSER_CONTEXT, SERVER_CONTEXT, PEER_CONTEXT } from './Constants'; export function contextMethod(context: Context) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (this: MultiContextObject, ...args: any[]) { if (this.getCurrentContext() !== context) { throw new Error(`Method ${propertyKey} can only be called in ${context} context`); } return originalMethod.apply(this, args); }; return descriptor; }; } export function multiContext(...contexts: Context[]) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (this: MultiContextObject, ...args: any[]) { if (!contexts.includes(this.getCurrentContext())) { throw new Error(`Method ${propertyKey} can only be called in ${contexts.join(' or ')} context`); } return originalMethod.apply(this, args); }; return descriptor; }; } export function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling method ${propertyKey} with args:`, args); const result = originalMethod.apply(this, args); console.log(`Method ${propertyKey} returned:`, result); return result; }; return descriptor; } export function retry(maxAttempts: number = 3, delay: number = 1000) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = async function (...args: any[]) { let attempts = 0; while (attempts < maxAttempts) { try { return await originalMethod.apply(this, args); } catch (error) { attempts++; if (attempts >= maxAttempts) { throw error; } await new Promise(resolve => setTimeout(resolve, delay)); } } }; return descriptor; }; } export function memoize(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; const cache = new Map(); descriptor.value = function (...args: any[]) { const key = JSON.stringify(args); if (cache.has(key)) { return cache.get(key); } const result = originalMethod.apply(this, args); cache.set(key, result); return result; }; return descriptor; } export function debounce(delay: number = 300) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; let timeoutId: NodeJS.Timeout; descriptor.value = function (...args: any[]) { clearTimeout(timeoutId); timeoutId = setTimeout(() => originalMethod.apply(this, args), delay); }; return descriptor; }; } export function throttle(limit: number = 300) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; let lastRun = 0; descriptor.value = function (...args: any[]) { const now = Date.now(); if (now - lastRun >= limit) { lastRun = now; return originalMethod.apply(this, args); } }; return descriptor; }; }.//utils/EventEmitter.ts type Listener = (...args: any[]) => void; export class EventEmitter { private events: { [event: string]: Listener[] } = {}; on(event: string, listener: Listener): void { if (!this.events[event]) { this.events[event] = []; } this.events[event].push(listener); } off(event: string, listenerToRemove: Listener): void { if (!this.events[event]) { return; } this.events[event] = this.events[event].filter(listener => listener !== listenerToRemove); } emit(event: string, ...args: any[]): void { if (!this.events[event]) { return; } this.events[event].forEach(listener => { listener.apply(this, args); }); } once(event: string, listener: Listener): void { const onceWrapper = (...args: any[]) => { listener.apply(this, args); this.off(event, onceWrapper); }; this.on(event, onceWrapper); } removeAllListeners(event?: string): void { if (event) { delete this.events[event]; } else { this.events = {}; } } listenerCount(event: string): number { return this.events[event] ? this.events[event].length : 0; } listeners(event: string): Listener[] { return this.events[event] ? [...this.events[event]] : []; } eventNames(): string[] { return Object.keys(this.events); } executeInContext(event: string, context: any, ...args: any[]): any { if (!this.events[event]) { return; } const results: any[] = []; this.events[event].forEach(listener => { results.push(listener.apply(context, args)); }); return results; } }.//utils/ConfigManager.ts import { EventEmitter } from '../utils/EventEmitter'; import { Logger } from '../Logger'; import { STORAGE_PREFIX } from '../utils/Constants'; export class ConfigManager extends EventEmitter { private static instance: ConfigManager; private config: { [key: string]: any } = {}; private logger: Logger; private constructor() { super(); this.logger = Logger.getInstance(); this.loadConfig(); } static getInstance(): ConfigManager { if (!ConfigManager.instance) { ConfigManager.instance = new ConfigManager(); } return ConfigManager.instance; } private loadConfig(): void { const storedConfig = localStorage.getItem(`${STORAGE_PREFIX}config`); if (storedConfig) { try { this.config = JSON.parse(storedConfig); } catch (error) { this.logger.error('Failed to parse stored config', 'ConfigManager', error); } } } private saveConfig(): void { localStorage.setItem(`${STORAGE_PREFIX}config`, JSON.stringify(this.config)); } get(key: string, defaultValue?: any): any { return this.config.hasOwnProperty(key) ? this.config[key] : defaultValue; } set(key: string, value: any): void { this.config[key] = value; this.saveConfig(); this.emit('configChanged', { key, value }); } remove(key: string): void { if (this.config.hasOwnProperty(key)) { delete this.config[key]; this.saveConfig(); this.emit('configChanged', { key, value: undefined }); } } clear(): void { this.config = {}; this.saveConfig(); this.emit('configCleared'); } getAll(): { [key: string]: any } { return { ...this.config }; } setMultiple(configs: { [key: string]: any }): void { Object.assign(this.config, configs); this.saveConfig(); Object.keys(configs).forEach(key => { this.emit('configChanged', { key, value: configs[key] }); }); } has(key: string): boolean { return this.config.hasOwnProperty(key); } subscribe(callback: (config: { [key: string]: any }) => void): () => void { const listener = () => callback(this.getAll()); this.on('configChanged', listener); return () => this.off('configChanged', listener); } validate(schema: { [key: string]: any }): boolean { for (const [key, value] of Object.entries(schema)) { if (!this.has(key) || typeof this.get(key) !== value) { return false; } } return true; } }.//utils/Constants.ts export const BROWSER_CONTEXT = 'browser'; export const SERVER_CONTEXT = 'server'; export const PEER_CONTEXT = 'peer'; export const DEFAULT_PEER_URL = 'https://gun-manhattan.herokuapp.com/gun'; export const MAX_RETRY_ATTEMPTS = 3; export const RETRY_DELAY_MS = 1000; export const DEFAULT_DEBOUNCE_TIME = 300; export const DEFAULT_THROTTLE_TIME = 300; export const MAX_BATCH_SIZE = 100; export const STORAGE_PREFIX = 'decentralized_app_'; export const CRYPTO_ALGORITHM = 'AES-GCM'; export const CRYPTO_KEY_LENGTH = 256; export const DEFAULT_LOG_LEVEL = 'info'; export const EVENT_STATE_CHANGE = 'state_change'; export const EVENT_PEER_CONNECTED = 'peer_connected'; export const EVENT_PEER_DISCONNECTED = 'peer_disconnected'; export const EVENT_SYNC_COMPLETE = 'sync_complete'; export const EVENT_AUTH_STATE_CHANGE = 'auth_state_change'; export const DEFAULT_COMPONENT_PREFIX = 'da'; // for DecentralizedApp export const API_VERSION = '1.0.0'; export const MAX_MESSAGE_SIZE = 1024 * 1024; // 1MB export const RESERVED_KEYS = ['_', '#', '@', '$', '=', '+']; export const DEFAULT_TIMEOUT = 30000; // 30 seconds export const PLUGIN_NAMESPACE = 'decentralized_app_plugin_'; export const DEV_TOOLS_KEY = '__DECENTRALIZED_APP_DEVTOOLS__';.//utils/VirtualDOM.ts export type VNodeType = string | Function; export interface VNodeProps { [key: string]: any; } export interface VNode { type: VNodeType; props: VNodeProps; component?: Function; children: (VNode | string)[]; key?: string | number; tag?: string; } export type PatchType = 'CREATE' | 'UPDATE' | 'REPLACE' | 'REMOVE' | 'REORDER'; export interface Patch { type: PatchType; node?: VNode; index?: number; props?: VNodeProps; from?: number; to?: number; } export class VirtualDOM { private rootNode: VNode | null = null; createElement(type: VNodeType, props: VNodeProps = {}, ...children: (VNode | string)[]): VNode { return { type, props, children, key: props.key }; } render(node: VNode | string): HTMLElement | Text { if (typeof node === 'string') { return document.createTextNode(node); } const element = typeof node.type === 'function' ? (node.type as Function)(node.props) : document.createElement(node.type as string); this.updateProps(element, {}, node.props); node.children.forEach(child => { element.appendChild(this.render(child)); }); return element; } clear(): void { this.rootNode = null; } private updateProps(element: HTMLElement, oldProps: VNodeProps, newProps: VNodeProps): void { const mergedProps = { ...oldProps, ...newProps }; Object.keys(mergedProps).forEach(name => { const oldValue = oldProps[name]; const newValue = newProps[name]; if (name.startsWith('on') && typeof newValue === 'function') { const eventName = name.toLowerCase().substr(2); if (oldValue) element.removeEventListener(eventName, oldValue); element.addEventListener(eventName, newValue); } else if (name === 'style' && typeof newValue === 'object') { Object.assign(element.style, newValue); } else if (name === 'className') { element.className = newValue; } else if (newValue == null || newValue === false) { element.removeAttribute(name); } else { element.setAttribute(name, newValue.toString()); } }); } diff(oldNode: VNode | null, newNode: VNode): Patch[] { const patches: Patch[] = []; if (oldNode === null) { patches.push({ type: 'CREATE', node: newNode }); } else if (typeof oldNode === 'string' || typeof newNode === 'string') { if (oldNode !== newNode) { patches.push({ type: 'REPLACE', node: newNode }); } } else if (oldNode.type !== newNode.type) { patches.push({ type: 'REPLACE', node: newNode }); } else { const propPatches = this.diffProps(oldNode.props, newNode.props); if (Object.keys(propPatches).length > 0) { patches.push({ type: 'UPDATE', props: propPatches }); } const childPatches = this.diffChildren(oldNode.children, newNode.children); patches.push(...childPatches); } return patches; } getRootNode(): VNode | null { return this.rootNode; } private diffProps(oldProps: VNodeProps, newProps: VNodeProps): VNodeProps { const patches: VNodeProps = {}; // Find changed or new props Object.entries(newProps).forEach(([key, value]) => { if (oldProps[key] !== value) { patches[key] = value; } }); // Find removed props Object.keys(oldProps).forEach(key => { if (!(key in newProps)) { patches[key] = undefined; } }); return patches; } private diffChildren(oldChildren: (VNode | string)[], newChildren: (VNode | string)[]): Patch[] { const patches: Patch[] = []; const oldKeyedChildren = new Map(); const newKeyedChildren = new Map(); // Separate keyed and non-keyed children oldChildren.forEach((child, index) => { if (typeof child !== 'string' && child.key != null) { oldKeyedChildren.set(child.key, child); } }); newChildren.forEach((child, index) => { if (typeof child !== 'string' && child.key != null) { newKeyedChildren.set(child.key, child); } }); // Handle keyed children newKeyedChildren.forEach((newChild, key) => { const oldChild = oldKeyedChildren.get(key); if (oldChild) { patches.push(...this.diff(oldChild, newChild).map(patch => ({ ...patch, key }))); oldKeyedChildren.delete(key); } else { patches.push({ type: 'CREATE', node: newChild, key } as any); } }); oldKeyedChildren.forEach((oldChild, key: any) => { patches.push({ type: 'REMOVE', key } as any); }); // Handle non-keyed children const oldNonKeyedChildren = oldChildren.filter(child => typeof child === 'string' || child.key == null); const newNonKeyedChildren = newChildren.filter(child => typeof child === 'string' || child.key == null); for (let i = 0; i < Math.max(oldNonKeyedChildren.length, newNonKeyedChildren.length); i++) { if (i >= oldNonKeyedChildren.length) { patches.push({ type: 'CREATE', node: newNonKeyedChildren[i] as any, index: i }); } else if (i >= newNonKeyedChildren.length) { patches.push({ type: 'REMOVE', index: i }); } else { patches.push(...this.diff(oldNonKeyedChildren[i] as VNode, newNonKeyedChildren[i] as VNode).map(patch => ({ ...patch, index: i }))); } } return patches; } applyPatches(rootElement: HTMLElement, patches: Patch[]): void { patches.forEach((patch: any) => { switch (patch.type) { case 'CREATE': if (patch.node) { const newElement = this.render(patch.node); if (patch.index !== undefined) { rootElement.insertBefore(newElement, rootElement.childNodes[patch.index] || null); } else if (patch.key !== undefined) { rootElement.appendChild(newElement); } } break; case 'UPDATE': if (patch.props && (patch.index !== undefined || patch.key !== undefined)) { const element = patch.key !== undefined ? Array.from(rootElement.children).find(child => child.getAttribute('key') === patch.key?.toString()) : rootElement.childNodes[patch.index!]; if (element && element instanceof HTMLElement) { this.updateProps(element, {}, patch.props); } } break; case 'REPLACE': if (patch.node && (patch.index !== undefined || patch.key !== undefined)) { const newElement = this.render(patch.node); const oldElement = patch.key !== undefined ? Array.from(rootElement.children).find(child => child.getAttribute('key') === patch.key?.toString()) : rootElement.childNodes[patch.index!]; if (oldElement) { rootElement.replaceChild(newElement, oldElement); } } break; case 'REMOVE': if (patch.index !== undefined) { rootElement.removeChild(rootElement.childNodes[patch.index]); } else if (patch.key !== undefined) { const element = Array.from(rootElement.children).find(child => child.getAttribute('key') === patch.key?.toString()); if (element) rootElement.removeChild(element); } break; case 'REORDER': if (patch.from !== undefined && patch.to !== undefined) { const element = rootElement.childNodes[patch.from]; rootElement.insertBefore(element, rootElement.childNodes[patch.to]); } break; } }); } updateDOM(rootElement: HTMLElement, newVNode: VNode): void { const patches = this.diff(this.rootNode, newVNode); this.applyPatches(rootElement, patches); this.rootNode = newVNode; } }.//env/SandboxedEnvironment.ts import { NodeVM, VMScript } from 'vm2'; import { Component } from '../core/Component'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; export class SandboxedEnvironment { private vm: NodeVM; private logger: Logger; private errorHandler: ErrorHandler; constructor() { this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); this.vm = new NodeVM({ console: 'redirect', sandbox: { Component, // Add any other necessary classes or functions here }, require: { external: true, builtin: ['assert', 'buffer', 'crypto', 'events', 'stream', 'util'], root: './', mock: { fs: { readFileSync: () => 'Not allowed in sandbox', }, }, }, }); this.setupConsoleRedirect(); } private setupConsoleRedirect(): void { this.vm.on('console.log', (...args: any[]) => { this.logger.info('Sandbox console.log', 'SandboxedEnvironment', ...args); }); this.vm.on('console.error', (...args: any[]) => { this.logger.error('Sandbox console.error', 'SandboxedEnvironment', ...args); }); this.vm.on('console.warn', ((...args: any[]) => { this.logger.warn('Sandbox console.warn', 'SandboxedEnvironment', ...args); })); } evaluate(code: string): any { try { const script = new VMScript(code); return this.vm.run(script); } catch (error) { this.errorHandler.handleError(error as Error, 'SandboxedEnvironment.evaluate'); throw error; } } runFunction(func: Function, ...args: any[]): any { try { const argsString = JSON.stringify(args); const code = ` (function() { const args = ${argsString}; return (${func.toString()})(...args); })() `; return this.vm.run(code, 'vm.js'); } catch (error) { this.errorHandler.handleError(error as Error, 'SandboxedEnvironment.runFunction'); throw error; } } setGlobal(key: string, value: any): void { this.vm.setGlobal(key, value); } getGlobal(key: string): any { return this.vm.getGlobal(key); } }.//Types.ts export type Context = 'browser' | 'server' | 'peer'; import { Component } from './core/Component'; import { DistributedState } from './data/DistributedState'; export interface NetworkGraph { nodes: { id: string; data: PeerInfo }[]; edges: { source: string; target: string }[]; } export interface TopologyAnalysis { totalPeers: number; totalConnections: number; averageConnections: number; centralPeers: string[]; } export interface ErrorInfo { code: string; message: string; stack?: string | undefined; context?: string | undefined; } // Add these to your Types.ts file if not already present export type ErrorCategory = 'TYPE_ERROR' | 'REFERENCE_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR'; export type ErrorHandlingStrategy = (error: Error, errorInfo: ErrorInfo) => void; export interface ErrorReportingConfig { endpoint: string; } export interface ContextSwitch { from: Context; to: Context; } export interface ContextState { active: boolean; data: Record; context: Context; } export interface ContextTransition { from: Context; to: Context; } export interface ComponentMetadata { id: string; // Unique identifier for the component name: string; version: string; author: string; description: string; tags: string[]; dependencies: { [key: string]: string }; acl: AccessControlList; signature: string; // Digital signature of the component } // Types.ts export type RouteHandler = (context: RouteContext) => Promise | any; export interface PeerManager { sendToPeer(peerId: string, message: any): void; broadcast(message: any): void; } export interface RouteContext { path: string; params: RouteParams; data?: any; context: Context; peerManager: PeerManager; } export interface Middleware { (context: any): Promise; } export interface RouteOptions { auth?: boolean; middleware?: Middleware[]; } export interface RouteConfig { handler: RouteHandler; options: RouteOptions; } export interface RouteMatch { routeConfig: Map; params: RouteParams; } export interface RouteParams { [key: string]: string; } export interface AccessControlList { type: 'public' | 'private' | 'shared'; allowedUsers?: string[]; // Public keys of allowed users } export interface ComponentPackage { metadata: any; code: string; state?: any; schema?: SchemaDefinition; } export interface ComponentState { [key: string]: any; } export interface ComponentProps { [key: string]: any; } export interface PeerMessage { type: string; data: any; } export interface EncryptedComponentPackage { metadata: string; // Encrypted JSON string code: string; // Encrypted code state?: string; // Encrypted initial state encryptedKey: { [userPubKey: string]: string }; // Encrypted symmetric key for each allowed user } export interface ComponentInstance { component: Component; state: DistributedState; } export interface ComponentUpdateEvent { id: string; version: string; changes: string[]; // List of changes in the new version } export interface GunDataProviderOptions { peers?: string[]; localStorage?: boolean; radisk?: boolean; multicast?: boolean; } export interface MultiContextObjectOptions { id: string; type: string; contexts: Context[]; } export interface DecoratorOptions { context?: Context; name?: string; } export interface AuthCredentials { username: string; password: string; } export interface User { alias: string; pub: string; } export interface EncryptedData { ct: string; // ciphertext iv: string; // initialization vector s: string; // salt } export type LogLevel = 'debug' | 'info' | 'warn' | 'error'; export interface LogEntry { level: LogLevel; message: string; timestamp: number; context?: string; data?: any; } export interface PeerInfo { id: string; url: string; lastSeen: number; } export enum SyncPriority { Low = 'low', Normal = 'normal', High = 'high' } export interface SyncStatus { lastSyncTime: number; pendingChanges: number; priority: SyncPriority; isPaused: boolean; } export interface PluginMetadata { name: string; version: string; description: string; author: string; } export interface Plugin { metadata: PluginMetadata; initialize: () => Promise; destroy: () => Promise; } export interface SchemaDefinition { [key: string]: 'string' | 'number' | 'boolean' | 'object' | 'array' | SchemaDefinition; } export interface QueryOptions { limit?: number; skip?: number; sort?: {[key: string]: 'asc' | 'desc'}; } export interface NetworkStats { peers: number; inbound: number; outbound: number; latency: number; } export type Unsubscribe = () => void; export interface ComponentConfig { name: string; template: string; styles?: string; } export interface RouteDefinition { path: string; component: any; children?: RouteDefinition[]; } export interface ErrorInfo { code: string; message: string; stack?: string; context?: string | undefined; }.//Logger.ts import { LogLevel, LogEntry } from './Types'; import { DEFAULT_LOG_LEVEL } from './utils/Constants'; export class Logger { private static instance: Logger; private logLevel: LogLevel; private logs: LogEntry[] = []; private constructor() { this.logLevel = DEFAULT_LOG_LEVEL; } static getInstance(): Logger { if (!Logger.instance) { Logger.instance = new Logger(); } return Logger.instance; } setLogLevel(level: LogLevel): void { this.logLevel = level; } private shouldLog(level: LogLevel): boolean { const levels: LogLevel[] = ['debug', 'info', 'warn', 'error']; return levels.indexOf(level) >= levels.indexOf(this.logLevel); } private log(level: LogLevel, message: string, context?: string, data?: any): void { if (this.shouldLog(level)) { const logEntry: LogEntry = { level, message, timestamp: Date.now(), context, data }; this.logs.push(logEntry); console[level]( `[${new Date(logEntry.timestamp).toISOString()}] [${level.toUpperCase()}]${context ? ` [${context}]` : ''}: ${message}`, data ? data : '' ); } } debug(message: string, context?: string, data?: any): void { this.log('debug', message, context, data); } info(message: string, context?: string, data?: any): void { this.log('info', message, context, data); } warn(message: string, context?: string, data?: any): void { this.log('warn', message, context, data); } error(message: string, context?: string, data?: any): void { this.log('error', message, context, data); } getLogs(): LogEntry[] { return this.logs; } clearLogs(): void { this.logs = []; } exportLogs(): string { return JSON.stringify(this.logs); } importLogs(logsJson: string): void { try { const importedLogs = JSON.parse(logsJson); if (Array.isArray(importedLogs)) { this.logs = importedLogs; } else { throw new Error('Invalid log format'); } } catch (error) { console.error('Failed to import logs:', error); } } }.//dev/Performance.ts // Performance.ts import { EventEmitter } from '../utils/EventEmitter'; import { performance as nodePerformance } from 'perf_hooks'; import { Logger } from '../Logger'; interface TimingData { start: number; end: number; duration: number; } interface MetricData { count: number; total: number; min: number; max: number; average: number; } export class Performance extends EventEmitter { private timings: Map = new Map(); private metrics: Map = new Map(); private logger: Logger; constructor() { super(); this.logger = Logger.getInstance(); } private getTimestamp(): number { if (typeof window !== 'undefined' && window.performance && window.performance.now) { return window.performance.now(); } return nodePerformance.now(); } startTiming(label: string): void { if (!this.timings.has(label)) { this.timings.set(label, []); } this.timings.get(label)!.push({ start: this.getTimestamp(), end: 0, duration: 0 }); this.logger.debug(`Timing started: ${label}`, 'Performance'); } endTiming(label: string): number { const timings = this.timings.get(label); if (!timings || timings.length === 0) { this.logger.warn(`No timing started for: ${label}`, 'Performance'); return 0; } const timing = timings[timings.length - 1]; timing.end = this.getTimestamp(); timing.duration = timing.end - timing.start; this.logger.debug(`Timing ended: ${label}`, 'Performance', { duration: timing.duration }); this.emit('timingComplete', { label, duration: timing.duration }); return timing.duration; } recordMetric(name: string, value: number): void { if (!this.metrics.has(name)) { this.metrics.set(name, { count: 0, total: 0, min: Infinity, max: -Infinity, average: 0 }); } const metric = this.metrics.get(name)!; metric.count++; metric.total += value; metric.min = Math.min(metric.min, value); metric.max = Math.max(metric.max, value); metric.average = metric.total / metric.count; this.logger.debug(`Metric recorded: ${name}`, 'Performance', { value }); this.emit('metricRecorded', { name, value }); } trackMemoryUsage(interval: number = 60000): () => void { const trackMemory = () => { if (typeof process !== 'undefined' && process.memoryUsage) { const usage = process.memoryUsage(); this.recordMetric('memory.rss', usage.rss); this.recordMetric('memory.heapTotal', usage.heapTotal); this.recordMetric('memory.heapUsed', usage.heapUsed); this.recordMetric('memory.external', usage.external); } else if (typeof window !== 'undefined' && (window.performance as any).memory) { const memory = (window.performance as any).memory; this.recordMetric('memory.jsHeapSizeLimit', memory.jsHeapSizeLimit); this.recordMetric('memory.totalJSHeapSize', memory.totalJSHeapSize); this.recordMetric('memory.usedJSHeapSize', memory.usedJSHeapSize); } }; const timer = setInterval(trackMemory, interval); return () => clearInterval(timer); } getTimings(label: string): TimingData[] { return this.timings.get(label) || []; } getMetric(name: string): MetricData | undefined { return this.metrics.get(name); } getAllMetrics(): Map { return new Map(this.metrics); } clearTimings(): void { this.timings.clear(); this.logger.info('All timings cleared', 'Performance'); } clearMetrics(): void { this.metrics.clear(); this.logger.info('All metrics cleared', 'Performance'); } generateReport(): string { let report = "Performance Report\n==================\n\n"; report += "Timings:\n"; for (const [label, timings] of this.timings.entries()) { const averageDuration = timings.reduce((sum, t) => sum + t.duration, 0) / timings.length; report += `${label}: ${averageDuration.toFixed(2)}ms (${timings.length} samples)\n`; } report += "\nMetrics:\n"; for (const [name, metric] of this.metrics.entries()) { report += `${name}: avg=${metric.average.toFixed(2)}, min=${metric.min}, max=${metric.max}, count=${metric.count}\n`; } return report; } async measureAsync(label: string, fn: () => Promise): Promise { this.startTiming(label); try { const result = await fn(); return result; } finally { this.endTiming(label); } } measure(label: string, fn: () => T): T { this.startTiming(label); try { return fn(); } finally { this.endTiming(label); } } startProfiling(label: string): void { if (typeof console !== 'undefined' && console.profile) { console.profile(label); } } endProfiling(label: string): void { if (typeof console !== 'undefined' && console.profileEnd) { console.profileEnd(label); } } measureOperationTime(label: string, fn: () => T): T { this.startProfiling(label); try { return fn(); } finally { this.endProfiling(label); } } } // Singleton instance export const performance = new Performance(); // Decorator for measuring method performance export function Measure(label?: string) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { const measureLabel = label || `${target.constructor.name}.${propertyKey}`; return performance.measure(measureLabel, () => originalMethod.apply(this, args)); }; return descriptor; }; } // Decorator for measuring async method performance export function MeasureAsync(label?: string) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { const measureLabel = label || `${target.constructor.name}.${propertyKey}`; return performance.measureAsync(measureLabel, () => originalMethod.apply(this, args)); }; return descriptor; }; }.//dev/FaultInjector.ts // FaultInjector.ts import { EventEmitter } from '../utils/EventEmitter'; import { Logger } from '../Logger'; type FaultType = 'error' | 'delay' | 'networkError' | 'timeout' | 'customError'; interface FaultConfig { probability: number; type: FaultType; details?: any; } interface InjectionPoint { name: string; config: FaultConfig; } export class FaultInjector extends EventEmitter { private injectionPoints: Map = new Map(); private logger: Logger; constructor() { super(); this.logger = Logger.getInstance(); } addFault(name: string, config: FaultConfig): void { this.injectionPoints.set(name, config); this.logger.info(`Fault added: ${name}`, 'FaultInjector', { config }); } removeFault(name: string): void { this.injectionPoints.delete(name); this.logger.info(`Fault removed: ${name}`, 'FaultInjector'); } async injectFault(name: string, options?: any): Promise { // TODO implement options const config = this.injectionPoints.get(name); if (!config) { this.logger.warn(`No fault configured for: ${name}`, 'FaultInjector'); return; } if (Math.random() < config.probability) { this.logger.info(`Injecting fault: ${name}`, 'FaultInjector', { type: config.type }); this.emit('faultInjected', { name, type: config.type }); switch (config.type) { case 'error': throw new Error(`Injected error for ${name}`); case 'delay': await this.injectDelay(config.details || 1000); break; case 'networkError': throw new Error(`Simulated network error for ${name}`); case 'timeout': await this.injectTimeout(config.details || 5000); break; case 'customError': if (typeof config.details === 'function') { config.details(); } else { throw new Error(`Custom error for ${name}: ${config.details}`); } break; } } } private async injectDelay(ms: number): Promise { await new Promise(resolve => setTimeout(resolve, ms)); } private async injectTimeout(ms: number): Promise { await new Promise((_, reject) => setTimeout(() => reject(new Error('Operation timed out')), ms)); } getAllFaults(): InjectionPoint[] { return Array.from(this.injectionPoints.entries()).map(([name, config]) => ({ name, config })); } clearAllFaults(): void { this.injectionPoints.clear(); this.logger.info('All faults cleared', 'FaultInjector'); } async injectRandomFault(): Promise { const faults = this.getAllFaults(); if (faults.length === 0) { this.logger.warn('No faults configured for random injection', 'FaultInjector'); return; } const randomFault = faults[Math.floor(Math.random() * faults.length)]; await this.injectFault(randomFault.name); } setGlobalFaultProbability(probability: number): void { for (const [name, config] of this.injectionPoints) { this.injectionPoints.set(name, { ...config, probability }); } this.logger.info(`Global fault probability set to ${probability}`, 'FaultInjector'); } } // Singleton instance export const faultInjector = new FaultInjector(); // Decorator for injecting faults into methods export function InjectFault(faultName: string) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = async function (...args: any[]) { await faultInjector.injectFault(faultName); return originalMethod.apply(this, args); }; return descriptor; }; }.//dev/DevTools.ts import { Logger } from '../Logger'; import { NetworkMonitor } from '../net/NetworkMonitor'; import { PeerManager } from '../net/PeerManager'; import { SyncManager } from '../net/SyncManager'; import { DistributedState } from '../data/DistributedState'; import { EventEmitter } from '../utils/EventEmitter'; import { PluginSystem } from '../core/PluginSystem'; import { GunDataProvider } from '../data/GunDataProvider'; import { AuthManager } from '../auth/AuthManager'; import { ContextRouter } from '../core/ContextRouter'; import { Performance } from './Performance'; import { FaultInjector } from './FaultInjector'; export class DevTools extends EventEmitter { private logger: Logger; private networkMonitor: NetworkMonitor; private peerManager: PeerManager; private syncManager: SyncManager; private pluginSystem: PluginSystem; private gunDataProvider: GunDataProvider; private authManager: AuthManager; private contextRouter: ContextRouter; private performance: Performance; private faultInjector: FaultInjector; private isRecording: boolean = false; private recordedEvents: any[] = []; constructor( logger: Logger, networkMonitor: NetworkMonitor, peerManager: PeerManager, syncManager: SyncManager, pluginSystem: PluginSystem, gunDataProvider: GunDataProvider, authManager: AuthManager, contextRouter: ContextRouter ) { super(); this.logger = logger; this.networkMonitor = networkMonitor; this.peerManager = peerManager; this.syncManager = syncManager; this.pluginSystem = pluginSystem; this.gunDataProvider = gunDataProvider; this.authManager = authManager; this.contextRouter = contextRouter; this.performance = new Performance(); this.faultInjector = new FaultInjector(); this.setupListeners(); } private setupListeners(): void { this.peerManager.on('peerEvent', this.recordEvent.bind(this, 'peer')); this.syncManager.on('syncEvent', this.recordEvent.bind(this, 'sync')); this.pluginSystem.on('pluginEvent', this.recordEvent.bind(this, 'plugin')); this.gunDataProvider.on('dataEvent', this.recordEvent.bind(this, 'data')); this.authManager.on('authEvent', this.recordEvent.bind(this, 'auth')); this.contextRouter.on('routeEvent', this.recordEvent.bind(this, 'route')); } private recordEvent(category: string, event: any): void { if (this.isRecording) { this.recordedEvents.push({ timestamp: Date.now(), category, event }); } this.emit('devToolsUpdate', { type: `${category}Event`, event }); } // Logging and Monitoring getLogs(filter?: { level?: string; context?: string }): any[] { return this.logger.getLogs().filter(log => { if (filter && filter.level && log.level !== filter.level) return false; if (filter && filter.context && log.context !== filter.context) return false; return true; } ); } getNetworkStats(): any { return this.networkMonitor.getStats(); } getPeers(): any[] { return this.peerManager.getPeers(); } getSyncStatus(): any { return this.syncManager.getSyncedPaths().map(path => ({ path, status: this.syncManager.getSyncStatus(path) })); } // State Inspection inspectDistributedState(statePath: string): DistributedState | null { return this.syncManager.getDistributedState(statePath); } monitorStateChanges(statePath: string, callback: (newState: any) => void): () => void { const state = this.inspectDistributedState(statePath); if (state) { return state.subscribe(callback); } return () => {}; } // Network Analysis generateNetworkGraph(): any { return this.peerManager.generateNetworkGraph(); } analyzeNetworkTopology(): any { return this.peerManager.analyzeTopology(); } measurePeerLatency(peerId: string): Promise { return Promise.resolve(this.peerManager.measureLatency(peerId)); } // Performance Profiling startPerformanceProfile(label: string): void { this.performance.startProfiling(label); this.emit('performanceProfileStarted'); } stopPerformanceProfile(label: string): any { const profileData = this.performance.endProfiling(label); this.emit('performanceProfileStopped', profileData); return profileData; } // Fault Injection injectFault(faultType: string, options: any): void { this.faultInjector.injectFault(faultType, options); this.emit('faultInjected', { faultType, options }); } simulatePeerDisconnection(peerId: string): void { this.peerManager.disconnectFromPeer(peerId); } simulateNetworkLatency(latency: number): void { this.networkMonitor.simulateLatency(latency); } // Event Recording startRecording(): void { this.isRecording = true; this.recordedEvents = []; this.emit('recordingStarted'); } stopRecording(): any[] { this.isRecording = false; const events = [...this.recordedEvents]; this.recordedEvents = []; this.emit('recordingStopped', events); return events; } replayEvents(events: any[]): void { events.forEach(event => { this.emit('replayEvent', event); // Implement actual event replay logic here }); } // Plugin Inspection getLoadedPlugins(): any[] { return this.pluginSystem.getAllPlugins(); } inspectPlugin(pluginName: string): any { return this.pluginSystem.getPlugin(pluginName); } // Data Inspection inspectGunData(path: string): Promise { return this.gunDataProvider.get(path); } // Auth Inspection getCurrentUser(): any { return this.authManager.getCurrentUser(); } // Route Inspection getRoutes(): any { return this.contextRouter.getRoutes(); } // Utility Methods clearLogs(): void { this.logger.clearLogs(); } exportDevToolsState(): any { return { logs: this.getLogs(), networkStats: this.getNetworkStats(), peers: this.getPeers(), syncStatus: this.getSyncStatus(), plugins: this.getLoadedPlugins(), currentUser: this.getCurrentUser(), routes: this.getRoutes() }; } importDevToolsState(state: any): void { // Implement logic to restore DevTools state this.emit('devToolsStateImported', state); } // Remote Debugging enableRemoteDebugging(port: number): void { // Implement WebSocket server for remote debugging this.emit('remoteDebuggingEnabled', port); } sendRemoteCommand(command: string, params: any): Promise { // Implement remote command execution return Promise.resolve(); } }.//index.ts // Core export { Component } from './core/Component'; export { DecentralizedApp } from './core/DecentralizedApp'; export { MultiContextObject } from './core/MultiContextObject'; export { PluginSystem } from './core/PluginSystem'; export { ContextRouter } from './core/ContextRouter'; export { ComponentRegistry } from './core/ComponentRegistry'; // UI export { ReactiveUI } from './ui/ReactiveUI'; // Data export { DistributedState } from './data/DistributedState'; export { GunDataProvider } from './data/GunDataProvider'; export { GunNode } from './data/GunNode'; export { GunQuery } from './data/GunQuery'; export { IndexedDBAdapter } from './data/IndexedDBAdapter'; export { TypedSchema } from './data/TypedSchema'; // Auth export { AuthManager } from './auth/AuthManager'; export { CryptoUtils } from './auth/CryptoUtils'; export { SEA } from './auth/SEA'; // Net export { NetworkMonitor } from './net/NetworkMonitor'; export { PeerManager } from './net/PeerManager'; export { SyncManager } from './net/SyncManager'; export { WebRTCAdapter } from './net/WebRTCAdapter'; // Utils export { EventEmitter } from './utils/EventEmitter'; export { ConfigManager } from './utils/ConfigManager'; export * from './utils/Decorators'; export * from './utils/Constants'; // Dev export { DevTools } from './dev/DevTools'; // Types export * from './Types'; // Contexts export { BROWSER_CONTEXT, isBrowserContext, executeInBrowserContext } from './ui/BrowserContext'; export { SERVER_CONTEXT, isServerContext, executeInServerContext } from './net/ServerContext'; export { PEER_CONTEXT, isPeerContext, executeInPeerContext } from './net/PeerContext'; // Other export { Logger } from './Logger'; export { ErrorHandler } from './ui/ErrorHandler';.//index.d.ts // Type definitions for @nomyx/decentranet // Project: @nomyx/decentranet // Definitions by: Nomyx declare module '@nomyx/decentranet' { export type Context = 'browser' | 'server' | 'peer'; export interface ComponentMetadata { id: string; // Unique identifier for the component name: string; version: string; author: string; description: string; tags: string[]; dependencies: { [key: string]: string }; acl: AccessControlList; signature: string; // Digital signature of the component } export interface AccessControlList { type: 'public' | 'private' | 'shared'; allowedUsers?: string[]; // Public keys of allowed users } export interface ComponentPackage { metadata: ComponentMetadata; code: string; state?: any; // Initial state of the component } export interface EncryptedComponentPackage { metadata: string; // Encrypted JSON string code: string; // Encrypted code state?: string; // Encrypted initial state encryptedKey: { [userPubKey: string]: string }; // Encrypted symmetric key for each allowed user } export interface ComponentInstance { component: Component; state: DistributedState; } export interface ComponentUpdateEvent { id: string; version: string; changes: string[]; // List of changes in the new version } export interface GunDataProviderOptions { peers?: string[]; localStorage?: boolean; radisk?: boolean; multicast?: boolean; } export interface MultiContextObjectOptions { id: string; type: string; contexts: Context[]; } export interface DecoratorOptions { context?: Context; name?: string; } export interface AuthCredentials { username: string; password: string; } export interface User { alias: string; pub: string; } export interface EncryptedData { ct: string; // ciphertext iv: string; // initialization vector s: string; // salt } export type LogLevel = 'debug' | 'info' | 'warn' | 'error'; export interface LogEntry { level: LogLevel; message: string; timestamp: number; context?: string; data?: any; } export interface PeerInfo { id: string; url: string; lastSeen: number; } export interface SyncStatus { lastSyncTime: number; pendingChanges: number; } export interface PluginMetadata { name: string; version: string; description: string; author: string; } export interface Plugin { metadata: PluginMetadata; initialize: () => Promise; destroy: () => Promise; } export interface SchemaDefinition { [key: string]: 'string' | 'number' | 'boolean' | 'object' | 'array' | SchemaDefinition; } export interface QueryOptions { limit?: number; skip?: number; sort?: { [key: string]: 'asc' | 'desc' }; } export interface NetworkStats { peers: number; inbound: number; outbound: number; latency: number; } export type Unsubscribe = () => void; export interface ComponentConfig { name: string; template: string; styles?: string; } export interface RouteDefinition { path: string; component: any; children?: RouteDefinition[]; } export interface ErrorInfo { code: string; message: string; stack?: string; context?: any; } export interface ComponentState {} export interface ComponentProps {} export interface PeerMessage {} export class Component { constructor( contexts: Context[], initialState: S, props: P, peerManager: PeerManager, syncManager: SyncManager ); render(): string; publish(registry: ComponentRegistry, currentUserPair: any): Promise; onMount(): void; onUnmount(): void; onUpdate(prevProps: any, prevState: any): void; setState(newState: Partial, broadcast?: boolean): void; update(): void; mount(element: HTMLElement): void; unmount(): void; updateProps(newProps: Partial

): void; } export class ComponentRegistry { constructor(gun: GunDataProvider); getComponent(address: string, userPair: any): Promise; searchComponents(query: string, limit?: number): Promise; publishComponent(component: ComponentPackage, currentUserPair: any): Promise; updateComponentAccess(componentId: string, newAcl: AccessControlList, currentUserPair: any): Promise; } export class DecentralizedApp { constructor(gun: GunDataProvider); initialize(): Promise; start(): Promise; stop(): Promise; getAuthManager(): AuthManager; getSyncManager(): SyncManager; getPeerManager(): PeerManager; getPluginSystem(): PluginSystem; getContextRouter(): ContextRouter; getDevTools(): DevTools; createDistributedState(initialState: T, path: string): DistributedState; registerComponent(name: string, component: typeof Component): void; getComponent(name: string): typeof Component | undefined; route(path: string, data?: any): Promise; broadcastRoute(path: string, data?: any): Promise; executeInPeer(peerId: string, func: Function): Promise; onPeerMessage(callback: (peerId: string, message: any) => void): void; broadcastToPeers(message: any): void; publishComponent(component: Component): Promise; loadComponent(address: string): Promise; searchComponents(query: string, limit?: number): Promise; getLoadedComponent(address: string): ComponentInstance | undefined; unloadComponent(address: string): void; } export class AuthManager { constructor(gunDataProvider: GunDataProvider); register(credentials: AuthCredentials): Promise; login(credentials: AuthCredentials): Promise; logout(): void; getCurrentUser(): User | null; isAuthenticated(): boolean; changePassword(currentPassword: string, newPassword: string): Promise; resetPassword(username: string, resetToken: string, newPassword: string): Promise; requestPasswordReset(username: string): Promise; } export class CryptoUtils { static encrypt(data: string, key?: string): Promise; static decrypt(encryptedData: EncryptedData): Promise; static hash(data: string): Promise; static generateRandomId(length?: number): string; } export class DevTools { constructor( logger: Logger, networkMonitor: NetworkMonitor, peerManager: PeerManager, syncManager: SyncManager, pluginSystem: PluginSystem, gunDataProvider: GunDataProvider, authManager: AuthManager, contextRouter: ContextRouter ); getLogs(filter?: { level?: string; context?: string }): any[]; getNetworkStats(): any; getPeers(): any[]; getSyncStatus(): any; inspectDistributedState(statePath: string): DistributedState | null; monitorStateChanges(statePath: string, callback: (newState: any) => void): () => void; generateNetworkGraph(): any; analyzeNetworkTopology(): any; measurePeerLatency(peerId: string): Promise; startPerformanceProfile(): void; stopPerformanceProfile(): any; measureOperationTime(operation: () => Promise): Promise<{ result: any; executionTime: number }>; injectFault(faultType: string, options: any): void; simulatePeerDisconnection(peerId: string): void; simulateNetworkLatency(latency: number): void; startRecording(): void; stopRecording(): any[]; replayEvents(events: any[]): void; getLoadedPlugins(): any[]; inspectPlugin(pluginName: string): any; inspectGunData(path: string): Promise; getCurrentUser(): any; getRoutes(): any; clearLogs(): void; exportDevToolsState(): any; importDevToolsState(state: any): void; enableRemoteDebugging(port: number): void; sendRemoteCommand(command: string, params: any): Promise; } export class DistributedState { constructor(gunDataProvider: GunDataProvider, path: string, schema: SchemaDefinition); get(): Promise; set(data: Partial): Promise; update(updater: (currentState: T) => Partial): Promise; subscribe(listener: (state: T, oldState: T) => void): () => void; getSchema(): SchemaDefinition; validate(data: any): boolean; reset(): Promise; transaction(transactionFn: (currentState: T) => Partial): Promise; } export class ErrorHandler { static getInstance(): ErrorHandler; handleError(error: Error, context?: string): void; handleAsyncError(promise: Promise, context?: string): Promise; registerGlobalErrorHandlers(): void; } export class Listener { listener: (...args: any[]) => void; once: boolean; } export class EventEmitter { on(event: string, listener: (...args: any[]) => void): void; off(event: string, listenerToRemove: Listener): void; emit(event: string, ...args: any[]): void; once(event: string, listener: (...args: any[]) => void): void; removeAllListeners(event?: string): void; listenerCount(event: string): number; listeners(event: string): Listener[]; eventNames(): string[]; } export class GunDataProvider { constructor(options?: GunDataProviderOptions); getNode(path: string): GunNode; createQuery(path: string): GunQuery; put(path: string, data: any): Promise; get(path: string): Promise; set(path: string, data: any): Promise; onUpdate(path: string, callback: (data: any) => void): void; offUpdate(path: string, callback: (data: any) => void): void; createUser(username: string, password: string): Promise; login(username: string, password: string): Promise; logout(): void; getCurrentUser(): any; isAuthenticated(): boolean; generateUuid(): string; getServerTime(): Promise; } export class Gun { constructor(options?: GunDataProviderOptions); get(path: string): GunNode; on(event: string, listener: (data: any, key: string) => void): void; once(listener: (data: any, key: string) => void): void; put(data: any, callback: (ack: any) => void): void; set(data: any, callback: (ack: any) => void): void; offUpdate(callback: (data: any, key: string) => void): void; } export class GunNode { constructor(gun: Gun, path: string); put(data: Partial): Promise; get(): Promise; set(data: T): Promise; map(): GunNode; each(callback: (data: T, key: string) => void | Promise): Promise; } export class GunQuery { constructor(node: GunNode); find(predicate: (item: T) => boolean, options?: QueryOptions): Promise; findOne(predicate: (item: T) => boolean): Promise; count(predicate?: (item: T) => boolean): Promise; update(predicate: (item: T) => boolean, updateFn: (item: T) => Partial): Promise; delete(predicate: (item: T) => boolean): Promise; map(mapper: (item: T) => R): GunQuery; filter(predicate: (item: T) => boolean): GunQuery; } export class Logger { static getInstance(): Logger; setLogLevel(level: LogLevel): void; debug(message: string, context?: string, data?: any): void; info(message: string, context?: string, data?: any): void; warn(message: string, context?: string, data?: any): void; error(message: string, context?: string, data?: any): void; getLogs(): LogEntry[]; clearLogs(): void; exportLogs(): string; importLogs(logsJson: string): void; } export class ContextState { context: Context; data: any; } export class ContextTransition { from: Context; to: Context; } export class MultiContextObject { constructor(contexts: Context[]); isValidContext(context: Context): boolean; getCurrentContext(): Context; getContextState(context: Context): ContextState | undefined; setContextData(context: Context, key: string, value: any): void; getContextData(context: Context, key: string): any; switchContext(newContext: Context): Promise; executeInContext(context: Context, func: () => Promise | T): Promise; executeInAllContexts(func: (context: Context) => Promise | T): Promise>; executeInMultipleContexts(contexts: Context[], func: (context: Context) => Promise | T): Promise>; onContextActivated(callback: (context: Context) => void): void; onContextDeactivated(callback: (context: Context) => void): void; onBeforeContextSwitch(callback: (transition: ContextTransition) => void): void; onAfterContextSwitch(callback: (transition: ContextTransition) => void): void; withContext(context: Context, func: () => Promise | T): Promise; isContextActive(context: Context): boolean; getActiveContexts(): Context[]; broadcastToActiveContexts(func: (context: Context) => Promise | T): Promise>; } export class NetworkMonitor { constructor(gunDataProvider: GunDataProvider, checkInterval?: number); getStats(): NetworkStats; isNetworkOnline(): boolean; setCheckInterval(interval: number): void; stopMonitoring(): void; destroy(): void; } export class PeerManager { constructor(); connectToPeer(peerId: string, peerUrl: string): Promise; handleIncomingConnection(peerId: string, offer: RTCSessionDescriptionInit): Promise; handleAnswer(peerId: string, answer: RTCSessionDescriptionInit): Promise; addIceCandidate(peerId: string, candidate: RTCIceCandidateInit): Promise; sendMessage(peerId: string, message: string): void; disconnectFromPeer(peerId: string): void; getPeers(): PeerInfo[]; } export class PluginSystem { constructor(contexts: Context[]); registerPlugin(plugin: Plugin): void; getPlugin(name: string): Plugin | undefined; getAllPlugins(): Plugin[]; broadcastToPlugins(eventName: string, ...args: any[]): Promise; } export class VNode { constructor(tag: string, props: any, children: VNode[], text?: string); } export class ReactiveUI { constructor(); mount(element: HTMLElement): void; unmount(): void; update(newVDOM: VNode): void; getComponentInstance(id: string): Component | undefined; updateComponentProps(id: string, newProps: any): void; } export class SEA { static pair(): Promise; static encrypt(data: any, pair: any): Promise; static decrypt(encryptedData: string, pair: any): Promise; static sign(data: any, pair: any): Promise; static verify(signedData: string, pair: any): Promise; static work(data: string, salt: string, options?: any): Promise; static certify(certificants: string | string[], policy: any, authority: any, expiry?: number, cb?: any): Promise; static recall(props: any, cb?: any): Promise; static secret(key: any, pair: any, cb?: any): Promise; static derive(passphrase: string, salt?: string, options?: any): Promise<{ epriv: string; epub: string }>; static authenticateUser(alias: string, password: string): Promise; static createUser(alias: string, password: string): Promise; } export class SyncManager { constructor(gunDataProvider: GunDataProvider); startSync(path: string): void; stopSync(path: string): void; getSyncStatus(path: string): SyncStatus | undefined; forceSyncAll(): Promise; forceSync(path: string): Promise; getPendingChangesCount(): number; isAnySyncInProgress(): boolean; getSyncedPaths(): string[]; } export class TypedSchema { constructor(schema: SchemaDefinition); validate(data: any): boolean; cast(data: any): any; getDefaultValue(): any; } export class RouteHandler { constructor(); handleRoute(data: any): any; } export class Middleware { constructor(); handleRequest(data: any): any; } export class RouteOptions { constructor(); broadcast: boolean; middleware: Middleware[]; } export class RouteConfig { constructor(); context: Context; handler: RouteHandler; options: RouteOptions; } export class ContextRouter { constructor(peerManager: PeerManager); addRoute(path: string, context: Context, handler: RouteHandler, options?: RouteOptions): void; use(middleware: Middleware): void; route(path: string, multiContextObject: MultiContextObject, data?: any): Promise; broadcastRoute(path: string, multiContextObject: MultiContextObject, data?: any): Promise; routeToPeer(peerId: string, path: string, data?: any): Promise; getRoutes(): Map>; clearRoutes(): void; removeRoute(path: string, context?: Context): void; } export class WebRTCAdapter { constructor(); createOffer(peerId: string): Promise; handleOffer(peerId: string, offer: RTCSessionDescriptionInit): Promise; handleAnswer(peerId: string, answer: RTCSessionDescriptionInit): Promise; addIceCandidate(peerId: string, candidate: RTCIceCandidateInit): Promise; sendMessage(peerId: string, message: string): void; close(peerId: string): void; } export function contextMethod(context: Context): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor; export function multiContext(...contexts: Context[]): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor; export function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor; export function retry(maxAttempts?: number, delay?: number): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor; export function memoize(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor; export function debounce(delay?: number): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor; export function throttle(limit?: number): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor; export const BROWSER_CONTEXT: Context; export const SERVER_CONTEXT: Context; export const PEER_CONTEXT: Context; }.//data/TypedSchema.ts import { SchemaDefinition } from '../Types'; export class TypedSchema { public schema: SchemaDefinition; constructor(schema: SchemaDefinition) { this.schema = schema; } validate(data: any): boolean { return this.validateObject(data, this.schema); } private validateObject(data: any, schema: SchemaDefinition): boolean { if (typeof data !== 'object' || data === null) { return false; } for (const [key, type] of Object.entries(schema)) { if (!(key in data)) { return false; } if (!this.validateValue(data[key], type)) { return false; } } return true; } private validateValue(value: any, type: string | SchemaDefinition): boolean { if (typeof type === 'string') { switch (type) { case 'string': return typeof value === 'string'; case 'number': return typeof value === 'number'; case 'boolean': return typeof value === 'boolean'; case 'object': return typeof value === 'object' && value !== null; case 'array': return Array.isArray(value); default: return false; } } else if (typeof type === 'object') { return this.validateObject(value, type); } return false; } cast(data: any): any { return this.castObject(data, this.schema); } private castObject(data: any, schema: SchemaDefinition): any { const result: any = {}; for (const [key, type] of Object.entries(schema)) { if (key in data) { result[key] = this.castValue(data[key], type); } } return result; } private castValue(value: any, type: string | SchemaDefinition): any { if (typeof type === 'string') { switch (type) { case 'string': return String(value); case 'number': return Number(value); case 'boolean': return Boolean(value); case 'object': return typeof value === 'object' ? value : {}; case 'array': return Array.isArray(value) ? value : []; default: return value; } } else if (typeof type === 'object') { return this.castObject(value, type); } return value; } getDefaultValue(): any { return this.getDefaultValueForSchema(this.schema); } private getDefaultValueForSchema(schema: SchemaDefinition): any { const result: any = {}; for (const [key, type] of Object.entries(schema)) { result[key] = this.getDefaultValueForType(type); } return result; } private getDefaultValueForType(type: string | SchemaDefinition): any { if (typeof type === 'string') { switch (type) { case 'string': return ''; case 'number': return 0; case 'boolean': return false; case 'object': return {}; case 'array': return []; default: return null; } } else if (typeof type === 'object') { return this.getDefaultValueForSchema(type); } return null; } }.//data/IndexedDBAdapter.ts import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; export class IndexedDBAdapter { private db: IDBDatabase | null = null; private dbName: string; private dbVersion: number; private stores: string[]; private logger: Logger; private errorHandler: ErrorHandler; constructor(dbName: string, dbVersion: number, stores: string[]) { this.dbName = dbName; this.dbVersion = dbVersion; this.stores = stores; this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); } async connect(): Promise { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.dbVersion); request.onerror = (event) => { this.errorHandler.handleError(new Error('IndexedDB connection error'), 'IndexedDBAdapter'); reject(event); }; request.onsuccess = (event) => { this.db = (event.target as IDBOpenDBRequest).result; this.logger.info('IndexedDB connection established', 'IndexedDBAdapter'); resolve(); }; request.onupgradeneeded = (event) => { this.db = (event.target as IDBOpenDBRequest).result; this.stores.forEach(storeName => { if (!this.db!.objectStoreNames.contains(storeName)) { this.db!.createObjectStore(storeName, { keyPath: 'id' }); this.logger.info(`Object store '${storeName}' created`, 'IndexedDBAdapter'); } }); }; }); } async put(storeName: string, data: any): Promise { return new Promise((resolve, reject) => { const transaction = this.db!.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); const request = store.put(data); request.onerror = (event) => { this.errorHandler.handleError(new Error('IndexedDB put error'), 'IndexedDBAdapter'); reject(event); }; request.onsuccess = () => { this.logger.debug(`Data stored in '${storeName}'`, 'IndexedDBAdapter', { id: data.id }); resolve(); }; }); } async get(storeName: string, id: string): Promise { return new Promise((resolve, reject) => { const transaction = this.db!.transaction(storeName, 'readonly'); const store = transaction.objectStore(storeName); const request = store.get(id); request.onerror = (event) => { this.errorHandler.handleError(new Error('IndexedDB get error'), 'IndexedDBAdapter'); reject(event); }; request.onsuccess = () => { this.logger.debug(`Data retrieved from '${storeName}'`, 'IndexedDBAdapter', { id }); resolve(request.result); }; }); } async delete(storeName: string, id: string): Promise { return new Promise((resolve, reject) => { const transaction = this.db!.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); const request = store.delete(id); request.onerror = (event) => { this.errorHandler.handleError(new Error('IndexedDB delete error'), 'IndexedDBAdapter'); reject(event); }; request.onsuccess = () => { this.logger.debug(`Data deleted from '${storeName}'`, 'IndexedDBAdapter', { id }); resolve(); }; }); } async getAll(storeName: string): Promise { return new Promise((resolve, reject) => { const transaction = this.db!.transaction(storeName, 'readonly'); const store = transaction.objectStore(storeName); const request = store.getAll(); request.onerror = (event) => { this.errorHandler.handleError(new Error('IndexedDB getAll error'), 'IndexedDBAdapter'); reject(event); }; request.onsuccess = () => { this.logger.debug(`All data retrieved from '${storeName}'`, 'IndexedDBAdapter'); resolve(request.result); }; }); } async clear(storeName: string): Promise { return new Promise((resolve, reject) => { const transaction = this.db!.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); const request = store.clear(); request.onerror = (event) => { this.errorHandler.handleError(new Error('IndexedDB clear error'), 'IndexedDBAdapter'); reject(event); }; request.onsuccess = () => { this.logger.debug(`All data cleared from '${storeName}'`, 'IndexedDBAdapter'); resolve(); }; }); } disconnect(): void { if (this.db) { this.db.close(); this.logger.info('IndexedDB connection closed', 'IndexedDBAdapter'); } } }.//data/DistributedState.ts import { GunDataProvider } from '../data/GunDataProvider'; import { EventEmitter } from '../utils/EventEmitter'; import { TypedSchema } from './TypedSchema'; import { SchemaDefinition } from '../Types'; export class DistributedState extends EventEmitter { private gunDataProvider: GunDataProvider; private path: string; private schema: TypedSchema; private state: T; constructor(gunDataProvider: GunDataProvider, path: string, schema: SchemaDefinition, initialState?: T) { super(); this.gunDataProvider = gunDataProvider; this.path = path; this.schema = new TypedSchema(schema); this.state = this.schema.getDefaultValue() as T; if (initialState) { this.state = { ...this.state, ...initialState }; } this.setupListeners(); } private setupListeners(): void { this.gunDataProvider.onUpdate(this.path, (data: any) => { const validData = this.schema.cast(data); this.updateState(validData); }); } private updateState(newState: Partial): void { const oldState = { ...this.state }; this.state = { ...this.state, ...newState }; this.emit('stateChanged', this.state, oldState); } async get(): Promise { const data = await this.gunDataProvider.get(this.path); return this.schema.cast(data) as T; } async set(data: Partial): Promise { const validData = this.schema.cast(data); await this.gunDataProvider.put(this.path, validData); this.updateState(validData); } async update(updater: (currentState: T) => Partial): Promise { const currentState = await this.get(); const updates = updater(currentState); await this.set(updates); } subscribe(listener: (state: T, oldState: T) => void): () => void { this.on('stateChanged', listener); return () => this.off('stateChanged', listener); } getSchema(): SchemaDefinition { return this.schema.schema; } validate(data: any): boolean { return this.schema.validate(data); } async reset(): Promise { const defaultState = this.schema.getDefaultValue() as T; return this.set(defaultState); } getId(): string { return this.path; } async transaction(transactionFn: (currentState: T) => Partial): Promise { const currentState = await this.get(); const updates = transactionFn(currentState); await this.set(updates); } // New method to get the current state synchronously getCurrentState(): T { return { ...this.state }; } // New method to set state without emitting events (for internal use) setStateQuiet(newState: Partial): void { this.state = { ...this.state, ...newState }; } // New method to force a refresh from the data provider async refresh(): Promise { const data = await this.gunDataProvider.get(this.path); const validData = this.schema.cast(data) as T; this.setStateQuiet(validData); this.emit('stateChanged', this.state, {}); } }.//data/GunNode.ts import { EventEmitter } from '../utils/EventEmitter'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; export class GunNode extends EventEmitter { private node: any; private logger: Logger; private errorHandler: ErrorHandler; constructor(gun: any, path: string) { super(); this.node = gun.get(path); this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); this.setupListeners(); } private setupListeners(): void { this.node.on((data: any, key: any) => { this.emit('update', { data, key }); }); } async put(data: Partial): Promise { return new Promise((resolve, reject) => { this.node.put(data, (ack: any) => { if (ack.err) { this.errorHandler.handleError(new Error(ack.err), 'GunNode.put'); reject(ack.err); } else { this.logger.debug('Data put successful', 'GunNode', { data }); resolve(); } }); }); } async get(): Promise { return new Promise((resolve) => { this.node.once((data: any) => { if (data) { this.logger.debug('Data retrieved', 'GunNode', { data }); resolve(data as T); } else { resolve(null); } }); }); } async set(data: T): Promise { return new Promise((resolve, reject) => { this.node.set(data, (ack: any) => { if (ack.err) { this.errorHandler.handleError(new Error(ack.err), 'GunNode.set'); reject(ack.err); } else { this.logger.debug('Data set successful', 'GunNode', { data }); resolve(); } }); }); } map(): GunNode { return new GunNode(this.node.map() as any, ''); } async each(callback: (data: T, key: string) => void | Promise): Promise { return new Promise((resolve) => { this.node.map().once(async (data: any, key: any) => { await callback(data as T, key); }).then(() => { this.logger.debug('Each operation completed', 'GunNode'); resolve(); }); }); } on(event: 'update', listener: (data: { data: T, key: string }) => void): void; on(event: string, listener: (...args: any[]) => void): void { super.on(event, listener); } off(event: 'update', listener: (data: { data: T, key: string }) => void): void; off(event: string, listener: (...args: any[]) => void): void { super.off(event, listener); } }.//data/Gun.ts import Gun from 'gun'; import 'gun/sea'; function getGun(options: any) { return Gun({ peers: options.peers || [], localStorage: options.localStorage !== false, radisk: options.radisk !== false, multicast: options.multicast !== false }); } export default getGun;.//data/GunQuery.ts import { GunNode } from './GunNode'; import { QueryOptions } from '../Types'; import { Logger } from '../Logger'; export class GunQuery { private node: GunNode; private logger: Logger; constructor(node: GunNode) { this.node = node; this.logger = Logger.getInstance(); } async find(predicate: (item: T) => boolean, options: QueryOptions = {}): Promise { const result: T[] = []; let count = 0; let skipped = 0; await this.node.each((item, key) => { if (predicate(item)) { if (options.skip && skipped < options.skip) { skipped++; return; } result.push(item); count++; if (options.limit && count >= options.limit) { return; } } }); if (options.sort) { const [key, order] = Object.entries(options.sort)[0]; result.sort((a: any, b: any) => { if (a[key] < b[key]) return order === 'asc' ? -1 : 1; if (a[key] > b[key]) return order === 'asc' ? 1 : -1; return 0; }); } this.logger.debug('Query executed', 'GunQuery', { resultCount: result.length, options }); return result; } async findOne(predicate: (item: T) => boolean): Promise { let result: T | null = null; await this.node.each((item: T, key: string) => { if (result) { return; } if (predicate(item)) { result = item; return; } }); this.logger.debug('FindOne query executed', 'GunQuery', { found: result !== null }); return result; } async count(predicate?: (item: T) => boolean): Promise { let count = 0; await this.node.each((item) => { if (!predicate || predicate(item)) { count++; } }); this.logger.debug('Count query executed', 'GunQuery', { count }); return count; } async update(predicate: (item: T) => boolean, updateFn: (item: T) => Partial): Promise { let updatedCount = 0; await this.node.each(async (item, key) => { if (predicate(item)) { const updates = updateFn(item); await this.node.put({ ...item, ...updates }); updatedCount++; } }); this.logger.debug('Update query executed', 'GunQuery', { updatedCount }); return updatedCount; } async delete(predicate: (item: T) => boolean): Promise { let deletedCount = 0; await this.node.each(async (item, key) => { if (predicate(item)) { await this.node.put(null as any); deletedCount++; } }); this.logger.debug('Delete query executed', 'GunQuery', { deletedCount }); return deletedCount; } map(mapper: (item: T) => R): GunQuery { const mappedNode = new GunNode(this.node as any, ''); return new GunQuery(mappedNode); } filter(predicate: (item: T) => boolean): GunQuery { const filteredNode = new GunNode(this.node as any, ''); return new GunQuery(filteredNode); } }.//data/GunDataProvider.ts import { GunDataProviderOptions } from '../Types'; import getGun from './Gun'; import { GunNode } from './GunNode'; import { GunQuery } from './GunQuery'; import { Logger } from '../Logger'; import { ErrorHandler } from '../ui/ErrorHandler'; import { EventEmitter } from '../utils/EventEmitter'; export class GunDataProvider extends EventEmitter { public gun: any; private logger: Logger; private errorHandler: ErrorHandler; constructor(options: GunDataProviderOptions = {}) { super(); this.gun = getGun(options); this.logger = Logger.getInstance(); this.errorHandler = ErrorHandler.getInstance(); this.setupErrorHandling(); } private setupErrorHandling(): void { this.gun.on('error', (error: any) => { this.errorHandler.handleError(error, 'GunDataProvider'); }); } getNode(path: string): GunNode { return new GunNode(this.gun, path); } createQuery(path: string): GunQuery { const node = this.getNode(path); return new GunQuery(node); } async put(path: string, data: any): Promise { const node = this.getNode(path); await node.put(data); this.logger.debug('Data put successful', 'GunDataProvider', { path, data }); } async get(path: string): Promise { const node = this.getNode(path); const data = await node.get(); this.logger.debug('Data retrieved', 'GunDataProvider', { path, data }); return data; } async set(path: string, data: any): Promise { const node = this.getNode(path); await node.set(data); this.logger.debug('Data set successful', 'GunDataProvider', { path, data }); } onUpdate(path: string, callback: (data: any) => void): void { const node = this.getNode(path); node.on('update', ({ data }) => { callback(data); }); this.logger.debug('Update listener added', 'GunDataProvider', { path }); } offUpdate(path: string, callback: (data: any) => void): void { const node = this.getNode(path); node.off('update', callback); this.logger.debug('Update listener removed', 'GunDataProvider', { path }); } async createUser(username: string, password: string): Promise { return new Promise((resolve, reject) => { this.gun.user().create(username, password, (ack: any) => { if (ack.err) { this.errorHandler.handleError(new Error(ack.err), 'GunDataProvider.createUser'); reject(ack.err); } else { this.logger.info('User created', 'GunDataProvider', { username }); resolve(ack); } }); }); } async login(username: string, password: string): Promise { return new Promise((resolve, reject) => { this.gun.user().auth(username, password, (ack: any) => { if (ack.err) { this.errorHandler.handleError(new Error(ack.err), 'GunDataProvider.login'); reject(ack.err); } else { this.logger.info('User logged in', 'GunDataProvider', { username }); resolve(ack); } }); }); } logout(): void { this.gun.user().leave(); this.logger.info('User logged out', 'GunDataProvider'); } getCurrentUser(): any { return this.gun.user().is; } isAuthenticated(): boolean { return !!this.getCurrentUser(); } generateUuid(): string { return this.gun.user().text.random(24); } getServerTime(): Promise { return new Promise((resolve) => { this.gun.time((time: any) => { resolve(time); }); }); } }