@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.
- package/CHANGELOG.md +14 -0
- package/definitions.d.ts +1 -1
- package/dist/cjs/src/storm/event-parser.d.ts +2 -1
- package/dist/cjs/src/storm/event-parser.js +43 -12
- package/dist/cjs/src/storm/routes.js +1 -1
- package/dist/cjs/test/storm/blog-events.json +860 -0
- package/dist/cjs/test/storm/codegen.test.js +2 -2
- package/dist/cjs/test/storm/event-parser.test.js +25 -7
- package/dist/cjs/test/storm/predefined-user-events.json +9 -0
- package/dist/esm/src/storm/event-parser.d.ts +2 -1
- package/dist/esm/src/storm/event-parser.js +43 -12
- package/dist/esm/src/storm/routes.js +1 -1
- package/dist/esm/test/storm/blog-events.json +860 -0
- package/dist/esm/test/storm/codegen.test.js +2 -2
- package/dist/esm/test/storm/event-parser.test.js +25 -7
- package/dist/esm/test/storm/predefined-user-events.json +9 -0
- package/package.json +1 -1
- package/src/storm/event-parser.ts +76 -37
- package/src/storm/routes.ts +1 -1
- package/test/storm/blog-events.json +860 -0
- package/test/storm/codegen.test.ts +4 -2
- package/test/storm/event-parser.test.ts +27 -7
- package/test/storm/predefined-user-events.json +9 -0
@@ -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'))
|
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-
|
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/
|
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/
|
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
|
-
|
194
|
-
expect(
|
195
|
-
expect(
|
196
|
-
expect(
|
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
@@ -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
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
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
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
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
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
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
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
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(),
|
package/src/storm/routes.ts
CHANGED
@@ -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;
|