@kapeta/local-cluster-service 0.55.1 → 0.55.3

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.
@@ -26,8 +26,8 @@ describe('codegen', () => {
26
26
  await codegen.process();
27
27
  const stormEvents = await codegenPromise;
28
28
  expect(stormEvents.filter((event) => event.type === 'FILE_DONE').length).toBeGreaterThan(1);
29
- expect(stormEvents.filter((event) => event.type === 'FILE_DONE' && event.payload.filename.endsWith('UserDTO.java')).length)
30
- .toBe(1);
29
+ expect(stormEvents.filter((event) => event.type === 'FILE_DONE' && event.payload.filename.endsWith('UserDTO.java'))
30
+ .length).toBe(1);
31
31
  expect(stormEvents.at(-1).type).toBe('BLOCK_READY');
32
32
  });
33
33
  });
@@ -11,9 +11,10 @@ exports.parserOptions = void 0;
11
11
  const event_parser_1 = require("../../src/storm/event-parser");
12
12
  const simple_blog_events_json_1 = __importDefault(require("./simple-blog-events.json"));
13
13
  const predefined_user_events_json_1 = __importDefault(require("./predefined-user-events.json"));
14
+ const blog_events_json_1 = __importDefault(require("./blog-events.json"));
14
15
  exports.parserOptions = {
15
16
  serviceKind: 'kapeta/block-service:local',
16
- serviceLanguage: 'kapeta/language-target-nodejs-ts:local',
17
+ serviceLanguage: 'kapeta/language-target-java-spring-boot:local',
17
18
  frontendKind: 'kapeta/block-type-frontend:local',
18
19
  frontendLanguage: 'kapeta/language-target-react-ts:local',
19
20
  cliKind: 'kapeta/block-type-cli:local',
@@ -27,7 +28,7 @@ exports.parserOptions = {
27
28
  publisherKind: 'kapeta/resource-type-publisher:local',
28
29
  subscriberKind: 'kapeta/resource-type-subscriber:local',
29
30
  databaseKind: 'kapeta/block-type-database:local',
30
- apiKind: 'kapeta/block-type-api:local',
31
+ apiKind: 'kapeta/resource-type-rest-api:local',
31
32
  clientKind: 'kapeta/block-type-client:local',
32
33
  webPageKind: 'kapeta/block-type-web-page:local',
33
34
  webFragmentKind: 'kapeta/block-type-web-fragment:local',
@@ -176,7 +177,7 @@ describe('event-parser', () => {
176
177
  const blogService = result.blocks.find((block) => block.aiName === 'blog-service');
177
178
  expect(blogService).toBeDefined();
178
179
  expect(blogService?.content).toBeDefined();
179
- const apiProviders = blogService?.content?.spec?.providers?.filter((provider) => provider.kind === 'kapeta/block-type-api:local');
180
+ const apiProviders = blogService?.content?.spec?.providers?.filter((provider) => provider.kind === 'kapeta/resource-type-rest-api:local');
180
181
  expect(apiProviders).toBeDefined();
181
182
  expect(apiProviders.length).toBe(2);
182
183
  expect(apiProviders['0'].spec.source.value).not.toBe('');
@@ -190,9 +191,26 @@ describe('event-parser', () => {
190
191
  }
191
192
  const result = await parser.toResult('kapeta');
192
193
  expect(result.blocks.length).toBe(1);
193
- expect(result.blocks[0].content.metadata.title).toBe('user-service');
194
- expect(result.blocks[0].content.metadata.title).toBe('user-service');
195
- expect(result.blocks[0].content.metadata.name).toBe('kapeta/user-service');
196
- expect(result.blocks[0].archetype).toBeDefined();
194
+ const block = result.blocks[0];
195
+ expect(block.content.metadata.title).toBe('user-service');
196
+ expect(block.content.metadata.title).toBe('user-service');
197
+ expect(block.content.metadata.name).toBe('kapeta/user-service');
198
+ expect(block.archetype).toBeDefined();
199
+ expect(block.content.spec.target?.options).toBeDefined();
200
+ expect(block.content.spec.target?.options.groupId).toBe('ai.kapeta');
201
+ expect(block.content.spec.target?.options.artifactId).toBe('blogplatform');
202
+ expect(block.content.spec.target?.options.basePackage).toBe('ai.kapeta.blogplatform');
203
+ });
204
+ it('ensure post-service has api', async () => {
205
+ const events = blog_events_json_1.default;
206
+ const parser = new event_parser_1.StormEventParser(exports.parserOptions);
207
+ for (const event of events) {
208
+ await parser.processEvent('kapeta', event);
209
+ }
210
+ const result = await parser.toResult('kapeta', true);
211
+ const postService = result.blocks.find((block) => block.aiName === 'post-service');
212
+ expect(postService).toBeDefined();
213
+ expect(postService?.content?.spec?.providers?.length).toBe(1);
214
+ expect(postService?.content?.spec?.providers[0].spec.source.value.startsWith('controller')).toBeTruthy();
197
215
  });
198
216
  });
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "type": "CREATE_PLAN_PROPERTIES",
4
+ "reason": "Define the properties for the plan itself",
5
+ "payload": {
6
+ "description": "A blogging platform with user management, post management, and comment management functionalities.",
7
+ "name": "Blog Platform"
8
+ },
9
+ "created": 1720768973436
10
+ },
2
11
  {
3
12
  "type": "CREATE_BLOCK",
4
13
  "reason": "Handles user registration, authentication, and authorization.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.55.1",
3
+ "version": "0.55.3",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -76,6 +76,7 @@ export interface StormOptions {
76
76
  desktopKind: string;
77
77
  desktopLanguage: string;
78
78
  gatewayKind: string;
79
+ [key: string]: string;
79
80
  }
80
81
 
81
82
  function prettifyKaplang(source: string) {
@@ -281,11 +282,15 @@ export class StormEventParser {
281
282
  this.planDescription = evt.payload.description;
282
283
  break;
283
284
  case 'CREATE_BLOCK':
285
+ const apis = this.blocks[evt.payload.name]?.apis;
286
+ const models = this.blocks[evt.payload.name]?.models;
287
+ const types = this.blocks[evt.payload.name]?.types;
288
+
284
289
  this.blocks[evt.payload.name] = {
285
290
  ...evt.payload,
286
- apis: [],
287
- models: [],
288
- types: [],
291
+ apis: apis ?? [],
292
+ models: models ?? [],
293
+ types: types ?? [],
289
294
  };
290
295
  evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.name).toNormalizedString();
291
296
  evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
@@ -360,7 +365,7 @@ export class StormEventParser {
360
365
  return this.error;
361
366
  }
362
367
 
363
- public async toResult(handle: string): Promise<StormDefinitions> {
368
+ public async toResult(handle: string, warn: boolean = false): Promise<StormDefinitions> {
364
369
  const planRef = StormEventParser.toRef(handle, this.planName || 'undefined');
365
370
  const blockDefinitions = await this.toBlockDefinitions(handle);
366
371
  const refIdMap: { [key: string]: string } = {};
@@ -405,12 +410,14 @@ export class StormEventParser {
405
410
  );
406
411
 
407
412
  if (!apiResource) {
408
- console.warn(
409
- 'API resource not found: %s on %s',
410
- apiConnection.fromResource,
411
- apiProviderRef.toNormalizedString(),
412
- apiConnection
413
- );
413
+ if (warn) {
414
+ console.warn(
415
+ 'API resource not found: %s on %s',
416
+ apiConnection.fromResource,
417
+ apiProviderRef.toNormalizedString(),
418
+ apiConnection
419
+ );
420
+ }
414
421
  return;
415
422
  }
416
423
 
@@ -424,12 +431,14 @@ export class StormEventParser {
424
431
  });
425
432
 
426
433
  if (!clientResource) {
427
- console.warn(
428
- 'Client resource not found: %s on %s',
429
- apiConnection.toResource,
430
- clientConsumerRef.toNormalizedString(),
431
- apiConnection
432
- );
434
+ if (warn) {
435
+ console.warn(
436
+ 'Client resource not found: %s on %s',
437
+ apiConnection.toResource,
438
+ clientConsumerRef.toNormalizedString(),
439
+ apiConnection
440
+ );
441
+ }
433
442
  return;
434
443
  }
435
444
 
@@ -483,7 +492,7 @@ export class StormEventParser {
483
492
  blockId: refIdMap[fromRef.toNormalizedString()],
484
493
  resourceName: connection.fromResource,
485
494
  },
486
- mapping: this.toConnectionMapping(handle, connection, blockDefinitions),
495
+ mapping: this.toConnectionMapping(handle, connection, blockDefinitions, warn),
487
496
  } satisfies Connection;
488
497
  });
489
498
 
@@ -517,7 +526,7 @@ export class StormEventParser {
517
526
  let blockDefinitionInfo: BlockDefinitionInfo;
518
527
 
519
528
  if (blockInfo.archetype) {
520
- blockDefinitionInfo = await this.resolveArchetypeBlockDefinition(blockRef, blockInfo);
529
+ blockDefinitionInfo = await this.resolveArchetypeBlockDefinition(blockRef, blockInfo, handle);
521
530
  } else {
522
531
  blockDefinitionInfo = this.createBlockDefinitionInfo(blockRef, blockInfo, handle);
523
532
  }
@@ -685,18 +694,18 @@ export class StormEventParser {
685
694
  }
686
695
  }
687
696
 
688
- if (!exactMatch) {
689
- // if we couldn't place the given api on the exact resource we just park it on the first
690
- // available rest resource
691
- const firstKey = Object.keys(apiResources)[0];
692
- const firstEntry = apiResources[firstKey];
693
- if (firstEntry) {
694
- firstEntry.spec.source.value += api + '\n\n';
695
- } else {
696
- console.warn('Unable to find resource for API', api);
697
- }
697
+ if (!exactMatch) {
698
+ // if we couldn't place the given api on the exact resource we just park it on the first
699
+ // available rest resource
700
+ const firstKey = Object.keys(apiResources)[0];
701
+ const firstEntry = apiResources[firstKey];
702
+ if (firstEntry) {
703
+ firstEntry.spec.source.value += api + '\n\n';
704
+ } else {
705
+ // this might be ok as we might receive api and types before resources from the ai-service
698
706
  }
699
- });
707
+ }
708
+ });
700
709
 
701
710
  blockInfo.types.forEach((type) => {
702
711
  blockSpec.entities!.source!.value += type + '\n';
@@ -766,7 +775,8 @@ export class StormEventParser {
766
775
  private toConnectionMapping(
767
776
  handle: string,
768
777
  connection: StormConnection,
769
- blockDefinitions: { [key: string]: BlockDefinitionInfo }
778
+ blockDefinitions: { [key: string]: BlockDefinitionInfo },
779
+ warn: boolean
770
780
  ): any {
771
781
  if (connection.fromResourceType !== 'API') {
772
782
  return;
@@ -785,12 +795,14 @@ export class StormEventParser {
785
795
  );
786
796
 
787
797
  if (!apiResource) {
788
- console.warn(
789
- 'API resource not found: %s on %s',
790
- connection.fromResource,
791
- fromRef.toNormalizedString(),
792
- connection
793
- );
798
+ if (warn) {
799
+ console.warn(
800
+ 'API resource not found: %s on %s',
801
+ connection.fromResource,
802
+ fromRef.toNormalizedString(),
803
+ connection
804
+ );
805
+ }
794
806
  return;
795
807
  }
796
808
 
@@ -884,16 +896,43 @@ export class StormEventParser {
884
896
 
885
897
  private async resolveArchetypeBlockDefinition(
886
898
  blockRef: KapetaURI,
887
- blockInfo: StormBlockInfoFilled
899
+ blockInfo: StormBlockInfoFilled,
900
+ handle: string
888
901
  ): Promise<BlockDefinitionInfo> {
889
902
  const predefinedBlock = PREDEFINED_BLOCKS.get(blockInfo.archetype!);
890
903
  if (!predefinedBlock) {
891
904
  throw new Error('Predefined block not found for archetype [' + blockInfo.archetype + ']');
892
905
  }
893
906
 
907
+ const target = this.toBlockTarget(handle, blockInfo.type);
908
+
894
909
  const blockDefinition = await predefinedBlock.getBlockDefinition();
895
910
  _.set(blockDefinition!, ['metadata', 'name'], blockRef.fullName);
896
911
  _.set(blockDefinition!, ['metadata', 'title'], blockRef.name);
912
+ _.set(blockDefinition!, ['spec', 'target', 'options'], target?.options);
913
+
914
+ const options: StormOptions = this.options;
915
+
916
+ function getKind(kind: string): string | undefined {
917
+ for (const prop in options) {
918
+ if (options.hasOwnProperty(prop)) {
919
+ const value = options[prop];
920
+ if (value.startsWith(kind)) {
921
+ return value;
922
+ }
923
+ }
924
+ }
925
+ }
926
+
927
+ blockDefinition!.kind = getKind(parseKapetaUri(blockDefinition!.kind).fullName) ?? blockDefinition!.kind;
928
+ for (const provider of blockDefinition!.spec.providers ?? []) {
929
+ provider.kind = getKind(parseKapetaUri(provider.kind).fullName) ?? provider.kind;
930
+ }
931
+ for (const consumer of blockDefinition!.spec.consumers ?? []) {
932
+ consumer.kind = getKind(parseKapetaUri(consumer.kind).fullName) ?? consumer.kind;
933
+ }
934
+ blockDefinition!.spec.target!.kind =
935
+ getKind(parseKapetaUri(blockDefinition!.spec.target!.kind).fullName) ?? blockDefinition!.spec.target!.kind;
897
936
 
898
937
  return {
899
938
  uri: blockRef.toNormalizedString(),
@@ -103,7 +103,7 @@ router.post('/:handle/all', async (req: KapetaBodyRequest, res: Response) => {
103
103
  return;
104
104
  }
105
105
 
106
- const result = await eventParser.toResult(handle);
106
+ const result = await eventParser.toResult(handle, true);
107
107
 
108
108
  if (metaStream.isAborted()) {
109
109
  return;