CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-lumino--application

Pluggable application framework for building extensible desktop-like web applications with plugin architecture support

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

service-resolution.mddocs/

Service Resolution

Dependency injection system for resolving plugin services with support for both required and optional dependencies. The Application class provides service resolution capabilities through its integrated PluginRegistry.

Capabilities

Required Service Resolution

Resolve services that must be available for the application to function correctly.

/**
 * Resolve a required service of a given type.
 * @param token - The token for the service type of interest
 * @returns A promise which resolves to an instance of the requested service, or rejects if it cannot be resolved
 */
resolveRequiredService<U>(token: Token<U>): Promise<U>;

Usage Example:

import { Token } from "@lumino/coreutils";

// Define a service token
interface IDataService {
  getData(): Promise<any[]>;
  saveData(data: any): Promise<void>;
}

const IDataService = new Token<IDataService>('IDataService');

// Register a plugin that provides the service
app.registerPlugin({
  id: 'data-provider',
  provides: IDataService,
  activate: () => ({
    getData: async () => [{ id: 1, name: 'Sample' }],
    saveData: async (data) => console.log('Saving:', data)
  })
});

// Resolve the required service
try {
  const dataService = await app.resolveRequiredService(IDataService);
  const data = await dataService.getData();
  console.log('Retrieved data:', data);
} catch (error) {
  console.error('Failed to resolve required service:', error);
}

Optional Service Resolution

Resolve services that are optional - the application can function without them.

/**
 * Resolve an optional service of a given type.
 * @param token - The token for the service type of interest
 * @returns A promise which resolves to an instance of the requested service, or null if it cannot be resolved
 */
resolveOptionalService<U>(token: Token<U>): Promise<U | null>;

Usage Example:

import { Token } from "@lumino/coreutils";

// Define optional service tokens
interface IThemeService {
  setTheme(theme: string): void;
  getTheme(): string;
}

interface IAnalyticsService {
  track(event: string, data?: any): void;
}

const IThemeService = new Token<IThemeService>('IThemeService');
const IAnalyticsService = new Token<IAnalyticsService>('IAnalyticsService');

// Register plugins that provide optional services
app.registerPlugin({
  id: 'theme-provider',
  provides: IThemeService,
  activate: () => ({
    setTheme: (theme: string) => document.body.className = `theme-${theme}`,
    getTheme: () => 'default'
  })
});

// Resolve optional services
const themeService = await app.resolveOptionalService(IThemeService);
if (themeService) {
  themeService.setTheme('dark');
  console.log('Theme service available');
} else {
  console.log('Theme service not available, using defaults');
}

const analyticsService = await app.resolveOptionalService(IAnalyticsService);
if (analyticsService) {
  analyticsService.track('app-started');
} else {
  console.log('Analytics service not available');
}

Service Tokens

Service tokens are used to identify and request specific services. They are created using the Token class from @lumino/coreutils.

interface Token<T> {
  readonly name: string;
}

// Token constructor (from @lumino/coreutils)
// new Token<T>(name: string): Token<T>

Token Creation Examples:

import { Token } from "@lumino/coreutils";

// Service interface definitions
interface ILoggerService {
  log(message: string): void;
  error(message: string): void;
  warn(message: string): void;
}

interface IConfigService {
  get<T>(key: string): T | undefined;
  set<T>(key: string, value: T): void;
}

interface INotificationService {
  show(message: string, type?: 'info' | 'warning' | 'error'): void;
}

// Create service tokens
const ILoggerService = new Token<ILoggerService>('ILoggerService');
const IConfigService = new Token<IConfigService>('IConfigService');  
const INotificationService = new Token<INotificationService>('INotificationService');

// Use tokens for service resolution
const logger = await app.resolveRequiredService(ILoggerService);
const config = await app.resolveOptionalService(IConfigService);
const notifications = await app.resolveOptionalService(INotificationService);

Service Dependencies in Plugins

Plugins can declare service dependencies that will be automatically resolved when the plugin is activated.

interface IPlugin<T = any, U = any> {
  // ... other properties
  /** Array of tokens for services this plugin requires */
  requires?: Token<any>[];
  /** Array of tokens for services this plugin optionally uses */
  optional?: Token<any>[];
}

Plugin with Service Dependencies:

// Plugin that requires logger and optionally uses config
const myPlugin: IPlugin<Application> = {
  id: 'my-feature',
  description: 'Feature with service dependencies',
  requires: [ILoggerService],
  optional: [IConfigService, INotificationService],
  activate: (app: Application, logger: ILoggerService, config?: IConfigService, notifications?: INotificationService) => {
    logger.log('My feature plugin activated');
    
    // Use required service
    logger.log('Initializing feature...');
    
    // Use optional services if available
    if (config) {
      const setting = config.get<string>('my-feature.setting');
      logger.log(`Using setting: ${setting}`);
    }
    
    if (notifications) {
      notifications.show('Feature activated successfully!', 'info');
    }
    
    return {
      doSomething: () => logger.log('Doing something...')
    };
  }
};

app.registerPlugin(myPlugin);

Service Resolution Notes

Important Behaviors:

  1. Automatic Activation: If a plugin providing a required service hasn't been activated yet, resolving the service will automatically activate that plugin.

  2. Singletons: Services are singletons - the same instance is returned each time a service token is resolved.

  3. Dependency Order: Plugins are activated in dependency order - plugins providing services are activated before plugins that require them.

  4. Circular Dependencies: The plugin system detects and prevents circular dependency chains.

  5. Error Handling: Required service resolution throws an error if the service cannot be provided, while optional service resolution returns null.

Best Practices:

  • Use descriptive names for service tokens to avoid conflicts
  • Define clear service interfaces with TypeScript types
  • Handle optional services gracefully with null checks
  • Prefer composition over inheritance when designing services
  • Keep service interfaces focused and cohesive

docs

application-core.md

application-lifecycle.md

index.md

plugin-management.md

service-resolution.md

tile.json