# Network Library Phase 0 Implementation Plan This document outlines the implementation plan for Phase 0 of the network library, focusing on core components and event system integration. ## Implementation Goals 1. Create utils directory with @suaveplan/events integration 2. Implement core NetworkNode methods 3. Implement NetworkSystem core methods 4. Add API versioning infrastructure 5. Establish testing patterns ## Architectural Overview Phase 0 will establish the foundation for the modular network library. The core components and their relationships are illustrated in the following diagram: ```mermaid classDiagram class EventEmitter { <<@suaveplan/events>> +on(event, listener, context?) +once(event, listener, context?) +off(event, listener, context?) +emit(event, ...args) } class NetworkEventEmitter { -_emitter: EventEmitter +on(event, listener, context?) +once(event, listener, context?) +off(event, listener, context?) +emit(event, ...args) +onNodeConnected(handler) +onNodeDisconnected(handler) +onMessageSent(handler) } class NetworkNode { -_id: string -_level: number -_parent: NetworkNode | null -_children: Map~string, NetworkNode~ -_siblings: Map~string, NetworkNode~ -_events: NetworkEventEmitter +connect() +disconnect() +addChild(node) +removeChild(nodeId) +sendMessage(message) } class NetworkSystem { -_nodes: Map~string, NetworkNode~ -_config: NetworkSystemConfig -_events: NetworkEventEmitter +createNode(id, capabilities) +getNode(id) +removeNode(id) +placeNodeInHierarchy(node) } class VersionInfo { +major: number +minor: number +patch: number +isCompatibleWith(version) } class IPlugin { <> +id: string +onRegister(entity) +onUnregister(entity) } class PluginRegistry { -_plugins: Map~string, IPlugin~ +register(plugin) +unregister(pluginId) +getPlugin(pluginId) } NetworkNode --> NetworkEventEmitter : uses NetworkSystem --> NetworkEventEmitter : uses NetworkSystem --> NetworkNode : manages NetworkNode --> PluginRegistry : has NetworkEventEmitter --> EventEmitter : wraps NetworkNode ..> IPlugin : supports PluginRegistry o-- IPlugin : contains ``` ## Implementation Steps ### 1. Create Utils Directory with Event Integration #### 1.1 Create Event Constants **File: `src/utils/event-constants.ts`** ```typescript /** * Standard event names used throughout the network library */ export enum NetworkEvents { // Node lifecycle events NODE_CREATED = 'node:created', NODE_CONNECTED = 'node:connected', NODE_DISCONNECTED = 'node:disconnected', NODE_UPDATED = 'node:updated', NODE_REMOVED = 'node:removed', // Message events MESSAGE_SENT = 'message:sent', MESSAGE_RECEIVED = 'message:received', MESSAGE_ROUTED = 'message:routed', MESSAGE_DROPPED = 'message:dropped', // Hierarchy events HIERARCHY_CHANGED = 'hierarchy:changed', PARENT_CHANGED = 'hierarchy:parent-changed', CHILD_ADDED = 'hierarchy:child-added', CHILD_REMOVED = 'hierarchy:child-removed', SIBLING_ADDED = 'hierarchy:sibling-added', SIBLING_REMOVED = 'hierarchy:sibling-removed', LEVEL_CHANGED = 'hierarchy:level-changed', // Plugin events PLUGIN_REGISTERED = 'plugin:registered', PLUGIN_UNREGISTERED = 'plugin:unregistered', // System events SYSTEM_ERROR = 'system:error', SYSTEM_WARNING = 'system:warning', SYSTEM_INFO = 'system:info' } ``` #### 1.2 Create Network Event Emitter **File: `src/utils/network-event-emitter.ts`** ```typescript import { EventEmitter } from '@suaveplan/events'; import { NetworkEvents } from './event-constants'; /** * NetworkEventEmitter provides a standardized event handling system for the network library. * It wraps the @suaveplan/events EventEmitter with network-specific features. */ export class NetworkEventEmitter { private _emitter: EventEmitter; constructor(emitter?: EventEmitter) { this._emitter = emitter || new EventEmitter(); } /** * Registers a listener for the specified event */ on(event: string, listener: Function, context?: any): this { this._emitter.on(event, listener, context); return this; } /** * Registers a one-time listener for the specified event */ once(event: string, listener: Function, context?: any): this { this._emitter.once(event, listener, context); return this; } /** * Removes a listener for the specified event */ off(event: string, listener?: Function, context?: any): this { this._emitter.off(event, listener, context); return this; } /** * Emits an event with the provided arguments */ emit(event: string, ...args: any[]): boolean { return this._emitter.emit(event, ...args); } /** * Returns all registered event names */ eventNames(): string[] { return this._emitter.eventNames(); } /** * Returns the number of listeners for a given event */ listenerCount(event: string): number { return this._emitter.listenerCount(event); } // Convenience methods for common events /** * Registers a listener for the NODE_CONNECTED event */ onNodeConnected(listener: Function, context?: any): this { return this.on(NetworkEvents.NODE_CONNECTED, listener, context); } /** * Registers a listener for the NODE_DISCONNECTED event */ onNodeDisconnected(listener: Function, context?: any): this { return this.on(NetworkEvents.NODE_DISCONNECTED, listener, context); } /** * Registers a listener for the MESSAGE_SENT event */ onMessageSent(listener: Function, context?: any): this { return this.on(NetworkEvents.MESSAGE_SENT, listener, context); } /** * Registers a listener for the MESSAGE_RECEIVED event */ onMessageReceived(listener: Function, context?: any): this { return this.on(NetworkEvents.MESSAGE_RECEIVED, listener, context); } } ``` #### 1.3 Create Utils Index **File: `src/utils/index.ts`** ```typescript export * from './event-constants'; export * from './network-event-emitter'; ``` ### 2. Update Types for Event System Integration **File: `src/types.ts` (additions)** ```typescript // Add these interfaces to the existing types.ts file /** * Interface for event emitters, matching the core functionality of @suaveplan/events */ export interface IEventEmitter { on(event: string, listener: Function, context?: any): any; once(event: string, listener: Function, context?: any): any; off(event: string, listener?: Function, context?: any): any; emit(event: string, ...args: any[]): boolean; eventNames?(): string[]; listenerCount?(event: string): number; } /** * Interface for NetworkEventEmitter, extending the base IEventEmitter */ export interface INetworkEventEmitter extends IEventEmitter { onNodeConnected(listener: Function, context?: any): any; onNodeDisconnected(listener: Function, context?: any): any; onMessageSent(listener: Function, context?: any): any; onMessageReceived(listener: Function, context?: any): any; } // Add to NodeState enum if it doesn't already exist export enum NodeState { CREATED = 'created', CONNECTING = 'connecting', CONNECTED = 'connected', DISCONNECTING = 'disconnecting', DISCONNECTED = 'disconnected', ERROR = 'error' } // Add API version interface export interface APIVersion { major: number; minor: number; patch: number; } ``` ### 3. Implement Basic Plugin System Interfaces **File: `src/plugins/plugin-registry.ts`** ```typescript import { IPlugin } from '../types'; /** * PluginRegistry manages the registration and lifecycle of plugins. */ export class PluginRegistry { private _plugins: Map; private _entity: any; // The entity (node or system) this registry belongs to constructor(entity: any) { this._plugins = new Map(); this._entity = entity; } /** * Registers a plugin with the entity */ register(plugin: IPlugin): boolean { if (this._plugins.has(plugin.id)) { return false; } this._plugins.set(plugin.id, plugin); plugin.onRegister(this._entity); return true; } /** * Unregisters a plugin from the entity */ unregister(pluginId: string): boolean { const plugin = this._plugins.get(pluginId); if (!plugin) { return false; } plugin.onUnregister(this._entity); this._plugins.delete(pluginId); return true; } /** * Returns a plugin by ID */ getPlugin(pluginId: string): T | undefined { return this._plugins.get(pluginId) as T | undefined; } /** * Checks if a plugin is registered */ hasPlugin(pluginId: string): boolean { return this._plugins.has(pluginId); } /** * Returns all registered plugins */ getAllPlugins(): IPlugin[] { return Array.from(this._plugins.values()); } } ``` ### 4. Implement API Versioning Infrastructure #### 4.1 Create Version Info Class **File: `src/versioning/version-info.ts`** ```typescript import { APIVersion } from '../types'; /** * VersionInfo represents a semantic version and provides * compatibility checking functionality. */ export class VersionInfo implements APIVersion { readonly major: number; readonly minor: number; readonly patch: number; constructor(major: number, minor: number, patch: number) { this.major = major; this.minor = minor; this.patch = patch; } /** * Creates a VersionInfo from a version string (e.g., "1.2.3") */ static fromString(version: string): VersionInfo { const parts = version.split('.').map(p => parseInt(p, 10)); return new VersionInfo( parts[0] || 0, parts[1] || 0, parts[2] || 0 ); } /** * Converts the version to a string representation */ toString(): string { return `${this.major}.${this.minor}.${this.patch}`; } /** * Checks if this version is compatible with another version * Compatible means same major version and minor version >= required */ isCompatibleWith(other: VersionInfo): boolean { // Major version must match for compatibility if (this.major !== other.major) { return false; } // Minor version must be >= the required version return this.minor >= other.minor; } /** * Checks if this version is newer than another version */ isNewerThan(other: VersionInfo): boolean { if (this.major > other.major) return true; if (this.major < other.major) return false; if (this.minor > other.minor) return true; if (this.minor < other.minor) return false; return this.patch > other.patch; } } ``` #### 4.2 Create Version Manager **File: `src/versioning/version-manager.ts`** ```typescript import { VersionInfo } from './version-info'; /** * VersionManager handles API versioning and compatibility checking */ export class VersionManager { static readonly CURRENT_VERSION = new VersionInfo(0, 1, 0); /** * Checks if a version is compatible with the current library version */ static isCompatible(version: VersionInfo): boolean { return VersionManager.CURRENT_VERSION.isCompatibleWith(version); } /** * Returns a list of versions between from and to (inclusive) * This can be used for migration paths */ static getMigrationPath(fromVersion: VersionInfo, toVersion: VersionInfo): VersionInfo[] { const result: VersionInfo[] = []; // If versions are incompatible (different major), return empty path if (fromVersion.major !== toVersion.major) { return result; } // Add all minor versions between from and to for (let minor = fromVersion.minor; minor <= toVersion.minor; minor++) { result.push(new VersionInfo(fromVersion.major, minor, 0)); } return result; } /** * Returns the stability classification for the current version */ static getStabilityClassification(): 'experimental' | 'stable' | 'deprecated' { // Phase 0 is experimental return 'experimental'; } } ``` #### 4.3 Create Versioning Index **File: `src/versioning/index.ts`** ```typescript export * from './version-info'; export * from './version-manager'; ``` ### 5. Implement Core NetworkNode Methods **File: `src/node/node.ts` (update)** ```typescript import { NodeState, NodeCapabilities, NodePerformance, NetworkMessage, MessagePriority, LevelConfig, MessageRoutingConfig, NetworkSystemConfig, INetworkEventEmitter } from '../types'; import { NetworkEventEmitter, NetworkEvents } from '../utils'; import { PluginRegistry } from '../plugins/plugin-registry'; import { IPlugin } from '../types'; export class NetworkNode { private _id: string; private _state: NodeState = NodeState.CREATED; private _level: number; private _parent: NetworkNode | null = null; private _children: Map = new Map(); private _siblings: Map = new Map(); private _capabilities: NodeCapabilities; private _events: INetworkEventEmitter; private _plugins: PluginRegistry; constructor( id: string, level: number, capabilities: NodeCapabilities, eventEmitter?: INetworkEventEmitter ) { this._id = id; this._level = level; this._capabilities = capabilities; this._events = eventEmitter || new NetworkEventEmitter(); this._plugins = new PluginRegistry(this); // Emit node created event this._events.emit(NetworkEvents.NODE_CREATED, this); } /** * Returns the node's ID */ get id(): string { return this._id; } /** * Returns the node's hierarchy level */ get level(): number { return this._level; } /** * Returns the node's parent node, or null if it has no parent */ get parent(): NetworkNode | null { return this._parent; } /** * Returns the node's children as an array */ get children(): NetworkNode[] { return Array.from(this._children.values()); } /** * Returns the node's siblings as an array */ get siblings(): NetworkNode[] { return Array.from(this._siblings.values()); } /** * Returns the node's capabilities */ get capabilities(): NodeCapabilities { return this._capabilities; } /** * Returns the node's current state */ get state(): NodeState { return this._state; } /** * Returns the number of children */ get childCount(): number { return this._children.size; } /** * Connects the node to the network */ connect(): boolean { if (this._state !== NodeState.CREATED && this._state !== NodeState.DISCONNECTED) { return false; } this._state = NodeState.CONNECTING; this._events.emit(NetworkEvents.NODE_UPDATED, this); // Simulate successful connection for Phase 0 this._state = NodeState.CONNECTED; this._events.emit(NetworkEvents.NODE_CONNECTED, this); return true; } /** * Disconnects the node from the network */ disconnect(): boolean { if (this._state !== NodeState.CONNECTED && this._state !== NodeState.CONNECTING) { return false; } this._state = NodeState.DISCONNECTING; this._events.emit(NetworkEvents.NODE_UPDATED, this); // Simulate successful disconnection for Phase 0 this._state = NodeState.DISCONNECTED; this._events.emit(NetworkEvents.NODE_DISCONNECTED, this); return true; } /** * Checks if the node can accept more children */ canAcceptChildren(): boolean { // For Phase 0, just check if level > 0 (clients can't have children) return this._level > 0; } /** * Adds a child node to this node */ addChild(node: NetworkNode): boolean { if (!this.canAcceptChildren() || this._children.has(node.id) || node.id === this._id) { return false; } // Remove from previous parent if exists if (node.parent) { node.parent.removeChild(node.id); } // Add as child this._children.set(node.id, node); this._setParentForNode(node); // Emit events this._events.emit(NetworkEvents.CHILD_ADDED, this, node); this._events.emit(NetworkEvents.HIERARCHY_CHANGED, this); return true; } /** * Removes a child node from this node */ removeChild(nodeId: string): boolean { const node = this._children.get(nodeId); if (!node) { return false; } // Remove child reference this._children.delete(nodeId); // Clear parent reference this._clearParentForNode(node); // Emit events this._events.emit(NetworkEvents.CHILD_REMOVED, this, node); this._events.emit(NetworkEvents.HIERARCHY_CHANGED, this); return true; } /** * Adds a sibling node to this node */ addSibling(node: NetworkNode): boolean { if (node.id === this._id || this._siblings.has(node.id)) { return false; } // Add sibling relationship (bidirectional) this._siblings.set(node.id, node); node._siblings.set(this._id, this); // Emit events this._events.emit(NetworkEvents.SIBLING_ADDED, this, node); this._events.emit(NetworkEvents.HIERARCHY_CHANGED, this); return true; } /** * Removes a sibling node from this node */ removeSibling(nodeId: string): boolean { const node = this._siblings.get(nodeId); if (!node) { return false; } // Remove sibling relationship (bidirectional) this._siblings.delete(nodeId); node._siblings.delete(this._id); // Emit events this._events.emit(NetworkEvents.SIBLING_REMOVED, this, node); this._events.emit(NetworkEvents.HIERARCHY_CHANGED, this); return true; } /** * Sends a message from this node * Phase 0 implementation just emits an event */ async sendMessage(message: NetworkMessage): Promise { // For Phase 0, just emit the event this._events.emit(NetworkEvents.MESSAGE_SENT, message, this); } /** * Updates the node's level */ updateLevel(newLevel: number): boolean { if (newLevel === this._level) { return false; } const oldLevel = this._level; this._level = newLevel; // Emit events this._events.emit(NetworkEvents.LEVEL_CHANGED, this, oldLevel, newLevel); this._events.emit(NetworkEvents.NODE_UPDATED, this); return true; } /** * Registers a plugin with this node */ registerPlugin(plugin: IPlugin): boolean { const result = this._plugins.register(plugin); if (result) { this._events.emit(NetworkEvents.PLUGIN_REGISTERED, this, plugin); } return result; } /** * Removes a plugin from this node */ removePlugin(pluginId: string): boolean { const plugin = this._plugins.getPlugin(pluginId); const result = this._plugins.unregister(pluginId); if (result && plugin) { this._events.emit(NetworkEvents.PLUGIN_UNREGISTERED, this, plugin); } return result; } /** * Gets a plugin by ID */ getPlugin(pluginId: string): T | undefined { return this._plugins.getPlugin(pluginId); } /** * Sets the parent for a node */ private _setParentForNode(node: NetworkNode): void { node._parent = this; node._events.emit(NetworkEvents.PARENT_CHANGED, node, null, this); } /** * Clears the parent for a node */ private _clearParentForNode(node: NetworkNode): void { const oldParent = node._parent; node._parent = null; node._events.emit(NetworkEvents.PARENT_CHANGED, node, oldParent, null); } } ``` ### 6. Implement NetworkSystem Core Methods **File: `src/network/network.ts` (update)** ```typescript import { NetworkSystemConfig, NodeCapabilities, INetworkEventEmitter, NodeState } from '../types'; import { NetworkNode } from '../node/node'; import { NetworkEventEmitter, NetworkEvents } from '../utils'; import { PluginRegistry } from '../plugins/plugin-registry'; import { IPlugin } from '../types'; import { VersionManager } from '../versioning'; export class NetworkSystem { private _nodes: Map = new Map(); private _config: NetworkSystemConfig; private _events: INetworkEventEmitter; private _plugins: PluginRegistry; constructor(config: Partial = {}, eventEmitter?: INetworkEventEmitter) { this._config = this._createDefaultConfig(config); this._events = eventEmitter || new NetworkEventEmitter(); this._plugins = new PluginRegistry(this); } /** * Creates a new node and adds it to the system */ createNode( id: string, capabilities: NodeCapabilities ): NetworkNode { // Determine initial level based on capabilities const level = this._determineInitialLevel(capabilities); // Create the node const node = new NetworkNode(id, level, capabilities, this._events); // Add to nodes map this._nodes.set(id, node); // Setup event handlers this._setupNodeEventHandlers(node); // Emit event this._events.emit(NetworkEvents.NODE_CREATED, node); return node; } /** * Gets a node by ID */ getNode(id: string): NetworkNode | undefined { return this._nodes.get(id); } /** * Removes a node from the system */ removeNode(id: string): boolean { const node = this._nodes.get(id); if (!node) { return false; } // Disconnect the node if connected if (node.state === NodeState.CONNECTED) { node.disconnect(); } // Remove parent-child relationships if (node.parent) { node.parent.removeChild(node.id); } // Remove child-parent relationships for (const child of node.children) { node.removeChild(child.id); } // Remove sibling relationships for (const sibling of node.siblings) { node.removeSibling(sibling.id); } // Remove from nodes map this._nodes.delete(id); // Emit event this._events.emit(NetworkEvents.NODE_REMOVED, node); return true; } /** * Gets all nodes in the system */ getAllNodes(): NetworkNode[] { return Array.from(this._nodes.values()); } /** * Gets all nodes at a specific level */ getNodesByLevel(level: number): NetworkNode[] { return this.getAllNodes().filter(node => node.level === level); } /** * Finds the best parent for a node based on hierarchy */ findBestParent(node: NetworkNode): NetworkNode | null { // For Phase 0, just find a node at the next higher level with available capacity const potentialParents = this.getNodesByLevel(node.level + 1) .filter(parent => parent.canAcceptChildren()); if (potentialParents.length === 0) { return null; } // For now, just return the first available parent // In future phases, this will use metrics to find optimal parent return potentialParents[0]; } /** * Places a node in the hierarchy by finding an appropriate parent */ placeNodeInHierarchy(node: NetworkNode): boolean { // Find best parent const parent = this.findBestParent(node); // If no parent available and not at top level, cannot place in hierarchy if (!parent && node.level < this._config.maxLevels - 1) { return false; } // If parent found, add as child if (parent) { return parent.addChild(node); } // If no parent and at top level, node is at top of hierarchy return true; } /** * Registers a plugin with the system */ registerPlugin(plugin: IPlugin): boolean { const result = this._plugins.register(plugin); if (result) { this._events.emit(NetworkEvents.PLUGIN_REGISTERED, this, plugin); } return result; } /** * Removes a plugin from the system */ removePlugin(pluginId: string): boolean { const plugin = this._plugins.getPlugin(pluginId); const result = this._plugins.unregister(pluginId); if (result && plugin) { this._events.emit(NetworkEvents.PLUGIN_UNREGISTERED, this, plugin); } return result; } /** * Gets a plugin by ID */ getPlugin(pluginId: string): T | undefined { return this._plugins.getPlugin(pluginId); } /** * Returns the current library version */ getVersion() { return VersionManager.CURRENT_VERSION; } /** * Creates a default configuration */ private _createDefaultConfig(partial: Partial): NetworkSystemConfig { return { maxLevels: partial.maxLevels || 5, defaultLevel: partial.defaultLevel || 0, levelConfigs: partial.levelConfigs || DEFAULT_LEVEL_CONFIGS, enableVoting: partial.enableVoting ?? false, enableStateSync: partial.enableStateSync ?? false, enableMetrics: partial.enableMetrics ?? false, enableFailover: partial.enableFailover ?? false, transportFallbackOrder: partial.transportFallbackOrder || [], connectionTimeout: partial.connectionTimeout || 30000, connectionRetries: partial.connectionRetries || 3, heartbeatInterval: partial.heartbeatInterval || 5000 }; } /** * Determines the initial level for a node based on capabilities */ private _determineInitialLevel(capabilities: NodeCapabilities): number { // For Phase 0, just use default level // In future phases, this will examine capabilities return this._config.defaultLevel; } /** * Sets up event handlers for a node */ private _setupNodeEventHandlers(node: NetworkNode): void { // For Phase 0, just listen for basic events // In future phases, this will be more comprehensive } } export const DEFAULT_LEVEL_CONFIGS = [ { level: 0, name: "Client", maxChildren: 0, maxSiblings: Infinity, minPromotionScore: 0.7, demotionThreshold: 0 }, { level: 1, name: "Host", maxChildren: 20, maxSiblings: 10, minPromotionScore: 0.8, demotionThreshold: 0.4 }, { level: 2, name: "Tier Host", maxChildren: 10, maxSiblings: 5, minPromotionScore: 0.9, demotionThreshold: 0.5 }, { level: 3, name: "Region Host", maxChildren: 5, maxSiblings: 10, minPromotionScore: 0.95, demotionThreshold: 0.6 }, { level: 4, name: "Country Host", maxChildren: 10, maxSiblings: 0, minPromotionScore: 1.0, demotionThreshold: 0.7 } ]; ``` ### 7. Update Index File with Exports **File: `src/index.ts` (update)** ```typescript // Core components export * from './node'; export * from './network'; export * from './utils'; export * from './versioning'; export * from './plugins/plugin-registry'; // Types export * from './types'; ``` ## Testing Strategy For Phase 0, we'll implement the following tests: 1. **Unit Tests**: - NetworkNode class tests - NetworkSystem class tests - NetworkEventEmitter tests - VersionInfo and VersionManager tests - PluginRegistry tests 2. **Integration Tests**: - Event propagation through hierarchy - Plugin registration and interaction with nodes - System configuration and node placement 3. **Edge Cases**: - Node removal and hierarchy reorganization - Version compatibility checking - Plugin dependency resolution ## Next Steps After implementing Phase 0, we'll proceed to Phase 1, which will focus on: 1. Implementing the transport layer 2. Enhancing the relay capabilities 3. Building out the message routing system 4. Adding metrics and host selection ## Conclusion This implementation plan establishes the foundational components of the network library with a focus on modularity, event handling, and plugin support. By following this plan, we'll create a solid base that supports all future phases of development while maintaining compatibility and extensibility.