@kapeta/local-cluster-service 0.12.1 → 0.14.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 +14 -0
  2. package/dist/cjs/index.js +4 -0
  3. package/dist/cjs/src/api.d.ts +3 -0
  4. package/dist/cjs/src/api.js +22 -0
  5. package/dist/cjs/src/assetManager.d.ts +3 -1
  6. package/dist/cjs/src/assetManager.js +20 -4
  7. package/dist/cjs/src/assets/routes.js +23 -2
  8. package/dist/cjs/src/containerManager.js +130 -109
  9. package/dist/cjs/src/instanceManager.d.ts +4 -3
  10. package/dist/cjs/src/instanceManager.js +80 -59
  11. package/dist/cjs/src/instances/routes.js +19 -11
  12. package/dist/cjs/src/operatorManager.d.ts +5 -3
  13. package/dist/cjs/src/operatorManager.js +34 -23
  14. package/dist/cjs/src/providerManager.js +1 -1
  15. package/dist/cjs/src/repositoryManager.d.ts +2 -4
  16. package/dist/cjs/src/repositoryManager.js +51 -66
  17. package/dist/cjs/src/socketManager.js +1 -1
  18. package/dist/cjs/src/taskManager.d.ts +64 -0
  19. package/dist/cjs/src/taskManager.js +161 -0
  20. package/dist/cjs/src/tasks/routes.d.ts +3 -0
  21. package/dist/cjs/src/tasks/routes.js +35 -0
  22. package/dist/esm/index.js +4 -0
  23. package/dist/esm/src/api.d.ts +3 -0
  24. package/dist/esm/src/api.js +17 -0
  25. package/dist/esm/src/assetManager.d.ts +3 -1
  26. package/dist/esm/src/assetManager.js +20 -4
  27. package/dist/esm/src/assets/routes.js +23 -2
  28. package/dist/esm/src/containerManager.js +130 -109
  29. package/dist/esm/src/instanceManager.d.ts +4 -3
  30. package/dist/esm/src/instanceManager.js +80 -59
  31. package/dist/esm/src/instances/routes.js +19 -11
  32. package/dist/esm/src/operatorManager.d.ts +5 -3
  33. package/dist/esm/src/operatorManager.js +34 -23
  34. package/dist/esm/src/providerManager.js +1 -1
  35. package/dist/esm/src/repositoryManager.d.ts +2 -4
  36. package/dist/esm/src/repositoryManager.js +51 -66
  37. package/dist/esm/src/socketManager.js +1 -1
  38. package/dist/esm/src/taskManager.d.ts +64 -0
  39. package/dist/esm/src/taskManager.js +157 -0
  40. package/dist/esm/src/tasks/routes.d.ts +3 -0
  41. package/dist/esm/src/tasks/routes.js +30 -0
  42. package/index.ts +9 -0
  43. package/package.json +2 -1
  44. package/src/api.ts +21 -0
  45. package/src/assetManager.ts +28 -4
  46. package/src/assets/routes.ts +24 -2
  47. package/src/containerManager.ts +151 -126
  48. package/src/instanceManager.ts +106 -70
  49. package/src/instances/routes.ts +18 -12
  50. package/src/operatorManager.ts +46 -28
  51. package/src/providerManager.ts +1 -1
  52. package/src/repositoryManager.ts +65 -63
  53. package/src/socketManager.ts +1 -1
  54. package/src/taskManager.ts +223 -0
  55. package/src/tasks/routes.ts +38 -0
  56. package/src/utils/BlockInstanceRunner.ts +0 -2
@@ -1,10 +1,12 @@
1
+ import { DefinitionInfo } from '@kapeta/local-cluster-config';
1
2
  import { ContainerInfo } from './containerManager';
2
3
  import { EnvironmentType, OperatorInfo } from './types';
3
4
  export declare const KIND_OPERATOR = "core/resource-type-operator";
4
5
  declare class Operator {
5
- private _data;
6
- constructor(data: any);
7
- getData(): any;
6
+ private readonly _data;
7
+ constructor(data: DefinitionInfo);
8
+ getLocalData(): any;
9
+ getDefinitionInfo(): DefinitionInfo;
8
10
  getCredentials(): any;
9
11
  }
10
12
  declare class OperatorManager {
@@ -9,17 +9,21 @@ import { definitionsManager } from './definitionsManager';
9
9
  import { getBindHost, normalizeKapetaUri } from './utils/utils';
10
10
  import _ from 'lodash';
11
11
  import AsyncLock from 'async-lock';
12
+ import { taskManager } from './taskManager';
12
13
  export const KIND_OPERATOR = 'core/resource-type-operator';
13
14
  class Operator {
14
15
  _data;
15
16
  constructor(data) {
16
17
  this._data = data;
17
18
  }
18
- getData() {
19
+ getLocalData() {
20
+ return this._data.definition.spec.local;
21
+ }
22
+ getDefinitionInfo() {
19
23
  return this._data;
20
24
  }
21
25
  getCredentials() {
22
- return this._data.credentials;
26
+ return this._data.definition.spec.local.credentials;
23
27
  }
24
28
  }
25
29
  class OperatorManager {
@@ -52,7 +56,7 @@ class OperatorManager {
52
56
  if (!operator.definition.spec || !operator.definition.spec.local) {
53
57
  throw new Error(`Operator missing local definition: ${resourceType}:${version}`);
54
58
  }
55
- return new Operator(operator.definition.spec.local);
59
+ return new Operator(operator);
56
60
  }
57
61
  /**
58
62
  * Get information about a specific consumed resource
@@ -113,7 +117,7 @@ class OperatorManager {
113
117
  const key = `${systemId}#${resourceType}:${version}`;
114
118
  return await this.operatorLock.acquire(key, async () => {
115
119
  const operator = this.getOperator(resourceType, version);
116
- const operatorData = operator.getData();
120
+ const operatorData = operator.getLocalData();
117
121
  const portTypes = Object.keys(operatorData.ports);
118
122
  portTypes.sort();
119
123
  const ports = {};
@@ -141,6 +145,7 @@ class OperatorManager {
141
145
  const Labels = {
142
146
  kapeta: 'true',
143
147
  };
148
+ const operatorMetadata = operator.getDefinitionInfo().definition.metadata;
144
149
  const bindHost = getBindHost();
145
150
  const ExposedPorts = {};
146
151
  _.forEach(ports, (portInfo, containerPort) => {
@@ -157,26 +162,32 @@ class OperatorManager {
157
162
  _.forEach(operatorData.env, (value, name) => {
158
163
  Env.push(name + '=' + value);
159
164
  });
160
- let HealthCheck = undefined;
161
- if (operatorData.health) {
162
- HealthCheck = containerManager.toDockerHealth(operatorData.health);
163
- }
164
- const container = await containerManager.ensureContainer({
165
- name: containerName,
166
- Image: operatorData.image,
167
- Hostname: containerName + '.kapeta',
168
- Labels,
169
- Cmd: operatorData.cmd,
170
- ExposedPorts,
171
- Env,
172
- HealthCheck,
173
- HostConfig: {
174
- PortBindings,
175
- Mounts,
176
- },
165
+ const task = taskManager.add(`operator:ensure:${key}`, async () => {
166
+ let HealthCheck = undefined;
167
+ if (operatorData.health) {
168
+ HealthCheck = containerManager.toDockerHealth(operatorData.health);
169
+ }
170
+ const container = await containerManager.ensureContainer({
171
+ name: containerName,
172
+ Image: operatorData.image,
173
+ Hostname: containerName + '.kapeta',
174
+ Labels,
175
+ Cmd: operatorData.cmd,
176
+ ExposedPorts,
177
+ Env,
178
+ HealthCheck,
179
+ HostConfig: {
180
+ PortBindings,
181
+ Mounts,
182
+ },
183
+ });
184
+ await containerManager.waitForReady(container);
185
+ return new ContainerInfo(container);
186
+ }, {
187
+ name: `Ensuring ${operatorMetadata.title ?? operatorMetadata.name}`,
188
+ systemId,
177
189
  });
178
- await containerManager.waitForReady(container);
179
- return new ContainerInfo(container);
190
+ return task.wait();
180
191
  });
181
192
  }
182
193
  }
@@ -16,7 +16,7 @@ class ProviderManager {
16
16
  if (this._webAssetCache[id] && (await FSExtra.pathExists(this._webAssetCache[id]))) {
17
17
  return FSExtra.readFile(this._webAssetCache[id], 'utf8');
18
18
  }
19
- await repositoryManager.ensureAsset(handle, name, version);
19
+ await repositoryManager.ensureAsset(handle, name, version, true);
20
20
  const installedProvider = this.getWebProviders().find((providerDefinition) => {
21
21
  return providerDefinition.definition.metadata.name === fullName && providerDefinition.version === version;
22
22
  });
@@ -1,17 +1,15 @@
1
+ import { Task } from './taskManager';
1
2
  declare class RepositoryManager {
2
3
  private changeEventsEnabled;
3
4
  private _registryService;
4
5
  private _cache;
5
6
  private watcher?;
6
- private _installQueue;
7
- private _processing;
8
7
  constructor();
9
8
  setChangeEventsEnabled(enabled: boolean): void;
10
9
  listenForChanges(): void;
11
10
  stopListening(): void;
12
11
  private _install;
13
- _processNext(): Promise<void>;
14
- ensureAsset(handle: string, name: string, version: string): Promise<void>;
12
+ ensureAsset(handle: string, name: string, version: string, wait?: boolean): Promise<undefined | Task[]>;
15
13
  }
16
14
  export declare const repositoryManager: RepositoryManager;
17
15
  export {};
@@ -9,20 +9,20 @@ import { socketManager } from './socketManager';
9
9
  import { progressListener } from './progressListener';
10
10
  import { Actions, Config, RegistryService } from '@kapeta/nodejs-registry-utils';
11
11
  import { definitionsManager } from './definitionsManager';
12
+ import { taskManager } from './taskManager';
13
+ import { normalizeKapetaUri } from './utils/utils';
14
+ import { assetManager } from './assetManager';
12
15
  const INSTALL_ATTEMPTED = {};
13
16
  class RepositoryManager {
14
17
  changeEventsEnabled;
15
18
  _registryService;
16
19
  _cache;
17
20
  watcher;
18
- _installQueue;
19
- _processing = false;
20
21
  constructor() {
21
22
  this.changeEventsEnabled = true;
22
23
  this.listenForChanges();
23
24
  this._registryService = new RegistryService(Config.data.registry.url);
24
25
  this._cache = {};
25
- this._installQueue = [];
26
26
  }
27
27
  setChangeEventsEnabled(enabled) {
28
28
  this.changeEventsEnabled = enabled;
@@ -103,74 +103,54 @@ class RepositoryManager {
103
103
  }
104
104
  async _install(refs) {
105
105
  //We make sure to only install one asset at a time - otherwise unexpected things might happen
106
- const out = new Promise((resolve, reject) => {
107
- this._installQueue.push(async () => {
108
- try {
109
- const normalizedRefs = refs.map((ref) => parseKapetaUri(ref).id);
110
- const filteredRefs = normalizedRefs
111
- .filter((ref) => !INSTALL_ATTEMPTED[ref])
112
- .filter((ref) => !definitionsManager.exists(ref));
113
- if (filteredRefs.length > 0) {
114
- console.log(`Auto-installing dependencies: ${filteredRefs.join(', ')}`);
115
- filteredRefs.forEach((ref) => (INSTALL_ATTEMPTED[ref] = true));
116
- //Auto-install missing asset
117
- try {
118
- //We change to a temp dir to avoid issues with the current working directory
119
- process.chdir(os.tmpdir());
120
- //Disable change events while installing
121
- this.setChangeEventsEnabled(false);
122
- socketManager.emit(`install`, 'install:action', {
123
- type: 'start',
124
- refs,
125
- });
126
- await Actions.install(progressListener, normalizedRefs, {});
127
- socketManager.emit(`install`, 'install:action', {
128
- type: 'done',
129
- refs,
130
- });
131
- }
132
- catch (e) {
133
- socketManager.emit(`install`, 'install:action', {
134
- type: 'failed',
135
- refs,
136
- error: e.message,
137
- });
138
- }
139
- finally {
140
- this.setChangeEventsEnabled(true);
141
- }
142
- }
143
- resolve();
106
+ const createInstaller = (ref) => {
107
+ return async () => {
108
+ if (INSTALL_ATTEMPTED[ref]) {
109
+ return;
144
110
  }
145
- catch (e) {
146
- reject(e);
111
+ if (definitionsManager.exists(ref)) {
112
+ return;
147
113
  }
148
- finally {
149
- this._processNext().catch((e) => console.error(e));
114
+ console.log(`Installing asset: ${ref}`);
115
+ INSTALL_ATTEMPTED[ref] = true;
116
+ //Auto-install missing asset
117
+ try {
118
+ //We change to a temp dir to avoid issues with the current working directory
119
+ process.chdir(os.tmpdir());
120
+ //Disable change events while installing
121
+ this.setChangeEventsEnabled(false);
122
+ await Actions.install(progressListener, [ref], {});
150
123
  }
151
- });
152
- });
153
- this._processNext().catch((e) => console.error(e));
154
- return out;
155
- }
156
- async _processNext() {
157
- if (this._processing) {
158
- return;
159
- }
160
- this._processing = true;
161
- try {
162
- while (this._installQueue.length > 0) {
163
- const item = this._installQueue.shift();
164
- if (item) {
165
- await item();
124
+ finally {
125
+ this.setChangeEventsEnabled(true);
166
126
  }
127
+ definitionsManager.clearCache();
128
+ assetManager.clearCache();
129
+ console.log(`Asset installed: ${ref}`);
130
+ };
131
+ };
132
+ const tasks = [];
133
+ while (refs.length > 0) {
134
+ let ref = refs.shift();
135
+ if (!ref) {
136
+ continue;
167
137
  }
138
+ ref = normalizeKapetaUri(ref);
139
+ if (INSTALL_ATTEMPTED[ref]) {
140
+ continue;
141
+ }
142
+ if (definitionsManager.exists(ref)) {
143
+ continue;
144
+ }
145
+ const task = taskManager.add(`asset:install:${ref}`, createInstaller(ref), {
146
+ name: `Installing ${ref}`,
147
+ group: 'asset:install:',
148
+ });
149
+ tasks.push(task);
168
150
  }
169
- finally {
170
- this._processing = false;
171
- }
151
+ return tasks;
172
152
  }
173
- async ensureAsset(handle, name, version) {
153
+ async ensureAsset(handle, name, version, wait = true) {
174
154
  const fullName = `${handle}/${name}`;
175
155
  const ref = `${fullName}:${version}`;
176
156
  if (version === 'local') {
@@ -201,16 +181,21 @@ class RepositoryManager {
201
181
  throw e;
202
182
  }
203
183
  this._cache[ref] = true;
184
+ let tasks = undefined;
204
185
  if (!installedAsset) {
205
- await this._install([ref]);
186
+ tasks = await this._install([ref]);
206
187
  }
207
188
  else {
208
189
  //Ensure dependencies are installed
209
190
  const refs = assetVersion.dependencies.map((dep) => dep.name);
210
191
  if (refs.length > 0) {
211
- await this._install(refs);
192
+ tasks = await this._install(refs);
212
193
  }
213
194
  }
195
+ if (tasks && wait) {
196
+ await Promise.all(tasks.map((t) => t.future.promise));
197
+ }
198
+ return tasks;
214
199
  }
215
200
  }
216
201
  export const repositoryManager = new RepositoryManager();
@@ -24,7 +24,7 @@ export class SocketManager {
24
24
  this.io.to(context).emit(type, { context, payload });
25
25
  }
26
26
  emitGlobal(type, payload) {
27
- this.io.emit(type, { payload });
27
+ this.io.emit(type, payload);
28
28
  }
29
29
  _bindIO() {
30
30
  this.io.on('connection', (socket) => this._handleSocketCreated(socket));
@@ -0,0 +1,64 @@
1
+ export type TaskRunner<T> = (task: Task<T>) => Promise<T>;
2
+ export declare enum TaskStatus {
3
+ PENDING = "PENDING",
4
+ RUNNING = "RUNNING",
5
+ COMPLETED = "COMPLETED",
6
+ FAILED = "FAILED"
7
+ }
8
+ interface Future<T = void> {
9
+ promise: Promise<T>;
10
+ resolve: (result: T) => void;
11
+ reject: (e: any) => void;
12
+ }
13
+ interface TaskMetadata {
14
+ name: string;
15
+ /**
16
+ * A unique prefix for the task. If defined only 1 task with this ID prefix will be executed at a time
17
+ */
18
+ group?: string;
19
+ progress?: number;
20
+ [key: string]: any;
21
+ }
22
+ interface TaskData<T = void> {
23
+ id: string;
24
+ status: TaskStatus;
25
+ errorMessage?: string;
26
+ metadata: TaskMetadata;
27
+ future: Future<T>;
28
+ run: TaskRunner<T>;
29
+ }
30
+ export declare class Task<T = void> implements TaskData<T> {
31
+ private data;
32
+ constructor(task: TaskData<T>);
33
+ get id(): string;
34
+ get status(): TaskStatus;
35
+ get errorMessage(): string | undefined;
36
+ get metadata(): TaskMetadata;
37
+ get future(): Future<T>;
38
+ get run(): TaskRunner<T>;
39
+ set status(status: TaskStatus);
40
+ set errorMessage(errorMessage: string | undefined);
41
+ set metadata(metadata: TaskMetadata);
42
+ emitUpdate(): void;
43
+ wait(): Promise<T>;
44
+ toData(): {
45
+ id: string;
46
+ status: TaskStatus;
47
+ errorMessage?: string | undefined;
48
+ metadata: TaskMetadata;
49
+ future: Future<T>;
50
+ run: TaskRunner<T>;
51
+ };
52
+ }
53
+ declare class TaskManager {
54
+ private _tasks;
55
+ add<T>(id: string, runner: TaskRunner<T>, metadata: TaskMetadata): Task<T>;
56
+ waitFor(filter: (task: Task<any>) => boolean): Promise<void>;
57
+ get(taskId: string): Task<any> | undefined;
58
+ exists(taskId: string): boolean;
59
+ remove(taskId: string): void;
60
+ list(): TaskData[];
61
+ private invokeTask;
62
+ }
63
+ export declare const taskManager: TaskManager;
64
+ export {};
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Class that handles processing background tasks.
3
+ */
4
+ import { socketManager } from './socketManager';
5
+ const EVENT_TASK_UPDATED = 'task-updated';
6
+ const EVENT_TASK_ADDED = 'task-added';
7
+ const EVENT_TASK_REMOVED = 'task-removed';
8
+ export var TaskStatus;
9
+ (function (TaskStatus) {
10
+ TaskStatus["PENDING"] = "PENDING";
11
+ TaskStatus["RUNNING"] = "RUNNING";
12
+ TaskStatus["COMPLETED"] = "COMPLETED";
13
+ TaskStatus["FAILED"] = "FAILED";
14
+ })(TaskStatus || (TaskStatus = {}));
15
+ export class Task {
16
+ data;
17
+ constructor(task) {
18
+ this.data = task;
19
+ }
20
+ get id() {
21
+ return this.data.id;
22
+ }
23
+ get status() {
24
+ return this.data.status;
25
+ }
26
+ get errorMessage() {
27
+ return this.data.errorMessage;
28
+ }
29
+ get metadata() {
30
+ return this.data.metadata;
31
+ }
32
+ get future() {
33
+ return this.data.future;
34
+ }
35
+ get run() {
36
+ return this.data.run;
37
+ }
38
+ set status(status) {
39
+ this.data.status = status;
40
+ }
41
+ set errorMessage(errorMessage) {
42
+ this.data.errorMessage = errorMessage;
43
+ }
44
+ set metadata(metadata) {
45
+ this.data.metadata = metadata;
46
+ }
47
+ emitUpdate() {
48
+ socketManager.emitGlobal(EVENT_TASK_UPDATED, this.toData());
49
+ }
50
+ async wait() {
51
+ return this.future.promise;
52
+ }
53
+ toData() {
54
+ return { ...this.data };
55
+ }
56
+ }
57
+ function createFuture() {
58
+ let resolve = () => { };
59
+ let reject = () => { };
60
+ const promise = new Promise((res, rej) => {
61
+ resolve = res;
62
+ reject = rej;
63
+ });
64
+ return {
65
+ promise,
66
+ resolve,
67
+ reject,
68
+ };
69
+ }
70
+ class TaskManager {
71
+ _tasks = [];
72
+ add(id, runner, metadata) {
73
+ const existingTask = this.get(id);
74
+ if (existingTask) {
75
+ return existingTask;
76
+ }
77
+ const future = createFuture();
78
+ const task = new Task({
79
+ id,
80
+ status: TaskStatus.PENDING,
81
+ metadata,
82
+ future,
83
+ run: runner,
84
+ });
85
+ this._tasks.push(task);
86
+ socketManager.emitGlobal(EVENT_TASK_ADDED, task.toData());
87
+ this.invokeTask(task).catch(() => { });
88
+ return task;
89
+ }
90
+ async waitFor(filter) {
91
+ const tasks = this._tasks.filter(filter);
92
+ while (tasks.length > 0) {
93
+ const task = tasks.shift();
94
+ if (!task) {
95
+ continue;
96
+ }
97
+ try {
98
+ await task.wait();
99
+ }
100
+ catch (e) {
101
+ //Ignore
102
+ }
103
+ }
104
+ }
105
+ get(taskId) {
106
+ return this._tasks.find((t) => t.id === taskId);
107
+ }
108
+ exists(taskId) {
109
+ return !!this.get(taskId);
110
+ }
111
+ remove(taskId) {
112
+ const task = this.get(taskId);
113
+ if (!task) {
114
+ return;
115
+ }
116
+ if (task.status === TaskStatus.RUNNING) {
117
+ throw new Error('Cannot remove a running task');
118
+ }
119
+ this._tasks = this._tasks.filter((t) => t.id !== taskId);
120
+ socketManager.emitGlobal(EVENT_TASK_REMOVED, task.toData());
121
+ }
122
+ list() {
123
+ return this._tasks.map((t) => t.toData());
124
+ }
125
+ async invokeTask(task) {
126
+ if (task.metadata.group) {
127
+ const existingTaskInGroup = this._tasks.find((t) => t.id !== task.id && t.metadata.group === task.metadata.group && t.status === TaskStatus.RUNNING);
128
+ if (existingTaskInGroup) {
129
+ return;
130
+ }
131
+ }
132
+ try {
133
+ task.status = TaskStatus.RUNNING;
134
+ task.emitUpdate();
135
+ const result = await task.run(task);
136
+ task.status = TaskStatus.COMPLETED;
137
+ task.future.resolve(result);
138
+ task.emitUpdate();
139
+ }
140
+ catch (e) {
141
+ task.errorMessage = e.message;
142
+ task.status = TaskStatus.FAILED;
143
+ task.future.reject(e);
144
+ task.emitUpdate();
145
+ }
146
+ finally {
147
+ this.remove(task.id);
148
+ }
149
+ if (task.metadata.group) {
150
+ const nextTaskInGroup = this._tasks.find((t) => t.id !== task.id && t.metadata.group === task.metadata.group && t.status === TaskStatus.PENDING);
151
+ if (nextTaskInGroup) {
152
+ return this.invokeTask(nextTaskInGroup);
153
+ }
154
+ }
155
+ }
156
+ }
157
+ export const taskManager = new TaskManager();
@@ -0,0 +1,3 @@
1
+ /// <reference types="express" />
2
+ declare const router: import("express").Router;
3
+ export default router;
@@ -0,0 +1,30 @@
1
+ import Router from 'express-promise-router';
2
+ import { corsHandler } from '../middleware/cors';
3
+ import { taskManager } from '../taskManager';
4
+ const router = Router();
5
+ router.use('/', corsHandler);
6
+ /**
7
+ * Get all current tasks
8
+ */
9
+ router.get('/', (req, res) => {
10
+ res.send(taskManager.list());
11
+ });
12
+ router.get('/:taskId', (req, res) => {
13
+ const task = taskManager.get(req.params.taskId);
14
+ if (!task) {
15
+ res.status(404).send({ error: 'Task not found' });
16
+ return;
17
+ }
18
+ res.send(task.toData());
19
+ });
20
+ router.delete('/:taskId', (req, res) => {
21
+ try {
22
+ taskManager.remove(req.params.taskId);
23
+ res.send({ ok: true });
24
+ }
25
+ catch (e) {
26
+ res.status(400).send({ error: e.message });
27
+ return;
28
+ }
29
+ });
30
+ export default router;
package/index.ts CHANGED
@@ -16,8 +16,14 @@ import FilesystemRoutes from './src/filesystem/routes';
16
16
  import AssetsRoutes from './src/assets/routes';
17
17
  import ProviderRoutes from './src/providers/routes';
18
18
  import AttachmentRoutes from './src/attachments/routes';
19
+ import TaskRoutes from './src/tasks/routes';
20
+ import APIRoutes from './src/api';
19
21
  import { getBindHost } from './src/utils/utils';
20
22
  import request from 'request';
23
+ import ClusterConfiguration from "@kapeta/local-cluster-config";
24
+ import {KapetaAPI} from "@kapeta/nodejs-api-client";
25
+ import {corsHandler} from "./src/middleware/cors";
26
+
21
27
 
22
28
  export type LocalClusterService = HTTP.Server & { host?: string; port?: number };
23
29
 
@@ -36,6 +42,9 @@ function createServer() {
36
42
  app.use('/assets', AssetsRoutes);
37
43
  app.use('/providers', ProviderRoutes);
38
44
  app.use('/attachments', AttachmentRoutes);
45
+ app.use('/tasks', TaskRoutes);
46
+ app.use('/api', APIRoutes);
47
+
39
48
  app.get('/status', async (req, res) => {
40
49
  res.send({
41
50
  ok: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.12.1",
3
+ "version": "0.14.0",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -50,6 +50,7 @@
50
50
  "@kapeta/nodejs-utils": "<2",
51
51
  "@kapeta/schemas": "^0.0.58",
52
52
  "@kapeta/sdk-config": "<2",
53
+ "@kapeta/web-microfrontend": "^0.2.1",
53
54
  "async-lock": "^1.4.0",
54
55
  "express": "4.17.1",
55
56
  "express-promise-router": "^4.1.1",
package/src/api.ts ADDED
@@ -0,0 +1,21 @@
1
+ import Router from 'express-promise-router';
2
+ import {corsHandler} from "./middleware/cors";
3
+ import {KapetaAPI} from "@kapeta/nodejs-api-client";
4
+ import ClusterConfiguration from '@kapeta/local-cluster-config';
5
+ const { createAPIRoute } = require('@kapeta/web-microfrontend/server');
6
+ const packageJson = require('../package.json');
7
+
8
+ const router = Router();
9
+
10
+ const remoteServices = ClusterConfiguration.getClusterConfig().remoteServices ?? {};
11
+ router.use('/', corsHandler)
12
+
13
+ router.use('/registry', createAPIRoute(remoteServices.registry ?? 'https://registry.kapeta.com', {
14
+ nonce: false,
15
+ userAgent: `KapetaDesktopCluster/${packageJson.version}`,
16
+ tokenFetcher: () => {
17
+ return new KapetaAPI().getAccessToken();
18
+ }
19
+ }));
20
+
21
+ export default router;