@twin.org/node-core 0.0.2-next.16 → 0.0.2-next.18

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.
Files changed (38) hide show
  1. package/dist/cjs/index.cjs +211 -75
  2. package/dist/esm/index.mjs +203 -77
  3. package/dist/types/builders/engineServerEnvBuilder.d.ts +1 -1
  4. package/dist/types/builders/extensionsBuilder.d.ts +32 -0
  5. package/dist/types/defaults.d.ts +6 -0
  6. package/dist/types/index.d.ts +4 -0
  7. package/dist/types/models/IEngineEnvironmentVariables.d.ts +35 -14
  8. package/dist/types/models/INodeEngineConfig.d.ts +6 -0
  9. package/dist/types/models/INodeOptions.d.ts +2 -1
  10. package/dist/types/models/nodeExtensionMethods.d.ts +27 -0
  11. package/dist/types/node.d.ts +2 -2
  12. package/dist/types/server.d.ts +4 -2
  13. package/docs/changelog.md +15 -0
  14. package/docs/reference/functions/buildConfiguration.md +2 -2
  15. package/docs/reference/functions/buildEngineServerConfiguration.md +1 -1
  16. package/docs/reference/functions/extensionsConfiguration.md +25 -0
  17. package/docs/reference/functions/extensionsInitialiseEngine.md +25 -0
  18. package/docs/reference/functions/extensionsInitialiseEngineServer.md +31 -0
  19. package/docs/reference/functions/shutdownExtensions.md +25 -0
  20. package/docs/reference/functions/start.md +4 -4
  21. package/docs/reference/index.md +15 -0
  22. package/docs/reference/interfaces/IEngineEnvironmentVariables.md +73 -22
  23. package/docs/reference/interfaces/IEngineServerEnvironmentVariables.md +101 -30
  24. package/docs/reference/interfaces/INodeEngineConfig.md +7 -0
  25. package/docs/reference/interfaces/INodeEnvironmentVariables.md +101 -30
  26. package/docs/reference/interfaces/INodeOptions.md +6 -2
  27. package/docs/reference/type-aliases/NodeExtensionInitialiseEngineMethod.md +18 -0
  28. package/docs/reference/type-aliases/NodeExtensionInitialiseEngineServerMethod.md +24 -0
  29. package/docs/reference/type-aliases/NodeExtensionInitialiseMethod.md +23 -0
  30. package/docs/reference/type-aliases/NodeExtensionShutdownMethod.md +10 -0
  31. package/docs/reference/variables/ATTESTATION_VERIFICATION_METHOD_ID.md +3 -0
  32. package/docs/reference/variables/AUTH_SIGNING_KEY_ID.md +3 -0
  33. package/docs/reference/variables/BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
  34. package/docs/reference/variables/IMMUTABLE_PROOF_VERIFICATION_METHOD_ID.md +3 -0
  35. package/docs/reference/variables/SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
  36. package/docs/reference/variables/VC_AUTHENTICATION_VERIFICATION_METHOD_ID.md +3 -0
  37. package/locales/en.json +9 -2
  38. package/package.json +13 -1
@@ -1,5 +1,5 @@
1
1
  import { PasswordHelper } from '@twin.org/api-auth-entity-storage-service';
2
- import { I18n, Is, Coerce, Converter, RandomHelper, Urn, GeneralError, ErrorHelper, EnvHelper } from '@twin.org/core';
2
+ import { I18n, Is, Coerce, Converter, RandomHelper, Urn, GeneralError, EnvHelper } from '@twin.org/core';
3
3
  import { PasswordGenerator, Bip39 } from '@twin.org/crypto';
4
4
  import { AuthenticationComponentType, InformationComponentType, RestRouteProcessorType, SocketRouteProcessorType, AuthenticationAdminComponentType } from '@twin.org/engine-server-types';
5
5
  import { WalletConnectorType, IdentityConnectorType, EntityStorageConnectorType, BlobStorageConnectorType, BlobStorageComponentType, VaultConnectorType, DltConfigType, LoggingConnectorType, LoggingComponentType, BackgroundTaskConnectorType, TaskSchedulerComponentType, EventBusConnectorType, EventBusComponentType, TelemetryConnectorType, TelemetryComponentType, MessagingEmailConnectorType, MessagingSmsConnectorType, MessagingPushNotificationConnectorType, MessagingAdminComponentType, MessagingComponentType, FaucetConnectorType, EngineTypeHelper, NftConnectorType, NftComponentType, VerifiableStorageConnectorType, VerifiableStorageComponentType, ImmutableProofComponentType, IdentityComponentType, IdentityResolverConnectorType, IdentityResolverComponentType, IdentityProfileConnectorType, IdentityProfileComponentType, AttestationConnectorType, AttestationComponentType, DataProcessingComponentType, DataConverterConnectorType, DataExtractorConnectorType, AuditableItemGraphComponentType, AuditableItemStreamComponentType, DocumentManagementComponentType, AuthenticationGeneratorComponentType, RightsManagementPapComponentType, RightsManagementPmpComponentType, RightsManagementPipComponentType, RightsManagementPxpComponentType, RightsManagementPdpComponentType, RightsManagementPepComponentType, RightsManagementPnpComponentType, RightsManagementPnapComponentType, RightsManagementDapComponentType, RightsManagementDarpComponentType, SynchronisedStorageComponentType, FederatedCatalogueComponentType, DataSpaceConnectorComponentType } from '@twin.org/engine-types';
@@ -9,6 +9,7 @@ import { VaultConnectorFactory, VaultKeyType } from '@twin.org/vault-models';
9
9
  import { WalletConnectorFactory } from '@twin.org/wallet-models';
10
10
  import { readFile, stat, readdir } from 'node:fs/promises';
11
11
  import path from 'node:path';
12
+ import { CLIDisplay } from '@twin.org/cli-core';
12
13
  import { PolicyNegotiationPointClient, DataAccessPointClient } from '@twin.org/rights-management-rest-client';
13
14
  import { addDefaultRestPaths, addDefaultSocketPaths, EngineServer } from '@twin.org/engine-server';
14
15
  import { ModuleHelper } from '@twin.org/modules';
@@ -17,6 +18,15 @@ import { Engine } from '@twin.org/engine';
17
18
  import { FileStateStorage } from '@twin.org/engine-core';
18
19
  import { EngineCoreFactory } from '@twin.org/engine-models';
19
20
 
21
+ // Copyright 2024 IOTA Stiftung.
22
+ // SPDX-License-Identifier: Apache-2.0.
23
+ const ATTESTATION_VERIFICATION_METHOD_ID = "attestation-assertion";
24
+ const IMMUTABLE_PROOF_VERIFICATION_METHOD_ID = "immutable-proof-assertion";
25
+ const BLOB_STORAGE_ENCRYPTION_KEY_ID = "blob-encryption";
26
+ const SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID = "synchronised-storage-blob-encryption";
27
+ const VC_AUTHENTICATION_VERIFICATION_METHOD_ID = "node-authentication-assertion";
28
+ const AUTH_SIGNING_KEY_ID = "auth-signing";
29
+
20
30
  // Copyright 2024 IOTA Stiftung.
21
31
  // SPDX-License-Identifier: Apache-2.0.
22
32
  /**
@@ -40,20 +50,19 @@ const NodeFeatures = {
40
50
 
41
51
  // Copyright 2024 IOTA Stiftung.
42
52
  // SPDX-License-Identifier: Apache-2.0.
43
- /* eslint-disable no-console */
44
53
  /**
45
54
  * Initialise the locales for the application.
46
55
  * @param localesDirectory The directory containing the locales.
47
56
  */
48
57
  async function initialiseLocales(localesDirectory) {
49
58
  const localesFile = path.resolve(path.join(localesDirectory, "en.json"));
50
- console.info("Locales File:", localesFile);
59
+ CLIDisplay.value("Locales File", localesFile);
51
60
  if (await fileExists(localesFile)) {
52
61
  const enLangContent = await readFile(localesFile, "utf8");
53
62
  I18n.addDictionary("en", JSON.parse(enLangContent));
54
63
  }
55
64
  else {
56
- console.warn(`Locales file not found: ${localesFile}`);
65
+ CLIDisplay.error(`Locales file not found: ${localesFile}`);
57
66
  }
58
67
  }
59
68
  /**
@@ -188,10 +197,16 @@ async function bootstrap(engineCore, context, envVars) {
188
197
  await bootstrapNodeUser(engineCore, context, envVars, features);
189
198
  await bootstrapAuth(engineCore, context, envVars);
190
199
  await bootstrapBlobEncryption(engineCore, context, envVars);
191
- await addVerificationMethod(engineCore, context, "attestation", envVars.attestationVerificationMethodId);
192
- await addVerificationMethod(engineCore, context, "immutable proof", envVars.immutableProofVerificationMethodId);
200
+ const defaultAttestationConnectorType = engineCore.getRegisteredInstanceTypeOptional("attestationConnector");
201
+ if (!Is.empty(defaultAttestationConnectorType)) {
202
+ await addVerificationMethod(engineCore, context, "attestation", envVars.attestationVerificationMethodId ?? ATTESTATION_VERIFICATION_METHOD_ID);
203
+ }
204
+ const defaultImmutableProofComponentType = engineCore.getRegisteredInstanceTypeOptional("immutableProofComponent");
205
+ if (!Is.empty(defaultImmutableProofComponentType)) {
206
+ await addVerificationMethod(engineCore, context, "immutable proof", envVars.immutableProofVerificationMethodId ?? IMMUTABLE_PROOF_VERIFICATION_METHOD_ID);
207
+ }
193
208
  if (Coerce.boolean(envVars.vcAuthenticationEnabled) ?? false) {
194
- await addVerificationMethod(engineCore, context, "verifiable credential authentication", envVars.vcAuthenticationVerificationMethodId);
209
+ await addVerificationMethod(engineCore, context, "verifiable credential authentication", envVars.vcAuthenticationVerificationMethodId ?? VC_AUTHENTICATION_VERIFICATION_METHOD_ID);
195
210
  }
196
211
  await bootstrapSynchronisedStorage(engineCore, context, envVars);
197
212
  }
@@ -467,7 +482,7 @@ async function bootstrapBlobEncryption(engineCore, context, envVars, features) {
467
482
  // Create a new key for encrypting blobs
468
483
  const defaultVaultConnectorType = engineCore.getRegisteredInstanceType("vaultConnector");
469
484
  const vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);
470
- const keyName = `${context.state.nodeIdentity}/${envVars.blobStorageEncryptionKeyId}`;
485
+ const keyName = `${context.state.nodeIdentity}/${envVars.blobStorageEncryptionKeyId ?? BLOB_STORAGE_ENCRYPTION_KEY_ID}`;
471
486
  let existingKey;
472
487
  try {
473
488
  existingKey = await vaultConnector.getKey(keyName);
@@ -507,7 +522,7 @@ async function bootstrapAuth(engineCore, context, envVars, features) {
507
522
  // Create a new JWT signing key and a user login for the node
508
523
  const defaultVaultConnectorType = engineCore.getRegisteredInstanceType("vaultConnector");
509
524
  const vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);
510
- const keyName = `${context.state.nodeIdentity}/${envVars.authSigningKeyId}`;
525
+ const keyName = `${context.state.nodeIdentity}/${envVars.authSigningKeyId ?? AUTH_SIGNING_KEY_ID}`;
511
526
  let existingKey;
512
527
  try {
513
528
  existingKey = await vaultConnector.getKey(keyName);
@@ -532,11 +547,11 @@ async function bootstrapAuth(engineCore, context, envVars, features) {
532
547
  async function bootstrapSynchronisedStorage(engineCore, context, envVars, features) {
533
548
  if (Coerce.boolean(envVars.synchronisedStorageEnabled) ?? false) {
534
549
  // If this is a trusted node we need to add the blob encryption key pair
535
- if (Is.stringValue(envVars.synchronisedStorageBlobStorageEncryptionKeyId) &&
536
- Is.stringBase64(envVars.synchronisedStorageBlobStorageKey)) {
550
+ if (Is.stringBase64(envVars.synchronisedStorageBlobStorageKey)) {
537
551
  const defaultVaultConnectorType = engineCore.getRegisteredInstanceType("vaultConnector");
538
552
  const vaultConnector = VaultConnectorFactory.get(defaultVaultConnectorType);
539
- const keyName = envVars.synchronisedStorageBlobStorageEncryptionKeyId;
553
+ const keyName = envVars.synchronisedStorageBlobStorageEncryptionKeyId ??
554
+ SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID;
540
555
  let existingKey;
541
556
  try {
542
557
  existingKey = await vaultConnector.getKey(keyName);
@@ -604,12 +619,6 @@ async function buildEngineConfiguration(envVars) {
604
619
  envVars.storageFileRoot = path.resolve(envVars.storageFileRoot);
605
620
  envVars.stateFilename = path.join(envVars.storageFileRoot, envVars.stateFilename);
606
621
  }
607
- envVars.attestationVerificationMethodId ??= "attestation-assertion";
608
- envVars.immutableProofVerificationMethodId ??= "immutable-proof-assertion";
609
- envVars.blobStorageEnableEncryption ??= "false";
610
- envVars.blobStorageEncryptionKeyId ??= "blob-encryption";
611
- envVars.synchronisedStorageBlobStorageEncryptionKeyId ??= "synchronised-storage-blob-encryption";
612
- envVars.vcAuthenticationVerificationMethodId ??= "node-authentication-assertion";
613
622
  const coreConfig = {
614
623
  debug: Coerce.boolean(envVars.debug) ?? false,
615
624
  types: {}
@@ -672,9 +681,10 @@ async function configureEntityStorage(coreConfig, envVars) {
672
681
  options: {
673
682
  config: {
674
683
  region: envVars.awsDynamodbRegion ?? "",
675
- accessKeyId: envVars.awsDynamodbAccessKeyId ?? "",
676
- secretAccessKey: envVars.awsDynamodbSecretAccessKey ?? "",
677
- endpoint: envVars.awsDynamodbEndpoint ?? ""
684
+ authMode: envVars.awsDynamodbAuthMode,
685
+ accessKeyId: envVars.awsDynamodbAccessKeyId,
686
+ secretAccessKey: envVars.awsDynamodbSecretAccessKey,
687
+ endpoint: envVars.awsDynamodbEndpoint
678
688
  },
679
689
  tablePrefix: envVars.entityStorageTablePrefix
680
690
  }
@@ -831,9 +841,10 @@ async function configureBlobStorage(coreConfig, envVars) {
831
841
  config: {
832
842
  region: envVars.awsS3Region ?? "",
833
843
  bucketName: envVars.awsS3BucketName ?? "",
834
- accessKeyId: envVars.awsS3AccessKeyId ?? "",
835
- secretAccessKey: envVars.awsS3SecretAccessKey ?? "",
836
- endpoint: envVars.awsS3Endpoint ?? ""
844
+ authMode: envVars.awsS3AuthMode,
845
+ accessKeyId: envVars.awsS3AccessKeyId,
846
+ secretAccessKey: envVars.awsS3SecretAccessKey,
847
+ endpoint: envVars.awsS3Endpoint
837
848
  },
838
849
  storagePrefix: envVars.blobStoragePrefix
839
850
  }
@@ -890,7 +901,7 @@ async function configureBlobStorage(coreConfig, envVars) {
890
901
  options: {
891
902
  config: {
892
903
  vaultKeyId: (envVars.blobStorageEnableEncryption ?? false)
893
- ? envVars.blobStorageEncryptionKeyId
904
+ ? (envVars.blobStorageEncryptionKeyId ?? BLOB_STORAGE_ENCRYPTION_KEY_ID)
894
905
  : undefined
895
906
  }
896
907
  }
@@ -1030,10 +1041,11 @@ async function configureMessaging(coreConfig, envVars) {
1030
1041
  type: MessagingEmailConnectorType.Aws,
1031
1042
  options: {
1032
1043
  config: {
1033
- region: envVars.awsS3Region ?? "",
1034
- accessKeyId: envVars.awsS3AccessKeyId ?? "",
1035
- secretAccessKey: envVars.awsS3SecretAccessKey ?? "",
1036
- endpoint: envVars.awsS3Endpoint ?? ""
1044
+ region: envVars.awsSesRegion ?? "",
1045
+ authMode: envVars.awsSesAuthMode,
1046
+ accessKeyId: envVars.awsSesAccessKeyId,
1047
+ secretAccessKey: envVars.awsSesSecretAccessKey,
1048
+ endpoint: envVars.awsSesEndpoint
1037
1049
  }
1038
1050
  }
1039
1051
  });
@@ -1048,10 +1060,11 @@ async function configureMessaging(coreConfig, envVars) {
1048
1060
  type: MessagingSmsConnectorType.Aws,
1049
1061
  options: {
1050
1062
  config: {
1051
- region: envVars.awsS3Region ?? "",
1052
- accessKeyId: envVars.awsS3AccessKeyId ?? "",
1053
- secretAccessKey: envVars.awsS3SecretAccessKey ?? "",
1054
- endpoint: envVars.awsS3Endpoint ?? ""
1063
+ region: envVars.awsSesRegion ?? "",
1064
+ authMode: envVars.awsSesAuthMode,
1065
+ accessKeyId: envVars.awsSesAccessKeyId,
1066
+ secretAccessKey: envVars.awsSesSecretAccessKey,
1067
+ endpoint: envVars.awsSesEndpoint
1055
1068
  }
1056
1069
  }
1057
1070
  });
@@ -1068,8 +1081,9 @@ async function configureMessaging(coreConfig, envVars) {
1068
1081
  options: {
1069
1082
  config: {
1070
1083
  region: envVars.awsSesRegion ?? "",
1071
- accessKeyId: envVars.awsSesAccessKeyId ?? "",
1072
- secretAccessKey: envVars.awsSesSecretAccessKey ?? "",
1084
+ authMode: envVars.awsSesAuthMode,
1085
+ accessKeyId: envVars.awsSesAccessKeyId,
1086
+ secretAccessKey: envVars.awsSesSecretAccessKey,
1073
1087
  endpoint: envVars.awsSesEndpoint,
1074
1088
  applicationsSettings: Is.json(envVars.awsMessagingPushNotificationApplications)
1075
1089
  ? JSON.parse(envVars.awsMessagingPushNotificationApplications)
@@ -1199,7 +1213,7 @@ async function configureVerifiableStorage(coreConfig, envVars) {
1199
1213
  type: ImmutableProofComponentType.Service,
1200
1214
  options: {
1201
1215
  config: {
1202
- verificationMethodId: envVars.immutableProofVerificationMethodId
1216
+ verificationMethodId: envVars.immutableProofVerificationMethodId ?? IMMUTABLE_PROOF_VERIFICATION_METHOD_ID
1203
1217
  }
1204
1218
  }
1205
1219
  });
@@ -1304,7 +1318,7 @@ async function configureAttestation(coreConfig, envVars) {
1304
1318
  type: AttestationComponentType.Service,
1305
1319
  options: {
1306
1320
  config: {
1307
- verificationMethodId: envVars.attestationVerificationMethodId
1321
+ verificationMethodId: envVars.attestationVerificationMethodId ?? ATTESTATION_VERIFICATION_METHOD_ID
1308
1322
  }
1309
1323
  }
1310
1324
  });
@@ -1395,7 +1409,9 @@ async function configureVerifiableCredentialAuthentication(coreConfig, envVars)
1395
1409
  coreConfig.types.authenticationGeneratorComponent.push({
1396
1410
  type: AuthenticationGeneratorComponentType.VerifiableCredential,
1397
1411
  options: {
1398
- config: { verificationMethodId: envVars.vcAuthenticationVerificationMethodId ?? "" }
1412
+ config: {
1413
+ verificationMethodId: envVars.vcAuthenticationVerificationMethodId ?? VC_AUTHENTICATION_VERIFICATION_METHOD_ID
1414
+ }
1399
1415
  },
1400
1416
  features: ["verifiable-credential"]
1401
1417
  });
@@ -1523,7 +1539,8 @@ async function configureSynchronisedStorage(coreConfig, envVars) {
1523
1539
  options: {
1524
1540
  config: {
1525
1541
  verifiableStorageKeyId: verifiableStorageKeyId ?? "",
1526
- blobStorageEncryptionKeyId: envVars.synchronisedStorageBlobStorageEncryptionKeyId,
1542
+ blobStorageEncryptionKeyId: envVars.synchronisedStorageBlobStorageEncryptionKeyId ??
1543
+ SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID,
1527
1544
  entityUpdateIntervalMinutes: Coerce.number(envVars.synchronisedStorageEntityUpdateIntervalMinutes),
1528
1545
  consolidationIntervalMinutes: Coerce.number(envVars.synchronisedStorageConsolidationIntervalMinutes),
1529
1546
  consolidationBatchSize: Coerce.number(envVars.synchronisedStorageConsolidationBatchSize),
@@ -1576,9 +1593,8 @@ async function configureDataSpaceConnector(coreConfig, envVars) {
1576
1593
  type: DataSpaceConnectorComponentType.Service,
1577
1594
  options: {
1578
1595
  config: {
1579
- dataSpaceConnectorAppDescriptors: Is.arrayValue(envVars.dataSpaceConnectorApps)
1580
- ? envVars.dataSpaceConnectorApps
1581
- : undefined
1596
+ retainActivityLogsFor: Coerce.number(envVars.dataSpaceConnectorRetainActivityLogsFor),
1597
+ activityLogsCleanUpInterval: Coerce.number(envVars.dataSpaceConnectorActivityLogsCleanUpInterval)
1582
1598
  }
1583
1599
  }
1584
1600
  });
@@ -1624,10 +1640,9 @@ async function configureDlt(coreConfig, envVars) {
1624
1640
  * @param serverInfo The server information.
1625
1641
  * @param openApiSpecPath The path to the open api spec.
1626
1642
  * @param favIconPath The path to the favicon.
1627
- * @returns The the config for the core and the server.
1643
+ * @returns The config for the core and the server.
1628
1644
  */
1629
1645
  async function buildEngineServerConfiguration(envVars, coreEngineConfig, serverInfo, openApiSpecPath, favIconPath) {
1630
- envVars.authSigningKeyId ??= "auth-signing";
1631
1646
  const webServerOptions = {
1632
1647
  port: Coerce.number(envVars.port),
1633
1648
  host: Coerce.string(envVars.host),
@@ -1743,7 +1758,7 @@ async function buildEngineServerConfiguration(envVars, coreEngineConfig, serverI
1743
1758
  type: AuthenticationComponentType.EntityStorage,
1744
1759
  options: {
1745
1760
  config: {
1746
- signingKeyName: envVars.authSigningKeyId
1761
+ signingKeyName: envVars.authSigningKeyId ?? AUTH_SIGNING_KEY_ID
1747
1762
  }
1748
1763
  }
1749
1764
  });
@@ -1751,7 +1766,7 @@ async function buildEngineServerConfiguration(envVars, coreEngineConfig, serverI
1751
1766
  type: RestRouteProcessorType.AuthHeader,
1752
1767
  options: {
1753
1768
  config: {
1754
- signingKeyName: envVars.authSigningKeyId
1769
+ signingKeyName: envVars.authSigningKeyId ?? AUTH_SIGNING_KEY_ID
1755
1770
  }
1756
1771
  }
1757
1772
  });
@@ -1759,7 +1774,7 @@ async function buildEngineServerConfiguration(envVars, coreEngineConfig, serverI
1759
1774
  type: SocketRouteProcessorType.AuthHeader,
1760
1775
  options: {
1761
1776
  config: {
1762
- signingKeyName: envVars.authSigningKeyId
1777
+ signingKeyName: envVars.authSigningKeyId ?? AUTH_SIGNING_KEY_ID
1763
1778
  }
1764
1779
  }
1765
1780
  });
@@ -1779,15 +1794,111 @@ async function buildEngineServerConfiguration(envVars, coreEngineConfig, serverI
1779
1794
 
1780
1795
  // Copyright 2024 IOTA Stiftung.
1781
1796
  // SPDX-License-Identifier: Apache-2.0.
1782
- /* eslint-disable no-console */
1797
+ /**
1798
+ * Handles the configuration of the extensions.
1799
+ * @param envVars The environment variables for the node.
1800
+ * @param nodeEngineConfig The node engine config.
1801
+ * @returns The config for the core and the server.
1802
+ */
1803
+ async function extensionsConfiguration(envVars, nodeEngineConfig) {
1804
+ if (Is.stringValue(envVars.extensions)) {
1805
+ const extensions = envVars.extensions.split(",");
1806
+ for (const extension of extensions) {
1807
+ let initialiseConfigMethod;
1808
+ try {
1809
+ CLIDisplay.value(I18n.formatMessage("node.extensionLoading"), extension);
1810
+ initialiseConfigMethod = await ModuleHelper.getModuleMethod(extension, "extensionInitialise");
1811
+ }
1812
+ catch (err) {
1813
+ throw new GeneralError("node", "extensionLoadingError", { extension }, err);
1814
+ }
1815
+ if (Is.function(initialiseConfigMethod)) {
1816
+ await initialiseConfigMethod(envVars, nodeEngineConfig);
1817
+ }
1818
+ }
1819
+ }
1820
+ return nodeEngineConfig;
1821
+ }
1822
+ /**
1823
+ * Handles the initialisation of the extensions when the engine has been constructed.
1824
+ * @param envVars The environment variables for the node.
1825
+ * @param engineCore The engine core instance.
1826
+ * @returns Nothing.
1827
+ */
1828
+ async function extensionsInitialiseEngine(envVars, engineCore) {
1829
+ if (Is.stringValue(envVars.extensions)) {
1830
+ const extensions = envVars.extensions.split(",");
1831
+ for (const extension of extensions) {
1832
+ let initialiseEngineMethod;
1833
+ try {
1834
+ engineCore.logInfo(I18n.formatMessage("node.extensionInitialisingEngine", { extension }));
1835
+ initialiseEngineMethod =
1836
+ await ModuleHelper.getModuleMethod(extension, "extensionInitialiseEngine");
1837
+ }
1838
+ catch { }
1839
+ if (Is.function(initialiseEngineMethod)) {
1840
+ await initialiseEngineMethod(engineCore);
1841
+ }
1842
+ }
1843
+ }
1844
+ }
1845
+ /**
1846
+ * Handles the initialisation of the extensions when the engine server has been constructed.
1847
+ * @param envVars The environment variables for the node.
1848
+ * @param engineCore The engine core instance.
1849
+ * @param engineServer The engine server instance.
1850
+ * @returns Nothing.
1851
+ */
1852
+ async function extensionsInitialiseEngineServer(envVars, engineCore, engineServer) {
1853
+ if (Is.stringValue(envVars.extensions)) {
1854
+ const extensions = envVars.extensions.split(",");
1855
+ for (const extension of extensions) {
1856
+ let initialiseEngineServerMethod;
1857
+ try {
1858
+ engineCore.logInfo(I18n.formatMessage("node.extensionInitialisingEngineServer", { extension }));
1859
+ initialiseEngineServerMethod =
1860
+ await ModuleHelper.getModuleMethod(extension, "extensionInitialiseEngineServer");
1861
+ }
1862
+ catch { }
1863
+ if (Is.function(initialiseEngineServerMethod)) {
1864
+ await initialiseEngineServerMethod(engineCore, engineServer);
1865
+ }
1866
+ }
1867
+ }
1868
+ }
1869
+ /**
1870
+ * Handles the shutdown of the extensions.
1871
+ * @param envVars The environment variables for the node.
1872
+ * @param engineCore The engine core instance.
1873
+ * @returns Nothing.
1874
+ */
1875
+ async function shutdownExtensions(envVars, engineCore) {
1876
+ if (Is.stringValue(envVars.extensions)) {
1877
+ const extensions = envVars.extensions.split(",");
1878
+ for (const extension of extensions) {
1879
+ let shutdownMethod;
1880
+ try {
1881
+ engineCore.logInfo(I18n.formatMessage("node.extensionShutdown", { extension }));
1882
+ shutdownMethod = await ModuleHelper.getModuleMethod(extension, "extensionShutdown");
1883
+ }
1884
+ catch { }
1885
+ if (Is.function(shutdownMethod)) {
1886
+ await shutdownMethod();
1887
+ }
1888
+ }
1889
+ }
1890
+ }
1891
+
1892
+ // Copyright 2024 IOTA Stiftung.
1893
+ // SPDX-License-Identifier: Apache-2.0.
1783
1894
  /**
1784
1895
  * Start the engine server.
1785
1896
  * @param nodeOptions Optional run options for the engine server.
1786
- * @param engineServerConfig The configuration for the engine server.
1897
+ * @param nodeEngineConfig The configuration for the engine server.
1787
1898
  * @param envVars The environment variables.
1788
1899
  * @returns The engine server.
1789
1900
  */
1790
- async function start(nodeOptions, engineServerConfig, envVars) {
1901
+ async function start(nodeOptions, nodeEngineConfig, envVars) {
1791
1902
  const entityStorageConnectorType = envVars.entityStorageConnectorType?.split(",") ?? [];
1792
1903
  const blobStorageConnectorType = envVars.blobStorageConnectorType?.split(",") ?? [];
1793
1904
  // If the blob storage or entity storage is configured with file connectors
@@ -1802,7 +1913,7 @@ async function start(nodeOptions, engineServerConfig, envVars) {
1802
1913
  }
1803
1914
  // Create the engine instance using file state storage unless one is configured in options
1804
1915
  const engine = new Engine({
1805
- config: engineServerConfig,
1916
+ config: nodeEngineConfig,
1806
1917
  stateStorage: nodeOptions?.stateStorage ?? new FileStateStorage(envVars.stateFilename ?? ""),
1807
1918
  customBootstrap: async (core, engineContext) => bootstrap(core, engineContext, envVars)
1808
1919
  });
@@ -1810,14 +1921,16 @@ async function start(nodeOptions, engineServerConfig, envVars) {
1810
1921
  const server = new EngineServer({ engineCore: engine });
1811
1922
  // Extend the engine.
1812
1923
  if (Is.function(nodeOptions?.extendEngine)) {
1813
- console.info("Extending Engine");
1924
+ engine.logInfo(I18n.formatMessage("node.extendingEngine"));
1814
1925
  await nodeOptions.extendEngine(engine);
1815
1926
  }
1927
+ await extensionsInitialiseEngine(envVars, engine);
1816
1928
  // Extend the engine server.
1817
1929
  if (Is.function(nodeOptions?.extendEngineServer)) {
1818
- console.info("Extending Engine Server");
1930
+ engine.logInfo(I18n.formatMessage("node.extendingEngineServer"));
1819
1931
  await nodeOptions?.extendEngineServer(server);
1820
1932
  }
1933
+ await extensionsInitialiseEngineServer(envVars, engine, server);
1821
1934
  // Need to register the engine with the factory so that background tasks
1822
1935
  // can clone it to spawn new instances.
1823
1936
  EngineCoreFactory.register("engine", () => engine);
@@ -1826,14 +1939,17 @@ async function start(nodeOptions, engineServerConfig, envVars) {
1826
1939
  if (canContinue) {
1827
1940
  return {
1828
1941
  engine,
1829
- server
1942
+ server,
1943
+ shutdown: async () => {
1944
+ await server.stop();
1945
+ await shutdownExtensions(envVars, engine);
1946
+ }
1830
1947
  };
1831
1948
  }
1832
1949
  }
1833
1950
 
1834
1951
  // Copyright 2024 IOTA Stiftung.
1835
1952
  // SPDX-License-Identifier: Apache-2.0.
1836
- /* eslint-disable no-console */
1837
1953
  /**
1838
1954
  * Run the TWIN Node server.
1839
1955
  * @param nodeOptions Optional configuration options for running the server.
@@ -1844,50 +1960,59 @@ async function run(nodeOptions) {
1844
1960
  nodeOptions ??= {};
1845
1961
  const serverInfo = {
1846
1962
  name: nodeOptions?.serverName ?? "TWIN Node Server",
1847
- version: nodeOptions?.serverVersion ?? "0.0.2-next.16" // x-release-please-version
1963
+ version: nodeOptions?.serverVersion ?? "0.0.2-next.18" // x-release-please-version
1848
1964
  };
1849
- console.log(`\u001B[4m🌩️ ${serverInfo.name} v${serverInfo.version}\u001B[24m\n`);
1965
+ CLIDisplay.header(serverInfo.name, serverInfo.version, "🌩️ ");
1850
1966
  if (!Is.stringValue(nodeOptions?.executionDirectory)) {
1851
1967
  nodeOptions.executionDirectory = getExecutionDirectory();
1852
1968
  }
1853
- console.info("Execution Directory:", nodeOptions.executionDirectory);
1969
+ CLIDisplay.value("Execution Directory", nodeOptions.executionDirectory);
1854
1970
  nodeOptions.localesDirectory =
1855
1971
  nodeOptions?.localesDirectory ??
1856
1972
  path.resolve(path.join(nodeOptions.executionDirectory, "dist", "locales"));
1857
- console.info("Locales Directory:", nodeOptions.localesDirectory);
1973
+ CLIDisplay.value("Locales Directory", nodeOptions.localesDirectory);
1858
1974
  await initialiseLocales(nodeOptions.localesDirectory);
1859
1975
  if (Is.empty(nodeOptions?.openApiSpecFile)) {
1860
1976
  const specFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "docs", "open-api", "spec.json"));
1861
- console.info("Default OpenAPI Spec File:", specFile);
1977
+ CLIDisplay.value("Default OpenAPI Spec File", specFile);
1862
1978
  if (await fileExists(specFile)) {
1863
1979
  nodeOptions ??= {};
1864
1980
  nodeOptions.openApiSpecFile = specFile;
1865
1981
  }
1866
1982
  }
1983
+ else {
1984
+ CLIDisplay.value("OpenAPI Spec File", nodeOptions.openApiSpecFile);
1985
+ }
1867
1986
  if (Is.empty(nodeOptions?.favIconFile)) {
1868
1987
  const favIconFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "static", "favicon.png"));
1869
- console.info("Default Favicon File:", favIconFile);
1988
+ CLIDisplay.value("Default Favicon File", favIconFile);
1870
1989
  if (await fileExists(favIconFile)) {
1871
1990
  nodeOptions ??= {};
1872
1991
  nodeOptions.favIconFile = favIconFile;
1873
1992
  }
1874
1993
  }
1994
+ else {
1995
+ CLIDisplay.value("Favicon File", nodeOptions.favIconFile);
1996
+ }
1875
1997
  nodeOptions.envPrefix ??= "TWIN_NODE_";
1876
- console.info("Environment Prefix:", nodeOptions.envPrefix);
1998
+ CLIDisplay.value("Environment Variable Prefix", nodeOptions.envPrefix);
1877
1999
  overrideModuleImport(nodeOptions.executionDirectory ?? "");
1878
- const { engineServerConfig, nodeEnvVars: envVars } = await buildConfiguration(process.env, nodeOptions, serverInfo);
1879
- console.info();
1880
- const startResult = await start(nodeOptions, engineServerConfig, envVars);
2000
+ const { nodeEngineConfig, nodeEnvVars: envVars } = await buildConfiguration(
2001
+ // This is the only location in the code base that should access process.env directly
2002
+ // eslint-disable-next-line no-restricted-syntax
2003
+ process.env, nodeOptions, serverInfo);
2004
+ CLIDisplay.break();
2005
+ const startResult = await start(nodeOptions, nodeEngineConfig, envVars);
1881
2006
  if (!Is.empty(startResult)) {
1882
2007
  for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
1883
2008
  process.on(signal, async () => {
1884
- await startResult.server.stop();
2009
+ await startResult.shutdown();
1885
2010
  });
1886
2011
  }
1887
2012
  }
1888
2013
  }
1889
2014
  catch (err) {
1890
- console.error(ErrorHelper.formatErrors(err).join("\n"));
2015
+ CLIDisplay.error(err);
1891
2016
  // eslint-disable-next-line unicorn/no-process-exit
1892
2017
  process.exit(1);
1893
2018
  }
@@ -1904,7 +2029,7 @@ async function buildConfiguration(processEnv, options, serverInfo) {
1904
2029
  let defaultEnvOnly = false;
1905
2030
  if (Is.empty(options?.envFilenames)) {
1906
2031
  const envFile = path.resolve(path.join(options.executionDirectory ?? "", ".env"));
1907
- console.info("Default Environment File:", envFile);
2032
+ CLIDisplay.value("Default Environment File", envFile);
1908
2033
  options ??= {};
1909
2034
  options.envFilenames = [envFile];
1910
2035
  defaultEnvOnly = true;
@@ -1932,18 +2057,18 @@ async function buildConfiguration(processEnv, options, serverInfo) {
1932
2057
  const filePath = envVars[key].slice(6).trim();
1933
2058
  const embeddedFile = path.resolve(path.join(options.executionDirectory ?? "", filePath));
1934
2059
  if (envVars[key].startsWith("@text:")) {
1935
- console.info(`Expanding Environment Variable: ${key} from text file: ${embeddedFile}`);
2060
+ CLIDisplay.value(`Expanding Environment Variable: ${key} from text file`, embeddedFile);
1936
2061
  envVars[key] = await loadTextFile(embeddedFile);
1937
2062
  }
1938
2063
  else if (envVars[key].startsWith("@json:")) {
1939
- console.info(`Expanding Environment Variable: ${key} from JSON file: ${embeddedFile}`);
2064
+ CLIDisplay.value(`Expanding Environment Variable: ${key} from JSON file`, embeddedFile);
1940
2065
  envVars[key] = await loadJsonFile(embeddedFile);
1941
2066
  }
1942
2067
  }
1943
2068
  }
1944
2069
  // Extend the environment variables with any additional custom configuration.
1945
2070
  if (Is.function(options?.extendEnvVars)) {
1946
- console.info("Extending Environment Variables");
2071
+ CLIDisplay.task("Extending Environment Variables");
1947
2072
  await options.extendEnvVars(envVars);
1948
2073
  }
1949
2074
  // Build the engine configuration from the environment variables.
@@ -1952,22 +2077,23 @@ async function buildConfiguration(processEnv, options, serverInfo) {
1952
2077
  // Merge any custom configuration provided in the options.
1953
2078
  if (Is.arrayValue(options?.configFilenames)) {
1954
2079
  for (const configFile of options.configFilenames) {
1955
- console.info("Loading Configuration File:", configFile);
2080
+ CLIDisplay.value("Loading Configuration File", configFile);
1956
2081
  const configFilePath = path.resolve(path.join(options.executionDirectory ?? "", configFile));
1957
2082
  const config = await loadJsonFile(configFilePath);
1958
2083
  Object.assign(engineServerConfig, config);
1959
2084
  }
1960
2085
  }
1961
2086
  if (Is.objectValue(options?.config)) {
1962
- console.info("Merging Custom Configuration");
2087
+ CLIDisplay.task("Merging Custom Configuration");
1963
2088
  Object.assign(engineServerConfig, options.config);
1964
2089
  }
1965
2090
  // Merge any custom configuration provided in the options.
1966
2091
  if (Is.function(options?.extendConfig)) {
1967
- console.info("Extending Configuration");
1968
- await options.extendConfig(engineServerConfig);
2092
+ CLIDisplay.task("Extending Configuration");
2093
+ await options.extendConfig(envVars, engineServerConfig);
1969
2094
  }
1970
- return { engineServerConfig, nodeEnvVars: envVars };
2095
+ const nodeEngineConfig = await extensionsConfiguration(envVars, engineServerConfig);
2096
+ return { nodeEngineConfig, nodeEnvVars: envVars };
1971
2097
  }
1972
2098
  /**
1973
2099
  * Override module imports to use local files where possible.
@@ -2004,4 +2130,4 @@ function overrideModuleImport(executionDirectory) {
2004
2130
  });
2005
2131
  }
2006
2132
 
2007
- export { NodeFeatures, bootstrap, bootstrapAuth, bootstrapBlobEncryption, bootstrapImmutableProofMethod, bootstrapNodeIdentity, bootstrapNodeUser, bootstrapSynchronisedStorage, buildConfiguration, buildEngineConfiguration, buildEngineServerConfiguration, directoryExists, fileExists, getExecutionDirectory, getFeatures, getFiles, getSubFolders, initialiseLocales, loadJsonFile, loadTextFile, overrideModuleImport, run, start };
2133
+ export { ATTESTATION_VERIFICATION_METHOD_ID, AUTH_SIGNING_KEY_ID, BLOB_STORAGE_ENCRYPTION_KEY_ID, IMMUTABLE_PROOF_VERIFICATION_METHOD_ID, NodeFeatures, SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID, VC_AUTHENTICATION_VERIFICATION_METHOD_ID, bootstrap, bootstrapAuth, bootstrapBlobEncryption, bootstrapImmutableProofMethod, bootstrapNodeIdentity, bootstrapNodeUser, bootstrapSynchronisedStorage, buildConfiguration, buildEngineConfiguration, buildEngineServerConfiguration, directoryExists, extensionsConfiguration, extensionsInitialiseEngine, extensionsInitialiseEngineServer, fileExists, getExecutionDirectory, getFeatures, getFiles, getSubFolders, initialiseLocales, loadJsonFile, loadTextFile, overrideModuleImport, run, shutdownExtensions, start };
@@ -9,6 +9,6 @@ import type { IEngineServerEnvironmentVariables } from "../models/IEngineServerE
9
9
  * @param serverInfo The server information.
10
10
  * @param openApiSpecPath The path to the open api spec.
11
11
  * @param favIconPath The path to the favicon.
12
- * @returns The the config for the core and the server.
12
+ * @returns The config for the core and the server.
13
13
  */
14
14
  export declare function buildEngineServerConfiguration(envVars: IEngineServerEnvironmentVariables, coreEngineConfig: IEngineCoreConfig, serverInfo: IServerInfo, openApiSpecPath?: string, favIconPath?: string): Promise<IEngineServerConfig>;
@@ -0,0 +1,32 @@
1
+ import type { IEngineCore, IEngineServer } from "@twin.org/engine-models";
2
+ import type { INodeEngineConfig } from "../models/INodeEngineConfig";
3
+ import type { INodeEnvironmentVariables } from "../models/INodeEnvironmentVariables";
4
+ /**
5
+ * Handles the configuration of the extensions.
6
+ * @param envVars The environment variables for the node.
7
+ * @param nodeEngineConfig The node engine config.
8
+ * @returns The config for the core and the server.
9
+ */
10
+ export declare function extensionsConfiguration(envVars: INodeEnvironmentVariables, nodeEngineConfig: INodeEngineConfig): Promise<INodeEngineConfig>;
11
+ /**
12
+ * Handles the initialisation of the extensions when the engine has been constructed.
13
+ * @param envVars The environment variables for the node.
14
+ * @param engineCore The engine core instance.
15
+ * @returns Nothing.
16
+ */
17
+ export declare function extensionsInitialiseEngine(envVars: INodeEnvironmentVariables, engineCore: IEngineCore): Promise<void>;
18
+ /**
19
+ * Handles the initialisation of the extensions when the engine server has been constructed.
20
+ * @param envVars The environment variables for the node.
21
+ * @param engineCore The engine core instance.
22
+ * @param engineServer The engine server instance.
23
+ * @returns Nothing.
24
+ */
25
+ export declare function extensionsInitialiseEngineServer(envVars: INodeEnvironmentVariables, engineCore: IEngineCore, engineServer: IEngineServer): Promise<void>;
26
+ /**
27
+ * Handles the shutdown of the extensions.
28
+ * @param envVars The environment variables for the node.
29
+ * @param engineCore The engine core instance.
30
+ * @returns Nothing.
31
+ */
32
+ export declare function shutdownExtensions(envVars: INodeEnvironmentVariables, engineCore: IEngineCore): Promise<void>;
@@ -0,0 +1,6 @@
1
+ export declare const ATTESTATION_VERIFICATION_METHOD_ID = "attestation-assertion";
2
+ export declare const IMMUTABLE_PROOF_VERIFICATION_METHOD_ID = "immutable-proof-assertion";
3
+ export declare const BLOB_STORAGE_ENCRYPTION_KEY_ID = "blob-encryption";
4
+ export declare const SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID = "synchronised-storage-blob-encryption";
5
+ export declare const VC_AUTHENTICATION_VERIFICATION_METHOD_ID = "node-authentication-assertion";
6
+ export declare const AUTH_SIGNING_KEY_ID = "auth-signing";
@@ -1,10 +1,14 @@
1
1
  export * from "./bootstrap";
2
2
  export * from "./builders/engineEnvBuilder";
3
3
  export * from "./builders/engineServerEnvBuilder";
4
+ export * from "./builders/extensionsBuilder";
5
+ export * from "./defaults";
4
6
  export * from "./models/IEngineEnvironmentVariables";
5
7
  export * from "./models/IEngineServerEnvironmentVariables";
8
+ export * from "./models/INodeEngineConfig";
6
9
  export * from "./models/INodeEnvironmentVariables";
7
10
  export * from "./models/INodeOptions";
11
+ export * from "./models/nodeExtensionMethods";
8
12
  export * from "./models/nodeFeatures";
9
13
  export * from "./node";
10
14
  export * from "./server";