@memberjunction/server 2.112.0 → 2.113.1
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/dist/agents/skip-agent.d.ts +4 -4
- package/dist/agents/skip-agent.d.ts.map +1 -1
- package/dist/agents/skip-agent.js +951 -808
- package/dist/agents/skip-agent.js.map +1 -1
- package/dist/agents/skip-sdk.d.ts +1 -1
- package/dist/agents/skip-sdk.d.ts.map +1 -1
- package/dist/agents/skip-sdk.js +43 -53
- package/dist/agents/skip-sdk.js.map +1 -1
- package/dist/apolloServer/index.js +1 -1
- package/dist/auth/AuthProviderFactory.d.ts +1 -1
- package/dist/auth/AuthProviderFactory.d.ts.map +1 -1
- package/dist/auth/AuthProviderFactory.js +3 -1
- package/dist/auth/AuthProviderFactory.js.map +1 -1
- package/dist/auth/BaseAuthProvider.d.ts +1 -1
- package/dist/auth/BaseAuthProvider.d.ts.map +1 -1
- package/dist/auth/BaseAuthProvider.js +2 -3
- package/dist/auth/BaseAuthProvider.js.map +1 -1
- package/dist/auth/IAuthProvider.d.ts +1 -1
- package/dist/auth/IAuthProvider.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.js +1 -1
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +6 -6
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.js +1 -1
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/newUsers.d.ts +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +7 -7
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/auth/providers/Auth0Provider.d.ts +1 -1
- package/dist/auth/providers/Auth0Provider.d.ts.map +1 -1
- package/dist/auth/providers/Auth0Provider.js +1 -1
- package/dist/auth/providers/Auth0Provider.js.map +1 -1
- package/dist/auth/providers/CognitoProvider.d.ts +1 -1
- package/dist/auth/providers/CognitoProvider.d.ts.map +1 -1
- package/dist/auth/providers/CognitoProvider.js +6 -3
- package/dist/auth/providers/CognitoProvider.js.map +1 -1
- package/dist/auth/providers/GoogleProvider.d.ts +1 -1
- package/dist/auth/providers/GoogleProvider.d.ts.map +1 -1
- package/dist/auth/providers/GoogleProvider.js +1 -1
- package/dist/auth/providers/GoogleProvider.js.map +1 -1
- package/dist/auth/providers/MSALProvider.d.ts +1 -1
- package/dist/auth/providers/MSALProvider.d.ts.map +1 -1
- package/dist/auth/providers/MSALProvider.js +1 -1
- package/dist/auth/providers/MSALProvider.js.map +1 -1
- package/dist/auth/providers/OktaProvider.d.ts +1 -1
- package/dist/auth/providers/OktaProvider.d.ts.map +1 -1
- package/dist/auth/providers/OktaProvider.js +1 -1
- package/dist/auth/providers/OktaProvider.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -22
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +7 -9
- package/dist/context.js.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.js +1 -1
- package/dist/entitySubclasses/entityPermissions.server.js.map +1 -1
- package/dist/generated/generated.d.ts +788 -658
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +2050 -3054
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/KeyInputOutputTypes.d.ts +1 -1
- package/dist/generic/KeyInputOutputTypes.d.ts.map +1 -1
- package/dist/generic/KeyInputOutputTypes.js +1 -1
- package/dist/generic/KeyInputOutputTypes.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +1 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +10 -15
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +15 -15
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -18
- package/dist/index.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +2 -2
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +30 -28
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +2 -2
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +50 -60
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +38 -36
- package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/CreateQueryResolver.js +40 -43
- package/dist/resolvers/CreateQueryResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/DatasetResolver.js +1 -1
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/EntityResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityResolver.js +1 -1
- package/dist/resolvers/EntityResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +1 -1
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.js +1 -1
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +5 -5
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +6 -8
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +3 -3
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +3 -3
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +11 -11
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/ReportResolver.js +1 -1
- package/dist/resolvers/ReportResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +28 -27
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +31 -31
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +9 -9
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +10 -10
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +14 -15
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +44 -48
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/TaskResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskResolver.js +7 -7
- package/dist/resolvers/TaskResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +12 -12
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +1 -1
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +16 -14
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +25 -23
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +21 -17
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.d.ts.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.js.map +1 -1
- package/dist/services/ScheduledJobsService.d.ts.map +1 -1
- package/dist/services/ScheduledJobsService.js +6 -4
- package/dist/services/ScheduledJobsService.js.map +1 -1
- package/dist/services/TaskOrchestrator.d.ts +1 -1
- package/dist/services/TaskOrchestrator.d.ts.map +1 -1
- package/dist/services/TaskOrchestrator.js +30 -30
- package/dist/services/TaskOrchestrator.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +2 -2
- package/dist/util.js.map +1 -1
- package/package.json +39 -36
- package/src/agents/skip-agent.ts +1200 -1067
- package/src/agents/skip-sdk.ts +851 -877
- package/src/apolloServer/index.ts +2 -2
- package/src/auth/AuthProviderFactory.ts +14 -8
- package/src/auth/BaseAuthProvider.ts +4 -5
- package/src/auth/IAuthProvider.ts +2 -2
- package/src/auth/exampleNewUserSubClass.ts +2 -9
- package/src/auth/index.ts +26 -31
- package/src/auth/initializeProviders.ts +3 -3
- package/src/auth/newUsers.ts +134 -166
- package/src/auth/providers/Auth0Provider.ts +5 -5
- package/src/auth/providers/CognitoProvider.ts +10 -7
- package/src/auth/providers/GoogleProvider.ts +5 -4
- package/src/auth/providers/MSALProvider.ts +5 -5
- package/src/auth/providers/OktaProvider.ts +7 -6
- package/src/config.ts +54 -63
- package/src/context.ts +30 -42
- package/src/entitySubclasses/entityPermissions.server.ts +3 -3
- package/src/generated/generated.ts +40442 -48106
- package/src/generic/KeyInputOutputTypes.ts +6 -3
- package/src/generic/ResolverBase.ts +78 -119
- package/src/generic/RunViewResolver.ts +23 -27
- package/src/index.ts +48 -66
- package/src/resolvers/ActionResolver.ts +57 -46
- package/src/resolvers/AskSkipResolver.ts +533 -607
- package/src/resolvers/ComponentRegistryResolver.ts +562 -547
- package/src/resolvers/CreateQueryResolver.ts +655 -683
- package/src/resolvers/DatasetResolver.ts +6 -5
- package/src/resolvers/EntityCommunicationsResolver.ts +1 -1
- package/src/resolvers/EntityRecordNameResolver.ts +5 -9
- package/src/resolvers/EntityResolver.ts +7 -9
- package/src/resolvers/FileCategoryResolver.ts +2 -2
- package/src/resolvers/FileResolver.ts +4 -4
- package/src/resolvers/GetDataContextDataResolver.ts +118 -106
- package/src/resolvers/GetDataResolver.ts +205 -194
- package/src/resolvers/MergeRecordsResolver.ts +5 -5
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +1 -1
- package/src/resolvers/QueryResolver.ts +78 -95
- package/src/resolvers/ReportResolver.ts +2 -2
- package/src/resolvers/RunAIAgentResolver.ts +828 -818
- package/src/resolvers/RunAIPromptResolver.ts +709 -693
- package/src/resolvers/RunTemplateResolver.ts +103 -105
- package/src/resolvers/SqlLoggingConfigResolver.ts +72 -69
- package/src/resolvers/SyncDataResolver.ts +352 -386
- package/src/resolvers/SyncRolesUsersResolver.ts +350 -387
- package/src/resolvers/TaskResolver.ts +115 -110
- package/src/resolvers/TransactionGroupResolver.ts +138 -143
- package/src/resolvers/UserFavoriteResolver.ts +8 -17
- package/src/resolvers/UserViewResolver.ts +12 -17
- package/src/rest/EntityCRUDHandler.ts +268 -291
- package/src/rest/RESTEndpointHandler.ts +776 -782
- package/src/rest/ViewOperationsHandler.ts +195 -191
- package/src/scheduler/LearningCycleScheduler.ts +52 -8
- package/src/services/ScheduledJobsService.ts +132 -129
- package/src/services/TaskOrchestrator.ts +776 -792
- package/src/types.ts +9 -15
- package/src/util.ts +109 -112
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Arg, Ctx, Field, InputType, ObjectType, Query, Mutation, Resolver } from 'type-graphql';
|
|
2
|
-
import { UserInfo, Metadata, LogError, LogStatus } from '@memberjunction/
|
|
2
|
+
import { UserInfo, Metadata, LogError, LogStatus } from '@memberjunction/core';
|
|
3
3
|
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
4
4
|
import { ComponentEntity, ComponentRegistryEntity, ComponentMetadataEngine } from '@memberjunction/core-entities';
|
|
5
5
|
import { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
ComponentRegistryClient,
|
|
8
|
+
ComponentResponse,
|
|
9
|
+
ComponentSearchResult,
|
|
10
|
+
DependencyTree,
|
|
11
|
+
RegistryError,
|
|
12
|
+
RegistryErrorCode,
|
|
13
|
+
ComponentFeedbackParams as SDKComponentFeedbackParams,
|
|
14
|
+
ComponentFeedbackResponse as SDKComponentFeedbackResponse
|
|
15
15
|
} from '@memberjunction/component-registry-client-sdk';
|
|
16
16
|
import { AppContext } from '../types.js';
|
|
17
17
|
import { configInfo } from '../config.js';
|
|
@@ -22,80 +22,80 @@ import { configInfo } from '../config.js';
|
|
|
22
22
|
|
|
23
23
|
@ObjectType()
|
|
24
24
|
class ComponentSpecWithHashType {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
@Field(() => String, { nullable: true })
|
|
26
|
+
specification?: string; // JSON string of ComponentSpec
|
|
27
|
+
|
|
28
|
+
@Field(() => String)
|
|
29
|
+
hash: string;
|
|
30
|
+
|
|
31
|
+
@Field(() => Boolean)
|
|
32
|
+
notModified: boolean;
|
|
33
|
+
|
|
34
|
+
@Field(() => String, { nullable: true })
|
|
35
|
+
message?: string;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
@InputType()
|
|
39
39
|
class SearchRegistryComponentsInput {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
@Field({ nullable: true })
|
|
41
|
+
registryId?: string;
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
@Field({ nullable: true })
|
|
44
|
+
namespace?: string;
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
@Field({ nullable: true })
|
|
47
|
+
query?: string;
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
@Field({ nullable: true })
|
|
50
|
+
type?: string;
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
@Field(() => [String], { nullable: true })
|
|
53
|
+
tags?: string[];
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
@Field({ nullable: true })
|
|
56
|
+
limit?: number;
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
@Field({ nullable: true })
|
|
59
|
+
offset?: number;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
@ObjectType()
|
|
63
63
|
class RegistryComponentSearchResultType {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
@Field(() => [String])
|
|
65
|
+
components: string[]; // Array of JSON strings of ComponentSpec
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
@Field()
|
|
68
|
+
total: number;
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
@Field()
|
|
71
|
+
offset: number;
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
@Field()
|
|
74
|
+
limit: number;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
@ObjectType()
|
|
78
78
|
class ComponentDependencyTreeType {
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
@Field()
|
|
80
|
+
componentId: string;
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
@Field({ nullable: true })
|
|
83
|
+
name?: string;
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
@Field({ nullable: true })
|
|
86
|
+
namespace?: string;
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
@Field({ nullable: true })
|
|
89
|
+
version?: string;
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
@Field({ nullable: true })
|
|
92
|
+
circular?: boolean;
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
@Field({ nullable: true })
|
|
95
|
+
totalCount?: number;
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
@Field(() => [ComponentDependencyTreeType], { nullable: true })
|
|
98
|
+
dependencies?: ComponentDependencyTreeType[];
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|
|
@@ -104,38 +104,38 @@ class ComponentDependencyTreeType {
|
|
|
104
104
|
*/
|
|
105
105
|
@InputType()
|
|
106
106
|
class ComponentFeedbackInput {
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
@Field()
|
|
108
|
+
componentName: string;
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
@Field()
|
|
111
|
+
componentNamespace: string;
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
@Field({ nullable: true })
|
|
114
|
+
componentVersion?: string;
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
@Field({ nullable: true })
|
|
117
|
+
registryName?: string;
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
@Field()
|
|
120
|
+
rating: number;
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
@Field({ nullable: true })
|
|
123
|
+
feedbackType?: string;
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
@Field({ nullable: true })
|
|
126
|
+
comments?: string;
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
@Field({ nullable: true })
|
|
129
|
+
conversationID?: string;
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
@Field({ nullable: true })
|
|
132
|
+
conversationDetailID?: string;
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
@Field({ nullable: true })
|
|
135
|
+
reportID?: string;
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
@Field({ nullable: true })
|
|
138
|
+
dashboardID?: string;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
/**
|
|
@@ -143,507 +143,522 @@ class ComponentFeedbackInput {
|
|
|
143
143
|
*/
|
|
144
144
|
@ObjectType()
|
|
145
145
|
class ComponentFeedbackResponse {
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
@Field()
|
|
147
|
+
success: boolean;
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
@Field({ nullable: true })
|
|
150
|
+
feedbackID?: string;
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
@Field({ nullable: true })
|
|
153
|
+
error?: string;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
157
|
* Resolver for Component Registry operations
|
|
158
|
-
*
|
|
158
|
+
*
|
|
159
159
|
* Environment Variables for Development:
|
|
160
160
|
* - REGISTRY_URI_OVERRIDE_<REGISTRY_NAME>: Override the URI for a specific registry
|
|
161
161
|
* Example: REGISTRY_URI_OVERRIDE_MJ_CENTRAL=http://localhost:8080
|
|
162
162
|
* Registry names are converted to uppercase with non-alphanumeric chars replaced by underscores
|
|
163
|
-
*
|
|
163
|
+
*
|
|
164
164
|
* - REGISTRY_API_KEY_<REGISTRY_NAME>: API key for authenticating with the registry
|
|
165
165
|
* Example: REGISTRY_API_KEY_MJ_CENTRAL=your-api-key-here
|
|
166
166
|
*/
|
|
167
167
|
@Resolver()
|
|
168
168
|
export class ComponentRegistryExtendedResolver {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Get a component from a registry with optional hash for caching
|
|
177
|
-
*/
|
|
178
|
-
@Query(() => ComponentSpecWithHashType)
|
|
179
|
-
async GetRegistryComponent(
|
|
180
|
-
@Arg('registryName') registryName: string,
|
|
181
|
-
@Arg('namespace') namespace: string,
|
|
182
|
-
@Arg('name') name: string,
|
|
183
|
-
@Ctx() { userPayload }: AppContext,
|
|
184
|
-
@Arg('version', { nullable: true }) version?: string,
|
|
185
|
-
@Arg('hash', { nullable: true }) hash?: string
|
|
186
|
-
): Promise<ComponentSpecWithHashType> {
|
|
187
|
-
try {
|
|
188
|
-
// Get user from cache
|
|
189
|
-
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
190
|
-
if (!user) throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
191
|
-
|
|
192
|
-
// Get registry from database by name
|
|
193
|
-
const registry = await this.getRegistryByName(registryName, user);
|
|
194
|
-
if (!registry) {
|
|
195
|
-
throw new Error(`Registry not found: ${registryName}`);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Check user permissions (use registry ID for permission check)
|
|
199
|
-
await this.checkUserAccess(user, registry.ID);
|
|
200
|
-
|
|
201
|
-
// Initialize component engine
|
|
202
|
-
await this.componentEngine.Config(false, user);
|
|
203
|
-
|
|
204
|
-
// Create client on-demand for this registry
|
|
205
|
-
const registryClient = this.createClientForRegistry(registry);
|
|
206
|
-
|
|
207
|
-
// Fetch component from registry with hash support
|
|
208
|
-
const response = await registryClient.getComponentWithHash({
|
|
209
|
-
registry: registry.Name,
|
|
210
|
-
namespace,
|
|
211
|
-
name,
|
|
212
|
-
version: version || 'latest',
|
|
213
|
-
hash: hash,
|
|
214
|
-
userEmail: user.Email,
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// If not modified (304), return response with notModified flag
|
|
218
|
-
if (response.notModified) {
|
|
219
|
-
LogStatus(`Component ${namespace}/${name} not modified (hash: ${response.hash})`);
|
|
220
|
-
return {
|
|
221
|
-
specification: undefined,
|
|
222
|
-
hash: response.hash,
|
|
223
|
-
notModified: true,
|
|
224
|
-
message: response.message || 'Not modified',
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Extract the specification from the response
|
|
229
|
-
const component = response.specification;
|
|
230
|
-
if (!component) {
|
|
231
|
-
throw new Error(`Component ${namespace}/${name} returned without specification`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Optional: Cache in database if configured
|
|
235
|
-
if (this.shouldCache(registry)) {
|
|
236
|
-
await this.cacheComponent(component, registry.ID, user);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Return the ComponentSpec as a JSON string
|
|
240
|
-
return {
|
|
241
|
-
specification: JSON.stringify(component),
|
|
242
|
-
hash: response.hash,
|
|
243
|
-
notModified: false,
|
|
244
|
-
message: undefined,
|
|
245
|
-
};
|
|
246
|
-
} catch (error) {
|
|
247
|
-
if (error instanceof RegistryError) {
|
|
248
|
-
// Log specific registry errors
|
|
249
|
-
LogError(`Registry error [${error.code}]: ${error.message}`);
|
|
250
|
-
if (error.code === RegistryErrorCode.COMPONENT_NOT_FOUND) {
|
|
251
|
-
// Return an error response structure
|
|
252
|
-
return {
|
|
253
|
-
specification: undefined,
|
|
254
|
-
hash: '',
|
|
255
|
-
notModified: false,
|
|
256
|
-
message: 'Component not found',
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
LogError(error);
|
|
261
|
-
throw error;
|
|
169
|
+
private componentEngine = ComponentMetadataEngine.Instance;
|
|
170
|
+
|
|
171
|
+
constructor() {
|
|
172
|
+
// No longer pre-initialize clients - create on demand
|
|
262
173
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get a component from a registry with optional hash for caching
|
|
177
|
+
*/
|
|
178
|
+
@Query(() => ComponentSpecWithHashType)
|
|
179
|
+
async GetRegistryComponent(
|
|
180
|
+
@Arg('registryName') registryName: string,
|
|
181
|
+
@Arg('namespace') namespace: string,
|
|
182
|
+
@Arg('name') name: string,
|
|
183
|
+
@Ctx() { userPayload }: AppContext,
|
|
184
|
+
@Arg('version', { nullable: true }) version?: string,
|
|
185
|
+
@Arg('hash', { nullable: true }) hash?: string
|
|
186
|
+
): Promise<ComponentSpecWithHashType> {
|
|
187
|
+
try {
|
|
188
|
+
// Get user from cache
|
|
189
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
190
|
+
if (!user) throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
191
|
+
|
|
192
|
+
// Get registry from database by name
|
|
193
|
+
const registry = await this.getRegistryByName(registryName, user);
|
|
194
|
+
if (!registry) {
|
|
195
|
+
throw new Error(`Registry not found: ${registryName}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check user permissions (use registry ID for permission check)
|
|
199
|
+
await this.checkUserAccess(user, registry.ID);
|
|
200
|
+
|
|
201
|
+
// Initialize component engine
|
|
202
|
+
await this.componentEngine.Config(false, user);
|
|
203
|
+
|
|
204
|
+
// Create client on-demand for this registry
|
|
205
|
+
const registryClient = this.createClientForRegistry(registry);
|
|
206
|
+
|
|
207
|
+
// Fetch component from registry with hash support
|
|
208
|
+
const response = await registryClient.getComponentWithHash({
|
|
209
|
+
registry: registry.Name,
|
|
210
|
+
namespace,
|
|
211
|
+
name,
|
|
212
|
+
version: version || 'latest',
|
|
213
|
+
hash: hash,
|
|
214
|
+
userEmail: user.Email
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// If not modified (304), return response with notModified flag
|
|
218
|
+
if (response.notModified) {
|
|
219
|
+
LogStatus(`Component ${namespace}/${name} not modified (hash: ${response.hash})`);
|
|
220
|
+
return {
|
|
221
|
+
specification: undefined,
|
|
222
|
+
hash: response.hash,
|
|
223
|
+
notModified: true,
|
|
224
|
+
message: response.message || 'Not modified'
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Extract the specification from the response
|
|
229
|
+
const component = response.specification;
|
|
230
|
+
if (!component) {
|
|
231
|
+
throw new Error(`Component ${namespace}/${name} returned without specification`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Optional: Cache in database if configured
|
|
235
|
+
if (this.shouldCache(registry)) {
|
|
236
|
+
await this.cacheComponent(component, registry.ID, user);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Return the ComponentSpec as a JSON string
|
|
240
|
+
return {
|
|
241
|
+
specification: JSON.stringify(component),
|
|
242
|
+
hash: response.hash,
|
|
243
|
+
notModified: false,
|
|
244
|
+
message: undefined
|
|
245
|
+
};
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (error instanceof RegistryError) {
|
|
248
|
+
// Log specific registry errors
|
|
249
|
+
LogError(`Registry error [${error.code}]: ${error.message}`);
|
|
250
|
+
if (error.code === RegistryErrorCode.COMPONENT_NOT_FOUND) {
|
|
251
|
+
// Return an error response structure
|
|
252
|
+
return {
|
|
253
|
+
specification: undefined,
|
|
254
|
+
hash: '',
|
|
255
|
+
notModified: false,
|
|
256
|
+
message: 'Component not found'
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
LogError(error);
|
|
261
|
+
throw error;
|
|
286
262
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
return this.mapSearchResult(result);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Otherwise, search across all active registries
|
|
303
|
-
const allResults: ComponentSpec[] = [];
|
|
304
|
-
|
|
305
|
-
// Get all active registries from database
|
|
306
|
-
await this.componentEngine.Config(false, user);
|
|
307
|
-
const activeRegistries = this.componentEngine.ComponentRegistries?.filter((r) => r.Status === 'Active') || [];
|
|
308
|
-
|
|
309
|
-
for (const registry of activeRegistries) {
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Search for components in registries
|
|
267
|
+
*/
|
|
268
|
+
@Query(() => RegistryComponentSearchResultType)
|
|
269
|
+
async SearchRegistryComponents(
|
|
270
|
+
@Arg('params') params: SearchRegistryComponentsInput,
|
|
271
|
+
@Ctx() { userPayload }: AppContext
|
|
272
|
+
): Promise<RegistryComponentSearchResultType> {
|
|
310
273
|
try {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
274
|
+
// Get user from cache
|
|
275
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
276
|
+
if (!user) throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
277
|
+
|
|
278
|
+
// If a specific registry is specified, use only that one
|
|
279
|
+
if (params.registryId) {
|
|
280
|
+
await this.checkUserAccess(user, params.registryId);
|
|
281
|
+
|
|
282
|
+
// Get registry and create client on-demand
|
|
283
|
+
const registry = await this.getRegistry(params.registryId, user);
|
|
284
|
+
if (!registry) {
|
|
285
|
+
throw new Error(`Registry not found: ${params.registryId}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const client = this.createClientForRegistry(registry);
|
|
289
|
+
|
|
290
|
+
const result = await client.searchComponents({
|
|
291
|
+
namespace: params.namespace,
|
|
292
|
+
query: params.query,
|
|
293
|
+
type: params.type,
|
|
294
|
+
tags: params.tags,
|
|
295
|
+
limit: params.limit || 10,
|
|
296
|
+
offset: params.offset || 0
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
return this.mapSearchResult(result);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Otherwise, search across all active registries
|
|
303
|
+
const allResults: ComponentSpec[] = [];
|
|
304
|
+
|
|
305
|
+
// Get all active registries from database
|
|
306
|
+
await this.componentEngine.Config(false, user);
|
|
307
|
+
const activeRegistries = this.componentEngine.ComponentRegistries?.filter(
|
|
308
|
+
r => r.Status === 'Active'
|
|
309
|
+
) || [];
|
|
310
|
+
|
|
311
|
+
for (const registry of activeRegistries) {
|
|
312
|
+
try {
|
|
313
|
+
await this.checkUserAccess(user, registry.ID);
|
|
314
|
+
|
|
315
|
+
const client = this.createClientForRegistry(registry);
|
|
316
|
+
const result = await client.searchComponents({
|
|
317
|
+
namespace: params.namespace,
|
|
318
|
+
query: params.query,
|
|
319
|
+
type: params.type,
|
|
320
|
+
tags: params.tags,
|
|
321
|
+
limit: params.limit || 10,
|
|
322
|
+
offset: 0 // Reset offset for each registry
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
allResults.push(...result.components);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
// Log but continue with other registries
|
|
328
|
+
LogError(`Failed to search registry ${registry.Name}: ${error}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Apply pagination to combined results
|
|
333
|
+
const offset = params.offset || 0;
|
|
334
|
+
const limit = params.limit || 10;
|
|
335
|
+
const paginatedResults = allResults.slice(offset, offset + limit);
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
components: paginatedResults.map(spec => JSON.stringify(spec)),
|
|
339
|
+
total: allResults.length,
|
|
340
|
+
offset,
|
|
341
|
+
limit
|
|
342
|
+
};
|
|
324
343
|
} catch (error) {
|
|
325
|
-
|
|
326
|
-
|
|
344
|
+
LogError(error);
|
|
345
|
+
throw error;
|
|
327
346
|
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Apply pagination to combined results
|
|
331
|
-
const offset = params.offset || 0;
|
|
332
|
-
const limit = params.limit || 10;
|
|
333
|
-
const paginatedResults = allResults.slice(offset, offset + limit);
|
|
334
|
-
|
|
335
|
-
return {
|
|
336
|
-
components: paginatedResults.map((spec) => JSON.stringify(spec)),
|
|
337
|
-
total: allResults.length,
|
|
338
|
-
offset,
|
|
339
|
-
limit,
|
|
340
|
-
};
|
|
341
|
-
} catch (error) {
|
|
342
|
-
LogError(error);
|
|
343
|
-
throw error;
|
|
344
347
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Resolve component dependencies
|
|
351
|
+
*/
|
|
352
|
+
@Query(() => ComponentDependencyTreeType, { nullable: true })
|
|
353
|
+
async ResolveComponentDependencies(
|
|
354
|
+
@Arg('registryName') registryName: string,
|
|
355
|
+
@Arg('componentId') componentId: string,
|
|
356
|
+
@Ctx() { userPayload }: AppContext
|
|
357
|
+
): Promise<ComponentDependencyTreeType | null> {
|
|
358
|
+
try {
|
|
359
|
+
// Get user from cache
|
|
360
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
361
|
+
if (!user) throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
362
|
+
|
|
363
|
+
// Get registry to find its ID for permission check
|
|
364
|
+
const registry = await this.getRegistryByName(registryName, user);
|
|
365
|
+
if (!registry) {
|
|
366
|
+
throw new Error(`Registry not found: ${registryName}`);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
await this.checkUserAccess(user, registry.ID);
|
|
370
|
+
|
|
371
|
+
// Create client on-demand
|
|
372
|
+
const client = this.createClientForRegistry(registry);
|
|
373
|
+
|
|
374
|
+
const tree = await client.resolveDependencies(componentId);
|
|
375
|
+
return tree as ComponentDependencyTreeType;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
LogError(error);
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
377
380
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Check if user has access to a registry
|
|
384
|
+
*/
|
|
385
|
+
private async checkUserAccess(userInfo: UserInfo | undefined, registryId: string): Promise<void> {
|
|
386
|
+
// TODO: Implement actual permission checking
|
|
387
|
+
// For now, just ensure user is authenticated
|
|
388
|
+
if (!userInfo) {
|
|
389
|
+
throw new Error('User must be authenticated to access component registries');
|
|
390
|
+
}
|
|
388
391
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get registry entity from database by ID
|
|
395
|
+
*/
|
|
396
|
+
private async getRegistry(registryId: string, userInfo: UserInfo): Promise<ComponentRegistryEntity | null> {
|
|
397
|
+
try {
|
|
398
|
+
await this.componentEngine.Config(false, userInfo);
|
|
399
|
+
|
|
400
|
+
const registry = this.componentEngine.ComponentRegistries?.find(
|
|
401
|
+
r => r.ID === registryId
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
return registry || null;
|
|
405
|
+
} catch (error) {
|
|
406
|
+
LogError(error);
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
404
409
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Get registry entity from database by Name
|
|
413
|
+
*/
|
|
414
|
+
private async getRegistryByName(registryName: string, userInfo: UserInfo): Promise<ComponentRegistryEntity | null> {
|
|
415
|
+
try {
|
|
416
|
+
await this.componentEngine.Config(false, userInfo);
|
|
417
|
+
|
|
418
|
+
const registry = this.componentEngine.ComponentRegistries?.find(
|
|
419
|
+
r => r.Name === registryName && r.Status === 'Active'
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
return registry || null;
|
|
423
|
+
} catch (error) {
|
|
424
|
+
LogError(error);
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
420
427
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Get the registry URI, checking for environment variable override first
|
|
431
|
+
* Environment variable format: REGISTRY_URI_OVERRIDE_<REGISTRY_NAME>
|
|
432
|
+
* Example: REGISTRY_URI_OVERRIDE_MJ_CENTRAL=http://localhost:8080
|
|
433
|
+
*/
|
|
434
|
+
private getRegistryUri(registry: ComponentRegistryEntity): string {
|
|
435
|
+
if (!registry.Name) {
|
|
436
|
+
return registry.URI || '';
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Convert registry name to environment variable format
|
|
440
|
+
// Replace spaces, hyphens, and other non-alphanumeric chars with underscores
|
|
441
|
+
const envVarName = `REGISTRY_URI_OVERRIDE_${registry.Name.replace(/[^A-Za-z0-9]/g, '_').toUpperCase()}`;
|
|
442
|
+
|
|
443
|
+
// Check for environment variable override
|
|
444
|
+
const override = process.env[envVarName];
|
|
445
|
+
if (override) {
|
|
446
|
+
LogStatus(`Using URI override for registry ${registry.Name}: ${override}`);
|
|
447
|
+
return override;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Use production URI from database
|
|
451
|
+
return registry.URI || '';
|
|
431
452
|
}
|
|
432
453
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
454
|
+
/**
|
|
455
|
+
* Create a client for a registry on-demand
|
|
456
|
+
* Checks configuration first, then falls back to default settings
|
|
457
|
+
*/
|
|
458
|
+
private createClientForRegistry(registry: ComponentRegistryEntity): ComponentRegistryClient {
|
|
459
|
+
// Check if there's a configuration for this registry
|
|
460
|
+
const config = configInfo.componentRegistries?.find(r =>
|
|
461
|
+
r.id === registry.ID || r.name === registry.Name
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
// Get API key from environment or config
|
|
465
|
+
const apiKey = process.env[`REGISTRY_API_KEY_${registry.ID.replace(/-/g, '_').toUpperCase()}`] ||
|
|
466
|
+
process.env[`REGISTRY_API_KEY_${registry.Name?.replace(/-/g, '_').toUpperCase()}`] ||
|
|
467
|
+
config?.apiKey;
|
|
468
|
+
|
|
469
|
+
// Get the registry URI (with possible override)
|
|
470
|
+
const baseUrl = this.getRegistryUri(registry);
|
|
471
|
+
|
|
472
|
+
// Build retry policy with defaults
|
|
473
|
+
const retryPolicy = {
|
|
474
|
+
maxRetries: config?.retryPolicy?.maxRetries ?? 3,
|
|
475
|
+
initialDelay: config?.retryPolicy?.initialDelay ?? 1000,
|
|
476
|
+
maxDelay: config?.retryPolicy?.maxDelay ?? 10000,
|
|
477
|
+
backoffMultiplier: config?.retryPolicy?.backoffMultiplier ?? 2
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// Use config settings if available, otherwise defaults
|
|
481
|
+
return new ComponentRegistryClient({
|
|
482
|
+
baseUrl: baseUrl,
|
|
483
|
+
apiKey: apiKey,
|
|
484
|
+
timeout: config?.timeout || 30000,
|
|
485
|
+
retryPolicy: retryPolicy,
|
|
486
|
+
headers: config?.headers
|
|
487
|
+
});
|
|
442
488
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Check if component should be cached
|
|
492
|
+
*/
|
|
493
|
+
private shouldCache(registry: ComponentRegistryEntity): boolean {
|
|
494
|
+
// Check config for caching settings
|
|
495
|
+
const config = configInfo.componentRegistries?.find(r =>
|
|
496
|
+
r.id === registry.ID || r.name === registry.Name
|
|
497
|
+
);
|
|
498
|
+
return config?.cache !== false; // Cache by default
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Cache component in database
|
|
503
|
+
*/
|
|
504
|
+
private async cacheComponent(
|
|
505
|
+
component: ComponentSpec,
|
|
506
|
+
registryId: string,
|
|
507
|
+
userInfo: UserInfo
|
|
508
|
+
): Promise<void> {
|
|
509
|
+
try {
|
|
510
|
+
// Find or create component entity
|
|
511
|
+
const md = new Metadata();
|
|
512
|
+
const componentEntity = await md.GetEntityObject<ComponentEntity>('MJ: Components', userInfo);
|
|
513
|
+
|
|
514
|
+
// Check if component already exists
|
|
515
|
+
const existingComponent = this.componentEngine.Components?.find(
|
|
516
|
+
c => c.Name === component.name &&
|
|
517
|
+
c.Namespace === component.namespace &&
|
|
518
|
+
c.SourceRegistryID === registryId
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
if (existingComponent) {
|
|
522
|
+
// Update existing component
|
|
523
|
+
if (!await componentEntity.Load(existingComponent.ID)) {
|
|
524
|
+
throw new Error(`Failed to load component: ${existingComponent.ID}`);
|
|
525
|
+
}
|
|
526
|
+
} else {
|
|
527
|
+
// Create new component
|
|
528
|
+
componentEntity.NewRecord();
|
|
529
|
+
componentEntity.SourceRegistryID = registryId;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Update component fields
|
|
533
|
+
componentEntity.Name = component.name;
|
|
534
|
+
componentEntity.Namespace = component.namespace || '';
|
|
535
|
+
componentEntity.Version = component.version || '1.0.0';
|
|
536
|
+
componentEntity.Title = component.title;
|
|
537
|
+
componentEntity.Description = component.description;
|
|
538
|
+
componentEntity.Type = this.mapComponentType(component.type);
|
|
539
|
+
componentEntity.FunctionalRequirements = component.functionalRequirements;
|
|
540
|
+
componentEntity.TechnicalDesign = component.technicalDesign;
|
|
541
|
+
componentEntity.Specification = JSON.stringify(component);
|
|
542
|
+
componentEntity.LastSyncedAt = new Date();
|
|
543
|
+
|
|
544
|
+
if (!existingComponent) {
|
|
545
|
+
componentEntity.ReplicatedAt = new Date();
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Save component
|
|
549
|
+
const result = await componentEntity.Save();
|
|
550
|
+
if (!result) {
|
|
551
|
+
throw new Error(`Failed to cache component: ${component.name}`);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Refresh metadata cache
|
|
555
|
+
await this.componentEngine.Config(true, userInfo);
|
|
556
|
+
} catch (error) {
|
|
557
|
+
// Log but don't throw - caching failure shouldn't break the operation
|
|
558
|
+
LogError('Failed to cache component:');
|
|
510
559
|
}
|
|
511
|
-
} else {
|
|
512
|
-
// Create new component
|
|
513
|
-
componentEntity.NewRecord();
|
|
514
|
-
componentEntity.SourceRegistryID = registryId;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// Update component fields
|
|
518
|
-
componentEntity.Name = component.name;
|
|
519
|
-
componentEntity.Namespace = component.namespace || '';
|
|
520
|
-
componentEntity.Version = component.version || '1.0.0';
|
|
521
|
-
componentEntity.Title = component.title;
|
|
522
|
-
componentEntity.Description = component.description;
|
|
523
|
-
componentEntity.Type = this.mapComponentType(component.type);
|
|
524
|
-
componentEntity.FunctionalRequirements = component.functionalRequirements;
|
|
525
|
-
componentEntity.TechnicalDesign = component.technicalDesign;
|
|
526
|
-
componentEntity.Specification = JSON.stringify(component);
|
|
527
|
-
componentEntity.LastSyncedAt = new Date();
|
|
528
|
-
|
|
529
|
-
if (!existingComponent) {
|
|
530
|
-
componentEntity.ReplicatedAt = new Date();
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Save component
|
|
534
|
-
const result = await componentEntity.Save();
|
|
535
|
-
if (!result) {
|
|
536
|
-
throw new Error(`Failed to cache component: ${component.name}`);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// Refresh metadata cache
|
|
540
|
-
await this.componentEngine.Config(true, userInfo);
|
|
541
|
-
} catch (error) {
|
|
542
|
-
// Log but don't throw - caching failure shouldn't break the operation
|
|
543
|
-
LogError('Failed to cache component:');
|
|
544
560
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
other: 'Other',
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
return typeMap[type.toLowerCase()] || 'Other';
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* Map search result to GraphQL type
|
|
569
|
-
*/
|
|
570
|
-
private mapSearchResult(result: ComponentSearchResult): RegistryComponentSearchResultType {
|
|
571
|
-
return {
|
|
572
|
-
components: result.components.map((spec) => JSON.stringify(spec)),
|
|
573
|
-
total: result.total,
|
|
574
|
-
offset: result.offset,
|
|
575
|
-
limit: result.limit,
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* Send feedback for a component from any registry
|
|
581
|
-
* This is a registry-agnostic mutation that allows feedback collection
|
|
582
|
-
* for components from any source registry (Skip, MJ Central, etc.)
|
|
583
|
-
*/
|
|
584
|
-
@Mutation(() => ComponentFeedbackResponse)
|
|
585
|
-
async SendComponentFeedback(
|
|
586
|
-
@Arg('feedback') feedback: ComponentFeedbackInput,
|
|
587
|
-
@Ctx() { userPayload }: AppContext
|
|
588
|
-
): Promise<ComponentFeedbackResponse> {
|
|
589
|
-
try {
|
|
590
|
-
// Get user from cache
|
|
591
|
-
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
592
|
-
if (!user) {
|
|
593
|
-
return {
|
|
594
|
-
success: false,
|
|
595
|
-
error: `User ${userPayload.email} not found in UserCache`,
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Map component type string to entity enum
|
|
564
|
+
*/
|
|
565
|
+
private mapComponentType(type: string): ComponentEntity['Type'] {
|
|
566
|
+
const typeMap: Record<string, ComponentEntity['Type']> = {
|
|
567
|
+
'report': 'Report',
|
|
568
|
+
'dashboard': 'Dashboard',
|
|
569
|
+
'form': 'Form',
|
|
570
|
+
'table': 'Table',
|
|
571
|
+
'chart': 'Chart',
|
|
572
|
+
'navigation': 'Navigation',
|
|
573
|
+
'search': 'Search',
|
|
574
|
+
'widget': 'Widget',
|
|
575
|
+
'utility': 'Utility',
|
|
576
|
+
'other': 'Other'
|
|
596
577
|
};
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
578
|
+
|
|
579
|
+
return typeMap[type.toLowerCase()] || 'Other';
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Map search result to GraphQL type
|
|
584
|
+
*/
|
|
585
|
+
private mapSearchResult(result: ComponentSearchResult): RegistryComponentSearchResultType {
|
|
601
586
|
return {
|
|
602
|
-
|
|
603
|
-
|
|
587
|
+
components: result.components.map(spec => JSON.stringify(spec)),
|
|
588
|
+
total: result.total,
|
|
589
|
+
offset: result.offset,
|
|
590
|
+
limit: result.limit
|
|
604
591
|
};
|
|
605
|
-
|
|
592
|
+
}
|
|
606
593
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
594
|
+
/**
|
|
595
|
+
* Send feedback for a component from any registry
|
|
596
|
+
* This is a registry-agnostic mutation that allows feedback collection
|
|
597
|
+
* for components from any source registry (Skip, MJ Central, etc.)
|
|
598
|
+
*/
|
|
599
|
+
@Mutation(() => ComponentFeedbackResponse)
|
|
600
|
+
async SendComponentFeedback(
|
|
601
|
+
@Arg('feedback') feedback: ComponentFeedbackInput,
|
|
602
|
+
@Ctx() { userPayload }: AppContext
|
|
603
|
+
): Promise<ComponentFeedbackResponse> {
|
|
604
|
+
try {
|
|
605
|
+
// Get user from cache
|
|
606
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
607
|
+
if (!user) {
|
|
608
|
+
return {
|
|
609
|
+
success: false,
|
|
610
|
+
error: `User ${userPayload.email} not found in UserCache`
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Registry name is required for feedback submission
|
|
615
|
+
if (!feedback.registryName) {
|
|
616
|
+
return {
|
|
617
|
+
success: false,
|
|
618
|
+
error: 'Registry name is required for feedback submission'
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Get registry configuration
|
|
623
|
+
const registry = await this.getRegistryByName(feedback.registryName, user);
|
|
624
|
+
if (!registry) {
|
|
625
|
+
return {
|
|
626
|
+
success: false,
|
|
627
|
+
error: `Registry not found: ${feedback.registryName}`
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Check user permissions
|
|
632
|
+
await this.checkUserAccess(user, registry.ID);
|
|
633
|
+
|
|
634
|
+
// Create client using the same pattern as GetRegistryComponent
|
|
635
|
+
// This respects REGISTRY_URI_OVERRIDE_* and REGISTRY_API_KEY_* environment variables
|
|
636
|
+
const registryClient = this.createClientForRegistry(registry);
|
|
637
|
+
|
|
638
|
+
const sdkParams: SDKComponentFeedbackParams = {
|
|
639
|
+
componentName: feedback.componentName,
|
|
640
|
+
componentNamespace: feedback.componentNamespace,
|
|
641
|
+
componentVersion: feedback.componentVersion,
|
|
642
|
+
registryName: feedback.registryName,
|
|
643
|
+
rating: feedback.rating,
|
|
644
|
+
feedbackType: feedback.feedbackType,
|
|
645
|
+
comments: feedback.comments,
|
|
646
|
+
conversationID: feedback.conversationID,
|
|
647
|
+
conversationDetailID: feedback.conversationDetailID,
|
|
648
|
+
reportID: feedback.reportID,
|
|
649
|
+
dashboardID: feedback.dashboardID,
|
|
650
|
+
userEmail: user.Email // Pass the authenticated user's email to the registry
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
const result = await registryClient.submitFeedback(sdkParams);
|
|
654
|
+
|
|
655
|
+
return result;
|
|
656
|
+
} catch (error) {
|
|
657
|
+
LogError(error);
|
|
658
|
+
return {
|
|
659
|
+
success: false,
|
|
660
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
661
|
+
};
|
|
662
|
+
}
|
|
647
663
|
}
|
|
648
|
-
|
|
649
|
-
}
|
|
664
|
+
}
|