@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.
Files changed (56) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/index.js +2 -0
  3. package/dist/cjs/src/socketManager.js +6 -0
  4. package/dist/cjs/src/utils/DefaultProviderInstaller.d.ts +11 -0
  5. package/dist/cjs/src/utils/DefaultProviderInstaller.js +129 -0
  6. package/dist/esm/index.js +64 -57
  7. package/dist/esm/src/RepositoryWatcher.js +40 -33
  8. package/dist/esm/src/api.js +14 -9
  9. package/dist/esm/src/assetManager.js +62 -56
  10. package/dist/esm/src/assets/routes.js +22 -17
  11. package/dist/esm/src/attachments/routes.js +14 -9
  12. package/dist/esm/src/cacheManager.js +13 -5
  13. package/dist/esm/src/clusterService.js +6 -3
  14. package/dist/esm/src/codeGeneratorManager.js +19 -13
  15. package/dist/esm/src/config/routes.js +30 -25
  16. package/dist/esm/src/configManager.js +29 -26
  17. package/dist/esm/src/containerManager.js +48 -39
  18. package/dist/esm/src/definitionsManager.js +15 -9
  19. package/dist/esm/src/filesystem/routes.js +21 -16
  20. package/dist/esm/src/filesystemManager.js +23 -17
  21. package/dist/esm/src/identities/routes.js +13 -8
  22. package/dist/esm/src/instanceManager.js +163 -156
  23. package/dist/esm/src/instances/routes.js +38 -33
  24. package/dist/esm/src/middleware/cors.js +5 -1
  25. package/dist/esm/src/middleware/kapeta.js +8 -4
  26. package/dist/esm/src/middleware/stringBody.js +5 -1
  27. package/dist/esm/src/networkManager.js +15 -9
  28. package/dist/esm/src/operatorManager.js +45 -39
  29. package/dist/esm/src/progressListener.js +16 -12
  30. package/dist/esm/src/providerManager.js +22 -16
  31. package/dist/esm/src/providers/routes.js +14 -9
  32. package/dist/esm/src/proxy/routes.js +26 -21
  33. package/dist/esm/src/proxy/types/rest.js +29 -22
  34. package/dist/esm/src/proxy/types/web.js +18 -11
  35. package/dist/esm/src/repositoryManager.js +28 -22
  36. package/dist/esm/src/serviceManager.js +25 -19
  37. package/dist/esm/src/socketManager.js +31 -18
  38. package/dist/esm/src/storageService.js +18 -12
  39. package/dist/esm/src/taskManager.js +12 -8
  40. package/dist/esm/src/tasks/routes.js +14 -9
  41. package/dist/esm/src/traffic/routes.js +12 -7
  42. package/dist/esm/src/types.js +11 -8
  43. package/dist/esm/src/utils/BlockInstanceRunner.js +57 -50
  44. package/dist/esm/src/utils/DefaultProviderInstaller.d.ts +11 -0
  45. package/dist/esm/src/utils/DefaultProviderInstaller.js +129 -0
  46. package/dist/esm/src/utils/LogData.js +5 -1
  47. package/dist/esm/src/utils/commandLineUtils.js +12 -7
  48. package/dist/esm/src/utils/pathTemplateParser.js +7 -2
  49. package/dist/esm/src/utils/utils.js +30 -17
  50. package/dist/esm/start.js +7 -2
  51. package/index.ts +3 -0
  52. package/package.json +10 -4
  53. package/src/instanceManager.ts +1 -1
  54. package/src/socketManager.ts +6 -0
  55. package/src/utils/DefaultProviderInstaller.ts +141 -0
  56. 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
- export class LogData {
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
- import { spawn, hasApp } from '@kapeta/nodejs-process';
2
- import { taskManager } from '../taskManager';
3
- export async function hasCLI() {
4
- return hasApp('kap');
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
- export async function ensureCLI() {
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
- export class PathTemplate {
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
- export function pathTemplateParser(path) {
118
+ function pathTemplateParser(path) {
115
119
  return new PathTemplate(path);
116
120
  }
121
+ exports.pathTemplateParser = pathTemplateParser;
@@ -1,40 +1,53 @@
1
- import FS from 'node:fs';
2
- import YAML from 'yaml';
3
- import { parseKapetaUri } from '@kapeta/nodejs-utils';
4
- import md5 from 'md5';
5
- export function getBlockInstanceContainerName(systemId, instanceId) {
6
- return `kapeta-block-instance-${md5(systemId + instanceId)}`;
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
- export function normalizeKapetaUri(uri) {
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
- export function readYML(path) {
19
- const rawYaml = FS.readFileSync(path);
25
+ exports.normalizeKapetaUri = normalizeKapetaUri;
26
+ function readYML(path) {
27
+ const rawYaml = node_fs_1.default.readFileSync(path);
20
28
  try {
21
- return YAML.parse(rawYaml.toString());
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
- export function isWindows() {
35
+ exports.readYML = readYML;
36
+ function isWindows() {
28
37
  return 'win32' === process.platform;
29
38
  }
30
- export function isMac() {
39
+ exports.isWindows = isWindows;
40
+ function isMac() {
31
41
  return 'darwin' === process.platform;
32
42
  }
33
- export function isLinux() {
43
+ exports.isMac = isMac;
44
+ function isLinux() {
34
45
  return !isWindows() && !isMac();
35
46
  }
36
- export function getBindHost(preferredHost = '127.0.0.1') {
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
- import localClusterService from './index';
2
- localClusterService
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.16.8",
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 esnext --outDir ./dist/esm && echo '{\"type\":\"module\"}' > ./dist/esm/package.json",
38
- "build:cjs": "tsc --module commonjs --outDir ./dist/cjs && echo '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json",
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",
@@ -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: NodeJS.Timer | undefined = undefined;
25
+ private _interval: any = undefined;
26
26
 
27
27
  private readonly _instances: InstanceInfo[] = [];
28
28
 
@@ -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
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "extends": "@tsconfig/node18/tsconfig.json",
3
3
  "compilerOptions": {
4
+ "module": "node16",
5
+ "moduleResolution": "node16",
4
6
  "outDir": "./dist",
5
- "declaration": true,
6
- "esModuleInterop": true
7
+ "declaration": true
7
8
  },
8
9
  "ts-node": {
9
10
  "files": true