@kapeta/local-cluster-service 0.16.8 → 0.17.0
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/CHANGELOG.md +13 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/src/socketManager.js +6 -0
- package/dist/cjs/src/utils/DefaultProviderInstaller.d.ts +11 -0
- package/dist/cjs/src/utils/DefaultProviderInstaller.js +129 -0
- package/dist/esm/index.js +64 -57
- package/dist/esm/src/RepositoryWatcher.js +40 -33
- package/dist/esm/src/api.js +14 -9
- package/dist/esm/src/assetManager.js +62 -56
- package/dist/esm/src/assets/routes.js +22 -17
- package/dist/esm/src/attachments/routes.js +14 -9
- package/dist/esm/src/cacheManager.js +13 -5
- package/dist/esm/src/clusterService.js +6 -3
- package/dist/esm/src/codeGeneratorManager.js +19 -13
- package/dist/esm/src/config/routes.js +30 -25
- package/dist/esm/src/configManager.js +29 -26
- package/dist/esm/src/containerManager.js +48 -39
- package/dist/esm/src/definitionsManager.js +15 -9
- package/dist/esm/src/filesystem/routes.js +21 -16
- package/dist/esm/src/filesystemManager.js +23 -17
- package/dist/esm/src/identities/routes.js +13 -8
- package/dist/esm/src/instanceManager.js +163 -156
- package/dist/esm/src/instances/routes.js +38 -33
- package/dist/esm/src/middleware/cors.js +5 -1
- package/dist/esm/src/middleware/kapeta.js +8 -4
- package/dist/esm/src/middleware/stringBody.js +5 -1
- package/dist/esm/src/networkManager.js +15 -9
- package/dist/esm/src/operatorManager.js +45 -39
- package/dist/esm/src/progressListener.js +16 -12
- package/dist/esm/src/providerManager.js +22 -16
- package/dist/esm/src/providers/routes.js +14 -9
- package/dist/esm/src/proxy/routes.js +26 -21
- package/dist/esm/src/proxy/types/rest.js +29 -22
- package/dist/esm/src/proxy/types/web.js +18 -11
- package/dist/esm/src/repositoryManager.js +28 -22
- package/dist/esm/src/serviceManager.js +25 -19
- package/dist/esm/src/socketManager.js +31 -18
- package/dist/esm/src/storageService.js +18 -12
- package/dist/esm/src/taskManager.js +12 -8
- package/dist/esm/src/tasks/routes.js +14 -9
- package/dist/esm/src/traffic/routes.js +12 -7
- package/dist/esm/src/types.js +11 -8
- package/dist/esm/src/utils/BlockInstanceRunner.js +57 -50
- package/dist/esm/src/utils/DefaultProviderInstaller.d.ts +11 -0
- package/dist/esm/src/utils/DefaultProviderInstaller.js +129 -0
- package/dist/esm/src/utils/LogData.js +5 -1
- package/dist/esm/src/utils/commandLineUtils.js +12 -7
- package/dist/esm/src/utils/pathTemplateParser.js +7 -2
- package/dist/esm/src/utils/utils.js +30 -17
- package/dist/esm/start.js +7 -2
- package/index.ts +3 -0
- package/package.json +10 -4
- package/src/instanceManager.ts +1 -1
- package/src/socketManager.ts +6 -0
- package/src/utils/DefaultProviderInstaller.ts +141 -0
- package/tsconfig.json +3 -2
@@ -1,5 +1,8 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.LogData = void 0;
|
1
4
|
const MAX_LINES = 1000;
|
2
|
-
|
5
|
+
class LogData {
|
3
6
|
static MAX_LINES = MAX_LINES;
|
4
7
|
entries = [];
|
5
8
|
constructor() { }
|
@@ -36,3 +39,4 @@ export class LogData {
|
|
36
39
|
.join('\n');
|
37
40
|
}
|
38
41
|
}
|
42
|
+
exports.LogData = LogData;
|
@@ -1,14 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ensureCLI = exports.hasCLI = void 0;
|
4
|
+
const nodejs_process_1 = require("@kapeta/nodejs-process");
|
5
|
+
const taskManager_1 = require("../taskManager");
|
6
|
+
async function hasCLI() {
|
7
|
+
return (0, nodejs_process_1.hasApp)('kap');
|
5
8
|
}
|
6
|
-
|
9
|
+
exports.hasCLI = hasCLI;
|
10
|
+
async function ensureCLI() {
|
7
11
|
if (await hasCLI()) {
|
8
12
|
return null;
|
9
13
|
}
|
10
|
-
return taskManager.add(`cli:install`, () => {
|
11
|
-
const process = spawn('npm', ['install', '-g', '@kapeta/kap'], {
|
14
|
+
return taskManager_1.taskManager.add(`cli:install`, () => {
|
15
|
+
const process = (0, nodejs_process_1.spawn)('npm', ['install', '-g', '@kapeta/kap'], {
|
12
16
|
shell: true,
|
13
17
|
});
|
14
18
|
return process.wait();
|
@@ -16,3 +20,4 @@ export async function ensureCLI() {
|
|
16
20
|
name: `Installing Kapeta CLI`,
|
17
21
|
});
|
18
22
|
}
|
23
|
+
exports.ensureCLI = ensureCLI;
|
@@ -1,3 +1,6 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.pathTemplateParser = exports.PathTemplate = void 0;
|
1
4
|
const TYPE_VARIABLE = 'variable';
|
2
5
|
const TYPE_PATH = 'path';
|
3
6
|
/**
|
@@ -11,7 +14,7 @@ const TYPE_PATH = 'path';
|
|
11
14
|
* /foo/{bar:[0-9]+}/baz
|
12
15
|
*
|
13
16
|
*/
|
14
|
-
|
17
|
+
class PathTemplate {
|
15
18
|
_path;
|
16
19
|
_parts = [];
|
17
20
|
constructor(pathTemplate) {
|
@@ -108,9 +111,11 @@ export class PathTemplate {
|
|
108
111
|
return 'tmpl: ' + this.path;
|
109
112
|
}
|
110
113
|
}
|
114
|
+
exports.PathTemplate = PathTemplate;
|
111
115
|
/**
|
112
116
|
* Parses a path into a RESTPath
|
113
117
|
*/
|
114
|
-
|
118
|
+
function pathTemplateParser(path) {
|
115
119
|
return new PathTemplate(path);
|
116
120
|
}
|
121
|
+
exports.pathTemplateParser = pathTemplateParser;
|
@@ -1,40 +1,53 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.getBindHost = exports.isLinux = exports.isMac = exports.isWindows = exports.readYML = exports.normalizeKapetaUri = exports.getBlockInstanceContainerName = void 0;
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
8
|
+
const yaml_1 = __importDefault(require("yaml"));
|
9
|
+
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
10
|
+
const md5_1 = __importDefault(require("md5"));
|
11
|
+
function getBlockInstanceContainerName(systemId, instanceId) {
|
12
|
+
return `kapeta-block-instance-${(0, md5_1.default)(systemId + instanceId)}`;
|
7
13
|
}
|
8
|
-
|
14
|
+
exports.getBlockInstanceContainerName = getBlockInstanceContainerName;
|
15
|
+
function normalizeKapetaUri(uri) {
|
9
16
|
if (!uri) {
|
10
17
|
return '';
|
11
18
|
}
|
12
|
-
const uriObj = parseKapetaUri(uri);
|
19
|
+
const uriObj = (0, nodejs_utils_1.parseKapetaUri)(uri);
|
13
20
|
if (!uriObj.version) {
|
14
|
-
return `kapeta://${parseKapetaUri(uri).fullName}`;
|
21
|
+
return `kapeta://${(0, nodejs_utils_1.parseKapetaUri)(uri).fullName}`;
|
15
22
|
}
|
16
|
-
return `kapeta://${parseKapetaUri(uri).id}`;
|
23
|
+
return `kapeta://${(0, nodejs_utils_1.parseKapetaUri)(uri).id}`;
|
17
24
|
}
|
18
|
-
|
19
|
-
|
25
|
+
exports.normalizeKapetaUri = normalizeKapetaUri;
|
26
|
+
function readYML(path) {
|
27
|
+
const rawYaml = node_fs_1.default.readFileSync(path);
|
20
28
|
try {
|
21
|
-
return
|
29
|
+
return yaml_1.default.parse(rawYaml.toString());
|
22
30
|
}
|
23
31
|
catch (err) {
|
24
32
|
throw new Error(`Failed to parse plan YAML: ${err}`);
|
25
33
|
}
|
26
34
|
}
|
27
|
-
|
35
|
+
exports.readYML = readYML;
|
36
|
+
function isWindows() {
|
28
37
|
return 'win32' === process.platform;
|
29
38
|
}
|
30
|
-
|
39
|
+
exports.isWindows = isWindows;
|
40
|
+
function isMac() {
|
31
41
|
return 'darwin' === process.platform;
|
32
42
|
}
|
33
|
-
|
43
|
+
exports.isMac = isMac;
|
44
|
+
function isLinux() {
|
34
45
|
return !isWindows() && !isMac();
|
35
46
|
}
|
36
|
-
|
47
|
+
exports.isLinux = isLinux;
|
48
|
+
function getBindHost(preferredHost = '127.0.0.1') {
|
37
49
|
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
38
50
|
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
39
51
|
return isLinux() ? '0.0.0.0' : preferredHost;
|
40
52
|
}
|
53
|
+
exports.getBindHost = getBindHost;
|
package/dist/esm/start.js
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const index_1 = __importDefault(require("./index"));
|
7
|
+
index_1.default
|
3
8
|
.start()
|
4
9
|
.then(({ host, port }) => console.log('Listening on port %s:%s', host, port))
|
5
10
|
.catch((e) => {
|
package/index.ts
CHANGED
@@ -22,6 +22,7 @@ import { getBindHost } from './src/utils/utils';
|
|
22
22
|
import request from 'request';
|
23
23
|
import { repositoryManager } from './src/repositoryManager';
|
24
24
|
import { ensureCLI } from './src/utils/commandLineUtils';
|
25
|
+
import { defaultProviderInstaller } from './src/utils/DefaultProviderInstaller';
|
25
26
|
|
26
27
|
export type LocalClusterService = HTTP.Server & { host?: string; port?: number };
|
27
28
|
|
@@ -122,6 +123,8 @@ export default {
|
|
122
123
|
);
|
123
124
|
}
|
124
125
|
|
126
|
+
await defaultProviderInstaller.checkForDefault();
|
127
|
+
|
125
128
|
const clusterPort = storageService.get('cluster', 'port');
|
126
129
|
if (clusterPort) {
|
127
130
|
clusterService.setClusterServicePort(clusterPort);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.17.0",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -34,8 +34,8 @@
|
|
34
34
|
"dev": "nodemon -e js,ts,json ./start.ts",
|
35
35
|
"test": "echo its fine",
|
36
36
|
"clean": "rm -rf ./dist",
|
37
|
-
"build:esm": "tsc --module
|
38
|
-
"build:cjs": "tsc
|
37
|
+
"build:esm": "tsc --module nodenext --moduleResolution nodenext --outDir ./dist/esm && echo '{\"type\":\"module\"}' > ./dist/esm/package.json",
|
38
|
+
"build:cjs": "tsc --outDir ./dist/cjs && echo '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json",
|
39
39
|
"build": "npm run clean && npm run build:esm && npm run build:cjs",
|
40
40
|
"format": "prettier --write .",
|
41
41
|
"lint": "tsc --noEmit && eslint src/**/*.ts",
|
@@ -57,7 +57,8 @@
|
|
57
57
|
"express": "4.17.1",
|
58
58
|
"express-promise-router": "^4.1.1",
|
59
59
|
"fs-extra": "^11.1.0",
|
60
|
-
"glob": "7.1.6",
|
60
|
+
"glob": "^7.1.6",
|
61
|
+
"gunzip-maybe": "^1.4.2",
|
61
62
|
"lodash": "^4.17.15",
|
62
63
|
"md5": "2.2.1",
|
63
64
|
"node-cache": "^5.1.2",
|
@@ -66,6 +67,7 @@
|
|
66
67
|
"request": "2.88.2",
|
67
68
|
"request-promise": "4.2.6",
|
68
69
|
"socket.io": "^4.5.2",
|
70
|
+
"tar-stream": "^3.1.6",
|
69
71
|
"typescript": "^5.1.6",
|
70
72
|
"yaml": "^1.6.0"
|
71
73
|
},
|
@@ -76,10 +78,14 @@
|
|
76
78
|
"@types/async-lock": "^1.4.0",
|
77
79
|
"@types/express": "^4.17.17",
|
78
80
|
"@types/fs-extra": "^11.0.1",
|
81
|
+
"@types/glob": "^8.1.0",
|
82
|
+
"@types/gunzip-maybe": "^1.4.0",
|
79
83
|
"@types/lodash": "^4.14.195",
|
80
84
|
"@types/md5": "^2.3.2",
|
85
|
+
"@types/node": "^20.5.8",
|
81
86
|
"@types/node-uuid": "^0.0.29",
|
82
87
|
"@types/request": "^2.48.8",
|
88
|
+
"@types/tar-stream": "^2.2.2",
|
83
89
|
"eslint": "^8.42.0",
|
84
90
|
"eslint-config-prettier": "^8.8.0",
|
85
91
|
"nodemon": "^2.0.2",
|
package/src/instanceManager.ts
CHANGED
@@ -22,7 +22,7 @@ const DEFAULT_HEALTH_PORT_TYPE = 'rest';
|
|
22
22
|
const MIN_TIME_RUNNING = 30000; //If something didnt run for more than 30 secs - it failed
|
23
23
|
|
24
24
|
export class InstanceManager {
|
25
|
-
private _interval:
|
25
|
+
private _interval: any = undefined;
|
26
26
|
|
27
27
|
private readonly _instances: InstanceInfo[] = [];
|
28
28
|
|
package/src/socketManager.ts
CHANGED
@@ -37,10 +37,16 @@ export class SocketManager {
|
|
37
37
|
}
|
38
38
|
|
39
39
|
emit(context: string, type: string, payload: any) {
|
40
|
+
if (!this._io) {
|
41
|
+
return;
|
42
|
+
}
|
40
43
|
this.io.to(context).emit(type, { context, payload });
|
41
44
|
}
|
42
45
|
|
43
46
|
emitGlobal(type: string, payload: any) {
|
47
|
+
if (!this._io) {
|
48
|
+
return;
|
49
|
+
}
|
44
50
|
this.io.emit(type, payload);
|
45
51
|
}
|
46
52
|
|
@@ -0,0 +1,141 @@
|
|
1
|
+
import Path from 'node:path';
|
2
|
+
import OS from 'node:os';
|
3
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
4
|
+
import FS from 'fs-extra';
|
5
|
+
import request from 'request';
|
6
|
+
import { extract } from 'tar-stream';
|
7
|
+
import gunzip from 'gunzip-maybe';
|
8
|
+
import { filesystemManager } from '../filesystemManager';
|
9
|
+
import { Actions } from '@kapeta/nodejs-registry-utils';
|
10
|
+
import { ProgressListener } from '../progressListener';
|
11
|
+
import { glob } from 'glob';
|
12
|
+
|
13
|
+
const DEFAULT_PROVIDERS_URL = 'https://storage.googleapis.com/kapeta-production-cdn/archives/default-providers.tar.gz';
|
14
|
+
const DEFAULT_PROJECT_HOME_DIR = 'KapetaProjects';
|
15
|
+
|
16
|
+
const ARCHIVE_LOCAL_PREFIX = 'local';
|
17
|
+
|
18
|
+
class DefaultProviderInstaller {
|
19
|
+
private readonly progressListener = new ProgressListener();
|
20
|
+
|
21
|
+
public async checkForDefault() {
|
22
|
+
const definitions = ClusterConfiguration.getDefinitions();
|
23
|
+
if (definitions.length < 1) {
|
24
|
+
console.log('Installing default providers');
|
25
|
+
try {
|
26
|
+
await this.install();
|
27
|
+
} catch (e) {
|
28
|
+
console.warn('Failed to install defaults', e);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
private async install() {
|
34
|
+
await this.download();
|
35
|
+
await this.linkLocal();
|
36
|
+
}
|
37
|
+
|
38
|
+
private async linkLocal() {
|
39
|
+
const projectBase = await this.ensureDefaultProjectHome();
|
40
|
+
const folders = this.scanProjectBase(projectBase);
|
41
|
+
for (let folder of folders) {
|
42
|
+
console.log('Linking %s', folder);
|
43
|
+
await Actions.link(this.progressListener, folder);
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
private scanProjectBase(projectBase: string) {
|
48
|
+
const assetFiles = glob.sync('*/**/kapeta.yml', { cwd: projectBase });
|
49
|
+
return assetFiles.map((assetFile) => {
|
50
|
+
return Path.dirname(Path.join(projectBase, assetFile));
|
51
|
+
});
|
52
|
+
}
|
53
|
+
|
54
|
+
private async ensureDefaultProjectHome(): Promise<string> {
|
55
|
+
const defaultProjectHome = Path.join(OS.homedir(), DEFAULT_PROJECT_HOME_DIR);
|
56
|
+
let projectBase = filesystemManager.getProjectRootFolder();
|
57
|
+
|
58
|
+
if (!projectBase) {
|
59
|
+
filesystemManager.setProjectRootFolder(defaultProjectHome);
|
60
|
+
projectBase = defaultProjectHome;
|
61
|
+
if (!(await FS.pathExists(projectBase))) {
|
62
|
+
await FS.mkdirp(projectBase);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
return projectBase;
|
66
|
+
}
|
67
|
+
|
68
|
+
private async download() {
|
69
|
+
const projectBase: string = await this.ensureDefaultProjectHome();
|
70
|
+
const repoBase: string = ClusterConfiguration.getRepositoryBasedir();
|
71
|
+
|
72
|
+
return new Promise<void>((resolve, reject) => {
|
73
|
+
const extractor = extract();
|
74
|
+
const dirCache = new Set<string>();
|
75
|
+
extractor.on('entry', async function (header, stream, next) {
|
76
|
+
if (header.type !== 'file') {
|
77
|
+
stream.on('end', function () {
|
78
|
+
next(); // ready for next entry
|
79
|
+
});
|
80
|
+
stream.resume(); // just auto drain the stream
|
81
|
+
return;
|
82
|
+
}
|
83
|
+
|
84
|
+
// Local (editable) assets should be stored in the project folder
|
85
|
+
// - installed assets goes into the repository folder
|
86
|
+
const baseDir: string = header.name.startsWith(ARCHIVE_LOCAL_PREFIX) ? projectBase : repoBase;
|
87
|
+
|
88
|
+
const parts = header.name.split(/\//g);
|
89
|
+
parts.shift();
|
90
|
+
const filename = parts.join(Path.sep);
|
91
|
+
|
92
|
+
try {
|
93
|
+
const dirname = Path.join(baseDir, Path.dirname(filename));
|
94
|
+
if (!dirCache.has(dirname)) {
|
95
|
+
let dirExists = false;
|
96
|
+
try {
|
97
|
+
await FS.stat(dirname);
|
98
|
+
dirExists = true;
|
99
|
+
} catch (e) {}
|
100
|
+
if (!dirExists) {
|
101
|
+
await FS.mkdirp(dirname);
|
102
|
+
}
|
103
|
+
dirCache.add(dirname);
|
104
|
+
}
|
105
|
+
const fileTarget = Path.join(baseDir, filename);
|
106
|
+
stream.on('error', (err) => {
|
107
|
+
reject(err);
|
108
|
+
});
|
109
|
+
stream.on('end', next);
|
110
|
+
|
111
|
+
stream.pipe(
|
112
|
+
FS.createWriteStream(fileTarget, {
|
113
|
+
mode: header.mode,
|
114
|
+
})
|
115
|
+
);
|
116
|
+
} catch (e) {
|
117
|
+
reject(e);
|
118
|
+
}
|
119
|
+
});
|
120
|
+
|
121
|
+
extractor.on('finish', function () {
|
122
|
+
// all entries done - lets finalize it
|
123
|
+
console.log('Default providers installed');
|
124
|
+
resolve();
|
125
|
+
});
|
126
|
+
|
127
|
+
extractor.on('error', function (err) {
|
128
|
+
reject(err);
|
129
|
+
});
|
130
|
+
|
131
|
+
console.log('Downloading default providers from %s', DEFAULT_PROVIDERS_URL);
|
132
|
+
const response = request(DEFAULT_PROVIDERS_URL);
|
133
|
+
response.on('error', function (err) {
|
134
|
+
reject(err);
|
135
|
+
});
|
136
|
+
response.pipe(gunzip()).pipe(extractor);
|
137
|
+
});
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
export const defaultProviderInstaller = new DefaultProviderInstaller();
|
package/tsconfig.json
CHANGED