@twin.org/node-core 0.0.2-next.17 → 0.0.2-next.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +35 -28
- package/dist/esm/index.mjs +36 -29
- package/dist/types/builders/extensionsBuilder.d.ts +2 -1
- package/dist/types/models/nodeExtensionMethods.d.ts +5 -0
- package/docs/changelog.md +7 -0
- package/docs/reference/functions/shutdownExtensions.md +7 -1
- package/docs/reference/index.md +1 -0
- package/docs/reference/type-aliases/NodeExtensionShutdownMethod.md +10 -0
- package/locales/en.json +9 -2
- package/package.json +2 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -11,6 +11,7 @@ var vaultModels = require('@twin.org/vault-models');
|
|
|
11
11
|
var walletModels = require('@twin.org/wallet-models');
|
|
12
12
|
var promises = require('node:fs/promises');
|
|
13
13
|
var path = require('node:path');
|
|
14
|
+
var cliCore = require('@twin.org/cli-core');
|
|
14
15
|
var rightsManagementRestClient = require('@twin.org/rights-management-rest-client');
|
|
15
16
|
var engineServer = require('@twin.org/engine-server');
|
|
16
17
|
var modules = require('@twin.org/modules');
|
|
@@ -70,20 +71,19 @@ const NodeFeatures = {
|
|
|
70
71
|
|
|
71
72
|
// Copyright 2024 IOTA Stiftung.
|
|
72
73
|
// SPDX-License-Identifier: Apache-2.0.
|
|
73
|
-
/* eslint-disable no-console */
|
|
74
74
|
/**
|
|
75
75
|
* Initialise the locales for the application.
|
|
76
76
|
* @param localesDirectory The directory containing the locales.
|
|
77
77
|
*/
|
|
78
78
|
async function initialiseLocales(localesDirectory) {
|
|
79
79
|
const localesFile = path.resolve(path.join(localesDirectory, "en.json"));
|
|
80
|
-
|
|
80
|
+
cliCore.CLIDisplay.value("Locales File", localesFile);
|
|
81
81
|
if (await fileExists(localesFile)) {
|
|
82
82
|
const enLangContent = await promises.readFile(localesFile, "utf8");
|
|
83
83
|
core.I18n.addDictionary("en", JSON.parse(enLangContent));
|
|
84
84
|
}
|
|
85
85
|
else {
|
|
86
|
-
|
|
86
|
+
cliCore.CLIDisplay.error(`Locales file not found: ${localesFile}`);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
@@ -1815,7 +1815,6 @@ async function buildEngineServerConfiguration(envVars, coreEngineConfig, serverI
|
|
|
1815
1815
|
|
|
1816
1816
|
// Copyright 2024 IOTA Stiftung.
|
|
1817
1817
|
// SPDX-License-Identifier: Apache-2.0.
|
|
1818
|
-
/* eslint-disable no-console */
|
|
1819
1818
|
/**
|
|
1820
1819
|
* Handles the configuration of the extensions.
|
|
1821
1820
|
* @param envVars The environment variables for the node.
|
|
@@ -1828,11 +1827,11 @@ async function extensionsConfiguration(envVars, nodeEngineConfig) {
|
|
|
1828
1827
|
for (const extension of extensions) {
|
|
1829
1828
|
let initialiseConfigMethod;
|
|
1830
1829
|
try {
|
|
1831
|
-
|
|
1830
|
+
cliCore.CLIDisplay.value(core.I18n.formatMessage("node.extensionLoading"), extension);
|
|
1832
1831
|
initialiseConfigMethod = await modules.ModuleHelper.getModuleMethod(extension, "extensionInitialise");
|
|
1833
1832
|
}
|
|
1834
1833
|
catch (err) {
|
|
1835
|
-
|
|
1834
|
+
throw new core.GeneralError("node", "extensionLoadingError", { extension }, err);
|
|
1836
1835
|
}
|
|
1837
1836
|
if (core.Is.function(initialiseConfigMethod)) {
|
|
1838
1837
|
await initialiseConfigMethod(envVars, nodeEngineConfig);
|
|
@@ -1853,6 +1852,7 @@ async function extensionsInitialiseEngine(envVars, engineCore) {
|
|
|
1853
1852
|
for (const extension of extensions) {
|
|
1854
1853
|
let initialiseEngineMethod;
|
|
1855
1854
|
try {
|
|
1855
|
+
engineCore.logInfo(core.I18n.formatMessage("node.extensionInitialisingEngine", { extension }));
|
|
1856
1856
|
initialiseEngineMethod =
|
|
1857
1857
|
await modules.ModuleHelper.getModuleMethod(extension, "extensionInitialiseEngine");
|
|
1858
1858
|
}
|
|
@@ -1876,6 +1876,7 @@ async function extensionsInitialiseEngineServer(envVars, engineCore, engineServe
|
|
|
1876
1876
|
for (const extension of extensions) {
|
|
1877
1877
|
let initialiseEngineServerMethod;
|
|
1878
1878
|
try {
|
|
1879
|
+
engineCore.logInfo(core.I18n.formatMessage("node.extensionInitialisingEngineServer", { extension }));
|
|
1879
1880
|
initialiseEngineServerMethod =
|
|
1880
1881
|
await modules.ModuleHelper.getModuleMethod(extension, "extensionInitialiseEngineServer");
|
|
1881
1882
|
}
|
|
@@ -1889,14 +1890,16 @@ async function extensionsInitialiseEngineServer(envVars, engineCore, engineServe
|
|
|
1889
1890
|
/**
|
|
1890
1891
|
* Handles the shutdown of the extensions.
|
|
1891
1892
|
* @param envVars The environment variables for the node.
|
|
1893
|
+
* @param engineCore The engine core instance.
|
|
1892
1894
|
* @returns Nothing.
|
|
1893
1895
|
*/
|
|
1894
|
-
async function shutdownExtensions(envVars) {
|
|
1896
|
+
async function shutdownExtensions(envVars, engineCore) {
|
|
1895
1897
|
if (core.Is.stringValue(envVars.extensions)) {
|
|
1896
1898
|
const extensions = envVars.extensions.split(",");
|
|
1897
1899
|
for (const extension of extensions) {
|
|
1898
1900
|
let shutdownMethod;
|
|
1899
1901
|
try {
|
|
1902
|
+
engineCore.logInfo(core.I18n.formatMessage("node.extensionShutdown", { extension }));
|
|
1900
1903
|
shutdownMethod = await modules.ModuleHelper.getModuleMethod(extension, "extensionShutdown");
|
|
1901
1904
|
}
|
|
1902
1905
|
catch { }
|
|
@@ -1909,7 +1912,6 @@ async function shutdownExtensions(envVars) {
|
|
|
1909
1912
|
|
|
1910
1913
|
// Copyright 2024 IOTA Stiftung.
|
|
1911
1914
|
// SPDX-License-Identifier: Apache-2.0.
|
|
1912
|
-
/* eslint-disable no-console */
|
|
1913
1915
|
/**
|
|
1914
1916
|
* Start the engine server.
|
|
1915
1917
|
* @param nodeOptions Optional run options for the engine server.
|
|
@@ -1940,13 +1942,13 @@ async function start(nodeOptions, nodeEngineConfig, envVars) {
|
|
|
1940
1942
|
const server = new engineServer.EngineServer({ engineCore: engine$1 });
|
|
1941
1943
|
// Extend the engine.
|
|
1942
1944
|
if (core.Is.function(nodeOptions?.extendEngine)) {
|
|
1943
|
-
|
|
1945
|
+
engine$1.logInfo(core.I18n.formatMessage("node.extendingEngine"));
|
|
1944
1946
|
await nodeOptions.extendEngine(engine$1);
|
|
1945
1947
|
}
|
|
1946
1948
|
await extensionsInitialiseEngine(envVars, engine$1);
|
|
1947
1949
|
// Extend the engine server.
|
|
1948
1950
|
if (core.Is.function(nodeOptions?.extendEngineServer)) {
|
|
1949
|
-
|
|
1951
|
+
engine$1.logInfo(core.I18n.formatMessage("node.extendingEngineServer"));
|
|
1950
1952
|
await nodeOptions?.extendEngineServer(server);
|
|
1951
1953
|
}
|
|
1952
1954
|
await extensionsInitialiseEngineServer(envVars, engine$1, server);
|
|
@@ -1961,7 +1963,7 @@ async function start(nodeOptions, nodeEngineConfig, envVars) {
|
|
|
1961
1963
|
server,
|
|
1962
1964
|
shutdown: async () => {
|
|
1963
1965
|
await server.stop();
|
|
1964
|
-
await shutdownExtensions(envVars);
|
|
1966
|
+
await shutdownExtensions(envVars, engine$1);
|
|
1965
1967
|
}
|
|
1966
1968
|
};
|
|
1967
1969
|
}
|
|
@@ -1969,7 +1971,6 @@ async function start(nodeOptions, nodeEngineConfig, envVars) {
|
|
|
1969
1971
|
|
|
1970
1972
|
// Copyright 2024 IOTA Stiftung.
|
|
1971
1973
|
// SPDX-License-Identifier: Apache-2.0.
|
|
1972
|
-
/* eslint-disable no-console */
|
|
1973
1974
|
/**
|
|
1974
1975
|
* Run the TWIN Node server.
|
|
1975
1976
|
* @param nodeOptions Optional configuration options for running the server.
|
|
@@ -1980,42 +1981,48 @@ async function run(nodeOptions) {
|
|
|
1980
1981
|
nodeOptions ??= {};
|
|
1981
1982
|
const serverInfo = {
|
|
1982
1983
|
name: nodeOptions?.serverName ?? "TWIN Node Server",
|
|
1983
|
-
version: nodeOptions?.serverVersion ?? "0.0.2-next.
|
|
1984
|
+
version: nodeOptions?.serverVersion ?? "0.0.2-next.18" // x-release-please-version
|
|
1984
1985
|
};
|
|
1985
|
-
|
|
1986
|
+
cliCore.CLIDisplay.header(serverInfo.name, serverInfo.version, "🌩️ ");
|
|
1986
1987
|
if (!core.Is.stringValue(nodeOptions?.executionDirectory)) {
|
|
1987
1988
|
nodeOptions.executionDirectory = getExecutionDirectory();
|
|
1988
1989
|
}
|
|
1989
|
-
|
|
1990
|
+
cliCore.CLIDisplay.value("Execution Directory", nodeOptions.executionDirectory);
|
|
1990
1991
|
nodeOptions.localesDirectory =
|
|
1991
1992
|
nodeOptions?.localesDirectory ??
|
|
1992
1993
|
path.resolve(path.join(nodeOptions.executionDirectory, "dist", "locales"));
|
|
1993
|
-
|
|
1994
|
+
cliCore.CLIDisplay.value("Locales Directory", nodeOptions.localesDirectory);
|
|
1994
1995
|
await initialiseLocales(nodeOptions.localesDirectory);
|
|
1995
1996
|
if (core.Is.empty(nodeOptions?.openApiSpecFile)) {
|
|
1996
1997
|
const specFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "docs", "open-api", "spec.json"));
|
|
1997
|
-
|
|
1998
|
+
cliCore.CLIDisplay.value("Default OpenAPI Spec File", specFile);
|
|
1998
1999
|
if (await fileExists(specFile)) {
|
|
1999
2000
|
nodeOptions ??= {};
|
|
2000
2001
|
nodeOptions.openApiSpecFile = specFile;
|
|
2001
2002
|
}
|
|
2002
2003
|
}
|
|
2004
|
+
else {
|
|
2005
|
+
cliCore.CLIDisplay.value("OpenAPI Spec File", nodeOptions.openApiSpecFile);
|
|
2006
|
+
}
|
|
2003
2007
|
if (core.Is.empty(nodeOptions?.favIconFile)) {
|
|
2004
2008
|
const favIconFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "static", "favicon.png"));
|
|
2005
|
-
|
|
2009
|
+
cliCore.CLIDisplay.value("Default Favicon File", favIconFile);
|
|
2006
2010
|
if (await fileExists(favIconFile)) {
|
|
2007
2011
|
nodeOptions ??= {};
|
|
2008
2012
|
nodeOptions.favIconFile = favIconFile;
|
|
2009
2013
|
}
|
|
2010
2014
|
}
|
|
2015
|
+
else {
|
|
2016
|
+
cliCore.CLIDisplay.value("Favicon File", nodeOptions.favIconFile);
|
|
2017
|
+
}
|
|
2011
2018
|
nodeOptions.envPrefix ??= "TWIN_NODE_";
|
|
2012
|
-
|
|
2019
|
+
cliCore.CLIDisplay.value("Environment Variable Prefix", nodeOptions.envPrefix);
|
|
2013
2020
|
overrideModuleImport(nodeOptions.executionDirectory ?? "");
|
|
2014
2021
|
const { nodeEngineConfig, nodeEnvVars: envVars } = await buildConfiguration(
|
|
2015
2022
|
// This is the only location in the code base that should access process.env directly
|
|
2016
2023
|
// eslint-disable-next-line no-restricted-syntax
|
|
2017
2024
|
process.env, nodeOptions, serverInfo);
|
|
2018
|
-
|
|
2025
|
+
cliCore.CLIDisplay.break();
|
|
2019
2026
|
const startResult = await start(nodeOptions, nodeEngineConfig, envVars);
|
|
2020
2027
|
if (!core.Is.empty(startResult)) {
|
|
2021
2028
|
for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
|
|
@@ -2026,7 +2033,7 @@ async function run(nodeOptions) {
|
|
|
2026
2033
|
}
|
|
2027
2034
|
}
|
|
2028
2035
|
catch (err) {
|
|
2029
|
-
|
|
2036
|
+
cliCore.CLIDisplay.error(err);
|
|
2030
2037
|
// eslint-disable-next-line unicorn/no-process-exit
|
|
2031
2038
|
process.exit(1);
|
|
2032
2039
|
}
|
|
@@ -2043,7 +2050,7 @@ async function buildConfiguration(processEnv, options, serverInfo) {
|
|
|
2043
2050
|
let defaultEnvOnly = false;
|
|
2044
2051
|
if (core.Is.empty(options?.envFilenames)) {
|
|
2045
2052
|
const envFile = path.resolve(path.join(options.executionDirectory ?? "", ".env"));
|
|
2046
|
-
|
|
2053
|
+
cliCore.CLIDisplay.value("Default Environment File", envFile);
|
|
2047
2054
|
options ??= {};
|
|
2048
2055
|
options.envFilenames = [envFile];
|
|
2049
2056
|
defaultEnvOnly = true;
|
|
@@ -2071,18 +2078,18 @@ async function buildConfiguration(processEnv, options, serverInfo) {
|
|
|
2071
2078
|
const filePath = envVars[key].slice(6).trim();
|
|
2072
2079
|
const embeddedFile = path.resolve(path.join(options.executionDirectory ?? "", filePath));
|
|
2073
2080
|
if (envVars[key].startsWith("@text:")) {
|
|
2074
|
-
|
|
2081
|
+
cliCore.CLIDisplay.value(`Expanding Environment Variable: ${key} from text file`, embeddedFile);
|
|
2075
2082
|
envVars[key] = await loadTextFile(embeddedFile);
|
|
2076
2083
|
}
|
|
2077
2084
|
else if (envVars[key].startsWith("@json:")) {
|
|
2078
|
-
|
|
2085
|
+
cliCore.CLIDisplay.value(`Expanding Environment Variable: ${key} from JSON file`, embeddedFile);
|
|
2079
2086
|
envVars[key] = await loadJsonFile(embeddedFile);
|
|
2080
2087
|
}
|
|
2081
2088
|
}
|
|
2082
2089
|
}
|
|
2083
2090
|
// Extend the environment variables with any additional custom configuration.
|
|
2084
2091
|
if (core.Is.function(options?.extendEnvVars)) {
|
|
2085
|
-
|
|
2092
|
+
cliCore.CLIDisplay.task("Extending Environment Variables");
|
|
2086
2093
|
await options.extendEnvVars(envVars);
|
|
2087
2094
|
}
|
|
2088
2095
|
// Build the engine configuration from the environment variables.
|
|
@@ -2091,19 +2098,19 @@ async function buildConfiguration(processEnv, options, serverInfo) {
|
|
|
2091
2098
|
// Merge any custom configuration provided in the options.
|
|
2092
2099
|
if (core.Is.arrayValue(options?.configFilenames)) {
|
|
2093
2100
|
for (const configFile of options.configFilenames) {
|
|
2094
|
-
|
|
2101
|
+
cliCore.CLIDisplay.value("Loading Configuration File", configFile);
|
|
2095
2102
|
const configFilePath = path.resolve(path.join(options.executionDirectory ?? "", configFile));
|
|
2096
2103
|
const config = await loadJsonFile(configFilePath);
|
|
2097
2104
|
Object.assign(engineServerConfig, config);
|
|
2098
2105
|
}
|
|
2099
2106
|
}
|
|
2100
2107
|
if (core.Is.objectValue(options?.config)) {
|
|
2101
|
-
|
|
2108
|
+
cliCore.CLIDisplay.task("Merging Custom Configuration");
|
|
2102
2109
|
Object.assign(engineServerConfig, options.config);
|
|
2103
2110
|
}
|
|
2104
2111
|
// Merge any custom configuration provided in the options.
|
|
2105
2112
|
if (core.Is.function(options?.extendConfig)) {
|
|
2106
|
-
|
|
2113
|
+
cliCore.CLIDisplay.task("Extending Configuration");
|
|
2107
2114
|
await options.extendConfig(envVars, engineServerConfig);
|
|
2108
2115
|
}
|
|
2109
2116
|
const nodeEngineConfig = await extensionsConfiguration(envVars, engineServerConfig);
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PasswordHelper } from '@twin.org/api-auth-entity-storage-service';
|
|
2
|
-
import { I18n, Is, Coerce, Converter, RandomHelper, Urn, GeneralError,
|
|
2
|
+
import { I18n, Is, Coerce, Converter, RandomHelper, Urn, GeneralError, EnvHelper } from '@twin.org/core';
|
|
3
3
|
import { PasswordGenerator, Bip39 } from '@twin.org/crypto';
|
|
4
4
|
import { AuthenticationComponentType, InformationComponentType, RestRouteProcessorType, SocketRouteProcessorType, AuthenticationAdminComponentType } from '@twin.org/engine-server-types';
|
|
5
5
|
import { WalletConnectorType, IdentityConnectorType, EntityStorageConnectorType, BlobStorageConnectorType, BlobStorageComponentType, VaultConnectorType, DltConfigType, LoggingConnectorType, LoggingComponentType, BackgroundTaskConnectorType, TaskSchedulerComponentType, EventBusConnectorType, EventBusComponentType, TelemetryConnectorType, TelemetryComponentType, MessagingEmailConnectorType, MessagingSmsConnectorType, MessagingPushNotificationConnectorType, MessagingAdminComponentType, MessagingComponentType, FaucetConnectorType, EngineTypeHelper, NftConnectorType, NftComponentType, VerifiableStorageConnectorType, VerifiableStorageComponentType, ImmutableProofComponentType, IdentityComponentType, IdentityResolverConnectorType, IdentityResolverComponentType, IdentityProfileConnectorType, IdentityProfileComponentType, AttestationConnectorType, AttestationComponentType, DataProcessingComponentType, DataConverterConnectorType, DataExtractorConnectorType, AuditableItemGraphComponentType, AuditableItemStreamComponentType, DocumentManagementComponentType, AuthenticationGeneratorComponentType, RightsManagementPapComponentType, RightsManagementPmpComponentType, RightsManagementPipComponentType, RightsManagementPxpComponentType, RightsManagementPdpComponentType, RightsManagementPepComponentType, RightsManagementPnpComponentType, RightsManagementPnapComponentType, RightsManagementDapComponentType, RightsManagementDarpComponentType, SynchronisedStorageComponentType, FederatedCatalogueComponentType, DataSpaceConnectorComponentType } from '@twin.org/engine-types';
|
|
@@ -9,6 +9,7 @@ import { VaultConnectorFactory, VaultKeyType } from '@twin.org/vault-models';
|
|
|
9
9
|
import { WalletConnectorFactory } from '@twin.org/wallet-models';
|
|
10
10
|
import { readFile, stat, readdir } from 'node:fs/promises';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
+
import { CLIDisplay } from '@twin.org/cli-core';
|
|
12
13
|
import { PolicyNegotiationPointClient, DataAccessPointClient } from '@twin.org/rights-management-rest-client';
|
|
13
14
|
import { addDefaultRestPaths, addDefaultSocketPaths, EngineServer } from '@twin.org/engine-server';
|
|
14
15
|
import { ModuleHelper } from '@twin.org/modules';
|
|
@@ -49,20 +50,19 @@ const NodeFeatures = {
|
|
|
49
50
|
|
|
50
51
|
// Copyright 2024 IOTA Stiftung.
|
|
51
52
|
// SPDX-License-Identifier: Apache-2.0.
|
|
52
|
-
/* eslint-disable no-console */
|
|
53
53
|
/**
|
|
54
54
|
* Initialise the locales for the application.
|
|
55
55
|
* @param localesDirectory The directory containing the locales.
|
|
56
56
|
*/
|
|
57
57
|
async function initialiseLocales(localesDirectory) {
|
|
58
58
|
const localesFile = path.resolve(path.join(localesDirectory, "en.json"));
|
|
59
|
-
|
|
59
|
+
CLIDisplay.value("Locales File", localesFile);
|
|
60
60
|
if (await fileExists(localesFile)) {
|
|
61
61
|
const enLangContent = await readFile(localesFile, "utf8");
|
|
62
62
|
I18n.addDictionary("en", JSON.parse(enLangContent));
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
|
-
|
|
65
|
+
CLIDisplay.error(`Locales file not found: ${localesFile}`);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
@@ -1794,7 +1794,6 @@ async function buildEngineServerConfiguration(envVars, coreEngineConfig, serverI
|
|
|
1794
1794
|
|
|
1795
1795
|
// Copyright 2024 IOTA Stiftung.
|
|
1796
1796
|
// SPDX-License-Identifier: Apache-2.0.
|
|
1797
|
-
/* eslint-disable no-console */
|
|
1798
1797
|
/**
|
|
1799
1798
|
* Handles the configuration of the extensions.
|
|
1800
1799
|
* @param envVars The environment variables for the node.
|
|
@@ -1807,11 +1806,11 @@ async function extensionsConfiguration(envVars, nodeEngineConfig) {
|
|
|
1807
1806
|
for (const extension of extensions) {
|
|
1808
1807
|
let initialiseConfigMethod;
|
|
1809
1808
|
try {
|
|
1810
|
-
|
|
1809
|
+
CLIDisplay.value(I18n.formatMessage("node.extensionLoading"), extension);
|
|
1811
1810
|
initialiseConfigMethod = await ModuleHelper.getModuleMethod(extension, "extensionInitialise");
|
|
1812
1811
|
}
|
|
1813
1812
|
catch (err) {
|
|
1814
|
-
|
|
1813
|
+
throw new GeneralError("node", "extensionLoadingError", { extension }, err);
|
|
1815
1814
|
}
|
|
1816
1815
|
if (Is.function(initialiseConfigMethod)) {
|
|
1817
1816
|
await initialiseConfigMethod(envVars, nodeEngineConfig);
|
|
@@ -1832,6 +1831,7 @@ async function extensionsInitialiseEngine(envVars, engineCore) {
|
|
|
1832
1831
|
for (const extension of extensions) {
|
|
1833
1832
|
let initialiseEngineMethod;
|
|
1834
1833
|
try {
|
|
1834
|
+
engineCore.logInfo(I18n.formatMessage("node.extensionInitialisingEngine", { extension }));
|
|
1835
1835
|
initialiseEngineMethod =
|
|
1836
1836
|
await ModuleHelper.getModuleMethod(extension, "extensionInitialiseEngine");
|
|
1837
1837
|
}
|
|
@@ -1855,6 +1855,7 @@ async function extensionsInitialiseEngineServer(envVars, engineCore, engineServe
|
|
|
1855
1855
|
for (const extension of extensions) {
|
|
1856
1856
|
let initialiseEngineServerMethod;
|
|
1857
1857
|
try {
|
|
1858
|
+
engineCore.logInfo(I18n.formatMessage("node.extensionInitialisingEngineServer", { extension }));
|
|
1858
1859
|
initialiseEngineServerMethod =
|
|
1859
1860
|
await ModuleHelper.getModuleMethod(extension, "extensionInitialiseEngineServer");
|
|
1860
1861
|
}
|
|
@@ -1868,14 +1869,16 @@ async function extensionsInitialiseEngineServer(envVars, engineCore, engineServe
|
|
|
1868
1869
|
/**
|
|
1869
1870
|
* Handles the shutdown of the extensions.
|
|
1870
1871
|
* @param envVars The environment variables for the node.
|
|
1872
|
+
* @param engineCore The engine core instance.
|
|
1871
1873
|
* @returns Nothing.
|
|
1872
1874
|
*/
|
|
1873
|
-
async function shutdownExtensions(envVars) {
|
|
1875
|
+
async function shutdownExtensions(envVars, engineCore) {
|
|
1874
1876
|
if (Is.stringValue(envVars.extensions)) {
|
|
1875
1877
|
const extensions = envVars.extensions.split(",");
|
|
1876
1878
|
for (const extension of extensions) {
|
|
1877
1879
|
let shutdownMethod;
|
|
1878
1880
|
try {
|
|
1881
|
+
engineCore.logInfo(I18n.formatMessage("node.extensionShutdown", { extension }));
|
|
1879
1882
|
shutdownMethod = await ModuleHelper.getModuleMethod(extension, "extensionShutdown");
|
|
1880
1883
|
}
|
|
1881
1884
|
catch { }
|
|
@@ -1888,7 +1891,6 @@ async function shutdownExtensions(envVars) {
|
|
|
1888
1891
|
|
|
1889
1892
|
// Copyright 2024 IOTA Stiftung.
|
|
1890
1893
|
// SPDX-License-Identifier: Apache-2.0.
|
|
1891
|
-
/* eslint-disable no-console */
|
|
1892
1894
|
/**
|
|
1893
1895
|
* Start the engine server.
|
|
1894
1896
|
* @param nodeOptions Optional run options for the engine server.
|
|
@@ -1919,13 +1921,13 @@ async function start(nodeOptions, nodeEngineConfig, envVars) {
|
|
|
1919
1921
|
const server = new EngineServer({ engineCore: engine });
|
|
1920
1922
|
// Extend the engine.
|
|
1921
1923
|
if (Is.function(nodeOptions?.extendEngine)) {
|
|
1922
|
-
|
|
1924
|
+
engine.logInfo(I18n.formatMessage("node.extendingEngine"));
|
|
1923
1925
|
await nodeOptions.extendEngine(engine);
|
|
1924
1926
|
}
|
|
1925
1927
|
await extensionsInitialiseEngine(envVars, engine);
|
|
1926
1928
|
// Extend the engine server.
|
|
1927
1929
|
if (Is.function(nodeOptions?.extendEngineServer)) {
|
|
1928
|
-
|
|
1930
|
+
engine.logInfo(I18n.formatMessage("node.extendingEngineServer"));
|
|
1929
1931
|
await nodeOptions?.extendEngineServer(server);
|
|
1930
1932
|
}
|
|
1931
1933
|
await extensionsInitialiseEngineServer(envVars, engine, server);
|
|
@@ -1940,7 +1942,7 @@ async function start(nodeOptions, nodeEngineConfig, envVars) {
|
|
|
1940
1942
|
server,
|
|
1941
1943
|
shutdown: async () => {
|
|
1942
1944
|
await server.stop();
|
|
1943
|
-
await shutdownExtensions(envVars);
|
|
1945
|
+
await shutdownExtensions(envVars, engine);
|
|
1944
1946
|
}
|
|
1945
1947
|
};
|
|
1946
1948
|
}
|
|
@@ -1948,7 +1950,6 @@ async function start(nodeOptions, nodeEngineConfig, envVars) {
|
|
|
1948
1950
|
|
|
1949
1951
|
// Copyright 2024 IOTA Stiftung.
|
|
1950
1952
|
// SPDX-License-Identifier: Apache-2.0.
|
|
1951
|
-
/* eslint-disable no-console */
|
|
1952
1953
|
/**
|
|
1953
1954
|
* Run the TWIN Node server.
|
|
1954
1955
|
* @param nodeOptions Optional configuration options for running the server.
|
|
@@ -1959,42 +1960,48 @@ async function run(nodeOptions) {
|
|
|
1959
1960
|
nodeOptions ??= {};
|
|
1960
1961
|
const serverInfo = {
|
|
1961
1962
|
name: nodeOptions?.serverName ?? "TWIN Node Server",
|
|
1962
|
-
version: nodeOptions?.serverVersion ?? "0.0.2-next.
|
|
1963
|
+
version: nodeOptions?.serverVersion ?? "0.0.2-next.18" // x-release-please-version
|
|
1963
1964
|
};
|
|
1964
|
-
|
|
1965
|
+
CLIDisplay.header(serverInfo.name, serverInfo.version, "🌩️ ");
|
|
1965
1966
|
if (!Is.stringValue(nodeOptions?.executionDirectory)) {
|
|
1966
1967
|
nodeOptions.executionDirectory = getExecutionDirectory();
|
|
1967
1968
|
}
|
|
1968
|
-
|
|
1969
|
+
CLIDisplay.value("Execution Directory", nodeOptions.executionDirectory);
|
|
1969
1970
|
nodeOptions.localesDirectory =
|
|
1970
1971
|
nodeOptions?.localesDirectory ??
|
|
1971
1972
|
path.resolve(path.join(nodeOptions.executionDirectory, "dist", "locales"));
|
|
1972
|
-
|
|
1973
|
+
CLIDisplay.value("Locales Directory", nodeOptions.localesDirectory);
|
|
1973
1974
|
await initialiseLocales(nodeOptions.localesDirectory);
|
|
1974
1975
|
if (Is.empty(nodeOptions?.openApiSpecFile)) {
|
|
1975
1976
|
const specFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "docs", "open-api", "spec.json"));
|
|
1976
|
-
|
|
1977
|
+
CLIDisplay.value("Default OpenAPI Spec File", specFile);
|
|
1977
1978
|
if (await fileExists(specFile)) {
|
|
1978
1979
|
nodeOptions ??= {};
|
|
1979
1980
|
nodeOptions.openApiSpecFile = specFile;
|
|
1980
1981
|
}
|
|
1981
1982
|
}
|
|
1983
|
+
else {
|
|
1984
|
+
CLIDisplay.value("OpenAPI Spec File", nodeOptions.openApiSpecFile);
|
|
1985
|
+
}
|
|
1982
1986
|
if (Is.empty(nodeOptions?.favIconFile)) {
|
|
1983
1987
|
const favIconFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "static", "favicon.png"));
|
|
1984
|
-
|
|
1988
|
+
CLIDisplay.value("Default Favicon File", favIconFile);
|
|
1985
1989
|
if (await fileExists(favIconFile)) {
|
|
1986
1990
|
nodeOptions ??= {};
|
|
1987
1991
|
nodeOptions.favIconFile = favIconFile;
|
|
1988
1992
|
}
|
|
1989
1993
|
}
|
|
1994
|
+
else {
|
|
1995
|
+
CLIDisplay.value("Favicon File", nodeOptions.favIconFile);
|
|
1996
|
+
}
|
|
1990
1997
|
nodeOptions.envPrefix ??= "TWIN_NODE_";
|
|
1991
|
-
|
|
1998
|
+
CLIDisplay.value("Environment Variable Prefix", nodeOptions.envPrefix);
|
|
1992
1999
|
overrideModuleImport(nodeOptions.executionDirectory ?? "");
|
|
1993
2000
|
const { nodeEngineConfig, nodeEnvVars: envVars } = await buildConfiguration(
|
|
1994
2001
|
// This is the only location in the code base that should access process.env directly
|
|
1995
2002
|
// eslint-disable-next-line no-restricted-syntax
|
|
1996
2003
|
process.env, nodeOptions, serverInfo);
|
|
1997
|
-
|
|
2004
|
+
CLIDisplay.break();
|
|
1998
2005
|
const startResult = await start(nodeOptions, nodeEngineConfig, envVars);
|
|
1999
2006
|
if (!Is.empty(startResult)) {
|
|
2000
2007
|
for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
|
|
@@ -2005,7 +2012,7 @@ async function run(nodeOptions) {
|
|
|
2005
2012
|
}
|
|
2006
2013
|
}
|
|
2007
2014
|
catch (err) {
|
|
2008
|
-
|
|
2015
|
+
CLIDisplay.error(err);
|
|
2009
2016
|
// eslint-disable-next-line unicorn/no-process-exit
|
|
2010
2017
|
process.exit(1);
|
|
2011
2018
|
}
|
|
@@ -2022,7 +2029,7 @@ async function buildConfiguration(processEnv, options, serverInfo) {
|
|
|
2022
2029
|
let defaultEnvOnly = false;
|
|
2023
2030
|
if (Is.empty(options?.envFilenames)) {
|
|
2024
2031
|
const envFile = path.resolve(path.join(options.executionDirectory ?? "", ".env"));
|
|
2025
|
-
|
|
2032
|
+
CLIDisplay.value("Default Environment File", envFile);
|
|
2026
2033
|
options ??= {};
|
|
2027
2034
|
options.envFilenames = [envFile];
|
|
2028
2035
|
defaultEnvOnly = true;
|
|
@@ -2050,18 +2057,18 @@ async function buildConfiguration(processEnv, options, serverInfo) {
|
|
|
2050
2057
|
const filePath = envVars[key].slice(6).trim();
|
|
2051
2058
|
const embeddedFile = path.resolve(path.join(options.executionDirectory ?? "", filePath));
|
|
2052
2059
|
if (envVars[key].startsWith("@text:")) {
|
|
2053
|
-
|
|
2060
|
+
CLIDisplay.value(`Expanding Environment Variable: ${key} from text file`, embeddedFile);
|
|
2054
2061
|
envVars[key] = await loadTextFile(embeddedFile);
|
|
2055
2062
|
}
|
|
2056
2063
|
else if (envVars[key].startsWith("@json:")) {
|
|
2057
|
-
|
|
2064
|
+
CLIDisplay.value(`Expanding Environment Variable: ${key} from JSON file`, embeddedFile);
|
|
2058
2065
|
envVars[key] = await loadJsonFile(embeddedFile);
|
|
2059
2066
|
}
|
|
2060
2067
|
}
|
|
2061
2068
|
}
|
|
2062
2069
|
// Extend the environment variables with any additional custom configuration.
|
|
2063
2070
|
if (Is.function(options?.extendEnvVars)) {
|
|
2064
|
-
|
|
2071
|
+
CLIDisplay.task("Extending Environment Variables");
|
|
2065
2072
|
await options.extendEnvVars(envVars);
|
|
2066
2073
|
}
|
|
2067
2074
|
// Build the engine configuration from the environment variables.
|
|
@@ -2070,19 +2077,19 @@ async function buildConfiguration(processEnv, options, serverInfo) {
|
|
|
2070
2077
|
// Merge any custom configuration provided in the options.
|
|
2071
2078
|
if (Is.arrayValue(options?.configFilenames)) {
|
|
2072
2079
|
for (const configFile of options.configFilenames) {
|
|
2073
|
-
|
|
2080
|
+
CLIDisplay.value("Loading Configuration File", configFile);
|
|
2074
2081
|
const configFilePath = path.resolve(path.join(options.executionDirectory ?? "", configFile));
|
|
2075
2082
|
const config = await loadJsonFile(configFilePath);
|
|
2076
2083
|
Object.assign(engineServerConfig, config);
|
|
2077
2084
|
}
|
|
2078
2085
|
}
|
|
2079
2086
|
if (Is.objectValue(options?.config)) {
|
|
2080
|
-
|
|
2087
|
+
CLIDisplay.task("Merging Custom Configuration");
|
|
2081
2088
|
Object.assign(engineServerConfig, options.config);
|
|
2082
2089
|
}
|
|
2083
2090
|
// Merge any custom configuration provided in the options.
|
|
2084
2091
|
if (Is.function(options?.extendConfig)) {
|
|
2085
|
-
|
|
2092
|
+
CLIDisplay.task("Extending Configuration");
|
|
2086
2093
|
await options.extendConfig(envVars, engineServerConfig);
|
|
2087
2094
|
}
|
|
2088
2095
|
const nodeEngineConfig = await extensionsConfiguration(envVars, engineServerConfig);
|
|
@@ -26,6 +26,7 @@ export declare function extensionsInitialiseEngineServer(envVars: INodeEnvironme
|
|
|
26
26
|
/**
|
|
27
27
|
* Handles the shutdown of the extensions.
|
|
28
28
|
* @param envVars The environment variables for the node.
|
|
29
|
+
* @param engineCore The engine core instance.
|
|
29
30
|
* @returns Nothing.
|
|
30
31
|
*/
|
|
31
|
-
export declare function shutdownExtensions(envVars: INodeEnvironmentVariables): Promise<void>;
|
|
32
|
+
export declare function shutdownExtensions(envVars: INodeEnvironmentVariables, engineCore: IEngineCore): Promise<void>;
|
|
@@ -20,3 +20,8 @@ export type NodeExtensionInitialiseEngineMethod = (engineCore: IEngineCore) => P
|
|
|
20
20
|
* @param engineServer The engine server instance.
|
|
21
21
|
*/
|
|
22
22
|
export type NodeExtensionInitialiseEngineServerMethod = (engineCore: IEngineCore, engineServer: IEngineServer) => Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* The type for the shutdown method of an extension module.
|
|
25
|
+
* This is called when the engine is shutting down.
|
|
26
|
+
*/
|
|
27
|
+
export type NodeExtensionShutdownMethod = () => Promise<void>;
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @twin.org/node-core - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.2-next.18](https://github.com/twinfoundation/node/compare/node-core-v0.0.2-next.17...node-core-v0.0.2-next.18) (2025-10-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* improve error handling for extensions and logging ([bd84fde](https://github.com/twinfoundation/node/commit/bd84fde67e5a9db6ac66730397992401ca52e88c))
|
|
9
|
+
|
|
3
10
|
## [0.0.2-next.17](https://github.com/twinfoundation/node/compare/node-core-v0.0.2-next.16...node-core-v0.0.2-next.17) (2025-10-02)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Function: shutdownExtensions()
|
|
2
2
|
|
|
3
|
-
> **shutdownExtensions**(`envVars`): `Promise`\<`void`\>
|
|
3
|
+
> **shutdownExtensions**(`envVars`, `engineCore`): `Promise`\<`void`\>
|
|
4
4
|
|
|
5
5
|
Handles the shutdown of the extensions.
|
|
6
6
|
|
|
@@ -12,6 +12,12 @@ Handles the shutdown of the extensions.
|
|
|
12
12
|
|
|
13
13
|
The environment variables for the node.
|
|
14
14
|
|
|
15
|
+
### engineCore
|
|
16
|
+
|
|
17
|
+
`IEngineCore`
|
|
18
|
+
|
|
19
|
+
The engine core instance.
|
|
20
|
+
|
|
15
21
|
## Returns
|
|
16
22
|
|
|
17
23
|
`Promise`\<`void`\>
|
package/docs/reference/index.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
- [NodeExtensionInitialiseMethod](type-aliases/NodeExtensionInitialiseMethod.md)
|
|
14
14
|
- [NodeExtensionInitialiseEngineMethod](type-aliases/NodeExtensionInitialiseEngineMethod.md)
|
|
15
15
|
- [NodeExtensionInitialiseEngineServerMethod](type-aliases/NodeExtensionInitialiseEngineServerMethod.md)
|
|
16
|
+
- [NodeExtensionShutdownMethod](type-aliases/NodeExtensionShutdownMethod.md)
|
|
16
17
|
- [NodeFeatures](type-aliases/NodeFeatures.md)
|
|
17
18
|
|
|
18
19
|
## Variables
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Type Alias: NodeExtensionShutdownMethod()
|
|
2
|
+
|
|
3
|
+
> **NodeExtensionShutdownMethod** = () => `Promise`\<`void`\>
|
|
4
|
+
|
|
5
|
+
The type for the shutdown method of an extension module.
|
|
6
|
+
This is called when the engine is shutting down.
|
|
7
|
+
|
|
8
|
+
## Returns
|
|
9
|
+
|
|
10
|
+
`Promise`\<`void`\>
|
package/locales/en.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"error": {
|
|
3
3
|
"node": {
|
|
4
|
-
"storageFileRootNotSet": "{storageFileRoot} is not set, the server will not start without it, please set it in the shell or create a .env file"
|
|
4
|
+
"storageFileRootNotSet": "{storageFileRoot} is not set, the server will not start without it, please set it in the shell or create a .env file",
|
|
5
|
+
"extensionLoadingError": "Failed to load extension \"{extension}\""
|
|
5
6
|
}
|
|
6
7
|
},
|
|
7
8
|
"node": {
|
|
@@ -31,6 +32,12 @@
|
|
|
31
32
|
"existingUserProfile": "User profile already exists \"{identity}\"",
|
|
32
33
|
"nodeIdentity": "Node identity \"{identity}\"",
|
|
33
34
|
"nodeAdminUserEmail": "Node Admin User Email \"{email}\"",
|
|
34
|
-
"nodeAdminUserPassword": "Node Admin User Password \"{password}\""
|
|
35
|
+
"nodeAdminUserPassword": "Node Admin User Password \"{password}\"",
|
|
36
|
+
"extensionLoading": "Loading Extension",
|
|
37
|
+
"extensionInitialisingEngine": "Initialising engine for extension \"{extension}\"",
|
|
38
|
+
"extensionInitialisingEngineServer": "Initialising engine server for extension \"{extension}\"",
|
|
39
|
+
"extensionShutdown": "Shutdown extension \"{extension}\"",
|
|
40
|
+
"extendingEngine": "Extending Engine",
|
|
41
|
+
"extendingEngineServer": "Extending Engine Server"
|
|
35
42
|
}
|
|
36
43
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/node-core",
|
|
3
|
-
"version": "0.0.2-next.
|
|
3
|
+
"version": "0.0.2-next.18",
|
|
4
4
|
"description": "TWIN Node Core for serving APIs using the specified configuration",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@twin.org/api-auth-entity-storage-service": "next",
|
|
18
|
+
"@twin.org/cli-core": "next",
|
|
18
19
|
"@twin.org/core": "next",
|
|
19
20
|
"@twin.org/crypto": "next",
|
|
20
21
|
"@twin.org/data-space-connector-models": "next",
|