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