@kapeta/local-cluster-service 0.0.0-96f91ef

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 (274) hide show
  1. package/.eslintrc.cjs +25 -0
  2. package/.github/workflows/check-license.yml +17 -0
  3. package/.github/workflows/main.yml +26 -0
  4. package/.prettierignore +4 -0
  5. package/.vscode/launch.json +19 -0
  6. package/CHANGELOG.md +920 -0
  7. package/LICENSE +38 -0
  8. package/README.md +36 -0
  9. package/definitions.d.ts +35 -0
  10. package/dist/cjs/index.d.ts +34 -0
  11. package/dist/cjs/index.js +263 -0
  12. package/dist/cjs/package.json +1 -0
  13. package/dist/cjs/src/RepositoryWatcher.d.ts +30 -0
  14. package/dist/cjs/src/RepositoryWatcher.js +332 -0
  15. package/dist/cjs/src/ai/aiClient.d.ts +20 -0
  16. package/dist/cjs/src/ai/aiClient.js +74 -0
  17. package/dist/cjs/src/ai/routes.d.ts +7 -0
  18. package/dist/cjs/src/ai/routes.js +37 -0
  19. package/dist/cjs/src/ai/transform.d.ts +11 -0
  20. package/dist/cjs/src/ai/transform.js +239 -0
  21. package/dist/cjs/src/ai/types.d.ts +40 -0
  22. package/dist/cjs/src/ai/types.js +2 -0
  23. package/dist/cjs/src/api.d.ts +7 -0
  24. package/dist/cjs/src/api.js +29 -0
  25. package/dist/cjs/src/assetManager.d.ts +41 -0
  26. package/dist/cjs/src/assetManager.js +274 -0
  27. package/dist/cjs/src/assets/routes.d.ts +7 -0
  28. package/dist/cjs/src/assets/routes.js +165 -0
  29. package/dist/cjs/src/attachments/routes.d.ts +7 -0
  30. package/dist/cjs/src/attachments/routes.js +72 -0
  31. package/dist/cjs/src/authManager.d.ts +16 -0
  32. package/dist/cjs/src/authManager.js +64 -0
  33. package/dist/cjs/src/cacheManager.d.ts +20 -0
  34. package/dist/cjs/src/cacheManager.js +51 -0
  35. package/dist/cjs/src/clusterService.d.ts +44 -0
  36. package/dist/cjs/src/clusterService.js +120 -0
  37. package/dist/cjs/src/codeGeneratorManager.d.ts +14 -0
  38. package/dist/cjs/src/codeGeneratorManager.js +93 -0
  39. package/dist/cjs/src/config/routes.d.ts +7 -0
  40. package/dist/cjs/src/config/routes.js +160 -0
  41. package/dist/cjs/src/configManager.d.ts +42 -0
  42. package/dist/cjs/src/configManager.js +136 -0
  43. package/dist/cjs/src/containerManager.d.ts +148 -0
  44. package/dist/cjs/src/containerManager.js +958 -0
  45. package/dist/cjs/src/definitionsManager.d.ts +20 -0
  46. package/dist/cjs/src/definitionsManager.js +171 -0
  47. package/dist/cjs/src/filesystem/routes.d.ts +7 -0
  48. package/dist/cjs/src/filesystem/routes.js +105 -0
  49. package/dist/cjs/src/filesystemManager.d.ts +27 -0
  50. package/dist/cjs/src/filesystemManager.js +118 -0
  51. package/dist/cjs/src/identities/routes.d.ts +7 -0
  52. package/dist/cjs/src/identities/routes.js +37 -0
  53. package/dist/cjs/src/instanceManager.d.ts +69 -0
  54. package/dist/cjs/src/instanceManager.js +910 -0
  55. package/dist/cjs/src/instances/routes.d.ts +7 -0
  56. package/dist/cjs/src/instances/routes.js +179 -0
  57. package/dist/cjs/src/middleware/cors.d.ts +6 -0
  58. package/dist/cjs/src/middleware/cors.js +14 -0
  59. package/dist/cjs/src/middleware/kapeta.d.ts +15 -0
  60. package/dist/cjs/src/middleware/kapeta.js +28 -0
  61. package/dist/cjs/src/middleware/stringBody.d.ts +9 -0
  62. package/dist/cjs/src/middleware/stringBody.js +18 -0
  63. package/dist/cjs/src/networkManager.d.ts +37 -0
  64. package/dist/cjs/src/networkManager.js +119 -0
  65. package/dist/cjs/src/operatorManager.d.ts +41 -0
  66. package/dist/cjs/src/operatorManager.js +211 -0
  67. package/dist/cjs/src/progressListener.d.ts +31 -0
  68. package/dist/cjs/src/progressListener.js +133 -0
  69. package/dist/cjs/src/providerManager.d.ts +11 -0
  70. package/dist/cjs/src/providerManager.js +84 -0
  71. package/dist/cjs/src/providers/routes.d.ts +7 -0
  72. package/dist/cjs/src/providers/routes.js +46 -0
  73. package/dist/cjs/src/proxy/routes.d.ts +7 -0
  74. package/dist/cjs/src/proxy/routes.js +115 -0
  75. package/dist/cjs/src/proxy/types/rest.d.ts +10 -0
  76. package/dist/cjs/src/proxy/types/rest.js +123 -0
  77. package/dist/cjs/src/proxy/types/web.d.ts +8 -0
  78. package/dist/cjs/src/proxy/types/web.js +61 -0
  79. package/dist/cjs/src/repositoryManager.d.ts +35 -0
  80. package/dist/cjs/src/repositoryManager.js +247 -0
  81. package/dist/cjs/src/serviceManager.d.ts +36 -0
  82. package/dist/cjs/src/serviceManager.js +106 -0
  83. package/dist/cjs/src/socketManager.d.ts +32 -0
  84. package/dist/cjs/src/socketManager.js +125 -0
  85. package/dist/cjs/src/storageService.d.ts +21 -0
  86. package/dist/cjs/src/storageService.js +81 -0
  87. package/dist/cjs/src/taskManager.d.ts +70 -0
  88. package/dist/cjs/src/taskManager.js +181 -0
  89. package/dist/cjs/src/tasks/routes.d.ts +7 -0
  90. package/dist/cjs/src/tasks/routes.js +39 -0
  91. package/dist/cjs/src/traffic/routes.d.ts +7 -0
  92. package/dist/cjs/src/traffic/routes.js +22 -0
  93. package/dist/cjs/src/types.d.ts +99 -0
  94. package/dist/cjs/src/types.js +39 -0
  95. package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +28 -0
  96. package/dist/cjs/src/utils/BlockInstanceRunner.js +432 -0
  97. package/dist/cjs/src/utils/DefaultProviderInstaller.d.ts +15 -0
  98. package/dist/cjs/src/utils/DefaultProviderInstaller.js +136 -0
  99. package/dist/cjs/src/utils/InternalConfigProvider.d.ts +38 -0
  100. package/dist/cjs/src/utils/InternalConfigProvider.js +146 -0
  101. package/dist/cjs/src/utils/LogData.d.ts +23 -0
  102. package/dist/cjs/src/utils/LogData.js +46 -0
  103. package/dist/cjs/src/utils/commandLineUtils.d.ts +8 -0
  104. package/dist/cjs/src/utils/commandLineUtils.js +39 -0
  105. package/dist/cjs/src/utils/pathTemplateParser.d.ts +30 -0
  106. package/dist/cjs/src/utils/pathTemplateParser.js +135 -0
  107. package/dist/cjs/src/utils/utils.d.ts +40 -0
  108. package/dist/cjs/src/utils/utils.js +148 -0
  109. package/dist/cjs/start.d.ts +5 -0
  110. package/dist/cjs/start.js +17 -0
  111. package/dist/cjs/test/proxy/types/rest.test.d.ts +5 -0
  112. package/dist/cjs/test/proxy/types/rest.test.js +48 -0
  113. package/dist/cjs/test/utils/pathTemplateParser.test.d.ts +5 -0
  114. package/dist/cjs/test/utils/pathTemplateParser.test.js +27 -0
  115. package/dist/esm/index.d.ts +34 -0
  116. package/dist/esm/index.js +263 -0
  117. package/dist/esm/package.json +1 -0
  118. package/dist/esm/src/RepositoryWatcher.d.ts +30 -0
  119. package/dist/esm/src/RepositoryWatcher.js +332 -0
  120. package/dist/esm/src/ai/aiClient.d.ts +20 -0
  121. package/dist/esm/src/ai/aiClient.js +74 -0
  122. package/dist/esm/src/ai/routes.d.ts +7 -0
  123. package/dist/esm/src/ai/routes.js +37 -0
  124. package/dist/esm/src/ai/transform.d.ts +11 -0
  125. package/dist/esm/src/ai/transform.js +239 -0
  126. package/dist/esm/src/ai/types.d.ts +40 -0
  127. package/dist/esm/src/ai/types.js +2 -0
  128. package/dist/esm/src/api.d.ts +7 -0
  129. package/dist/esm/src/api.js +29 -0
  130. package/dist/esm/src/assetManager.d.ts +41 -0
  131. package/dist/esm/src/assetManager.js +274 -0
  132. package/dist/esm/src/assets/routes.d.ts +7 -0
  133. package/dist/esm/src/assets/routes.js +165 -0
  134. package/dist/esm/src/attachments/routes.d.ts +7 -0
  135. package/dist/esm/src/attachments/routes.js +72 -0
  136. package/dist/esm/src/authManager.d.ts +16 -0
  137. package/dist/esm/src/authManager.js +64 -0
  138. package/dist/esm/src/cacheManager.d.ts +20 -0
  139. package/dist/esm/src/cacheManager.js +51 -0
  140. package/dist/esm/src/clusterService.d.ts +44 -0
  141. package/dist/esm/src/clusterService.js +120 -0
  142. package/dist/esm/src/codeGeneratorManager.d.ts +14 -0
  143. package/dist/esm/src/codeGeneratorManager.js +93 -0
  144. package/dist/esm/src/config/routes.d.ts +7 -0
  145. package/dist/esm/src/config/routes.js +160 -0
  146. package/dist/esm/src/configManager.d.ts +42 -0
  147. package/dist/esm/src/configManager.js +136 -0
  148. package/dist/esm/src/containerManager.d.ts +148 -0
  149. package/dist/esm/src/containerManager.js +958 -0
  150. package/dist/esm/src/definitionsManager.d.ts +20 -0
  151. package/dist/esm/src/definitionsManager.js +171 -0
  152. package/dist/esm/src/filesystem/routes.d.ts +7 -0
  153. package/dist/esm/src/filesystem/routes.js +105 -0
  154. package/dist/esm/src/filesystemManager.d.ts +27 -0
  155. package/dist/esm/src/filesystemManager.js +118 -0
  156. package/dist/esm/src/identities/routes.d.ts +7 -0
  157. package/dist/esm/src/identities/routes.js +37 -0
  158. package/dist/esm/src/instanceManager.d.ts +69 -0
  159. package/dist/esm/src/instanceManager.js +910 -0
  160. package/dist/esm/src/instances/routes.d.ts +7 -0
  161. package/dist/esm/src/instances/routes.js +179 -0
  162. package/dist/esm/src/middleware/cors.d.ts +6 -0
  163. package/dist/esm/src/middleware/cors.js +14 -0
  164. package/dist/esm/src/middleware/kapeta.d.ts +15 -0
  165. package/dist/esm/src/middleware/kapeta.js +28 -0
  166. package/dist/esm/src/middleware/stringBody.d.ts +9 -0
  167. package/dist/esm/src/middleware/stringBody.js +18 -0
  168. package/dist/esm/src/networkManager.d.ts +37 -0
  169. package/dist/esm/src/networkManager.js +119 -0
  170. package/dist/esm/src/operatorManager.d.ts +41 -0
  171. package/dist/esm/src/operatorManager.js +211 -0
  172. package/dist/esm/src/progressListener.d.ts +31 -0
  173. package/dist/esm/src/progressListener.js +133 -0
  174. package/dist/esm/src/providerManager.d.ts +11 -0
  175. package/dist/esm/src/providerManager.js +84 -0
  176. package/dist/esm/src/providers/routes.d.ts +7 -0
  177. package/dist/esm/src/providers/routes.js +46 -0
  178. package/dist/esm/src/proxy/routes.d.ts +7 -0
  179. package/dist/esm/src/proxy/routes.js +115 -0
  180. package/dist/esm/src/proxy/types/rest.d.ts +10 -0
  181. package/dist/esm/src/proxy/types/rest.js +123 -0
  182. package/dist/esm/src/proxy/types/web.d.ts +8 -0
  183. package/dist/esm/src/proxy/types/web.js +61 -0
  184. package/dist/esm/src/repositoryManager.d.ts +35 -0
  185. package/dist/esm/src/repositoryManager.js +247 -0
  186. package/dist/esm/src/serviceManager.d.ts +36 -0
  187. package/dist/esm/src/serviceManager.js +106 -0
  188. package/dist/esm/src/socketManager.d.ts +32 -0
  189. package/dist/esm/src/socketManager.js +125 -0
  190. package/dist/esm/src/storageService.d.ts +21 -0
  191. package/dist/esm/src/storageService.js +81 -0
  192. package/dist/esm/src/taskManager.d.ts +70 -0
  193. package/dist/esm/src/taskManager.js +181 -0
  194. package/dist/esm/src/tasks/routes.d.ts +7 -0
  195. package/dist/esm/src/tasks/routes.js +39 -0
  196. package/dist/esm/src/traffic/routes.d.ts +7 -0
  197. package/dist/esm/src/traffic/routes.js +22 -0
  198. package/dist/esm/src/types.d.ts +99 -0
  199. package/dist/esm/src/types.js +39 -0
  200. package/dist/esm/src/utils/BlockInstanceRunner.d.ts +28 -0
  201. package/dist/esm/src/utils/BlockInstanceRunner.js +432 -0
  202. package/dist/esm/src/utils/DefaultProviderInstaller.d.ts +15 -0
  203. package/dist/esm/src/utils/DefaultProviderInstaller.js +136 -0
  204. package/dist/esm/src/utils/InternalConfigProvider.d.ts +38 -0
  205. package/dist/esm/src/utils/InternalConfigProvider.js +146 -0
  206. package/dist/esm/src/utils/LogData.d.ts +23 -0
  207. package/dist/esm/src/utils/LogData.js +46 -0
  208. package/dist/esm/src/utils/commandLineUtils.d.ts +8 -0
  209. package/dist/esm/src/utils/commandLineUtils.js +39 -0
  210. package/dist/esm/src/utils/pathTemplateParser.d.ts +30 -0
  211. package/dist/esm/src/utils/pathTemplateParser.js +135 -0
  212. package/dist/esm/src/utils/utils.d.ts +40 -0
  213. package/dist/esm/src/utils/utils.js +148 -0
  214. package/dist/esm/start.d.ts +5 -0
  215. package/dist/esm/start.js +17 -0
  216. package/dist/esm/test/proxy/types/rest.test.d.ts +5 -0
  217. package/dist/esm/test/proxy/types/rest.test.js +48 -0
  218. package/dist/esm/test/utils/pathTemplateParser.test.d.ts +5 -0
  219. package/dist/esm/test/utils/pathTemplateParser.test.js +27 -0
  220. package/index.ts +280 -0
  221. package/jest.config.js +8 -0
  222. package/package.json +134 -0
  223. package/src/RepositoryWatcher.ts +363 -0
  224. package/src/ai/aiClient.ts +93 -0
  225. package/src/ai/routes.ts +39 -0
  226. package/src/ai/transform.ts +275 -0
  227. package/src/ai/types.ts +45 -0
  228. package/src/api.ts +32 -0
  229. package/src/assetManager.ts +355 -0
  230. package/src/assets/routes.ts +183 -0
  231. package/src/attachments/routes.ts +79 -0
  232. package/src/authManager.ts +67 -0
  233. package/src/cacheManager.ts +59 -0
  234. package/src/clusterService.ts +142 -0
  235. package/src/codeGeneratorManager.ts +109 -0
  236. package/src/config/routes.ts +201 -0
  237. package/src/configManager.ts +180 -0
  238. package/src/containerManager.ts +1178 -0
  239. package/src/definitionsManager.ts +212 -0
  240. package/src/filesystem/routes.ts +123 -0
  241. package/src/filesystemManager.ts +133 -0
  242. package/src/identities/routes.ts +38 -0
  243. package/src/instanceManager.ts +1160 -0
  244. package/src/instances/routes.ts +203 -0
  245. package/src/middleware/cors.ts +14 -0
  246. package/src/middleware/kapeta.ts +41 -0
  247. package/src/middleware/stringBody.ts +21 -0
  248. package/src/networkManager.ts +148 -0
  249. package/src/operatorManager.ts +294 -0
  250. package/src/progressListener.ts +151 -0
  251. package/src/providerManager.ts +97 -0
  252. package/src/providers/routes.ts +51 -0
  253. package/src/proxy/routes.ts +153 -0
  254. package/src/proxy/types/rest.ts +172 -0
  255. package/src/proxy/types/web.ts +70 -0
  256. package/src/repositoryManager.ts +291 -0
  257. package/src/serviceManager.ts +133 -0
  258. package/src/socketManager.ts +138 -0
  259. package/src/storageService.ts +97 -0
  260. package/src/taskManager.ts +247 -0
  261. package/src/tasks/routes.ts +43 -0
  262. package/src/traffic/routes.ts +23 -0
  263. package/src/types.ts +112 -0
  264. package/src/utils/BlockInstanceRunner.ts +577 -0
  265. package/src/utils/DefaultProviderInstaller.ts +150 -0
  266. package/src/utils/InternalConfigProvider.ts +214 -0
  267. package/src/utils/LogData.ts +50 -0
  268. package/src/utils/commandLineUtils.ts +45 -0
  269. package/src/utils/pathTemplateParser.ts +157 -0
  270. package/src/utils/utils.ts +155 -0
  271. package/start.ts +14 -0
  272. package/test/proxy/types/rest.test.ts +54 -0
  273. package/test/utils/pathTemplateParser.test.ts +29 -0
  274. package/tsconfig.json +15 -0
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+ import { BlockDefinition, Plan } from '@kapeta/schemas';
6
+ import { Application } from './types';
7
+ import { definitionsManager } from '../definitionsManager';
8
+ import { normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
9
+ import uuid from 'node-uuid';
10
+
11
+ export type PlanContext = {
12
+ plan: Plan;
13
+ blocks: BlockDefinition[];
14
+ };
15
+
16
+ async function getFreeName(name: string) {
17
+ let currentName = name;
18
+ let iteration = 1;
19
+ do {
20
+ const found = await definitionsManager.getLatestDefinition(currentName);
21
+ if (!found) {
22
+ return currentName;
23
+ }
24
+ currentName = name + '_' + iteration++;
25
+ } while (true);
26
+ }
27
+
28
+ export const transformToPlan = async (handle: string, application: Application): Promise<PlanContext> => {
29
+ const blockTypeService = await definitionsManager.getLatestDefinition('kapeta/block-type-service');
30
+ const blockTypeFrontend = await definitionsManager.getLatestDefinition('kapeta/block-type-frontend');
31
+ const mongoDbResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-mongodb');
32
+ const postgresResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-postgresql');
33
+ const webPageResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-web-page');
34
+ const webFragmentResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-web-fragment');
35
+ const restApiResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-rest-api');
36
+ const restClientResource = await definitionsManager.getLatestDefinition('kapeta/resource-type-rest-client');
37
+ const javaLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-java-spring-boot');
38
+ const nodejsLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-nodejs');
39
+ const reactLanguage = await definitionsManager.getLatestDefinition('kapeta/language-target-react-ts');
40
+
41
+ if (
42
+ !blockTypeService ||
43
+ !blockTypeFrontend ||
44
+ !mongoDbResource ||
45
+ !postgresResource ||
46
+ !javaLanguage ||
47
+ !nodejsLanguage ||
48
+ !reactLanguage ||
49
+ !webPageResource ||
50
+ !restApiResource ||
51
+ !restClientResource ||
52
+ !webFragmentResource
53
+ ) {
54
+ throw new Error('Missing definitions');
55
+ }
56
+
57
+ const plan: Plan = {
58
+ kind: 'core/plan',
59
+ metadata: {
60
+ name: await getFreeName(`${handle}/${application.name}`),
61
+ title: application.title,
62
+ description: application.description,
63
+ visibility: 'private',
64
+ },
65
+ spec: {
66
+ blocks: [],
67
+ connections: [],
68
+ },
69
+ };
70
+
71
+ const blocks: BlockDefinition[] = [];
72
+
73
+ const addToPlan = (ref: string, name: string) => {
74
+ const top = 100 + Math.floor(plan.spec.blocks.length / 3) * 300;
75
+ const left = 200 + (plan.spec.blocks.length % 3) * 450;
76
+
77
+ plan.spec.blocks.push({
78
+ block: {
79
+ ref,
80
+ },
81
+ name,
82
+ id: uuid.v4(),
83
+ dimensions: {
84
+ top,
85
+ left,
86
+ width: -1,
87
+ height: -1,
88
+ },
89
+ });
90
+ };
91
+
92
+ const nameMapper = new Map<string, string>();
93
+
94
+ for (const backend of application.backends) {
95
+ const blockName = `${handle}/${backend.name}`;
96
+ const blockRealName = await getFreeName(blockName);
97
+ nameMapper.set(blockName, blockRealName);
98
+
99
+ const language = backend.targetLanguage === 'java' ? javaLanguage : nodejsLanguage;
100
+ const databaseInfo = backend.databases?.[0];
101
+ const database = databaseInfo?.type === 'mongodb' ? mongoDbResource : postgresResource;
102
+
103
+ const blockRef = normalizeKapetaUri(blockRealName + ':local');
104
+ let targetOptions = {};
105
+ if (backend.targetLanguage === 'java') {
106
+ targetOptions = {
107
+ basePackage: `${handle}.${application.name}`.toLowerCase().replace(/-/g, '_'),
108
+ groupId: `${handle}.${application.name}`.toLowerCase().replace(/-/g, '_'),
109
+ artifactId: backend.name.toLowerCase().replace(/-/g, '_'),
110
+ };
111
+ }
112
+ blocks.push({
113
+ kind: normalizeKapetaUri(`${blockTypeService.definition.metadata.name}:${blockTypeService.version}`),
114
+ metadata: {
115
+ name: blockRealName,
116
+ title: backend.title,
117
+ description: backend.description,
118
+ visibility: 'private',
119
+ },
120
+ spec: {
121
+ target: {
122
+ kind: normalizeKapetaUri(`${language.definition.metadata.name}:${language.version}`),
123
+ options: targetOptions,
124
+ },
125
+ consumers: [
126
+ {
127
+ kind: normalizeKapetaUri(`${database.definition.metadata.name}:${database.version}`),
128
+ metadata: {
129
+ name: (databaseInfo?.name ?? 'main').replace(/-/g, ''),
130
+ },
131
+ spec: {
132
+ port: {
133
+ type: database.definition.spec.ports[0].type,
134
+ },
135
+ },
136
+ },
137
+ ],
138
+ providers: [
139
+ {
140
+ kind: normalizeKapetaUri(
141
+ `${restApiResource.definition.metadata.name}:${restApiResource.version}`
142
+ ),
143
+ metadata: {
144
+ name: 'main',
145
+ },
146
+ spec: {
147
+ port: {
148
+ type: restApiResource.definition.spec.ports[0].type,
149
+ },
150
+ },
151
+ },
152
+ ],
153
+ },
154
+ });
155
+
156
+ addToPlan(blockRef, backend.name);
157
+ }
158
+
159
+ for (const frontend of application.frontends) {
160
+ const blockName = `${handle}/${frontend.name}`;
161
+ const blockRealName = await getFreeName(blockName);
162
+ nameMapper.set(blockName, blockRealName);
163
+
164
+ const language = reactLanguage;
165
+
166
+ const blockRef = normalizeKapetaUri(blockRealName + ':local');
167
+ blocks.push({
168
+ kind: normalizeKapetaUri(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
169
+ metadata: {
170
+ name: blockRealName,
171
+ title: frontend.title,
172
+ description: frontend.description,
173
+ visibility: 'private',
174
+ },
175
+ spec: {
176
+ target: {
177
+ kind: normalizeKapetaUri(`${language.definition.metadata.name}:${language.version}`),
178
+ options: {},
179
+ },
180
+ consumers: [],
181
+ providers: [
182
+ {
183
+ kind: normalizeKapetaUri(
184
+ `${webPageResource.definition.metadata.name}:${webPageResource.version}`
185
+ ),
186
+ metadata: {
187
+ name: 'main',
188
+ },
189
+ spec: {
190
+ port: {
191
+ type: webPageResource.definition.spec.ports[0].type,
192
+ },
193
+ },
194
+ },
195
+ ],
196
+ },
197
+ });
198
+
199
+ addToPlan(blockRef, frontend.name);
200
+ }
201
+
202
+ application.connections?.forEach((connection) => {
203
+ const fullProviderName = nameMapper.get(`${handle}/${connection.provider.name}`) as string;
204
+ const fullConsumerName = nameMapper.get(`${handle}/${connection.consumer.name}`) as string;
205
+ const consumerResourceName = connection.provider.name;
206
+ const providerRef = normalizeKapetaUri(`${fullProviderName}:local`);
207
+ const consumerRef = normalizeKapetaUri(`${fullConsumerName}:local`);
208
+
209
+ const instanceProvider = plan.spec.blocks.find((b) => b.block.ref === providerRef)!;
210
+ const instanceConsumer = plan.spec.blocks.find((b) => b.block.ref === consumerRef)!;
211
+ const consumerBlock = blocks.find((block) => block.metadata.name === fullConsumerName);
212
+ const providerBlock = blocks.find((block) => block.metadata.name === fullProviderName);
213
+ if (!consumerBlock) {
214
+ throw new Error('Missing consumer block: ' + fullConsumerName);
215
+ }
216
+
217
+ if (!providerBlock) {
218
+ throw new Error('Missing provider block: ' + fullProviderName);
219
+ }
220
+
221
+ const portType = parseKapetaUri(providerBlock.kind).fullName === 'kapeta/block-type-service' ? 'rest' : 'web';
222
+
223
+ if (portType === 'rest') {
224
+ consumerBlock.spec.consumers!.push({
225
+ kind: normalizeKapetaUri(
226
+ `${restClientResource.definition.metadata.name}:${restClientResource.version}`
227
+ ),
228
+ metadata: {
229
+ name: consumerResourceName,
230
+ },
231
+ spec: {
232
+ port: {
233
+ type: 'rest',
234
+ },
235
+ },
236
+ });
237
+ } else {
238
+ consumerBlock.spec.consumers!.push({
239
+ kind: normalizeKapetaUri(
240
+ `${webFragmentResource.definition.metadata.name}:${webFragmentResource.version}`
241
+ ),
242
+ metadata: {
243
+ name: consumerResourceName,
244
+ },
245
+ spec: {
246
+ port: {
247
+ type: 'web',
248
+ },
249
+ },
250
+ });
251
+ }
252
+
253
+ plan.spec.connections.push({
254
+ provider: {
255
+ blockId: instanceProvider.id,
256
+ resourceName: 'main',
257
+ port: {
258
+ type: portType,
259
+ },
260
+ },
261
+ consumer: {
262
+ blockId: instanceConsumer.id,
263
+ resourceName: consumerResourceName,
264
+ port: {
265
+ type: portType,
266
+ },
267
+ },
268
+ });
269
+ });
270
+
271
+ return {
272
+ plan,
273
+ blocks,
274
+ };
275
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+ export interface Database {
6
+ name: string;
7
+ type: 'mongodb' | 'postgres';
8
+ }
9
+
10
+ export interface BackendService {
11
+ name: string;
12
+ title: string;
13
+ description: string;
14
+ targetLanguage: 'java' | 'node';
15
+ databases: Database[] | null;
16
+ }
17
+
18
+ export interface FrontendService {
19
+ name: string;
20
+ title: string;
21
+ description: string;
22
+ targetLanguage: 'react';
23
+ }
24
+
25
+ export interface Endpoint {
26
+ type: 'backend' | 'frontend';
27
+ name: string;
28
+ }
29
+
30
+ export interface Connection {
31
+ provider: Endpoint;
32
+ consumer: Endpoint;
33
+ }
34
+
35
+ export interface Application {
36
+ kind: 'core/plan';
37
+ name: string;
38
+ title: string;
39
+ description: string;
40
+ backends: BackendService[];
41
+ frontends: FrontendService[];
42
+ connections: Connection[];
43
+ explanation: string;
44
+ response: string;
45
+ }
package/src/api.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+
6
+ import Router from 'express-promise-router';
7
+ import { corsHandler } from './middleware/cors';
8
+ import { KapetaAPI } from '@kapeta/nodejs-api-client';
9
+ import { Config } from '@kapeta/nodejs-registry-utils';
10
+ const { createAPIRoute } = require('@kapeta/web-microfrontend/server');
11
+ const packageJson = require('../package.json');
12
+
13
+ const router = Router();
14
+
15
+ router.use('/', corsHandler);
16
+
17
+ router.use(
18
+ '/registry',
19
+ createAPIRoute(Config.data?.registry?.url ?? 'https://registry.kapeta.com', {
20
+ nonce: false,
21
+ userAgent: `KapetaDesktopCluster/${packageJson.version}`,
22
+ tokenFetcher: () => {
23
+ const api = new KapetaAPI();
24
+ if (api.hasToken()) {
25
+ return api.getAccessToken();
26
+ }
27
+ return null;
28
+ },
29
+ })
30
+ );
31
+
32
+ export default router;
@@ -0,0 +1,355 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+
6
+ import Path from 'node:path';
7
+ import FS from 'fs-extra';
8
+ import YAML from 'yaml';
9
+ import { Definition, DefinitionInfo } from '@kapeta/local-cluster-config';
10
+ import { codeGeneratorManager } from './codeGeneratorManager';
11
+ import { ProgressListener, TaskProgressListener } from './progressListener';
12
+ import { normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
13
+ import { repositoryManager } from './repositoryManager';
14
+ import { BlockDefinition, BlockInstance, Plan } from '@kapeta/schemas';
15
+ import { Actions } from '@kapeta/nodejs-registry-utils';
16
+ import { definitionsManager } from './definitionsManager';
17
+ import { Task, taskManager } from './taskManager';
18
+ import { KIND_BLOCK_TYPE_EXECUTABLE, KIND_BLOCK_TYPE_OPERATOR, KIND_BLOCK_TYPE, SourceOfChange } from './types';
19
+ import { cacheManager } from './cacheManager';
20
+ import uuid from 'node-uuid';
21
+ import os from 'node:os';
22
+
23
+ const CACHE_TTL = 60 * 60 * 1000; // 1 hour
24
+ const UPGRADE_CHECK_INTERVAL = 10 * 60 * 1000; // 10 minutes
25
+
26
+ const toKey = (ref: string) => `assetManager:asset:${ref}`;
27
+
28
+ export interface EnrichedAsset {
29
+ ref: string;
30
+ editable: boolean;
31
+ exists: boolean;
32
+ version: string;
33
+ kind: string;
34
+ data: Definition;
35
+ path: string;
36
+ ymlPath: string;
37
+ }
38
+
39
+ function filterExists(asset: DefinitionInfo): boolean {
40
+ return FS.existsSync(asset.path) && FS.existsSync(asset.ymlPath);
41
+ }
42
+
43
+ function enrichAsset(asset: DefinitionInfo): EnrichedAsset {
44
+ return {
45
+ ref: `kapeta://${asset.definition.metadata.name}:${asset.version}`,
46
+ editable: asset.version === 'local', //Only local versions are editable
47
+ exists: true,
48
+ version: asset.version,
49
+ kind: asset.definition.kind,
50
+ data: asset.definition,
51
+ path: FS.realpathSync(asset.path),
52
+ ymlPath: FS.realpathSync(asset.ymlPath),
53
+ };
54
+ }
55
+
56
+ function compareRefs(a: string, b: string) {
57
+ const [aProtocol, aId] = parseRef(a);
58
+ const [bProtocol, bId] = parseRef(b);
59
+
60
+ return aProtocol === bProtocol && aId === bId;
61
+ }
62
+
63
+ function parseRef(ref: string) {
64
+ let out = ref.split(/:\/\//, 2);
65
+
66
+ if (out.length === 1) {
67
+ return ['kapeta', ref.toLowerCase()];
68
+ }
69
+ return [out[0].toLowerCase(), out[1].toLowerCase()];
70
+ }
71
+
72
+ class AssetManager {
73
+ public startUpgradeInterval() {
74
+ console.debug('Checking for upgrades...');
75
+ this.upgradeAllProviders()
76
+ .then((task) => {
77
+ return task && task.wait();
78
+ })
79
+ .catch((e) => {
80
+ console.error('Failed to upgrade providers', e);
81
+ })
82
+ .finally(() => {
83
+ setTimeout(() => {
84
+ this.startUpgradeInterval();
85
+ }, UPGRADE_CHECK_INTERVAL);
86
+ });
87
+ }
88
+
89
+ /**
90
+ *
91
+ * @param {string[]} [assetKinds]
92
+ * @returns {{path: *, ref: string, data: *, editable: boolean, kind: *, exists: boolean}[]}
93
+ */
94
+ async getAssets(assetKinds?: string[]): Promise<EnrichedAsset[]> {
95
+ if (!assetKinds) {
96
+ const blockTypeProviders = await definitionsManager.getDefinitions([
97
+ KIND_BLOCK_TYPE,
98
+ KIND_BLOCK_TYPE_OPERATOR,
99
+ KIND_BLOCK_TYPE_EXECUTABLE,
100
+ ]);
101
+ assetKinds = blockTypeProviders.map((p) => {
102
+ return `${p.definition.metadata.name}:${p.version}`;
103
+ });
104
+ assetKinds.push('core/plan');
105
+ }
106
+
107
+ const assets = await definitionsManager.getDefinitions(assetKinds);
108
+
109
+ return assets.filter(filterExists).map(enrichAsset);
110
+ }
111
+
112
+ async getPlans(): Promise<EnrichedAsset[]> {
113
+ return this.getAssets(['core/plan']);
114
+ }
115
+
116
+ async getPlan(ref: string, noCache: boolean = false): Promise<Plan> {
117
+ const asset = await this.getAsset(ref, noCache);
118
+
119
+ if (!asset) {
120
+ throw new Error('Plan was not found: ' + ref);
121
+ }
122
+
123
+ if ('core/plan' !== asset?.kind) {
124
+ throw new Error('Asset was not a plan: ' + ref);
125
+ }
126
+
127
+ return asset.data as Plan;
128
+ }
129
+
130
+ async getBlockInstance(systemId: string, instanceId: string): Promise<BlockInstance> {
131
+ const plan = await this.getPlan(systemId, true);
132
+
133
+ const instance = plan.spec.blocks?.find((instance) => instance.id === instanceId);
134
+ if (!instance) {
135
+ throw new Error(`Instance not found: ${instanceId} in plan ${systemId}`);
136
+ }
137
+
138
+ return instance;
139
+ }
140
+
141
+ async getAsset(
142
+ ref: string,
143
+ noCache: boolean = false,
144
+ autoFetch: boolean = true
145
+ ): Promise<EnrichedAsset | undefined> {
146
+ ref = normalizeKapetaUri(ref);
147
+ const cacheKey = toKey(ref);
148
+ if (!noCache && cacheManager.has(cacheKey)) {
149
+ return cacheManager.get(cacheKey);
150
+ }
151
+ const uri = parseKapetaUri(ref);
152
+ if (autoFetch) {
153
+ await repositoryManager.ensureAsset(uri.handle, uri.name, uri.version, true);
154
+ }
155
+
156
+ const definitionInfo = await definitionsManager.getDefinition(ref);
157
+ if (autoFetch && !definitionInfo) {
158
+ throw new Error('Asset not found: ' + ref);
159
+ }
160
+
161
+ if (definitionInfo) {
162
+ const asset = enrichAsset(definitionInfo);
163
+ cacheManager.set(cacheKey, asset, CACHE_TTL);
164
+ return asset;
165
+ }
166
+
167
+ return undefined;
168
+ }
169
+
170
+ async createAsset(
171
+ path: string,
172
+ yaml: BlockDefinition,
173
+ sourceOfChange: SourceOfChange = 'filesystem'
174
+ ): Promise<EnrichedAsset[]> {
175
+ if (await FS.pathExists(path)) {
176
+ throw new Error('File already exists: ' + path);
177
+ }
178
+
179
+ const dirName = Path.dirname(path);
180
+ if (!(await FS.pathExists(dirName))) {
181
+ await FS.mkdirp(dirName);
182
+ }
183
+ await repositoryManager.setSourceOfChangeFor(path, sourceOfChange);
184
+ await FS.writeFile(path, YAML.stringify(yaml));
185
+ const asset = await this.importFile(path);
186
+ asset.forEach((a) => {
187
+ const ref = normalizeKapetaUri(a.ref);
188
+ const key = toKey(ref);
189
+ cacheManager.set(key, a, CACHE_TTL);
190
+ });
191
+
192
+ definitionsManager.clearCache();
193
+ console.log(`Created asset at: ${path}`);
194
+
195
+ const ref = `kapeta://${yaml.metadata.name}:local`;
196
+
197
+ await this.maybeGenerateCode(ref, path, yaml);
198
+
199
+ return asset;
200
+ }
201
+
202
+ async updateAsset(ref: string, yaml: Definition, sourceOfChange: SourceOfChange = 'filesystem') {
203
+ ref = normalizeKapetaUri(ref);
204
+ const asset = await this.getAsset(ref, true, false);
205
+ if (!asset) {
206
+ throw new Error('Attempted to update unknown asset: ' + ref);
207
+ }
208
+
209
+ if (!asset.editable) {
210
+ throw new Error('Attempted to update read-only asset: ' + ref);
211
+ }
212
+
213
+ if (!asset.ymlPath) {
214
+ throw new Error('Attempted to update corrupted asset: ' + ref);
215
+ }
216
+
217
+ await repositoryManager.setSourceOfChangeFor(asset.ymlPath, sourceOfChange);
218
+ await FS.writeFile(asset.ymlPath, YAML.stringify(yaml));
219
+ console.log(`Updated asset at: ${asset.ymlPath}`);
220
+
221
+ cacheManager.remove(toKey(ref));
222
+ definitionsManager.clearCache();
223
+
224
+ await this.maybeGenerateCode(asset.ref, asset.ymlPath, yaml);
225
+ }
226
+
227
+ async importFile(filePath: string) {
228
+ if (filePath.startsWith('file://')) {
229
+ filePath = filePath.substring('file://'.length);
230
+ }
231
+
232
+ if (!(await FS.pathExists(filePath))) {
233
+ throw new Error('File not found: ' + filePath);
234
+ }
235
+ const content = await FS.readFile(filePath);
236
+
237
+ const assetInfos = YAML.parseAllDocuments(content.toString()).map((doc) => doc.toJSON());
238
+
239
+ await Actions.link(new ProgressListener(), Path.dirname(filePath));
240
+
241
+ const version = 'local';
242
+ const refs = assetInfos.map((assetInfo) =>
243
+ normalizeKapetaUri(`kapeta://${assetInfo.metadata.name}:${version}`)
244
+ );
245
+ refs.forEach((ref) => {
246
+ const key = toKey(ref);
247
+ cacheManager.remove(key);
248
+ });
249
+
250
+ definitionsManager.clearCache();
251
+
252
+ // Get all possible asset kinds, to make sure we return the result if possible
253
+ const assets = await this.getAssets([]);
254
+
255
+ return assets.filter((a) => refs.some((ref) => compareRefs(ref, a.ref)));
256
+ }
257
+
258
+ async unregisterAsset(ref: string) {
259
+ const asset = await this.getAsset(ref, true, false);
260
+ if (!asset) {
261
+ throw new Error('Asset does not exists: ' + ref);
262
+ }
263
+
264
+ const key = toKey(ref);
265
+ cacheManager.remove(key);
266
+ definitionsManager.clearCache();
267
+
268
+ await Actions.uninstall(new ProgressListener(), [asset.ref]);
269
+ }
270
+
271
+ async installAsset(ref: string, wait: boolean = false) {
272
+ const asset = await this.getAsset(ref, true, false);
273
+ if (asset) {
274
+ throw new Error('Asset already installed: ' + ref);
275
+ }
276
+ const uri = parseKapetaUri(ref);
277
+ console.log('Installing %s (sync: %s)', ref, wait);
278
+ const key = toKey(ref);
279
+ cacheManager.remove(key);
280
+ definitionsManager.clearCache();
281
+
282
+ return await repositoryManager.ensureAsset(uri.handle, uri.name, uri.version, wait);
283
+ }
284
+
285
+ private async cleanupUnusedProviders(): Promise<void> {
286
+ const unusedProviders = await repositoryManager.getUnusedProviders();
287
+ if (unusedProviders.length < 1) {
288
+ return;
289
+ }
290
+
291
+ console.log('Cleaning up unused providers: ', unusedProviders);
292
+ await Promise.all(
293
+ unusedProviders.map((ref) => {
294
+ return this.unregisterAsset(ref);
295
+ })
296
+ );
297
+ }
298
+
299
+ private async upgradeAllProviders() {
300
+ const providers = await definitionsManager.getProviderDefinitions();
301
+ const names = providers.map((p) => p.definition.metadata.name);
302
+
303
+ const refs = await repositoryManager.getUpdatableAssets(names);
304
+
305
+ if (refs.length < 1) {
306
+ await this.cleanupUnusedProviders();
307
+ return;
308
+ }
309
+
310
+ console.log('Installing updates', refs);
311
+ const updateAll = async (task: Task) => {
312
+ const progressListener = new TaskProgressListener(task);
313
+ try {
314
+ //We change to a temp dir to avoid issues with the current working directory
315
+ process.chdir(os.tmpdir());
316
+ await Actions.install(progressListener, refs, {});
317
+ await this.cleanupUnusedProviders();
318
+ } catch (e) {
319
+ console.error(`Failed to update assets: ${refs.join(',')}`, e);
320
+ throw e;
321
+ }
322
+ cacheManager.flush();
323
+ definitionsManager.clearCache();
324
+ };
325
+
326
+ return taskManager.add(`asset:update`, updateAll, {
327
+ name: `Installing ${refs.length} updates`,
328
+ group: 'asset:update:check',
329
+ });
330
+ }
331
+
332
+ private async maybeGenerateCode(ref: string, ymlPath: string, block: Definition) {
333
+ ref = normalizeKapetaUri(ref);
334
+ if (await codeGeneratorManager.canGenerateCode(block)) {
335
+ const assetTitle = block.metadata.title ? block.metadata.title : parseKapetaUri(block.metadata.name).name;
336
+ const taskId = `codegen:${uuid.v4()}`;
337
+ const group = `codegen:${ref}`;
338
+ // We group the codegen tasks since we want to run them all but only 1 at a time per block
339
+ taskManager.add(
340
+ taskId,
341
+ async () => {
342
+ await codeGeneratorManager.generate(ymlPath, block);
343
+ },
344
+ {
345
+ name: `Generating code for ${assetTitle}`,
346
+ group, //Group prevents multiple tasks from running at the same time
347
+ }
348
+ );
349
+ return true;
350
+ }
351
+ return false;
352
+ }
353
+ }
354
+
355
+ export const assetManager = new AssetManager();