@memberjunction/server 2.111.1 → 2.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +808 -951
- 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 +53 -43
- 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 +1 -3
- 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 +3 -2
- 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 +3 -6
- 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 +22 -10
- 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 +9 -7
- 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 +648 -648
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +2986 -1133
- 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 +15 -10
- 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 +18 -9
- 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 +28 -30
- 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 +60 -50
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +36 -38
- 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 +43 -40
- 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 +8 -6
- 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 +27 -28
- 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 +15 -14
- 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 +48 -44
- 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 +14 -16
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +23 -25
- 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 +17 -21
- 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 +4 -6
- 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 +0 -1
- 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 +36 -37
- package/src/agents/skip-agent.ts +1067 -1200
- package/src/agents/skip-sdk.ts +877 -851
- package/src/apolloServer/index.ts +2 -2
- package/src/auth/AuthProviderFactory.ts +8 -14
- package/src/auth/BaseAuthProvider.ts +5 -4
- package/src/auth/IAuthProvider.ts +2 -2
- package/src/auth/exampleNewUserSubClass.ts +9 -2
- package/src/auth/index.ts +31 -26
- package/src/auth/initializeProviders.ts +3 -3
- package/src/auth/newUsers.ts +166 -134
- package/src/auth/providers/Auth0Provider.ts +5 -5
- package/src/auth/providers/CognitoProvider.ts +7 -10
- package/src/auth/providers/GoogleProvider.ts +4 -5
- package/src/auth/providers/MSALProvider.ts +5 -5
- package/src/auth/providers/OktaProvider.ts +6 -7
- package/src/config.ts +63 -54
- package/src/context.ts +42 -30
- package/src/entitySubclasses/entityPermissions.server.ts +3 -3
- package/src/generated/generated.ts +48130 -39930
- package/src/generic/KeyInputOutputTypes.ts +3 -6
- package/src/generic/ResolverBase.ts +119 -78
- package/src/generic/RunViewResolver.ts +27 -23
- package/src/index.ts +66 -42
- package/src/resolvers/ActionResolver.ts +46 -57
- package/src/resolvers/AskSkipResolver.ts +607 -533
- package/src/resolvers/ComponentRegistryResolver.ts +547 -562
- package/src/resolvers/CreateQueryResolver.ts +683 -655
- package/src/resolvers/DatasetResolver.ts +5 -6
- package/src/resolvers/EntityCommunicationsResolver.ts +1 -1
- package/src/resolvers/EntityRecordNameResolver.ts +9 -5
- package/src/resolvers/EntityResolver.ts +9 -7
- package/src/resolvers/FileCategoryResolver.ts +2 -2
- package/src/resolvers/FileResolver.ts +4 -4
- package/src/resolvers/GetDataContextDataResolver.ts +106 -118
- package/src/resolvers/GetDataResolver.ts +194 -205
- package/src/resolvers/MergeRecordsResolver.ts +5 -5
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +1 -1
- package/src/resolvers/QueryResolver.ts +95 -78
- package/src/resolvers/ReportResolver.ts +2 -2
- package/src/resolvers/RunAIAgentResolver.ts +818 -828
- package/src/resolvers/RunAIPromptResolver.ts +693 -709
- package/src/resolvers/RunTemplateResolver.ts +105 -103
- package/src/resolvers/SqlLoggingConfigResolver.ts +69 -72
- package/src/resolvers/SyncDataResolver.ts +386 -352
- package/src/resolvers/SyncRolesUsersResolver.ts +387 -350
- package/src/resolvers/TaskResolver.ts +110 -115
- package/src/resolvers/TransactionGroupResolver.ts +143 -138
- package/src/resolvers/UserFavoriteResolver.ts +17 -8
- package/src/resolvers/UserViewResolver.ts +17 -12
- package/src/rest/EntityCRUDHandler.ts +291 -268
- package/src/rest/RESTEndpointHandler.ts +782 -776
- package/src/rest/ViewOperationsHandler.ts +191 -195
- package/src/scheduler/LearningCycleScheduler.ts +8 -52
- package/src/services/ScheduledJobsService.ts +129 -132
- package/src/services/TaskOrchestrator.ts +792 -776
- package/src/types.ts +15 -9
- package/src/util.ts +112 -109
|
@@ -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/global';
|
|
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,522 +143,507 @@ 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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
|
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
|
+
};
|
|
262
258
|
}
|
|
259
|
+
}
|
|
260
|
+
LogError(error);
|
|
261
|
+
throw error;
|
|
263
262
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
):
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
};
|
|
343
|
-
} catch (error) {
|
|
344
|
-
LogError(error);
|
|
345
|
-
throw error;
|
|
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> {
|
|
273
|
+
try {
|
|
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}`);
|
|
346
286
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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((r) => r.Status === 'Active') || [];
|
|
308
|
+
|
|
309
|
+
for (const registry of activeRegistries) {
|
|
358
310
|
try {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const client = this.createClientForRegistry(registry);
|
|
373
|
-
|
|
374
|
-
const tree = await client.resolveDependencies(componentId);
|
|
375
|
-
return tree as ComponentDependencyTreeType;
|
|
311
|
+
await this.checkUserAccess(user, registry.ID);
|
|
312
|
+
|
|
313
|
+
const client = this.createClientForRegistry(registry);
|
|
314
|
+
const result = await client.searchComponents({
|
|
315
|
+
namespace: params.namespace,
|
|
316
|
+
query: params.query,
|
|
317
|
+
type: params.type,
|
|
318
|
+
tags: params.tags,
|
|
319
|
+
limit: params.limit || 10,
|
|
320
|
+
offset: 0, // Reset offset for each registry
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
allResults.push(...result.components);
|
|
376
324
|
} catch (error) {
|
|
377
|
-
|
|
378
|
-
|
|
325
|
+
// Log but continue with other registries
|
|
326
|
+
LogError(`Failed to search registry ${registry.Name}: ${error}`);
|
|
379
327
|
}
|
|
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;
|
|
380
344
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Resolve component dependencies
|
|
349
|
+
*/
|
|
350
|
+
@Query(() => ComponentDependencyTreeType, { nullable: true })
|
|
351
|
+
async ResolveComponentDependencies(
|
|
352
|
+
@Arg('registryName') registryName: string,
|
|
353
|
+
@Arg('componentId') componentId: string,
|
|
354
|
+
@Ctx() { userPayload }: AppContext
|
|
355
|
+
): Promise<ComponentDependencyTreeType | null> {
|
|
356
|
+
try {
|
|
357
|
+
// Get user from cache
|
|
358
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
359
|
+
if (!user) throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
360
|
+
|
|
361
|
+
// Get registry to find its ID for permission check
|
|
362
|
+
const registry = await this.getRegistryByName(registryName, user);
|
|
363
|
+
if (!registry) {
|
|
364
|
+
throw new Error(`Registry not found: ${registryName}`);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
await this.checkUserAccess(user, registry.ID);
|
|
368
|
+
|
|
369
|
+
// Create client on-demand
|
|
370
|
+
const client = this.createClientForRegistry(registry);
|
|
371
|
+
|
|
372
|
+
const tree = await client.resolveDependencies(componentId);
|
|
373
|
+
return tree as ComponentDependencyTreeType;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
LogError(error);
|
|
376
|
+
throw error;
|
|
391
377
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
);
|
|
403
|
-
|
|
404
|
-
return registry || null;
|
|
405
|
-
} catch (error) {
|
|
406
|
-
LogError(error);
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
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
|
-
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Check if user has access to a registry
|
|
382
|
+
*/
|
|
383
|
+
private async checkUserAccess(userInfo: UserInfo | undefined, registryId: string): Promise<void> {
|
|
384
|
+
// TODO: Implement actual permission checking
|
|
385
|
+
// For now, just ensure user is authenticated
|
|
386
|
+
if (!userInfo) {
|
|
387
|
+
throw new Error('User must be authenticated to access component registries');
|
|
427
388
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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 || '';
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Get registry entity from database by ID
|
|
393
|
+
*/
|
|
394
|
+
private async getRegistry(registryId: string, userInfo: UserInfo): Promise<ComponentRegistryEntity | null> {
|
|
395
|
+
try {
|
|
396
|
+
await this.componentEngine.Config(false, userInfo);
|
|
397
|
+
|
|
398
|
+
const registry = this.componentEngine.ComponentRegistries?.find((r) => r.ID === registryId);
|
|
399
|
+
|
|
400
|
+
return registry || null;
|
|
401
|
+
} catch (error) {
|
|
402
|
+
LogError(error);
|
|
403
|
+
return null;
|
|
452
404
|
}
|
|
405
|
+
}
|
|
453
406
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
});
|
|
407
|
+
/**
|
|
408
|
+
* Get registry entity from database by Name
|
|
409
|
+
*/
|
|
410
|
+
private async getRegistryByName(registryName: string, userInfo: UserInfo): Promise<ComponentRegistryEntity | null> {
|
|
411
|
+
try {
|
|
412
|
+
await this.componentEngine.Config(false, userInfo);
|
|
413
|
+
|
|
414
|
+
const registry = this.componentEngine.ComponentRegistries?.find((r) => r.Name === registryName && r.Status === 'Active');
|
|
415
|
+
|
|
416
|
+
return registry || null;
|
|
417
|
+
} catch (error) {
|
|
418
|
+
LogError(error);
|
|
419
|
+
return null;
|
|
488
420
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Get the registry URI, checking for environment variable override first
|
|
425
|
+
* Environment variable format: REGISTRY_URI_OVERRIDE_<REGISTRY_NAME>
|
|
426
|
+
* Example: REGISTRY_URI_OVERRIDE_MJ_CENTRAL=http://localhost:8080
|
|
427
|
+
*/
|
|
428
|
+
private getRegistryUri(registry: ComponentRegistryEntity): string {
|
|
429
|
+
if (!registry.Name) {
|
|
430
|
+
return registry.URI || '';
|
|
499
431
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
432
|
+
|
|
433
|
+
// Convert registry name to environment variable format
|
|
434
|
+
// Replace spaces, hyphens, and other non-alphanumeric chars with underscores
|
|
435
|
+
const envVarName = `REGISTRY_URI_OVERRIDE_${registry.Name.replace(/[^A-Za-z0-9]/g, '_').toUpperCase()}`;
|
|
436
|
+
|
|
437
|
+
// Check for environment variable override
|
|
438
|
+
const override = process.env[envVarName];
|
|
439
|
+
if (override) {
|
|
440
|
+
LogStatus(`Using URI override for registry ${registry.Name}: ${override}`);
|
|
441
|
+
return override;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Use production URI from database
|
|
445
|
+
return registry.URI || '';
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Create a client for a registry on-demand
|
|
450
|
+
* Checks configuration first, then falls back to default settings
|
|
451
|
+
*/
|
|
452
|
+
private createClientForRegistry(registry: ComponentRegistryEntity): ComponentRegistryClient {
|
|
453
|
+
// Check if there's a configuration for this registry
|
|
454
|
+
const config = configInfo.componentRegistries?.find((r) => r.id === registry.ID || r.name === registry.Name);
|
|
455
|
+
|
|
456
|
+
// Get API key from environment or config
|
|
457
|
+
const apiKey =
|
|
458
|
+
process.env[`REGISTRY_API_KEY_${registry.ID.replace(/-/g, '_').toUpperCase()}`] ||
|
|
459
|
+
process.env[`REGISTRY_API_KEY_${registry.Name?.replace(/-/g, '_').toUpperCase()}`] ||
|
|
460
|
+
config?.apiKey;
|
|
461
|
+
|
|
462
|
+
// Get the registry URI (with possible override)
|
|
463
|
+
const baseUrl = this.getRegistryUri(registry);
|
|
464
|
+
|
|
465
|
+
// Build retry policy with defaults
|
|
466
|
+
const retryPolicy = {
|
|
467
|
+
maxRetries: config?.retryPolicy?.maxRetries ?? 3,
|
|
468
|
+
initialDelay: config?.retryPolicy?.initialDelay ?? 1000,
|
|
469
|
+
maxDelay: config?.retryPolicy?.maxDelay ?? 10000,
|
|
470
|
+
backoffMultiplier: config?.retryPolicy?.backoffMultiplier ?? 2,
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// Use config settings if available, otherwise defaults
|
|
474
|
+
return new ComponentRegistryClient({
|
|
475
|
+
baseUrl: baseUrl,
|
|
476
|
+
apiKey: apiKey,
|
|
477
|
+
timeout: config?.timeout || 30000,
|
|
478
|
+
retryPolicy: retryPolicy,
|
|
479
|
+
headers: config?.headers,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Check if component should be cached
|
|
485
|
+
*/
|
|
486
|
+
private shouldCache(registry: ComponentRegistryEntity): boolean {
|
|
487
|
+
// Check config for caching settings
|
|
488
|
+
const config = configInfo.componentRegistries?.find((r) => r.id === registry.ID || r.name === registry.Name);
|
|
489
|
+
return config?.cache !== false; // Cache by default
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Cache component in database
|
|
494
|
+
*/
|
|
495
|
+
private async cacheComponent(component: ComponentSpec, registryId: string, userInfo: UserInfo): Promise<void> {
|
|
496
|
+
try {
|
|
497
|
+
// Find or create component entity
|
|
498
|
+
const md = new Metadata();
|
|
499
|
+
const componentEntity = await md.GetEntityObject<ComponentEntity>('MJ: Components', userInfo);
|
|
500
|
+
|
|
501
|
+
// Check if component already exists
|
|
502
|
+
const existingComponent = this.componentEngine.Components?.find(
|
|
503
|
+
(c) => c.Name === component.name && c.Namespace === component.namespace && c.SourceRegistryID === registryId
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
if (existingComponent) {
|
|
507
|
+
// Update existing component
|
|
508
|
+
if (!(await componentEntity.Load(existingComponent.ID))) {
|
|
509
|
+
throw new Error(`Failed to load component: ${existingComponent.ID}`);
|
|
559
510
|
}
|
|
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:');
|
|
560
544
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Map component type string to entity enum
|
|
549
|
+
*/
|
|
550
|
+
private mapComponentType(type: string): ComponentEntity['Type'] {
|
|
551
|
+
const typeMap: Record<string, ComponentEntity['Type']> = {
|
|
552
|
+
report: 'Report',
|
|
553
|
+
dashboard: 'Dashboard',
|
|
554
|
+
form: 'Form',
|
|
555
|
+
table: 'Table',
|
|
556
|
+
chart: 'Chart',
|
|
557
|
+
navigation: 'Navigation',
|
|
558
|
+
search: 'Search',
|
|
559
|
+
widget: 'Widget',
|
|
560
|
+
utility: 'Utility',
|
|
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`,
|
|
577
596
|
};
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
/**
|
|
583
|
-
* Map search result to GraphQL type
|
|
584
|
-
*/
|
|
585
|
-
private mapSearchResult(result: ComponentSearchResult): RegistryComponentSearchResultType {
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Registry name is required for feedback submission
|
|
600
|
+
if (!feedback.registryName) {
|
|
586
601
|
return {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
offset: result.offset,
|
|
590
|
-
limit: result.limit
|
|
602
|
+
success: false,
|
|
603
|
+
error: 'Registry name is required for feedback submission',
|
|
591
604
|
};
|
|
592
|
-
|
|
605
|
+
}
|
|
593
606
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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
|
-
// 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
|
-
}
|
|
607
|
+
// Get registry configuration
|
|
608
|
+
const registry = await this.getRegistryByName(feedback.registryName, user);
|
|
609
|
+
if (!registry) {
|
|
610
|
+
return {
|
|
611
|
+
success: false,
|
|
612
|
+
error: `Registry not found: ${feedback.registryName}`,
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Check user permissions
|
|
617
|
+
await this.checkUserAccess(user, registry.ID);
|
|
618
|
+
|
|
619
|
+
// Create client using the same pattern as GetRegistryComponent
|
|
620
|
+
// This respects REGISTRY_URI_OVERRIDE_* and REGISTRY_API_KEY_* environment variables
|
|
621
|
+
const registryClient = this.createClientForRegistry(registry);
|
|
622
|
+
|
|
623
|
+
const sdkParams: SDKComponentFeedbackParams = {
|
|
624
|
+
componentName: feedback.componentName,
|
|
625
|
+
componentNamespace: feedback.componentNamespace,
|
|
626
|
+
componentVersion: feedback.componentVersion,
|
|
627
|
+
registryName: feedback.registryName,
|
|
628
|
+
rating: feedback.rating,
|
|
629
|
+
feedbackType: feedback.feedbackType,
|
|
630
|
+
comments: feedback.comments,
|
|
631
|
+
conversationID: feedback.conversationID,
|
|
632
|
+
conversationDetailID: feedback.conversationDetailID,
|
|
633
|
+
reportID: feedback.reportID,
|
|
634
|
+
dashboardID: feedback.dashboardID,
|
|
635
|
+
userEmail: user.Email, // Pass the authenticated user's email to the registry
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
const result = await registryClient.submitFeedback(sdkParams);
|
|
639
|
+
|
|
640
|
+
return result;
|
|
641
|
+
} catch (error) {
|
|
642
|
+
LogError(error);
|
|
643
|
+
return {
|
|
644
|
+
success: false,
|
|
645
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
646
|
+
};
|
|
663
647
|
}
|
|
664
|
-
}
|
|
648
|
+
}
|
|
649
|
+
}
|