@twin.org/node-core 0.0.2-next.9 → 0.0.3-next.10

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 (195) hide show
  1. package/README.md +1 -1
  2. package/dist/es/builders/engineEnvBuilder.js +1132 -0
  3. package/dist/es/builders/engineEnvBuilder.js.map +1 -0
  4. package/dist/es/builders/engineServerEnvBuilder.js +206 -0
  5. package/dist/es/builders/engineServerEnvBuilder.js.map +1 -0
  6. package/dist/es/builders/extensionsBuilder.js +109 -0
  7. package/dist/es/builders/extensionsBuilder.js.map +1 -0
  8. package/dist/es/cli.js +255 -0
  9. package/dist/es/cli.js.map +1 -0
  10. package/dist/es/commands/bootstrapLegacy.js +175 -0
  11. package/dist/es/commands/bootstrapLegacy.js.map +1 -0
  12. package/dist/es/commands/help.js +85 -0
  13. package/dist/es/commands/help.js.map +1 -0
  14. package/dist/es/commands/identityCreate.js +310 -0
  15. package/dist/es/commands/identityCreate.js.map +1 -0
  16. package/dist/es/commands/identityImports.js +76 -0
  17. package/dist/es/commands/identityImports.js.map +1 -0
  18. package/dist/es/commands/identityVerifiableCredentialCreate.js +140 -0
  19. package/dist/es/commands/identityVerifiableCredentialCreate.js.map +1 -0
  20. package/dist/es/commands/identityVerificationMethodCreate.js +208 -0
  21. package/dist/es/commands/identityVerificationMethodCreate.js.map +1 -0
  22. package/dist/es/commands/identityVerificationMethodImport.js +120 -0
  23. package/dist/es/commands/identityVerificationMethodImport.js.map +1 -0
  24. package/dist/es/commands/nodeSetIdentity.js +51 -0
  25. package/dist/es/commands/nodeSetIdentity.js.map +1 -0
  26. package/dist/es/commands/nodeSetTenant.js +49 -0
  27. package/dist/es/commands/nodeSetTenant.js.map +1 -0
  28. package/dist/es/commands/tenantCreate.js +120 -0
  29. package/dist/es/commands/tenantCreate.js.map +1 -0
  30. package/dist/es/commands/tenantImport.js +78 -0
  31. package/dist/es/commands/tenantImport.js.map +1 -0
  32. package/dist/es/commands/userCreate.js +197 -0
  33. package/dist/es/commands/userCreate.js.map +1 -0
  34. package/dist/es/commands/vaultKeyCreate.js +185 -0
  35. package/dist/es/commands/vaultKeyCreate.js.map +1 -0
  36. package/dist/es/commands/vaultKeyImport.js +98 -0
  37. package/dist/es/commands/vaultKeyImport.js.map +1 -0
  38. package/dist/es/defaults.js +28 -0
  39. package/dist/es/defaults.js.map +1 -0
  40. package/dist/es/index.js +27 -0
  41. package/dist/es/index.js.map +1 -0
  42. package/dist/es/models/ICacheMetadata.js +4 -0
  43. package/dist/es/models/ICacheMetadata.js.map +1 -0
  44. package/dist/es/models/ICliArgs.js +4 -0
  45. package/dist/es/models/ICliArgs.js.map +1 -0
  46. package/dist/es/models/ICliCommand.js +2 -0
  47. package/dist/es/models/ICliCommand.js.map +1 -0
  48. package/dist/es/models/ICliCommandDefinition.js +2 -0
  49. package/dist/es/models/ICliCommandDefinition.js.map +1 -0
  50. package/dist/es/models/ICliCommandDefinitionParam.js +2 -0
  51. package/dist/es/models/ICliCommandDefinitionParam.js.map +1 -0
  52. package/dist/es/models/IEngineEnvironmentVariables.js +4 -0
  53. package/dist/es/models/IEngineEnvironmentVariables.js.map +1 -0
  54. package/dist/es/models/IEngineServerEnvironmentVariables.js +2 -0
  55. package/dist/es/models/IEngineServerEnvironmentVariables.js.map +1 -0
  56. package/dist/es/models/IModuleProtocol.js +2 -0
  57. package/dist/es/models/IModuleProtocol.js.map +1 -0
  58. package/dist/es/models/INodeEngineConfig.js +2 -0
  59. package/dist/es/models/INodeEngineConfig.js.map +1 -0
  60. package/dist/es/models/INodeEngineState.js +2 -0
  61. package/dist/es/models/INodeEngineState.js.map +1 -0
  62. package/dist/es/models/INodeEnvironmentVariables.js +2 -0
  63. package/dist/es/models/INodeEnvironmentVariables.js.map +1 -0
  64. package/dist/es/models/INodeOptions.js +2 -0
  65. package/dist/es/models/INodeOptions.js.map +1 -0
  66. package/dist/es/models/IProtocolHandlerResult.js +4 -0
  67. package/dist/es/models/IProtocolHandlerResult.js.map +1 -0
  68. package/dist/es/models/cliCommandParamType.js +4 -0
  69. package/dist/es/models/cliCommandParamType.js.map +1 -0
  70. package/dist/es/models/moduleProtocol.js +29 -0
  71. package/dist/es/models/moduleProtocol.js.map +1 -0
  72. package/dist/es/models/nodeExtensionMethods.js +2 -0
  73. package/dist/es/models/nodeExtensionMethods.js.map +1 -0
  74. package/dist/es/node.js +285 -0
  75. package/dist/es/node.js.map +1 -0
  76. package/dist/es/start.js +128 -0
  77. package/dist/es/start.js.map +1 -0
  78. package/dist/es/utils.js +397 -0
  79. package/dist/es/utils.js.map +1 -0
  80. package/dist/types/builders/engineEnvBuilder.d.ts +6 -2
  81. package/dist/types/builders/engineServerEnvBuilder.d.ts +7 -3
  82. package/dist/types/builders/extensionsBuilder.d.ts +32 -0
  83. package/dist/types/cli.d.ts +66 -0
  84. package/dist/types/commands/bootstrapLegacy.d.ts +66 -0
  85. package/dist/types/commands/help.d.ts +23 -0
  86. package/dist/types/commands/identityCreate.d.ts +39 -0
  87. package/dist/types/commands/identityImports.d.ts +24 -0
  88. package/dist/types/commands/identityVerifiableCredentialCreate.d.ts +43 -0
  89. package/dist/types/commands/identityVerificationMethodCreate.d.ts +47 -0
  90. package/dist/types/commands/identityVerificationMethodImport.d.ts +31 -0
  91. package/dist/types/commands/nodeSetIdentity.d.ts +22 -0
  92. package/dist/types/commands/nodeSetTenant.d.ts +22 -0
  93. package/dist/types/commands/tenantCreate.d.ts +35 -0
  94. package/dist/types/commands/tenantImport.d.ts +24 -0
  95. package/dist/types/commands/userCreate.d.ts +46 -0
  96. package/dist/types/commands/vaultKeyCreate.d.ts +43 -0
  97. package/dist/types/commands/vaultKeyImport.d.ts +28 -0
  98. package/dist/types/defaults.d.ts +16 -0
  99. package/dist/types/index.d.ts +24 -11
  100. package/dist/types/models/ICacheMetadata.d.ts +17 -0
  101. package/dist/types/models/ICliArgs.d.ts +20 -0
  102. package/dist/types/models/ICliCommand.d.ts +17 -0
  103. package/dist/types/models/ICliCommandDefinition.d.ts +46 -0
  104. package/dist/types/models/ICliCommandDefinitionParam.d.ts +35 -0
  105. package/dist/types/models/IEngineEnvironmentVariables.d.ts +154 -37
  106. package/dist/types/models/IEngineServerEnvironmentVariables.d.ts +12 -3
  107. package/dist/types/models/IModuleProtocol.d.ts +18 -0
  108. package/dist/types/models/INodeEngineConfig.d.ts +6 -0
  109. package/dist/types/models/INodeEngineState.d.ts +14 -0
  110. package/dist/types/models/INodeEnvironmentVariables.d.ts +17 -15
  111. package/dist/types/models/INodeOptions.d.ts +14 -3
  112. package/dist/types/models/IProtocolHandlerResult.d.ts +13 -0
  113. package/dist/types/models/cliCommandParamType.d.ts +4 -0
  114. package/dist/types/models/moduleProtocol.d.ts +29 -0
  115. package/dist/types/models/nodeExtensionMethods.d.ts +27 -0
  116. package/dist/types/node.d.ts +21 -7
  117. package/dist/types/start.d.ts +25 -0
  118. package/dist/types/utils.d.ts +83 -6
  119. package/docs/changelog.md +241 -0
  120. package/docs/detailed-guide.md +129 -0
  121. package/docs/reference/functions/buildConfiguration.md +2 -2
  122. package/docs/reference/functions/buildEngineConfiguration.md +8 -2
  123. package/docs/reference/functions/buildEngineServerConfiguration.md +9 -3
  124. package/docs/reference/functions/constructCliCommand.md +27 -0
  125. package/docs/reference/functions/createModuleImportUrl.md +21 -0
  126. package/docs/reference/functions/directoryExists.md +19 -0
  127. package/docs/reference/functions/executeCommand.md +29 -0
  128. package/docs/reference/functions/extensionsConfiguration.md +25 -0
  129. package/docs/reference/functions/extensionsInitialiseEngine.md +25 -0
  130. package/docs/reference/functions/extensionsInitialiseEngineServer.md +31 -0
  131. package/docs/reference/functions/getEnvDefaults.md +19 -0
  132. package/docs/reference/functions/getExtensionsCacheDir.md +31 -0
  133. package/docs/reference/functions/getFiles.md +19 -0
  134. package/docs/reference/functions/getSubFolders.md +19 -0
  135. package/docs/reference/functions/handleHttpsProtocol.md +49 -0
  136. package/docs/reference/functions/handleNpmProtocol.md +31 -0
  137. package/docs/reference/functions/hashUrl.md +19 -0
  138. package/docs/reference/functions/initCli.md +27 -0
  139. package/docs/reference/functions/isCacheExpired.md +31 -0
  140. package/docs/reference/functions/overrideModuleImport.md +8 -2
  141. package/docs/reference/functions/parseCommandLineArgs.md +19 -0
  142. package/docs/reference/functions/parseModuleProtocol.md +19 -0
  143. package/docs/reference/functions/processEnvOptions.md +27 -0
  144. package/docs/reference/functions/registerCommands.md +9 -0
  145. package/docs/reference/functions/resolvePackageEntryPoint.md +32 -0
  146. package/docs/reference/functions/run.md +9 -3
  147. package/docs/reference/functions/shutdownExtensions.md +25 -0
  148. package/docs/reference/functions/start.md +17 -5
  149. package/docs/reference/functions/substituteEnvOptions.md +25 -0
  150. package/docs/reference/index.md +47 -10
  151. package/docs/reference/interfaces/ICacheMetadata.md +27 -0
  152. package/docs/reference/interfaces/ICliArgs.md +35 -0
  153. package/docs/reference/interfaces/ICliCommand.md +23 -0
  154. package/docs/reference/interfaces/ICliCommandDefinition.md +101 -0
  155. package/docs/reference/interfaces/ICliCommandDefinitionParam.md +65 -0
  156. package/docs/reference/interfaces/IEngineEnvironmentVariables.md +303 -60
  157. package/docs/reference/interfaces/IEngineServerEnvironmentVariables.md +1737 -5
  158. package/docs/reference/interfaces/IModuleProtocol.md +27 -0
  159. package/docs/reference/interfaces/INodeEngineConfig.md +7 -0
  160. package/docs/reference/interfaces/INodeEngineState.md +23 -0
  161. package/docs/reference/interfaces/INodeEnvironmentVariables.md +599 -198
  162. package/docs/reference/interfaces/INodeOptions.md +27 -3
  163. package/docs/reference/interfaces/IProtocolHandlerResult.md +19 -0
  164. package/docs/reference/type-aliases/CliCommandParamType.md +5 -0
  165. package/docs/reference/type-aliases/ModuleProtocol.md +5 -0
  166. package/docs/reference/type-aliases/NodeExtensionInitialiseEngineMethod.md +18 -0
  167. package/docs/reference/type-aliases/NodeExtensionInitialiseEngineServerMethod.md +24 -0
  168. package/docs/reference/type-aliases/NodeExtensionInitialiseMethod.md +23 -0
  169. package/docs/reference/type-aliases/NodeExtensionShutdownMethod.md +10 -0
  170. package/docs/reference/variables/ATTESTATION_VERIFICATION_METHOD_ID.md +3 -0
  171. package/docs/reference/variables/AUTH_SIGNING_KEY_ID.md +3 -0
  172. package/docs/reference/variables/BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
  173. package/docs/reference/variables/CONTEXT_ID_HANDLER_FEATURE_DID.md +3 -0
  174. package/docs/reference/variables/CONTEXT_ID_HANDLER_FEATURE_TENANT.md +3 -0
  175. package/docs/reference/variables/IMMUTABLE_PROOF_VERIFICATION_METHOD_ID.md +3 -0
  176. package/docs/reference/variables/ModuleProtocol.md +37 -0
  177. package/docs/reference/variables/SYNCHRONISED_STORAGE_BLOB_STORAGE_ENCRYPTION_KEY_ID.md +3 -0
  178. package/docs/reference/variables/VC_AUTHENTICATION_VERIFICATION_METHOD_ID.md +3 -0
  179. package/locales/en.json +479 -28
  180. package/package.json +29 -9
  181. package/dist/cjs/index.cjs +0 -1910
  182. package/dist/esm/index.mjs +0 -1870
  183. package/dist/types/bootstrap.d.ts +0 -59
  184. package/dist/types/models/nodeFeatures.d.ts +0 -21
  185. package/dist/types/server.d.ts +0 -17
  186. package/docs/reference/functions/bootstrap.md +0 -29
  187. package/docs/reference/functions/bootstrapAuth.md +0 -35
  188. package/docs/reference/functions/bootstrapBlobEncryption.md +0 -35
  189. package/docs/reference/functions/bootstrapImmutableProofMethod.md +0 -35
  190. package/docs/reference/functions/bootstrapNodeIdentity.md +0 -35
  191. package/docs/reference/functions/bootstrapNodeUser.md +0 -35
  192. package/docs/reference/functions/bootstrapSynchronisedStorage.md +0 -35
  193. package/docs/reference/functions/getFeatures.md +0 -19
  194. package/docs/reference/type-aliases/NodeFeatures.md +0 -5
  195. package/docs/reference/variables/NodeFeatures.md +0 -25
@@ -0,0 +1,285 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { execSync } from "node:child_process";
4
+ import path from "node:path";
5
+ import { CLIDisplay } from "@twin.org/cli-core";
6
+ import { BaseError, Coerce, EnvHelper, GeneralError, Is, ObjectHelper } from "@twin.org/core";
7
+ import { ModuleHelper } from "@twin.org/modules";
8
+ import * as dotenv from "dotenv";
9
+ import { buildEngineConfiguration } from "./builders/engineEnvBuilder.js";
10
+ import { buildEngineServerConfiguration } from "./builders/engineServerEnvBuilder.js";
11
+ import { extensionsConfiguration } from "./builders/extensionsBuilder.js";
12
+ import { initCli } from "./cli.js";
13
+ import { getEnvDefaults } from "./defaults.js";
14
+ import { ModuleProtocol } from "./models/moduleProtocol.js";
15
+ import { start } from "./start.js";
16
+ import { createModuleImportUrl, fileExists, getExecutionDirectory, getExtensionsCacheDir, handleHttpsProtocol, handleNpmProtocol, initialiseLocales, loadJsonFile, loadTextFile, parseModuleProtocol, resolvePackageEntryPoint } from "./utils.js";
17
+ const moduleCache = {};
18
+ /**
19
+ * Run the TWIN Node server.
20
+ * @param nodeOptions Optional configuration options for running the server.
21
+ * @param args Optional command line arguments.
22
+ * @returns A promise that resolves when the server is started containing a shutdown method.
23
+ */
24
+ export async function run(nodeOptions, args) {
25
+ let isSilent = true;
26
+ try {
27
+ nodeOptions ??= {};
28
+ const serverInfo = {
29
+ name: nodeOptions?.serverName ?? "TWIN Node Server",
30
+ version: nodeOptions?.serverVersion ?? "0.0.3-next.10" // x-release-please-version
31
+ };
32
+ CLIDisplay.header(serverInfo.name, serverInfo.version, "🌩️ ");
33
+ if (!Is.stringValue(nodeOptions?.executionDirectory)) {
34
+ nodeOptions.executionDirectory = getExecutionDirectory();
35
+ }
36
+ nodeOptions.localesDirectory =
37
+ nodeOptions?.localesDirectory ??
38
+ path.resolve(path.join(nodeOptions.executionDirectory, "dist", "locales"));
39
+ await initialiseLocales(nodeOptions.localesDirectory);
40
+ nodeOptions.envPrefix ??= "TWIN_";
41
+ CLIDisplay.value("Environment Variable Prefix", nodeOptions.envPrefix);
42
+ overrideModuleImport(nodeOptions.executionDirectory ?? "");
43
+ // This is the only location in the code base that should access process.env directly
44
+ // So we can safely disable the linting rule here.
45
+ let finalEnvVars =
46
+ // eslint-disable-next-line no-restricted-syntax
47
+ process.env;
48
+ if (Is.objectValue(nodeOptions?.envVars)) {
49
+ finalEnvVars = {
50
+ ...finalEnvVars,
51
+ ...nodeOptions.envVars
52
+ };
53
+ }
54
+ finalEnvVars = {
55
+ ...getEnvDefaults(nodeOptions.envPrefix),
56
+ ...finalEnvVars
57
+ };
58
+ const cliCommand = initCli(finalEnvVars, args);
59
+ if (cliCommand) {
60
+ finalEnvVars[`${nodeOptions.envPrefix}SILENT`] ??= "true";
61
+ }
62
+ else {
63
+ CLIDisplay.value("Execution Directory", nodeOptions.executionDirectory);
64
+ CLIDisplay.value("Locales Directory", nodeOptions.localesDirectory);
65
+ if (Is.empty(nodeOptions?.openApiSpecFile)) {
66
+ const specFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "docs", "open-api", "spec.json"));
67
+ if (await fileExists(specFile)) {
68
+ nodeOptions ??= {};
69
+ nodeOptions.openApiSpecFile = specFile;
70
+ }
71
+ }
72
+ if (Is.stringValue(nodeOptions.openApiSpecFile)) {
73
+ CLIDisplay.value("OpenAPI Spec File", nodeOptions.openApiSpecFile);
74
+ }
75
+ if (Is.empty(nodeOptions?.favIconFile)) {
76
+ const favIconFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "static", "favicon.png"));
77
+ if (await fileExists(favIconFile)) {
78
+ nodeOptions ??= {};
79
+ nodeOptions.favIconFile = favIconFile;
80
+ }
81
+ }
82
+ if (Is.stringValue(nodeOptions.favIconFile)) {
83
+ CLIDisplay.value("Favicon File", nodeOptions.favIconFile);
84
+ }
85
+ }
86
+ const { nodeEngineConfig, nodeEnvVars, availableContextIdKeys } = await buildConfiguration(finalEnvVars, nodeOptions, serverInfo);
87
+ isSilent = Coerce.boolean(nodeEnvVars.silent) ?? false;
88
+ CLIDisplay.break();
89
+ const startResult = await start(nodeOptions, nodeEngineConfig, nodeEnvVars, cliCommand, availableContextIdKeys);
90
+ if (!Is.empty(startResult)) {
91
+ for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
92
+ process.on(signal, async () => {
93
+ CLIDisplay.value("Terminate Signal", signal);
94
+ await startResult.shutdown();
95
+ process.exit(0);
96
+ });
97
+ }
98
+ }
99
+ return startResult;
100
+ }
101
+ catch (err) {
102
+ if (nodeOptions?.disableProcessExitOnFailure ?? false) {
103
+ throw err;
104
+ }
105
+ if (isSilent) {
106
+ const baseError = BaseError.fromError(err);
107
+ if (baseError.source === "node") {
108
+ ObjectHelper.propertyDelete(err, "stack");
109
+ }
110
+ CLIDisplay.error(err);
111
+ }
112
+ // eslint-disable-next-line unicorn/no-process-exit
113
+ process.exit(1);
114
+ }
115
+ }
116
+ /**
117
+ * Build the configuration for the TWIN Node server.
118
+ * @param processEnv The environment variables from the process.
119
+ * @param options The options for running the server.
120
+ * @param serverInfo The server information.
121
+ * @returns A promise that resolves to the engine server configuration, environment prefix, environment variables,
122
+ * and options.
123
+ */
124
+ export async function buildConfiguration(processEnv, options, serverInfo) {
125
+ const availableContextIdKeys = [];
126
+ let defaultEnvOnly = false;
127
+ if (Is.empty(options?.envFilenames)) {
128
+ const envFile = path.resolve(path.join(options.executionDirectory ?? "", ".env"));
129
+ CLIDisplay.value("Default Environment File", envFile);
130
+ options ??= {};
131
+ options.envFilenames = [envFile];
132
+ defaultEnvOnly = true;
133
+ }
134
+ if (Is.arrayValue(options?.envFilenames)) {
135
+ const output = dotenv.config({
136
+ path: options?.envFilenames,
137
+ quiet: true
138
+ });
139
+ // We don't want to throw an error if the default environment file is not found.
140
+ // Only if we have custom environment files.
141
+ if (!defaultEnvOnly && output.error) {
142
+ throw output.error;
143
+ }
144
+ if (Is.objectValue(output.parsed)) {
145
+ Object.assign(processEnv, output.parsed);
146
+ }
147
+ }
148
+ const envVars = EnvHelper.envToJson(processEnv, options.envPrefix ?? "");
149
+ // Expand any environment variables that use the @file: syntax
150
+ const keys = Object.keys(envVars);
151
+ for (const key of keys) {
152
+ if (Is.stringValue(envVars[key]) &&
153
+ (envVars[key].startsWith("@text:") || envVars[key].startsWith("@json:"))) {
154
+ const filePath = envVars[key].slice(6).trim();
155
+ const embeddedFile = path.resolve(path.join(options.executionDirectory ?? "", filePath));
156
+ if (envVars[key].startsWith("@text:")) {
157
+ CLIDisplay.value(`Expanding Environment Variable: ${key} from text file`, embeddedFile);
158
+ envVars[key] = await loadTextFile(embeddedFile);
159
+ }
160
+ else if (envVars[key].startsWith("@json:")) {
161
+ CLIDisplay.value(`Expanding Environment Variable: ${key} from JSON file`, embeddedFile);
162
+ envVars[key] = await loadJsonFile(embeddedFile);
163
+ }
164
+ }
165
+ }
166
+ // Extend the environment variables with any additional custom configuration.
167
+ if (Is.function(options?.extendEnvVars)) {
168
+ CLIDisplay.task("Extending Environment Variables");
169
+ await options.extendEnvVars(envVars);
170
+ }
171
+ // Build the engine configuration from the environment variables.
172
+ const coreConfig = await buildEngineConfiguration(envVars, availableContextIdKeys);
173
+ const engineServerConfig = await buildEngineServerConfiguration(envVars, availableContextIdKeys, coreConfig, serverInfo, options?.openApiSpecFile, options?.favIconFile);
174
+ // Merge any custom configuration provided in the options.
175
+ if (Is.arrayValue(options?.configFilenames)) {
176
+ for (const configFile of options.configFilenames) {
177
+ CLIDisplay.value("Loading Configuration File", configFile);
178
+ const configFilePath = path.resolve(path.join(options.executionDirectory ?? "", configFile));
179
+ const config = await loadJsonFile(configFilePath);
180
+ Object.assign(engineServerConfig, config);
181
+ }
182
+ }
183
+ if (Is.objectValue(options?.config)) {
184
+ CLIDisplay.task("Merging Custom Configuration");
185
+ Object.assign(engineServerConfig, options.config);
186
+ }
187
+ // Merge any custom configuration provided in the options.
188
+ if (Is.function(options?.extendConfig)) {
189
+ CLIDisplay.task("Extending Configuration");
190
+ await options.extendConfig(envVars, engineServerConfig);
191
+ }
192
+ const nodeEngineConfig = await extensionsConfiguration(envVars, engineServerConfig);
193
+ return { nodeEngineConfig, nodeEnvVars: envVars, availableContextIdKeys };
194
+ }
195
+ /**
196
+ * Override module imports to support protocol-based loading (npm:, https:) and local files.
197
+ * @param executionDirectory The execution directory for resolving local module paths.
198
+ * @param envVars The environment variables containing extension configuration (optional, uses defaults if not provided).
199
+ */
200
+ export function overrideModuleImport(executionDirectory, envVars) {
201
+ const maxSizeMb = Coerce.number(envVars?.extensionsMaxSizeMb) ?? 10;
202
+ const cacheDirectory = envVars?.extensionsCacheDirectory;
203
+ ModuleHelper.overrideImport(async (moduleName) => {
204
+ if (moduleCache[moduleName]) {
205
+ return {
206
+ module: moduleCache[moduleName],
207
+ useDefault: false
208
+ };
209
+ }
210
+ const parsed = parseModuleProtocol(moduleName);
211
+ let resolvedPath;
212
+ switch (parsed.protocol) {
213
+ case ModuleProtocol.Npm: {
214
+ const result = await handleNpmProtocol(parsed.identifier, executionDirectory, cacheDirectory);
215
+ resolvedPath = result.resolvedPath;
216
+ break;
217
+ }
218
+ case ModuleProtocol.Https: {
219
+ const result = await handleHttpsProtocol(parsed.identifier, executionDirectory, maxSizeMb, cacheDirectory, envVars?.extensionsCacheTtlHours, envVars?.extensionsForceRefresh);
220
+ resolvedPath = result.resolvedPath;
221
+ break;
222
+ }
223
+ case ModuleProtocol.Http: {
224
+ throw new GeneralError("node", "insecureProtocol", { protocol: ModuleProtocol.Http });
225
+ }
226
+ case ModuleProtocol.Local: {
227
+ let localFilename = path.resolve(moduleName);
228
+ let exists = await fileExists(localFilename);
229
+ if (!exists) {
230
+ localFilename = path.resolve(executionDirectory, moduleName);
231
+ exists = await fileExists(localFilename);
232
+ }
233
+ if (exists) {
234
+ resolvedPath = localFilename;
235
+ }
236
+ break;
237
+ }
238
+ case ModuleProtocol.Default: {
239
+ try {
240
+ const npmRoot = execSync("npm root").toString().trim().replace(/\\/g, "/");
241
+ const packagePath = path.resolve(npmRoot, moduleName);
242
+ const mainFile = await resolvePackageEntryPoint(packagePath, moduleName);
243
+ const modulePath = path.resolve(packagePath, mainFile);
244
+ const exists = await fileExists(modulePath);
245
+ if (exists) {
246
+ resolvedPath = modulePath;
247
+ break;
248
+ }
249
+ }
250
+ catch {
251
+ // Continue to fallback resolution
252
+ }
253
+ // Fallback: resolve from npm protocol cache directory (installed via handleNpmProtocol)
254
+ try {
255
+ const cacheNpmRoot = path.resolve(getExtensionsCacheDir(executionDirectory, ModuleProtocol.Npm, cacheDirectory), "node_modules");
256
+ const packagePath = path.resolve(cacheNpmRoot, moduleName);
257
+ const mainFile = await resolvePackageEntryPoint(packagePath, moduleName);
258
+ const modulePath = path.resolve(packagePath, mainFile);
259
+ const exists = await fileExists(modulePath);
260
+ if (exists) {
261
+ resolvedPath = modulePath;
262
+ }
263
+ }
264
+ catch {
265
+ // No cached resolution either; fall through
266
+ }
267
+ break;
268
+ }
269
+ }
270
+ // Common module loading and caching logic
271
+ if (resolvedPath) {
272
+ const module = await import(createModuleImportUrl(resolvedPath));
273
+ moduleCache[moduleName] = module;
274
+ return {
275
+ module,
276
+ useDefault: false
277
+ };
278
+ }
279
+ return {
280
+ module: undefined,
281
+ useDefault: true
282
+ };
283
+ });
284
+ }
285
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/node.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport type { IServerInfo } from \"@twin.org/api-models\";\nimport { CLIDisplay } from \"@twin.org/cli-core\";\nimport { BaseError, Coerce, EnvHelper, GeneralError, Is, ObjectHelper } from \"@twin.org/core\";\nimport type { Engine } from \"@twin.org/engine\";\nimport type { EngineServer } from \"@twin.org/engine-server\";\nimport type { IEngineServerConfig } from \"@twin.org/engine-server-types\";\nimport { ModuleHelper } from \"@twin.org/modules\";\nimport * as dotenv from \"dotenv\";\nimport { buildEngineConfiguration } from \"./builders/engineEnvBuilder.js\";\nimport { buildEngineServerConfiguration } from \"./builders/engineServerEnvBuilder.js\";\nimport { extensionsConfiguration } from \"./builders/extensionsBuilder.js\";\nimport { initCli } from \"./cli.js\";\nimport { getEnvDefaults } from \"./defaults.js\";\nimport type { INodeEngineConfig } from \"./models/INodeEngineConfig.js\";\nimport type { INodeEngineState } from \"./models/INodeEngineState.js\";\nimport type { INodeEnvironmentVariables } from \"./models/INodeEnvironmentVariables.js\";\nimport type { INodeOptions } from \"./models/INodeOptions.js\";\nimport { ModuleProtocol } from \"./models/moduleProtocol.js\";\nimport { start } from \"./start.js\";\nimport {\n\tcreateModuleImportUrl,\n\tfileExists,\n\tgetExecutionDirectory,\n\tgetExtensionsCacheDir,\n\thandleHttpsProtocol,\n\thandleNpmProtocol,\n\tinitialiseLocales,\n\tloadJsonFile,\n\tloadTextFile,\n\tparseModuleProtocol,\n\tresolvePackageEntryPoint\n} from \"./utils.js\";\n\nconst moduleCache: { [id: string]: unknown } = {};\n\n/**\n * Run the TWIN Node server.\n * @param nodeOptions Optional configuration options for running the server.\n * @param args Optional command line arguments.\n * @returns A promise that resolves when the server is started containing a shutdown method.\n */\nexport async function run(\n\tnodeOptions?: INodeOptions,\n\targs?: string[]\n): Promise<\n\t| {\n\t\t\tengine: Engine<IEngineServerConfig, INodeEngineState>;\n\t\t\tserver: EngineServer;\n\t\t\tshutdown: () => Promise<void>;\n\t }\n\t| undefined\n> {\n\tlet isSilent = true;\n\ttry {\n\t\tnodeOptions ??= {};\n\n\t\tconst serverInfo: IServerInfo = {\n\t\t\tname: nodeOptions?.serverName ?? \"TWIN Node Server\",\n\t\t\tversion: nodeOptions?.serverVersion ?? \"0.0.3-next.10\" // x-release-please-version\n\t\t};\n\n\t\tCLIDisplay.header(serverInfo.name, serverInfo.version, \"🌩️ \");\n\n\t\tif (!Is.stringValue(nodeOptions?.executionDirectory)) {\n\t\t\tnodeOptions.executionDirectory = getExecutionDirectory();\n\t\t}\n\n\t\tnodeOptions.localesDirectory =\n\t\t\tnodeOptions?.localesDirectory ??\n\t\t\tpath.resolve(path.join(nodeOptions.executionDirectory, \"dist\", \"locales\"));\n\n\t\tawait initialiseLocales(nodeOptions.localesDirectory);\n\n\t\tnodeOptions.envPrefix ??= \"TWIN_\";\n\t\tCLIDisplay.value(\"Environment Variable Prefix\", nodeOptions.envPrefix);\n\n\t\toverrideModuleImport(nodeOptions.executionDirectory ?? \"\");\n\n\t\t// This is the only location in the code base that should access process.env directly\n\t\t// So we can safely disable the linting rule here.\n\t\tlet finalEnvVars =\n\t\t\t// eslint-disable-next-line no-restricted-syntax\n\t\t\tprocess.env as {\n\t\t\t\t[id: string]: string;\n\t\t\t};\n\n\t\tif (Is.objectValue(nodeOptions?.envVars)) {\n\t\t\tfinalEnvVars = {\n\t\t\t\t...finalEnvVars,\n\t\t\t\t...nodeOptions.envVars\n\t\t\t};\n\t\t}\n\n\t\tfinalEnvVars = {\n\t\t\t...getEnvDefaults(nodeOptions.envPrefix),\n\t\t\t...finalEnvVars\n\t\t};\n\n\t\tconst cliCommand = initCli(finalEnvVars, args);\n\n\t\tif (cliCommand) {\n\t\t\tfinalEnvVars[`${nodeOptions.envPrefix}SILENT`] ??= \"true\";\n\t\t} else {\n\t\t\tCLIDisplay.value(\"Execution Directory\", nodeOptions.executionDirectory);\n\t\t\tCLIDisplay.value(\"Locales Directory\", nodeOptions.localesDirectory);\n\n\t\t\tif (Is.empty(nodeOptions?.openApiSpecFile)) {\n\t\t\t\tconst specFile = path.resolve(\n\t\t\t\t\tpath.join(nodeOptions.executionDirectory ?? \"\", \"docs\", \"open-api\", \"spec.json\")\n\t\t\t\t);\n\t\t\t\tif (await fileExists(specFile)) {\n\t\t\t\t\tnodeOptions ??= {};\n\t\t\t\t\tnodeOptions.openApiSpecFile = specFile;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Is.stringValue(nodeOptions.openApiSpecFile)) {\n\t\t\t\tCLIDisplay.value(\"OpenAPI Spec File\", nodeOptions.openApiSpecFile);\n\t\t\t}\n\n\t\t\tif (Is.empty(nodeOptions?.favIconFile)) {\n\t\t\t\tconst favIconFile = path.resolve(\n\t\t\t\t\tpath.join(nodeOptions.executionDirectory ?? \"\", \"static\", \"favicon.png\")\n\t\t\t\t);\n\t\t\t\tif (await fileExists(favIconFile)) {\n\t\t\t\t\tnodeOptions ??= {};\n\t\t\t\t\tnodeOptions.favIconFile = favIconFile;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Is.stringValue(nodeOptions.favIconFile)) {\n\t\t\t\tCLIDisplay.value(\"Favicon File\", nodeOptions.favIconFile);\n\t\t\t}\n\t\t}\n\n\t\tconst { nodeEngineConfig, nodeEnvVars, availableContextIdKeys } = await buildConfiguration(\n\t\t\tfinalEnvVars,\n\t\t\tnodeOptions,\n\t\t\tserverInfo\n\t\t);\n\n\t\tisSilent = Coerce.boolean(nodeEnvVars.silent) ?? false;\n\n\t\tCLIDisplay.break();\n\n\t\tconst startResult = await start(\n\t\t\tnodeOptions,\n\t\t\tnodeEngineConfig,\n\t\t\tnodeEnvVars,\n\t\t\tcliCommand,\n\t\t\tavailableContextIdKeys\n\t\t);\n\n\t\tif (!Is.empty(startResult)) {\n\t\t\tfor (const signal of [\"SIGHUP\", \"SIGINT\", \"SIGTERM\"]) {\n\t\t\t\tprocess.on(signal, async () => {\n\t\t\t\t\tCLIDisplay.value(\"Terminate Signal\", signal);\n\t\t\t\t\tawait startResult.shutdown();\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn startResult;\n\t} catch (err) {\n\t\tif (nodeOptions?.disableProcessExitOnFailure ?? false) {\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (isSilent) {\n\t\t\tconst baseError = BaseError.fromError(err);\n\t\t\tif (baseError.source === \"node\") {\n\t\t\t\tObjectHelper.propertyDelete(err, \"stack\");\n\t\t\t}\n\t\t\tCLIDisplay.error(err);\n\t\t}\n\n\t\t// eslint-disable-next-line unicorn/no-process-exit\n\t\tprocess.exit(1);\n\t}\n}\n\n/**\n * Build the configuration for the TWIN Node server.\n * @param processEnv The environment variables from the process.\n * @param options The options for running the server.\n * @param serverInfo The server information.\n * @returns A promise that resolves to the engine server configuration, environment prefix, environment variables,\n * and options.\n */\nexport async function buildConfiguration(\n\tprocessEnv: {\n\t\t[id: string]: string;\n\t},\n\toptions: INodeOptions,\n\tserverInfo: IServerInfo\n): Promise<{\n\tnodeEnvVars: INodeEnvironmentVariables & { [id: string]: string | unknown };\n\tnodeEngineConfig: INodeEngineConfig;\n\tavailableContextIdKeys: { key: string; requiredHandlerFeatures: string[] }[];\n}> {\n\tconst availableContextIdKeys: { key: string; requiredHandlerFeatures: string[] }[] = [];\n\n\tlet defaultEnvOnly = false;\n\tif (Is.empty(options?.envFilenames)) {\n\t\tconst envFile = path.resolve(path.join(options.executionDirectory ?? \"\", \".env\"));\n\t\tCLIDisplay.value(\"Default Environment File\", envFile);\n\t\toptions ??= {};\n\t\toptions.envFilenames = [envFile];\n\t\tdefaultEnvOnly = true;\n\t}\n\n\tif (Is.arrayValue(options?.envFilenames)) {\n\t\tconst output = dotenv.config({\n\t\t\tpath: options?.envFilenames,\n\t\t\tquiet: true\n\t\t});\n\n\t\t// We don't want to throw an error if the default environment file is not found.\n\t\t// Only if we have custom environment files.\n\t\tif (!defaultEnvOnly && output.error) {\n\t\t\tthrow output.error;\n\t\t}\n\n\t\tif (Is.objectValue(output.parsed)) {\n\t\t\tObject.assign(processEnv, output.parsed);\n\t\t}\n\t}\n\n\tconst envVars = EnvHelper.envToJson<{ [id: string]: string | unknown }>(\n\t\tprocessEnv,\n\t\toptions.envPrefix ?? \"\"\n\t);\n\n\t// Expand any environment variables that use the @file: syntax\n\tconst keys = Object.keys(envVars);\n\tfor (const key of keys) {\n\t\tif (\n\t\t\tIs.stringValue(envVars[key]) &&\n\t\t\t(envVars[key].startsWith(\"@text:\") || envVars[key].startsWith(\"@json:\"))\n\t\t) {\n\t\t\tconst filePath = envVars[key].slice(6).trim();\n\t\t\tconst embeddedFile = path.resolve(path.join(options.executionDirectory ?? \"\", filePath));\n\n\t\t\tif (envVars[key].startsWith(\"@text:\")) {\n\t\t\t\tCLIDisplay.value(`Expanding Environment Variable: ${key} from text file`, embeddedFile);\n\t\t\t\tenvVars[key] = await loadTextFile(embeddedFile);\n\t\t\t} else if (envVars[key].startsWith(\"@json:\")) {\n\t\t\t\tCLIDisplay.value(`Expanding Environment Variable: ${key} from JSON file`, embeddedFile);\n\t\t\t\tenvVars[key] = await loadJsonFile(embeddedFile);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Extend the environment variables with any additional custom configuration.\n\tif (Is.function(options?.extendEnvVars)) {\n\t\tCLIDisplay.task(\"Extending Environment Variables\");\n\t\tawait options.extendEnvVars(envVars);\n\t}\n\n\t// Build the engine configuration from the environment variables.\n\tconst coreConfig = await buildEngineConfiguration(envVars, availableContextIdKeys);\n\tconst engineServerConfig = await buildEngineServerConfiguration(\n\t\tenvVars,\n\t\tavailableContextIdKeys,\n\t\tcoreConfig,\n\t\tserverInfo,\n\t\toptions?.openApiSpecFile,\n\t\toptions?.favIconFile\n\t);\n\n\t// Merge any custom configuration provided in the options.\n\tif (Is.arrayValue(options?.configFilenames)) {\n\t\tfor (const configFile of options.configFilenames) {\n\t\t\tCLIDisplay.value(\"Loading Configuration File\", configFile);\n\t\t\tconst configFilePath = path.resolve(path.join(options.executionDirectory ?? \"\", configFile));\n\t\t\tconst config = await loadJsonFile(configFilePath);\n\t\t\tObject.assign(engineServerConfig, config);\n\t\t}\n\t}\n\n\tif (Is.objectValue(options?.config)) {\n\t\tCLIDisplay.task(\"Merging Custom Configuration\");\n\t\tObject.assign(engineServerConfig, options.config);\n\t}\n\n\t// Merge any custom configuration provided in the options.\n\tif (Is.function(options?.extendConfig)) {\n\t\tCLIDisplay.task(\"Extending Configuration\");\n\t\tawait options.extendConfig(envVars, engineServerConfig);\n\t}\n\n\tconst nodeEngineConfig = await extensionsConfiguration(envVars, engineServerConfig);\n\n\treturn { nodeEngineConfig, nodeEnvVars: envVars, availableContextIdKeys };\n}\n\n/**\n * Override module imports to support protocol-based loading (npm:, https:) and local files.\n * @param executionDirectory The execution directory for resolving local module paths.\n * @param envVars The environment variables containing extension configuration (optional, uses defaults if not provided).\n */\nexport function overrideModuleImport(\n\texecutionDirectory: string,\n\tenvVars?: INodeEnvironmentVariables\n): void {\n\tconst maxSizeMb = Coerce.number(envVars?.extensionsMaxSizeMb) ?? 10;\n\tconst cacheDirectory = envVars?.extensionsCacheDirectory;\n\n\tModuleHelper.overrideImport(async moduleName => {\n\t\tif (moduleCache[moduleName]) {\n\t\t\treturn {\n\t\t\t\tmodule: moduleCache[moduleName],\n\t\t\t\tuseDefault: false\n\t\t\t};\n\t\t}\n\n\t\tconst parsed = parseModuleProtocol(moduleName);\n\t\tlet resolvedPath: string | undefined;\n\n\t\tswitch (parsed.protocol) {\n\t\t\tcase ModuleProtocol.Npm: {\n\t\t\t\tconst result = await handleNpmProtocol(\n\t\t\t\t\tparsed.identifier,\n\t\t\t\t\texecutionDirectory,\n\t\t\t\t\tcacheDirectory\n\t\t\t\t);\n\t\t\t\tresolvedPath = result.resolvedPath;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase ModuleProtocol.Https: {\n\t\t\t\tconst result = await handleHttpsProtocol(\n\t\t\t\t\tparsed.identifier,\n\t\t\t\t\texecutionDirectory,\n\t\t\t\t\tmaxSizeMb,\n\t\t\t\t\tcacheDirectory,\n\t\t\t\t\tenvVars?.extensionsCacheTtlHours,\n\t\t\t\t\tenvVars?.extensionsForceRefresh\n\t\t\t\t);\n\t\t\t\tresolvedPath = result.resolvedPath;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase ModuleProtocol.Http: {\n\t\t\t\tthrow new GeneralError(\"node\", \"insecureProtocol\", { protocol: ModuleProtocol.Http });\n\t\t\t}\n\n\t\t\tcase ModuleProtocol.Local: {\n\t\t\t\tlet localFilename = path.resolve(moduleName);\n\n\t\t\t\tlet exists = await fileExists(localFilename);\n\t\t\t\tif (!exists) {\n\t\t\t\t\tlocalFilename = path.resolve(executionDirectory, moduleName);\n\t\t\t\t\texists = await fileExists(localFilename);\n\t\t\t\t}\n\n\t\t\t\tif (exists) {\n\t\t\t\t\tresolvedPath = localFilename;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase ModuleProtocol.Default: {\n\t\t\t\ttry {\n\t\t\t\t\tconst npmRoot = execSync(\"npm root\").toString().trim().replace(/\\\\/g, \"/\");\n\t\t\t\t\tconst packagePath = path.resolve(npmRoot, moduleName);\n\t\t\t\t\tconst mainFile = await resolvePackageEntryPoint(packagePath, moduleName);\n\t\t\t\t\tconst modulePath = path.resolve(packagePath, mainFile);\n\t\t\t\t\tconst exists = await fileExists(modulePath);\n\t\t\t\t\tif (exists) {\n\t\t\t\t\t\tresolvedPath = modulePath;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Continue to fallback resolution\n\t\t\t\t}\n\n\t\t\t\t// Fallback: resolve from npm protocol cache directory (installed via handleNpmProtocol)\n\t\t\t\ttry {\n\t\t\t\t\tconst cacheNpmRoot = path.resolve(\n\t\t\t\t\t\tgetExtensionsCacheDir(executionDirectory, ModuleProtocol.Npm, cacheDirectory),\n\t\t\t\t\t\t\"node_modules\"\n\t\t\t\t\t);\n\n\t\t\t\t\tconst packagePath = path.resolve(cacheNpmRoot, moduleName);\n\t\t\t\t\tconst mainFile = await resolvePackageEntryPoint(packagePath, moduleName);\n\t\t\t\t\tconst modulePath = path.resolve(packagePath, mainFile);\n\t\t\t\t\tconst exists = await fileExists(modulePath);\n\t\t\t\t\tif (exists) {\n\t\t\t\t\t\tresolvedPath = modulePath;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// No cached resolution either; fall through\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Common module loading and caching logic\n\t\tif (resolvedPath) {\n\t\t\tconst module = await import(createModuleImportUrl(resolvedPath));\n\t\t\tmoduleCache[moduleName] = module;\n\t\t\treturn {\n\t\t\t\tmodule,\n\t\t\t\tuseDefault: false\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tmodule: undefined,\n\t\t\tuseDefault: true\n\t\t};\n\t});\n}\n"]}
@@ -0,0 +1,128 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { ContextIdKeys } from "@twin.org/context";
4
+ import { Coerce, GeneralError, I18n, Is } from "@twin.org/core";
5
+ import { Engine } from "@twin.org/engine";
6
+ import { FileStateStorage } from "@twin.org/engine-core";
7
+ import { EngineCoreFactory } from "@twin.org/engine-models";
8
+ import { EngineServer } from "@twin.org/engine-server";
9
+ import { BlobStorageConnectorType, EntityStorageConnectorType } from "@twin.org/engine-types";
10
+ import { extensionsInitialiseEngine, extensionsInitialiseEngineServer, shutdownExtensions } from "./builders/extensionsBuilder.js";
11
+ import { executeCommand } from "./cli.js";
12
+ /**
13
+ * Start the engine server.
14
+ * @param nodeOptions Optional run options for the engine server.
15
+ * @param nodeEngineConfig The configuration for the engine server.
16
+ * @param envVars The environment variables.
17
+ * @param cliCommand The constructed CLI command (optional).
18
+ * @param availableContextIdKeys The context ID keys available for operation.
19
+ * @returns The engine server.
20
+ */
21
+ export async function start(nodeOptions, nodeEngineConfig, envVars, cliCommand, availableContextIdKeys) {
22
+ const entityStorageConnectorType = envVars.entityStorageConnectorType?.split(",") ?? [];
23
+ const blobStorageConnectorType = envVars.blobStorageConnectorType?.split(",") ?? [];
24
+ // If the blob storage or entity storage is configured with file connectors
25
+ // then we need to make sure the storageFileRoot is set
26
+ if ((entityStorageConnectorType.includes(EntityStorageConnectorType.File) ||
27
+ blobStorageConnectorType.includes(BlobStorageConnectorType.File) ||
28
+ Is.empty(nodeOptions?.stateStorage)) &&
29
+ !Is.stringValue(envVars.storageFileRoot)) {
30
+ throw new GeneralError("node", "storageFileRootNotSet", {
31
+ storageFileRoot: `${nodeOptions?.envPrefix ?? ""}STORAGE_FILE_ROOT`
32
+ });
33
+ }
34
+ // Create the engine instance using file state storage unless one is configured in options
35
+ const engine = new Engine({
36
+ config: nodeEngineConfig,
37
+ stateStorage: nodeOptions?.stateStorage ?? new FileStateStorage(envVars.stateFilename ?? ""),
38
+ customBootstrap: async (engineCore, context) => {
39
+ const requiresEngineStarted = cliCommand?.definition?.requiresEngineStarted ?? true;
40
+ const requiresNodeIdentity = cliCommand?.definition?.requiresNodeIdentity ?? true;
41
+ const requiresTenantId = cliCommand?.definition?.requiresTenantId ?? true;
42
+ configureContextIds(engineCore, envVars, requiresEngineStarted, requiresNodeIdentity, requiresTenantId, availableContextIdKeys);
43
+ }
44
+ });
45
+ // Construct the server with the engine.
46
+ const server = new EngineServer({ engineCore: engine });
47
+ // Extend the engine.
48
+ if (Is.function(nodeOptions?.extendEngine)) {
49
+ await engine.logInfo(I18n.formatMessage("node.extendingEngine"));
50
+ await nodeOptions.extendEngine(engine);
51
+ }
52
+ await extensionsInitialiseEngine(envVars, engine);
53
+ // Extend the engine server.
54
+ if (Is.function(nodeOptions?.extendEngineServer)) {
55
+ await engine.logInfo(I18n.formatMessage("node.extendingEngineServer"));
56
+ await nodeOptions?.extendEngineServer(server);
57
+ }
58
+ await extensionsInitialiseEngineServer(envVars, engine, server);
59
+ // Need to register the engine with the factory so that background tasks
60
+ // can clone it to spawn new instances.
61
+ EngineCoreFactory.register("engine", () => engine);
62
+ if (Is.objectValue(cliCommand)) {
63
+ await executeCommand(engine, envVars, cliCommand);
64
+ }
65
+ else {
66
+ try {
67
+ // Start the server, which also starts the engine.
68
+ await server.start();
69
+ return {
70
+ engine,
71
+ server,
72
+ shutdown: async () => {
73
+ await shutdownExtensions(envVars, engine);
74
+ await server.stop();
75
+ }
76
+ };
77
+ }
78
+ catch (err) {
79
+ await shutdownExtensions(envVars, engine);
80
+ throw err;
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Configure the context IDs for the engine.
86
+ * @param engine The engine to configure.
87
+ * @param envVars The environment variables.
88
+ * @param requiresEngineStarted Whether the engine is required to be started.
89
+ * @param requiresNodeIdentity Whether the node identity is required.
90
+ * @param requiresTenantId Whether the tenant id is required.
91
+ * @param availableContextIdKeys The available context ID keys.
92
+ * @throws GeneralError Throws if the node identity or tenant is required but not set.
93
+ */
94
+ function configureContextIds(engine, envVars, requiresEngineStarted, requiresNodeIdentity, requiresTenantId, availableContextIdKeys) {
95
+ const state = engine.getState();
96
+ if (requiresEngineStarted && requiresNodeIdentity) {
97
+ const nodeIdentityEnabled = Coerce.boolean(envVars.nodeIdentityEnabled) ?? true;
98
+ if (nodeIdentityEnabled) {
99
+ if (Is.stringValue(state.nodeId)) {
100
+ engine.addContextId(ContextIdKeys.Node, state.nodeId);
101
+ }
102
+ else {
103
+ throw new GeneralError("node", "nodeIdentityNotSet");
104
+ }
105
+ }
106
+ }
107
+ if (requiresEngineStarted && requiresTenantId) {
108
+ const tenantEnabled = Coerce.boolean(envVars.tenantEnabled) ?? false;
109
+ if (tenantEnabled) {
110
+ if (Is.stringValue(state.nodeTenantId)) {
111
+ engine.addContextId(ContextIdKeys.Tenant, state.nodeTenantId);
112
+ }
113
+ else {
114
+ throw new GeneralError("node", "nodeTenantNotSet");
115
+ }
116
+ }
117
+ }
118
+ if (Is.arrayValue(availableContextIdKeys)) {
119
+ const added = [];
120
+ for (const availableContextIdKey of availableContextIdKeys) {
121
+ if (!added.includes(availableContextIdKey.key)) {
122
+ engine.addContextIdKey(availableContextIdKey.key, availableContextIdKey.requiredHandlerFeatures);
123
+ added.push(availableContextIdKey.key);
124
+ }
125
+ }
126
+ }
127
+ }
128
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/start.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EACN,iBAAiB,EAGjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAC9F,OAAO,EACN,0BAA0B,EAC1B,gCAAgC,EAChC,kBAAkB,EAClB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAO1C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAC1B,WAAqC,EACrC,gBAAmC,EACnC,OAAkC,EAClC,UAAwB,EACxB,sBAA6E;IAS7E,MAAM,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACxF,MAAM,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAEpF,2EAA2E;IAC3E,uDAAuD;IACvD,IACC,CAAC,0BAA0B,CAAC,QAAQ,CAAC,0BAA0B,CAAC,IAAI,CAAC;QACpE,wBAAwB,CAAC,QAAQ,CAAC,wBAAwB,CAAC,IAAI,CAAC;QAChE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QACrC,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,eAAe,CAAC,EACvC,CAAC;QACF,MAAM,IAAI,YAAY,CAAC,MAAM,EAAE,uBAAuB,EAAE;YACvD,eAAe,EAAE,GAAG,WAAW,EAAE,SAAS,IAAI,EAAE,mBAAmB;SACnE,CAAC,CAAC;IACJ,CAAC;IAED,0FAA0F;IAC1F,MAAM,MAAM,GAAG,IAAI,MAAM,CAAwC;QAChE,MAAM,EAAE,gBAAgB;QACxB,YAAY,EAAE,WAAW,EAAE,YAAY,IAAI,IAAI,gBAAgB,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;QAC5F,eAAe,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE;YAC9C,MAAM,qBAAqB,GAAG,UAAU,EAAE,UAAU,EAAE,qBAAqB,IAAI,IAAI,CAAC;YACpF,MAAM,oBAAoB,GAAG,UAAU,EAAE,UAAU,EAAE,oBAAoB,IAAI,IAAI,CAAC;YAClF,MAAM,gBAAgB,GAAG,UAAU,EAAE,UAAU,EAAE,gBAAgB,IAAI,IAAI,CAAC;YAC1E,mBAAmB,CAClB,UAAU,EACV,OAAO,EACP,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,CACtB,CAAC;QACH,CAAC;KACD,CAAC,CAAC;IAEH,wCAAwC;IACxC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IAExD,qBAAqB;IACrB,IAAI,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,CAAC;QAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACjE,MAAM,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,0BAA0B,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAElD,4BAA4B;IAC5B,IAAI,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC,EAAE,CAAC;QAClD,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,4BAA4B,CAAC,CAAC,CAAC;QACvE,MAAM,WAAW,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,gCAAgC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhE,wEAAwE;IACxE,uCAAuC;IACvC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;IAEnD,IAAI,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,MAAM,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACnD,CAAC;SAAM,CAAC;QACP,IAAI,CAAC;YACJ,kDAAkD;YAClD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YAErB,OAAO;gBACN,MAAM;gBACN,MAAM;gBACN,QAAQ,EAAE,KAAK,IAAI,EAAE;oBACpB,MAAM,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBAC1C,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBACrB,CAAC;aACD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1C,MAAM,GAAG,CAAC;QACX,CAAC;IACF,CAAC;AACF,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,mBAAmB,CAC3B,MAAwD,EACxD,OAAkC,EAClC,qBAA8B,EAC9B,oBAA6B,EAC7B,gBAAyB,EACzB,sBAAwF;IAExF,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAEhC,IAAI,qBAAqB,IAAI,oBAAoB,EAAE,CAAC;QACnD,MAAM,mBAAmB,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,IAAI,CAAC;QAChF,IAAI,mBAAmB,EAAE,CAAC;YACzB,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,YAAY,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;YACtD,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,qBAAqB,IAAI,gBAAgB,EAAE,CAAC;QAC/C,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC;QACrE,IAAI,aAAa,EAAE,CAAC;YACnB,IAAI,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;gBACxC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;YAC/D,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,YAAY,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;YACpD,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,EAAE,CAAC,UAAU,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,qBAAqB,IAAI,sBAAsB,EAAE,CAAC;YAC5D,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChD,MAAM,CAAC,eAAe,CACrB,qBAAqB,CAAC,GAAG,EACzB,qBAAqB,CAAC,uBAAuB,CAC7C,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;QACF,CAAC;IACF,CAAC;AACF,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ContextIdKeys } from \"@twin.org/context\";\nimport { Coerce, GeneralError, I18n, Is } from \"@twin.org/core\";\nimport { Engine } from \"@twin.org/engine\";\nimport { FileStateStorage } from \"@twin.org/engine-core\";\nimport {\n\tEngineCoreFactory,\n\ttype IEngineCore,\n\ttype IEngineCoreConfig\n} from \"@twin.org/engine-models\";\nimport { EngineServer } from \"@twin.org/engine-server\";\nimport type { IEngineServerConfig } from \"@twin.org/engine-server-types\";\nimport { BlobStorageConnectorType, EntityStorageConnectorType } from \"@twin.org/engine-types\";\nimport {\n\textensionsInitialiseEngine,\n\textensionsInitialiseEngineServer,\n\tshutdownExtensions\n} from \"./builders/extensionsBuilder.js\";\nimport { executeCommand } from \"./cli.js\";\nimport type { ICliCommand } from \"./models/ICliCommand.js\";\nimport type { INodeEngineConfig } from \"./models/INodeEngineConfig.js\";\nimport type { INodeEngineState } from \"./models/INodeEngineState.js\";\nimport type { INodeEnvironmentVariables } from \"./models/INodeEnvironmentVariables.js\";\nimport type { INodeOptions } from \"./models/INodeOptions.js\";\n\n/**\n * Start the engine server.\n * @param nodeOptions Optional run options for the engine server.\n * @param nodeEngineConfig The configuration for the engine server.\n * @param envVars The environment variables.\n * @param cliCommand The constructed CLI command (optional).\n * @param availableContextIdKeys The context ID keys available for operation.\n * @returns The engine server.\n */\nexport async function start(\n\tnodeOptions: INodeOptions | undefined,\n\tnodeEngineConfig: INodeEngineConfig,\n\tenvVars: INodeEnvironmentVariables,\n\tcliCommand?: ICliCommand,\n\tavailableContextIdKeys?: { key: string; requiredHandlerFeatures: string[] }[]\n): Promise<\n\t| {\n\t\t\tengine: Engine<IEngineServerConfig, INodeEngineState>;\n\t\t\tserver: EngineServer;\n\t\t\tshutdown: () => Promise<void>;\n\t }\n\t| undefined\n> {\n\tconst entityStorageConnectorType = envVars.entityStorageConnectorType?.split(\",\") ?? [];\n\tconst blobStorageConnectorType = envVars.blobStorageConnectorType?.split(\",\") ?? [];\n\n\t// If the blob storage or entity storage is configured with file connectors\n\t// then we need to make sure the storageFileRoot is set\n\tif (\n\t\t(entityStorageConnectorType.includes(EntityStorageConnectorType.File) ||\n\t\t\tblobStorageConnectorType.includes(BlobStorageConnectorType.File) ||\n\t\t\tIs.empty(nodeOptions?.stateStorage)) &&\n\t\t!Is.stringValue(envVars.storageFileRoot)\n\t) {\n\t\tthrow new GeneralError(\"node\", \"storageFileRootNotSet\", {\n\t\t\tstorageFileRoot: `${nodeOptions?.envPrefix ?? \"\"}STORAGE_FILE_ROOT`\n\t\t});\n\t}\n\n\t// Create the engine instance using file state storage unless one is configured in options\n\tconst engine = new Engine<IEngineServerConfig, INodeEngineState>({\n\t\tconfig: nodeEngineConfig,\n\t\tstateStorage: nodeOptions?.stateStorage ?? new FileStateStorage(envVars.stateFilename ?? \"\"),\n\t\tcustomBootstrap: async (engineCore, context) => {\n\t\t\tconst requiresEngineStarted = cliCommand?.definition?.requiresEngineStarted ?? true;\n\t\t\tconst requiresNodeIdentity = cliCommand?.definition?.requiresNodeIdentity ?? true;\n\t\t\tconst requiresTenantId = cliCommand?.definition?.requiresTenantId ?? true;\n\t\t\tconfigureContextIds(\n\t\t\t\tengineCore,\n\t\t\t\tenvVars,\n\t\t\t\trequiresEngineStarted,\n\t\t\t\trequiresNodeIdentity,\n\t\t\t\trequiresTenantId,\n\t\t\t\tavailableContextIdKeys\n\t\t\t);\n\t\t}\n\t});\n\n\t// Construct the server with the engine.\n\tconst server = new EngineServer({ engineCore: engine });\n\n\t// Extend the engine.\n\tif (Is.function(nodeOptions?.extendEngine)) {\n\t\tawait engine.logInfo(I18n.formatMessage(\"node.extendingEngine\"));\n\t\tawait nodeOptions.extendEngine(engine);\n\t}\n\n\tawait extensionsInitialiseEngine(envVars, engine);\n\n\t// Extend the engine server.\n\tif (Is.function(nodeOptions?.extendEngineServer)) {\n\t\tawait engine.logInfo(I18n.formatMessage(\"node.extendingEngineServer\"));\n\t\tawait nodeOptions?.extendEngineServer(server);\n\t}\n\n\tawait extensionsInitialiseEngineServer(envVars, engine, server);\n\n\t// Need to register the engine with the factory so that background tasks\n\t// can clone it to spawn new instances.\n\tEngineCoreFactory.register(\"engine\", () => engine);\n\n\tif (Is.objectValue(cliCommand)) {\n\t\tawait executeCommand(engine, envVars, cliCommand);\n\t} else {\n\t\ttry {\n\t\t\t// Start the server, which also starts the engine.\n\t\t\tawait server.start();\n\n\t\t\treturn {\n\t\t\t\tengine,\n\t\t\t\tserver,\n\t\t\t\tshutdown: async () => {\n\t\t\t\t\tawait shutdownExtensions(envVars, engine);\n\t\t\t\t\tawait server.stop();\n\t\t\t\t}\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tawait shutdownExtensions(envVars, engine);\n\t\t\tthrow err;\n\t\t}\n\t}\n}\n\n/**\n * Configure the context IDs for the engine.\n * @param engine The engine to configure.\n * @param envVars The environment variables.\n * @param requiresEngineStarted Whether the engine is required to be started.\n * @param requiresNodeIdentity Whether the node identity is required.\n * @param requiresTenantId Whether the tenant id is required.\n * @param availableContextIdKeys The available context ID keys.\n * @throws GeneralError Throws if the node identity or tenant is required but not set.\n */\nfunction configureContextIds(\n\tengine: IEngineCore<IEngineCoreConfig, INodeEngineState>,\n\tenvVars: INodeEnvironmentVariables,\n\trequiresEngineStarted: boolean,\n\trequiresNodeIdentity: boolean,\n\trequiresTenantId: boolean,\n\tavailableContextIdKeys: { key: string; requiredHandlerFeatures: string[] }[] | undefined\n): void {\n\tconst state = engine.getState();\n\n\tif (requiresEngineStarted && requiresNodeIdentity) {\n\t\tconst nodeIdentityEnabled = Coerce.boolean(envVars.nodeIdentityEnabled) ?? true;\n\t\tif (nodeIdentityEnabled) {\n\t\t\tif (Is.stringValue(state.nodeId)) {\n\t\t\t\tengine.addContextId(ContextIdKeys.Node, state.nodeId);\n\t\t\t} else {\n\t\t\t\tthrow new GeneralError(\"node\", \"nodeIdentityNotSet\");\n\t\t\t}\n\t\t}\n\t}\n\n\tif (requiresEngineStarted && requiresTenantId) {\n\t\tconst tenantEnabled = Coerce.boolean(envVars.tenantEnabled) ?? false;\n\t\tif (tenantEnabled) {\n\t\t\tif (Is.stringValue(state.nodeTenantId)) {\n\t\t\t\tengine.addContextId(ContextIdKeys.Tenant, state.nodeTenantId);\n\t\t\t} else {\n\t\t\t\tthrow new GeneralError(\"node\", \"nodeTenantNotSet\");\n\t\t\t}\n\t\t}\n\t}\n\n\tif (Is.arrayValue(availableContextIdKeys)) {\n\t\tconst added: string[] = [];\n\t\tfor (const availableContextIdKey of availableContextIdKeys) {\n\t\t\tif (!added.includes(availableContextIdKey.key)) {\n\t\t\t\tengine.addContextIdKey(\n\t\t\t\t\tavailableContextIdKey.key,\n\t\t\t\t\tavailableContextIdKey.requiredHandlerFeatures\n\t\t\t\t);\n\t\t\t\tadded.push(availableContextIdKey.key);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}