@twin.org/node-core 0.0.1-next.9 → 0.0.1

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 (37) hide show
  1. package/dist/cjs/index.cjs +1140 -53
  2. package/dist/esm/index.mjs +1141 -57
  3. package/dist/types/bootstrap.d.ts +9 -10
  4. package/dist/types/builders/engineEnvBuilder.d.ts +8 -0
  5. package/dist/types/builders/engineServerEnvBuilder.d.ts +13 -0
  6. package/dist/types/index.d.ts +5 -3
  7. package/dist/types/models/IEngineEnvironmentVariables.d.ts +389 -0
  8. package/dist/types/models/IEngineServerEnvironmentVariables.d.ts +49 -0
  9. package/dist/types/models/{INodeVariables.d.ts → INodeEnvironmentVariables.d.ts} +3 -3
  10. package/dist/types/models/{IRunOptions.d.ts → INodeOptions.d.ts} +17 -1
  11. package/dist/types/node.d.ts +22 -3
  12. package/dist/types/server.d.ts +7 -14
  13. package/dist/types/utils.d.ts +8 -2
  14. package/docs/changelog.md +42 -0
  15. package/docs/reference/functions/bootstrap.md +2 -2
  16. package/docs/reference/functions/bootstrapAttestationMethod.md +2 -2
  17. package/docs/reference/functions/bootstrapAuth.md +2 -2
  18. package/docs/reference/functions/bootstrapBlobEncryption.md +2 -2
  19. package/docs/reference/functions/bootstrapImmutableProofMethod.md +2 -2
  20. package/docs/reference/functions/bootstrapNodeIdentity.md +2 -2
  21. package/docs/reference/functions/bootstrapNodeUser.md +2 -2
  22. package/docs/reference/functions/buildConfiguration.md +30 -0
  23. package/docs/reference/functions/buildEngineConfiguration.md +19 -0
  24. package/docs/reference/functions/getFeatures.md +1 -1
  25. package/docs/reference/functions/loadJsonFile.md +25 -0
  26. package/docs/reference/functions/run.md +3 -3
  27. package/docs/reference/functions/start.md +9 -39
  28. package/docs/reference/index.md +7 -3
  29. package/docs/reference/interfaces/IEngineEnvironmentVariables.md +775 -0
  30. package/docs/reference/interfaces/IEngineServerEnvironmentVariables.md +95 -0
  31. package/docs/reference/interfaces/INodeEnvironmentVariables.md +1343 -0
  32. package/docs/reference/interfaces/{IRunOptions.md → INodeOptions.md} +38 -1
  33. package/locales/en.json +0 -1
  34. package/package.json +15 -15
  35. package/dist/types/models/INodeState.d.ts +0 -10
  36. package/docs/reference/interfaces/INodeState.md +0 -15
  37. package/docs/reference/interfaces/INodeVariables.md +0 -59
@@ -1,7 +1,7 @@
1
1
  import { PasswordHelper } from '@twin.org/api-auth-entity-storage-service';
2
- import { I18n, Is, Converter, RandomHelper, StringHelper, Coerce, Urn, GeneralError, EnvHelper, ErrorHelper } from '@twin.org/core';
2
+ import { I18n, Is, Converter, RandomHelper, StringHelper, Coerce, Urn, GeneralError, ErrorHelper, EnvHelper } from '@twin.org/core';
3
3
  import { PasswordGenerator, Bip39 } from '@twin.org/crypto';
4
- import { WalletConnectorType, IdentityConnectorType, EntityStorageConnectorType, BlobStorageConnectorType } from '@twin.org/engine-types';
4
+ import { WalletConnectorType, IdentityConnectorType, EntityStorageConnectorType, BlobStorageConnectorType, BlobStorageComponentType, VaultConnectorType, DltConfigType, LoggingConnectorType, LoggingComponentType, BackgroundTaskConnectorType, EventBusConnectorType, EventBusComponentType, TelemetryConnectorType, TelemetryComponentType, MessagingEmailConnectorType, MessagingSmsConnectorType, MessagingPushNotificationConnectorType, MessagingComponentType, FaucetConnectorType, NftConnectorType, NftComponentType, VerifiableStorageConnectorType, VerifiableStorageComponentType, ImmutableProofComponentType, AuditableItemGraphComponentType, AuditableItemStreamComponentType, IdentityComponentType, IdentityResolverConnectorType, IdentityResolverComponentType, IdentityProfileConnectorType, IdentityProfileComponentType, AttestationConnectorType, AttestationComponentType, DataConverterConnectorType, DataExtractorConnectorType, DataProcessingComponentType, DocumentManagementComponentType, FederatedCatalogueComponentType, RightsManagementPapComponentType, RightsManagementComponentType, TaskSchedulerComponentType } from '@twin.org/engine-types';
5
5
  import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
6
6
  import { IdentityProfileConnectorFactory, IdentityConnectorFactory, IdentityResolverConnectorFactory, DocumentHelper } from '@twin.org/identity-models';
7
7
  import { VaultConnectorFactory, VaultKeyType } from '@twin.org/vault-models';
@@ -9,10 +9,11 @@ import { WalletConnectorFactory } from '@twin.org/wallet-models';
9
9
  import { readFile, stat } from 'node:fs/promises';
10
10
  import path from 'node:path';
11
11
  import * as dotenv from 'dotenv';
12
- import { buildEngineConfiguration, Engine } from '@twin.org/engine';
12
+ import { addDefaultRestPaths, addDefaultSocketPaths, EngineServer } from '@twin.org/engine-server';
13
+ import { InformationComponentType, RestRouteProcessorType, SocketRouteProcessorType, AuthenticationAdminComponentType, AuthenticationComponentType } from '@twin.org/engine-server-types';
14
+ import { Engine } from '@twin.org/engine';
13
15
  import { FileStateStorage } from '@twin.org/engine-core';
14
16
  import { EngineCoreFactory } from '@twin.org/engine-models';
15
- import { buildEngineServerConfiguration, EngineServer } from '@twin.org/engine-server';
16
17
 
17
18
  // Copyright 2024 IOTA Stiftung.
18
19
  // SPDX-License-Identifier: Apache-2.0.
@@ -70,6 +71,15 @@ async function fileExists(filename) {
70
71
  return false;
71
72
  }
72
73
  }
74
+ /**
75
+ * Load the JSON file.
76
+ * @param filename The filename of the JSON file to load.
77
+ * @returns The contents of the JSON file or null if it could not be loaded.
78
+ */
79
+ async function loadJsonFile(filename) {
80
+ const content = await readFile(filename, "utf8");
81
+ return JSON.parse(content);
82
+ }
73
83
  /**
74
84
  * Get the features that are enabled on the node.
75
85
  * @param env The environment variables for the node.
@@ -134,7 +144,6 @@ async function bootstrapNodeIdentity(engineCore, context, envVars, features) {
134
144
  await finaliseWallet(engineCore, envVars, features, finalIdentity, addresses);
135
145
  await finaliseMnemonic(vaultConnector, workingIdentity, finalIdentity);
136
146
  context.state.nodeIdentity = finalIdentity;
137
- context.state.addresses = addresses;
138
147
  context.stateDirty = true;
139
148
  engineCore.logInfo(I18n.formatMessage("node.nodeIdentity", {
140
149
  identity: context.state.nodeIdentity
@@ -487,51 +496,1061 @@ async function bootstrapAuth(engineCore, context, envVars, features) {
487
496
  }
488
497
  }
489
498
 
499
+ // Copyright 2024 IOTA Stiftung.
500
+ // SPDX-License-Identifier: Apache-2.0.
490
501
  /**
491
- * Start the engine server.
502
+ * Build the engine core configuration from environment variables.
503
+ * @param envVars The environment variables.
504
+ * @returns The config for the core.
505
+ */
506
+ function buildEngineConfiguration(envVars) {
507
+ if (Is.stringValue(envVars.storageFileRoot)) {
508
+ envVars.stateFilename ??= "engine-state.json";
509
+ envVars.storageFileRoot = path.resolve(envVars.storageFileRoot);
510
+ envVars.stateFilename = path.join(envVars.storageFileRoot, envVars.stateFilename);
511
+ }
512
+ envVars.attestationVerificationMethodId ??= "attestation-assertion";
513
+ envVars.immutableProofVerificationMethodId ??= "immutable-proof-assertion";
514
+ envVars.blobStorageEnableEncryption ??= "false";
515
+ envVars.blobStorageEncryptionKey ??= "blob-encryption";
516
+ const coreConfig = {
517
+ debug: Coerce.boolean(envVars.debug) ?? false,
518
+ types: {}
519
+ };
520
+ configureEntityStorage(coreConfig, envVars);
521
+ configureBlobStorage(coreConfig, envVars);
522
+ configureVault(coreConfig, envVars);
523
+ configureDlt(coreConfig, envVars);
524
+ configureLogging(coreConfig, envVars);
525
+ configureBackgroundTask(coreConfig, envVars);
526
+ configureEventBus(coreConfig, envVars);
527
+ configureTelemetry(coreConfig, envVars);
528
+ configureMessaging(coreConfig, envVars);
529
+ configureFaucet(coreConfig, envVars);
530
+ configureWallet(coreConfig, envVars);
531
+ configureNft(coreConfig, envVars);
532
+ configureVerifiableStorage(coreConfig, envVars);
533
+ configureIdentity(coreConfig, envVars);
534
+ configureIdentityResolver(coreConfig, envVars);
535
+ configureIdentityProfile(coreConfig, envVars);
536
+ configureAttestation(coreConfig, envVars);
537
+ configureDataProcessing(coreConfig, envVars);
538
+ configureAuditableItemGraph(coreConfig);
539
+ configureAuditableItemStream(coreConfig);
540
+ configureDocumentManagement(coreConfig);
541
+ configureFederatedCatalogue(coreConfig, envVars);
542
+ configureRightsManagement(coreConfig, envVars);
543
+ configureTaskScheduler(coreConfig, envVars);
544
+ return coreConfig;
545
+ }
546
+ /**
547
+ * Helper function to get IOTA configuration from centralized dltConfig.
548
+ * @param coreConfig The core config.
549
+ * @returns The IOTA configuration if found, undefined otherwise.
550
+ */
551
+ function getIotaConfig(coreConfig) {
552
+ const dltConfig = coreConfig.types.dltConfig?.find(config => config.type === DltConfigType.Iota && config.isDefault);
553
+ return dltConfig?.options?.config;
554
+ }
555
+ /**
556
+ * Configures the entity storage.
557
+ * @param coreConfig The core config.
558
+ * @param envVars The environment variables.
559
+ */
560
+ function configureEntityStorage(coreConfig, envVars) {
561
+ coreConfig.types ??= {};
562
+ coreConfig.types.entityStorageConnector ??= [];
563
+ if ((Coerce.boolean(envVars.entityMemoryEnable) ?? false) ||
564
+ envVars.entityStorageConnectorType === EntityStorageConnectorType.Memory) {
565
+ coreConfig.types.entityStorageConnector.push({
566
+ type: EntityStorageConnectorType.Memory
567
+ });
568
+ }
569
+ if ((Coerce.boolean(envVars.entityFileEnable) ?? false) ||
570
+ envVars.entityStorageConnectorType === EntityStorageConnectorType.File) {
571
+ coreConfig.types.entityStorageConnector.push({
572
+ type: EntityStorageConnectorType.File,
573
+ options: {
574
+ config: { directory: envVars.storageFileRoot ?? "" },
575
+ folderPrefix: envVars.entityStorageTablePrefix
576
+ }
577
+ });
578
+ }
579
+ if (Is.stringValue(envVars.awsDynamodbAccessKeyId)) {
580
+ coreConfig.types.entityStorageConnector.push({
581
+ type: EntityStorageConnectorType.AwsDynamoDb,
582
+ options: {
583
+ config: {
584
+ region: envVars.awsDynamodbRegion ?? "",
585
+ accessKeyId: envVars.awsDynamodbAccessKeyId ?? "",
586
+ secretAccessKey: envVars.awsDynamodbSecretAccessKey ?? "",
587
+ endpoint: envVars.awsDynamodbEndpoint ?? ""
588
+ },
589
+ tablePrefix: envVars.entityStorageTablePrefix
590
+ }
591
+ });
592
+ }
593
+ if (Is.stringValue(envVars.azureCosmosdbKey)) {
594
+ coreConfig.types.entityStorageConnector.push({
595
+ type: EntityStorageConnectorType.AzureCosmosDb,
596
+ options: {
597
+ config: {
598
+ endpoint: envVars.azureCosmosdbEndpoint ?? "",
599
+ key: envVars.azureCosmosdbKey ?? "",
600
+ databaseId: envVars.azureCosmosdbDatabaseId ?? "",
601
+ containerId: envVars.azureCosmosdbContainerId ?? ""
602
+ },
603
+ tablePrefix: envVars.entityStorageTablePrefix
604
+ }
605
+ });
606
+ }
607
+ if (Is.stringValue(envVars.gcpFirestoreCredentials)) {
608
+ coreConfig.types.entityStorageConnector.push({
609
+ type: EntityStorageConnectorType.GcpFirestoreDb,
610
+ options: {
611
+ config: {
612
+ projectId: envVars.gcpFirestoreProjectId ?? "",
613
+ credentials: envVars.gcpFirestoreCredentials ?? "",
614
+ databaseId: envVars.gcpFirestoreDatabaseId ?? "",
615
+ collectionName: envVars.gcpFirestoreCollectionName ?? "",
616
+ endpoint: envVars.gcpFirestoreApiEndpoint ?? ""
617
+ },
618
+ tablePrefix: envVars.entityStorageTablePrefix
619
+ }
620
+ });
621
+ }
622
+ if (Is.stringValue(envVars.scylladbHosts)) {
623
+ coreConfig.types.entityStorageConnector.push({
624
+ type: EntityStorageConnectorType.ScyllaDb,
625
+ options: {
626
+ config: {
627
+ hosts: envVars.scylladbHosts.split(",") ?? "",
628
+ localDataCenter: envVars.scylladbLocalDataCenter ?? "",
629
+ keyspace: envVars.scylladbKeyspace ?? ""
630
+ },
631
+ tablePrefix: envVars.entityStorageTablePrefix
632
+ }
633
+ });
634
+ }
635
+ if (Is.stringValue(envVars.mySqlHost)) {
636
+ coreConfig.types.entityStorageConnector.push({
637
+ type: EntityStorageConnectorType.MySqlDb,
638
+ options: {
639
+ config: {
640
+ host: envVars.mySqlHost,
641
+ port: envVars.mySqlPort ?? 3306,
642
+ user: envVars.mySqlUser ?? "",
643
+ password: envVars.mySqlPassword ?? "",
644
+ database: envVars.mySqlDatabase ?? ""
645
+ },
646
+ tablePrefix: envVars.entityStorageTablePrefix
647
+ }
648
+ });
649
+ }
650
+ if (Is.stringValue(envVars.mySqlHost)) {
651
+ coreConfig.types.entityStorageConnector.push({
652
+ type: EntityStorageConnectorType.MySqlDb,
653
+ options: {
654
+ config: {
655
+ host: envVars.mySqlHost,
656
+ port: envVars.mySqlPort ?? 3306,
657
+ user: envVars.mySqlUser ?? "",
658
+ password: envVars.mySqlPassword ?? "",
659
+ database: envVars.mySqlDatabase ?? ""
660
+ },
661
+ tablePrefix: envVars.entityStorageTablePrefix
662
+ }
663
+ });
664
+ }
665
+ if (Is.stringValue(envVars.mongoDbHost)) {
666
+ coreConfig.types.entityStorageConnector.push({
667
+ type: EntityStorageConnectorType.MongoDb,
668
+ options: {
669
+ config: {
670
+ host: envVars.mongoDbHost,
671
+ port: envVars.mongoDbPort,
672
+ user: envVars.mongoDbUser ?? "",
673
+ password: envVars.mongoDbPassword ?? "",
674
+ database: envVars.mongoDbDatabase ?? ""
675
+ },
676
+ tablePrefix: envVars.entityStorageTablePrefix
677
+ }
678
+ });
679
+ }
680
+ if (Is.stringValue(envVars.postgreSqlHost)) {
681
+ coreConfig.types.entityStorageConnector.push({
682
+ type: EntityStorageConnectorType.PostgreSql,
683
+ options: {
684
+ config: {
685
+ host: envVars.postgreSqlHost,
686
+ port: envVars.postgreSqlPort,
687
+ user: envVars.postgreSqlUser ?? "",
688
+ password: envVars.postgreSqlPassword ?? "",
689
+ database: envVars.postgreSqlDatabase ?? ""
690
+ },
691
+ tablePrefix: envVars.entityStorageTablePrefix
692
+ }
693
+ });
694
+ }
695
+ const defaultStorageConnector = envVars.entityStorageConnectorType;
696
+ if (Is.stringValue(defaultStorageConnector)) {
697
+ for (const config of coreConfig.types.entityStorageConnector) {
698
+ if (config.type === defaultStorageConnector) {
699
+ config.isDefault = true;
700
+ }
701
+ }
702
+ }
703
+ }
704
+ /**
705
+ * Configures the blob storage.
706
+ * @param coreConfig The core config.
707
+ * @param envVars The environment variables.
708
+ */
709
+ function configureBlobStorage(coreConfig, envVars) {
710
+ coreConfig.types.blobStorageConnector ??= [];
711
+ if ((Coerce.boolean(envVars.blobMemoryEnable) ?? false) ||
712
+ envVars.blobStorageConnectorType === BlobStorageConnectorType.Memory) {
713
+ coreConfig.types.blobStorageConnector.push({
714
+ type: BlobStorageConnectorType.Memory
715
+ });
716
+ }
717
+ if ((Coerce.boolean(envVars.blobFileEnable) ?? false) ||
718
+ envVars.blobStorageConnectorType === BlobStorageConnectorType.File) {
719
+ coreConfig.types.blobStorageConnector.push({
720
+ type: BlobStorageConnectorType.File,
721
+ options: {
722
+ config: {
723
+ directory: Is.stringValue(envVars.storageFileRoot)
724
+ ? path.join(envVars.storageFileRoot, "blob-storage")
725
+ : ""
726
+ },
727
+ storagePrefix: envVars.blobStoragePrefix
728
+ }
729
+ });
730
+ }
731
+ if (Is.stringValue(envVars.ipfsApiUrl)) {
732
+ coreConfig.types.blobStorageConnector.push({
733
+ type: BlobStorageConnectorType.Ipfs,
734
+ options: {
735
+ config: {
736
+ apiUrl: envVars.ipfsApiUrl,
737
+ bearerToken: envVars.ipfsBearerToken
738
+ }
739
+ }
740
+ });
741
+ }
742
+ if (Is.stringValue(envVars.awsS3AccessKeyId)) {
743
+ coreConfig.types.blobStorageConnector.push({
744
+ type: BlobStorageConnectorType.AwsS3,
745
+ options: {
746
+ config: {
747
+ region: envVars.awsS3Region ?? "",
748
+ bucketName: envVars.awsS3BucketName ?? "",
749
+ accessKeyId: envVars.awsS3AccessKeyId ?? "",
750
+ secretAccessKey: envVars.awsS3SecretAccessKey ?? "",
751
+ endpoint: envVars.awsS3Endpoint ?? ""
752
+ },
753
+ storagePrefix: envVars.blobStoragePrefix
754
+ }
755
+ });
756
+ }
757
+ if (Is.stringValue(envVars.azureStorageAccountKey)) {
758
+ coreConfig.types.blobStorageConnector.push({
759
+ type: BlobStorageConnectorType.AzureStorage,
760
+ options: {
761
+ config: {
762
+ accountName: envVars.azureStorageAccountName ?? "",
763
+ accountKey: envVars.azureStorageAccountKey ?? "",
764
+ containerName: envVars.azureStorageContainerName ?? "",
765
+ endpoint: envVars.azureStorageEndpoint ?? ""
766
+ },
767
+ storagePrefix: envVars.blobStoragePrefix
768
+ }
769
+ });
770
+ }
771
+ if (Is.stringValue(envVars.gcpStorageCredentials)) {
772
+ coreConfig.types.blobStorageConnector.push({
773
+ type: BlobStorageConnectorType.GcpStorage,
774
+ options: {
775
+ config: {
776
+ projectId: envVars.gcpStorageProjectId ?? "",
777
+ credentials: envVars.gcpStorageCredentials ?? "",
778
+ bucketName: envVars.gcpStorageBucketName ?? "",
779
+ apiEndpoint: envVars.gcpFirestoreApiEndpoint
780
+ },
781
+ storagePrefix: envVars.blobStoragePrefix
782
+ }
783
+ });
784
+ }
785
+ const defaultStorageConnectorType = envVars.blobStorageConnectorType;
786
+ if (Is.stringValue(defaultStorageConnectorType)) {
787
+ for (const config of coreConfig.types.blobStorageConnector) {
788
+ if (config.type === defaultStorageConnectorType) {
789
+ config.isDefault = true;
790
+ }
791
+ }
792
+ }
793
+ if (coreConfig.types.blobStorageConnector.length > 0) {
794
+ coreConfig.types.blobStorageComponent ??= [];
795
+ coreConfig.types.blobStorageComponent.push({
796
+ type: BlobStorageComponentType.Service,
797
+ options: {
798
+ config: {
799
+ vaultKeyId: (envVars.blobStorageEnableEncryption ?? false)
800
+ ? envVars.blobStorageEncryptionKey
801
+ : undefined
802
+ }
803
+ }
804
+ });
805
+ }
806
+ }
807
+ /**
808
+ * Configures the logging.
809
+ * @param coreConfig The core config.
810
+ * @param envVars The environment variables.
811
+ */
812
+ function configureLogging(coreConfig, envVars) {
813
+ coreConfig.types.loggingConnector ??= [];
814
+ const loggingConnectors = (envVars.loggingConnector ?? "").split(",");
815
+ for (const loggingConnector of loggingConnectors) {
816
+ if (loggingConnector === LoggingConnectorType.Console) {
817
+ coreConfig.types.loggingConnector?.push({
818
+ type: LoggingConnectorType.Console,
819
+ options: {
820
+ config: {
821
+ translateMessages: true,
822
+ hideGroups: true
823
+ }
824
+ },
825
+ isDefault: loggingConnectors.length === 1
826
+ });
827
+ }
828
+ else if (loggingConnector === LoggingConnectorType.EntityStorage) {
829
+ coreConfig.types.loggingConnector?.push({
830
+ type: LoggingConnectorType.EntityStorage,
831
+ isDefault: loggingConnectors.length === 1
832
+ });
833
+ }
834
+ }
835
+ if (loggingConnectors.length > 1) {
836
+ coreConfig.types.loggingConnector?.push({
837
+ type: LoggingConnectorType.Multi,
838
+ isDefault: true,
839
+ options: {
840
+ loggingConnectorTypes: loggingConnectors
841
+ }
842
+ });
843
+ }
844
+ if (loggingConnectors.length > 0) {
845
+ coreConfig.types.loggingComponent ??= [];
846
+ coreConfig.types.loggingComponent.push({ type: LoggingComponentType.Service });
847
+ }
848
+ }
849
+ /**
850
+ * Configures the vault.
851
+ * @param coreConfig The core config.
852
+ * @param envVars The environment variables.
853
+ */
854
+ function configureVault(coreConfig, envVars) {
855
+ coreConfig.types.vaultConnector ??= [];
856
+ if (envVars.vaultConnector === VaultConnectorType.EntityStorage) {
857
+ coreConfig.types.vaultConnector.push({
858
+ type: VaultConnectorType.EntityStorage
859
+ });
860
+ }
861
+ else if (envVars.vaultConnector === VaultConnectorType.Hashicorp) {
862
+ coreConfig.types.vaultConnector.push({
863
+ type: VaultConnectorType.Hashicorp,
864
+ options: {
865
+ config: {
866
+ endpoint: envVars.hashicorpVaultEndpoint ?? "",
867
+ token: envVars.hashicorpVaultToken ?? ""
868
+ }
869
+ }
870
+ });
871
+ }
872
+ }
873
+ /**
874
+ * Configures the background task.
875
+ * @param coreConfig The core config.
876
+ * @param envVars The environment variables.
877
+ */
878
+ function configureBackgroundTask(coreConfig, envVars) {
879
+ coreConfig.types.backgroundTaskConnector ??= [];
880
+ if (envVars.backgroundTaskConnector === BackgroundTaskConnectorType.EntityStorage) {
881
+ coreConfig.types.backgroundTaskConnector.push({
882
+ type: BackgroundTaskConnectorType.EntityStorage
883
+ });
884
+ }
885
+ }
886
+ /**
887
+ * Configures the event bud.
888
+ * @param coreConfig The core config.
889
+ * @param envVars The environment variables.
890
+ */
891
+ function configureEventBus(coreConfig, envVars) {
892
+ coreConfig.types.eventBusConnector ??= [];
893
+ if (envVars.eventBusConnector === EventBusConnectorType.Local) {
894
+ coreConfig.types.eventBusConnector.push({
895
+ type: EventBusConnectorType.Local
896
+ });
897
+ }
898
+ if (coreConfig.types.eventBusConnector.length > 0) {
899
+ coreConfig.types.eventBusComponent ??= [];
900
+ coreConfig.types.eventBusComponent.push({ type: EventBusComponentType.Service });
901
+ }
902
+ }
903
+ /**
904
+ * Configures the telemetry.
905
+ * @param coreConfig The core config.
906
+ * @param envVars The environment variables.
907
+ */
908
+ function configureTelemetry(coreConfig, envVars) {
909
+ coreConfig.types.telemetryConnector ??= [];
910
+ if (envVars.telemetryConnector === TelemetryConnectorType.EntityStorage) {
911
+ coreConfig.types.telemetryConnector.push({
912
+ type: TelemetryConnectorType.EntityStorage
913
+ });
914
+ }
915
+ if (coreConfig.types.telemetryConnector.length > 0) {
916
+ coreConfig.types.telemetryComponent ??= [];
917
+ coreConfig.types.telemetryComponent.push({ type: TelemetryComponentType.Service });
918
+ }
919
+ }
920
+ /**
921
+ * Configures the messaging.
922
+ * @param coreConfig The core config.
923
+ * @param envVars The environment variables.
924
+ */
925
+ function configureMessaging(coreConfig, envVars) {
926
+ coreConfig.types.messagingEmailConnector ??= [];
927
+ coreConfig.types.messagingSmsConnector ??= [];
928
+ coreConfig.types.messagingPushNotificationConnector ??= [];
929
+ if (envVars.messagingEmailConnector === MessagingEmailConnectorType.EntityStorage) {
930
+ coreConfig.types.messagingEmailConnector.push({
931
+ type: MessagingEmailConnectorType.EntityStorage
932
+ });
933
+ }
934
+ else if (envVars.messagingEmailConnector === MessagingEmailConnectorType.Aws) {
935
+ coreConfig.types.messagingEmailConnector.push({
936
+ type: MessagingEmailConnectorType.Aws,
937
+ options: {
938
+ config: {
939
+ region: envVars.awsS3Region ?? "",
940
+ accessKeyId: envVars.awsS3AccessKeyId ?? "",
941
+ secretAccessKey: envVars.awsS3SecretAccessKey ?? "",
942
+ endpoint: envVars.awsS3Endpoint ?? ""
943
+ }
944
+ }
945
+ });
946
+ }
947
+ if (envVars.messagingSmsConnector === MessagingSmsConnectorType.EntityStorage) {
948
+ coreConfig.types.messagingSmsConnector.push({
949
+ type: MessagingSmsConnectorType.EntityStorage
950
+ });
951
+ }
952
+ else if (envVars.messagingSmsConnector === MessagingSmsConnectorType.Aws) {
953
+ coreConfig.types.messagingSmsConnector.push({
954
+ type: MessagingSmsConnectorType.Aws,
955
+ options: {
956
+ config: {
957
+ region: envVars.awsS3Region ?? "",
958
+ accessKeyId: envVars.awsS3AccessKeyId ?? "",
959
+ secretAccessKey: envVars.awsS3SecretAccessKey ?? "",
960
+ endpoint: envVars.awsS3Endpoint ?? ""
961
+ }
962
+ }
963
+ });
964
+ }
965
+ if (envVars.messagingPushNotificationConnector ===
966
+ MessagingPushNotificationConnectorType.EntityStorage) {
967
+ coreConfig.types.messagingPushNotificationConnector.push({
968
+ type: MessagingPushNotificationConnectorType.EntityStorage
969
+ });
970
+ }
971
+ else if (envVars.messagingPushNotificationConnector === MessagingPushNotificationConnectorType.Aws) {
972
+ coreConfig.types.messagingPushNotificationConnector.push({
973
+ type: MessagingPushNotificationConnectorType.Aws,
974
+ options: {
975
+ config: {
976
+ region: envVars.awsS3Region ?? "",
977
+ accessKeyId: envVars.awsS3AccessKeyId ?? "",
978
+ secretAccessKey: envVars.awsS3SecretAccessKey ?? "",
979
+ endpoint: envVars.awsS3Endpoint ?? "",
980
+ applicationsSettings: Is.json(envVars.awsMessagingPushNotificationApplications)
981
+ ? JSON.parse(envVars.awsMessagingPushNotificationApplications)
982
+ : []
983
+ }
984
+ }
985
+ });
986
+ }
987
+ if (coreConfig.types.messagingEmailConnector.length > 0 ||
988
+ coreConfig.types.messagingSmsConnector.length > 0 ||
989
+ coreConfig.types.messagingPushNotificationConnector.length > 0) {
990
+ coreConfig.types.messagingComponent ??= [];
991
+ coreConfig.types.messagingComponent.push({ type: MessagingComponentType.Service });
992
+ }
993
+ }
994
+ /**
995
+ * Configures the faucet.
996
+ * @param coreConfig The core config.
997
+ * @param envVars The environment variables.
998
+ */
999
+ function configureFaucet(coreConfig, envVars) {
1000
+ coreConfig.types.faucetConnector ??= [];
1001
+ if (envVars.faucetConnector === FaucetConnectorType.EntityStorage) {
1002
+ coreConfig.types.faucetConnector.push({
1003
+ type: FaucetConnectorType.EntityStorage
1004
+ });
1005
+ }
1006
+ else if (envVars.faucetConnector === FaucetConnectorType.Iota) {
1007
+ const iotaConfig = getIotaConfig(coreConfig);
1008
+ coreConfig.types.faucetConnector.push({
1009
+ type: FaucetConnectorType.Iota,
1010
+ options: {
1011
+ config: {
1012
+ endpoint: envVars.iotaFaucetEndpoint ?? "",
1013
+ clientOptions: iotaConfig?.clientOptions ?? { url: "" },
1014
+ network: iotaConfig?.network ?? ""
1015
+ }
1016
+ }
1017
+ });
1018
+ }
1019
+ }
1020
+ /**
1021
+ * Configures the wallet.
1022
+ * @param coreConfig The core config.
1023
+ * @param envVars The environment variables.
1024
+ */
1025
+ function configureWallet(coreConfig, envVars) {
1026
+ coreConfig.types.walletConnector ??= [];
1027
+ if (envVars.walletConnector === WalletConnectorType.EntityStorage) {
1028
+ coreConfig.types.walletConnector.push({
1029
+ type: WalletConnectorType.EntityStorage
1030
+ });
1031
+ }
1032
+ else if (envVars.walletConnector === WalletConnectorType.Iota) {
1033
+ const iotaConfig = getIotaConfig(coreConfig);
1034
+ coreConfig.types.walletConnector.push({
1035
+ type: WalletConnectorType.Iota,
1036
+ options: {
1037
+ config: iotaConfig ?? {}
1038
+ }
1039
+ });
1040
+ }
1041
+ }
1042
+ /**
1043
+ * Configures the NFT.
1044
+ * @param coreConfig The core config.
1045
+ * @param envVars The environment variables.
1046
+ */
1047
+ function configureNft(coreConfig, envVars) {
1048
+ coreConfig.types.nftConnector ??= [];
1049
+ if (envVars.nftConnector === NftConnectorType.EntityStorage) {
1050
+ coreConfig.types.nftConnector.push({
1051
+ type: NftConnectorType.EntityStorage
1052
+ });
1053
+ }
1054
+ else if (envVars.nftConnector === NftConnectorType.Iota) {
1055
+ const iotaConfig = getIotaConfig(coreConfig);
1056
+ coreConfig.types.nftConnector.push({
1057
+ type: NftConnectorType.Iota,
1058
+ options: {
1059
+ config: iotaConfig ?? {}
1060
+ }
1061
+ });
1062
+ }
1063
+ if (coreConfig.types.nftConnector.length > 0) {
1064
+ coreConfig.types.nftComponent ??= [];
1065
+ coreConfig.types.nftComponent.push({ type: NftComponentType.Service });
1066
+ }
1067
+ }
1068
+ /**
1069
+ * Configures the verifiable storage.
1070
+ * @param coreConfig The core config.
1071
+ * @param envVars The environment variables.
1072
+ */
1073
+ function configureVerifiableStorage(coreConfig, envVars) {
1074
+ coreConfig.types.verifiableStorageConnector ??= [];
1075
+ if (envVars.verifiableStorageConnector === VerifiableStorageConnectorType.EntityStorage) {
1076
+ coreConfig.types.verifiableStorageConnector.push({
1077
+ type: VerifiableStorageConnectorType.EntityStorage
1078
+ });
1079
+ }
1080
+ else if (envVars.verifiableStorageConnector === VerifiableStorageConnectorType.Iota) {
1081
+ const iotaConfig = getIotaConfig(coreConfig);
1082
+ coreConfig.types.verifiableStorageConnector.push({
1083
+ type: VerifiableStorageConnectorType.Iota,
1084
+ options: {
1085
+ config: iotaConfig ?? {}
1086
+ }
1087
+ });
1088
+ }
1089
+ if (coreConfig.types.verifiableStorageConnector.length > 0) {
1090
+ coreConfig.types.verifiableStorageComponent ??= [];
1091
+ coreConfig.types.verifiableStorageComponent.push({
1092
+ type: VerifiableStorageComponentType.Service
1093
+ });
1094
+ coreConfig.types.immutableProofComponent ??= [];
1095
+ coreConfig.types.immutableProofComponent.push({
1096
+ type: ImmutableProofComponentType.Service,
1097
+ options: {
1098
+ config: {
1099
+ verificationMethodId: envVars.immutableProofVerificationMethodId
1100
+ }
1101
+ }
1102
+ });
1103
+ coreConfig.types.auditableItemGraphComponent ??= [];
1104
+ coreConfig.types.auditableItemGraphComponent.push({
1105
+ type: AuditableItemGraphComponentType.Service
1106
+ });
1107
+ coreConfig.types.auditableItemStreamComponent ??= [];
1108
+ coreConfig.types.auditableItemStreamComponent.push({
1109
+ type: AuditableItemStreamComponentType.Service
1110
+ });
1111
+ }
1112
+ }
1113
+ /**
1114
+ * Configures the identity.
1115
+ * @param coreConfig The core config.
1116
+ * @param envVars The environment variables.
1117
+ */
1118
+ function configureIdentity(coreConfig, envVars) {
1119
+ coreConfig.types.identityConnector ??= [];
1120
+ if (envVars.identityConnector === IdentityConnectorType.EntityStorage) {
1121
+ coreConfig.types.identityConnector.push({
1122
+ type: IdentityConnectorType.EntityStorage
1123
+ });
1124
+ }
1125
+ else if (envVars.identityConnector === IdentityConnectorType.Iota) {
1126
+ const iotaConfig = getIotaConfig(coreConfig);
1127
+ coreConfig.types.identityConnector.push({
1128
+ type: IdentityConnectorType.Iota,
1129
+ options: {
1130
+ config: iotaConfig ?? {}
1131
+ }
1132
+ });
1133
+ }
1134
+ if (coreConfig.types.identityConnector.length > 0) {
1135
+ coreConfig.types.identityComponent ??= [];
1136
+ coreConfig.types.identityComponent.push({ type: IdentityComponentType.Service });
1137
+ }
1138
+ }
1139
+ /**
1140
+ * Configures the identity resolver.
1141
+ * @param coreConfig The core config.
1142
+ * @param envVars The environment variables.
1143
+ */
1144
+ function configureIdentityResolver(coreConfig, envVars) {
1145
+ coreConfig.types.identityResolverConnector ??= [];
1146
+ if (envVars.identityResolverConnector === IdentityResolverConnectorType.EntityStorage) {
1147
+ coreConfig.types.identityResolverConnector.push({
1148
+ type: IdentityResolverConnectorType.EntityStorage
1149
+ });
1150
+ }
1151
+ else if (envVars.identityResolverConnector === IdentityResolverConnectorType.Iota) {
1152
+ const iotaConfig = getIotaConfig(coreConfig);
1153
+ coreConfig.types.identityResolverConnector.push({
1154
+ type: IdentityResolverConnectorType.Iota,
1155
+ options: {
1156
+ config: iotaConfig ?? {}
1157
+ }
1158
+ });
1159
+ }
1160
+ else if (envVars.identityResolverConnector === IdentityResolverConnectorType.Universal) {
1161
+ coreConfig.types.identityResolverConnector.push({
1162
+ type: IdentityResolverConnectorType.Universal,
1163
+ options: {
1164
+ config: {
1165
+ endpoint: envVars.universalResolverEndpoint ?? ""
1166
+ }
1167
+ }
1168
+ });
1169
+ }
1170
+ if (coreConfig.types.identityResolverConnector.length > 0) {
1171
+ coreConfig.types.identityResolverComponent ??= [];
1172
+ coreConfig.types.identityResolverComponent.push({
1173
+ type: IdentityResolverComponentType.Service
1174
+ });
1175
+ }
1176
+ }
1177
+ /**
1178
+ * Configures the identity profile.
1179
+ * @param coreConfig The core config.
1180
+ * @param envVars The environment variables.
1181
+ */
1182
+ function configureIdentityProfile(coreConfig, envVars) {
1183
+ coreConfig.types.identityProfileConnector ??= [];
1184
+ if (envVars.identityProfileConnector === IdentityConnectorType.EntityStorage) {
1185
+ coreConfig.types.identityProfileConnector.push({
1186
+ type: IdentityProfileConnectorType.EntityStorage
1187
+ });
1188
+ }
1189
+ if (coreConfig.types.identityProfileConnector.length > 0) {
1190
+ coreConfig.types.identityProfileComponent ??= [];
1191
+ coreConfig.types.identityProfileComponent.push({ type: IdentityProfileComponentType.Service });
1192
+ }
1193
+ }
1194
+ /**
1195
+ * Configures the attestation.
1196
+ * @param coreConfig The core config.
1197
+ * @param envVars The environment variables.
1198
+ */
1199
+ function configureAttestation(coreConfig, envVars) {
1200
+ coreConfig.types.attestationConnector ??= [];
1201
+ if (envVars.attestationConnector === AttestationConnectorType.Nft) {
1202
+ coreConfig.types.attestationConnector.push({
1203
+ type: AttestationConnectorType.Nft
1204
+ });
1205
+ }
1206
+ if (coreConfig.types.attestationConnector.length > 0) {
1207
+ coreConfig.types.attestationComponent ??= [];
1208
+ coreConfig.types.attestationComponent.push({
1209
+ type: AttestationComponentType.Service,
1210
+ options: {
1211
+ config: {
1212
+ verificationMethodId: envVars.attestationVerificationMethodId
1213
+ }
1214
+ }
1215
+ });
1216
+ }
1217
+ }
1218
+ /**
1219
+ * Configures the auditable item graph.
1220
+ * @param coreConfig The core config.
1221
+ * @param envVars The environment variables.
1222
+ */
1223
+ function configureAuditableItemGraph(coreConfig, envVars) {
1224
+ if (Is.arrayValue(coreConfig.types.verifiableStorageConnector)) {
1225
+ coreConfig.types.auditableItemGraphComponent ??= [];
1226
+ coreConfig.types.auditableItemGraphComponent.push({
1227
+ type: AuditableItemGraphComponentType.Service
1228
+ });
1229
+ }
1230
+ }
1231
+ /**
1232
+ * Configures the auditable item stream.
1233
+ * @param coreConfig The core config.
1234
+ * @param envVars The environment variables.
1235
+ */
1236
+ function configureAuditableItemStream(coreConfig, envVars) {
1237
+ if (Is.arrayValue(coreConfig.types.verifiableStorageConnector)) {
1238
+ coreConfig.types.auditableItemStreamComponent ??= [];
1239
+ coreConfig.types.auditableItemStreamComponent.push({
1240
+ type: AuditableItemStreamComponentType.Service
1241
+ });
1242
+ }
1243
+ }
1244
+ /**
1245
+ * Configures the data processing.
1246
+ * @param coreConfig The core config.
1247
+ * @param envVars The environment variables.
1248
+ */
1249
+ function configureDataProcessing(coreConfig, envVars) {
1250
+ coreConfig.types.dataConverterConnector ??= [];
1251
+ coreConfig.types.dataExtractorConnector ??= [];
1252
+ const converterConnectors = envVars.dataConverterConnectors?.split(",") ?? [];
1253
+ for (const converterConnector of converterConnectors) {
1254
+ if (converterConnector === DataConverterConnectorType.Json) {
1255
+ coreConfig.types.dataConverterConnector.push({
1256
+ type: DataConverterConnectorType.Json
1257
+ });
1258
+ }
1259
+ else if (converterConnector === DataConverterConnectorType.Xml) {
1260
+ coreConfig.types.dataConverterConnector.push({
1261
+ type: DataConverterConnectorType.Xml
1262
+ });
1263
+ }
1264
+ }
1265
+ const extractorConnectors = envVars.dataExtractorConnectors?.split(",") ?? [];
1266
+ for (const extractorConnector of extractorConnectors) {
1267
+ if (extractorConnector === DataExtractorConnectorType.JsonPath) {
1268
+ coreConfig.types.dataExtractorConnector.push({
1269
+ type: DataExtractorConnectorType.JsonPath
1270
+ });
1271
+ }
1272
+ }
1273
+ if (coreConfig.types.dataConverterConnector.length > 0 ||
1274
+ coreConfig.types.dataExtractorConnector.length > 0) {
1275
+ coreConfig.types.dataProcessingComponent ??= [];
1276
+ coreConfig.types.dataProcessingComponent.push({ type: DataProcessingComponentType.Service });
1277
+ }
1278
+ }
1279
+ /**
1280
+ * Configures the document management.
1281
+ * @param coreConfig The core config.
1282
+ * @param envVars The environment variables.
1283
+ */
1284
+ function configureDocumentManagement(coreConfig, envVars) {
1285
+ if (Is.arrayValue(coreConfig.types.auditableItemGraphComponent) &&
1286
+ Is.arrayValue(coreConfig.types.blobStorageComponent) &&
1287
+ Is.arrayValue(coreConfig.types.attestationComponent)) {
1288
+ coreConfig.types.documentManagementComponent ??= [];
1289
+ coreConfig.types.documentManagementComponent.push({
1290
+ type: DocumentManagementComponentType.Service
1291
+ });
1292
+ }
1293
+ }
1294
+ /**
1295
+ * Configures the federated catalogue.
1296
+ * @param coreConfig The core config.
1297
+ * @param envVars The environment variables.
1298
+ */
1299
+ function configureFederatedCatalogue(coreConfig, envVars) {
1300
+ if (Is.arrayValue(coreConfig.types.identityResolverComponent)) {
1301
+ coreConfig.types.federatedCatalogueComponent ??= [];
1302
+ coreConfig.types.federatedCatalogueComponent.push({
1303
+ type: FederatedCatalogueComponentType.Service,
1304
+ options: {
1305
+ config: {
1306
+ subResourceCacheTtlMs: Coerce.number(envVars.federatedCatalogueCacheTtlMs),
1307
+ clearingHouseApproverList: Coerce.object(envVars.federatedCatalogueClearingHouseApproverList) ?? []
1308
+ }
1309
+ }
1310
+ });
1311
+ }
1312
+ }
1313
+ /**
1314
+ * Configures the rights management.
1315
+ * @param coreConfig The core config.
1316
+ * @param envVars The environment variables.
1317
+ */
1318
+ function configureRightsManagement(coreConfig, envVars) {
1319
+ if (Coerce.boolean(envVars.rightsManagementEnabled) ?? false) {
1320
+ coreConfig.types.rightsManagementPapComponent ??= [];
1321
+ coreConfig.types.rightsManagementPapComponent.push({
1322
+ type: RightsManagementPapComponentType.Service
1323
+ });
1324
+ coreConfig.types.rightsManagementComponent ??= [];
1325
+ coreConfig.types.rightsManagementComponent.push({
1326
+ type: RightsManagementComponentType.Service
1327
+ });
1328
+ }
1329
+ }
1330
+ /**
1331
+ * Configures the task scheduler.
1332
+ * @param coreConfig The core config.
1333
+ * @param envVars The environment variables.
1334
+ */
1335
+ function configureTaskScheduler(coreConfig, envVars) {
1336
+ if (Coerce.boolean(envVars.taskSchedulerEnabled) ?? true) {
1337
+ coreConfig.types.taskSchedulerComponent ??= [];
1338
+ coreConfig.types.taskSchedulerComponent.push({
1339
+ type: TaskSchedulerComponentType.Default
1340
+ });
1341
+ }
1342
+ }
1343
+ /**
1344
+ * Configures the DLT.
1345
+ * @param coreConfig The core config.
1346
+ * @param envVars The environment variables.
1347
+ */
1348
+ function configureDlt(coreConfig, envVars) {
1349
+ // Create centralized DLT configuration for IOTA if essential IOTA variables are set
1350
+ if (Is.stringValue(envVars.iotaNodeEndpoint) && Is.stringValue(envVars.iotaNetwork)) {
1351
+ coreConfig.types.dltConfig ??= [];
1352
+ const gasStationConfig = Is.stringValue(envVars.iotaGasStationEndpoint) &&
1353
+ Is.stringValue(envVars.iotaGasStationAuthToken)
1354
+ ? {
1355
+ gasStationUrl: envVars.iotaGasStationEndpoint,
1356
+ gasStationAuthToken: envVars.iotaGasStationAuthToken
1357
+ }
1358
+ : undefined;
1359
+ coreConfig.types.dltConfig.push({
1360
+ type: DltConfigType.Iota,
1361
+ isDefault: true,
1362
+ options: {
1363
+ config: {
1364
+ clientOptions: {
1365
+ url: envVars.iotaNodeEndpoint ?? ""
1366
+ },
1367
+ network: envVars.iotaNetwork ?? "",
1368
+ coinType: Coerce.number(envVars.iotaCoinType),
1369
+ gasStation: gasStationConfig
1370
+ }
1371
+ }
1372
+ });
1373
+ }
1374
+ }
1375
+
1376
+ /**
1377
+ * Handles the configuration of the server.
1378
+ * @param envVars The environment variables for the engine server.
1379
+ * @param coreEngineConfig The core engine config.
492
1380
  * @param serverInfo The server information.
493
- * @param envVarsPrefix The prefix for the environment variables.
1381
+ * @param openApiSpecPath The path to the open api spec.
1382
+ * @returns The the config for the core and the server.
1383
+ */
1384
+ function buildEngineServerConfiguration(envVars, coreEngineConfig, serverInfo, openApiSpecPath) {
1385
+ envVars.authSigningKeyId ??= "auth-signing";
1386
+ const webServerOptions = {
1387
+ port: Coerce.number(envVars.port),
1388
+ host: Coerce.string(envVars.host),
1389
+ methods: Is.stringValue(envVars.httpMethods)
1390
+ ? envVars.httpMethods.split(",")
1391
+ : undefined,
1392
+ allowedHeaders: Is.stringValue(envVars.httpAllowedHeaders)
1393
+ ? envVars.httpAllowedHeaders.split(",")
1394
+ : undefined,
1395
+ exposedHeaders: Is.stringValue(envVars.httpExposedHeaders)
1396
+ ? envVars.httpExposedHeaders.split(",")
1397
+ : undefined,
1398
+ corsOrigins: Is.stringValue(envVars.corsOrigins) ? envVars.corsOrigins.split(",") : undefined
1399
+ };
1400
+ const serverConfig = {
1401
+ ...coreEngineConfig,
1402
+ web: webServerOptions,
1403
+ types: {
1404
+ ...coreEngineConfig.types,
1405
+ informationComponent: [
1406
+ {
1407
+ type: InformationComponentType.Service,
1408
+ options: {
1409
+ config: {
1410
+ serverInfo,
1411
+ openApiSpecPath
1412
+ }
1413
+ }
1414
+ }
1415
+ ]
1416
+ }
1417
+ };
1418
+ if (Is.stringValue(envVars.mimeTypeProcessors)) {
1419
+ const mimeTypeProcessors = envVars.mimeTypeProcessors.split(",");
1420
+ if (Is.arrayValue(mimeTypeProcessors)) {
1421
+ serverConfig.types.mimeTypeProcessor ??= [];
1422
+ for (const mimeTypeProcessor of mimeTypeProcessors) {
1423
+ serverConfig.types.mimeTypeProcessor.push({
1424
+ type: mimeTypeProcessor
1425
+ });
1426
+ }
1427
+ }
1428
+ }
1429
+ serverConfig.types.restRouteProcessor ??= [];
1430
+ serverConfig.types.socketRouteProcessor ??= [];
1431
+ const disableNodeIdentity = Coerce.boolean(envVars.disableNodeIdentity);
1432
+ if (!disableNodeIdentity) {
1433
+ serverConfig.types.restRouteProcessor.push({
1434
+ type: RestRouteProcessorType.NodeIdentity
1435
+ });
1436
+ serverConfig.types.socketRouteProcessor.push({
1437
+ type: SocketRouteProcessorType.NodeIdentity
1438
+ });
1439
+ }
1440
+ if (!coreEngineConfig.silent) {
1441
+ serverConfig.types.restRouteProcessor.push({
1442
+ type: RestRouteProcessorType.Logging,
1443
+ options: {
1444
+ config: {
1445
+ includeBody: coreEngineConfig.debug
1446
+ }
1447
+ }
1448
+ });
1449
+ serverConfig.types.socketRouteProcessor.push({
1450
+ type: SocketRouteProcessorType.Logging,
1451
+ options: {
1452
+ config: {
1453
+ includeBody: coreEngineConfig.debug
1454
+ }
1455
+ }
1456
+ });
1457
+ }
1458
+ serverConfig.types.restRouteProcessor.push({
1459
+ type: RestRouteProcessorType.RestRoute,
1460
+ options: {
1461
+ config: {
1462
+ includeErrorStack: coreEngineConfig.debug
1463
+ }
1464
+ }
1465
+ });
1466
+ serverConfig.types.socketRouteProcessor.push({
1467
+ type: SocketRouteProcessorType.SocketRoute,
1468
+ options: {
1469
+ config: {
1470
+ includeErrorStack: coreEngineConfig.debug
1471
+ }
1472
+ }
1473
+ });
1474
+ const authAdminProcessorType = envVars.authAdminProcessorType;
1475
+ if (authAdminProcessorType === AuthenticationAdminComponentType.EntityStorage) {
1476
+ serverConfig.types.authenticationAdminComponent ??= [];
1477
+ serverConfig.types.authenticationAdminComponent.push({
1478
+ type: AuthenticationAdminComponentType.EntityStorage,
1479
+ options: {
1480
+ config: {}
1481
+ }
1482
+ });
1483
+ }
1484
+ const authProcessorType = envVars.authProcessorType;
1485
+ if (authProcessorType === AuthenticationComponentType.EntityStorage) {
1486
+ serverConfig.types.authenticationComponent ??= [];
1487
+ serverConfig.types.authenticationComponent.push({
1488
+ type: AuthenticationComponentType.EntityStorage,
1489
+ options: {
1490
+ config: {
1491
+ signingKeyName: envVars.authSigningKeyId
1492
+ }
1493
+ }
1494
+ });
1495
+ serverConfig.types.restRouteProcessor.push({
1496
+ type: RestRouteProcessorType.AuthHeader,
1497
+ options: {
1498
+ config: {
1499
+ signingKeyName: envVars.authSigningKeyId
1500
+ }
1501
+ }
1502
+ });
1503
+ serverConfig.types.socketRouteProcessor.push({
1504
+ type: SocketRouteProcessorType.AuthHeader,
1505
+ options: {
1506
+ config: {
1507
+ signingKeyName: envVars.authSigningKeyId
1508
+ }
1509
+ }
1510
+ });
1511
+ }
1512
+ addDefaultRestPaths(serverConfig);
1513
+ addDefaultSocketPaths(serverConfig);
1514
+ return serverConfig;
1515
+ }
1516
+
1517
+ // Copyright 2024 IOTA Stiftung.
1518
+ // SPDX-License-Identifier: Apache-2.0.
1519
+ /* eslint-disable no-console */
1520
+ /**
1521
+ * Start the engine server.
1522
+ * @param nodeOptions Optional run options for the engine server.
1523
+ * @param engineServerConfig The configuration for the engine server.
494
1524
  * @param envVars The environment variables.
495
- * @param openApiSpecFile Path to the OpenAPI spec file.
496
- * @param stateStorage The state storage.
497
- * @param extendConfig Extends the engine configuration with any additional custom configuration.
498
- * @param extendEngine Extends the engine with any additional options.
499
- * @param extendEngineServer Extends the engine server with any additional options.
500
1525
  * @returns The engine server.
501
1526
  */
502
- async function start(serverInfo, envVarsPrefix, envVars, openApiSpecFile, stateStorage, extendConfig, extendEngine, extendEngineServer) {
1527
+ async function start(nodeOptions, engineServerConfig, envVars) {
503
1528
  envVars.storageFileRoot ??= "";
504
1529
  if ((envVars.entityStorageConnectorType === EntityStorageConnectorType.File ||
505
1530
  envVars.blobStorageConnectorType === BlobStorageConnectorType.File ||
506
- Is.empty(stateStorage)) &&
1531
+ Is.empty(nodeOptions?.stateStorage)) &&
507
1532
  !Is.stringValue(envVars.storageFileRoot)) {
508
1533
  throw new GeneralError("node", "storageFileRootNotSet", {
509
- storageFileRoot: `${envVarsPrefix}_STORAGE_FILE_ROOT`
1534
+ storageFileRoot: `${nodeOptions?.envPrefix ?? ""}_STORAGE_FILE_ROOT`
510
1535
  });
511
1536
  }
512
- // Build the engine configuration from the environment variables.
513
- const engineConfig = buildEngineConfiguration(envVars);
514
- // Extend the engine configuration with a custom type.
515
- if (Is.function(extendConfig)) {
516
- await extendConfig(engineConfig);
517
- }
518
- // Build the server configuration from the environment variables.
519
- const serverConfig = buildEngineServerConfiguration(envVars, engineConfig, serverInfo, openApiSpecFile);
520
1537
  // Create the engine instance using file state storage and custom bootstrap.
521
1538
  const engine = new Engine({
522
- config: { ...engineConfig, ...serverConfig },
523
- stateStorage: stateStorage ?? new FileStateStorage(envVars.stateFilename ?? ""),
1539
+ config: engineServerConfig,
1540
+ stateStorage: nodeOptions?.stateStorage ?? new FileStateStorage(envVars.stateFilename ?? ""),
524
1541
  customBootstrap: async (core, engineContext) => bootstrap(core, engineContext, envVars)
525
1542
  });
526
1543
  // Extend the engine.
527
- if (Is.function(extendEngine)) {
528
- await extendEngine(engine);
1544
+ if (Is.function(nodeOptions?.extendEngine)) {
1545
+ console.info("Extending Engine");
1546
+ await nodeOptions.extendEngine(engine);
529
1547
  }
530
1548
  // Construct the server with the engine.
531
1549
  const server = new EngineServer({ engineCore: engine });
532
1550
  // Extend the engine server.
533
- if (Is.function(extendEngineServer)) {
534
- await extendEngineServer(server);
1551
+ if (Is.function(nodeOptions?.extendEngineServer)) {
1552
+ console.info("Extending Engine Server");
1553
+ await nodeOptions?.extendEngineServer(server);
535
1554
  }
536
1555
  // Need to register the engine with the factory so that background tasks
537
1556
  // can clone it to spawn new instances.
@@ -551,44 +1570,39 @@ async function start(serverInfo, envVarsPrefix, envVars, openApiSpecFile, stateS
551
1570
  /* eslint-disable no-console */
552
1571
  /**
553
1572
  * Run the TWIN Node server.
554
- * @param options Optional configuration options for running the server.
1573
+ * @param nodeOptions Optional configuration options for running the server.
555
1574
  * @returns A promise that resolves when the server is started.
556
1575
  */
557
- async function run(options) {
1576
+ async function run(nodeOptions) {
558
1577
  try {
1578
+ nodeOptions ??= {};
559
1579
  const serverInfo = {
560
- name: options?.serverName ?? "TWIN Node Server",
561
- version: options?.serverVersion ?? "0.0.1-next.9" // x-release-please-version
1580
+ name: nodeOptions?.serverName ?? "TWIN Node Server",
1581
+ version: nodeOptions?.serverVersion ?? "0.0.1-next.11" // x-release-please-version
562
1582
  };
563
1583
  console.log(`\u001B[4m🌩️ ${serverInfo.name} v${serverInfo.version}\u001B[24m\n`);
564
- const executionDirectory = options?.executionDirectory ?? getExecutionDirectory();
565
- console.info("Execution Directory:", process.cwd());
566
- await initialiseLocales(options?.localesDirectory ?? path.resolve(path.join(executionDirectory, "dist", "locales")));
567
- if (Is.empty(options?.openApiSpecFile)) {
568
- const specFile = path.resolve(path.join(executionDirectory, "docs", "open-api", "spec.json"));
1584
+ if (!Is.stringValue(nodeOptions?.executionDirectory)) {
1585
+ nodeOptions.executionDirectory = getExecutionDirectory();
1586
+ }
1587
+ console.info("Execution Directory:", nodeOptions.executionDirectory);
1588
+ nodeOptions.localesDirectory =
1589
+ nodeOptions?.localesDirectory ??
1590
+ path.resolve(path.join(nodeOptions.executionDirectory, "dist", "locales"));
1591
+ console.info("Locales Directory:", nodeOptions.localesDirectory);
1592
+ await initialiseLocales(nodeOptions.localesDirectory);
1593
+ if (Is.empty(nodeOptions?.openApiSpecFile)) {
1594
+ const specFile = path.resolve(path.join(nodeOptions.executionDirectory, "docs", "open-api", "spec.json"));
569
1595
  console.info("Default OpenAPI Spec File:", specFile);
570
1596
  if (await fileExists(specFile)) {
571
- options ??= {};
572
- options.openApiSpecFile = specFile;
1597
+ nodeOptions ??= {};
1598
+ nodeOptions.openApiSpecFile = specFile;
573
1599
  }
574
1600
  }
575
- if (Is.empty(options?.envFilenames)) {
576
- const envFile = path.resolve(path.join(executionDirectory, ".env"));
577
- console.info("Default Environment File:", envFile);
578
- options ??= {};
579
- options.envFilenames = [envFile];
580
- }
581
- dotenv.config({
582
- path: options?.envFilenames
583
- });
584
- const envPrefix = options?.envPrefix ?? "TWIN_NODE_";
585
- console.info("Environment Prefix:", envPrefix);
586
- const envVars = EnvHelper.envToJson(process.env, envPrefix);
587
- if (Object.keys(envVars).length === 0) {
588
- throw new GeneralError("node", "noEnvVars", { prefix: envPrefix });
589
- }
1601
+ nodeOptions.envPrefix ??= "TWIN_NODE_";
1602
+ console.info("Environment Prefix:", nodeOptions.envPrefix);
1603
+ const { engineServerConfig, nodeEnvVars: envVars } = await buildConfiguration(process.env, nodeOptions, serverInfo);
590
1604
  console.info();
591
- const startResult = await start(serverInfo, envPrefix, envVars, options?.openApiSpecFile, options.stateStorage, options.extendConfig, options.extendEngine, options.extendEngineServer);
1605
+ const startResult = await start(nodeOptions, engineServerConfig, envVars);
592
1606
  if (!Is.empty(startResult)) {
593
1607
  for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
594
1608
  process.on(signal, async () => {
@@ -603,5 +1617,75 @@ async function run(options) {
603
1617
  process.exit(1);
604
1618
  }
605
1619
  }
1620
+ /**
1621
+ * Build the configuration for the TWIN Node server.
1622
+ * @param processEnv The environment variables from the process.
1623
+ * @param options The options for running the server.
1624
+ * @param serverInfo The server information.
1625
+ * @returns A promise that resolves to the engine server configuration, environment prefix, environment variables,
1626
+ * and options.
1627
+ */
1628
+ async function buildConfiguration(processEnv, options, serverInfo) {
1629
+ let defaultEnvOnly = false;
1630
+ if (Is.empty(options?.envFilenames)) {
1631
+ const envFile = path.resolve(path.join(options.executionDirectory ?? "", ".env"));
1632
+ console.info("Default Environment File:", envFile);
1633
+ options ??= {};
1634
+ options.envFilenames = [envFile];
1635
+ defaultEnvOnly = true;
1636
+ }
1637
+ if (Is.arrayValue(options?.envFilenames)) {
1638
+ const output = dotenv.config({
1639
+ path: options?.envFilenames
1640
+ });
1641
+ // We don't want to throw an error if the default environment file is not found.
1642
+ // Only if we have custom environment files.
1643
+ if (!defaultEnvOnly && output.error) {
1644
+ throw output.error;
1645
+ }
1646
+ if (Is.objectValue(output.parsed)) {
1647
+ Object.assign(processEnv, output.parsed);
1648
+ }
1649
+ }
1650
+ const envVars = EnvHelper.envToJson(processEnv, options.envPrefix ?? "");
1651
+ // Expand any environment variables that use the @file: syntax
1652
+ const keys = Object.keys(envVars);
1653
+ for (const key of keys) {
1654
+ if (Is.stringValue(envVars[key]) && envVars[key].startsWith("@file:")) {
1655
+ const filePath = envVars[key].slice(6).trim();
1656
+ const embeddedFile = path.resolve(path.join(options.executionDirectory ?? "", filePath));
1657
+ console.info(`Expanding Environment Variable: ${key} from file: ${embeddedFile}`);
1658
+ const fileContent = await loadJsonFile(embeddedFile);
1659
+ envVars[key] = fileContent;
1660
+ }
1661
+ }
1662
+ // Extend the environment variables with any additional custom configuration.
1663
+ if (Is.function(options?.extendEnvVars)) {
1664
+ console.info("Extending Environment Variables");
1665
+ await options.extendEnvVars(envVars);
1666
+ }
1667
+ // Build the engine configuration from the environment variables.
1668
+ const coreConfig = buildEngineConfiguration(envVars);
1669
+ const engineServerConfig = buildEngineServerConfiguration(envVars, coreConfig, serverInfo, options?.openApiSpecFile);
1670
+ // Merge any custom configuration provided in the options.
1671
+ if (Is.arrayValue(options?.configFilenames)) {
1672
+ for (const configFile of options.configFilenames) {
1673
+ console.info("Loading Configuration File:", configFile);
1674
+ const configFilePath = path.resolve(path.join(options.executionDirectory ?? "", configFile));
1675
+ const config = await loadJsonFile(configFilePath);
1676
+ Object.assign(engineServerConfig, config);
1677
+ }
1678
+ }
1679
+ if (Is.objectValue(options?.config)) {
1680
+ console.info("Merging Custom Configuration");
1681
+ Object.assign(engineServerConfig, options.config);
1682
+ }
1683
+ // Merge any custom configuration provided in the options.
1684
+ if (Is.function(options?.extendConfig)) {
1685
+ console.info("Extending Configuration");
1686
+ await options.extendConfig(engineServerConfig);
1687
+ }
1688
+ return { engineServerConfig, nodeEnvVars: envVars };
1689
+ }
606
1690
 
607
- export { NodeFeatures, bootstrap, bootstrapAttestationMethod, bootstrapAuth, bootstrapBlobEncryption, bootstrapImmutableProofMethod, bootstrapNodeIdentity, bootstrapNodeUser, fileExists, getExecutionDirectory, getFeatures, initialiseLocales, run, start };
1691
+ export { NodeFeatures, bootstrap, bootstrapAttestationMethod, bootstrapAuth, bootstrapBlobEncryption, bootstrapImmutableProofMethod, bootstrapNodeIdentity, bootstrapNodeUser, buildConfiguration, buildEngineConfiguration, fileExists, getExecutionDirectory, getFeatures, initialiseLocales, loadJsonFile, run, start };