@harperfast/harper 5.2.0 → 5.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/copyDb.ts +40 -11
- package/bin/harper.ts +20 -51
- package/bin/help.ts +216 -0
- package/components/Application.ts +236 -46
- package/components/ApplicationScope.ts +26 -0
- package/components/EntryHandler.ts +410 -105
- package/components/RuntimeModuleTracker.ts +189 -0
- package/components/Scope.ts +68 -24
- package/components/componentLoader.ts +70 -16
- package/components/deployLifecycle.ts +119 -33
- package/components/deploymentRecorder.ts +102 -11
- package/components/mcp/tools/operations.ts +6 -0
- package/components/operations.js +8 -6
- package/config/configUtils.ts +78 -20
- package/config/harperConfigEnvVars.ts +114 -17
- package/config-root.schema.json +10 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +26 -5
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -4
- package/dataLayer/hdbInfoController.ts +8 -0
- package/dataLayer/schemaDescribe.ts +2 -1
- package/dist/bin/copyDb.js +33 -9
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/harper.d.ts +6 -0
- package/dist/bin/harper.js +18 -50
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.d.ts +8 -0
- package/dist/bin/help.js +192 -0
- package/dist/bin/help.js.map +1 -0
- package/dist/components/Application.d.ts +16 -1
- package/dist/components/Application.js +210 -38
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +7 -0
- package/dist/components/ApplicationScope.js +22 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.d.ts +4 -4
- package/dist/components/EntryHandler.js +386 -95
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.d.ts +11 -0
- package/dist/components/RuntimeModuleTracker.js +189 -0
- package/dist/components/RuntimeModuleTracker.js.map +1 -0
- package/dist/components/Scope.d.ts +1 -0
- package/dist/components/Scope.js +69 -22
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +69 -10
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deployLifecycle.d.ts +6 -2
- package/dist/components/deployLifecycle.js +109 -31
- package/dist/components/deployLifecycle.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +6 -0
- package/dist/components/deploymentRecorder.js +94 -12
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/tools/operations.js +6 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/operations.js +8 -6
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +6 -0
- package/dist/config/configUtils.js +78 -18
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.js +108 -16
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +12 -5
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +4 -4
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.js +4 -0
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +2 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +57 -0
- package/dist/resources/DatabaseTransaction.js +284 -104
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +8 -2
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/Resources.js +22 -4
- package/dist/resources/Resources.js.map +1 -1
- package/dist/resources/Table.d.ts +8 -6
- package/dist/resources/Table.js +158 -31
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +6 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.js +27 -1
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +0 -1
- package/dist/resources/blob.js +15 -7
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/databases.d.ts +22 -5
- package/dist/resources/databases.js +118 -9
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +15 -2
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +128 -39
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/jsResource.d.ts +4 -26
- package/dist/resources/jsResource.js +5 -59
- package/dist/resources/jsResource.js.map +1 -1
- package/dist/resources/models/Models.d.ts +11 -1
- package/dist/resources/models/Models.js +10 -1
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +9 -0
- package/dist/resources/models/backendRegistry.js +10 -0
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/openaiStream.d.ts +16 -1
- package/dist/resources/models/openaiStream.js +113 -21
- package/dist/resources/models/openaiStream.js.map +1 -1
- package/dist/resources/models/v1/chatCompletions.d.ts +54 -0
- package/dist/resources/models/v1/chatCompletions.js +115 -0
- package/dist/resources/models/v1/chatCompletions.js.map +1 -0
- package/dist/resources/models/v1/embeddings.d.ts +11 -0
- package/dist/resources/models/v1/embeddings.js +71 -0
- package/dist/resources/models/v1/embeddings.js.map +1 -0
- package/dist/resources/models/v1/errors.d.ts +54 -0
- package/dist/resources/models/v1/errors.js +130 -0
- package/dist/resources/models/v1/errors.js.map +1 -0
- package/dist/resources/models/v1/index.d.ts +36 -0
- package/dist/resources/models/v1/index.js +75 -0
- package/dist/resources/models/v1/index.js.map +1 -0
- package/dist/resources/models/v1/models.d.ts +26 -0
- package/dist/resources/models/v1/models.js +44 -0
- package/dist/resources/models/v1/models.js.map +1 -0
- package/dist/resources/models/v1/translation.d.ts +133 -0
- package/dist/resources/models/v1/translation.js +298 -0
- package/dist/resources/models/v1/translation.js.map +1 -0
- package/dist/resources/roles.d.ts +1 -1
- package/dist/resources/roles.js +54 -7
- package/dist/resources/roles.js.map +1 -1
- package/dist/resources/search.d.ts +1 -1
- package/dist/resources/search.js +7 -3
- package/dist/resources/search.js.map +1 -1
- package/dist/security/jsLoader.js +84 -33
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/role.js +4 -0
- package/dist/security/role.js.map +1 -1
- package/dist/security/superUserGuard.d.ts +7 -0
- package/dist/security/superUserGuard.js +23 -0
- package/dist/security/superUserGuard.js.map +1 -0
- package/dist/security/tokenAuthentication.d.ts +0 -1
- package/dist/security/tokenAuthentication.js +6 -2
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.d.ts +6 -1
- package/dist/security/user.js +23 -1
- package/dist/security/user.js.map +1 -1
- package/dist/server/http.d.ts +23 -2
- package/dist/server/http.js +99 -12
- package/dist/server/http.js.map +1 -1
- package/dist/server/operationsServer.d.ts +0 -2
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/multipartParser.js +9 -0
- package/dist/server/serverHelpers/multipartParser.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +2 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +13 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -0
- package/dist/server/serverHelpers/registeredOperations.d.ts +3 -2
- package/dist/server/serverHelpers/registeredOperations.js +14 -13
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/serverHandlers.js +19 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +1 -1
- package/dist/server/serverHelpers/serverUtilities.js +10 -7
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/static.js +57 -18
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +17 -0
- package/dist/server/storageReclamation.js +90 -6
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/manageThreads.js +8 -0
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.js +20 -0
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadServer.js +12 -0
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/diff/differential.js +7 -3
- package/dist/sqlEngine/diff/differential.js.map +1 -1
- package/dist/sqlEngine/parser/normalizer.js +37 -9
- package/dist/sqlEngine/parser/normalizer.js.map +1 -1
- package/dist/sqlTranslator/index.js +6 -1
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/upgradePrompt.d.ts +2 -2
- package/dist/upgrade/upgradePrompt.js +22 -3
- package/dist/upgrade/upgradePrompt.js.map +1 -1
- package/dist/utility/environment/environmentManager.d.ts +11 -0
- package/dist/utility/environment/environmentManager.js +154 -0
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +1 -0
- package/dist/utility/errors/commonErrors.js +1 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/hdbTerms.d.ts +2 -0
- package/dist/utility/hdbTerms.js +2 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/install/installer.js +32 -0
- package/dist/utility/install/installer.js.map +1 -1
- package/dist/utility/lmdb/environmentUtility.js +2 -1
- package/dist/utility/lmdb/environmentUtility.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +7 -0
- package/dist/utility/logging/harper_logger.js +57 -24
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/npm-shrinkwrap.json +208 -198
- package/package.json +10 -8
- package/resources/DESIGN.md +1 -0
- package/resources/DatabaseTransaction.ts +313 -102
- package/resources/ResourceInterface.ts +8 -2
- package/resources/Resources.ts +22 -4
- package/resources/Table.ts +398 -259
- package/resources/analytics/write.ts +22 -20
- package/resources/auditStore.ts +32 -1
- package/resources/blob.ts +15 -8
- package/resources/databases.ts +123 -12
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +119 -45
- package/resources/jsResource.ts +5 -62
- package/resources/models/Models.ts +14 -1
- package/resources/models/backendRegistry.ts +10 -0
- package/resources/models/openaiStream.ts +131 -19
- package/resources/models/v1/chatCompletions.ts +128 -0
- package/resources/models/v1/embeddings.ts +70 -0
- package/resources/models/v1/errors.ts +141 -0
- package/resources/models/v1/index.ts +72 -0
- package/resources/models/v1/models.ts +53 -0
- package/resources/models/v1/translation.ts +362 -0
- package/resources/roles.ts +67 -7
- package/resources/search.ts +8 -3
- package/security/jsLoader.ts +84 -30
- package/security/role.ts +7 -0
- package/security/superUserGuard.ts +20 -0
- package/security/tokenAuthentication.ts +6 -3
- package/security/user.ts +26 -1
- package/server/DESIGN.md +45 -34
- package/server/http.ts +100 -13
- package/server/operationsServer.ts +0 -2
- package/server/serverHelpers/multipartParser.ts +9 -0
- package/server/serverHelpers/operationAuthorizationState.ts +11 -0
- package/server/serverHelpers/registeredOperations.ts +19 -15
- package/server/serverHelpers/serverHandlers.js +20 -3
- package/server/serverHelpers/serverUtilities.ts +10 -7
- package/server/static.ts +75 -20
- package/server/storageReclamation.ts +104 -8
- package/server/threads/manageThreads.js +8 -0
- package/server/threads/socketRouter.ts +20 -0
- package/server/threads/threadServer.js +11 -0
- package/sqlTranslator/index.ts +6 -1
- package/static/defaultConfig.yaml +2 -0
- package/studio/web/assets/{Chat-DoVWScmq.js → Chat-BMUjPklt.js} +5 -5
- package/studio/web/assets/{Chat-DoVWScmq.js.map → Chat-BMUjPklt.js.map} +1 -1
- package/studio/web/assets/{FloatingChat-UZ2NsUOZ.js → FloatingChat-Cbghuxe5.js} +5 -5
- package/studio/web/assets/{FloatingChat-UZ2NsUOZ.js.map → FloatingChat-Cbghuxe5.js.map} +1 -1
- package/studio/web/assets/{apiToken-BUI_04o7.js → apiToken-CkgTQAqc.js} +2 -2
- package/studio/web/assets/{apiToken-BUI_04o7.js.map → apiToken-CkgTQAqc.js.map} +1 -1
- package/studio/web/assets/{applications-D03NA7wW.js → applications-WvF4NOTN.js} +13 -13
- package/studio/web/assets/applications-WvF4NOTN.js.map +1 -0
- package/studio/web/assets/chevron-right-anDJCGlp.js +2 -0
- package/studio/web/assets/chevron-right-anDJCGlp.js.map +1 -0
- package/studio/web/assets/index-CDeqVx71.css +1 -0
- package/studio/web/assets/index-Sevt3MVx.js +819 -0
- package/studio/web/assets/index-Sevt3MVx.js.map +1 -0
- package/studio/web/assets/index.lazy-Dg5YYPGg.js +14 -0
- package/studio/web/assets/{index.lazy-Dx3MpyDC.js.map → index.lazy-Dg5YYPGg.js.map} +1 -1
- package/studio/web/assets/{jsonMode-Cjj7dtlr.js → jsonMode-CBSEleE7.js} +2 -2
- package/studio/web/assets/{jsonMode-Cjj7dtlr.js.map → jsonMode-CBSEleE7.js.map} +1 -1
- package/studio/web/assets/languageServices-gxedeeTo.js +2 -0
- package/studio/web/assets/languageServices-gxedeeTo.js.map +1 -0
- package/studio/web/assets/{notifications-0edoFTsb.js → notifications-Ap84YyQp.js} +2 -2
- package/studio/web/assets/{notifications-0edoFTsb.js.map → notifications-Ap84YyQp.js.map} +1 -1
- package/studio/web/assets/notifications-vehqyOLM.js +2 -0
- package/studio/web/assets/{notifications-CwKhipK7.js.map → notifications-vehqyOLM.js.map} +1 -1
- package/studio/web/assets/{pollUnlessForbidden-HHdQZW1N.js → pollUnlessForbidden-BhzefVRn.js} +2 -2
- package/studio/web/assets/pollUnlessForbidden-BhzefVRn.js.map +1 -0
- package/studio/web/assets/{profile-DUfEPQtx.js → profile-DzDpRLHY.js} +2 -2
- package/studio/web/assets/{profile-DUfEPQtx.js.map → profile-DzDpRLHY.js.map} +1 -1
- package/studio/web/assets/queryClient-CgtkoiCY.js +2 -0
- package/studio/web/assets/queryClient-CgtkoiCY.js.map +1 -0
- package/studio/web/assets/regions-DpJ8s7iN.js +2 -0
- package/studio/web/assets/regions-DpJ8s7iN.js.map +1 -0
- package/studio/web/assets/register-BDy01-q3.js +3 -0
- package/studio/web/assets/register-BDy01-q3.js.map +1 -0
- package/studio/web/assets/register-CQHRwNP4.js +3 -0
- package/studio/web/assets/register-CQHRwNP4.js.map +1 -0
- package/studio/web/assets/{setComponentFile-DMPo4UjC.js → setComponentFile-D0aPcI3W.js} +2 -2
- package/studio/web/assets/{setComponentFile-DMPo4UjC.js.map → setComponentFile-D0aPcI3W.js.map} +1 -1
- package/studio/web/assets/setup-I15FAF9H.js +3 -0
- package/studio/web/assets/{setup-B56Oz1_u.js.map → setup-I15FAF9H.js.map} +1 -1
- package/studio/web/assets/status-BF1eJshJ.js +62 -0
- package/studio/web/assets/status-BF1eJshJ.js.map +1 -0
- package/studio/web/assets/{swagger-ui-react-lQrBxfwM.js → swagger-ui-react-DwSPXXhl.js} +2 -2
- package/studio/web/assets/{swagger-ui-react-lQrBxfwM.js.map → swagger-ui-react-DwSPXXhl.js.map} +1 -1
- package/studio/web/assets/{textarea-DhLMZ3PA.js → table-DpOjNQHt.js} +2 -10
- package/studio/web/assets/table-DpOjNQHt.js.map +1 -0
- package/studio/web/assets/{tsMode-CrHCRjTK.js → tsMode-Bu51A-VG.js} +2 -2
- package/studio/web/assets/{tsMode-CrHCRjTK.js.map → tsMode-Bu51A-VG.js.map} +1 -1
- package/studio/web/assets/{useEntityRestURL-DoaBMEvU.js → useEntityRestURL-DrV1zMrN.js} +2 -2
- package/studio/web/assets/{useEntityRestURL-DoaBMEvU.js.map → useEntityRestURL-DrV1zMrN.js.map} +1 -1
- package/studio/web/index.html +6 -7
- package/upgrade/upgradePrompt.ts +22 -3
- package/utility/environment/environmentManager.ts +152 -0
- package/utility/errors/commonErrors.ts +2 -0
- package/utility/hdbTerms.ts +2 -0
- package/utility/install/installer.ts +37 -0
- package/utility/lmdb/environmentUtility.ts +2 -1
- package/utility/logging/harper_logger.ts +57 -26
- package/studio/web/assets/applications-D03NA7wW.js.map +0 -1
- package/studio/web/assets/index-Bh_CNAHr.js +0 -809
- package/studio/web/assets/index-Bh_CNAHr.js.map +0 -1
- package/studio/web/assets/index-C8Mv9kHV.css +0 -1
- package/studio/web/assets/index.lazy-Dx3MpyDC.js +0 -14
- package/studio/web/assets/notifications-CwKhipK7.js +0 -2
- package/studio/web/assets/pollUnlessForbidden-HHdQZW1N.js.map +0 -1
- package/studio/web/assets/queryClient-CbA8wM7J.js +0 -2
- package/studio/web/assets/queryClient-CbA8wM7J.js.map +0 -1
- package/studio/web/assets/setup-B56Oz1_u.js +0 -3
- package/studio/web/assets/status-BAod7p3o.js +0 -62
- package/studio/web/assets/status-BAod7p3o.js.map +0 -1
- package/studio/web/assets/textarea-DhLMZ3PA.js.map +0 -1
|
@@ -9,6 +9,7 @@ import * as commonUtils from '../common_utils.ts';
|
|
|
9
9
|
import * as hdbTerms from '../hdbTerms.ts';
|
|
10
10
|
import * as configUtils from '../../config/configUtils.ts';
|
|
11
11
|
import { mkdirSync } from 'node:fs';
|
|
12
|
+
import { workerData } from 'node:worker_threads';
|
|
12
13
|
|
|
13
14
|
const INIT_ERR = 'Error initializing environment manager';
|
|
14
15
|
const BOOT_PROPS_FILE_PATH = 'BOOT_PROPS_FILE_PATH';
|
|
@@ -24,6 +25,19 @@ const installPropsToSave = {
|
|
|
24
25
|
let installProps: any = {};
|
|
25
26
|
export { BOOT_PROPS_FILE_PATH };
|
|
26
27
|
|
|
28
|
+
// Every param passed to setProperty() on this thread, keyed by its canonical config param so
|
|
29
|
+
// aliases collapse to one last-write-wins entry. Workers inherit this map (getConfigOverrides() and
|
|
30
|
+
// the workerDataProvider registration in server/threads/manageThreads.js) and it is replayed after
|
|
31
|
+
// a forced config reload; `base` is the configured value the override displaced, which is how
|
|
32
|
+
// reapplyAllOverrides() tells a reload that left the param alone from one that is itself the change.
|
|
33
|
+
//
|
|
34
|
+
// setProperty() therefore means operator/harness *intent* only. Code caching a value it derived
|
|
35
|
+
// from config it just read (initializePaths.js, utility/lmdb/environmentUtility.ts) must call
|
|
36
|
+
// configUtils.updateConfigObject() directly, or the derived value outlives what it was derived from
|
|
37
|
+
// and ships to every worker as an override.
|
|
38
|
+
const appliedOverrides = new Map<string, { value: any; base: any }>();
|
|
39
|
+
let inheritedOverridesApplied = false;
|
|
40
|
+
|
|
27
41
|
/**
|
|
28
42
|
* The base path of the HDB install is often referenced, but is referenced as a const variable at the top of many
|
|
29
43
|
* modules. This is a problem during install, as the path may not yet be defined. We offer a function to get the
|
|
@@ -62,11 +76,42 @@ export function get(propName: string): any {
|
|
|
62
76
|
* Note - this function will NOT update the config file. If you want to update the file
|
|
63
77
|
* use the updateConfigValue method in configUtils.
|
|
64
78
|
*
|
|
79
|
+
* The override is also recorded so it propagates to every worker thread spawned from here and
|
|
80
|
+
* survives a forced config reload — except a reload that changes this param on disk, which wins
|
|
81
|
+
* and retires the override (see reapplyAllOverrides()). `value` must be structured-cloneable.
|
|
82
|
+
*
|
|
65
83
|
* This function should only be used by the installer and unit tests.
|
|
66
84
|
* @param propName
|
|
67
85
|
* @param value
|
|
68
86
|
*/
|
|
69
87
|
export function setProperty(propName: string, value: any) {
|
|
88
|
+
// Snapshot rather than keep the caller's reference: initializePaths.js and environmentUtility.ts
|
|
89
|
+
// cache derived per-database paths by mutating the live `databases` value in place, which is
|
|
90
|
+
// often the very object handed to setProperty. Cloning here also settles cloneability at the
|
|
91
|
+
// caller that can still fix it — manageThreads.js's provider only logs a clone failure and
|
|
92
|
+
// spawns the worker on the on-disk config anyway.
|
|
93
|
+
let snapshot;
|
|
94
|
+
try {
|
|
95
|
+
snapshot = structuredClone(value);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
throw new Error(`Config property '${propName}' cannot be set to a value that is not structured-cloneable`, {
|
|
98
|
+
cause: err,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Key by the canonical param name, not the raw alias passed in: CONFIG_PARAM_MAP is many-to-one
|
|
103
|
+
// (e.g. SERVER_PORT_KEY and OPERATIONSAPI_NETWORK_PORT both canonicalize to
|
|
104
|
+
// 'operationsApi_network_port'), and replay of a stale alias after the canonical one would
|
|
105
|
+
// reintroduce the parent/worker skew this map exists to prevent.
|
|
106
|
+
const canonicalName = (hdbTerms.CONFIG_PARAM_MAP as any)[propName.toLowerCase()] ?? propName;
|
|
107
|
+
const existing = appliedOverrides.get(canonicalName);
|
|
108
|
+
appliedOverrides.set(canonicalName, {
|
|
109
|
+
value: snapshot,
|
|
110
|
+
// Keep the first override's base: everything after it displaced an override, not a
|
|
111
|
+
// configured value, so it says nothing about what the config file held.
|
|
112
|
+
base: existing ? existing.base : snapshotConfigValue(configUtils.getConfigValue(propName)),
|
|
113
|
+
});
|
|
114
|
+
|
|
70
115
|
if (installPropsToSave[propName]) {
|
|
71
116
|
installProps[propName] = value;
|
|
72
117
|
}
|
|
@@ -74,6 +119,98 @@ export function setProperty(propName: string, value: any) {
|
|
|
74
119
|
configUtils.updateConfigObject(propName, value);
|
|
75
120
|
}
|
|
76
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Every config override applied on this thread via setProperty(), for propagation to worker
|
|
124
|
+
* threads spawned from here (see server/threads/manageThreads.js's 'configOverrides'
|
|
125
|
+
* workerData provider). Returns undefined when nothing has been overridden, so a normal
|
|
126
|
+
* production boot contributes no extra workerData.
|
|
127
|
+
*/
|
|
128
|
+
export function getConfigOverrides(): Record<string, any> | undefined {
|
|
129
|
+
if (!appliedOverrides.size) return undefined;
|
|
130
|
+
const overrides = {};
|
|
131
|
+
for (const [propName, { value }] of appliedOverrides) {
|
|
132
|
+
overrides[propName] = value;
|
|
133
|
+
}
|
|
134
|
+
return overrides;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Replays the parent thread's config overrides (received via workerData) on THIS thread, so a
|
|
139
|
+
* worker's effective config matches its parent's rather than silently falling back to whatever
|
|
140
|
+
* is installed on disk. Applied once per thread, right after the on-disk config is first read —
|
|
141
|
+
* see initSync(). A later forced re-init is handled separately by reapplyAllOverrides(), since by
|
|
142
|
+
* then these inherited values are already folded into appliedOverrides.
|
|
143
|
+
*/
|
|
144
|
+
function applyInheritedConfigOverrides() {
|
|
145
|
+
const inherited = (workerData as any)?.configOverrides;
|
|
146
|
+
if (!inherited) return;
|
|
147
|
+
for (const propName of Object.keys(inherited)) {
|
|
148
|
+
setProperty(propName, inherited[propName]);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Detached copy of a config value; falls back to the value itself for the (unreached) non-cloneable case. */
|
|
153
|
+
function snapshotConfigValue(value: any) {
|
|
154
|
+
try {
|
|
155
|
+
return structuredClone(value);
|
|
156
|
+
} catch {
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Key-ordering is a YAML formatting choice, not a config change, so it must not affect equality. */
|
|
162
|
+
function stableStringify(value: any) {
|
|
163
|
+
if (value === null || typeof value !== 'object') return JSON.stringify(value);
|
|
164
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;
|
|
165
|
+
return `{${Object.keys(value)
|
|
166
|
+
.sort()
|
|
167
|
+
.map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`)
|
|
168
|
+
.join(',')}}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* A reload rebuilds config values into fresh objects, so identity says nothing about whether the
|
|
173
|
+
* file changed. Anything this cannot serialize (a cyclic value, which structuredClone accepts)
|
|
174
|
+
* counts as changed rather than throwing out of the reload path — initSync()'s catch exits the
|
|
175
|
+
* process.
|
|
176
|
+
*/
|
|
177
|
+
function sameConfigValue(a: any, b: any) {
|
|
178
|
+
if (Object.is(a, b)) return true;
|
|
179
|
+
if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false;
|
|
180
|
+
try {
|
|
181
|
+
return stableStringify(a) === stableStringify(b);
|
|
182
|
+
} catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Replays this thread's overrides on top of a config that was just re-read from disk. A forced
|
|
189
|
+
* initSync() rebuilds the whole config, which would otherwise revert the thread to the on-disk
|
|
190
|
+
* config regardless of any overrides — the same defect applyInheritedConfigOverrides() closes for a
|
|
191
|
+
* worker's first boot, but for a reload on any thread, main included.
|
|
192
|
+
*
|
|
193
|
+
* An override does NOT survive a reload that changed its own param on disk. A forced reload is how
|
|
194
|
+
* an operator's config edit takes effect (the RESTART handlers in security/keys.ts and
|
|
195
|
+
* processManagement.js), so replaying unconditionally would make editing an overridden param a
|
|
196
|
+
* silent no-op for the life of the process. The edit is the newer intent, so the override retires
|
|
197
|
+
* entirely — dropped from the map, so it stops reaching newly spawned workers as well.
|
|
198
|
+
*
|
|
199
|
+
* Call only after configUtils.initConfig(force) has repopulated the config from disk.
|
|
200
|
+
*/
|
|
201
|
+
function reapplyAllOverrides() {
|
|
202
|
+
if (appliedOverrides.size === 0) return;
|
|
203
|
+
// Iterate a snapshot: setProperty() re-inserts into appliedOverrides as we go.
|
|
204
|
+
for (const [propName, { value, base }] of [...appliedOverrides]) {
|
|
205
|
+
if (!sameConfigValue(configUtils.getConfigValue(propName), base)) {
|
|
206
|
+
appliedOverrides.delete(propName);
|
|
207
|
+
log.notify(`Config reload changed '${propName}'; dropping this thread's in-process override of it`);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
setProperty(propName, value);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
77
214
|
/**
|
|
78
215
|
* Checks to see if the Harper boot props file exists.
|
|
79
216
|
* If it does, it grabs the install user and settings path for future reference.
|
|
@@ -108,6 +245,21 @@ export function initSync(force: boolean = false) {
|
|
|
108
245
|
try {
|
|
109
246
|
if (propFileExists || doesPropFileExist() || commonUtils.noBootFile() || force) {
|
|
110
247
|
configUtils.initConfig(force);
|
|
248
|
+
if (!inheritedOverridesApplied) {
|
|
249
|
+
inheritedOverridesApplied = true;
|
|
250
|
+
applyInheritedConfigOverrides();
|
|
251
|
+
}
|
|
252
|
+
// force implies the on-disk config was just re-read from scratch, which would otherwise
|
|
253
|
+
// silently drop every override applied on this thread so far (inherited or local) —
|
|
254
|
+
// except the ones the re-read itself changed, which the config file wins.
|
|
255
|
+
if (force) reapplyAllOverrides();
|
|
256
|
+
|
|
257
|
+
// Sync installProps' HDB_ROOT from the config's rootPath *after* any override replay
|
|
258
|
+
// above (not before): setProperty() records a rootPath override under its canonical
|
|
259
|
+
// CONFIG_PARAM_MAP name, not under HDB_ROOT_KEY, so replaying it doesn't retrigger this
|
|
260
|
+
// same side effect below in setProperty() — this sync is what makes getHdbBasePath()
|
|
261
|
+
// track an isolated rootPath override instead of staying pinned to whatever the pre-replay
|
|
262
|
+
// disk read produced.
|
|
111
263
|
const configHdbRoot = configUtils.getConfigValue(hdbTerms.HDB_SETTINGS_NAMES.HDB_ROOT_KEY);
|
|
112
264
|
// Only overwrite if we actually got a value from config
|
|
113
265
|
if (configHdbRoot !== undefined) {
|
|
@@ -200,6 +200,8 @@ const USER_ERROR_MSGS = {
|
|
|
200
200
|
ALTER_USER_ROLE_NOT_FOUND: (role) => `Update failed. Requested '${role}' role not found.`,
|
|
201
201
|
DUP_ROLES_FOUND: (role) =>
|
|
202
202
|
`Multiple ${role} roles found. Roles must have unique 'role' value. Please update and try again.`,
|
|
203
|
+
LAST_SUPER_USER:
|
|
204
|
+
'Rejected: this change would leave the instance with no active super_user. Grant super_user to another active user first.',
|
|
203
205
|
ROLE_NAME_NOT_FOUND: (role) => `${role} role not found`,
|
|
204
206
|
USER_ALREADY_EXISTS: (user) => `User ${user} already exists`,
|
|
205
207
|
USER_NOT_EXIST: (user) => `User ${user} does not exist`,
|
package/utility/hdbTerms.ts
CHANGED
|
@@ -553,6 +553,7 @@ export const CONFIG_PARAMS = {
|
|
|
553
553
|
LICENSE_MODE: 'license_mode',
|
|
554
554
|
LICENSE_REGION: 'license_region',
|
|
555
555
|
LOCALSTUDIO_ENABLED: 'localStudio_enabled',
|
|
556
|
+
MODELSGATEWAY_ENABLED: 'modelsGateway_enabled',
|
|
556
557
|
LOGGING_COLORS: 'logging_colors',
|
|
557
558
|
LOGGING_CONSOLE: 'logging_console',
|
|
558
559
|
LOGGING_FILE: 'logging_file',
|
|
@@ -693,6 +694,7 @@ export const CONFIG_PARAMS = {
|
|
|
693
694
|
STORAGE_TRANSACTIONLOG_COOLINGINTERVAL: 'storage_transactionLog_coolingInterval',
|
|
694
695
|
STORAGE_ENGINE: 'storage_engine',
|
|
695
696
|
STORAGE_READONLY: 'storage_readOnly',
|
|
697
|
+
STORAGE_ROCKS_COMPRESSION: 'storage_rocks_compression',
|
|
696
698
|
STORAGE_ROCKS_BLOCKCACHESIZE: 'storage_rocks_blockCacheSize',
|
|
697
699
|
STORAGE_ROCKS_WRITEBUFFERMANAGERSIZE: 'storage_rocks_writeBufferManagerSize',
|
|
698
700
|
STORAGE_ROCKS_WRITEBUFFERMANAGERCOSTTOCACHE: 'storage_rocks_writeBufferManagerCostToCache',
|
|
@@ -19,6 +19,7 @@ import * as hdbTerms from '../hdbTerms.ts';
|
|
|
19
19
|
const { CONFIG_PARAMS } = hdbTerms;
|
|
20
20
|
import installValidator from '../../validation/installValidator.ts';
|
|
21
21
|
import mountHdb from '../mount_hdb.ts';
|
|
22
|
+
import { composeConfigFromEnv } from '../../config/harperConfigEnvVars.ts';
|
|
22
23
|
import * as configUtils from '../../config/configUtils.ts';
|
|
23
24
|
import * as userOps from '../../security/user.ts';
|
|
24
25
|
import * as roleOps from '../../security/role.ts';
|
|
@@ -197,6 +198,7 @@ async function install() {
|
|
|
197
198
|
}
|
|
198
199
|
envManager.setHdbBasePath(hdbRoot);
|
|
199
200
|
envManager.setProperty(hdbTerms.CONFIG_PARAMS.STORAGE_ENGINE, installParams.STORAGE_ENGINE);
|
|
201
|
+
stageRocksCompression();
|
|
200
202
|
|
|
201
203
|
// Creates the Harper project folder structure and the LMDB environments/dbis.
|
|
202
204
|
await mountHdb(hdbRoot);
|
|
@@ -575,6 +577,41 @@ export function applyInstallModeDefaults(args, defaultsMode) {
|
|
|
575
577
|
* @param installParams
|
|
576
578
|
* @returns {Promise<void>}
|
|
577
579
|
*/
|
|
580
|
+
/**
|
|
581
|
+
* Make the deployment codec readable before `mountHdb()` creates the system column families.
|
|
582
|
+
*
|
|
583
|
+
* The config file is not written until `createConfigFile()`, several steps after `mountHdb()`, but
|
|
584
|
+
* RocksDB fixes a column family's codec when the family is created and refuses a later reopen that
|
|
585
|
+
* asks for a different one — and worker threads share one process-wide family registry. Left
|
|
586
|
+
* unstaged, the main thread creates `__dbis__` at the build default while every worker resolves the
|
|
587
|
+
* configured codec, and Harper dies with "The system database failed to load". Staging it in the
|
|
588
|
+
* in-memory config here is the same trick the STORAGE_ENGINE line above uses.
|
|
589
|
+
*
|
|
590
|
+
* Checked in the same precedence `createConfigFile()` itself later resolves the value with, so
|
|
591
|
+
* `storage.compression` also participates when no explicit RocksDB codec is set: its default is
|
|
592
|
+
* true, which resolves to lz4. Stage both values from every source `createConfigFile()` honors so
|
|
593
|
+
* the first open cannot create `__dbis__` with `none` and later workers reopen it with lz4.
|
|
594
|
+
*/
|
|
595
|
+
function stageRocksCompression() {
|
|
596
|
+
const rocksCompression = hdbTerms.CONFIG_PARAMS.STORAGE_ROCKS_COMPRESSION;
|
|
597
|
+
const compression = hdbTerms.CONFIG_PARAMS.STORAGE_COMPRESSION;
|
|
598
|
+
const envConfig = composeConfigFromEnv();
|
|
599
|
+
const commandLineConfig = assignCMDENVVariables([rocksCompression, compression], true);
|
|
600
|
+
const fileConfig = cfgEnv[hdbTerms.INSTALL_PROMPTS.HDB_CONFIG] ? getConfigFromFile() : {};
|
|
601
|
+
const configuredRocksCompression =
|
|
602
|
+
envConfig?.storage?.rocks?.compression ?? commandLineConfig[rocksCompression] ?? fileConfig[rocksCompression];
|
|
603
|
+
const configuredCompression =
|
|
604
|
+
envConfig?.storage?.compression ?? commandLineConfig[compression] ?? fileConfig[compression] ?? true;
|
|
605
|
+
if (
|
|
606
|
+
configuredRocksCompression !== undefined &&
|
|
607
|
+
configuredRocksCompression !== null &&
|
|
608
|
+
configuredRocksCompression !== ''
|
|
609
|
+
) {
|
|
610
|
+
envManager.setProperty(rocksCompression, configuredRocksCompression);
|
|
611
|
+
}
|
|
612
|
+
envManager.setProperty(compression, configuredCompression);
|
|
613
|
+
}
|
|
614
|
+
|
|
578
615
|
async function createConfigFile(installParams) {
|
|
579
616
|
hdbLogger.trace('Creating Harper config file');
|
|
580
617
|
const args = assignCMDENVVariables(Object.keys(hdbTerms.CONFIG_PARAM_MAP), true);
|
|
@@ -13,6 +13,7 @@ import * as lmdbTerms from './terms.ts';
|
|
|
13
13
|
import * as hdbTerms from '../hdbTerms.ts';
|
|
14
14
|
import { resetDatabases } from '../../resources/databases.ts';
|
|
15
15
|
import * as envMngr from '../environment/environmentManager.ts';
|
|
16
|
+
import { updateConfigObject } from '../../config/configUtils.ts';
|
|
16
17
|
|
|
17
18
|
const INTERNAL_DBIS_NAME = lmdbTerms.INTERNAL_DBIS_NAME;
|
|
18
19
|
const DBI_DEFINITION_NAME = lmdbTerms.DBI_DEFINITION_NAME;
|
|
@@ -109,7 +110,7 @@ export async function createEnvironment(
|
|
|
109
110
|
|
|
110
111
|
envName = envName.toString();
|
|
111
112
|
let schemasConfig = envMngr.get(hdbTerms.CONFIG_PARAMS.DATABASES);
|
|
112
|
-
if (!schemasConfig)
|
|
113
|
+
if (!schemasConfig) updateConfigObject(hdbTerms.CONFIG_PARAMS.DATABASES, (schemasConfig = {}));
|
|
113
114
|
if (!schemasConfig[dbName]) schemasConfig[dbName] = {};
|
|
114
115
|
schemasConfig[dbName].path = basePath;
|
|
115
116
|
try {
|
|
@@ -381,14 +381,34 @@ module.exports = {
|
|
|
381
381
|
inspectForLog,
|
|
382
382
|
isErrorLike,
|
|
383
383
|
disableStdio,
|
|
384
|
+
isStdioBrokenError,
|
|
384
385
|
externalLogger,
|
|
385
386
|
};
|
|
386
387
|
|
|
388
|
+
// A bare no-op would read as permanent backpressure to a pipe()'d source; this drains and
|
|
389
|
+
// discards instead.
|
|
390
|
+
function noopWrite(_chunk?: any, encoding?: any, callback?: any) {
|
|
391
|
+
if (typeof encoding === 'function') callback = encoding;
|
|
392
|
+
if (typeof callback === 'function') callback();
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
|
|
387
396
|
/**
|
|
388
397
|
* We call this if stdio is not functional
|
|
389
398
|
*/
|
|
390
399
|
export function disableStdio(_unused?: any) {
|
|
391
|
-
nativeStdWrite =
|
|
400
|
+
nativeStdWrite = noopWrite;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const STDIO_BROKEN_ERROR_CODES = new Set(['EPIPE', 'EIO', 'ERR_STREAM_DESTROYED']);
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* True when this error means a stdio stream (stdout/stderr) is permanently unwritable - the
|
|
407
|
+
* pipe's reader died (EPIPE), the terminal closed (EIO), or the stream was already destroyed.
|
|
408
|
+
* Callers should disableStdio() on this rather than logging through the same sink that threw it.
|
|
409
|
+
*/
|
|
410
|
+
export function isStdioBrokenError(error: any): boolean {
|
|
411
|
+
return STDIO_BROKEN_ERROR_CODES.has(error?.code);
|
|
392
412
|
}
|
|
393
413
|
|
|
394
414
|
/**
|
|
@@ -509,32 +529,42 @@ export function initLogSettings(forceInit = false) {
|
|
|
509
529
|
stdioLogging();
|
|
510
530
|
}
|
|
511
531
|
let loggingEnabled = true;
|
|
532
|
+
|
|
533
|
+
// A POSIX pipe reports a broken pipe asynchronously - write() returns normally and the EPIPE
|
|
534
|
+
// arrives later as an 'error' event, past the try/catch below. An unhandled 'error' event on any
|
|
535
|
+
// EventEmitter becomes an uncaughtException, so the listener is what actually catches that case.
|
|
536
|
+
function installStdioGuard(stream) {
|
|
537
|
+
if (stream.harperStdioErrorHandler) stream.removeListener('error', stream.harperStdioErrorHandler);
|
|
538
|
+
stream.harperStdioErrorHandler = (error) => {
|
|
539
|
+
if (!isStdioBrokenError(error)) throw error;
|
|
540
|
+
disableStdio();
|
|
541
|
+
};
|
|
542
|
+
stream.on('error', stream.harperStdioErrorHandler);
|
|
543
|
+
|
|
544
|
+
stream.write = function (data) {
|
|
545
|
+
if (
|
|
546
|
+
log_to_file &&
|
|
547
|
+
typeof data === 'string' && // this is how we identify console output vs redirected output from a worker
|
|
548
|
+
loggingEnabled &&
|
|
549
|
+
logConsole
|
|
550
|
+
) {
|
|
551
|
+
data = data.toString();
|
|
552
|
+
if (data[data.length - 1] === '\n') data = data.slice(0, -1);
|
|
553
|
+
writeToLogFile(data);
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
return nativeStdWrite.apply(stream, arguments);
|
|
557
|
+
} catch (error) {
|
|
558
|
+
if (!isStdioBrokenError(error)) throw error;
|
|
559
|
+
disableStdio();
|
|
560
|
+
return noopWrite.apply(stream, arguments);
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
512
565
|
function stdioLogging() {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
if (
|
|
516
|
-
typeof data === 'string' && // this is how we identify console output vs redirected output from a worker
|
|
517
|
-
loggingEnabled &&
|
|
518
|
-
logConsole
|
|
519
|
-
) {
|
|
520
|
-
data = data.toString();
|
|
521
|
-
if (data[data.length - 1] === '\n') data = data.slice(0, -1);
|
|
522
|
-
writeToLogFile(data);
|
|
523
|
-
}
|
|
524
|
-
return nativeStdWrite.apply(process.stdout, arguments);
|
|
525
|
-
};
|
|
526
|
-
process.stderr.write = function (data) {
|
|
527
|
-
if (
|
|
528
|
-
typeof data === 'string' && // this is how we identify console output vs redirected output from a worker
|
|
529
|
-
loggingEnabled &&
|
|
530
|
-
logConsole
|
|
531
|
-
) {
|
|
532
|
-
if (data[data.length - 1] === '\n') data = data.slice(0, -1);
|
|
533
|
-
writeToLogFile(data);
|
|
534
|
-
}
|
|
535
|
-
return nativeStdWrite.apply(process.stderr, arguments);
|
|
536
|
-
};
|
|
537
|
-
}
|
|
566
|
+
installStdioGuard(process.stdout);
|
|
567
|
+
installStdioGuard(process.stderr);
|
|
538
568
|
}
|
|
539
569
|
|
|
540
570
|
export function loggerWithTag(tag: string, conditional?: boolean, logger: any = mainLogger) {
|
|
@@ -1809,6 +1839,7 @@ export default {
|
|
|
1809
1839
|
setLogLevel,
|
|
1810
1840
|
OUTPUTS,
|
|
1811
1841
|
disableStdio,
|
|
1842
|
+
isStdioBrokenError,
|
|
1812
1843
|
externalLogger,
|
|
1813
1844
|
AuthAuditLog,
|
|
1814
1845
|
errorToString,
|