@twin.org/node-core 0.0.3-next.1 → 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 (141) hide show
  1. package/dist/es/builders/engineEnvBuilder.js +155 -74
  2. package/dist/es/builders/engineEnvBuilder.js.map +1 -1
  3. package/dist/es/builders/engineServerEnvBuilder.js +24 -15
  4. package/dist/es/builders/engineServerEnvBuilder.js.map +1 -1
  5. package/dist/es/builders/extensionsBuilder.js +26 -17
  6. package/dist/es/builders/extensionsBuilder.js.map +1 -1
  7. package/dist/es/cli.js +255 -0
  8. package/dist/es/cli.js.map +1 -0
  9. package/dist/es/commands/bootstrapLegacy.js +175 -0
  10. package/dist/es/commands/bootstrapLegacy.js.map +1 -0
  11. package/dist/es/commands/help.js +85 -0
  12. package/dist/es/commands/help.js.map +1 -0
  13. package/dist/es/commands/identityCreate.js +310 -0
  14. package/dist/es/commands/identityCreate.js.map +1 -0
  15. package/dist/es/commands/identityImports.js +76 -0
  16. package/dist/es/commands/identityImports.js.map +1 -0
  17. package/dist/es/commands/identityVerifiableCredentialCreate.js +140 -0
  18. package/dist/es/commands/identityVerifiableCredentialCreate.js.map +1 -0
  19. package/dist/es/commands/identityVerificationMethodCreate.js +208 -0
  20. package/dist/es/commands/identityVerificationMethodCreate.js.map +1 -0
  21. package/dist/es/commands/identityVerificationMethodImport.js +120 -0
  22. package/dist/es/commands/identityVerificationMethodImport.js.map +1 -0
  23. package/dist/es/commands/nodeSetIdentity.js +51 -0
  24. package/dist/es/commands/nodeSetIdentity.js.map +1 -0
  25. package/dist/es/commands/nodeSetTenant.js +49 -0
  26. package/dist/es/commands/nodeSetTenant.js.map +1 -0
  27. package/dist/es/commands/tenantCreate.js +120 -0
  28. package/dist/es/commands/tenantCreate.js.map +1 -0
  29. package/dist/es/commands/tenantImport.js +78 -0
  30. package/dist/es/commands/tenantImport.js.map +1 -0
  31. package/dist/es/commands/userCreate.js +197 -0
  32. package/dist/es/commands/userCreate.js.map +1 -0
  33. package/dist/es/commands/vaultKeyCreate.js +185 -0
  34. package/dist/es/commands/vaultKeyCreate.js.map +1 -0
  35. package/dist/es/commands/vaultKeyImport.js +98 -0
  36. package/dist/es/commands/vaultKeyImport.js.map +1 -0
  37. package/dist/es/defaults.js +20 -1
  38. package/dist/es/defaults.js.map +1 -1
  39. package/dist/es/index.js +7 -3
  40. package/dist/es/index.js.map +1 -1
  41. package/dist/es/models/ICliArgs.js +4 -0
  42. package/dist/es/models/ICliArgs.js.map +1 -0
  43. package/dist/es/models/ICliCommand.js +2 -0
  44. package/dist/es/models/ICliCommand.js.map +1 -0
  45. package/dist/es/models/ICliCommandDefinition.js +2 -0
  46. package/dist/es/models/ICliCommandDefinition.js.map +1 -0
  47. package/dist/es/models/ICliCommandDefinitionParam.js +2 -0
  48. package/dist/es/models/ICliCommandDefinitionParam.js.map +1 -0
  49. package/dist/es/models/IEngineEnvironmentVariables.js.map +1 -1
  50. package/dist/es/models/INodeEngineState.js.map +1 -1
  51. package/dist/es/models/INodeEnvironmentVariables.js.map +1 -1
  52. package/dist/es/models/cliCommandParamType.js +4 -0
  53. package/dist/es/models/cliCommandParamType.js.map +1 -0
  54. package/dist/es/node.js +55 -35
  55. package/dist/es/node.js.map +1 -1
  56. package/dist/es/start.js +128 -0
  57. package/dist/es/start.js.map +1 -0
  58. package/dist/es/utils.js +1 -22
  59. package/dist/es/utils.js.map +1 -1
  60. package/dist/types/builders/engineEnvBuilder.d.ts +4 -1
  61. package/dist/types/builders/engineServerEnvBuilder.d.ts +5 -2
  62. package/dist/types/cli.d.ts +66 -0
  63. package/dist/types/commands/bootstrapLegacy.d.ts +66 -0
  64. package/dist/types/commands/help.d.ts +23 -0
  65. package/dist/types/commands/identityCreate.d.ts +39 -0
  66. package/dist/types/commands/identityImports.d.ts +24 -0
  67. package/dist/types/commands/identityVerifiableCredentialCreate.d.ts +43 -0
  68. package/dist/types/commands/identityVerificationMethodCreate.d.ts +47 -0
  69. package/dist/types/commands/identityVerificationMethodImport.d.ts +31 -0
  70. package/dist/types/commands/nodeSetIdentity.d.ts +22 -0
  71. package/dist/types/commands/nodeSetTenant.d.ts +22 -0
  72. package/dist/types/commands/tenantCreate.d.ts +35 -0
  73. package/dist/types/commands/tenantImport.d.ts +24 -0
  74. package/dist/types/commands/userCreate.d.ts +46 -0
  75. package/dist/types/commands/vaultKeyCreate.d.ts +43 -0
  76. package/dist/types/commands/vaultKeyImport.d.ts +28 -0
  77. package/dist/types/defaults.d.ts +11 -1
  78. package/dist/types/index.d.ts +7 -3
  79. package/dist/types/models/ICliArgs.d.ts +20 -0
  80. package/dist/types/models/ICliCommand.d.ts +17 -0
  81. package/dist/types/models/ICliCommandDefinition.d.ts +46 -0
  82. package/dist/types/models/ICliCommandDefinitionParam.d.ts +35 -0
  83. package/dist/types/models/IEngineEnvironmentVariables.d.ts +51 -42
  84. package/dist/types/models/INodeEngineState.d.ts +0 -8
  85. package/dist/types/models/INodeEnvironmentVariables.d.ts +0 -38
  86. package/dist/types/models/cliCommandParamType.d.ts +4 -0
  87. package/dist/types/node.d.ts +6 -2
  88. package/dist/types/{server.d.ts → start.d.ts} +7 -2
  89. package/dist/types/utils.d.ts +0 -8
  90. package/docs/changelog.md +63 -0
  91. package/docs/reference/functions/buildConfiguration.md +2 -2
  92. package/docs/reference/functions/buildEngineConfiguration.md +1 -1
  93. package/docs/reference/functions/buildEngineServerConfiguration.md +3 -3
  94. package/docs/reference/functions/constructCliCommand.md +27 -0
  95. package/docs/reference/functions/executeCommand.md +29 -0
  96. package/docs/reference/functions/getEnvDefaults.md +19 -0
  97. package/docs/reference/functions/initCli.md +27 -0
  98. package/docs/reference/functions/parseCommandLineArgs.md +19 -0
  99. package/docs/reference/functions/processEnvOptions.md +27 -0
  100. package/docs/reference/functions/registerCommands.md +9 -0
  101. package/docs/reference/functions/run.md +7 -1
  102. package/docs/reference/functions/start.md +10 -4
  103. package/docs/reference/functions/substituteEnvOptions.md +25 -0
  104. package/docs/reference/index.md +15 -12
  105. package/docs/reference/interfaces/ICliArgs.md +35 -0
  106. package/docs/reference/interfaces/ICliCommand.md +23 -0
  107. package/docs/reference/interfaces/ICliCommandDefinition.md +101 -0
  108. package/docs/reference/interfaces/ICliCommandDefinitionParam.md +65 -0
  109. package/docs/reference/interfaces/IEngineEnvironmentVariables.md +90 -65
  110. package/docs/reference/interfaces/IEngineServerEnvironmentVariables.md +129 -88
  111. package/docs/reference/interfaces/INodeEngineState.md +0 -16
  112. package/docs/reference/interfaces/INodeEnvironmentVariables.md +129 -172
  113. package/docs/reference/type-aliases/CliCommandParamType.md +5 -0
  114. package/docs/reference/variables/CONTEXT_ID_HANDLER_FEATURE_DID.md +3 -0
  115. package/docs/reference/variables/CONTEXT_ID_HANDLER_FEATURE_TENANT.md +3 -0
  116. package/docs/reference/variables/VC_AUTHENTICATION_VERIFICATION_METHOD_ID.md +1 -1
  117. package/locales/en.json +463 -30
  118. package/package.json +3 -1
  119. package/dist/es/bootstrap.js +0 -374
  120. package/dist/es/bootstrap.js.map +0 -1
  121. package/dist/es/identity.js +0 -169
  122. package/dist/es/identity.js.map +0 -1
  123. package/dist/es/models/nodeFeatures.js +0 -21
  124. package/dist/es/models/nodeFeatures.js.map +0 -1
  125. package/dist/es/server.js +0 -74
  126. package/dist/es/server.js.map +0 -1
  127. package/dist/types/bootstrap.d.ts +0 -76
  128. package/dist/types/identity.d.ts +0 -14
  129. package/dist/types/models/nodeFeatures.d.ts +0 -21
  130. package/docs/reference/functions/bootstrap.md +0 -29
  131. package/docs/reference/functions/bootstrapAuth.md +0 -35
  132. package/docs/reference/functions/bootstrapBlobEncryption.md +0 -35
  133. package/docs/reference/functions/bootstrapContextIdHandlers.md +0 -35
  134. package/docs/reference/functions/bootstrapImmutableProofMethod.md +0 -35
  135. package/docs/reference/functions/bootstrapNodeAdminUser.md +0 -35
  136. package/docs/reference/functions/bootstrapNodeId.md +0 -35
  137. package/docs/reference/functions/bootstrapSynchronisedStorage.md +0 -35
  138. package/docs/reference/functions/bootstrapTenantId.md +0 -35
  139. package/docs/reference/functions/getFeatures.md +0 -19
  140. package/docs/reference/type-aliases/NodeFeatures.md +0 -5
  141. package/docs/reference/variables/NodeFeatures.md +0 -25
package/dist/es/node.js CHANGED
@@ -3,60 +3,40 @@
3
3
  import { execSync } from "node:child_process";
4
4
  import path from "node:path";
5
5
  import { CLIDisplay } from "@twin.org/cli-core";
6
- import { Coerce, EnvHelper, GeneralError, Is } from "@twin.org/core";
6
+ import { BaseError, Coerce, EnvHelper, GeneralError, Is, ObjectHelper } from "@twin.org/core";
7
7
  import { ModuleHelper } from "@twin.org/modules";
8
8
  import * as dotenv from "dotenv";
9
9
  import { buildEngineConfiguration } from "./builders/engineEnvBuilder.js";
10
10
  import { buildEngineServerConfiguration } from "./builders/engineServerEnvBuilder.js";
11
11
  import { extensionsConfiguration } from "./builders/extensionsBuilder.js";
12
+ import { initCli } from "./cli.js";
13
+ import { getEnvDefaults } from "./defaults.js";
12
14
  import { ModuleProtocol } from "./models/moduleProtocol.js";
13
- import { start } from "./server.js";
15
+ import { start } from "./start.js";
14
16
  import { createModuleImportUrl, fileExists, getExecutionDirectory, getExtensionsCacheDir, handleHttpsProtocol, handleNpmProtocol, initialiseLocales, loadJsonFile, loadTextFile, parseModuleProtocol, resolvePackageEntryPoint } from "./utils.js";
15
17
  const moduleCache = {};
16
18
  /**
17
19
  * Run the TWIN Node server.
18
20
  * @param nodeOptions Optional configuration options for running the server.
21
+ * @param args Optional command line arguments.
19
22
  * @returns A promise that resolves when the server is started containing a shutdown method.
20
23
  */
21
- export async function run(nodeOptions) {
24
+ export async function run(nodeOptions, args) {
25
+ let isSilent = true;
22
26
  try {
23
27
  nodeOptions ??= {};
24
28
  const serverInfo = {
25
29
  name: nodeOptions?.serverName ?? "TWIN Node Server",
26
- version: nodeOptions?.serverVersion ?? "0.0.3-next.0" // x-release-please-version
30
+ version: nodeOptions?.serverVersion ?? "0.0.3-next.10" // x-release-please-version
27
31
  };
28
32
  CLIDisplay.header(serverInfo.name, serverInfo.version, "🌩️ ");
29
33
  if (!Is.stringValue(nodeOptions?.executionDirectory)) {
30
34
  nodeOptions.executionDirectory = getExecutionDirectory();
31
35
  }
32
- CLIDisplay.value("Execution Directory", nodeOptions.executionDirectory);
33
36
  nodeOptions.localesDirectory =
34
37
  nodeOptions?.localesDirectory ??
35
38
  path.resolve(path.join(nodeOptions.executionDirectory, "dist", "locales"));
36
- CLIDisplay.value("Locales Directory", nodeOptions.localesDirectory);
37
39
  await initialiseLocales(nodeOptions.localesDirectory);
38
- if (Is.empty(nodeOptions?.openApiSpecFile)) {
39
- const specFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "docs", "open-api", "spec.json"));
40
- CLIDisplay.value("Default OpenAPI Spec File", specFile);
41
- if (await fileExists(specFile)) {
42
- nodeOptions ??= {};
43
- nodeOptions.openApiSpecFile = specFile;
44
- }
45
- }
46
- else {
47
- CLIDisplay.value("OpenAPI Spec File", nodeOptions.openApiSpecFile);
48
- }
49
- if (Is.empty(nodeOptions?.favIconFile)) {
50
- const favIconFile = path.resolve(path.join(nodeOptions.executionDirectory ?? "", "static", "favicon.png"));
51
- CLIDisplay.value("Default Favicon File", favIconFile);
52
- if (await fileExists(favIconFile)) {
53
- nodeOptions ??= {};
54
- nodeOptions.favIconFile = favIconFile;
55
- }
56
- }
57
- else {
58
- CLIDisplay.value("Favicon File", nodeOptions.favIconFile);
59
- }
60
40
  nodeOptions.envPrefix ??= "TWIN_";
61
41
  CLIDisplay.value("Environment Variable Prefix", nodeOptions.envPrefix);
62
42
  overrideModuleImport(nodeOptions.executionDirectory ?? "");
@@ -71,14 +51,48 @@ export async function run(nodeOptions) {
71
51
  ...nodeOptions.envVars
72
52
  };
73
53
  }
74
- const { nodeEngineConfig, nodeEnvVars: envVars, contextIdKeys } = await buildConfiguration(finalEnvVars, nodeOptions, serverInfo);
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;
75
88
  CLIDisplay.break();
76
- const startResult = await start(nodeOptions, nodeEngineConfig, envVars, contextIdKeys);
89
+ const startResult = await start(nodeOptions, nodeEngineConfig, nodeEnvVars, cliCommand, availableContextIdKeys);
77
90
  if (!Is.empty(startResult)) {
78
91
  for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
79
92
  process.on(signal, async () => {
80
93
  CLIDisplay.value("Terminate Signal", signal);
81
94
  await startResult.shutdown();
95
+ process.exit(0);
82
96
  });
83
97
  }
84
98
  }
@@ -88,7 +102,13 @@ export async function run(nodeOptions) {
88
102
  if (nodeOptions?.disableProcessExitOnFailure ?? false) {
89
103
  throw err;
90
104
  }
91
- CLIDisplay.error(err);
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
+ }
92
112
  // eslint-disable-next-line unicorn/no-process-exit
93
113
  process.exit(1);
94
114
  }
@@ -102,7 +122,7 @@ export async function run(nodeOptions) {
102
122
  * and options.
103
123
  */
104
124
  export async function buildConfiguration(processEnv, options, serverInfo) {
105
- const contextIdKeys = [];
125
+ const availableContextIdKeys = [];
106
126
  let defaultEnvOnly = false;
107
127
  if (Is.empty(options?.envFilenames)) {
108
128
  const envFile = path.resolve(path.join(options.executionDirectory ?? "", ".env"));
@@ -149,8 +169,8 @@ export async function buildConfiguration(processEnv, options, serverInfo) {
149
169
  await options.extendEnvVars(envVars);
150
170
  }
151
171
  // Build the engine configuration from the environment variables.
152
- const coreConfig = await buildEngineConfiguration(envVars, contextIdKeys);
153
- const engineServerConfig = await buildEngineServerConfiguration(envVars, contextIdKeys, coreConfig, serverInfo, options?.openApiSpecFile, options?.favIconFile);
172
+ const coreConfig = await buildEngineConfiguration(envVars, availableContextIdKeys);
173
+ const engineServerConfig = await buildEngineServerConfiguration(envVars, availableContextIdKeys, coreConfig, serverInfo, options?.openApiSpecFile, options?.favIconFile);
154
174
  // Merge any custom configuration provided in the options.
155
175
  if (Is.arrayValue(options?.configFilenames)) {
156
176
  for (const configFile of options.configFilenames) {
@@ -170,7 +190,7 @@ export async function buildConfiguration(processEnv, options, serverInfo) {
170
190
  await options.extendConfig(envVars, engineServerConfig);
171
191
  }
172
192
  const nodeEngineConfig = await extensionsConfiguration(envVars, engineServerConfig);
173
- return { nodeEngineConfig, nodeEnvVars: envVars, contextIdKeys };
193
+ return { nodeEngineConfig, nodeEnvVars: envVars, availableContextIdKeys };
174
194
  }
175
195
  /**
176
196
  * Override module imports to support protocol-based loading (npm:, https:) and local files.
@@ -1 +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 { Coerce, EnvHelper, GeneralError, Is } 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 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 \"./server.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 * @returns A promise that resolves when the server is started containing a shutdown method.\n */\nexport async function run(nodeOptions?: INodeOptions): 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\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.0\" // 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\t\tCLIDisplay.value(\"Execution Directory\", nodeOptions.executionDirectory);\n\n\t\tnodeOptions.localesDirectory =\n\t\t\tnodeOptions?.localesDirectory ??\n\t\t\tpath.resolve(path.join(nodeOptions.executionDirectory, \"dist\", \"locales\"));\n\t\tCLIDisplay.value(\"Locales Directory\", nodeOptions.localesDirectory);\n\n\t\tawait initialiseLocales(nodeOptions.localesDirectory);\n\n\t\tif (Is.empty(nodeOptions?.openApiSpecFile)) {\n\t\t\tconst specFile = path.resolve(\n\t\t\t\tpath.join(nodeOptions.executionDirectory ?? \"\", \"docs\", \"open-api\", \"spec.json\")\n\t\t\t);\n\t\t\tCLIDisplay.value(\"Default OpenAPI Spec File\", specFile);\n\t\t\tif (await fileExists(specFile)) {\n\t\t\t\tnodeOptions ??= {};\n\t\t\t\tnodeOptions.openApiSpecFile = specFile;\n\t\t\t}\n\t\t} else {\n\t\t\tCLIDisplay.value(\"OpenAPI Spec File\", nodeOptions.openApiSpecFile);\n\t\t}\n\n\t\tif (Is.empty(nodeOptions?.favIconFile)) {\n\t\t\tconst favIconFile = path.resolve(\n\t\t\t\tpath.join(nodeOptions.executionDirectory ?? \"\", \"static\", \"favicon.png\")\n\t\t\t);\n\t\t\tCLIDisplay.value(\"Default Favicon File\", favIconFile);\n\t\t\tif (await fileExists(favIconFile)) {\n\t\t\t\tnodeOptions ??= {};\n\t\t\t\tnodeOptions.favIconFile = favIconFile;\n\t\t\t}\n\t\t} else {\n\t\t\tCLIDisplay.value(\"Favicon File\", nodeOptions.favIconFile);\n\t\t}\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\tconst {\n\t\t\tnodeEngineConfig,\n\t\t\tnodeEnvVars: envVars,\n\t\t\tcontextIdKeys\n\t\t} = await buildConfiguration(finalEnvVars, nodeOptions, serverInfo);\n\n\t\tCLIDisplay.break();\n\t\tconst startResult = await start(nodeOptions, nodeEngineConfig, envVars, contextIdKeys);\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});\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\t\tCLIDisplay.error(err);\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\tcontextIdKeys: string[];\n}> {\n\tconst contextIdKeys: 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, contextIdKeys);\n\tconst engineServerConfig = await buildEngineServerConfiguration(\n\t\tenvVars,\n\t\tcontextIdKeys,\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, contextIdKeys };\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"]}
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":"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","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"]}
package/dist/es/utils.js CHANGED
@@ -5,11 +5,10 @@ import { mkdir, readdir, readFile, rename, stat, writeFile } from "node:fs/promi
5
5
  import { get as httpsGet } from "node:https";
6
6
  import path from "node:path";
7
7
  import { CLIDisplay } from "@twin.org/cli-core";
8
- import { BaseError, Converter, GeneralError, I18n, Is } from "@twin.org/core";
8
+ import { BaseError, Converter, GeneralError, I18n } from "@twin.org/core";
9
9
  import { Sha256 } from "@twin.org/crypto";
10
10
  import { ModuleHelper } from "@twin.org/modules";
11
11
  import { ModuleProtocol } from "./models/moduleProtocol.js";
12
- import { NodeFeatures } from "./models/nodeFeatures.js";
13
12
  /**
14
13
  * Initialise the locales for the application.
15
14
  * @param localesDirectory The directory containing the locales.
@@ -121,26 +120,6 @@ export async function loadJsonFile(filename) {
121
120
  const content = await loadTextFile(filename);
122
121
  return JSON.parse(content);
123
122
  }
124
- /**
125
- * Get the features that are enabled on the node.
126
- * @param env The environment variables for the node.
127
- * @returns The features that are enabled on the node.
128
- */
129
- export function getFeatures(env) {
130
- if (Is.empty(env.features)) {
131
- return [];
132
- }
133
- const features = [];
134
- const allFeatures = Object.values(NodeFeatures);
135
- const splitFeatures = env.features.split(",");
136
- for (const feature of splitFeatures) {
137
- const featureTrimmed = feature.trim();
138
- if (allFeatures.includes(featureTrimmed)) {
139
- features.push(featureTrimmed);
140
- }
141
- }
142
- return features;
143
- }
144
123
  /**
145
124
  * Parse the protocol from a module name.
146
125
  * @param moduleName The module name to parse.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.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 { mkdir, readdir, readFile, rename, stat, writeFile } from \"node:fs/promises\";\nimport { get as httpsGet } from \"node:https\";\nimport path from \"node:path\";\nimport { CLIDisplay } from \"@twin.org/cli-core\";\nimport {\n\tBaseError,\n\tConverter,\n\tGeneralError,\n\tI18n,\n\tIs,\n\ttype ILocaleDictionary\n} from \"@twin.org/core\";\nimport { Sha256 } from \"@twin.org/crypto\";\nimport { ModuleHelper } from \"@twin.org/modules\";\nimport type { ICacheMetadata } from \"./models/ICacheMetadata.js\";\nimport type { IModuleProtocol } from \"./models/IModuleProtocol.js\";\nimport type { INodeEnvironmentVariables } from \"./models/INodeEnvironmentVariables.js\";\nimport type { IProtocolHandlerResult } from \"./models/IProtocolHandlerResult.js\";\nimport { ModuleProtocol } from \"./models/moduleProtocol.js\";\nimport { NodeFeatures } from \"./models/nodeFeatures.js\";\n\n/**\n * Initialise the locales for the application.\n * @param localesDirectory The directory containing the locales.\n */\nexport async function initialiseLocales(localesDirectory: string): Promise<void> {\n\tconst localesFile = path.resolve(path.join(localesDirectory, \"en.json\"));\n\tCLIDisplay.value(\"Locales File\", localesFile);\n\tif (await fileExists(localesFile)) {\n\t\tconst enLangContent = await readFile(localesFile, \"utf8\");\n\t\tI18n.addDictionary(\"en\", JSON.parse(enLangContent) as ILocaleDictionary);\n\t} else {\n\t\tCLIDisplay.error(`Locales file not found: ${localesFile}`);\n\t}\n}\n\n/**\n * Get the directory where the application is being executed.\n * @returns The execution directory.\n */\nexport function getExecutionDirectory(): string {\n\treturn process.cwd();\n}\n\n/**\n * Does the specified file exist.\n * @param filename The filename to check for existence.\n * @returns True if the file exists.\n */\nexport async function fileExists(filename: string): Promise<boolean> {\n\ttry {\n\t\tconst stats = await stat(filename);\n\t\treturn stats.isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Does the specified directory exist.\n * @param directory The directory to check for existence.\n * @returns True if the directory exists.\n */\nexport async function directoryExists(directory: string): Promise<boolean> {\n\ttry {\n\t\tconst stats = await stat(directory);\n\t\treturn stats.isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get the sub folders for the folder.\n * @param directory The directory to get the sub folders.\n * @returns The list of sub folders.\n */\nexport async function getSubFolders(directory: string): Promise<string[]> {\n\ttry {\n\t\tconst dir = await readdir(directory);\n\t\tconst folders: string[] = [];\n\t\tfor (const dirEntry of dir) {\n\t\t\tconst fullPath = path.join(directory, dirEntry);\n\t\t\tconst stats = await stat(fullPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tfolders.push(fullPath);\n\t\t\t}\n\t\t}\n\t\treturn folders;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Get the files in the directory.\n * @param directory The directory to get the files from.\n * @returns The list of files in the directory.\n */\nexport async function getFiles(directory: string): Promise<string[]> {\n\ttry {\n\t\tconst dir = await readdir(directory);\n\t\tconst files: string[] = [];\n\t\tfor (const dirEntry of dir) {\n\t\t\tconst fullPath = path.join(directory, dirEntry);\n\t\t\tconst stats = await stat(fullPath);\n\t\t\tif (stats.isFile()) {\n\t\t\t\tfiles.push(fullPath);\n\t\t\t}\n\t\t}\n\t\treturn files;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Load the text file.\n * @param filename The filename of the text file to load.\n * @returns The contents of the text file if it could not be loaded.\n */\nexport async function loadTextFile(filename: string): Promise<string> {\n\treturn readFile(filename, \"utf8\");\n}\n\n/**\n * Load the JSON file.\n * @param filename The filename of the JSON file to load.\n * @returns The contents of the JSON file or null if it could not be loaded.\n */\nexport async function loadJsonFile<T>(filename: string): Promise<T> {\n\tconst content = await loadTextFile(filename);\n\treturn JSON.parse(content) as T;\n}\n\n/**\n * Get the features that are enabled on the node.\n * @param env The environment variables for the node.\n * @returns The features that are enabled on the node.\n */\nexport function getFeatures(env: INodeEnvironmentVariables): NodeFeatures[] {\n\tif (Is.empty(env.features)) {\n\t\treturn [];\n\t}\n\n\tconst features: NodeFeatures[] = [];\n\tconst allFeatures = Object.values(NodeFeatures);\n\n\tconst splitFeatures = env.features.split(\",\");\n\tfor (const feature of splitFeatures) {\n\t\tconst featureTrimmed = feature.trim() as NodeFeatures;\n\t\tif (allFeatures.includes(featureTrimmed)) {\n\t\t\tfeatures.push(featureTrimmed);\n\t\t}\n\t}\n\n\treturn features;\n}\n\n/**\n * Parse the protocol from a module name.\n * @param moduleName The module name to parse.\n * @returns The parsed protocol information.\n */\nexport function parseModuleProtocol(moduleName: string): IModuleProtocol {\n\tconst trimmed = moduleName.trim();\n\n\tif (trimmed.startsWith(\"npm:\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Npm,\n\t\t\tidentifier: trimmed.slice(4),\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (trimmed.startsWith(\"https://\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Https,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (trimmed.startsWith(\"http://\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Http,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (trimmed.startsWith(\"file://\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Local,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (ModuleHelper.isLocalModule(trimmed)) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Local,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\treturn {\n\t\tprotocol: ModuleProtocol.Default,\n\t\tidentifier: trimmed,\n\t\toriginal: trimmed\n\t};\n}\n\n/**\n * Hash a URL to create a safe filename.\n * @param url The URL to hash.\n * @returns A hashed filename safe for the filesystem.\n */\nexport function hashUrl(url: string): string {\n\tconst urlBytes = Converter.utf8ToBytes(url);\n\tconst hashBytes = Sha256.sum256(urlBytes);\n\tconst hash = Converter.bytesToHex(hashBytes);\n\tconst ext = path.extname(new URL(url).pathname);\n\treturn `${hash}${ext}`;\n}\n\n/**\n * Get the extensions cache directory.\n * @param executionDirectory The execution directory.\n * @param protocol The protocol type for subdirectory organization.\n * @param cacheDirectory The cache directory base path.\n * @returns The cache directory path.\n */\nexport function getExtensionsCacheDir(\n\texecutionDirectory: string,\n\tprotocol: ModuleProtocol,\n\tcacheDirectory?: string\n): string {\n\t// Resolve to absolute path to ensure consistent behavior\n\tconst absoluteDir = path.resolve(executionDirectory);\n\tconst baseDir = cacheDirectory ?? \".tmp\";\n\treturn path.join(absoluteDir, baseDir, \"extensions\", protocol);\n}\n\n/**\n * Handle the npm: protocol by installing the package if needed.\n * @param packageName The npm package name (without npm: prefix).\n * @param executionDirectory The execution directory.\n * @param cacheDirectory The cache directory base path.\n * @returns The resolved path to the installed module.\n */\nexport async function handleNpmProtocol(\n\tpackageName: string,\n\texecutionDirectory: string,\n\tcacheDirectory?: string\n): Promise<IProtocolHandlerResult> {\n\tconst cacheDir = getExtensionsCacheDir(executionDirectory, ModuleProtocol.Npm, cacheDirectory);\n\t// Extract just the package name (without version) for the directory\n\t// e.g. \"picocolors@1.0.0\" becomes \"picocolors\"\n\t// e.g. \"@scope/package@1.0.0\" becomes \"@scope/package\"\n\tconst lastAtIndex = packageName.lastIndexOf(\"@\");\n\tconst packageNameOnly = lastAtIndex > 0 ? packageName.slice(0, lastAtIndex) : packageName;\n\tconst packageDir = path.join(cacheDir, \"node_modules\", packageNameOnly);\n\tconst packageJsonPath = path.join(packageDir, \"package.json\");\n\n\tconst exists = await fileExists(packageJsonPath);\n\tif (exists) {\n\t\tconst mainFile = await resolvePackageEntryPoint(packageDir, packageNameOnly);\n\t\tconst modulePath = path.join(packageDir, mainFile);\n\n\t\treturn {\n\t\t\tresolvedPath: modulePath,\n\t\t\tcached: true\n\t\t};\n\t}\n\n\tawait mkdir(cacheDir, { recursive: true });\n\n\tCLIDisplay.task(I18n.formatMessage(\"node.extensionNpmInstalling\"), packageName);\n\n\ttry {\n\t\t// Always pipe stdio to comply with env access restrictions in tests/lint\n\t\tconst stdio: \"pipe\" | \"inherit\" | \"ignore\" = \"pipe\";\n\t\texecSync(`npm install ${packageName} --prefix \"${cacheDir}\" --no-save --no-package-lock`, {\n\t\t\tcwd: cacheDir,\n\t\t\tstdio\n\t\t});\n\t} catch (err) {\n\t\tthrow new GeneralError(\n\t\t\t\"node\",\n\t\t\t\"extensionNpmInstallFailed\",\n\t\t\t{\n\t\t\t\tpackage: packageName\n\t\t\t},\n\t\t\tBaseError.fromError(err)\n\t\t);\n\t}\n\n\tconst mainFile = await resolvePackageEntryPoint(packageDir, packageNameOnly);\n\tconst modulePath = path.join(packageDir, mainFile);\n\n\treturn {\n\t\tresolvedPath: modulePath,\n\t\tcached: false\n\t};\n}\n\n/**\n * Check if a cached file has expired based on TTL and force refresh settings.\n * @param metadataPath Path to the cache metadata file.\n * @param ttlHours Time to live in hours.\n * @param forceRefresh Whether to force refresh regardless of TTL.\n * @returns True if the cache is expired or should be refreshed.\n */\nexport async function isCacheExpired(\n\tmetadataPath: string,\n\tttlHours: number,\n\tforceRefresh: boolean\n): Promise<boolean> {\n\tif (forceRefresh) {\n\t\treturn true;\n\t}\n\n\ttry {\n\t\tconst metadata = await loadJsonFile<ICacheMetadata>(metadataPath);\n\t\tconst ttlMillis = ttlHours * 60 * 60 * 1000;\n\t\tconst expireTime = metadata.downloadedAt + ttlMillis;\n\t\treturn Date.now() > expireTime;\n\t} catch {\n\t\t// If metadata doesn't exist or is corrupted, consider expired\n\t\treturn true;\n\t}\n}\n\n/**\n * Handle the https: protocol by downloading the module if needed.\n * @param url The HTTPS URL to download from.\n * @param executionDirectory The execution directory.\n * @param maxSizeMb The maximum size in MB for the download.\n * @param cacheDirectory The cache directory base path.\n * @param ttlHours TTL in hours for cache expiration.\n * @param forceRefresh Whether to force refresh the cache.\n * @returns The resolved path to the downloaded module.\n */\nexport async function handleHttpsProtocol(\n\turl: string,\n\texecutionDirectory: string,\n\tmaxSizeMb: number,\n\tcacheDirectory?: string,\n\tttlHours?: number,\n\tforceRefresh?: boolean\n): Promise<IProtocolHandlerResult> {\n\tconst effectiveTtlHours = ttlHours ?? 24;\n\tconst effectiveForceRefresh = forceRefresh ?? false;\n\tconst cacheDir = getExtensionsCacheDir(executionDirectory, ModuleProtocol.Https, cacheDirectory);\n\tconst filename = hashUrl(url);\n\tconst cachedPath = path.join(cacheDir, filename);\n\tconst metadataPath = `${cachedPath}.meta`;\n\n\tconst exists = await fileExists(cachedPath);\n\tif (exists) {\n\t\tconst expired = await isCacheExpired(metadataPath, effectiveTtlHours, effectiveForceRefresh);\n\t\tif (!expired) {\n\t\t\treturn {\n\t\t\t\tresolvedPath: cachedPath,\n\t\t\t\tcached: true\n\t\t\t};\n\t\t}\n\n\t\tif (effectiveForceRefresh) {\n\t\t\tCLIDisplay.warning(I18n.formatMessage(\"node.extensionForceRefresh\", { url }));\n\t\t} else {\n\t\t\tCLIDisplay.task(I18n.formatMessage(\"node.extensionCacheExpired\", { url }));\n\t\t}\n\t}\n\n\tCLIDisplay.warning(I18n.formatMessage(\"node.extensionSecurityWarning\", { url }));\n\tCLIDisplay.task(I18n.formatMessage(\"node.extensionHttpsDownloading\"), url);\n\n\tawait mkdir(cacheDir, { recursive: true });\n\n\tconst maxSizeBytes = maxSizeMb * 1024 * 1024;\n\tlet downloadedSize = 0;\n\tconst chunks: Buffer[] = [];\n\n\ttry {\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\thttpsGet(url, response => {\n\t\t\t\tif (response.statusCode !== 200) {\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew GeneralError(\"node\", \"extensionDownloadFailed\", {\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\tstatus: response.statusCode ?? 0\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresponse.on(\"data\", (chunk: Buffer) => {\n\t\t\t\t\tdownloadedSize += chunk.length;\n\n\t\t\t\t\tif (downloadedSize > maxSizeBytes) {\n\t\t\t\t\t\tresponse.destroy();\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew GeneralError(\"node\", \"extensionSizeLimitExceeded\", {\n\t\t\t\t\t\t\t\tsize: downloadedSize,\n\t\t\t\t\t\t\t\tlimit: maxSizeBytes\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tchunks.push(chunk);\n\t\t\t\t});\n\n\t\t\t\tresponse.on(\"end\", () => {\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\n\t\t\t\tresponse.on(\"error\", err => {\n\t\t\t\t\treject(BaseError.fromError(err));\n\t\t\t\t});\n\t\t\t}).on(\"error\", err => {\n\t\t\t\treject(BaseError.fromError(err));\n\t\t\t});\n\t\t});\n\t} catch (err) {\n\t\tthrow new GeneralError(\n\t\t\t\"node\",\n\t\t\t\"extensionDownloadFailed\",\n\t\t\t{\n\t\t\t\turl\n\t\t\t},\n\t\t\tBaseError.fromError(err)\n\t\t);\n\t}\n\n\tconst tempPath = `${cachedPath}.tmp`;\n\tawait writeFile(tempPath, Buffer.concat(chunks));\n\n\t// Atomic move from temp to final location\n\tawait rename(tempPath, cachedPath);\n\n\t// Save metadata for TTL tracking\n\tconst metadata: ICacheMetadata = {\n\t\tdownloadedAt: Date.now(),\n\t\turl,\n\t\tsize: Buffer.concat(chunks).length\n\t};\n\tawait writeFile(metadataPath, JSON.stringify(metadata, null, 2));\n\n\treturn {\n\t\tresolvedPath: cachedPath,\n\t\tcached: false\n\t};\n}\n\n/**\n * Resolve the main entry point from a package directory using Node.js resolution with fallback.\n * Uses require.resolve() when possible for standard Node.js behavior, with manual fallback.\n * @param packagePath The absolute path to the package directory.\n * @param packageName The package name for require.resolve().\n * @param fallback The fallback file name if no entry point is found.\n * @returns The resolved entry point file name (relative to package directory).\n */\nexport async function resolvePackageEntryPoint(\n\tpackagePath: string,\n\tpackageName: string,\n\tfallback = \"index.js\"\n): Promise<string> {\n\ttry {\n\t\t// Try require.resolve() first - handles exports, main, module automatically\n\t\tconst resolvedPath = require.resolve(packageName, { paths: [path.dirname(packagePath)] });\n\t\t// Convert absolute path back to relative filename within package\n\t\tconst relativePath = path.relative(packagePath, resolvedPath);\n\t\treturn relativePath ?? fallback;\n\t} catch {\n\t\t// Fallback to manual package.json parsing if require.resolve fails\n\t\ttry {\n\t\t\tconst packageJsonPath = path.join(packagePath, \"package.json\");\n\t\t\tconst packageJsonContent = await loadJsonFile<{\n\t\t\t\tmodule?: string;\n\t\t\t\tmain?: string;\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\texports?: any;\n\t\t\t}>(packageJsonPath);\n\n\t\t\t// Future: Could expand exports field support here\n\t\t\treturn packageJsonContent.module ?? packageJsonContent.main ?? fallback;\n\t\t} catch {\n\t\t\treturn fallback;\n\t\t}\n\t}\n}\n\n/**\n * Convert a file path to an import-compatible URL for cross-platform module loading.\n * On Windows, adds the 'file://' protocol prefix required for dynamic imports.\n * On other platforms, returns the path unchanged.\n * @param filePath The absolute file path to convert.\n * @returns A URL string compatible with dynamic import().\n */\nexport function createModuleImportUrl(filePath: string): string {\n\treturn process.platform === \"win32\" ? `file://${filePath}` : filePath;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.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 { mkdir, readdir, readFile, rename, stat, writeFile } from \"node:fs/promises\";\nimport { get as httpsGet } from \"node:https\";\nimport path from \"node:path\";\nimport { CLIDisplay } from \"@twin.org/cli-core\";\nimport { BaseError, Converter, GeneralError, I18n, type ILocaleDictionary } from \"@twin.org/core\";\nimport { Sha256 } from \"@twin.org/crypto\";\nimport { ModuleHelper } from \"@twin.org/modules\";\nimport type { ICacheMetadata } from \"./models/ICacheMetadata.js\";\nimport type { IModuleProtocol } from \"./models/IModuleProtocol.js\";\nimport type { IProtocolHandlerResult } from \"./models/IProtocolHandlerResult.js\";\nimport { ModuleProtocol } from \"./models/moduleProtocol.js\";\n\n/**\n * Initialise the locales for the application.\n * @param localesDirectory The directory containing the locales.\n */\nexport async function initialiseLocales(localesDirectory: string): Promise<void> {\n\tconst localesFile = path.resolve(path.join(localesDirectory, \"en.json\"));\n\tCLIDisplay.value(\"Locales File\", localesFile);\n\tif (await fileExists(localesFile)) {\n\t\tconst enLangContent = await readFile(localesFile, \"utf8\");\n\t\tI18n.addDictionary(\"en\", JSON.parse(enLangContent) as ILocaleDictionary);\n\t} else {\n\t\tCLIDisplay.error(`Locales file not found: ${localesFile}`);\n\t}\n}\n\n/**\n * Get the directory where the application is being executed.\n * @returns The execution directory.\n */\nexport function getExecutionDirectory(): string {\n\treturn process.cwd();\n}\n\n/**\n * Does the specified file exist.\n * @param filename The filename to check for existence.\n * @returns True if the file exists.\n */\nexport async function fileExists(filename: string): Promise<boolean> {\n\ttry {\n\t\tconst stats = await stat(filename);\n\t\treturn stats.isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Does the specified directory exist.\n * @param directory The directory to check for existence.\n * @returns True if the directory exists.\n */\nexport async function directoryExists(directory: string): Promise<boolean> {\n\ttry {\n\t\tconst stats = await stat(directory);\n\t\treturn stats.isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get the sub folders for the folder.\n * @param directory The directory to get the sub folders.\n * @returns The list of sub folders.\n */\nexport async function getSubFolders(directory: string): Promise<string[]> {\n\ttry {\n\t\tconst dir = await readdir(directory);\n\t\tconst folders: string[] = [];\n\t\tfor (const dirEntry of dir) {\n\t\t\tconst fullPath = path.join(directory, dirEntry);\n\t\t\tconst stats = await stat(fullPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tfolders.push(fullPath);\n\t\t\t}\n\t\t}\n\t\treturn folders;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Get the files in the directory.\n * @param directory The directory to get the files from.\n * @returns The list of files in the directory.\n */\nexport async function getFiles(directory: string): Promise<string[]> {\n\ttry {\n\t\tconst dir = await readdir(directory);\n\t\tconst files: string[] = [];\n\t\tfor (const dirEntry of dir) {\n\t\t\tconst fullPath = path.join(directory, dirEntry);\n\t\t\tconst stats = await stat(fullPath);\n\t\t\tif (stats.isFile()) {\n\t\t\t\tfiles.push(fullPath);\n\t\t\t}\n\t\t}\n\t\treturn files;\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Load the text file.\n * @param filename The filename of the text file to load.\n * @returns The contents of the text file if it could not be loaded.\n */\nexport async function loadTextFile(filename: string): Promise<string> {\n\treturn readFile(filename, \"utf8\");\n}\n\n/**\n * Load the JSON file.\n * @param filename The filename of the JSON file to load.\n * @returns The contents of the JSON file or null if it could not be loaded.\n */\nexport async function loadJsonFile<T>(filename: string): Promise<T> {\n\tconst content = await loadTextFile(filename);\n\treturn JSON.parse(content) as T;\n}\n\n/**\n * Parse the protocol from a module name.\n * @param moduleName The module name to parse.\n * @returns The parsed protocol information.\n */\nexport function parseModuleProtocol(moduleName: string): IModuleProtocol {\n\tconst trimmed = moduleName.trim();\n\n\tif (trimmed.startsWith(\"npm:\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Npm,\n\t\t\tidentifier: trimmed.slice(4),\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (trimmed.startsWith(\"https://\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Https,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (trimmed.startsWith(\"http://\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Http,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (trimmed.startsWith(\"file://\")) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Local,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\tif (ModuleHelper.isLocalModule(trimmed)) {\n\t\treturn {\n\t\t\tprotocol: ModuleProtocol.Local,\n\t\t\tidentifier: trimmed,\n\t\t\toriginal: trimmed\n\t\t};\n\t}\n\n\treturn {\n\t\tprotocol: ModuleProtocol.Default,\n\t\tidentifier: trimmed,\n\t\toriginal: trimmed\n\t};\n}\n\n/**\n * Hash a URL to create a safe filename.\n * @param url The URL to hash.\n * @returns A hashed filename safe for the filesystem.\n */\nexport function hashUrl(url: string): string {\n\tconst urlBytes = Converter.utf8ToBytes(url);\n\tconst hashBytes = Sha256.sum256(urlBytes);\n\tconst hash = Converter.bytesToHex(hashBytes);\n\tconst ext = path.extname(new URL(url).pathname);\n\treturn `${hash}${ext}`;\n}\n\n/**\n * Get the extensions cache directory.\n * @param executionDirectory The execution directory.\n * @param protocol The protocol type for subdirectory organization.\n * @param cacheDirectory The cache directory base path.\n * @returns The cache directory path.\n */\nexport function getExtensionsCacheDir(\n\texecutionDirectory: string,\n\tprotocol: ModuleProtocol,\n\tcacheDirectory?: string\n): string {\n\t// Resolve to absolute path to ensure consistent behavior\n\tconst absoluteDir = path.resolve(executionDirectory);\n\tconst baseDir = cacheDirectory ?? \".tmp\";\n\treturn path.join(absoluteDir, baseDir, \"extensions\", protocol);\n}\n\n/**\n * Handle the npm: protocol by installing the package if needed.\n * @param packageName The npm package name (without npm: prefix).\n * @param executionDirectory The execution directory.\n * @param cacheDirectory The cache directory base path.\n * @returns The resolved path to the installed module.\n */\nexport async function handleNpmProtocol(\n\tpackageName: string,\n\texecutionDirectory: string,\n\tcacheDirectory?: string\n): Promise<IProtocolHandlerResult> {\n\tconst cacheDir = getExtensionsCacheDir(executionDirectory, ModuleProtocol.Npm, cacheDirectory);\n\t// Extract just the package name (without version) for the directory\n\t// e.g. \"picocolors@1.0.0\" becomes \"picocolors\"\n\t// e.g. \"@scope/package@1.0.0\" becomes \"@scope/package\"\n\tconst lastAtIndex = packageName.lastIndexOf(\"@\");\n\tconst packageNameOnly = lastAtIndex > 0 ? packageName.slice(0, lastAtIndex) : packageName;\n\tconst packageDir = path.join(cacheDir, \"node_modules\", packageNameOnly);\n\tconst packageJsonPath = path.join(packageDir, \"package.json\");\n\n\tconst exists = await fileExists(packageJsonPath);\n\tif (exists) {\n\t\tconst mainFile = await resolvePackageEntryPoint(packageDir, packageNameOnly);\n\t\tconst modulePath = path.join(packageDir, mainFile);\n\n\t\treturn {\n\t\t\tresolvedPath: modulePath,\n\t\t\tcached: true\n\t\t};\n\t}\n\n\tawait mkdir(cacheDir, { recursive: true });\n\n\tCLIDisplay.task(I18n.formatMessage(\"node.extensionNpmInstalling\"), packageName);\n\n\ttry {\n\t\t// Always pipe stdio to comply with env access restrictions in tests/lint\n\t\tconst stdio: \"pipe\" | \"inherit\" | \"ignore\" = \"pipe\";\n\t\texecSync(`npm install ${packageName} --prefix \"${cacheDir}\" --no-save --no-package-lock`, {\n\t\t\tcwd: cacheDir,\n\t\t\tstdio\n\t\t});\n\t} catch (err) {\n\t\tthrow new GeneralError(\n\t\t\t\"node\",\n\t\t\t\"extensionNpmInstallFailed\",\n\t\t\t{\n\t\t\t\tpackage: packageName\n\t\t\t},\n\t\t\tBaseError.fromError(err)\n\t\t);\n\t}\n\n\tconst mainFile = await resolvePackageEntryPoint(packageDir, packageNameOnly);\n\tconst modulePath = path.join(packageDir, mainFile);\n\n\treturn {\n\t\tresolvedPath: modulePath,\n\t\tcached: false\n\t};\n}\n\n/**\n * Check if a cached file has expired based on TTL and force refresh settings.\n * @param metadataPath Path to the cache metadata file.\n * @param ttlHours Time to live in hours.\n * @param forceRefresh Whether to force refresh regardless of TTL.\n * @returns True if the cache is expired or should be refreshed.\n */\nexport async function isCacheExpired(\n\tmetadataPath: string,\n\tttlHours: number,\n\tforceRefresh: boolean\n): Promise<boolean> {\n\tif (forceRefresh) {\n\t\treturn true;\n\t}\n\n\ttry {\n\t\tconst metadata = await loadJsonFile<ICacheMetadata>(metadataPath);\n\t\tconst ttlMillis = ttlHours * 60 * 60 * 1000;\n\t\tconst expireTime = metadata.downloadedAt + ttlMillis;\n\t\treturn Date.now() > expireTime;\n\t} catch {\n\t\t// If metadata doesn't exist or is corrupted, consider expired\n\t\treturn true;\n\t}\n}\n\n/**\n * Handle the https: protocol by downloading the module if needed.\n * @param url The HTTPS URL to download from.\n * @param executionDirectory The execution directory.\n * @param maxSizeMb The maximum size in MB for the download.\n * @param cacheDirectory The cache directory base path.\n * @param ttlHours TTL in hours for cache expiration.\n * @param forceRefresh Whether to force refresh the cache.\n * @returns The resolved path to the downloaded module.\n */\nexport async function handleHttpsProtocol(\n\turl: string,\n\texecutionDirectory: string,\n\tmaxSizeMb: number,\n\tcacheDirectory?: string,\n\tttlHours?: number,\n\tforceRefresh?: boolean\n): Promise<IProtocolHandlerResult> {\n\tconst effectiveTtlHours = ttlHours ?? 24;\n\tconst effectiveForceRefresh = forceRefresh ?? false;\n\tconst cacheDir = getExtensionsCacheDir(executionDirectory, ModuleProtocol.Https, cacheDirectory);\n\tconst filename = hashUrl(url);\n\tconst cachedPath = path.join(cacheDir, filename);\n\tconst metadataPath = `${cachedPath}.meta`;\n\n\tconst exists = await fileExists(cachedPath);\n\tif (exists) {\n\t\tconst expired = await isCacheExpired(metadataPath, effectiveTtlHours, effectiveForceRefresh);\n\t\tif (!expired) {\n\t\t\treturn {\n\t\t\t\tresolvedPath: cachedPath,\n\t\t\t\tcached: true\n\t\t\t};\n\t\t}\n\n\t\tif (effectiveForceRefresh) {\n\t\t\tCLIDisplay.warning(I18n.formatMessage(\"node.extensionForceRefresh\", { url }));\n\t\t} else {\n\t\t\tCLIDisplay.task(I18n.formatMessage(\"node.extensionCacheExpired\", { url }));\n\t\t}\n\t}\n\n\tCLIDisplay.warning(I18n.formatMessage(\"node.extensionSecurityWarning\", { url }));\n\tCLIDisplay.task(I18n.formatMessage(\"node.extensionHttpsDownloading\"), url);\n\n\tawait mkdir(cacheDir, { recursive: true });\n\n\tconst maxSizeBytes = maxSizeMb * 1024 * 1024;\n\tlet downloadedSize = 0;\n\tconst chunks: Buffer[] = [];\n\n\ttry {\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\thttpsGet(url, response => {\n\t\t\t\tif (response.statusCode !== 200) {\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew GeneralError(\"node\", \"extensionDownloadFailed\", {\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\tstatus: response.statusCode ?? 0\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresponse.on(\"data\", (chunk: Buffer) => {\n\t\t\t\t\tdownloadedSize += chunk.length;\n\n\t\t\t\t\tif (downloadedSize > maxSizeBytes) {\n\t\t\t\t\t\tresponse.destroy();\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew GeneralError(\"node\", \"extensionSizeLimitExceeded\", {\n\t\t\t\t\t\t\t\tsize: downloadedSize,\n\t\t\t\t\t\t\t\tlimit: maxSizeBytes\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tchunks.push(chunk);\n\t\t\t\t});\n\n\t\t\t\tresponse.on(\"end\", () => {\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\n\t\t\t\tresponse.on(\"error\", err => {\n\t\t\t\t\treject(BaseError.fromError(err));\n\t\t\t\t});\n\t\t\t}).on(\"error\", err => {\n\t\t\t\treject(BaseError.fromError(err));\n\t\t\t});\n\t\t});\n\t} catch (err) {\n\t\tthrow new GeneralError(\n\t\t\t\"node\",\n\t\t\t\"extensionDownloadFailed\",\n\t\t\t{\n\t\t\t\turl\n\t\t\t},\n\t\t\tBaseError.fromError(err)\n\t\t);\n\t}\n\n\tconst tempPath = `${cachedPath}.tmp`;\n\tawait writeFile(tempPath, Buffer.concat(chunks));\n\n\t// Atomic move from temp to final location\n\tawait rename(tempPath, cachedPath);\n\n\t// Save metadata for TTL tracking\n\tconst metadata: ICacheMetadata = {\n\t\tdownloadedAt: Date.now(),\n\t\turl,\n\t\tsize: Buffer.concat(chunks).length\n\t};\n\tawait writeFile(metadataPath, JSON.stringify(metadata, null, 2));\n\n\treturn {\n\t\tresolvedPath: cachedPath,\n\t\tcached: false\n\t};\n}\n\n/**\n * Resolve the main entry point from a package directory using Node.js resolution with fallback.\n * Uses require.resolve() when possible for standard Node.js behavior, with manual fallback.\n * @param packagePath The absolute path to the package directory.\n * @param packageName The package name for require.resolve().\n * @param fallback The fallback file name if no entry point is found.\n * @returns The resolved entry point file name (relative to package directory).\n */\nexport async function resolvePackageEntryPoint(\n\tpackagePath: string,\n\tpackageName: string,\n\tfallback = \"index.js\"\n): Promise<string> {\n\ttry {\n\t\t// Try require.resolve() first - handles exports, main, module automatically\n\t\tconst resolvedPath = require.resolve(packageName, { paths: [path.dirname(packagePath)] });\n\t\t// Convert absolute path back to relative filename within package\n\t\tconst relativePath = path.relative(packagePath, resolvedPath);\n\t\treturn relativePath ?? fallback;\n\t} catch {\n\t\t// Fallback to manual package.json parsing if require.resolve fails\n\t\ttry {\n\t\t\tconst packageJsonPath = path.join(packagePath, \"package.json\");\n\t\t\tconst packageJsonContent = await loadJsonFile<{\n\t\t\t\tmodule?: string;\n\t\t\t\tmain?: string;\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\texports?: any;\n\t\t\t}>(packageJsonPath);\n\n\t\t\t// Future: Could expand exports field support here\n\t\t\treturn packageJsonContent.module ?? packageJsonContent.main ?? fallback;\n\t\t} catch {\n\t\t\treturn fallback;\n\t\t}\n\t}\n}\n\n/**\n * Convert a file path to an import-compatible URL for cross-platform module loading.\n * On Windows, adds the 'file://' protocol prefix required for dynamic imports.\n * On other platforms, returns the path unchanged.\n * @param filePath The absolute file path to convert.\n * @returns A URL string compatible with dynamic import().\n */\nexport function createModuleImportUrl(filePath: string): string {\n\treturn process.platform === \"win32\" ? `file://${filePath}` : filePath;\n}\n"]}
@@ -6,4 +6,7 @@ import type { IEngineEnvironmentVariables } from "../models/IEngineEnvironmentVa
6
6
  * @param contextIdKeys The context ID keys.
7
7
  * @returns The config for the core.
8
8
  */
9
- export declare function buildEngineConfiguration(envVars: IEngineEnvironmentVariables, contextIdKeys: string[]): Promise<IEngineConfig>;
9
+ export declare function buildEngineConfiguration(envVars: IEngineEnvironmentVariables, contextIdKeys: {
10
+ key: string;
11
+ requiredHandlerFeatures: string[];
12
+ }[]): Promise<IEngineConfig>;