@harperfast/harper-pro 5.0.6 → 5.0.7

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 (104) hide show
  1. package/core/bin/status.js +2 -2
  2. package/core/bin/stop.js +6 -5
  3. package/core/components/EntryHandler.ts +2 -4
  4. package/core/components/Scope.ts +1 -1
  5. package/core/components/componentLoader.ts +4 -11
  6. package/core/components/requestRestart.ts +2 -17
  7. package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
  8. package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
  9. package/core/package-lock.json +63 -971
  10. package/core/resources/DatabaseTransaction.ts +3 -8
  11. package/core/resources/Table.ts +17 -12
  12. package/core/resources/databases.ts +2 -2
  13. package/core/resources/graphql.ts +165 -163
  14. package/core/resources/indexes/HierarchicalNavigableSmallWorld.ts +3 -14
  15. package/core/resources/indexes/vector.ts +0 -17
  16. package/core/resources/loadEnv.ts +16 -20
  17. package/core/resources/login.ts +3 -4
  18. package/core/resources/roles.ts +65 -60
  19. package/core/security/auth.ts +14 -15
  20. package/core/security/jsLoader.ts +2 -14
  21. package/core/server/REST.ts +11 -10
  22. package/core/server/fastifyRoutes.ts +29 -30
  23. package/core/server/graphqlQuerying.ts +3 -4
  24. package/core/server/http.ts +1 -175
  25. package/core/server/mqtt.ts +2 -8
  26. package/core/server/serverHelpers/serverUtilities.ts +5 -2
  27. package/core/server/threads/threadServer.js +2 -30
  28. package/core/server/throttle.ts +0 -18
  29. package/core/utility/environment/environmentManager.js +4 -10
  30. package/core/utility/environment/systemInformation.js +355 -0
  31. package/core/utility/hdbTerms.ts +0 -1
  32. package/core/utility/operation_authorization.js +5 -2
  33. package/dist/core/bin/status.js +2 -2
  34. package/dist/core/bin/status.js.map +1 -1
  35. package/dist/core/bin/stop.js +5 -5
  36. package/dist/core/bin/stop.js.map +1 -1
  37. package/dist/core/components/EntryHandler.js +2 -4
  38. package/dist/core/components/EntryHandler.js.map +1 -1
  39. package/dist/core/components/Scope.js +1 -1
  40. package/dist/core/components/Scope.js.map +1 -1
  41. package/dist/core/components/componentLoader.js +3 -11
  42. package/dist/core/components/componentLoader.js.map +1 -1
  43. package/dist/core/components/requestRestart.js +1 -12
  44. package/dist/core/components/requestRestart.js.map +1 -1
  45. package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +24 -0
  46. package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js.map +1 -0
  47. package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +19 -18
  48. package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js.map +1 -1
  49. package/dist/core/resources/DatabaseTransaction.js +1 -6
  50. package/dist/core/resources/DatabaseTransaction.js.map +1 -1
  51. package/dist/core/resources/Table.js +18 -14
  52. package/dist/core/resources/Table.js.map +1 -1
  53. package/dist/core/resources/databases.js +1 -2
  54. package/dist/core/resources/databases.js.map +1 -1
  55. package/dist/core/resources/graphql.js +176 -176
  56. package/dist/core/resources/graphql.js.map +1 -1
  57. package/dist/core/resources/indexes/HierarchicalNavigableSmallWorld.js +2 -14
  58. package/dist/core/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
  59. package/dist/core/resources/indexes/vector.js +0 -14
  60. package/dist/core/resources/indexes/vector.js.map +1 -1
  61. package/dist/core/resources/loadEnv.js +17 -20
  62. package/dist/core/resources/loadEnv.js.map +1 -1
  63. package/dist/core/resources/login.js +4 -4
  64. package/dist/core/resources/login.js.map +1 -1
  65. package/dist/core/resources/roles.js +68 -64
  66. package/dist/core/resources/roles.js.map +1 -1
  67. package/dist/core/security/auth.js +15 -17
  68. package/dist/core/security/auth.js.map +1 -1
  69. package/dist/core/security/jsLoader.js +2 -16
  70. package/dist/core/security/jsLoader.js.map +1 -1
  71. package/dist/core/server/REST.js +11 -11
  72. package/dist/core/server/REST.js.map +1 -1
  73. package/dist/core/server/fastifyRoutes.js +29 -30
  74. package/dist/core/server/fastifyRoutes.js.map +1 -1
  75. package/dist/core/server/graphqlQuerying.js +4 -5
  76. package/dist/core/server/graphqlQuerying.js.map +1 -1
  77. package/dist/core/server/http.js +0 -179
  78. package/dist/core/server/http.js.map +1 -1
  79. package/dist/core/server/mqtt.js +3 -5
  80. package/dist/core/server/mqtt.js.map +1 -1
  81. package/dist/core/server/serverHelpers/serverUtilities.js +2 -2
  82. package/dist/core/server/serverHelpers/serverUtilities.js.map +1 -1
  83. package/dist/core/server/threads/threadServer.js +2 -26
  84. package/dist/core/server/threads/threadServer.js.map +1 -1
  85. package/dist/core/server/throttle.js +0 -17
  86. package/dist/core/server/throttle.js.map +1 -1
  87. package/dist/core/utility/environment/environmentManager.js +4 -9
  88. package/dist/core/utility/environment/environmentManager.js.map +1 -1
  89. package/dist/core/utility/environment/systemInformation.js +219 -359
  90. package/dist/core/utility/environment/systemInformation.js.map +1 -1
  91. package/dist/core/utility/hdbTerms.js +0 -1
  92. package/dist/core/utility/hdbTerms.js.map +1 -1
  93. package/dist/core/utility/operation_authorization.js +2 -2
  94. package/dist/core/utility/operation_authorization.js.map +1 -1
  95. package/npm-shrinkwrap.json +54 -974
  96. package/package.json +1 -2
  97. package/studio/web/assets/{index-qbLPhOzw.js → index-C0And10y.js} +2 -2
  98. package/studio/web/assets/{index-qbLPhOzw.js.map → index-C0And10y.js.map} +1 -1
  99. package/studio/web/index.html +1 -1
  100. package/core/dataLayer/harperBridge/TableSizeObject.ts +0 -35
  101. package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.ts +0 -24
  102. package/core/utility/environment/systemInformation.ts +0 -698
  103. package/dist/core/dataLayer/harperBridge/TableSizeObject.js +0 -32
  104. package/dist/core/dataLayer/harperBridge/TableSizeObject.js.map +0 -1
@@ -9,72 +9,73 @@ const USERS_NOT_DBS = ['super_user', 'structure_user'];
9
9
  * This is the component for handling role declarations in the Harper system. This will read roles.yaml for role
10
10
  * definitions and ensure that they are created in the system database.
11
11
  */
12
- export function handleApplication(scope: import('../components/Scope.ts').Scope) {
13
- scope.handleEntry(async (entry) => {
14
- if (entry.eventType === 'unlink') return;
15
- return handleFile(entry.contents);
16
- });
17
- }
12
+ // eslint-disable-next-line no-unused-vars
13
+ export function start({ ensureTable }) {
14
+ return {
15
+ handleFile,
16
+ setupFile: handleFile,
17
+ };
18
18
 
19
- /**
20
- * This function will handle the roles.yaml file content that has been read, and ensure that the roles are translated to
21
- * the right shape and created in the system database.
22
- * @param rolesContent
23
- */
24
- async function handleFile(rolesContent) {
25
- let rolesToDefine = parseDocument(rolesContent.toString(), { simpleKeys: true }).toJSON();
26
- for (let roleName in rolesToDefine) {
27
- let role = rolesToDefine[roleName];
28
- if (!role.permission) {
29
- // we allow the permission object to be collapsed into the root object for convenience
30
- role = {
31
- permission: role,
32
- };
33
- if (role.permission.access) {
34
- // this is the designed property object for user-defined flags and access levels
35
- role.access = role.permission.access;
36
- delete role.permission.access;
37
- }
38
- }
39
- for (let dbName in role.permission) {
40
- if (USERS_NOT_DBS.includes(dbName)) continue;
41
- let db = role.permission[dbName];
42
- if (!db.tables) {
43
- // we allow the tables object to be collapsed into the root object for convenience
44
- role.permission[dbName] = db = { tables: db };
19
+ /**
20
+ * This function will handle the roles.yaml file content that has been read, and ensure that the roles are translated to
21
+ * the right shape and created in the system database.
22
+ * @param rolesContent
23
+ */
24
+ async function handleFile(rolesContent) {
25
+ let rolesToDefine = parseDocument(rolesContent.toString(), { simpleKeys: true }).toJSON();
26
+ for (let roleName in rolesToDefine) {
27
+ let role = rolesToDefine[roleName];
28
+ if (!role.permission) {
29
+ // we allow the permission object to be collapsed into the root object for convenience
30
+ role = {
31
+ permission: role,
32
+ };
33
+ if (role.permission.access) {
34
+ // this is the designed property object for user-defined flags and access levels
35
+ role.access = role.permission.access;
36
+ delete role.permission.access;
37
+ }
45
38
  }
46
- for (let tableName in db.tables) {
47
- let table = db.tables[tableName];
48
- // ensure that all the flags are boolean
49
- table.read = Boolean(table.read);
50
- table.insert = Boolean(table.insert);
51
- table.update = Boolean(table.update);
52
- table.delete = Boolean(table.delete);
53
- if (table.attributes) {
54
- // allow attributes to be defined with an object, translating to an array
55
- let attributes = [];
56
- for (let attribute_name in table.attributes) {
57
- let attribute = table.attributes[attribute_name];
58
- attribute.attribute_name = attribute_name;
59
- attributes.push(attribute);
60
- }
61
- table.attribute_permissions = attributes;
62
- delete table.attributes;
39
+ for (let dbName in role.permission) {
40
+ if (USERS_NOT_DBS.includes(dbName)) continue;
41
+ let db = role.permission[dbName];
42
+ if (!db.tables) {
43
+ // we allow the tables object to be collapsed into the root object for convenience
44
+ role.permission[dbName] = db = { tables: db };
63
45
  }
64
- if (table.attribute_permissions) {
65
- if (!Array.isArray(table.attribute_permissions))
66
- throw new Error('attribute_permissions must be an array if defined');
67
- for (let attribute of table.attribute_permissions) {
68
- // ensure that all the flags are boolean
69
- attribute.read = Boolean(attribute.read);
70
- attribute.insert = Boolean(attribute.insert);
71
- attribute.update = Boolean(attribute.update);
46
+ for (let tableName in db.tables) {
47
+ let table = db.tables[tableName];
48
+ // ensure that all the flags are boolean
49
+ table.read = Boolean(table.read);
50
+ table.insert = Boolean(table.insert);
51
+ table.update = Boolean(table.update);
52
+ table.delete = Boolean(table.delete);
53
+ if (table.attributes) {
54
+ // allow attributes to be defined with an object, translating to an array
55
+ let attributes = [];
56
+ for (let attribute_name in table.attributes) {
57
+ let attribute = table.attributes[attribute_name];
58
+ attribute.attribute_name = attribute_name;
59
+ attributes.push(attribute);
60
+ }
61
+ table.attribute_permissions = attributes;
62
+ delete table.attributes;
72
63
  }
73
- } else table.attribute_permissions = null;
64
+ if (table.attribute_permissions) {
65
+ if (!Array.isArray(table.attribute_permissions))
66
+ throw new Error('attribute_permissions must be an array if defined');
67
+ for (let attribute of table.attribute_permissions) {
68
+ // ensure that all the flags are boolean
69
+ attribute.read = Boolean(attribute.read);
70
+ attribute.insert = Boolean(attribute.insert);
71
+ attribute.update = Boolean(attribute.update);
72
+ }
73
+ } else table.attribute_permissions = null;
74
+ }
74
75
  }
76
+ role.role = role.id = roleName;
77
+ await ensureRole(role);
75
78
  }
76
- role.role = role.id = roleName;
77
- await ensureRole(role);
78
79
  }
79
80
  }
80
81
  async function ensureRole(role) {
@@ -91,3 +92,7 @@ async function ensureRole(role) {
91
92
  }
92
93
  return addRole(role);
93
94
  }
95
+
96
+ // we can define these on the main thread
97
+ export const startOnMainThread = start;
98
+ // useful for testing
@@ -243,9 +243,7 @@ export async function authentication(request, nextHandler) {
243
243
  request.user = await server.getUser(session.user, null, request);
244
244
  } else if (
245
245
  (AUTHORIZE_LOCAL && (request.ip?.includes('127.0.0.') || request.ip == '::1')) ||
246
- (request?._nodeRequest?.socket?.server?._pipeName &&
247
- request?._nodeRequest?.socket?.server?.bypassLocalAuth &&
248
- request.ip === undefined) // allow operations API domain socket
246
+ (request?._nodeRequest?.socket?.server?._pipeName && request.ip === undefined) // allow socket domain
249
247
  ) {
250
248
  request.user = await getSuperUser();
251
249
  }
@@ -346,18 +344,19 @@ export async function authentication(request, nextHandler) {
346
344
  return response;
347
345
  }
348
346
  }
349
- setInterval(() => {
350
- authorizationCache = new Map();
351
- }, env.get(CONFIG_PARAMS.AUTHENTICATION_CACHETTL)).unref();
352
- user.addListener(() => {
353
- authorizationCache = new Map();
354
- });
355
- let started = false;
356
- export function handleApplication(scope: import('../components/Scope.ts').Scope) {
357
- if (started) return;
358
- started = true;
359
- const { port, securePort } = scope.options.getAll() as { port?: number; securePort?: number };
360
- scope.server.http(authentication, port || securePort ? { port, securePort } : { port: 'all' });
347
+ let started;
348
+ export function start({ server, port, securePort }) {
349
+ server.http(authentication, port || securePort ? { port, securePort } : { port: 'all' });
350
+ // keep it cleaned out periodically
351
+ if (!started) {
352
+ started = true;
353
+ setInterval(() => {
354
+ authorizationCache = new Map();
355
+ }, env.get(CONFIG_PARAMS.AUTHENTICATION_CACHETTL)).unref();
356
+ user.addListener(() => {
357
+ authorizationCache = new Map();
358
+ });
359
+ }
361
360
  }
362
361
  // operations
363
362
  export async function login(loginObject) {
@@ -181,13 +181,7 @@ async function loadModuleWithVM(moduleUrl: string, scope: ApplicationScope, useC
181
181
  if (parts[0] === 'file:') {
182
182
  return specifier;
183
183
  }
184
- let resolveReferrer = referrer;
185
- if (referrer.startsWith('file:')) {
186
- try {
187
- resolveReferrer = pathToFileURL(realpathSync(fileURLToPath(referrer))).toString();
188
- } catch {}
189
- }
190
- const resolved = createRequire(resolveReferrer).resolve(specifier);
184
+ const resolved = createRequire(referrer).resolve(specifier);
191
185
  if (isAbsolute(resolved)) {
192
186
  return pathToFileURL(resolved).toString();
193
187
  }
@@ -212,13 +206,7 @@ async function loadModuleWithVM(moduleUrl: string, scope: ApplicationScope, useC
212
206
  cjsModule.exports = parseJsonModule(source, url);
213
207
  return cjsModule;
214
208
  }
215
- let requireUrl = url;
216
- if (url.startsWith('file://')) {
217
- try {
218
- requireUrl = pathToFileURL(realpathSync(fileURLToPath(url))).toString();
219
- } catch {}
220
- }
221
- const require = createRequire(requireUrl);
209
+ const require = createRequire(url);
222
210
 
223
211
  const cjsRequire = (spec: string) => {
224
212
  const resolvedUrl = resolveModule(spec, url);
@@ -1,6 +1,7 @@
1
1
  import { serialize, serializeMessage, getDeserializer } from '../server/serverHelpers/contentTypes.ts';
2
2
  import { addAnalyticsListener, recordAction, recordActionBinary } from '../resources/analytics/write.ts';
3
3
  import * as harperLogger from '../utility/logging/harper_logger.js';
4
+ import { ServerOptions } from 'http';
4
5
  import { ServerError, ClientError } from '../utility/errors/hdbError.js';
5
6
  import { Resources } from '../resources/Resources.ts';
6
7
  import { Resource, missingMethod, allowedMethods } from '../resources/Resource.ts';
@@ -276,26 +277,26 @@ async function http(request: Context & Request, nextHandler) {
276
277
  }
277
278
  }
278
279
 
279
- let started = false;
280
+ let started;
280
281
  let resources: Resources;
281
282
  let addedMetrics;
282
283
  let connectionCount = 0;
283
284
 
284
- export function handleApplication(scope: import('../components/Scope.ts').Scope) {
285
- httpOptions = scope.options.getAll();
286
- if ((httpOptions as any).includeExpensiveRecordCountEstimates) {
285
+ export function start(options: ServerOptions & { path: string; port: number; server: any; resources: Resources }) {
286
+ httpOptions = options;
287
+ if (options.includeExpensiveRecordCountEstimates) {
287
288
  // If they really want to enable expensive record count estimates
288
289
  Request.prototype.includeExpensiveRecordCountEstimates = true;
289
290
  }
290
- resources = scope.resources;
291
291
  if (started) return;
292
292
  started = true;
293
- scope.server.http(async (request: Request, nextHandler) => {
293
+ resources = options.resources;
294
+ options.server.http(async (request: Request, nextHandler) => {
294
295
  if (request.isWebSocket) return;
295
296
  return http(request, nextHandler);
296
- }, httpOptions);
297
- if ((httpOptions as any).webSocket === false) return;
298
- scope.server.ws(async (ws, request, chainCompletion) => {
297
+ }, options);
298
+ if (options.webSocket === false) return;
299
+ options.server.ws(async (ws, request, chainCompletion) => {
299
300
  connectionCount++;
300
301
  const incomingMessages = new IterableEventQueue();
301
302
  if (!addedMetrics) {
@@ -381,7 +382,7 @@ export function handleApplication(scope: import('../components/Scope.ts').Scope)
381
382
  );
382
383
  }
383
384
  ws.close();
384
- }, httpOptions);
385
+ }, options);
385
386
  }
386
387
  const HTTP_TO_WEBSOCKET_CLOSE_CODES = {
387
388
  401: 3000,
@@ -1,4 +1,4 @@
1
- import { dirname, basename } from 'path';
1
+ import { dirname } from 'path';
2
2
  import { existsSync } from 'fs';
3
3
  import fastify from 'fastify';
4
4
  import fastifyCors from '@fastify/cors';
@@ -32,36 +32,35 @@ const routeFolders = new Set();
32
32
  * @param filePath
33
33
  * @param projectName
34
34
  */
35
- export function handleApplication(scope: import('../components/Scope.ts').Scope) {
35
+ export function start(options) {
36
36
  // if we have a secure port, need to use the secure HTTP server for fastify (it can be used for HTTP as well)
37
- const isHttps = (scope.options.getAll() as { securePort?: number }).securePort > 0;
38
- scope.handleEntry(async (entry) => {
39
- if (entry.eventType !== 'add') {
40
- scope.requestRestart();
41
- return;
42
- }
43
- if (!fastifyServer) {
44
- fastifyServer = buildServer(isHttps);
45
- server.http((await fastifyServer).server);
46
- }
47
- const resolvedServer = await fastifyServer;
48
- const routeFolder = dirname(entry.absolutePath);
49
- let prefix = basename(scope.appName);
50
- if (prefix.startsWith('/')) prefix = prefix.slice(1);
51
- if (!routeFolders.has(routeFolder)) {
52
- routeFolders.add(routeFolder);
53
- try {
54
- resolvedServer.register(buildRouteFolder(routeFolder, prefix));
55
- } catch (error) {
56
- if (error.message === 'Root plugin has already booted')
57
- harperLogger.warn(
58
- `Could not load root fastify route for ${entry.absolutePath}, this may require a restart to install properly`
59
- );
60
- else throw error;
37
+ const isHttps = options.securePort > 0;
38
+ return {
39
+ // eslint-disable-next-line no-unused-vars
40
+ async handleFile(jsContent, relativePath, filePath, projectName) {
41
+ if (!fastifyServer) {
42
+ fastifyServer = buildServer(isHttps);
43
+ server.http((await fastifyServer).server);
61
44
  }
62
- }
63
- await ready();
64
- });
45
+ const resolvedServer = await fastifyServer;
46
+ const routeFolder = dirname(filePath);
47
+ let prefix = dirname(relativePath);
48
+ if (prefix.startsWith('/')) prefix = prefix.slice(1);
49
+ if (!routeFolders.has(routeFolder)) {
50
+ routeFolders.add(routeFolder);
51
+ try {
52
+ resolvedServer.register(buildRouteFolder(routeFolder, prefix));
53
+ } catch (error) {
54
+ if (error.message === 'Root plugin has already booted')
55
+ harperLogger.warn(
56
+ `Could not load root fastify route for ${filePath}, this may require a restart to install properly`
57
+ );
58
+ else throw error;
59
+ }
60
+ }
61
+ },
62
+ ready,
63
+ };
65
64
  }
66
65
  /**
67
66
  * Function called to start up server instance on a forked process - this method is called from customFunctionServer after process is
@@ -119,7 +118,7 @@ async function setUp() {
119
118
  }
120
119
  }
121
120
 
122
- //
121
+ // eslint-disable-next-line require-await
123
122
  function buildRouteFolder(routesFolder, projectName) {
124
123
  return async function (cfServer) {
125
124
  try {
@@ -570,9 +570,8 @@ async function graphqlQueryingHandler(request: Request) {
570
570
  }
571
571
  }
572
572
 
573
- export function handleApplication(scope: import('../components/Scope.ts').Scope) {
574
- const { port, securePort } = scope.options.getAll() as { port?: number; securePort?: number };
575
- scope.server.http(
573
+ export function start(options) {
574
+ options.server.http(
576
575
  async (request, nextLayer) => {
577
576
  if (!request.url.startsWith('/graphql')) {
578
577
  return nextLayer(request);
@@ -696,6 +695,6 @@ export function handleApplication(scope: import('../components/Scope.ts').Scope)
696
695
  throw error;
697
696
  }
698
697
  },
699
- { port, securePort }
698
+ { port: options.port, securePort: options.securePort }
700
699
  );
701
700
  }
@@ -2,7 +2,6 @@
2
2
  * This module represents the HTTP component for Harper, and receives the HTTP options and uses them to configure
3
3
  * HTTP servers
4
4
  */
5
- import { currentThreadId } from '@harperfast/rocksdb-js';
6
5
  import { Scope } from '../components/Scope.ts';
7
6
  import { Socket } from 'node:net';
8
7
  import harperLogger from '../utility/logging/harper_logger.js';
@@ -10,7 +9,7 @@ import { parentPort } from 'node:worker_threads';
10
9
  import env from '../utility/environment/environmentManager.js';
11
10
  import * as terms from '../utility/hdbTerms.ts';
12
11
  import { getConfigPath } from '../config/configUtils.js';
13
- import { getTicketKeys, getWorkerIndex } from './threads/manageThreads.js';
12
+ import { getTicketKeys } from './threads/manageThreads.js';
14
13
  import { createTLSSelector } from '../security/keys.js';
15
14
  import { createSecureServer } from 'node:http2';
16
15
  import { createServer as createSecureServerHttp1 } from 'node:https';
@@ -20,8 +19,6 @@ import { appendHeader, Headers } from './serverHelpers/Headers.ts';
20
19
  import { Blob } from '../resources/blob.ts';
21
20
  import { recordAction, recordActionBinary } from '../resources/analytics/write.ts';
22
21
  import { Readable } from 'node:stream';
23
- import { mkdirSync, writeFileSync, unlinkSync, readdirSync } from 'node:fs';
24
- import { join } from 'node:path';
25
22
  import { server, type ServerOptions, type HttpOptions, type UpgradeOptions, UpgradeListener } from './Server.ts';
26
23
  import { setPortServerMap, SERVERS } from './serverRegistry.ts';
27
24
  import { getComponentName } from '../components/componentLoader.ts';
@@ -39,77 +36,6 @@ const httpServers = {},
39
36
  httpResponders = [];
40
37
  let httpOptions: HttpOptions = {};
41
38
  export const universalHeaders: [string, string][] = [];
42
- const udsCleanupPaths: { socketPath: string; yamlPath: string }[] = [];
43
-
44
- export function registerUdsCleanupPaths(socketPath: string, yamlPath: string) {
45
- udsCleanupPaths.push({ socketPath, yamlPath });
46
- }
47
-
48
- export function cleanupUdsFiles() {
49
- for (const { socketPath, yamlPath } of udsCleanupPaths) {
50
- try {
51
- unlinkSync(socketPath);
52
- } catch {}
53
- try {
54
- unlinkSync(yamlPath);
55
- } catch {}
56
- }
57
- }
58
-
59
- /** Write YAML metadata for a UDS mirror socket, describing the TLS certs from the corresponding secure server. */
60
- export function writeUdsMetadata(yamlPath: string, port: number | string, secureServer: any) {
61
- const contexts = secureServer.secureContexts;
62
- let yaml = `pid: ${process.pid}\ntid: ${currentThreadId()}\nport: ${port}\n`;
63
- yaml += `certificates:\n`;
64
- if (contexts?.size > 0) {
65
- const seen = new Set();
66
- for (const [, ctx] of contexts) {
67
- if (seen.has(ctx.name)) continue;
68
- seen.add(ctx.name);
69
- yaml += ` - name: ${JSON.stringify(ctx.name)}\n`;
70
- yaml += ` hostnames:\n`;
71
- for (const [h, c] of contexts) {
72
- if (c.name === ctx.name) yaml += ` - ${JSON.stringify(h)}\n`;
73
- }
74
- if (ctx.options.key_file) {
75
- yaml += ` privateKeyFile: ${JSON.stringify(join(env.get(terms.CONFIG_PARAMS.ROOTPATH), 'keys', ctx.options.key_file))}\n`;
76
- }
77
- if (ctx.options.cert) {
78
- yaml += ` certificate: |\n`;
79
- for (const line of ctx.options.cert.trimEnd().split('\n')) {
80
- yaml += ` ${line}\n`;
81
- }
82
- }
83
- if (ctx.certificateAuthorities?.length > 0) {
84
- yaml += ` certificateAuthorities:\n`;
85
- for (const [, ca] of ctx.certificateAuthorities) {
86
- yaml += ` - |\n`;
87
- for (const line of ca.trimEnd().split('\n')) {
88
- yaml += ` ${line}\n`;
89
- }
90
- }
91
- }
92
- }
93
- }
94
- try {
95
- writeFileSync(yamlPath, yaml);
96
- } catch (error) {
97
- harperLogger.error('Error writing UDS metadata to ' + yamlPath, error);
98
- }
99
- }
100
-
101
- /** Clean all files in the sockets directory. Call from main thread on process startup. */
102
- export function cleanupSocketsDirectory() {
103
- if (!env.get(terms.CONFIG_PARAMS.TLS_UNIXDOMAINSOCKETS)) return;
104
- const socketsDir = join(env.getHdbBasePath(), 'sockets');
105
- try {
106
- for (const file of readdirSync(socketsDir)) {
107
- try {
108
- unlinkSync(join(socketsDir, file));
109
- } catch {}
110
- }
111
- } catch {}
112
- }
113
39
 
114
40
  export function handleApplication(scope: Scope) {
115
41
  httpOptions = scope.options.getAll() as HttpOptions;
@@ -517,46 +443,6 @@ function getHTTPServer(port: number, secure: boolean, options: ServerOptions) {
517
443
  server.isSecure = true;
518
444
  }
519
445
  registerServer(server, port);
520
-
521
- // Operations API domain socket connections bypass auth (equivalent to local access)
522
- if (isOperationsServer && String(port).includes('/')) server.bypassLocalAuth = true;
523
-
524
- // Create a corresponding Unix Domain Socket mirror for secure ports
525
- if (secure && env.get(terms.CONFIG_PARAMS.TLS_UNIXDOMAINSOCKETS)) {
526
- const socketsDir = join(env.getHdbBasePath(), 'sockets');
527
- mkdirSync(socketsDir, { recursive: true });
528
- const socketName = `${getWorkerIndex()}-${port}`;
529
- const udsPath = join(socketsDir, `${socketName}.sock`);
530
- const yamlPath = join(socketsDir, `${socketName}.yaml`);
531
-
532
- // Create a plain HTTP server (no TLS) with the same request handler
533
- const udsServer = createServer(
534
- {
535
- keepAliveTimeout,
536
- headersTimeout,
537
- requestTimeout,
538
- highWaterMark: 128 * 1024,
539
- noDelay: true,
540
- keepAlive: true,
541
- keepAliveInitialDelay: 600,
542
- maxHeaderSize: env.get(terms.CONFIG_PARAMS.HTTP_MAXHEADERSIZE),
543
- },
544
- (nodeRequest: IncomingMessage, nodeResponse: any) => {
545
- const method = nodeRequest.method;
546
- if (method === 'GET' || method === 'OPTIONS' || method === 'HEAD') requestHandler(nodeRequest, nodeResponse);
547
- else throttledRequestHandler(nodeRequest, nodeResponse);
548
- }
549
- );
550
-
551
- udsServer.isPerThreadSocket = true;
552
- enableProxyProtocol(udsServer);
553
- SERVERS[udsPath] = udsServer;
554
- registerUdsCleanupPaths(udsPath, yamlPath);
555
-
556
- const writeMetadata = () => writeUdsMetadata(yamlPath, port, server);
557
- options.SNICallback.ready.then(writeMetadata);
558
- server.secureContextsListeners.push(writeMetadata);
559
- }
560
446
  }
561
447
  return httpServers[port];
562
448
  }
@@ -698,66 +584,6 @@ function onWebSocket(listener: (ws: WebSocket) => void, options: OnWebSocketOpti
698
584
  return servers;
699
585
  }
700
586
 
701
- // PROXY protocol v1 max header length per spec: 108 bytes
702
- const PROXY_V1_MAX_HEADER = 108;
703
-
704
- function enableProxyProtocol(httpServer) {
705
- // In Node.js v24+, the HTTP parser's data path goes through the C++ stream layer
706
- // and does not call socket.emit('data') via JavaScript method dispatch.
707
- // Overriding socket.emit or socket.push has no effect on the HTTP parser's data intake.
708
- //
709
- // Instead: use process.nextTick inside the 'connection' handler to wrap the HTTP
710
- // parser's 'data' listener after it has been registered (synchronously, by the HTTP
711
- // parser's own 'connection' handler which runs right after ours).
712
- // process.nextTick fires before any I/O callbacks, so it is guaranteed to run before
713
- // the first network data chunk reaches the socket — making the interception race-free.
714
- httpServer.prependListener('connection', (socket) => {
715
- process.nextTick(() => {
716
- // Capture the HTTP parser's 'data' listener(s) registered during this connection event.
717
- const dataListeners = socket.listeners('data') as ((chunk: Buffer) => void)[];
718
- if (dataListeners.length === 0) return;
719
- socket.removeAllListeners('data');
720
-
721
- let proxyDone = false;
722
- socket.on('data', (chunk: Buffer) => {
723
- if (!proxyDone) {
724
- proxyDone = true;
725
- // Fast path: PROXY v1 always starts with "PROXY " (0x50 0x52 0x4f 0x58 0x59 0x20)
726
- if (
727
- chunk.length >= 6 &&
728
- chunk[0] === 0x50 &&
729
- chunk[1] === 0x52 &&
730
- chunk[2] === 0x4f &&
731
- chunk[3] === 0x58 &&
732
- chunk[4] === 0x59 &&
733
- chunk[5] === 0x20
734
- ) {
735
- const header = chunk.toString('latin1', 0, Math.min(PROXY_V1_MAX_HEADER, chunk.length));
736
- const eol = header.indexOf('\r\n');
737
- if (eol !== -1) {
738
- // "PROXY TCP4 <src-ip> <dst-ip> <src-port> <dst-port>"
739
- const parts = header.slice(0, eol).split(' ');
740
- if (parts.length === 6) {
741
- // Override the UDS socket's undefined remoteAddress/remotePort with the real client values.
742
- Object.defineProperty(socket, 'remoteAddress', { value: parts[2], configurable: true });
743
- Object.defineProperty(socket, 'remotePort', { value: parseInt(parts[4], 10), configurable: true });
744
- }
745
- // Forward only the bytes after the PROXY header to the HTTP parser.
746
- const rest = chunk.subarray(eol + 2);
747
- if (rest.length > 0) {
748
- for (const listener of dataListeners) listener.call(socket, rest);
749
- }
750
- return;
751
- }
752
- }
753
- }
754
- // Not a PROXY header (or already handled) — forward unchanged.
755
- for (const listener of dataListeners) listener.call(socket, chunk);
756
- });
757
- });
758
- });
759
- }
760
-
761
587
  function defaultNotFound(request, response) {
762
588
  if (response.headersSent || response.writableEnded) return;
763
589
  response.writeHead(404);
@@ -23,14 +23,7 @@ export function bypassAuth() {
23
23
  const authorizeLocal = (remoteAddress: string) =>
24
24
  AUTHORIZE_LOCAL && (remoteAddress.includes('127.0.0.') || remoteAddress === '::1');
25
25
 
26
- export function handleApplication(scope: import('../components/Scope.ts').Scope) {
27
- const { network, webSocket, requireAuthentication } = scope.options.getAll() as {
28
- network?: any;
29
- webSocket?: any;
30
- requireAuthentication?: boolean;
31
- };
32
- const server = scope.server;
33
- const { port, securePort } = network ?? {};
26
+ export function start({ server, port, network, webSocket, securePort, requireAuthentication }) {
34
27
  // here we basically normalize the different types of sockets to pass to our socket/message handler
35
28
  if (!server.mqtt) {
36
29
  server.mqtt = {
@@ -167,6 +160,7 @@ export function handleApplication(scope: import('../components/Scope.ts').Scope)
167
160
  )
168
161
  );
169
162
  }
163
+ return serverInstances;
170
164
  }
171
165
  let addingMetrics,
172
166
  numberOfConnections = 0;
@@ -19,7 +19,7 @@ import restart from '../../bin/restart.js';
19
19
  import * as util from 'util';
20
20
  import insert from '../../dataLayer/insert.js';
21
21
  import globalSchema from '../../utility/globalSchema.js';
22
- import { systemInformation } from '../../utility/environment/systemInformation.ts';
22
+ import systemInformation from '../../utility/environment/systemInformation.js';
23
23
  import jobRunner from '../jobs/jobRunner.js';
24
24
  import * as tokenAuthentication from '../../security/tokenAuthentication.ts';
25
25
  import * as auth from '../../security/auth.ts';
@@ -363,7 +363,10 @@ function initializeOperationFunctionMap(): Map<OperationFunctionName, OperationF
363
363
  opFuncMap.set(terms.OPERATIONS_ENUM.RESTART, new OperationFunctionObject(restart.restart));
364
364
  opFuncMap.set(terms.OPERATIONS_ENUM.RESTART_SERVICE, new OperationFunctionObject(executeJob, restart.restartService));
365
365
  opFuncMap.set(terms.OPERATIONS_ENUM.CATCHUP, new OperationFunctionObject(catchup));
366
- opFuncMap.set(terms.OPERATIONS_ENUM.SYSTEM_INFORMATION, new OperationFunctionObject(systemInformation));
366
+ opFuncMap.set(
367
+ terms.OPERATIONS_ENUM.SYSTEM_INFORMATION,
368
+ new OperationFunctionObject(systemInformation.systemInformation)
369
+ );
367
370
  opFuncMap.set(
368
371
  terms.OPERATIONS_ENUM.DELETE_AUDIT_LOGS_BEFORE,
369
372
  new OperationFunctionObject(executeJob, delete_.deleteAuditLogsBefore)