@twin.org/engine-core 0.0.2-next.25 → 0.0.2-next.27

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,73 +1,18 @@
1
- import { isMainThread } from 'node:worker_threads';
2
- import { I18n, Is, Guards, BaseError, GeneralError, ErrorHelper, ComponentFactory } from '@twin.org/core';
3
- import { EntitySchemaFactory } from '@twin.org/entity';
4
- import { ConsoleLoggingConnector } from '@twin.org/logging-connector-console';
5
- import { SilentLoggingConnector, LoggingConnectorFactory } from '@twin.org/logging-models';
6
- import { LoggingService } from '@twin.org/logging-service';
7
- import { ModuleHelper } from '@twin.org/modules';
8
- import { readFile, mkdir, writeFile, stat } from 'node:fs/promises';
9
- import path from 'node:path';
10
-
11
- // Copyright 2024 IOTA Stiftung.
12
- // SPDX-License-Identifier: Apache-2.0.
13
- /**
14
- * Store state in memory.
15
- */
16
- class MemoryStateStorage {
17
- /**
18
- * Runtime name for the class.
19
- */
20
- static CLASS_NAME = "MemoryStateStorage";
21
- /**
22
- * Readonly mode state file is not updated.
23
- * @internal
24
- */
25
- _readonlyMode;
26
- /**
27
- * The state object.
28
- * @internal
29
- */
30
- _engineState;
31
- /**
32
- * Create a new instance of MemoryStateStorage.
33
- * @param readonlyMode Whether the file is in read-only mode.
34
- * @param state The initial state.
35
- */
36
- constructor(readonlyMode = false, state) {
37
- this._readonlyMode = readonlyMode;
38
- this._engineState = state;
39
- }
40
- /**
41
- * Method for loading the state.
42
- * @param engineCore The engine core to load the state for.
43
- * @returns The state of the engine or undefined if it doesn't exist.
44
- */
45
- async load(engineCore) {
46
- engineCore.logInfo(I18n.formatMessage(`${"memoryStateStorage"}.loading`, {
47
- filename: this._engineState
48
- }));
49
- return this._engineState;
50
- }
51
- /**
52
- * Method for saving the state.
53
- * @param engineCore The engine core to save the state for.
54
- * @param state The state of the engine to save.
55
- * @returns Nothing.
56
- */
57
- async save(engineCore, state) {
58
- if (!this._readonlyMode) {
59
- engineCore.logInfo(I18n.formatMessage(`${"memoryStateStorage"}.saving`));
60
- this._engineState = state;
61
- }
62
- }
63
- }
64
-
65
1
  // Copyright 2024 IOTA Stiftung.
66
2
  // SPDX-License-Identifier: Apache-2.0.
3
+ import { isMainThread } from "node:worker_threads";
4
+ import { ContextIdStore } from "@twin.org/context";
5
+ import { BaseError, ComponentFactory, ErrorHelper, GeneralError, Guards, I18n, Is } from "@twin.org/core";
6
+ import { EntitySchemaFactory } from "@twin.org/entity";
7
+ import { ConsoleLoggingConnector } from "@twin.org/logging-connector-console";
8
+ import { LoggingConnectorFactory, SilentLoggingConnector } from "@twin.org/logging-models";
9
+ import { LoggingService } from "@twin.org/logging-service";
10
+ import { ModuleHelper } from "@twin.org/modules";
11
+ import { MemoryStateStorage } from "./storage/memoryStateStorage.js";
67
12
  /**
68
13
  * Core for the engine.
69
14
  */
70
- class EngineCore {
15
+ export class EngineCore {
71
16
  /**
72
17
  * Name for the engine logger component, used for direct console logging.
73
18
  */
@@ -84,6 +29,14 @@ class EngineCore {
84
29
  * The core context.
85
30
  */
86
31
  _context;
32
+ /**
33
+ * The context ID keys.
34
+ */
35
+ _contextIdKeys;
36
+ /**
37
+ * The context IDs.
38
+ */
39
+ _contextIds;
87
40
  /**
88
41
  * The state storage interface.
89
42
  * @internal
@@ -138,6 +91,7 @@ class EngineCore {
138
91
  this._populateTypeInitialisers = options.populateTypeInitialisers;
139
92
  this._customBootstrap = options.customBootstrap;
140
93
  this._typeInitialisers = [];
94
+ this._contextIdKeys = [];
141
95
  this._context = {
142
96
  config: options.config,
143
97
  registeredInstances: {},
@@ -184,6 +138,38 @@ class EngineCore {
184
138
  Guards.stringValue(EngineCore.CLASS_NAME, "type", type);
185
139
  return this._context.config.types?.[type];
186
140
  }
141
+ /**
142
+ * Add a context ID key to the engine.
143
+ * @param key The context ID key.
144
+ */
145
+ addContextIdKey(key) {
146
+ if (!this._contextIdKeys.includes(key)) {
147
+ this._contextIdKeys.push(key);
148
+ }
149
+ }
150
+ /**
151
+ * Get the context ID keys for the engine.
152
+ * @returns The context IDs keys.
153
+ */
154
+ getContextIdKeys() {
155
+ return this._contextIdKeys;
156
+ }
157
+ /**
158
+ * Add a context ID to the engine.
159
+ * @param key The context ID key.
160
+ * @param value The context ID value.
161
+ */
162
+ addContextId(key, value) {
163
+ this._contextIds ??= {};
164
+ this._contextIds[key] = value;
165
+ }
166
+ /**
167
+ * Get the context IDs for the engine.
168
+ * @returns The context IDs or undefined if none are set.
169
+ */
170
+ getContextIds() {
171
+ return this._contextIds;
172
+ }
187
173
  /**
188
174
  * Start the engine core.
189
175
  * @returns True if the start was successful.
@@ -193,9 +179,9 @@ class EngineCore {
193
179
  return false;
194
180
  }
195
181
  this.setupEngineLogger();
196
- this.logInfo(I18n.formatMessage(`${"engineCore"}.starting`));
182
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.starting`));
197
183
  if (this._context.config.debug) {
198
- this.logInfo(I18n.formatMessage(`${"engineCore"}.debuggingEnabled`));
184
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.debuggingEnabled`));
199
185
  }
200
186
  let canContinue;
201
187
  try {
@@ -205,23 +191,36 @@ class EngineCore {
205
191
  await this.initialiseTypeConfig(type, module, method);
206
192
  }
207
193
  await this.bootstrap();
208
- this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStarting`));
209
- for (const instance of this._context.componentInstances) {
210
- if (Is.function(instance.component.start)) {
211
- this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStarting`, {
212
- element: instance.instanceType
213
- }));
214
- await instance.component.start(this._context.state.nodeIdentity, EngineCore.LOGGING_COMPONENT_TYPE_NAME);
194
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStarting`));
195
+ await ContextIdStore.run(this._contextIds ?? {}, async () => {
196
+ for (const instance of this._context.componentInstances) {
197
+ const startMethod = instance.component.start?.bind(instance.component);
198
+ if (Is.function(startMethod)) {
199
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStarting`, {
200
+ className: instance.component.className(),
201
+ instanceType: instance.instanceType
202
+ }));
203
+ try {
204
+ await startMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
205
+ }
206
+ catch (err) {
207
+ await this.logError(new GeneralError(EngineCore.CLASS_NAME, "componentStartFailed", {
208
+ className: instance.component.className(),
209
+ instanceType: instance.instanceType
210
+ }, BaseError.fromError(err)));
211
+ throw err;
212
+ }
213
+ }
215
214
  }
216
- }
217
- this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsComplete`));
215
+ });
216
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsComplete`));
218
217
  }
219
- this.logInfo(I18n.formatMessage(`${"engineCore"}.started`));
218
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.started`));
220
219
  this._isStarted = true;
221
220
  }
222
221
  catch (err) {
223
222
  canContinue = false;
224
- this.logError(BaseError.fromError(err));
223
+ await this.logError(BaseError.fromError(err));
225
224
  }
226
225
  finally {
227
226
  if (!(await this.stateSave())) {
@@ -235,26 +234,31 @@ class EngineCore {
235
234
  * @returns Nothing.
236
235
  */
237
236
  async stop() {
238
- this.logInfo(I18n.formatMessage(`${"engineCore"}.stopping`));
239
- this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopping`));
240
- for (const instance of this._context.componentInstances) {
241
- if (Is.function(instance.component.stop)) {
242
- this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStopping`, {
243
- element: instance.instanceType
244
- }));
245
- try {
246
- await instance.component.stop(this._context.state.nodeIdentity, EngineCore.LOGGING_COMPONENT_TYPE_NAME);
247
- }
248
- catch (err) {
249
- this.logError(new GeneralError(EngineCore.CLASS_NAME, "componentStopFailed", {
250
- component: instance.instanceType
251
- }, BaseError.fromError(err)));
237
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.stopping`));
238
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopping`));
239
+ await ContextIdStore.run(this._contextIds ?? {}, async () => {
240
+ for (const instance of this._context.componentInstances) {
241
+ const stopMethod = instance.component.stop?.bind(instance.component);
242
+ if (Is.function(stopMethod)) {
243
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStopping`, {
244
+ className: instance.component.className(),
245
+ instanceType: instance.instanceType
246
+ }));
247
+ try {
248
+ await stopMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
249
+ }
250
+ catch (err) {
251
+ await this.logError(new GeneralError(EngineCore.CLASS_NAME, "componentStopFailed", {
252
+ className: instance.component.className(),
253
+ instanceType: instance.instanceType
254
+ }, BaseError.fromError(err)));
255
+ }
252
256
  }
253
257
  }
254
- }
258
+ });
255
259
  await this.stateSave();
256
- this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopped`));
257
- this.logInfo(I18n.formatMessage(`${"engineCore"}.stopped`));
260
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopped`));
261
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.stopped`));
258
262
  }
259
263
  /**
260
264
  * Is the engine started.
@@ -281,8 +285,8 @@ class EngineCore {
281
285
  * Log info.
282
286
  * @param message The message to log.
283
287
  */
284
- logInfo(message) {
285
- this._engineLoggingComponent?.log({
288
+ async logInfo(message) {
289
+ await this._engineLoggingComponent?.log({
286
290
  source: EngineCore.CLASS_NAME,
287
291
  level: "info",
288
292
  message
@@ -292,7 +296,7 @@ class EngineCore {
292
296
  * Log error.
293
297
  * @param error The error to log.
294
298
  */
295
- logError(error) {
299
+ async logError(error) {
296
300
  const formattedErrors = ErrorHelper.localizeErrors(error);
297
301
  for (const formattedError of formattedErrors) {
298
302
  let message = Is.stringValue(formattedError.source)
@@ -301,7 +305,7 @@ class EngineCore {
301
305
  if (this._context.config.debug && Is.stringValue(formattedError.stack)) {
302
306
  message += `\n${formattedError.stack}`;
303
307
  }
304
- this._engineLoggingComponent?.log({
308
+ await this._engineLoggingComponent?.log({
305
309
  source: EngineCore.CLASS_NAME,
306
310
  level: "error",
307
311
  message
@@ -385,7 +389,8 @@ class EngineCore {
385
389
  config: this._context.config,
386
390
  state: this._context.state,
387
391
  typeInitialisers: this._typeInitialisers,
388
- entitySchemas
392
+ entitySchemas,
393
+ contextIdKeys: this._contextIdKeys
389
394
  };
390
395
  return cloneData;
391
396
  }
@@ -412,6 +417,7 @@ class EngineCore {
412
417
  stateDirty: false
413
418
  };
414
419
  this._typeInitialisers = cloneData.typeInitialisers;
420
+ this._contextIdKeys.push(...cloneData.contextIdKeys);
415
421
  for (const schemaName of Object.keys(cloneData.entitySchemas)) {
416
422
  EntitySchemaFactory.register(schemaName, () => cloneData.entitySchemas[schemaName]);
417
423
  }
@@ -429,8 +435,9 @@ class EngineCore {
429
435
  if (Is.arrayValue(typeConfig)) {
430
436
  const instanceMethod = await ModuleHelper.getModuleEntry(module, method);
431
437
  for (let i = 0; i < typeConfig.length; i++) {
432
- this.logInfo(I18n.formatMessage("engineCore.configuring", {
433
- element: `${typeKey}: ${typeConfig[i].type}`
438
+ await this.logInfo(I18n.formatMessage("engineCore.configuring", {
439
+ componentType: typeKey,
440
+ configType: typeConfig[i].type
434
441
  }));
435
442
  const result = await instanceMethod(this, this._context, typeConfig[i]);
436
443
  if (Is.stringValue(result.instanceType) && Is.object(result.component)) {
@@ -504,7 +511,7 @@ class EngineCore {
504
511
  return true;
505
512
  }
506
513
  catch (err) {
507
- this.logError(BaseError.fromError(err));
514
+ await this.logError(BaseError.fromError(err));
508
515
  return false;
509
516
  }
510
517
  }
@@ -523,7 +530,7 @@ class EngineCore {
523
530
  return true;
524
531
  }
525
532
  catch (err) {
526
- this.logError(BaseError.fromError(err));
533
+ await this.logError(BaseError.fromError(err));
527
534
  }
528
535
  return false;
529
536
  }
@@ -535,174 +542,32 @@ class EngineCore {
535
542
  */
536
543
  async bootstrap() {
537
544
  if (!this._skipBootstrap) {
538
- this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapStarted`));
545
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapStarted`));
539
546
  // First bootstrap the components.
540
547
  for (const instance of this._context.componentInstances) {
541
- if (Is.function(instance.component.bootstrap)) {
542
- const instanceName = this.getInstanceName(instance);
543
- this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapping`, {
544
- element: instanceName
548
+ const bootstrapMethod = instance.component.bootstrap?.bind(instance.component);
549
+ if (Is.function(bootstrapMethod)) {
550
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapping`, {
551
+ className: instance.component.className(),
552
+ instanceType: instance.instanceType
545
553
  }));
546
- const bootstrapSuccess = await instance.component.bootstrap(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
554
+ const bootstrapSuccess = await bootstrapMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
547
555
  // If the bootstrap method failed then throw an error
548
556
  if (!bootstrapSuccess) {
549
557
  throw new GeneralError(EngineCore.CLASS_NAME, "bootstrapFailed", {
550
- component: `${instance.component.CLASS_NAME}:${instance.instanceType}`
558
+ className: instance.component.className(),
559
+ instanceType: instance.instanceType
551
560
  });
552
561
  }
553
562
  }
554
563
  }
555
564
  // Now perform any custom bootstrap operations
556
- if (Is.function(this._customBootstrap)) {
557
- await this._customBootstrap(this, this._context);
558
- }
559
- this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapComplete`));
560
- }
561
- }
562
- /**
563
- * Get the instance name.
564
- * @param instance The instance to get the name for.
565
- * @param instance.instanceType The instance type.
566
- * @param instance.component The component.
567
- * @returns The instance name.
568
- * @internal
569
- */
570
- getInstanceName(instance) {
571
- return `${instance.component.CLASS_NAME}-${instance.instanceType}`;
572
- }
573
- }
574
-
575
- // Copyright 2024 IOTA Stiftung.
576
- // SPDX-License-Identifier: Apache-2.0.
577
- /**
578
- * Store state in a file.
579
- */
580
- class FileStateStorage {
581
- /**
582
- * Runtime name for the class.
583
- */
584
- static CLASS_NAME = "FileStateStorage";
585
- /**
586
- * The filename to store the state.
587
- * @internal
588
- */
589
- _filename;
590
- /**
591
- * Readonly mode state file is not updated.
592
- * @internal
593
- */
594
- _readonlyMode;
595
- /**
596
- * Create a new instance of FileStateStorage.
597
- * @param filename The filename to store the state.
598
- * @param readonlyMode Whether the file is in read-only mode.
599
- */
600
- constructor(filename, readonlyMode = false) {
601
- Guards.stringValue(FileStateStorage.CLASS_NAME, "filename", filename);
602
- this._filename = filename;
603
- this._readonlyMode = readonlyMode;
604
- }
605
- /**
606
- * Method for loading the state.
607
- * @param engineCore The engine core to load the state for.
608
- * @returns The state of the engine or undefined if it doesn't exist.
609
- */
610
- async load(engineCore) {
611
- try {
612
- engineCore.logInfo(I18n.formatMessage(`${"fileStateStorage"}.loading`, {
613
- filename: this._filename
614
- }));
615
- if (await this.fileExists(this._filename)) {
616
- const content = await readFile(this._filename, "utf8");
617
- return JSON.parse(content.toString());
618
- }
619
- }
620
- catch (err) {
621
- throw new GeneralError(FileStateStorage.CLASS_NAME, "failedLoading", { filename: this._filename }, BaseError.fromError(err));
622
- }
623
- }
624
- /**
625
- * Method for saving the state.
626
- * @param engineCore The engine core to save the state for.
627
- * @param state The state of the engine to save.
628
- * @returns Nothing.
629
- */
630
- async save(engineCore, state) {
631
- if (!this._readonlyMode) {
632
- try {
633
- engineCore.logInfo(I18n.formatMessage(`${"fileStateStorage"}.saving`, {
634
- filename: this._filename
635
- }));
636
- try {
637
- await mkdir(path.dirname(this._filename), { recursive: true });
638
- }
639
- catch { }
640
- await writeFile(this._filename, JSON.stringify(state, undefined, "\t"), "utf8");
565
+ const customBootstrap = this._customBootstrap;
566
+ if (Is.function(customBootstrap)) {
567
+ await customBootstrap.call(this, this, this._context);
641
568
  }
642
- catch (err) {
643
- throw new GeneralError(FileStateStorage.CLASS_NAME, "failedSaving", { filename: this._filename }, BaseError.fromError(err));
644
- }
645
- }
646
- }
647
- /**
648
- * Does the specified file exist.
649
- * @param filename The filename to check for existence.
650
- * @returns True if the file exists.
651
- * @internal
652
- */
653
- async fileExists(filename) {
654
- try {
655
- const stats = await stat(filename);
656
- return stats.isFile();
657
- }
658
- catch {
659
- return false;
660
- }
661
- }
662
- }
663
-
664
- // Copyright 2024 IOTA Stiftung.
665
- // SPDX-License-Identifier: Apache-2.0.
666
- /**
667
- * Helper class for engine modules.
668
- */
669
- class EngineModuleHelper {
670
- /**
671
- * Runtime name for the class.
672
- */
673
- static CLASS_NAME = "EngineModuleHelper";
674
- /**
675
- * Loads an engine component and constructs it with the relevant dependencies and configuration.
676
- * @param engineCore The engine core.
677
- * @param engineModuleConfig The configuration for the module.
678
- * @returns The instantiated component.
679
- */
680
- static async loadComponent(engineCore, engineModuleConfig) {
681
- const moduleClass = await ModuleHelper.getModuleEntry(engineModuleConfig.moduleName, engineModuleConfig.className);
682
- const isClass = Is.class(moduleClass);
683
- if (!isClass) {
684
- throw new GeneralError(EngineModuleHelper.CLASS_NAME, "moduleNotClass", {
685
- moduleName: engineModuleConfig.moduleName,
686
- className: engineModuleConfig.className
687
- });
688
- }
689
- const constructorOptions = {};
690
- if (Is.arrayValue(engineModuleConfig.dependencies)) {
691
- for (const dependency of engineModuleConfig.dependencies) {
692
- if (dependency.isOptional ?? false) {
693
- constructorOptions[dependency.propertyName] = engineCore.getRegisteredInstanceType(dependency.componentName, dependency.features);
694
- }
695
- else {
696
- constructorOptions[dependency.propertyName] =
697
- engineCore.getRegisteredInstanceTypeOptional(dependency.componentName, dependency.features);
698
- }
699
- }
700
- }
701
- if (Is.object(engineModuleConfig.config)) {
702
- constructorOptions.config = engineModuleConfig.config;
569
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapComplete`));
703
570
  }
704
- return new moduleClass(constructorOptions);
705
571
  }
706
572
  }
707
-
708
- export { EngineCore, EngineModuleHelper, FileStateStorage, MemoryStateStorage };
573
+ //# sourceMappingURL=engineCore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engineCore.js","sourceRoot":"","sources":["../../src/engineCore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { isMainThread } from \"node:worker_threads\";\nimport { ContextIdStore, type IContextIds } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tErrorHelper,\n\tGeneralError,\n\tGuards,\n\tI18n,\n\ttype IError,\n\tIs\n} from \"@twin.org/core\";\nimport type {\n\tEngineTypeInitialiser,\n\tIEngineCore,\n\tIEngineCoreClone,\n\tIEngineCoreConfig,\n\tIEngineCoreContext,\n\tIEngineCoreTypeConfig,\n\tIEngineState,\n\tIEngineStateStorage\n} from \"@twin.org/engine-models\";\nimport { EntitySchemaFactory, type IEntitySchema } from \"@twin.org/entity\";\nimport { ConsoleLoggingConnector } from \"@twin.org/logging-connector-console\";\nimport {\n\ttype ILoggingComponent,\n\tLoggingConnectorFactory,\n\tSilentLoggingConnector\n} from \"@twin.org/logging-models\";\nimport { LoggingService } from \"@twin.org/logging-service\";\nimport { ModuleHelper } from \"@twin.org/modules\";\nimport { nameof, nameofCamelCase } from \"@twin.org/nameof\";\nimport type { IEngineCoreOptions } from \"./models/IEngineCoreOptions.js\";\nimport { MemoryStateStorage } from \"./storage/memoryStateStorage.js\";\n\n/**\n * Core for the engine.\n */\nexport class EngineCore<\n\tC extends IEngineCoreConfig = IEngineCoreConfig,\n\tS extends IEngineState = IEngineState\n> implements IEngineCore<C, S>\n{\n\t/**\n\t * Name for the engine logger component, used for direct console logging.\n\t */\n\tpublic static readonly LOGGING_COMPONENT_TYPE_NAME: string = \"engine-logging-service\";\n\n\t/**\n\t * Name for the engine logger connector, used for direct console logging.\n\t */\n\tpublic static readonly LOGGING_CONNECTOR_TYPE_NAME: string = \"engine-logging-connector\";\n\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<EngineCore>();\n\n\t/**\n\t * The core context.\n\t */\n\tprotected _context: IEngineCoreContext<C, S>;\n\n\t/**\n\t * The context ID keys.\n\t */\n\tprotected readonly _contextIdKeys: string[];\n\n\t/**\n\t * The context IDs.\n\t */\n\tprotected _contextIds?: IContextIds;\n\n\t/**\n\t * The state storage interface.\n\t * @internal\n\t */\n\tprivate _stateStorage?: IEngineStateStorage<S>;\n\n\t/**\n\t * The logging component for the engine.\n\t * @internal\n\t */\n\tprivate _engineLoggingComponent?: ILoggingComponent;\n\n\t/**\n\t * Skip the bootstrap process.\n\t * @internal\n\t */\n\tprivate _skipBootstrap?: boolean;\n\n\t/**\n\t * The type initialisers.\n\t * @internal\n\t */\n\tprivate _typeInitialisers: {\n\t\ttype: string;\n\t\tmodule: string;\n\t\tmethod: string;\n\t}[];\n\n\t/**\n\t * Is the engine started.\n\t * @internal\n\t */\n\tprivate _isStarted: boolean;\n\n\t/**\n\t * Is the engine a clone.\n\t * @internal\n\t */\n\tprivate _isClone: boolean;\n\n\t/**\n\t * Add type initialisers to the engine.\n\t * @internal\n\t */\n\tprivate readonly _populateTypeInitialisers?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => void;\n\n\t/**\n\t * Method for bootstrapping any data for the engine.\n\t * @internal\n\t */\n\tprivate readonly _customBootstrap?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => Promise<void>;\n\n\t/**\n\t * Create a new instance of EngineCore.\n\t * @param options The options for the engine.\n\t */\n\tconstructor(options?: IEngineCoreOptions<C, S>) {\n\t\toptions = options ?? {};\n\t\toptions.config = options.config ?? ({} as C);\n\t\toptions.config.debug = options.config.debug ?? false;\n\t\toptions.config.silent = options.config.silent ?? false;\n\t\toptions.config.types ??= {};\n\n\t\tthis._skipBootstrap = options.skipBootstrap ?? false;\n\t\tthis._populateTypeInitialisers = options.populateTypeInitialisers;\n\t\tthis._customBootstrap = options.customBootstrap;\n\t\tthis._typeInitialisers = [];\n\t\tthis._contextIdKeys = [];\n\n\t\tthis._context = {\n\t\t\tconfig: options.config,\n\t\t\tregisteredInstances: {},\n\t\t\tcomponentInstances: [],\n\t\t\tstate: {} as S,\n\t\t\tstateDirty: false\n\t\t};\n\t\tthis._stateStorage = options.stateStorage;\n\t\tthis._isStarted = false;\n\t\tthis._isClone = false;\n\n\t\tif (Is.function(this._populateTypeInitialisers)) {\n\t\t\tthis._populateTypeInitialisers(this, this._context);\n\t\t}\n\t}\n\n\t/**\n\t * Add a type initialiser.\n\t * @param type The type to add the initialiser for.\n\t * @param module The name of the module which contains the initialiser method.\n\t * @param method The name of the method to call.\n\t */\n\tpublic addTypeInitialiser(type: string, module: string, method: string): void {\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(type), type);\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(module), module);\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(method), method);\n\n\t\tconst currentIndex = this._typeInitialisers.findIndex(t => t.type === type);\n\t\tif (currentIndex >= 0) {\n\t\t\tthis._typeInitialisers[currentIndex].module = module;\n\t\t\tthis._typeInitialisers[currentIndex].method = method;\n\t\t} else {\n\t\t\tthis._typeInitialisers.push({\n\t\t\t\ttype,\n\t\t\t\tmodule,\n\t\t\t\tmethod\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Get the type config for a specific type.\n\t * @param type The type to get the config for.\n\t * @returns The type config or undefined if not found.\n\t */\n\tpublic getTypeConfig(type: string): IEngineCoreTypeConfig[] | undefined {\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(type), type);\n\t\treturn this._context.config.types?.[type];\n\t}\n\n\t/**\n\t * Add a context ID key to the engine.\n\t * @param key The context ID key.\n\t */\n\tpublic addContextIdKey(key: string): void {\n\t\tif (!this._contextIdKeys.includes(key)) {\n\t\t\tthis._contextIdKeys.push(key);\n\t\t}\n\t}\n\n\t/**\n\t * Get the context ID keys for the engine.\n\t * @returns The context IDs keys.\n\t */\n\tpublic getContextIdKeys(): string[] {\n\t\treturn this._contextIdKeys;\n\t}\n\n\t/**\n\t * Add a context ID to the engine.\n\t * @param key The context ID key.\n\t * @param value The context ID value.\n\t */\n\tpublic addContextId(key: string, value: string): void {\n\t\tthis._contextIds ??= {};\n\t\tthis._contextIds[key] = value;\n\t}\n\n\t/**\n\t * Get the context IDs for the engine.\n\t * @returns The context IDs or undefined if none are set.\n\t */\n\tpublic getContextIds(): IContextIds | undefined {\n\t\treturn this._contextIds;\n\t}\n\n\t/**\n\t * Start the engine core.\n\t * @returns True if the start was successful.\n\t */\n\tpublic async start(): Promise<boolean> {\n\t\tif (this._isStarted) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.setupEngineLogger();\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.starting`));\n\n\t\tif (this._context.config.debug) {\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.debuggingEnabled`));\n\t\t}\n\n\t\tlet canContinue;\n\t\ttry {\n\t\t\tcanContinue = await this.stateLoad();\n\n\t\t\tif (canContinue) {\n\t\t\t\tfor (const { type, module, method } of this._typeInitialisers) {\n\t\t\t\t\tawait this.initialiseTypeConfig(type, module, method);\n\t\t\t\t}\n\n\t\t\t\tawait this.bootstrap();\n\n\t\t\t\tawait this.logInfo(\n\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsStarting`)\n\t\t\t\t);\n\n\t\t\t\tawait ContextIdStore.run(this._contextIds ?? {}, async () => {\n\t\t\t\t\tfor (const instance of this._context.componentInstances) {\n\t\t\t\t\t\tconst startMethod = instance.component.start?.bind(instance.component);\n\t\t\t\t\t\tif (Is.function(startMethod)) {\n\t\t\t\t\t\t\tawait this.logInfo(\n\t\t\t\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentStarting`, {\n\t\t\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait startMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tawait this.logError(\n\t\t\t\t\t\t\t\t\tnew GeneralError(\n\t\t\t\t\t\t\t\t\t\tEngineCore.CLASS_NAME,\n\t\t\t\t\t\t\t\t\t\t\"componentStartFailed\",\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tBaseError.fromError(err)\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tthrow err;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tawait this.logInfo(\n\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsComplete`)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.started`));\n\t\t\tthis._isStarted = true;\n\t\t} catch (err) {\n\t\t\tcanContinue = false;\n\t\t\tawait this.logError(BaseError.fromError(err));\n\t\t} finally {\n\t\t\tif (!(await this.stateSave())) {\n\t\t\t\tcanContinue = false;\n\t\t\t}\n\t\t}\n\n\t\treturn canContinue;\n\t}\n\n\t/**\n\t * Stop the engine core.\n\t * @returns Nothing.\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.stopping`));\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsStopping`));\n\n\t\tawait ContextIdStore.run(this._contextIds ?? {}, async () => {\n\t\t\tfor (const instance of this._context.componentInstances) {\n\t\t\t\tconst stopMethod = instance.component.stop?.bind(instance.component);\n\t\t\t\tif (Is.function(stopMethod)) {\n\t\t\t\t\tawait this.logInfo(\n\t\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentStopping`, {\n\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait stopMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tawait this.logError(\n\t\t\t\t\t\t\tnew GeneralError(\n\t\t\t\t\t\t\t\tEngineCore.CLASS_NAME,\n\t\t\t\t\t\t\t\t\"componentStopFailed\",\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tBaseError.fromError(err)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait this.stateSave();\n\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsStopped`));\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.stopped`));\n\t}\n\n\t/**\n\t * Is the engine started.\n\t * @returns True if the engine is started.\n\t */\n\tpublic isStarted(): boolean {\n\t\treturn this._isStarted;\n\t}\n\n\t/**\n\t * Is this the primary engine instance.\n\t * @returns True if the engine is the primary instance.\n\t */\n\tpublic isPrimary(): boolean {\n\t\treturn isMainThread && !this._isClone;\n\t}\n\n\t/**\n\t * Is this engine instance a clone.\n\t * @returns True if the engine instance is a clone.\n\t */\n\tpublic isClone(): boolean {\n\t\treturn this._isClone;\n\t}\n\n\t/**\n\t * Log info.\n\t * @param message The message to log.\n\t */\n\tpublic async logInfo(message: string): Promise<void> {\n\t\tawait this._engineLoggingComponent?.log({\n\t\t\tsource: EngineCore.CLASS_NAME,\n\t\t\tlevel: \"info\",\n\t\t\tmessage\n\t\t});\n\t}\n\n\t/**\n\t * Log error.\n\t * @param error The error to log.\n\t */\n\tpublic async logError(error: IError): Promise<void> {\n\t\tconst formattedErrors = ErrorHelper.localizeErrors(error);\n\t\tfor (const formattedError of formattedErrors) {\n\t\t\tlet message = Is.stringValue(formattedError.source)\n\t\t\t\t? `${formattedError.source}: ${formattedError.message}`\n\t\t\t\t: formattedError.message;\n\t\t\tif (this._context.config.debug && Is.stringValue(formattedError.stack)) {\n\t\t\t\tmessage += `\\n${formattedError.stack}`;\n\t\t\t}\n\t\t\tawait this._engineLoggingComponent?.log({\n\t\t\t\tsource: EngineCore.CLASS_NAME,\n\t\t\t\tlevel: \"error\",\n\t\t\t\tmessage\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Get the config for the engine.\n\t * @returns The config for the engine.\n\t */\n\tpublic getConfig(): C {\n\t\treturn this._context.config;\n\t}\n\n\t/**\n\t * Get the state of the engine.\n\t * @returns The state of the engine.\n\t */\n\tpublic getState(): S {\n\t\treturn this._context.state;\n\t}\n\n\t/**\n\t * Get all the registered instances.\n\t * @returns The registered instances.\n\t */\n\tpublic getRegisteredInstances(): {\n\t\t[name: string]: {\n\t\t\ttype: string;\n\t\t\tisDefault?: boolean;\n\t\t\tfeatures?: string[];\n\t\t}[];\n\t} {\n\t\treturn this._context.registeredInstances;\n\t}\n\n\t/**\n\t * Get the registered instance type for the component/connector.\n\t * @param componentConnectorType The type of the component/connector.\n\t * @param features The requested features of the component, if not specified the default entry will be retrieved.\n\t * @returns The instance type matching the criteria if one is registered.\n\t * @throws If a matching instance was not found.\n\t */\n\tpublic getRegisteredInstanceType(componentConnectorType: string, features?: string[]): string {\n\t\tGuards.stringValue(\n\t\t\tEngineCore.CLASS_NAME,\n\t\t\tnameof(componentConnectorType),\n\t\t\tcomponentConnectorType\n\t\t);\n\n\t\tconst registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);\n\n\t\tif (!Is.stringValue(registeredType)) {\n\t\t\tthrow new GeneralError(EngineCore.CLASS_NAME, \"instanceTypeNotFound\", {\n\t\t\t\ttype: componentConnectorType,\n\t\t\t\tfeatures: (features ?? [\"default\"]).join(\",\")\n\t\t\t});\n\t\t}\n\n\t\treturn registeredType;\n\t}\n\n\t/**\n\t * Get the registered instance type for the component/connector if it exists.\n\t * @param componentConnectorType The type of the component/connector.\n\t * @param features The requested features of the component, if not specified the default entry will be retrieved.\n\t * @returns The instance type matching the criteria if one is registered.\n\t */\n\tpublic getRegisteredInstanceTypeOptional(\n\t\tcomponentConnectorType: string,\n\t\tfeatures?: string[]\n\t): string | undefined {\n\t\tlet registeredType: string | undefined;\n\n\t\tconst registeredTypes = this._context.registeredInstances[componentConnectorType];\n\t\tif (Is.arrayValue(registeredTypes)) {\n\t\t\tif (Is.arrayValue(features)) {\n\t\t\t\tregisteredType = registeredTypes.find(t =>\n\t\t\t\t\tt.features?.every(f => features.includes(f))\n\t\t\t\t)?.type;\n\t\t\t} else {\n\t\t\t\t// First look for the default entry\n\t\t\t\tregisteredType = registeredTypes.find(t => t.isDefault)?.type;\n\n\t\t\t\t// Can't find a default so just use the first entry\n\t\t\t\tif (!Is.stringValue(registeredType)) {\n\t\t\t\t\tregisteredType = registeredTypes[0]?.type;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn registeredType;\n\t}\n\n\t/**\n\t * Get the data required to create a clone of the engine.\n\t * @returns The clone data.\n\t */\n\tpublic getCloneData(): IEngineCoreClone<C, S> {\n\t\tconst entitySchemas: {\n\t\t\t[schema: string]: IEntitySchema;\n\t\t} = {};\n\n\t\tconst entitySchemaNames = EntitySchemaFactory.names();\n\t\tfor (const schemaName of entitySchemaNames) {\n\t\t\tentitySchemas[schemaName] = EntitySchemaFactory.get(schemaName);\n\t\t}\n\n\t\tconst cloneData: IEngineCoreClone<C, S> = {\n\t\t\tconfig: this._context.config,\n\t\t\tstate: this._context.state,\n\t\t\ttypeInitialisers: this._typeInitialisers,\n\t\t\tentitySchemas,\n\t\t\tcontextIdKeys: this._contextIdKeys\n\t\t};\n\n\t\treturn cloneData;\n\t}\n\n\t/**\n\t * Populate the engine from the clone data.\n\t * @param cloneData The clone data to populate from.\n\t * @param silent Should the clone be silent.\n\t */\n\tpublic populateClone(cloneData: IEngineCoreClone<C, S>, silent?: boolean): void {\n\t\tGuards.object(EngineCore.CLASS_NAME, nameof(cloneData), cloneData);\n\t\tGuards.object(EngineCore.CLASS_NAME, nameof(cloneData.config), cloneData.config);\n\t\tGuards.object(EngineCore.CLASS_NAME, nameof(cloneData.state), cloneData.state);\n\t\tGuards.array(\n\t\t\tEngineCore.CLASS_NAME,\n\t\t\tnameof(cloneData.typeInitialisers),\n\t\t\tcloneData.typeInitialisers\n\t\t);\n\n\t\tthis._skipBootstrap = true;\n\t\tthis._isClone = true;\n\n\t\tif (silent ?? false) {\n\t\t\tcloneData.config.silent = true;\n\t\t}\n\n\t\tthis._context = {\n\t\t\tconfig: cloneData.config,\n\t\t\tregisteredInstances: {},\n\t\t\tcomponentInstances: [],\n\t\t\tstate: {} as S,\n\t\t\tstateDirty: false\n\t\t};\n\n\t\tthis._typeInitialisers = cloneData.typeInitialisers;\n\t\tthis._contextIdKeys.push(...cloneData.contextIdKeys);\n\n\t\tfor (const schemaName of Object.keys(cloneData.entitySchemas)) {\n\t\t\tEntitySchemaFactory.register(schemaName, () => cloneData.entitySchemas[schemaName]);\n\t\t}\n\n\t\tthis._stateStorage = new MemoryStateStorage(true, cloneData.state);\n\t\tthis._isStarted = false;\n\t}\n\n\t/**\n\t * Initialise the types from connector.\n\t * @param typeKey The key for the default types.\n\t * @param instanceMethod The function to initialise the instance.\n\t * @internal\n\t */\n\tprivate async initialiseTypeConfig(\n\t\ttypeKey: string,\n\t\tmodule: string,\n\t\tmethod: string\n\t): Promise<void> {\n\t\tconst typeConfig: IEngineCoreTypeConfig[] | undefined = this._context.config.types?.[typeKey];\n\n\t\tif (Is.arrayValue(typeConfig)) {\n\t\t\tconst instanceMethod = await ModuleHelper.getModuleEntry<EngineTypeInitialiser>(\n\t\t\t\tmodule,\n\t\t\t\tmethod\n\t\t\t);\n\n\t\t\tfor (let i = 0; i < typeConfig.length; i++) {\n\t\t\t\tawait this.logInfo(\n\t\t\t\t\tI18n.formatMessage(\"engineCore.configuring\", {\n\t\t\t\t\t\tcomponentType: typeKey,\n\t\t\t\t\t\tconfigType: typeConfig[i].type\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tconst result = await instanceMethod(this, this._context, typeConfig[i]);\n\n\t\t\t\tif (Is.stringValue(result.instanceType) && Is.object(result.component)) {\n\t\t\t\t\tconst finalInstanceType = typeConfig[i].overrideInstanceType ?? result.instanceType;\n\t\t\t\t\tthis._context.componentInstances.push({\n\t\t\t\t\t\tinstanceType: finalInstanceType,\n\t\t\t\t\t\tcomponent: result.component\n\t\t\t\t\t});\n\n\t\t\t\t\tresult.factory?.register(finalInstanceType, () => result.component);\n\n\t\t\t\t\tthis._context.registeredInstances[typeKey] ??= [];\n\n\t\t\t\t\tthis._context.registeredInstances[typeKey].push({\n\t\t\t\t\t\ttype: finalInstanceType,\n\t\t\t\t\t\tisDefault: typeConfig[i].isDefault,\n\t\t\t\t\t\tfeatures: typeConfig[i].features\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthrow new GeneralError(\"engineCore\", \"componentUnknownType\", {\n\t\t\t\t\t\ttype: typeConfig[i].type,\n\t\t\t\t\t\tcomponentType: typeKey\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Setup the engine logger.\n\t * @internal\n\t */\n\tprivate setupEngineLogger(): void {\n\t\tconst silent = this._context.config.silent ?? false;\n\t\tconst engineLoggerConnector = silent\n\t\t\t? new SilentLoggingConnector()\n\t\t\t: new ConsoleLoggingConnector({\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\ttranslateMessages: true,\n\t\t\t\t\t\thideGroups: true\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\tthis._context.componentInstances.push({\n\t\t\tinstanceType: EngineCore.LOGGING_CONNECTOR_TYPE_NAME,\n\t\t\tcomponent: engineLoggerConnector\n\t\t});\n\n\t\tLoggingConnectorFactory.register(\n\t\t\tEngineCore.LOGGING_CONNECTOR_TYPE_NAME,\n\t\t\t() => engineLoggerConnector\n\t\t);\n\n\t\tthis._context.registeredInstances.loggingConnector = [\n\t\t\t{\n\t\t\t\ttype: EngineCore.LOGGING_CONNECTOR_TYPE_NAME\n\t\t\t}\n\t\t];\n\n\t\tconst engineLoggerComponent = new LoggingService({\n\t\t\tloggingConnectorType: EngineCore.LOGGING_CONNECTOR_TYPE_NAME\n\t\t});\n\t\tthis._engineLoggingComponent = engineLoggerComponent;\n\n\t\tComponentFactory.register(EngineCore.LOGGING_COMPONENT_TYPE_NAME, () => engineLoggerComponent);\n\t\tthis._context.registeredInstances.loggingComponent = [\n\t\t\t{\n\t\t\t\ttype: EngineCore.LOGGING_COMPONENT_TYPE_NAME\n\t\t\t}\n\t\t];\n\t}\n\n\t/**\n\t * Load the state.\n\t * @returns True if the state was loaded and can continue.\n\t * @internal\n\t */\n\tprivate async stateLoad(): Promise<boolean> {\n\t\tif (this._stateStorage) {\n\t\t\ttry {\n\t\t\t\tthis._context.state = ((await this._stateStorage.load(this)) ?? {}) as S;\n\t\t\t\tthis._context.stateDirty = false;\n\n\t\t\t\treturn true;\n\t\t\t} catch (err) {\n\t\t\t\tawait this.logError(BaseError.fromError(err));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Save the state.\n\t * @returns True if the state was saved.\n\t * @internal\n\t */\n\tprivate async stateSave(): Promise<boolean> {\n\t\tif (this._stateStorage && !Is.empty(this._context.state) && this._context.stateDirty) {\n\t\t\ttry {\n\t\t\t\tawait this._stateStorage.save(this, this._context.state);\n\t\t\t\tthis._context.stateDirty = false;\n\t\t\t\treturn true;\n\t\t\t} catch (err) {\n\t\t\t\tawait this.logError(BaseError.fromError(err));\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Bootstrap the engine.\n\t * @internal\n\t */\n\tprivate async bootstrap(): Promise<void> {\n\t\tif (!this._skipBootstrap) {\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.bootstrapStarted`));\n\n\t\t\t// First bootstrap the components.\n\t\t\tfor (const instance of this._context.componentInstances) {\n\t\t\t\tconst bootstrapMethod = instance.component.bootstrap?.bind(instance.component);\n\t\t\t\tif (Is.function(bootstrapMethod)) {\n\t\t\t\t\tawait this.logInfo(\n\t\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.bootstrapping`, {\n\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\tconst bootstrapSuccess = await bootstrapMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);\n\n\t\t\t\t\t// If the bootstrap method failed then throw an error\n\t\t\t\t\tif (!bootstrapSuccess) {\n\t\t\t\t\t\tthrow new GeneralError(EngineCore.CLASS_NAME, \"bootstrapFailed\", {\n\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Now perform any custom bootstrap operations\n\t\t\tconst customBootstrap = this._customBootstrap;\n\t\t\tif (Is.function(customBootstrap)) {\n\t\t\t\tawait customBootstrap.call(this, this, this._context);\n\t\t\t}\n\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.bootstrapComplete`));\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,8 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export * from "./engineCore.js";
4
+ export * from "./models/IEngineCoreOptions.js";
5
+ export * from "./storage/fileStateStorage.js";
6
+ export * from "./storage/memoryStateStorage.js";
7
+ export * from "./utils/engineModuleHelper.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./engineCore.js\";\nexport * from \"./models/IEngineCoreOptions.js\";\nexport * from \"./storage/fileStateStorage.js\";\nexport * from \"./storage/memoryStateStorage.js\";\nexport * from \"./utils/engineModuleHelper.js\";\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=IEngineCoreOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEngineCoreOptions.js","sourceRoot":"","sources":["../../../src/models/IEngineCoreOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIEngineCore,\n\tIEngineCoreConfig,\n\tIEngineCoreContext,\n\tIEngineState,\n\tIEngineStateStorage\n} from \"@twin.org/engine-models\";\n\n/**\n * The options for creating engine core.\n */\nexport interface IEngineCoreOptions<\n\tC extends IEngineCoreConfig = IEngineCoreConfig,\n\tS extends IEngineState = IEngineState\n> {\n\t/**\n\t * The engine core config.\n\t */\n\tconfig?: C;\n\n\t/**\n\t * The state storage component.\n\t */\n\tstateStorage?: IEngineStateStorage<S>;\n\n\t/**\n\t * Skip the bootstrap process, useful for additional engine instances.\n\t */\n\tskipBootstrap?: boolean;\n\n\t/**\n\t * Populate the type initialisers for the engine.\n\t */\n\tpopulateTypeInitialisers?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => void;\n\n\t/**\n\t * Custom bootstrap method for the engine.\n\t */\n\tcustomBootstrap?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => Promise<void>;\n}\n"]}