@harperfast/harper-pro 5.0.0-beta.6 → 5.0.0-beta.8
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/core/bin/cliOperations.js +3 -3
- package/core/bin/harper.js +1 -1
- package/core/bin/run.js +2 -2
- package/core/components/Application.ts +6 -3
- package/core/components/ApplicationScope.ts +1 -0
- package/core/components/componentLoader.ts +23 -12
- package/core/components/operations.js +13 -13
- package/core/components/operationsValidation.js +3 -3
- package/core/config/configUtils.js +20 -4
- package/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +3 -2
- package/core/resources/DatabaseTransaction.ts +67 -32
- package/core/resources/Resource.ts +17 -6
- package/core/resources/RocksTransactionLogStore.ts +8 -1
- package/core/resources/Table.ts +29 -10
- package/core/resources/analytics/write.ts +6 -0
- package/core/resources/databases.ts +3 -2
- package/core/security/jsLoader.ts +258 -129
- package/core/server/REST.ts +32 -13
- package/core/server/http.ts +6 -3
- package/core/server/itc/serverHandlers.js +1 -1
- package/core/static/defaultConfig.yaml +1 -1
- package/core/utility/hdbTerms.ts +1 -0
- package/core/utility/logging/harper_logger.js +22 -1
- package/core/utility/logging/readLog.js +2 -2
- package/core/utility/npmUtilities.js +2 -2
- package/core/validation/configValidator.js +16 -8
- package/core/validation/readLogValidator.js +2 -2
- package/dist/core/bin/cliOperations.js +3 -3
- package/dist/core/bin/cliOperations.js.map +1 -1
- package/dist/core/bin/harper.js +1 -1
- package/dist/core/bin/run.js +2 -2
- package/dist/core/bin/run.js.map +1 -1
- package/dist/core/components/Application.js +7 -2
- package/dist/core/components/Application.js.map +1 -1
- package/dist/core/components/ApplicationScope.js +1 -0
- package/dist/core/components/ApplicationScope.js.map +1 -1
- package/dist/core/components/componentLoader.js +21 -10
- package/dist/core/components/componentLoader.js.map +1 -1
- package/dist/core/components/operations.js +13 -13
- package/dist/core/components/operations.js.map +1 -1
- package/dist/core/components/operationsValidation.js +3 -3
- package/dist/core/components/operationsValidation.js.map +1 -1
- package/dist/core/config/configUtils.js +23 -3
- package/dist/core/config/configUtils.js.map +1 -1
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +3 -2
- package/dist/core/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js.map +1 -1
- package/dist/core/resources/DatabaseTransaction.js +71 -35
- package/dist/core/resources/DatabaseTransaction.js.map +1 -1
- package/dist/core/resources/Resource.js +11 -4
- package/dist/core/resources/Resource.js.map +1 -1
- package/dist/core/resources/RocksTransactionLogStore.js +8 -1
- package/dist/core/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/core/resources/Table.js +15 -10
- package/dist/core/resources/Table.js.map +1 -1
- package/dist/core/resources/analytics/write.js +6 -0
- package/dist/core/resources/analytics/write.js.map +1 -1
- package/dist/core/resources/databases.js +3 -2
- package/dist/core/resources/databases.js.map +1 -1
- package/dist/core/security/jsLoader.js +223 -116
- package/dist/core/security/jsLoader.js.map +1 -1
- package/dist/core/server/REST.js +30 -14
- package/dist/core/server/REST.js.map +1 -1
- package/dist/core/server/http.js +6 -1
- package/dist/core/server/http.js.map +1 -1
- package/dist/core/server/itc/serverHandlers.js +1 -1
- package/dist/core/server/itc/serverHandlers.js.map +1 -1
- package/dist/core/utility/hdbTerms.js +1 -0
- package/dist/core/utility/hdbTerms.js.map +1 -1
- package/dist/core/utility/logging/harper_logger.js +24 -1
- package/dist/core/utility/logging/harper_logger.js.map +1 -1
- package/dist/core/utility/logging/readLog.js +2 -2
- package/dist/core/utility/logging/readLog.js.map +1 -1
- package/dist/core/utility/npmUtilities.js +2 -2
- package/dist/core/utility/npmUtilities.js.map +1 -1
- package/dist/core/validation/configValidator.js +18 -8
- package/dist/core/validation/configValidator.js.map +1 -1
- package/dist/core/validation/readLogValidator.js +2 -2
- package/dist/core/validation/readLogValidator.js.map +1 -1
- package/dist/licensing/usageLicensing.js +16 -26
- package/dist/licensing/usageLicensing.js.map +1 -1
- package/dist/replication/nodeIdMapping.js +1 -1
- package/dist/replication/nodeIdMapping.js.map +1 -1
- package/dist/replication/replicationConnection.js +2 -2
- package/dist/replication/replicationConnection.js.map +1 -1
- package/licensing/usageLicensing.ts +22 -32
- package/npm-shrinkwrap.json +615 -614
- package/package.json +9 -6
- package/replication/nodeIdMapping.ts +1 -1
- package/replication/replicationConnection.ts +2 -2
- package/static/defaultConfig.yaml +3 -0
- package/studio/web/assets/{index-BckVDix4.js → index-CXQsBaYq.js} +5 -5
- package/studio/web/assets/{index-BckVDix4.js.map → index-CXQsBaYq.js.map} +1 -1
- package/studio/web/assets/{index.lazy-iG1_8dzm.js → index.lazy-C3Ejfvna.js} +2 -2
- package/studio/web/assets/{index.lazy-iG1_8dzm.js.map → index.lazy-C3Ejfvna.js.map} +1 -1
- package/studio/web/assets/{profile-CzjslUXv.js → profile-BbbbWJCN.js} +2 -2
- package/studio/web/assets/{profile-CzjslUXv.js.map → profile-BbbbWJCN.js.map} +1 -1
- package/studio/web/assets/{status-BP4TQJDR.js → status-CFe85l8C.js} +2 -2
- package/studio/web/assets/{status-BP4TQJDR.js.map → status-CFe85l8C.js.map} +1 -1
- package/studio/web/index.html +1 -1
|
@@ -10,7 +10,7 @@ const YAML = require('yaml');
|
|
|
10
10
|
const { packageDirectory } = require('../components/packageComponent.ts');
|
|
11
11
|
const { encode } = require('cbor-x');
|
|
12
12
|
const { getHdbPid } = require('../utility/processManagement/processManagement.js');
|
|
13
|
-
const { initConfig } = require('../config/configUtils.js');
|
|
13
|
+
const { initConfig, getConfigPath } = require('../config/configUtils.js');
|
|
14
14
|
|
|
15
15
|
const OP_ALIASES = { deploy: 'deploy_component', package: 'package_component' };
|
|
16
16
|
|
|
@@ -93,7 +93,7 @@ async function cliOperations(req) {
|
|
|
93
93
|
process.exit(1);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
if (!fs.existsSync(
|
|
96
|
+
if (!fs.existsSync(getConfigPath(terms.CONFIG_PARAMS.OPERATIONSAPI_NETWORK_DOMAINSOCKET))) {
|
|
97
97
|
console.error('No domain socket found, unable to perform this operation');
|
|
98
98
|
process.exit(1);
|
|
99
99
|
}
|
|
@@ -102,7 +102,7 @@ async function cliOperations(req) {
|
|
|
102
102
|
try {
|
|
103
103
|
let options = target ?? {
|
|
104
104
|
protocol: 'http:',
|
|
105
|
-
socketPath:
|
|
105
|
+
socketPath: getConfigPath(terms.CONFIG_PARAMS.OPERATIONSAPI_NETWORK_DOMAINSOCKET),
|
|
106
106
|
};
|
|
107
107
|
options.method = 'POST';
|
|
108
108
|
options.headers = { 'Content-Type': 'application/json' };
|
package/core/bin/harper.js
CHANGED
package/core/bin/run.js
CHANGED
|
@@ -266,7 +266,7 @@ function startupLog(portResolutions) {
|
|
|
266
266
|
? `, TCP: ${env.get(CONFIG_PARAMS.THREADS_DEBUG_PORT)}\n`
|
|
267
267
|
: '\n';
|
|
268
268
|
}
|
|
269
|
-
const logFilePath = path.join(
|
|
269
|
+
const logFilePath = path.join(configUtils.getConfigPath(CONFIG_PARAMS.LOGGING_ROOT), 'hdb.log');
|
|
270
270
|
logMsg += `${pad('Logging:')}level: ${env.get(CONFIG_PARAMS.LOGGING_LEVEL)}, location: ${
|
|
271
271
|
logFilePath + (env.get(CONFIG_PARAMS.LOGGING_STDSTREAMS) ? ', stdout/err' : '')
|
|
272
272
|
}\n`;
|
|
@@ -292,7 +292,7 @@ function startupLog(portResolutions) {
|
|
|
292
292
|
? `enabled for ${env.get(CONFIG_PARAMS.OPERATIONSAPI_NETWORK_CORSACCESSLIST)}`
|
|
293
293
|
: 'disabled'
|
|
294
294
|
}`;
|
|
295
|
-
logMsg += `, unix socket: ${
|
|
295
|
+
logMsg += `, unix socket: ${configUtils.getConfigPath(CONFIG_PARAMS.OPERATIONSAPI_NETWORK_DOMAINSOCKET)}\n`;
|
|
296
296
|
if (env.get(CONFIG_PARAMS.OPERATIONSAPI_NETWORK_PORT)) {
|
|
297
297
|
logMsg +=
|
|
298
298
|
pad('') +
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Logger } from '../utility/logging/logger.ts';
|
|
2
|
-
import { getConfigObj, getConfigValue } from '../config/configUtils.js';
|
|
2
|
+
import { getConfigObj, getConfigValue, getConfigPath } from '../config/configUtils.js';
|
|
3
3
|
import { CONFIG_PARAMS } from '../utility/hdbTerms.js';
|
|
4
4
|
import logger from '../utility/logging/harper_logger.js';
|
|
5
5
|
|
|
@@ -402,7 +402,9 @@ export class Application {
|
|
|
402
402
|
this.payload = payload;
|
|
403
403
|
this.packageIdentifier = packageIdentifier && derivePackageIdentifier(packageIdentifier);
|
|
404
404
|
this.install = install;
|
|
405
|
-
|
|
405
|
+
const componentsRoot = getConfigPath(CONFIG_PARAMS.COMPONENTSROOT);
|
|
406
|
+
if (!componentsRoot) throw new Error('componentsRoot is not configured');
|
|
407
|
+
this.dirPath = join(componentsRoot, name);
|
|
406
408
|
this.logger = logger.loggerWithTag(name);
|
|
407
409
|
this.packageManagerPrefix = getConfigValue(CONFIG_PARAMS.APPLICATIONS_PACKAGEMANAGERPREFIX);
|
|
408
410
|
}
|
|
@@ -464,7 +466,8 @@ export async function installApplications() {
|
|
|
464
466
|
|
|
465
467
|
const config = getConfigObj();
|
|
466
468
|
|
|
467
|
-
const componentsRootDirPath =
|
|
469
|
+
const componentsRootDirPath = getConfigPath(CONFIG_PARAMS.COMPONENTSROOT);
|
|
470
|
+
if (!componentsRootDirPath) throw new Error('componentsRoot is not configured');
|
|
468
471
|
|
|
469
472
|
// Ensure component directory exists
|
|
470
473
|
await mkdir(componentsRootDirPath, { recursive: true });
|
|
@@ -23,6 +23,7 @@ export class ApplicationScope {
|
|
|
23
23
|
dependencyContainment?: boolean; // option to set this from the scope
|
|
24
24
|
verifyPath?: string;
|
|
25
25
|
config: any;
|
|
26
|
+
moduleCache: any; // used by the loader to retain a cache of modules, type is an internal detail of the loader
|
|
26
27
|
constructor(name: string, resources: Resources, server: Server, isInternal = false, verifyPath?: string) {
|
|
27
28
|
this.logger = forComponent(name, !isInternal);
|
|
28
29
|
|
|
@@ -27,7 +27,7 @@ import { getHdbBasePath } from '../utility/environment/environmentManager.js';
|
|
|
27
27
|
import * as operationsServer from '../server/operationsServer.ts';
|
|
28
28
|
import * as auth from '../security/auth.ts';
|
|
29
29
|
import * as mqtt from '../server/mqtt.ts';
|
|
30
|
-
import { getConfigObj,
|
|
30
|
+
import { getConfigObj, getConfigPath } from '../config/configUtils.js';
|
|
31
31
|
import { createReuseportFd } from '../server/serverHelpers/Request.ts';
|
|
32
32
|
import { ErrorResource } from '../resources/ErrorResource.ts';
|
|
33
33
|
import { Scope } from './Scope.ts';
|
|
@@ -39,8 +39,9 @@ import { lifecycle as componentLifecycle } from './status/index.ts';
|
|
|
39
39
|
import { DEFAULT_CONFIG } from './DEFAULT_CONFIG.ts';
|
|
40
40
|
import { PluginModule } from './PluginModule.ts';
|
|
41
41
|
import { getEnvBuiltInComponents } from './Application.ts';
|
|
42
|
+
import { pathToFileURL } from 'node:url';
|
|
42
43
|
|
|
43
|
-
const CF_ROUTES_DIR =
|
|
44
|
+
const CF_ROUTES_DIR = getConfigPath(CONFIG_PARAMS.COMPONENTSROOT);
|
|
44
45
|
let loadedComponents = new Map<any, any>();
|
|
45
46
|
let watchesSetup;
|
|
46
47
|
let resources;
|
|
@@ -147,20 +148,28 @@ function symlinkHarperModule(componentDirectory: string) {
|
|
|
147
148
|
mkdirSync(nodeModulesDir);
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
// validate
|
|
151
|
+
// validate harper module
|
|
151
152
|
const harperModule = join(nodeModulesDir, 'harper');
|
|
152
153
|
if (existsSync(harperModule)) {
|
|
153
|
-
if (realpathSync(harperModule)
|
|
154
|
-
// if it exists
|
|
155
|
-
|
|
154
|
+
if (realpathSync(harperModule) !== realpathSync(PACKAGE_ROOT)) {
|
|
155
|
+
// if it exists but is incorrectly linked, fix it
|
|
156
|
+
rmSync(harperModule, { recursive: true, force: true });
|
|
157
|
+
// create link to harper module
|
|
158
|
+
symlinkSync(PACKAGE_ROOT, harperModule, 'dir');
|
|
156
159
|
}
|
|
157
|
-
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
+
} else {
|
|
161
|
+
// create link to harper module
|
|
162
|
+
symlinkSync(PACKAGE_ROOT, harperModule, 'dir');
|
|
163
|
+
}
|
|
164
|
+
// if there is a harperdb module, fix that too
|
|
165
|
+
const harperdbModule = join(nodeModulesDir, 'harperdb');
|
|
166
|
+
if (existsSync(harperdbModule) && realpathSync(harperdbModule) !== realpathSync(PACKAGE_ROOT)) {
|
|
167
|
+
// if it exists but is incorrectly linked, fix it
|
|
168
|
+
rmSync(harperdbModule, { recursive: true, force: true });
|
|
169
|
+
// create link to harper module
|
|
170
|
+
symlinkSync(PACKAGE_ROOT, harperdbModule, 'dir');
|
|
160
171
|
}
|
|
161
172
|
|
|
162
|
-
// create link to harperdb module
|
|
163
|
-
symlinkSync(PACKAGE_ROOT, harperModule, 'dir');
|
|
164
173
|
resolve();
|
|
165
174
|
} finally {
|
|
166
175
|
// finally release the lock
|
|
@@ -352,7 +361,9 @@ export async function loadComponent(
|
|
|
352
361
|
const plugin = TRUSTED_RESOURCE_PLUGINS[componentName];
|
|
353
362
|
extensionModule =
|
|
354
363
|
typeof plugin === 'string'
|
|
355
|
-
? await import(
|
|
364
|
+
? await import(
|
|
365
|
+
plugin.startsWith('@/') ? pathToFileURL(join(PACKAGE_ROOT, plugin.slice(1))).toString() : plugin
|
|
366
|
+
)
|
|
356
367
|
: plugin;
|
|
357
368
|
}
|
|
358
369
|
|
|
@@ -31,7 +31,7 @@ function customFunctionsStatus() {
|
|
|
31
31
|
try {
|
|
32
32
|
response = {
|
|
33
33
|
port: env.get(hdbTerms.CONFIG_PARAMS.HTTP_PORT),
|
|
34
|
-
directory:
|
|
34
|
+
directory: configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT),
|
|
35
35
|
is_enabled: true,
|
|
36
36
|
};
|
|
37
37
|
} catch (err) {
|
|
@@ -54,7 +54,7 @@ function customFunctionsStatus() {
|
|
|
54
54
|
function getCustomFunctions() {
|
|
55
55
|
log.trace(`getting custom api endpoints`);
|
|
56
56
|
let response = {};
|
|
57
|
-
const dir =
|
|
57
|
+
const dir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
58
58
|
|
|
59
59
|
try {
|
|
60
60
|
const projectFolders = fg.sync(normalize(`${dir}/*`), { onlyDirectories: true });
|
|
@@ -103,7 +103,7 @@ function getCustomFunction(req) {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
log.trace(`getting custom api endpoint file content`);
|
|
106
|
-
const cfDir =
|
|
106
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
107
107
|
const { project, type, file } = req;
|
|
108
108
|
const fileLocation = path.join(cfDir, project, type, file + '.js');
|
|
109
109
|
|
|
@@ -141,7 +141,7 @@ async function setCustomFunction(req) {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
log.trace(`setting custom function file content`);
|
|
144
|
-
const cfDir =
|
|
144
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
145
145
|
const { project, type, file, function_content } = req;
|
|
146
146
|
|
|
147
147
|
try {
|
|
@@ -181,7 +181,7 @@ async function dropCustomFunction(req) {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
log.trace(`dropping custom function file`);
|
|
184
|
-
const cfDir =
|
|
184
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
185
185
|
const { project, type, file } = req;
|
|
186
186
|
|
|
187
187
|
try {
|
|
@@ -216,7 +216,7 @@ async function addComponent(req) {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
log.trace(`adding component`);
|
|
219
|
-
const cfDir =
|
|
219
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
220
220
|
const { project, install_command, install_timeout } = req;
|
|
221
221
|
|
|
222
222
|
const template = req.template || 'https://github.com/harperdb/application-template';
|
|
@@ -264,7 +264,7 @@ async function dropCustomFunctionProject(req) {
|
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
log.trace(`dropping custom function project`);
|
|
267
|
-
const cfDir =
|
|
267
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
268
268
|
const { project } = req;
|
|
269
269
|
|
|
270
270
|
let apps = env.get(hdbTerms.CONFIG_PARAMS.APPS);
|
|
@@ -318,7 +318,7 @@ async function packageComponent(req) {
|
|
|
318
318
|
throw handleHDBError(validation, validation.message, HTTP_STATUS_CODES.BAD_REQUEST);
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
const cfDir =
|
|
321
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
322
322
|
const { project } = req;
|
|
323
323
|
log.trace(`packaging component`, project);
|
|
324
324
|
|
|
@@ -507,8 +507,8 @@ async function getComponents() {
|
|
|
507
507
|
}
|
|
508
508
|
};
|
|
509
509
|
|
|
510
|
-
const results = await walkDir(
|
|
511
|
-
name:
|
|
510
|
+
const results = await walkDir(configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT), {
|
|
511
|
+
name: configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT).split(path.sep).slice(-1).pop(),
|
|
512
512
|
entries: [],
|
|
513
513
|
});
|
|
514
514
|
for (let entry of results.entries) {
|
|
@@ -557,7 +557,7 @@ async function getComponentFile(req) {
|
|
|
557
557
|
throw handleHDBError(validation, validation.message, HTTP_STATUS_CODES.BAD_REQUEST);
|
|
558
558
|
}
|
|
559
559
|
|
|
560
|
-
const compRoot =
|
|
560
|
+
const compRoot = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
561
561
|
const options = req.encoding ? { encoding: req.encoding } : { encoding: 'utf8' };
|
|
562
562
|
|
|
563
563
|
try {
|
|
@@ -588,7 +588,7 @@ async function setComponentFile(req) {
|
|
|
588
588
|
}
|
|
589
589
|
|
|
590
590
|
const options = req.encoding ? { encoding: req.encoding } : { encoding: 'utf8' };
|
|
591
|
-
const pathToComp = path.join(
|
|
591
|
+
const pathToComp = path.join(configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT), req.project, req.file);
|
|
592
592
|
if (req.payload !== undefined) {
|
|
593
593
|
await fs.ensureFile(pathToComp);
|
|
594
594
|
await fs.outputFile(pathToComp, req.payload, options);
|
|
@@ -613,7 +613,7 @@ async function dropComponent(req) {
|
|
|
613
613
|
|
|
614
614
|
const { project, file } = req;
|
|
615
615
|
const projectPath = req.file ? path.join(project, file) : project;
|
|
616
|
-
const pathToComponent = path.join(
|
|
616
|
+
const pathToComponent = path.join(configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT), projectPath);
|
|
617
617
|
|
|
618
618
|
const componentSymlink = path.join(env.get(hdbTerms.CONFIG_PARAMS.ROOTPATH), 'node_modules', project);
|
|
619
619
|
if (await fs.pathExists(componentSymlink)) {
|
|
@@ -4,9 +4,9 @@ const Joi = require('joi');
|
|
|
4
4
|
const fs = require('fs-extra');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const validator = require('../validation/validationWrapper.js');
|
|
7
|
-
const envMangr = require('../utility/environment/environmentManager.js');
|
|
8
7
|
const hdbTerms = require('../utility/hdbTerms.ts');
|
|
9
8
|
const hdbLogger = require('../utility/logging/harper_logger.js');
|
|
9
|
+
const configUtils = require('../config/configUtils.js');
|
|
10
10
|
const { hdbErrors } = require('../utility/errors/hdbError.js');
|
|
11
11
|
const { HDB_ERROR_MSGS } = hdbErrors;
|
|
12
12
|
|
|
@@ -34,7 +34,7 @@ module.exports = {
|
|
|
34
34
|
*/
|
|
35
35
|
function checkProjectExists(checkExists, project, helpers) {
|
|
36
36
|
try {
|
|
37
|
-
const cfDir =
|
|
37
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
38
38
|
const projectDir = path.join(cfDir, project);
|
|
39
39
|
|
|
40
40
|
if (!fs.existsSync(projectDir)) {
|
|
@@ -71,7 +71,7 @@ function checkFilePath(path, helpers) {
|
|
|
71
71
|
*/
|
|
72
72
|
function checkFileExists(project, type, file, helpers) {
|
|
73
73
|
try {
|
|
74
|
-
const cfDir =
|
|
74
|
+
const cfDir = configUtils.getConfigPath(hdbTerms.CONFIG_PARAMS.COMPONENTSROOT);
|
|
75
75
|
const filePath = path.join(cfDir, project, type, file + '.js');
|
|
76
76
|
if (!fs.existsSync(filePath)) {
|
|
77
77
|
return helpers.message(HDB_ERROR_MSGS.NO_FILE);
|
|
@@ -57,6 +57,7 @@ exports.deleteConfigFromFile = deleteConfigFromFile;
|
|
|
57
57
|
exports.getConfigObj = getConfigObj;
|
|
58
58
|
exports.resolvePath = resolvePath;
|
|
59
59
|
exports.getFlatConfigObj = getFlatConfigObj;
|
|
60
|
+
exports.getConfigPath = getConfigPath;
|
|
60
61
|
|
|
61
62
|
function resolvePath(relativePath) {
|
|
62
63
|
if (relativePath?.startsWith('~/')) {
|
|
@@ -70,7 +71,23 @@ function resolvePath(relativePath) {
|
|
|
70
71
|
return relativePath;
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Get a config value and resolve it as a path relative to rootPath.
|
|
76
|
+
* Use this for any config param that represents a file/directory path.
|
|
77
|
+
* @param param
|
|
78
|
+
*/
|
|
79
|
+
function getConfigPath(param) {
|
|
80
|
+
const env = require('../utility/environment/environmentManager.js');
|
|
81
|
+
const value = env.get(param);
|
|
82
|
+
if (!value || typeof value !== 'string') return value;
|
|
83
|
+
if (value.startsWith('~/')) {
|
|
84
|
+
return path.join(hdbUtils.getHomeDir(), value.slice(1));
|
|
85
|
+
}
|
|
86
|
+
if (path.isAbsolute(value)) return value;
|
|
87
|
+
const rootPath = env.getHdbBasePath();
|
|
88
|
+
if (!rootPath) return value;
|
|
89
|
+
return path.resolve(rootPath, value);
|
|
90
|
+
}
|
|
74
91
|
/**
|
|
75
92
|
* Builds the Harper config file using user inputs and default values from defaultConfig.yaml
|
|
76
93
|
* @param args - any args that the user provided.
|
|
@@ -332,15 +349,14 @@ function initConfig(force = false) {
|
|
|
332
349
|
* @param configFilePath
|
|
333
350
|
*/
|
|
334
351
|
function checkForUpdatedConfig(configDoc, configFilePath) {
|
|
335
|
-
const rootPath = configDoc.getIn(['rootPath']);
|
|
336
352
|
let updateFile = false;
|
|
337
353
|
if (!configDoc.hasIn(['storage', 'path'])) {
|
|
338
|
-
configDoc.setIn(['storage', 'path'],
|
|
354
|
+
configDoc.setIn(['storage', 'path'], 'database');
|
|
339
355
|
updateFile = true;
|
|
340
356
|
}
|
|
341
357
|
|
|
342
358
|
if (!configDoc.hasIn(['logging', 'rotation', 'path'])) {
|
|
343
|
-
configDoc.setIn(['logging', 'rotation', 'path'],
|
|
359
|
+
configDoc.setIn(['logging', 'rotation', 'path'], 'log');
|
|
344
360
|
updateFile = true;
|
|
345
361
|
}
|
|
346
362
|
|
|
@@ -7,6 +7,7 @@ const path = require('path');
|
|
|
7
7
|
const minimist = require('minimist');
|
|
8
8
|
const fs = require('fs-extra');
|
|
9
9
|
const _ = require('lodash');
|
|
10
|
+
const { getConfigPath } = require('../../../../config/configUtils.js');
|
|
10
11
|
env.initSync();
|
|
11
12
|
|
|
12
13
|
const { CONFIG_PARAMS, DATABASES_PARAM_CONFIG, SYSTEM_SCHEMA_NAME } = hdbTerms;
|
|
@@ -25,7 +26,7 @@ function getBaseSchemaPath() {
|
|
|
25
26
|
|
|
26
27
|
if (env.getHdbBasePath() !== undefined) {
|
|
27
28
|
BASE_SCHEMA_PATH =
|
|
28
|
-
|
|
29
|
+
getConfigPath(CONFIG_PARAMS.STORAGE_PATH) || path.join(env.getHdbBasePath(), hdbTerms.DATABASES_DIR_NAME);
|
|
29
30
|
return BASE_SCHEMA_PATH;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
@@ -52,7 +53,7 @@ function getTransactionAuditStoreBasePath() {
|
|
|
52
53
|
|
|
53
54
|
if (env.getHdbBasePath() !== undefined) {
|
|
54
55
|
TRANSACTION_STORE_PATH =
|
|
55
|
-
|
|
56
|
+
getConfigPath(hdbTerms.CONFIG_PARAMS.STORAGE_AUDIT_PATH) ||
|
|
56
57
|
path.join(env.getHdbBasePath(), hdbTerms.TRANSACTIONS_DIR_NAME);
|
|
57
58
|
return TRANSACTION_STORE_PATH;
|
|
58
59
|
}
|
|
@@ -35,6 +35,7 @@ export type CommitOptions = {
|
|
|
35
35
|
timestamp?: number;
|
|
36
36
|
retries?: number;
|
|
37
37
|
flush?: boolean;
|
|
38
|
+
transaction?: RocksTransaction;
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
type ReadTransaction = (LMDBTransaction | RocksTransaction) & {
|
|
@@ -116,8 +117,13 @@ export class DatabaseTransaction implements Transaction {
|
|
|
116
117
|
if (!this.transaction) return;
|
|
117
118
|
if (--this.readTxnsUsed === 0) {
|
|
118
119
|
trackedTxns.delete(this);
|
|
119
|
-
this.
|
|
120
|
-
|
|
120
|
+
if (this.open === TRANSACTION_STATE.LINGERING) {
|
|
121
|
+
// if we have lingering writes, we have to call commit to finish them
|
|
122
|
+
this.commit();
|
|
123
|
+
} else {
|
|
124
|
+
this.transaction?.abort();
|
|
125
|
+
this.transaction = null;
|
|
126
|
+
}
|
|
121
127
|
}
|
|
122
128
|
}
|
|
123
129
|
|
|
@@ -139,9 +145,6 @@ export class DatabaseTransaction implements Transaction {
|
|
|
139
145
|
}
|
|
140
146
|
|
|
141
147
|
addWrite(operation: TransactionWrite) {
|
|
142
|
-
if (this.open === TRANSACTION_STATE.CLOSED) {
|
|
143
|
-
throw new Error('Can not use a transaction that is no longer open');
|
|
144
|
-
}
|
|
145
148
|
this.writes.push(operation);
|
|
146
149
|
if (!operation.deferSave) {
|
|
147
150
|
// Setting saved to false means to defer saving
|
|
@@ -150,61 +153,94 @@ export class DatabaseTransaction implements Transaction {
|
|
|
150
153
|
return operation;
|
|
151
154
|
}
|
|
152
155
|
|
|
153
|
-
save(operation: TransactionWrite, reloadEntry = false) {
|
|
156
|
+
save(operation: TransactionWrite, transaction?: RocksTransaction, reloadEntry = false) {
|
|
154
157
|
let txnTime = this.timestamp;
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
transaction ??= this.transaction;
|
|
159
|
+
let immediateCommit = false;
|
|
160
|
+
if (!transaction) {
|
|
161
|
+
transaction = new RocksTransaction(this.db.store as RocksStore);
|
|
162
|
+
if (this.open === TRANSACTION_STATE.OPEN) {
|
|
163
|
+
this.transaction = transaction;
|
|
164
|
+
} else {
|
|
165
|
+
// if it is closed, we have to immediately commit, using our immediate transaction
|
|
166
|
+
immediateCommit = true;
|
|
167
|
+
}
|
|
157
168
|
if (txnTime) {
|
|
158
|
-
|
|
169
|
+
transaction.setTimestamp(txnTime);
|
|
159
170
|
}
|
|
160
171
|
}
|
|
161
172
|
if (this.retries > 0) {
|
|
162
173
|
// this is marks the rocks transaction as a retry so we don't write the transaction log again
|
|
163
|
-
|
|
174
|
+
transaction.isRetry = true;
|
|
164
175
|
}
|
|
165
|
-
if (!txnTime) txnTime = this.timestamp =
|
|
176
|
+
if (!txnTime) txnTime = this.timestamp = transaction.getTimestamp();
|
|
166
177
|
if (reloadEntry || operation.entry === undefined) {
|
|
167
|
-
operation.entry = operation.store.getEntry(operation.key, { transaction
|
|
178
|
+
operation.entry = operation.store.getEntry(operation.key, { transaction });
|
|
179
|
+
}
|
|
180
|
+
if (!operation.saved) {
|
|
181
|
+
operation.saved = true;
|
|
182
|
+
// immediately execute in this transaction
|
|
183
|
+
if (operation.validate?.(txnTime) === false) {
|
|
184
|
+
operation.commit = () => {}; // noop if we try again
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
let result: Promise<void> = operation.before?.() as Promise<void>;
|
|
188
|
+
if (result?.then) this.completions.push(result);
|
|
189
|
+
result = operation.beforeIntermediate?.() as Promise<void>;
|
|
190
|
+
if (result?.then) this.completions.push(result);
|
|
191
|
+
}
|
|
192
|
+
operation.commit(txnTime, operation.entry, this.retries > 0, transaction);
|
|
193
|
+
if (immediateCommit) {
|
|
194
|
+
return this.commit({ transaction }); // immediately commit if the harper transaction is closed
|
|
168
195
|
}
|
|
169
|
-
operation.saved = true;
|
|
170
|
-
// immediately execute in this transaction
|
|
171
|
-
if (operation.validate?.(txnTime) === false) return;
|
|
172
|
-
let result: Promise<void> = operation.before?.() as Promise<void>;
|
|
173
|
-
if (result?.then) this.completions.push(result);
|
|
174
|
-
result = operation.beforeIntermediate?.() as Promise<void>;
|
|
175
|
-
if (result?.then) this.completions.push(result);
|
|
176
|
-
operation.commit(txnTime, operation.entry, this.retries > 0, this.transaction);
|
|
177
196
|
}
|
|
178
197
|
|
|
179
198
|
/**
|
|
180
199
|
* Resolves with information on the timestamp and success of the commit
|
|
181
200
|
*/
|
|
182
201
|
commit(options: CommitOptions = {}): MaybePromise<CommitResolution> {
|
|
202
|
+
let transaction = options.transaction ?? this.transaction; // we need to preserve this transaction as we might to resurrect it if we have to retry
|
|
183
203
|
for (let i = 0; i < this.writes.length; i++) {
|
|
184
204
|
let operation = this.writes[i];
|
|
185
205
|
if (this.retries === 0 && operation.saved) continue;
|
|
186
|
-
this.save(operation, i < this.validated);
|
|
206
|
+
this.save(operation, transaction, i < this.validated);
|
|
187
207
|
}
|
|
188
208
|
this.validated = this.writes.length;
|
|
189
|
-
|
|
209
|
+
const completions = this.completions;
|
|
210
|
+
if (completions.length > 0) this.completions = []; // reset
|
|
211
|
+
return when(completions.length > 0 ? Promise.all(completions) : null, () => {
|
|
212
|
+
if (this.writes.length > this.validated) {
|
|
213
|
+
// check just in case we got any more transactions while we were waiting, if so just recursively continue to finish the additional writes now
|
|
214
|
+
return this.commit(options);
|
|
215
|
+
}
|
|
216
|
+
this.open = TRANSACTION_STATE.CLOSED;
|
|
190
217
|
let commitResolution: MaybePromise<void>;
|
|
191
218
|
if (--this.readTxnsUsed > 0) {
|
|
192
219
|
// we still have outstanding iterators using the transaction, we can't just commit/abort it, we will still
|
|
193
220
|
// need to use it
|
|
221
|
+
if (this.writes.length > 0) {
|
|
222
|
+
// if there are outstanding writes, we have to call commit later to finish them
|
|
223
|
+
this.open = TRANSACTION_STATE.LINGERING;
|
|
224
|
+
/* TODO: This is not really the intended behavior though, we want to immediately commit writes, but continue to use
|
|
225
|
+
* the transaction, as there is likely existing references to the transaction in other parts of the codebase,
|
|
226
|
+
* particularly in the query iterator */
|
|
227
|
+
}
|
|
228
|
+
/*
|
|
194
229
|
commitResolution =
|
|
195
230
|
this.writes.length > 0
|
|
196
|
-
?
|
|
197
|
-
|
|
231
|
+
? transaction?.commit({ renewAfterCommit: true }) // Try to use RocksDB's CommitAndTryCreateSnapshot
|
|
232
|
+
: // don't abort, we still have outstanding reads to complete
|
|
198
233
|
null;
|
|
234
|
+
*/
|
|
199
235
|
} else {
|
|
200
236
|
// no more reads need to be performed, just commit/abort based if there are any writes
|
|
201
237
|
trackedTxns.delete(this);
|
|
202
|
-
|
|
238
|
+
this.transaction = null; // clear transaction so any further operations operate immediately
|
|
239
|
+
if (transaction) {
|
|
203
240
|
if (this.writes.length > 0) {
|
|
204
|
-
commitResolution =
|
|
241
|
+
commitResolution = transaction.commit();
|
|
205
242
|
} else {
|
|
206
|
-
commitResolution =
|
|
207
|
-
this.transaction = null; // immediately clear transaction, no need to wait
|
|
243
|
+
commitResolution = transaction.abort();
|
|
208
244
|
}
|
|
209
245
|
}
|
|
210
246
|
}
|
|
@@ -220,8 +256,7 @@ export class DatabaseTransaction implements Transaction {
|
|
|
220
256
|
const completions = [];
|
|
221
257
|
return commitResolution.then(
|
|
222
258
|
() => {
|
|
223
|
-
|
|
224
|
-
this.transaction = null; // the native transaction is done (reset if needed)
|
|
259
|
+
transaction.onCommit?.();
|
|
225
260
|
if (this.next) {
|
|
226
261
|
completions.push(this.next.commit(options));
|
|
227
262
|
}
|
|
@@ -260,7 +295,7 @@ export class DatabaseTransaction implements Transaction {
|
|
|
260
295
|
// if the transaction failed due to concurrent changes, we need to retry. First record this as an increased risk of contention/retry
|
|
261
296
|
// for future transactions
|
|
262
297
|
this.retries++;
|
|
263
|
-
return this.commit(
|
|
298
|
+
return this.commit({ transaction }); // try again
|
|
264
299
|
} else throw error;
|
|
265
300
|
}
|
|
266
301
|
);
|
|
@@ -318,7 +353,7 @@ export class ImmediateTransaction extends DatabaseTransaction {
|
|
|
318
353
|
save(transaction: ImmediateTransaction) {
|
|
319
354
|
if (this.isCommitting) {
|
|
320
355
|
// if we are in the commit, do the save and force a reload so we get a read within the transaction
|
|
321
|
-
super.save(transaction, true);
|
|
356
|
+
super.save(transaction, null, true);
|
|
322
357
|
} else {
|
|
323
358
|
this.isCommitting = true;
|
|
324
359
|
return when(this.commit(), () => {
|
|
@@ -683,15 +683,26 @@ function transactional(
|
|
|
683
683
|
}
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
686
|
+
const KNOWN_METHODS = ['get', 'head', 'put', 'post', 'delete', 'patch', 'query', 'move', 'copy'];
|
|
687
|
+
type ClientErrorWithMethods = ClientError & { allow: string[]; method: string };
|
|
688
|
+
export function missingMethod(resource: any, method: string) {
|
|
689
|
+
const error = new ClientError(
|
|
690
|
+
`The ${resource.constructor.name} does not have a ${method} method implemented`,
|
|
691
|
+
405
|
|
692
|
+
) as ClientErrorWithMethods;
|
|
693
|
+
error.allow = allowedMethods(resource);
|
|
689
694
|
error.method = method;
|
|
690
|
-
for (const method of ['get', 'put', 'post', 'delete', 'query', 'move', 'copy']) {
|
|
691
|
-
if (typeof resource[method] === 'function') error.allow.push(method);
|
|
692
|
-
}
|
|
693
695
|
throw error;
|
|
694
696
|
}
|
|
697
|
+
|
|
698
|
+
export function allowedMethods(resource: any) {
|
|
699
|
+
const allow = [];
|
|
700
|
+
for (const method of KNOWN_METHODS) {
|
|
701
|
+
if (typeof resource[method] === 'function') allow.push(method);
|
|
702
|
+
}
|
|
703
|
+
return allow;
|
|
704
|
+
}
|
|
705
|
+
|
|
695
706
|
/**
|
|
696
707
|
* This is responsible for handling a select query parameter/call that selects specific
|
|
697
708
|
* properties from the returned record(s).
|
|
@@ -3,6 +3,7 @@ import { ExtendedIterable } from '@harperfast/extended-iterable';
|
|
|
3
3
|
import { Decoder, readAuditEntry, ENTRY_DATAVIEW, AuditRecord, createAuditEntry } from './auditStore.ts';
|
|
4
4
|
import { isMainThread } from 'node:worker_threads';
|
|
5
5
|
import { EventEmitter } from 'node:events';
|
|
6
|
+
import { asBinary } from 'lmdb';
|
|
6
7
|
|
|
7
8
|
if (!process.env.HARPER_NO_FLUSH_ON_EXIT && isMainThread) {
|
|
8
9
|
// we want to be able to test log replay
|
|
@@ -81,7 +82,7 @@ export class RocksTransactionLogStore extends EventEmitter {
|
|
|
81
82
|
|
|
82
83
|
putSync(suggestedKey: any, value: any, options: any) {
|
|
83
84
|
if (typeof suggestedKey === 'symbol') {
|
|
84
|
-
this.rootStore.putSync(suggestedKey, value, options);
|
|
85
|
+
this.rootStore.putSync(suggestedKey, asBinary(value), options);
|
|
85
86
|
} else {
|
|
86
87
|
this.put(suggestedKey, value, options);
|
|
87
88
|
}
|
|
@@ -107,6 +108,12 @@ export class RocksTransactionLogStore extends EventEmitter {
|
|
|
107
108
|
return this.rootStore.getSync(key);
|
|
108
109
|
}
|
|
109
110
|
}
|
|
111
|
+
getBinary(key: any) {
|
|
112
|
+
if (typeof key === 'number') {
|
|
113
|
+
throw new Error('Unsupported binary access by number');
|
|
114
|
+
}
|
|
115
|
+
return this.rootStore.getBinarySync(key);
|
|
116
|
+
}
|
|
110
117
|
getEntry() {
|
|
111
118
|
throw new Error('Not implemented');
|
|
112
119
|
}
|