CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-insert-koin--koin-core-js

KOIN - Kotlin simple Dependency Injection Framework for JavaScript/Browser platform

Pending
Overview
Eval results
Files

error-handling.mddocs/

Error Handling and Diagnostics

Comprehensive error handling with specific exception types for different failure scenarios in dependency injection and container management.

Capabilities

Definition and Resolution Errors

Handle errors related to dependency definition and resolution failures.

/**
 * Exception thrown when definition is not found during resolution
 */
class NoDefinitionFoundException extends Error {
  /**
   * Create exception for missing definition
   * @param message - Error description
   */
  constructor(message: string);
  
  /**
   * The qualifier that was not found (if any)
   */
  qualifier?: Qualifier;
  
  /**
   * The type that was being resolved
   */
  type?: any;
}

/**
 * Exception thrown when definition override is not allowed
 */
class DefinitionOverrideException extends Error {
  /**
   * Create exception for definition override conflict
   * @param message - Error description
   */
  constructor(message: string);
  
  /**
   * The definition that conflicts
   */
  definition?: BeanDefinition<any>;
}

/**
 * Exception thrown when instance creation fails
 */
class InstanceCreationException extends Error {
  /**
   * Create exception for instance creation failure
   * @param message - Error description
   * @param cause - Underlying cause of failure
   */
  constructor(message: string, cause?: Error);
  
  /**
   * The underlying cause of the creation failure
   */
  cause?: Error;
  
  /**
   * The definition that failed to create instance
   */
  definition?: BeanDefinition<any>;
}

Usage Examples:

import { 
  GlobalContext, 
  NoDefinitionFoundException,
  DefinitionOverrideException,
  InstanceCreationException,
  named 
} from "koin-core";

class ServiceManager {
  async getService(serviceName) {
    try {
      const koin = GlobalContext.get();
      return koin.get(named(serviceName));
      
    } catch (error) {
      if (error instanceof NoDefinitionFoundException) {
        console.error(`Service '${serviceName}' not found in DI container`);
        console.error(`Qualifier: ${error.qualifier?.value}`);
        console.error(`Type: ${error.type?.name}`);
        
        // Provide fallback or default service
        return this.createFallbackService(serviceName);
        
      } else if (error instanceof InstanceCreationException) {
        console.error(`Failed to create service '${serviceName}'`);
        console.error(`Cause: ${error.cause?.message}`);
        
        // Log additional context and re-throw
        this.logCreationFailure(error);
        throw new Error(`Service creation failed: ${error.message}`);
        
      } else {
        // Re-throw unknown errors
        throw error;
      }
    }
  }
  
  registerService(serviceName, factory, allowOverride = false) {
    try {
      const koin = GlobalContext.get();
      const module = module((builder) => {
        builder.single(named(serviceName), factory);
      });
      
      if (allowOverride) {
        // Handle override explicitly
        koin.declare(factory(), named(serviceName), [], true);
      } else {
        loadKoinModules([module]);
      }
      
    } catch (error) {
      if (error instanceof DefinitionOverrideException) {
        console.error(`Service '${serviceName}' already exists`);
        console.error(`Existing definition: ${error.definition?.qualifier?.value}`);
        
        if (allowOverride) {
          // Force override
          this.forceOverrideService(serviceName, factory);
        } else {
          throw new Error(`Service '${serviceName}' already registered`);
        }
      }
    }
  }
}

Scope-Related Errors

Handle errors related to scope lifecycle and management.

/**
 * Exception thrown when attempting to use a closed scope
 */
class ClosedScopeException extends Error {
  /**
   * Create exception for closed scope access
   * @param scopeId - The ID of the closed scope
   */
  constructor(scopeId: string);
  
  /**
   * ID of the scope that was closed
   */
  scopeId: string;
}

/**
 * Exception thrown when scope doesn't exist
 */
class ScopeNotCreatedException extends Error {
  /**
   * Create exception for non-existent scope
   * @param scopeId - The ID of the missing scope
   */
  constructor(scopeId: string);
  
  /**
   * ID of the scope that doesn't exist
   */
  scopeId: string;
}

/**
 * Exception thrown when scope already exists
 */
class ScopeAlreadyCreatedException extends Error {
  /**
   * Create exception for duplicate scope creation
   * @param scopeId - The ID of the existing scope
   */
  constructor(scopeId: string);
  
  /**
   * ID of the scope that already exists
   */
  scopeId: string;
}

/**
 * Exception thrown when scope definition is not found
 */
class NoScopeDefFoundException extends Error {
  /**
   * Create exception for missing scope definition
   * @param message - Error description
   */
  constructor(message: string);
  
  /**
   * The scope qualifier that was not found
   */
  scopeQualifier?: Qualifier;
}

/**
 * Exception thrown when scope value is missing
 */
class MissingScopeValueException extends Error {
  /**
   * Create exception for missing scope value
   * @param message - Error description
   */
  constructor(message: string);
}

Usage Examples:

import { 
  GlobalContext,
  ClosedScopeException,
  ScopeNotCreatedException,
  ScopeAlreadyCreatedException,
  NoScopeDefFoundException,
  named 
} from "koin-core";

class ScopeManager {
  constructor() {
    this.activeScopes = new Map();
  }
  
  async createUserSession(userId) {
    const scopeId = `session-${userId}`;
    
    try {
      const koin = GlobalContext.get();
      const scope = koin.createScope(scopeId, named("session"));
      
      this.activeScopes.set(userId, scope);
      return scope;
      
    } catch (error) {
      if (error instanceof ScopeAlreadyCreatedException) {
        console.warn(`Session scope for user ${userId} already exists`);
        // Return existing scope
        return koin.getScope(scopeId);
        
      } else if (error instanceof NoScopeDefFoundException) {
        console.error(`Session scope definition not found`);
        console.error(`Missing scope qualifier: ${error.scopeQualifier?.value}`);
        throw new Error("Session management not configured");
        
      } else {
        throw error;
      }
    }
  }
  
  async getUserSession(userId) {
    const scopeId = `session-${userId}`;
    
    try {
      const koin = GlobalContext.get();
      const scope = koin.getScope(scopeId);
      
      // Try to get user session from scope
      return scope.get(named("userSession"));
      
    } catch (error) {
      if (error instanceof ScopeNotCreatedException) {
        console.error(`No session scope found for user ${userId}`);
        // Create new session automatically
        const newScope = await this.createUserSession(userId);
        return newScope.get(named("userSession"));
        
      } else if (error instanceof ClosedScopeException) {
        console.error(`Session scope for user ${userId} is closed`);
        // Remove from active scopes and recreate
        this.activeScopes.delete(userId);
        const newScope = await this.createUserSession(userId);
        return newScope.get(named("userSession"));
        
      } else {
        throw error;
      }
    }
  }
  
  async closeUserSession(userId) {
    const scope = this.activeScopes.get(userId);
    
    if (scope) {
      try {
        scope.close();
        this.activeScopes.delete(userId);
        console.log(`Session closed for user ${userId}`);
        
      } catch (error) {
        if (error instanceof ClosedScopeException) {
          // Already closed, just clean up
          this.activeScopes.delete(userId);
        } else {
          throw error;
        }
      }
    }
  }
}

Parameter and Property Errors

Handle errors related to parameter injection and property access.

/**
 * Exception thrown when required parameter is not found
 */
class NoParameterFoundException extends Error {
  /**
   * Create exception for missing parameter
   * @param message - Error description
   */
  constructor(message: string);
  
  /**
   * Parameter index that was requested
   */
  parameterIndex?: number;
  
  /**
   * Parameter type that was requested
   */
  parameterType?: any;
}

/**
 * Exception thrown when parameter definition has errors
 */
class DefinitionParameterException extends Error {
  /**
   * Create exception for parameter definition error
   * @param message - Error description
   */
  constructor(message: string);
  
  /**
   * The definition that has parameter issues
   */
  definition?: BeanDefinition<any>;
}

/**
 * Exception thrown when property is not found
 */
class MissingPropertyException extends Error {
  /**
   * Create exception for missing property
   * @param key - The property key that was not found
   */
  constructor(key: string);
  
  /**
   * The property key that was missing
   */
  key: string;
}

/**
 * Exception thrown when property file is not found
 */
class NoPropertyFileFoundException extends Error {
  /**
   * Create exception for missing property file
   * @param message - Error description
   */
  constructor(message: string);
  
  /**
   * The property file path that was not found
   */
  filePath?: string;
}

Usage Examples:

import { 
  module,
  parametersOf,
  NoParameterFoundException,
  DefinitionParameterException,
  MissingPropertyException,
  KoinComponent 
} from "koin-core";

const dynamicModule = module((builder) => {
  builder.factory((scope, params) => {
    try {
      // Validate required parameters
      if (params.isEmpty()) {
        throw new DefinitionParameterException("Database connection requires parameters");
      }
      
      const host = params.elementAt(0);
      const port = params.elementAt(1);
      
      if (!host || !port) {
        throw new DefinitionParameterException("Host and port parameters required");
      }
      
      return new DatabaseConnection(host, port);
      
    } catch (error) {
      if (error instanceof NoParameterFoundException) {
        console.error(`Parameter missing: index ${error.parameterIndex}, type ${error.parameterType?.name}`);
        // Use default parameters
        return new DatabaseConnection("localhost", 5432);
      }
      throw error;
    }
  });
});

class ConfigurableService extends KoinComponent {
  constructor() {
    super();
    this.loadConfiguration();
  }
  
  loadConfiguration() {
    try {
      // Try to load configuration properties
      this.apiUrl = this.getProperty("api.url");
      this.timeout = this.getProperty("api.timeout", 5000);
      this.retries = this.getProperty("api.retries", 3);
      
    } catch (error) {
      if (error instanceof MissingPropertyException) {
        console.error(`Missing required property: ${error.key}`);
        
        // Provide sensible defaults
        switch (error.key) {
          case "api.url":
            this.apiUrl = "https://api.default.com";
            break;
          case "api.timeout":
            this.timeout = 5000;
            break;
          case "api.retries":
            this.retries = 3;
            break;
          default:
            throw new Error(`Required configuration missing: ${error.key}`);
        }
      } else {
        throw error;
      }
    }
  }
  
  async createConnection(host, port) {
    try {
      const connection = this.get(named("database"), () => 
        parametersOf(host, port)
      );
      return connection;
      
    } catch (error) {
      if (error instanceof DefinitionParameterException) {
        console.error(`Parameter error: ${error.message}`);
        console.error(`Definition: ${error.definition?.qualifier?.value}`);
        
        // Try with default parameters
        const defaultConnection = this.get(named("database"), () => 
          parametersOf("localhost", 5432)
        );
        return defaultConnection;
      }
      throw error;
    }
  }
}

Application State Errors

Handle errors related to application lifecycle and state management.

/**
 * Exception thrown when Koin application is already started
 */
class KoinApplicationAlreadyStartedException extends Error {
  /**
   * Create exception for duplicate application start
   * @param message - Error description
   */
  constructor(message: string);
}

/**
 * Exception thrown when trying to access Koin before it's started
 */
class IllegalStateException extends Error {
  /**
   * Create exception for illegal state access
   * @param message - Error description
   */
  constructor(message: string);
}

Usage Examples:

import { 
  startKoin,
  stopKoin,
  GlobalContext,
  KoinApplicationAlreadyStartedException,
  IllegalStateException 
} from "koin-core";

class ApplicationLifecycle {
  constructor() {
    this.isInitialized = false;
  }
  
  async start() {
    try {
      if (this.isInitialized) {
        console.log("Application already initialized");
        return;
      }
      
      startKoin((app) => {
        app.modules([coreModule, apiModule]);
        app.printLogger();
      });
      
      this.isInitialized = true;
      console.log("Application started successfully");
      
    } catch (error) {
      if (error instanceof KoinApplicationAlreadyStartedException) {
        console.warn("Koin application already started, skipping initialization");
        this.isInitialized = true;
      } else {
        console.error("Failed to start application:", error.message);
        throw error;
      }
    }
  }
  
  async stop() {
    try {
      if (!this.isInitialized) {
        console.log("Application not initialized, nothing to stop");
        return;
      }
      
      stopKoin();
      this.isInitialized = false;
      console.log("Application stopped successfully");
      
    } catch (error) {
      console.error("Error stopping application:", error.message);
      // Force cleanup
      this.isInitialized = false;
      throw error;
    }
  }
  
  getService(serviceName) {
    try {
      if (!this.isInitialized) {
        throw new IllegalStateException("Application not initialized");
      }
      
      const koin = GlobalContext.get();
      if (!koin) {
        throw new IllegalStateException("Koin container not available");
      }
      
      return koin.get(named(serviceName));
      
    } catch (error) {
      if (error instanceof IllegalStateException) {
        console.error(`Illegal state: ${error.message}`);
        throw new Error("Service not available - application not ready");
      }
      throw error;
    }
  }
}

Error Recovery and Fallback Strategies

Implement recovery strategies for robust error handling.

/**
 * Error recovery utility for dependency injection failures
 */
class DependencyRecovery {
  static createFallbackStrategy(primaryFactory, fallbackFactory) {
    return (scope, params) => {
      try {
        return primaryFactory(scope, params);
      } catch (error) {
        console.warn("Primary factory failed, using fallback:", error.message);
        return fallbackFactory(scope, params);
      }
    };
  }
  
  static createRetryStrategy(factory, maxRetries = 3, delay = 1000) {
    return async (scope, params) => {
      for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
          return await factory(scope, params);
        } catch (error) {
          if (attempt === maxRetries) {
            throw error;
          }
          console.warn(`Attempt ${attempt} failed, retrying in ${delay}ms:`, error.message);
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    };
  }
}

Usage Examples:

import { module, DependencyRecovery } from "koin-core";

const resilientModule = module((builder) => {
  // Service with fallback strategy
  builder.single(
    DependencyRecovery.createFallbackStrategy(
      (scope, params) => new PrimaryDatabaseService(),
      (scope, params) => new FallbackDatabaseService()
    )
  );
  
  // Service with retry strategy
  builder.factory(
    DependencyRecovery.createRetryStrategy(
      async (scope, params) => new ExternalApiClient(),
      3,  // max retries
      2000 // delay between retries
    )
  );
});

Types

/** Base error types for Koin dependency injection */

/** Definition and resolution errors */
class NoDefinitionFoundException extends Error {
  qualifier?: Qualifier;
  type?: any;
}

class DefinitionOverrideException extends Error {
  definition?: BeanDefinition<any>;
}

class InstanceCreationException extends Error {
  cause?: Error;
  definition?: BeanDefinition<any>;
}

/** Scope-related errors */
class ClosedScopeException extends Error {
  scopeId: string;
}

class ScopeNotCreatedException extends Error {
  scopeId: string;
}

class ScopeAlreadyCreatedException extends Error {
  scopeId: string;
}

class NoScopeDefFoundException extends Error {
  scopeQualifier?: Qualifier;
}

class MissingScopeValueException extends Error {}

/** Parameter and property errors */
class NoParameterFoundException extends Error {
  parameterIndex?: number;
  parameterType?: any;
}

class DefinitionParameterException extends Error {
  definition?: BeanDefinition<any>;
}

class MissingPropertyException extends Error {
  key: string;
}

class NoPropertyFileFoundException extends Error {
  filePath?: string;
}

/** Application state errors */
class KoinApplicationAlreadyStartedException extends Error {}

class IllegalStateException extends Error {}

Install with Tessl CLI

npx tessl i tessl/maven-io-insert-koin--koin-core-js

docs

application-startup.md

context-management.md

dependency-injection.md

error-handling.md

index.md

logging-system.md

module-system.md

qualifiers-parameters.md

scoping-lifecycle.md

tile.json