or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-core.mdapplication-lifecycle.mdindex.mdplugin-management.mdservice-resolution.md

service-resolution.mddocs/

0

# Service Resolution

1

2

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.

3

4

## Capabilities

5

6

### Required Service Resolution

7

8

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

9

10

```typescript { .api }

11

/**

12

* Resolve a required service of a given type.

13

* @param token - The token for the service type of interest

14

* @returns A promise which resolves to an instance of the requested service, or rejects if it cannot be resolved

15

*/

16

resolveRequiredService<U>(token: Token<U>): Promise<U>;

17

```

18

19

**Usage Example:**

20

21

```typescript

22

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

23

24

// Define a service token

25

interface IDataService {

26

getData(): Promise<any[]>;

27

saveData(data: any): Promise<void>;

28

}

29

30

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

31

32

// Register a plugin that provides the service

33

app.registerPlugin({

34

id: 'data-provider',

35

provides: IDataService,

36

activate: () => ({

37

getData: async () => [{ id: 1, name: 'Sample' }],

38

saveData: async (data) => console.log('Saving:', data)

39

})

40

});

41

42

// Resolve the required service

43

try {

44

const dataService = await app.resolveRequiredService(IDataService);

45

const data = await dataService.getData();

46

console.log('Retrieved data:', data);

47

} catch (error) {

48

console.error('Failed to resolve required service:', error);

49

}

50

```

51

52

### Optional Service Resolution

53

54

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

55

56

```typescript { .api }

57

/**

58

* Resolve an optional service of a given type.

59

* @param token - The token for the service type of interest

60

* @returns A promise which resolves to an instance of the requested service, or null if it cannot be resolved

61

*/

62

resolveOptionalService<U>(token: Token<U>): Promise<U | null>;

63

```

64

65

**Usage Example:**

66

67

```typescript

68

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

69

70

// Define optional service tokens

71

interface IThemeService {

72

setTheme(theme: string): void;

73

getTheme(): string;

74

}

75

76

interface IAnalyticsService {

77

track(event: string, data?: any): void;

78

}

79

80

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

81

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

82

83

// Register plugins that provide optional services

84

app.registerPlugin({

85

id: 'theme-provider',

86

provides: IThemeService,

87

activate: () => ({

88

setTheme: (theme: string) => document.body.className = `theme-${theme}`,

89

getTheme: () => 'default'

90

})

91

});

92

93

// Resolve optional services

94

const themeService = await app.resolveOptionalService(IThemeService);

95

if (themeService) {

96

themeService.setTheme('dark');

97

console.log('Theme service available');

98

} else {

99

console.log('Theme service not available, using defaults');

100

}

101

102

const analyticsService = await app.resolveOptionalService(IAnalyticsService);

103

if (analyticsService) {

104

analyticsService.track('app-started');

105

} else {

106

console.log('Analytics service not available');

107

}

108

```

109

110

### Service Tokens

111

112

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

113

114

```typescript { .api }

115

interface Token<T> {

116

readonly name: string;

117

}

118

119

// Token constructor (from @lumino/coreutils)

120

// new Token<T>(name: string): Token<T>

121

```

122

123

**Token Creation Examples:**

124

125

```typescript

126

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

127

128

// Service interface definitions

129

interface ILoggerService {

130

log(message: string): void;

131

error(message: string): void;

132

warn(message: string): void;

133

}

134

135

interface IConfigService {

136

get<T>(key: string): T | undefined;

137

set<T>(key: string, value: T): void;

138

}

139

140

interface INotificationService {

141

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

142

}

143

144

// Create service tokens

145

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

146

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

147

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

148

149

// Use tokens for service resolution

150

const logger = await app.resolveRequiredService(ILoggerService);

151

const config = await app.resolveOptionalService(IConfigService);

152

const notifications = await app.resolveOptionalService(INotificationService);

153

```

154

155

### Service Dependencies in Plugins

156

157

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

158

159

```typescript { .api }

160

interface IPlugin<T = any, U = any> {

161

// ... other properties

162

/** Array of tokens for services this plugin requires */

163

requires?: Token<any>[];

164

/** Array of tokens for services this plugin optionally uses */

165

optional?: Token<any>[];

166

}

167

```

168

169

**Plugin with Service Dependencies:**

170

171

```typescript

172

// Plugin that requires logger and optionally uses config

173

const myPlugin: IPlugin<Application> = {

174

id: 'my-feature',

175

description: 'Feature with service dependencies',

176

requires: [ILoggerService],

177

optional: [IConfigService, INotificationService],

178

activate: (app: Application, logger: ILoggerService, config?: IConfigService, notifications?: INotificationService) => {

179

logger.log('My feature plugin activated');

180

181

// Use required service

182

logger.log('Initializing feature...');

183

184

// Use optional services if available

185

if (config) {

186

const setting = config.get<string>('my-feature.setting');

187

logger.log(`Using setting: ${setting}`);

188

}

189

190

if (notifications) {

191

notifications.show('Feature activated successfully!', 'info');

192

}

193

194

return {

195

doSomething: () => logger.log('Doing something...')

196

};

197

}

198

};

199

200

app.registerPlugin(myPlugin);

201

```

202

203

### Service Resolution Notes

204

205

**Important Behaviors:**

206

207

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

208

209

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

210

211

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

212

213

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

214

215

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

216

217

**Best Practices:**

218

219

- Use descriptive names for service tokens to avoid conflicts

220

- Define clear service interfaces with TypeScript types

221

- Handle optional services gracefully with null checks

222

- Prefer composition over inheritance when designing services

223

- Keep service interfaces focused and cohesive