@twin.org/engine-core 0.0.1 → 0.0.2-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ var node_worker_threads = require('node:worker_threads');
3
4
  var core = require('@twin.org/core');
4
5
  var entity = require('@twin.org/entity');
5
6
  var loggingConnectorConsole = require('@twin.org/logging-connector-console');
6
7
  var loggingModels = require('@twin.org/logging-models');
8
+ var loggingService = require('@twin.org/logging-service');
7
9
  var modules = require('@twin.org/modules');
8
10
  var promises = require('node:fs/promises');
9
11
  var path = require('node:path');
@@ -72,10 +74,16 @@ class EngineCore {
72
74
  * Name for the engine logger.
73
75
  */
74
76
  static LOGGER_TYPE_NAME = "engine";
77
+ /**
78
+ * Runtime name for the class in camel case.
79
+ * @internal
80
+ */
81
+ static _CLASS_NAME_CAMEL_CASE = core.StringHelper.camelCase("EngineCore");
75
82
  /**
76
83
  * Runtime name for the class.
84
+ * @internal
77
85
  */
78
- CLASS_NAME = "EngineCore";
86
+ static _CLASS_NAME = "EngineCore";
79
87
  /**
80
88
  * The core context.
81
89
  */
@@ -86,10 +94,10 @@ class EngineCore {
86
94
  */
87
95
  _stateStorage;
88
96
  /**
89
- * The logging connector for the engine.
97
+ * The logging component for the engine.
90
98
  * @internal
91
99
  */
92
- _engineLoggingConnector;
100
+ _engineLoggingComponent;
93
101
  /**
94
102
  * Skip the bootstrap process.
95
103
  * @internal
@@ -110,6 +118,11 @@ class EngineCore {
110
118
  * @internal
111
119
  */
112
120
  _isStarted;
121
+ /**
122
+ * Is the engine a clone.
123
+ * @internal
124
+ */
125
+ _isClone;
113
126
  /**
114
127
  * Add type initialisers to the engine.
115
128
  * @internal
@@ -137,13 +150,14 @@ class EngineCore {
137
150
  this._typeInitialisers = [];
138
151
  this._context = {
139
152
  config: options.config,
140
- defaultTypes: {},
153
+ registeredInstances: {},
141
154
  componentInstances: [],
142
- state: { componentStates: {} },
155
+ state: {},
143
156
  stateDirty: false
144
157
  };
145
158
  this._stateStorage = options.stateStorage;
146
159
  this._isStarted = false;
160
+ this._isClone = false;
147
161
  if (core.Is.function(this._populateTypeInitialisers)) {
148
162
  this._populateTypeInitialisers(this, this._context);
149
163
  }
@@ -174,9 +188,9 @@ class EngineCore {
174
188
  return false;
175
189
  }
176
190
  this.setupEngineLogger();
177
- this.logInfo(core.I18n.formatMessage("engineCore.starting"));
191
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.starting`));
178
192
  if (this._context.config.debug) {
179
- this.logInfo(core.I18n.formatMessage("engineCore.debuggingEnabled"));
193
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.debuggingEnabled`));
180
194
  }
181
195
  let canContinue;
182
196
  try {
@@ -186,25 +200,18 @@ class EngineCore {
186
200
  await this.initialiseTypeConfig(type, typeConfig, module, method);
187
201
  }
188
202
  await this.bootstrap();
189
- this.logInfo(core.I18n.formatMessage("engineCore.componentsStarting"));
203
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStarting`));
190
204
  for (const instance of this._context.componentInstances) {
191
205
  if (core.Is.function(instance.component.start)) {
192
- const instanceName = this.getInstanceName(instance);
193
- this.logInfo(core.I18n.formatMessage("engineCore.componentStarting", {
206
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStarting`, {
194
207
  element: instance.instanceType
195
208
  }));
196
- const componentState = this._context.state.componentStates[instanceName] ?? {};
197
- const lastState = core.ObjectHelper.clone(componentState);
198
- await instance.component.start(this._context.state.nodeIdentity, this._loggerTypeName, componentState);
199
- if (!core.ObjectHelper.equal(lastState, componentState)) {
200
- this._context.state.componentStates[instanceName] = componentState;
201
- this._context.stateDirty = true;
202
- }
209
+ await instance.component.start(this._context.state.nodeIdentity, this._loggerTypeName);
203
210
  }
204
211
  }
205
- this.logInfo(core.I18n.formatMessage("engineCore.componentsComplete"));
212
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsComplete`));
206
213
  }
207
- this.logInfo(core.I18n.formatMessage("engineCore.started"));
214
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.started`));
208
215
  this._isStarted = true;
209
216
  }
210
217
  catch (err) {
@@ -223,39 +230,55 @@ class EngineCore {
223
230
  * @returns Nothing.
224
231
  */
225
232
  async stop() {
226
- this.logInfo(core.I18n.formatMessage("engineCore.stopping"));
227
- this.logInfo(core.I18n.formatMessage("engineCore.componentsStopping"));
233
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopping`));
234
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopping`));
228
235
  for (const instance of this._context.componentInstances) {
229
236
  if (core.Is.function(instance.component.stop)) {
230
- const instanceName = this.getInstanceName(instance);
231
- const componentState = this._context.state.componentStates[instanceName] ?? {};
232
- const lastState = core.ObjectHelper.clone(componentState);
233
- this.logInfo(core.I18n.formatMessage("engineCore.componentStopping", { element: instance.instanceType }));
237
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStopping`, {
238
+ element: instance.instanceType
239
+ }));
234
240
  try {
235
- await instance.component.stop(this._context.state.nodeIdentity, this._loggerTypeName, componentState);
236
- if (!core.ObjectHelper.equal(lastState, componentState)) {
237
- this._context.state.componentStates[instanceName] = componentState;
238
- this._context.stateDirty = true;
239
- }
241
+ await instance.component.stop(this._context.state.nodeIdentity, this._loggerTypeName);
240
242
  }
241
243
  catch (err) {
242
- this.logError(new core.GeneralError(this.CLASS_NAME, "componentStopFailed", {
244
+ this.logError(new core.GeneralError(EngineCore._CLASS_NAME, "componentStopFailed", {
243
245
  component: instance.instanceType
244
246
  }, core.BaseError.fromError(err)));
245
247
  }
246
248
  }
247
249
  }
248
250
  await this.stateSave();
249
- this.logInfo(core.I18n.formatMessage("engineCore.componentsStopped"));
250
- this.logInfo(core.I18n.formatMessage("engineCore.stopped"));
251
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopped`));
252
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopped`));
253
+ }
254
+ /**
255
+ * Is the engine started.
256
+ * @returns True if the engine is started.
257
+ */
258
+ isStarted() {
259
+ return this._isStarted;
260
+ }
261
+ /**
262
+ * Is this the primary engine instance.
263
+ * @returns True if the engine is the primary instance.
264
+ */
265
+ isPrimary() {
266
+ return node_worker_threads.isMainThread && !this._isClone;
267
+ }
268
+ /**
269
+ * Is this engine instance a clone.
270
+ * @returns True if the engine instance is a clone.
271
+ */
272
+ isClone() {
273
+ return this._isClone;
251
274
  }
252
275
  /**
253
276
  * Log info.
254
277
  * @param message The message to log.
255
278
  */
256
279
  logInfo(message) {
257
- this._engineLoggingConnector?.log({
258
- source: this.CLASS_NAME,
280
+ this._engineLoggingComponent?.log({
281
+ source: EngineCore._CLASS_NAME,
259
282
  level: "info",
260
283
  message
261
284
  });
@@ -273,8 +296,8 @@ class EngineCore {
273
296
  if (this._context.config.debug && core.Is.stringValue(formattedError.stack)) {
274
297
  message += `\n${formattedError.stack}`;
275
298
  }
276
- this._engineLoggingConnector?.log({
277
- source: this.CLASS_NAME,
299
+ this._engineLoggingComponent?.log({
300
+ source: EngineCore._CLASS_NAME,
278
301
  level: "error",
279
302
  message
280
303
  });
@@ -295,11 +318,48 @@ class EngineCore {
295
318
  return this._context.state;
296
319
  }
297
320
  /**
298
- * Get the types for the component.
299
- * @returns The default types.
321
+ * Get all the registered instances.
322
+ * @returns The registered instances.
300
323
  */
301
- getDefaultTypes() {
302
- return this._context.defaultTypes;
324
+ getRegisteredInstances() {
325
+ return this._context.registeredInstances;
326
+ }
327
+ /**
328
+ * Get the registered instance type for the component/connector.
329
+ * @param componentConnectorType The type of the component/connector.
330
+ * @param features The requested features of the component, if not specified the default entry will be retrieved.
331
+ * @returns The instance type matching the criteria if one is registered.
332
+ * @throws If a matching instance was not found.
333
+ */
334
+ getRegisteredInstanceType(componentConnectorType, features) {
335
+ core.Guards.stringValue(EngineCore._CLASS_NAME, "componentConnectorType", componentConnectorType);
336
+ const registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);
337
+ if (!core.Is.stringValue(registeredType)) {
338
+ throw new core.GeneralError(EngineCore._CLASS_NAME, "instanceTypeNotFound", {
339
+ type: componentConnectorType,
340
+ features: (features ?? ["default"]).join(",")
341
+ });
342
+ }
343
+ return registeredType;
344
+ }
345
+ /**
346
+ * Get the registered instance type for the component/connector if it exists.
347
+ * @param componentConnectorType The type of the component/connector.
348
+ * @param features The requested features of the component, if not specified the default entry will be retrieved.
349
+ * @returns The instance type matching the criteria if one is registered.
350
+ */
351
+ getRegisteredInstanceTypeOptional(componentConnectorType, features) {
352
+ let registeredType;
353
+ const registeredTypes = this._context.registeredInstances[componentConnectorType];
354
+ if (core.Is.arrayValue(registeredTypes)) {
355
+ if (core.Is.arrayValue(features)) {
356
+ registeredType = registeredTypes.find(t => t.features?.every(f => features.includes(f)))?.type;
357
+ }
358
+ else {
359
+ registeredType = registeredTypes[0]?.type;
360
+ }
361
+ }
362
+ return registeredType;
303
363
  }
304
364
  /**
305
365
  * Get the data required to create a clone of the engine.
@@ -326,20 +386,21 @@ class EngineCore {
326
386
  * @param silent Should the clone be silent.
327
387
  */
328
388
  populateClone(cloneData, silent) {
329
- core.Guards.object(this.CLASS_NAME, "cloneData", cloneData);
330
- core.Guards.object(this.CLASS_NAME, "cloneData.config", cloneData.config);
331
- core.Guards.object(this.CLASS_NAME, "cloneData.state", cloneData.state);
332
- core.Guards.array(this.CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
389
+ core.Guards.object(EngineCore._CLASS_NAME, "cloneData", cloneData);
390
+ core.Guards.object(EngineCore._CLASS_NAME, "cloneData.config", cloneData.config);
391
+ core.Guards.object(EngineCore._CLASS_NAME, "cloneData.state", cloneData.state);
392
+ core.Guards.array(EngineCore._CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
333
393
  this._loggerTypeName = cloneData.loggerTypeName;
334
394
  this._skipBootstrap = true;
395
+ this._isClone = true;
335
396
  if (silent ?? false) {
336
397
  cloneData.config.silent = true;
337
398
  }
338
399
  this._context = {
339
400
  config: cloneData.config,
340
- defaultTypes: {},
401
+ registeredInstances: {},
341
402
  componentInstances: [],
342
- state: { componentStates: {} },
403
+ state: {},
343
404
  stateDirty: false
344
405
  };
345
406
  this._typeInitialisers = cloneData.typeInitialisers;
@@ -360,9 +421,20 @@ class EngineCore {
360
421
  const instanceMethod = await modules.ModuleHelper.getModuleEntry(module, method);
361
422
  for (let i = 0; i < typeConfig.length; i++) {
362
423
  const instanceType = instanceMethod(this, this._context, typeConfig[i], typeConfig[i].overrideInstanceType);
363
- if (core.Is.stringValue(instanceType) &&
364
- (core.Is.empty(this._context.defaultTypes[typeKey]) || typeConfig[i].isDefault)) {
365
- this._context.defaultTypes[typeKey] = instanceType;
424
+ if (core.Is.stringValue(instanceType)) {
425
+ this._context.registeredInstances[typeKey] ??= [];
426
+ if (typeConfig[i].isDefault ?? false) {
427
+ this._context.registeredInstances[typeKey].unshift({
428
+ type: instanceType,
429
+ features: typeConfig[i].features
430
+ });
431
+ }
432
+ else {
433
+ this._context.registeredInstances[typeKey].push({
434
+ type: instanceType,
435
+ features: typeConfig[i].features
436
+ });
437
+ }
366
438
  }
367
439
  }
368
440
  }
@@ -373,7 +445,7 @@ class EngineCore {
373
445
  */
374
446
  setupEngineLogger() {
375
447
  const silent = this._context.config.silent ?? false;
376
- const engineLogger = silent
448
+ const engineLoggerConnector = silent
377
449
  ? new loggingModels.SilentLoggingConnector()
378
450
  : new loggingConnectorConsole.ConsoleLoggingConnector({
379
451
  config: {
@@ -383,11 +455,24 @@ class EngineCore {
383
455
  });
384
456
  this._context.componentInstances.push({
385
457
  instanceType: this._loggerTypeName,
386
- component: engineLogger
458
+ component: engineLoggerConnector
387
459
  });
388
- loggingModels.LoggingConnectorFactory.register(this._loggerTypeName, () => engineLogger);
389
- this._engineLoggingConnector = engineLogger;
390
- this._context.defaultTypes.loggingConnector = this._loggerTypeName;
460
+ loggingModels.LoggingConnectorFactory.register(this._loggerTypeName, () => engineLoggerConnector);
461
+ this._context.registeredInstances.loggingConnector = [
462
+ {
463
+ type: this._loggerTypeName
464
+ }
465
+ ];
466
+ const engineLoggerComponent = new loggingService.LoggingService({
467
+ loggingConnectorType: this._loggerTypeName
468
+ });
469
+ this._engineLoggingComponent = engineLoggerComponent;
470
+ core.ComponentFactory.register("logging-service", () => engineLoggerComponent);
471
+ this._context.registeredInstances.loggingComponent = [
472
+ {
473
+ type: "logging-service"
474
+ }
475
+ ];
391
476
  }
392
477
  /**
393
478
  * Load the state.
@@ -397,10 +482,7 @@ class EngineCore {
397
482
  async stateLoad() {
398
483
  if (this._stateStorage) {
399
484
  try {
400
- this._context.state = ((await this._stateStorage.load(this)) ?? {
401
- componentStates: {}
402
- });
403
- this._context.state.componentStates ??= {};
485
+ this._context.state = ((await this._stateStorage.load(this)) ?? {});
404
486
  this._context.stateDirty = false;
405
487
  return true;
406
488
  }
@@ -436,34 +518,28 @@ class EngineCore {
436
518
  */
437
519
  async bootstrap() {
438
520
  if (!this._skipBootstrap) {
439
- this.logInfo(core.I18n.formatMessage("engineCore.bootstrapStarted"));
521
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapStarted`));
440
522
  // First bootstrap the components.
441
523
  for (const instance of this._context.componentInstances) {
442
524
  if (core.Is.function(instance.component.bootstrap)) {
443
525
  const instanceName = this.getInstanceName(instance);
444
- this.logInfo(core.I18n.formatMessage("engineCore.bootstrapping", {
526
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapping`, {
445
527
  element: instanceName
446
528
  }));
447
- const componentState = this._context.state.componentStates[instanceName] ?? {};
448
- const lastState = core.ObjectHelper.clone(componentState);
449
- const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName, componentState);
529
+ const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName);
450
530
  // If the bootstrap method failed then throw an error
451
531
  if (!bootstrapSuccess) {
452
- throw new core.GeneralError(this.CLASS_NAME, "bootstrapFailed", {
532
+ throw new core.GeneralError(EngineCore._CLASS_NAME, "bootstrapFailed", {
453
533
  component: `${instance.component.CLASS_NAME}:${instance.instanceType}`
454
534
  });
455
535
  }
456
- if (!core.ObjectHelper.equal(lastState, componentState)) {
457
- this._context.state.componentStates[instanceName] = componentState;
458
- this._context.stateDirty = true;
459
- }
460
536
  }
461
537
  }
462
538
  // Now perform any custom bootstrap operations
463
539
  if (core.Is.function(this._customBootstrap)) {
464
540
  await this._customBootstrap(this, this._context);
465
541
  }
466
- this.logInfo(core.I18n.formatMessage("engineCore.bootstrapComplete"));
542
+ this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapComplete`));
467
543
  }
468
544
  }
469
545
  /**
@@ -1,7 +1,9 @@
1
- import { I18n, StringHelper, Is, ObjectHelper, BaseError, GeneralError, ErrorHelper, Guards } from '@twin.org/core';
1
+ import { isMainThread } from 'node:worker_threads';
2
+ import { I18n, StringHelper, Is, BaseError, GeneralError, ErrorHelper, Guards, ComponentFactory } from '@twin.org/core';
2
3
  import { EntitySchemaFactory } from '@twin.org/entity';
3
4
  import { ConsoleLoggingConnector } from '@twin.org/logging-connector-console';
4
5
  import { SilentLoggingConnector, LoggingConnectorFactory } from '@twin.org/logging-models';
6
+ import { LoggingService } from '@twin.org/logging-service';
5
7
  import { ModuleHelper } from '@twin.org/modules';
6
8
  import { readFile, mkdir, writeFile, stat } from 'node:fs/promises';
7
9
  import path from 'node:path';
@@ -70,10 +72,16 @@ class EngineCore {
70
72
  * Name for the engine logger.
71
73
  */
72
74
  static LOGGER_TYPE_NAME = "engine";
75
+ /**
76
+ * Runtime name for the class in camel case.
77
+ * @internal
78
+ */
79
+ static _CLASS_NAME_CAMEL_CASE = StringHelper.camelCase("EngineCore");
73
80
  /**
74
81
  * Runtime name for the class.
82
+ * @internal
75
83
  */
76
- CLASS_NAME = "EngineCore";
84
+ static _CLASS_NAME = "EngineCore";
77
85
  /**
78
86
  * The core context.
79
87
  */
@@ -84,10 +92,10 @@ class EngineCore {
84
92
  */
85
93
  _stateStorage;
86
94
  /**
87
- * The logging connector for the engine.
95
+ * The logging component for the engine.
88
96
  * @internal
89
97
  */
90
- _engineLoggingConnector;
98
+ _engineLoggingComponent;
91
99
  /**
92
100
  * Skip the bootstrap process.
93
101
  * @internal
@@ -108,6 +116,11 @@ class EngineCore {
108
116
  * @internal
109
117
  */
110
118
  _isStarted;
119
+ /**
120
+ * Is the engine a clone.
121
+ * @internal
122
+ */
123
+ _isClone;
111
124
  /**
112
125
  * Add type initialisers to the engine.
113
126
  * @internal
@@ -135,13 +148,14 @@ class EngineCore {
135
148
  this._typeInitialisers = [];
136
149
  this._context = {
137
150
  config: options.config,
138
- defaultTypes: {},
151
+ registeredInstances: {},
139
152
  componentInstances: [],
140
- state: { componentStates: {} },
153
+ state: {},
141
154
  stateDirty: false
142
155
  };
143
156
  this._stateStorage = options.stateStorage;
144
157
  this._isStarted = false;
158
+ this._isClone = false;
145
159
  if (Is.function(this._populateTypeInitialisers)) {
146
160
  this._populateTypeInitialisers(this, this._context);
147
161
  }
@@ -172,9 +186,9 @@ class EngineCore {
172
186
  return false;
173
187
  }
174
188
  this.setupEngineLogger();
175
- this.logInfo(I18n.formatMessage("engineCore.starting"));
189
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.starting`));
176
190
  if (this._context.config.debug) {
177
- this.logInfo(I18n.formatMessage("engineCore.debuggingEnabled"));
191
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.debuggingEnabled`));
178
192
  }
179
193
  let canContinue;
180
194
  try {
@@ -184,25 +198,18 @@ class EngineCore {
184
198
  await this.initialiseTypeConfig(type, typeConfig, module, method);
185
199
  }
186
200
  await this.bootstrap();
187
- this.logInfo(I18n.formatMessage("engineCore.componentsStarting"));
201
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStarting`));
188
202
  for (const instance of this._context.componentInstances) {
189
203
  if (Is.function(instance.component.start)) {
190
- const instanceName = this.getInstanceName(instance);
191
- this.logInfo(I18n.formatMessage("engineCore.componentStarting", {
204
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStarting`, {
192
205
  element: instance.instanceType
193
206
  }));
194
- const componentState = this._context.state.componentStates[instanceName] ?? {};
195
- const lastState = ObjectHelper.clone(componentState);
196
- await instance.component.start(this._context.state.nodeIdentity, this._loggerTypeName, componentState);
197
- if (!ObjectHelper.equal(lastState, componentState)) {
198
- this._context.state.componentStates[instanceName] = componentState;
199
- this._context.stateDirty = true;
200
- }
207
+ await instance.component.start(this._context.state.nodeIdentity, this._loggerTypeName);
201
208
  }
202
209
  }
203
- this.logInfo(I18n.formatMessage("engineCore.componentsComplete"));
210
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsComplete`));
204
211
  }
205
- this.logInfo(I18n.formatMessage("engineCore.started"));
212
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.started`));
206
213
  this._isStarted = true;
207
214
  }
208
215
  catch (err) {
@@ -221,39 +228,55 @@ class EngineCore {
221
228
  * @returns Nothing.
222
229
  */
223
230
  async stop() {
224
- this.logInfo(I18n.formatMessage("engineCore.stopping"));
225
- this.logInfo(I18n.formatMessage("engineCore.componentsStopping"));
231
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopping`));
232
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopping`));
226
233
  for (const instance of this._context.componentInstances) {
227
234
  if (Is.function(instance.component.stop)) {
228
- const instanceName = this.getInstanceName(instance);
229
- const componentState = this._context.state.componentStates[instanceName] ?? {};
230
- const lastState = ObjectHelper.clone(componentState);
231
- this.logInfo(I18n.formatMessage("engineCore.componentStopping", { element: instance.instanceType }));
235
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStopping`, {
236
+ element: instance.instanceType
237
+ }));
232
238
  try {
233
- await instance.component.stop(this._context.state.nodeIdentity, this._loggerTypeName, componentState);
234
- if (!ObjectHelper.equal(lastState, componentState)) {
235
- this._context.state.componentStates[instanceName] = componentState;
236
- this._context.stateDirty = true;
237
- }
239
+ await instance.component.stop(this._context.state.nodeIdentity, this._loggerTypeName);
238
240
  }
239
241
  catch (err) {
240
- this.logError(new GeneralError(this.CLASS_NAME, "componentStopFailed", {
242
+ this.logError(new GeneralError(EngineCore._CLASS_NAME, "componentStopFailed", {
241
243
  component: instance.instanceType
242
244
  }, BaseError.fromError(err)));
243
245
  }
244
246
  }
245
247
  }
246
248
  await this.stateSave();
247
- this.logInfo(I18n.formatMessage("engineCore.componentsStopped"));
248
- this.logInfo(I18n.formatMessage("engineCore.stopped"));
249
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopped`));
250
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopped`));
251
+ }
252
+ /**
253
+ * Is the engine started.
254
+ * @returns True if the engine is started.
255
+ */
256
+ isStarted() {
257
+ return this._isStarted;
258
+ }
259
+ /**
260
+ * Is this the primary engine instance.
261
+ * @returns True if the engine is the primary instance.
262
+ */
263
+ isPrimary() {
264
+ return isMainThread && !this._isClone;
265
+ }
266
+ /**
267
+ * Is this engine instance a clone.
268
+ * @returns True if the engine instance is a clone.
269
+ */
270
+ isClone() {
271
+ return this._isClone;
249
272
  }
250
273
  /**
251
274
  * Log info.
252
275
  * @param message The message to log.
253
276
  */
254
277
  logInfo(message) {
255
- this._engineLoggingConnector?.log({
256
- source: this.CLASS_NAME,
278
+ this._engineLoggingComponent?.log({
279
+ source: EngineCore._CLASS_NAME,
257
280
  level: "info",
258
281
  message
259
282
  });
@@ -271,8 +294,8 @@ class EngineCore {
271
294
  if (this._context.config.debug && Is.stringValue(formattedError.stack)) {
272
295
  message += `\n${formattedError.stack}`;
273
296
  }
274
- this._engineLoggingConnector?.log({
275
- source: this.CLASS_NAME,
297
+ this._engineLoggingComponent?.log({
298
+ source: EngineCore._CLASS_NAME,
276
299
  level: "error",
277
300
  message
278
301
  });
@@ -293,11 +316,48 @@ class EngineCore {
293
316
  return this._context.state;
294
317
  }
295
318
  /**
296
- * Get the types for the component.
297
- * @returns The default types.
319
+ * Get all the registered instances.
320
+ * @returns The registered instances.
298
321
  */
299
- getDefaultTypes() {
300
- return this._context.defaultTypes;
322
+ getRegisteredInstances() {
323
+ return this._context.registeredInstances;
324
+ }
325
+ /**
326
+ * Get the registered instance type for the component/connector.
327
+ * @param componentConnectorType The type of the component/connector.
328
+ * @param features The requested features of the component, if not specified the default entry will be retrieved.
329
+ * @returns The instance type matching the criteria if one is registered.
330
+ * @throws If a matching instance was not found.
331
+ */
332
+ getRegisteredInstanceType(componentConnectorType, features) {
333
+ Guards.stringValue(EngineCore._CLASS_NAME, "componentConnectorType", componentConnectorType);
334
+ const registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);
335
+ if (!Is.stringValue(registeredType)) {
336
+ throw new GeneralError(EngineCore._CLASS_NAME, "instanceTypeNotFound", {
337
+ type: componentConnectorType,
338
+ features: (features ?? ["default"]).join(",")
339
+ });
340
+ }
341
+ return registeredType;
342
+ }
343
+ /**
344
+ * Get the registered instance type for the component/connector if it exists.
345
+ * @param componentConnectorType The type of the component/connector.
346
+ * @param features The requested features of the component, if not specified the default entry will be retrieved.
347
+ * @returns The instance type matching the criteria if one is registered.
348
+ */
349
+ getRegisteredInstanceTypeOptional(componentConnectorType, features) {
350
+ let registeredType;
351
+ const registeredTypes = this._context.registeredInstances[componentConnectorType];
352
+ if (Is.arrayValue(registeredTypes)) {
353
+ if (Is.arrayValue(features)) {
354
+ registeredType = registeredTypes.find(t => t.features?.every(f => features.includes(f)))?.type;
355
+ }
356
+ else {
357
+ registeredType = registeredTypes[0]?.type;
358
+ }
359
+ }
360
+ return registeredType;
301
361
  }
302
362
  /**
303
363
  * Get the data required to create a clone of the engine.
@@ -324,20 +384,21 @@ class EngineCore {
324
384
  * @param silent Should the clone be silent.
325
385
  */
326
386
  populateClone(cloneData, silent) {
327
- Guards.object(this.CLASS_NAME, "cloneData", cloneData);
328
- Guards.object(this.CLASS_NAME, "cloneData.config", cloneData.config);
329
- Guards.object(this.CLASS_NAME, "cloneData.state", cloneData.state);
330
- Guards.array(this.CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
387
+ Guards.object(EngineCore._CLASS_NAME, "cloneData", cloneData);
388
+ Guards.object(EngineCore._CLASS_NAME, "cloneData.config", cloneData.config);
389
+ Guards.object(EngineCore._CLASS_NAME, "cloneData.state", cloneData.state);
390
+ Guards.array(EngineCore._CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
331
391
  this._loggerTypeName = cloneData.loggerTypeName;
332
392
  this._skipBootstrap = true;
393
+ this._isClone = true;
333
394
  if (silent ?? false) {
334
395
  cloneData.config.silent = true;
335
396
  }
336
397
  this._context = {
337
398
  config: cloneData.config,
338
- defaultTypes: {},
399
+ registeredInstances: {},
339
400
  componentInstances: [],
340
- state: { componentStates: {} },
401
+ state: {},
341
402
  stateDirty: false
342
403
  };
343
404
  this._typeInitialisers = cloneData.typeInitialisers;
@@ -358,9 +419,20 @@ class EngineCore {
358
419
  const instanceMethod = await ModuleHelper.getModuleEntry(module, method);
359
420
  for (let i = 0; i < typeConfig.length; i++) {
360
421
  const instanceType = instanceMethod(this, this._context, typeConfig[i], typeConfig[i].overrideInstanceType);
361
- if (Is.stringValue(instanceType) &&
362
- (Is.empty(this._context.defaultTypes[typeKey]) || typeConfig[i].isDefault)) {
363
- this._context.defaultTypes[typeKey] = instanceType;
422
+ if (Is.stringValue(instanceType)) {
423
+ this._context.registeredInstances[typeKey] ??= [];
424
+ if (typeConfig[i].isDefault ?? false) {
425
+ this._context.registeredInstances[typeKey].unshift({
426
+ type: instanceType,
427
+ features: typeConfig[i].features
428
+ });
429
+ }
430
+ else {
431
+ this._context.registeredInstances[typeKey].push({
432
+ type: instanceType,
433
+ features: typeConfig[i].features
434
+ });
435
+ }
364
436
  }
365
437
  }
366
438
  }
@@ -371,7 +443,7 @@ class EngineCore {
371
443
  */
372
444
  setupEngineLogger() {
373
445
  const silent = this._context.config.silent ?? false;
374
- const engineLogger = silent
446
+ const engineLoggerConnector = silent
375
447
  ? new SilentLoggingConnector()
376
448
  : new ConsoleLoggingConnector({
377
449
  config: {
@@ -381,11 +453,24 @@ class EngineCore {
381
453
  });
382
454
  this._context.componentInstances.push({
383
455
  instanceType: this._loggerTypeName,
384
- component: engineLogger
456
+ component: engineLoggerConnector
385
457
  });
386
- LoggingConnectorFactory.register(this._loggerTypeName, () => engineLogger);
387
- this._engineLoggingConnector = engineLogger;
388
- this._context.defaultTypes.loggingConnector = this._loggerTypeName;
458
+ LoggingConnectorFactory.register(this._loggerTypeName, () => engineLoggerConnector);
459
+ this._context.registeredInstances.loggingConnector = [
460
+ {
461
+ type: this._loggerTypeName
462
+ }
463
+ ];
464
+ const engineLoggerComponent = new LoggingService({
465
+ loggingConnectorType: this._loggerTypeName
466
+ });
467
+ this._engineLoggingComponent = engineLoggerComponent;
468
+ ComponentFactory.register("logging-service", () => engineLoggerComponent);
469
+ this._context.registeredInstances.loggingComponent = [
470
+ {
471
+ type: "logging-service"
472
+ }
473
+ ];
389
474
  }
390
475
  /**
391
476
  * Load the state.
@@ -395,10 +480,7 @@ class EngineCore {
395
480
  async stateLoad() {
396
481
  if (this._stateStorage) {
397
482
  try {
398
- this._context.state = ((await this._stateStorage.load(this)) ?? {
399
- componentStates: {}
400
- });
401
- this._context.state.componentStates ??= {};
483
+ this._context.state = ((await this._stateStorage.load(this)) ?? {});
402
484
  this._context.stateDirty = false;
403
485
  return true;
404
486
  }
@@ -434,34 +516,28 @@ class EngineCore {
434
516
  */
435
517
  async bootstrap() {
436
518
  if (!this._skipBootstrap) {
437
- this.logInfo(I18n.formatMessage("engineCore.bootstrapStarted"));
519
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapStarted`));
438
520
  // First bootstrap the components.
439
521
  for (const instance of this._context.componentInstances) {
440
522
  if (Is.function(instance.component.bootstrap)) {
441
523
  const instanceName = this.getInstanceName(instance);
442
- this.logInfo(I18n.formatMessage("engineCore.bootstrapping", {
524
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapping`, {
443
525
  element: instanceName
444
526
  }));
445
- const componentState = this._context.state.componentStates[instanceName] ?? {};
446
- const lastState = ObjectHelper.clone(componentState);
447
- const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName, componentState);
527
+ const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName);
448
528
  // If the bootstrap method failed then throw an error
449
529
  if (!bootstrapSuccess) {
450
- throw new GeneralError(this.CLASS_NAME, "bootstrapFailed", {
530
+ throw new GeneralError(EngineCore._CLASS_NAME, "bootstrapFailed", {
451
531
  component: `${instance.component.CLASS_NAME}:${instance.instanceType}`
452
532
  });
453
533
  }
454
- if (!ObjectHelper.equal(lastState, componentState)) {
455
- this._context.state.componentStates[instanceName] = componentState;
456
- this._context.stateDirty = true;
457
- }
458
534
  }
459
535
  }
460
536
  // Now perform any custom bootstrap operations
461
537
  if (Is.function(this._customBootstrap)) {
462
538
  await this._customBootstrap(this, this._context);
463
539
  }
464
- this.logInfo(I18n.formatMessage("engineCore.bootstrapComplete"));
540
+ this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapComplete`));
465
541
  }
466
542
  }
467
543
  /**
@@ -9,10 +9,6 @@ export declare class EngineCore<C extends IEngineCoreConfig = IEngineCoreConfig,
9
9
  * Name for the engine logger.
10
10
  */
11
11
  static readonly LOGGER_TYPE_NAME: string;
12
- /**
13
- * Runtime name for the class.
14
- */
15
- readonly CLASS_NAME: string;
16
12
  /**
17
13
  * The core context.
18
14
  */
@@ -40,6 +36,21 @@ export declare class EngineCore<C extends IEngineCoreConfig = IEngineCoreConfig,
40
36
  * @returns Nothing.
41
37
  */
42
38
  stop(): Promise<void>;
39
+ /**
40
+ * Is the engine started.
41
+ * @returns True if the engine is started.
42
+ */
43
+ isStarted(): boolean;
44
+ /**
45
+ * Is this the primary engine instance.
46
+ * @returns True if the engine is the primary instance.
47
+ */
48
+ isPrimary(): boolean;
49
+ /**
50
+ * Is this engine instance a clone.
51
+ * @returns True if the engine instance is a clone.
52
+ */
53
+ isClone(): boolean;
43
54
  /**
44
55
  * Log info.
45
56
  * @param message The message to log.
@@ -61,12 +72,30 @@ export declare class EngineCore<C extends IEngineCoreConfig = IEngineCoreConfig,
61
72
  */
62
73
  getState(): S;
63
74
  /**
64
- * Get the types for the component.
65
- * @returns The default types.
75
+ * Get all the registered instances.
76
+ * @returns The registered instances.
66
77
  */
67
- getDefaultTypes(): {
68
- [type: string]: string;
78
+ getRegisteredInstances(): {
79
+ [name: string]: {
80
+ type: string;
81
+ features?: string[];
82
+ }[];
69
83
  };
84
+ /**
85
+ * Get the registered instance type for the component/connector.
86
+ * @param componentConnectorType The type of the component/connector.
87
+ * @param features The requested features of the component, if not specified the default entry will be retrieved.
88
+ * @returns The instance type matching the criteria if one is registered.
89
+ * @throws If a matching instance was not found.
90
+ */
91
+ getRegisteredInstanceType(componentConnectorType: string, features?: string[]): string;
92
+ /**
93
+ * Get the registered instance type for the component/connector if it exists.
94
+ * @param componentConnectorType The type of the component/connector.
95
+ * @param features The requested features of the component, if not specified the default entry will be retrieved.
96
+ * @returns The instance type matching the criteria if one is registered.
97
+ */
98
+ getRegisteredInstanceTypeOptional(componentConnectorType: string, features?: string[]): string | undefined;
70
99
  /**
71
100
  * Get the data required to create a clone of the engine.
72
101
  * @returns The clone data.
package/docs/changelog.md CHANGED
@@ -1,5 +1,149 @@
1
1
  # @twin.org/engine-core - Changelog
2
2
 
3
+ ## [0.0.2-next.10](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.9...engine-core-v0.0.2-next.10) (2025-08-26)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **engine-core:** Synchronize repo versions
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/engine-models bumped from 0.0.2-next.9 to 0.0.2-next.10
16
+
17
+ ## [0.0.2-next.9](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.8...engine-core-v0.0.2-next.9) (2025-08-25)
18
+
19
+
20
+ ### Features
21
+
22
+ * add isPrimary and isClone methods ([a7c63e9](https://github.com/twinfoundation/engine/commit/a7c63e97f54c95b104cc81e66d3fa42c6607bdc1))
23
+
24
+
25
+ ### Dependencies
26
+
27
+ * The following workspace dependencies were updated
28
+ * dependencies
29
+ * @twin.org/engine-models bumped from 0.0.2-next.8 to 0.0.2-next.9
30
+
31
+ ## [0.0.2-next.8](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.7...engine-core-v0.0.2-next.8) (2025-08-22)
32
+
33
+
34
+ ### Miscellaneous Chores
35
+
36
+ * **engine-core:** Synchronize repo versions
37
+
38
+
39
+ ### Dependencies
40
+
41
+ * The following workspace dependencies were updated
42
+ * dependencies
43
+ * @twin.org/engine-models bumped from 0.0.2-next.7 to 0.0.2-next.8
44
+
45
+ ## [0.0.2-next.7](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.6...engine-core-v0.0.2-next.7) (2025-08-22)
46
+
47
+
48
+ ### Features
49
+
50
+ * remove unused component states ([d56d648](https://github.com/twinfoundation/engine/commit/d56d6486119ea8b8501a33f9e3a3101a08b826ed))
51
+
52
+
53
+ ### Dependencies
54
+
55
+ * The following workspace dependencies were updated
56
+ * dependencies
57
+ * @twin.org/engine-models bumped from 0.0.2-next.6 to 0.0.2-next.7
58
+
59
+ ## [0.0.2-next.6](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.5...engine-core-v0.0.2-next.6) (2025-08-21)
60
+
61
+
62
+ ### Features
63
+
64
+ * update framework core ([acc0f8d](https://github.com/twinfoundation/engine/commit/acc0f8d455a4b8ec47f1da643139fa0f07775fa6))
65
+
66
+
67
+ ### Dependencies
68
+
69
+ * The following workspace dependencies were updated
70
+ * dependencies
71
+ * @twin.org/engine-models bumped from 0.0.2-next.5 to 0.0.2-next.6
72
+
73
+ ## [0.0.2-next.5](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.4...engine-core-v0.0.2-next.5) (2025-08-14)
74
+
75
+
76
+ ### Features
77
+
78
+ * add synchronised storage support ([5142e34](https://github.com/twinfoundation/engine/commit/5142e3488f09195cf9f48a9c6c6d1014231a4c2c))
79
+
80
+
81
+ ### Dependencies
82
+
83
+ * The following workspace dependencies were updated
84
+ * dependencies
85
+ * @twin.org/engine-models bumped from 0.0.2-next.4 to 0.0.2-next.5
86
+
87
+ ## [0.0.2-next.4](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.3...engine-core-v0.0.2-next.4) (2025-07-25)
88
+
89
+
90
+ ### Features
91
+
92
+ * add default logging component for web server ([8ad94f0](https://github.com/twinfoundation/engine/commit/8ad94f0d2d9a5241a8854b1e59fb9a55ce310142))
93
+
94
+
95
+ ### Dependencies
96
+
97
+ * The following workspace dependencies were updated
98
+ * dependencies
99
+ * @twin.org/engine-models bumped from 0.0.2-next.3 to 0.0.2-next.4
100
+
101
+ ## [0.0.2-next.3](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.2...engine-core-v0.0.2-next.3) (2025-07-24)
102
+
103
+
104
+ ### Miscellaneous Chores
105
+
106
+ * **engine-core:** Synchronize repo versions
107
+
108
+
109
+ ### Dependencies
110
+
111
+ * The following workspace dependencies were updated
112
+ * dependencies
113
+ * @twin.org/engine-models bumped from 0.0.2-next.2 to 0.0.2-next.3
114
+
115
+ ## [0.0.2-next.2](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.1...engine-core-v0.0.2-next.2) (2025-07-21)
116
+
117
+
118
+ ### Miscellaneous Chores
119
+
120
+ * **engine-core:** Synchronize repo versions
121
+
122
+
123
+ ### Dependencies
124
+
125
+ * The following workspace dependencies were updated
126
+ * dependencies
127
+ * @twin.org/engine-models bumped from 0.0.2-next.1 to 0.0.2-next.2
128
+
129
+ ## [0.0.2-next.1](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.0...engine-core-v0.0.2-next.1) (2025-07-11)
130
+
131
+
132
+ ### Features
133
+
134
+ * add auth admin component ([201cd06](https://github.com/twinfoundation/engine/commit/201cd061be83afccb5a6b06856ffe7cf8db7d6b3))
135
+ * add mimeTypeProcessors and disableNodeIdentity ([bb7e81e](https://github.com/twinfoundation/engine/commit/bb7e81e2036fe042068a5645ec59b22e20d33aad))
136
+ * remove bootstrapped components, component should manage their own state ([5c7e9e4](https://github.com/twinfoundation/engine/commit/5c7e9e419ef26933e49c9c5a21a20a8961244e7f))
137
+ * update dependencies ([97c9f64](https://github.com/twinfoundation/engine/commit/97c9f64b6ef096963bcc5de338a2a9e99bdc1a11))
138
+ * use shared store mechanism ([#2](https://github.com/twinfoundation/engine/issues/2)) ([9eed8d7](https://github.com/twinfoundation/engine/commit/9eed8d7766388479b42f03e2542fe761f2156408))
139
+
140
+
141
+ ### Dependencies
142
+
143
+ * The following workspace dependencies were updated
144
+ * dependencies
145
+ * @twin.org/engine-models bumped from 0.0.2-next.0 to 0.0.2-next.1
146
+
3
147
  ## 0.0.1 (2025-07-11)
4
148
 
5
149
 
@@ -46,14 +46,6 @@ Name for the engine logger.
46
46
 
47
47
  ***
48
48
 
49
- ### CLASS\_NAME
50
-
51
- > `readonly` **CLASS\_NAME**: `string`
52
-
53
- Runtime name for the class.
54
-
55
- ***
56
-
57
49
  ### \_context
58
50
 
59
51
  > `protected` **\_context**: `IEngineCoreContext`\<`C`, `S`\>
@@ -140,6 +132,60 @@ Nothing.
140
132
 
141
133
  ***
142
134
 
135
+ ### isStarted()
136
+
137
+ > **isStarted**(): `boolean`
138
+
139
+ Is the engine started.
140
+
141
+ #### Returns
142
+
143
+ `boolean`
144
+
145
+ True if the engine is started.
146
+
147
+ #### Implementation of
148
+
149
+ `IEngineCore.isStarted`
150
+
151
+ ***
152
+
153
+ ### isPrimary()
154
+
155
+ > **isPrimary**(): `boolean`
156
+
157
+ Is this the primary engine instance.
158
+
159
+ #### Returns
160
+
161
+ `boolean`
162
+
163
+ True if the engine is the primary instance.
164
+
165
+ #### Implementation of
166
+
167
+ `IEngineCore.isPrimary`
168
+
169
+ ***
170
+
171
+ ### isClone()
172
+
173
+ > **isClone**(): `boolean`
174
+
175
+ Is this engine instance a clone.
176
+
177
+ #### Returns
178
+
179
+ `boolean`
180
+
181
+ True if the engine instance is a clone.
182
+
183
+ #### Implementation of
184
+
185
+ `IEngineCore.isClone`
186
+
187
+ ***
188
+
143
189
  ### logInfo()
144
190
 
145
191
  > **logInfo**(`message`): `void`
@@ -224,21 +270,89 @@ The state of the engine.
224
270
 
225
271
  ***
226
272
 
227
- ### getDefaultTypes()
273
+ ### getRegisteredInstances()
228
274
 
229
- > **getDefaultTypes**(): `object`
275
+ > **getRegisteredInstances**(): `object`
230
276
 
231
- Get the types for the component.
277
+ Get all the registered instances.
232
278
 
233
279
  #### Returns
234
280
 
235
281
  `object`
236
282
 
237
- The default types.
283
+ The registered instances.
284
+
285
+ #### Implementation of
286
+
287
+ `IEngineCore.getRegisteredInstances`
288
+
289
+ ***
290
+
291
+ ### getRegisteredInstanceType()
292
+
293
+ > **getRegisteredInstanceType**(`componentConnectorType`, `features?`): `string`
294
+
295
+ Get the registered instance type for the component/connector.
296
+
297
+ #### Parameters
298
+
299
+ ##### componentConnectorType
300
+
301
+ `string`
302
+
303
+ The type of the component/connector.
304
+
305
+ ##### features?
306
+
307
+ `string`[]
308
+
309
+ The requested features of the component, if not specified the default entry will be retrieved.
310
+
311
+ #### Returns
312
+
313
+ `string`
314
+
315
+ The instance type matching the criteria if one is registered.
316
+
317
+ #### Throws
318
+
319
+ If a matching instance was not found.
320
+
321
+ #### Implementation of
322
+
323
+ `IEngineCore.getRegisteredInstanceType`
324
+
325
+ ***
326
+
327
+ ### getRegisteredInstanceTypeOptional()
328
+
329
+ > **getRegisteredInstanceTypeOptional**(`componentConnectorType`, `features?`): `undefined` \| `string`
330
+
331
+ Get the registered instance type for the component/connector if it exists.
332
+
333
+ #### Parameters
334
+
335
+ ##### componentConnectorType
336
+
337
+ `string`
338
+
339
+ The type of the component/connector.
340
+
341
+ ##### features?
342
+
343
+ `string`[]
344
+
345
+ The requested features of the component, if not specified the default entry will be retrieved.
346
+
347
+ #### Returns
348
+
349
+ `undefined` \| `string`
350
+
351
+ The instance type matching the criteria if one is registered.
238
352
 
239
353
  #### Implementation of
240
354
 
241
- `IEngineCore.getDefaultTypes`
355
+ `IEngineCore.getRegisteredInstanceTypeOptional`
242
356
 
243
357
  ***
244
358
 
package/locales/en.json CHANGED
@@ -6,7 +6,8 @@
6
6
  "entityStorageCustomMissing": "Entity storage custom \"{typeCustom}\" missing for component \"{storageName}\"",
7
7
  "entityStorageMissing": "Entity storage configuration missing for component \"{storageName}\"",
8
8
  "bootstrapFailed": "Bootstrap failed for component \"{component}\", please check the logs for more information",
9
- "componentStopFailed": "Failed to stop component \"{component}\""
9
+ "componentStopFailed": "Failed to stop component \"{component}\"",
10
+ "instanceTypeNotFound": "Instance type not found for \"{type}\" with features \"{features}\""
10
11
  },
11
12
  "fileStateStorage": {
12
13
  "failedLoading": "Failed to load file state storage from \"{filename}\"",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/engine-core",
3
- "version": "0.0.1",
3
+ "version": "0.0.2-next.10",
4
4
  "description": "Engine core.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,10 +17,11 @@
17
17
  "@twin.org/core": "next",
18
18
  "@twin.org/crypto": "next",
19
19
  "@twin.org/data-core": "next",
20
- "@twin.org/engine-models": "0.0.1",
20
+ "@twin.org/engine-models": "0.0.2-next.10",
21
21
  "@twin.org/entity": "next",
22
22
  "@twin.org/logging-connector-console": "next",
23
23
  "@twin.org/logging-models": "next",
24
+ "@twin.org/logging-service": "next",
24
25
  "@twin.org/modules": "next",
25
26
  "@twin.org/nameof": "next"
26
27
  },