@memberjunction/server 2.89.0 → 2.91.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.
Files changed (89) hide show
  1. package/dist/auth/AuthProviderFactory.d.ts +24 -0
  2. package/dist/auth/AuthProviderFactory.d.ts.map +1 -0
  3. package/dist/auth/AuthProviderFactory.js +82 -0
  4. package/dist/auth/AuthProviderFactory.js.map +1 -0
  5. package/dist/auth/BaseAuthProvider.d.ts +18 -0
  6. package/dist/auth/BaseAuthProvider.d.ts.map +1 -0
  7. package/dist/auth/BaseAuthProvider.js +42 -0
  8. package/dist/auth/BaseAuthProvider.js.map +1 -0
  9. package/dist/auth/IAuthProvider.d.ts +13 -0
  10. package/dist/auth/IAuthProvider.d.ts.map +1 -0
  11. package/dist/auth/IAuthProvider.js +2 -0
  12. package/dist/auth/IAuthProvider.js.map +1 -0
  13. package/dist/auth/__tests__/backward-compatibility.test.d.ts +2 -0
  14. package/dist/auth/__tests__/backward-compatibility.test.d.ts.map +1 -0
  15. package/dist/auth/__tests__/backward-compatibility.test.js +135 -0
  16. package/dist/auth/__tests__/backward-compatibility.test.js.map +1 -0
  17. package/dist/auth/index.d.ts +22 -7
  18. package/dist/auth/index.d.ts.map +1 -1
  19. package/dist/auth/index.js +65 -32
  20. package/dist/auth/index.js.map +1 -1
  21. package/dist/auth/initializeProviders.d.ts +2 -0
  22. package/dist/auth/initializeProviders.d.ts.map +1 -0
  23. package/dist/auth/initializeProviders.js +23 -0
  24. package/dist/auth/initializeProviders.js.map +1 -0
  25. package/dist/auth/providers/Auth0Provider.d.ts +9 -0
  26. package/dist/auth/providers/Auth0Provider.d.ts.map +1 -0
  27. package/dist/auth/providers/Auth0Provider.js +42 -0
  28. package/dist/auth/providers/Auth0Provider.js.map +1 -0
  29. package/dist/auth/providers/CognitoProvider.d.ts +9 -0
  30. package/dist/auth/providers/CognitoProvider.d.ts.map +1 -0
  31. package/dist/auth/providers/CognitoProvider.js +46 -0
  32. package/dist/auth/providers/CognitoProvider.js.map +1 -0
  33. package/dist/auth/providers/GoogleProvider.d.ts +9 -0
  34. package/dist/auth/providers/GoogleProvider.d.ts.map +1 -0
  35. package/dist/auth/providers/GoogleProvider.js +41 -0
  36. package/dist/auth/providers/GoogleProvider.js.map +1 -0
  37. package/dist/auth/providers/MSALProvider.d.ts +9 -0
  38. package/dist/auth/providers/MSALProvider.d.ts.map +1 -0
  39. package/dist/auth/providers/MSALProvider.js +42 -0
  40. package/dist/auth/providers/MSALProvider.js.map +1 -0
  41. package/dist/auth/providers/OktaProvider.d.ts +9 -0
  42. package/dist/auth/providers/OktaProvider.d.ts.map +1 -0
  43. package/dist/auth/providers/OktaProvider.js +42 -0
  44. package/dist/auth/providers/OktaProvider.js.map +1 -0
  45. package/dist/config.d.ts +97 -21
  46. package/dist/config.d.ts.map +1 -1
  47. package/dist/config.js +13 -6
  48. package/dist/config.js.map +1 -1
  49. package/dist/context.d.ts.map +1 -1
  50. package/dist/context.js +25 -17
  51. package/dist/context.js.map +1 -1
  52. package/dist/generated/generated.d.ts +12 -0
  53. package/dist/generated/generated.d.ts.map +1 -1
  54. package/dist/generated/generated.js +61 -0
  55. package/dist/generated/generated.js.map +1 -1
  56. package/dist/generic/ResolverBase.d.ts +2 -2
  57. package/dist/generic/ResolverBase.d.ts.map +1 -1
  58. package/dist/generic/ResolverBase.js +5 -4
  59. package/dist/generic/ResolverBase.js.map +1 -1
  60. package/dist/generic/RunViewResolver.js.map +1 -1
  61. package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
  62. package/dist/resolvers/AskSkipResolver.js +3 -0
  63. package/dist/resolvers/AskSkipResolver.js.map +1 -1
  64. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  65. package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
  66. package/dist/types.d.ts +2 -2
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/types.js.map +1 -1
  69. package/package.json +39 -39
  70. package/src/auth/AuthProviderFactory.ts +152 -0
  71. package/src/auth/BaseAuthProvider.ts +71 -0
  72. package/src/auth/IAuthProvider.ts +49 -0
  73. package/src/auth/__tests__/backward-compatibility.test.ts +183 -0
  74. package/src/auth/index.ts +104 -36
  75. package/src/auth/initializeProviders.ts +31 -0
  76. package/src/auth/providers/Auth0Provider.ts +45 -0
  77. package/src/auth/providers/CognitoProvider.ts +50 -0
  78. package/src/auth/providers/GoogleProvider.ts +45 -0
  79. package/src/auth/providers/MSALProvider.ts +45 -0
  80. package/src/auth/providers/OktaProvider.ts +46 -0
  81. package/src/config.ts +14 -10
  82. package/src/context.ts +40 -17
  83. package/src/generated/generated.ts +37 -0
  84. package/src/generic/ResolverBase.ts +18 -13
  85. package/src/generic/RunViewResolver.ts +4 -4
  86. package/src/resolvers/AskSkipResolver.ts +3 -0
  87. package/src/resolvers/RunAIAgentResolver.ts +3 -3
  88. package/src/resolvers/RunAIPromptResolver.ts +2 -2
  89. package/src/types.ts +2 -4
@@ -0,0 +1,45 @@
1
+ import { JwtPayload } from 'jsonwebtoken';
2
+ import { RegisterClass } from '@memberjunction/global';
3
+ import { AuthProviderConfig, AuthUserInfo } from '@memberjunction/core';
4
+ import { BaseAuthProvider } from '../BaseAuthProvider.js';
5
+
6
+ /**
7
+ * Auth0 authentication provider implementation
8
+ */
9
+ @RegisterClass(BaseAuthProvider, 'auth0')
10
+ export class Auth0Provider extends BaseAuthProvider {
11
+ constructor(config: AuthProviderConfig) {
12
+ super(config);
13
+ }
14
+
15
+ /**
16
+ * Extracts user information from Auth0 JWT payload
17
+ */
18
+ extractUserInfo(payload: JwtPayload): AuthUserInfo {
19
+ // Auth0 uses standard OIDC claims
20
+ const email = payload.email as string | undefined;
21
+ const fullName = payload.name as string | undefined;
22
+ const firstName = payload.given_name as string | undefined;
23
+ const lastName = payload.family_name as string | undefined;
24
+ const preferredUsername = payload.preferred_username as string | undefined || email;
25
+
26
+ return {
27
+ email,
28
+ firstName: firstName || fullName?.split(' ')[0],
29
+ lastName: lastName || fullName?.split(' ')[1] || fullName?.split(' ')[0],
30
+ fullName,
31
+ preferredUsername
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Validates Auth0-specific configuration
37
+ */
38
+ validateConfig(): boolean {
39
+ const baseValid = super.validateConfig();
40
+ const hasClientId = !!this.config.clientId;
41
+ const hasDomain = !!this.config.domain;
42
+
43
+ return baseValid && hasClientId && hasDomain;
44
+ }
45
+ }
@@ -0,0 +1,50 @@
1
+ import { JwtPayload } from 'jsonwebtoken';
2
+ import { RegisterClass } from '@memberjunction/global';
3
+ import { AuthProviderConfig, AuthUserInfo } from '@memberjunction/core';
4
+ import { BaseAuthProvider } from '../BaseAuthProvider.js';
5
+
6
+
7
+ /**
8
+ * AWS Cognito authentication provider implementation
9
+ */
10
+ @RegisterClass(BaseAuthProvider, 'cognito')
11
+ export class CognitoProvider extends BaseAuthProvider {
12
+ constructor(config: AuthProviderConfig) {
13
+ super(config);
14
+ }
15
+
16
+ /**
17
+ * Extracts user information from Cognito JWT payload
18
+ */
19
+ extractUserInfo(payload: JwtPayload): AuthUserInfo {
20
+ // Cognito uses custom claims with 'cognito:' prefix for some fields
21
+ const email = payload.email as string | undefined ||
22
+ payload['cognito:username'] as string | undefined;
23
+ const fullName = payload.name as string | undefined;
24
+ const firstName = payload.given_name as string | undefined;
25
+ const lastName = payload.family_name as string | undefined;
26
+ const preferredUsername = payload['cognito:username'] as string | undefined ||
27
+ payload.preferred_username as string | undefined ||
28
+ email;
29
+
30
+ return {
31
+ email,
32
+ firstName: firstName || fullName?.split(' ')[0],
33
+ lastName: lastName || fullName?.split(' ')[1] || fullName?.split(' ')[0],
34
+ fullName,
35
+ preferredUsername
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Validates Cognito-specific configuration
41
+ */
42
+ validateConfig(): boolean {
43
+ const baseValid = super.validateConfig();
44
+ const hasClientId = !!this.config.clientId;
45
+ const hasRegion = !!this.config.region;
46
+ const hasUserPoolId = !!this.config.userPoolId;
47
+
48
+ return baseValid && hasClientId && hasRegion && hasUserPoolId;
49
+ }
50
+ }
@@ -0,0 +1,45 @@
1
+ import { JwtPayload } from 'jsonwebtoken';
2
+ import { RegisterClass } from '@memberjunction/global';
3
+ import { AuthProviderConfig, AuthUserInfo } from '@memberjunction/core';
4
+ import { BaseAuthProvider } from '../BaseAuthProvider.js';
5
+
6
+
7
+ /**
8
+ * Google Identity Platform authentication provider implementation
9
+ */
10
+ @RegisterClass(BaseAuthProvider, 'google')
11
+ export class GoogleProvider extends BaseAuthProvider {
12
+ constructor(config: AuthProviderConfig) {
13
+ super(config);
14
+ }
15
+
16
+ /**
17
+ * Extracts user information from Google JWT payload
18
+ */
19
+ extractUserInfo(payload: JwtPayload): AuthUserInfo {
20
+ // Google uses standard OIDC claims
21
+ const email = payload.email as string | undefined;
22
+ const fullName = payload.name as string | undefined;
23
+ const firstName = payload.given_name as string | undefined;
24
+ const lastName = payload.family_name as string | undefined;
25
+ const preferredUsername = email; // Google typically uses email as username
26
+
27
+ return {
28
+ email,
29
+ firstName: firstName || fullName?.split(' ')[0],
30
+ lastName: lastName || fullName?.split(' ')[1] || fullName?.split(' ')[0],
31
+ fullName,
32
+ preferredUsername
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Validates Google-specific configuration
38
+ */
39
+ validateConfig(): boolean {
40
+ const baseValid = super.validateConfig();
41
+ const hasClientId = !!this.config.clientId;
42
+
43
+ return baseValid && hasClientId;
44
+ }
45
+ }
@@ -0,0 +1,45 @@
1
+ import { JwtPayload } from 'jsonwebtoken';
2
+ import { RegisterClass } from '@memberjunction/global';
3
+ import { AuthProviderConfig, AuthUserInfo } from '@memberjunction/core';
4
+ import { BaseAuthProvider } from '../BaseAuthProvider.js';
5
+
6
+ /**
7
+ * Microsoft Authentication Library (MSAL) provider implementation
8
+ */
9
+ @RegisterClass(BaseAuthProvider, 'msal')
10
+ export class MSALProvider extends BaseAuthProvider {
11
+ constructor(config: AuthProviderConfig) {
12
+ super(config);
13
+ }
14
+
15
+ /**
16
+ * Extracts user information from MSAL/Azure AD JWT payload
17
+ */
18
+ extractUserInfo(payload: JwtPayload): AuthUserInfo {
19
+ // MSAL/Azure AD uses some custom claims
20
+ const email = payload.email as string | undefined || payload.preferred_username as string | undefined;
21
+ const fullName = payload.name as string | undefined;
22
+ const firstName = payload.given_name as string | undefined;
23
+ const lastName = payload.family_name as string | undefined;
24
+ const preferredUsername = payload.preferred_username as string | undefined;
25
+
26
+ return {
27
+ email,
28
+ firstName: firstName || fullName?.split(' ')[0],
29
+ lastName: lastName || fullName?.split(' ')[1] || fullName?.split(' ')[0],
30
+ fullName,
31
+ preferredUsername
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Validates MSAL-specific configuration
37
+ */
38
+ validateConfig(): boolean {
39
+ const baseValid = super.validateConfig();
40
+ const hasClientId = !!this.config.clientId;
41
+ const hasTenantId = !!this.config.tenantId;
42
+
43
+ return baseValid && hasClientId && hasTenantId;
44
+ }
45
+ }
@@ -0,0 +1,46 @@
1
+ import { JwtPayload } from 'jsonwebtoken';
2
+ import { RegisterClass } from '@memberjunction/global';
3
+ import { AuthProviderConfig, AuthUserInfo } from '@memberjunction/core';
4
+ import { BaseAuthProvider } from '../BaseAuthProvider.js';
5
+
6
+
7
+ /**
8
+ * Okta authentication provider implementation
9
+ */
10
+ @RegisterClass(BaseAuthProvider, 'okta')
11
+ export class OktaProvider extends BaseAuthProvider {
12
+ constructor(config: AuthProviderConfig) {
13
+ super(config);
14
+ }
15
+
16
+ /**
17
+ * Extracts user information from Okta JWT payload
18
+ */
19
+ extractUserInfo(payload: JwtPayload): AuthUserInfo {
20
+ // Okta uses standard OIDC claims plus some custom ones
21
+ const email = payload.email as string | undefined || payload.preferred_username as string | undefined;
22
+ const fullName = payload.name as string | undefined;
23
+ const firstName = payload.given_name as string | undefined;
24
+ const lastName = payload.family_name as string | undefined;
25
+ const preferredUsername = payload.preferred_username as string | undefined || email;
26
+
27
+ return {
28
+ email,
29
+ firstName: firstName || fullName?.split(' ')[0],
30
+ lastName: lastName || fullName?.split(' ')[1] || fullName?.split(' ')[0],
31
+ fullName,
32
+ preferredUsername
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Validates Okta-specific configuration
38
+ */
39
+ validateConfig(): boolean {
40
+ const baseValid = super.validateConfig();
41
+ const hasClientId = !!this.config.clientId;
42
+ const hasDomain = !!this.config.domain;
43
+
44
+ return baseValid && hasClientId && hasDomain;
45
+ }
46
+ }
package/src/config.ts CHANGED
@@ -102,6 +102,18 @@ const sqlLoggingSchema = z.object({
102
102
  sessionTimeout: z.number().optional().default(3600000), // 1 hour
103
103
  });
104
104
 
105
+ const authProviderSchema = z.object({
106
+ name: z.string(),
107
+ type: z.string(),
108
+ issuer: z.string(),
109
+ audience: z.string(),
110
+ jwksUri: z.string(),
111
+ clientId: z.string().optional(),
112
+ clientSecret: z.string().optional(),
113
+ tenantId: z.string().optional(),
114
+ domain: z.string().optional(),
115
+ }).passthrough(); // Allow additional provider-specific fields
116
+
105
117
  const configInfoSchema = z.object({
106
118
  userHandling: userHandlingInfoSchema,
107
119
  databaseSettings: databaseSettingsInfoSchema,
@@ -109,6 +121,7 @@ const configInfoSchema = z.object({
109
121
  restApiOptions: restApiOptionsSchema.optional().default({}),
110
122
  askSkip: askSkipInfoSchema.optional(),
111
123
  sqlLogging: sqlLoggingSchema.optional(),
124
+ authProviders: z.array(authProviderSchema).optional(),
112
125
 
113
126
  apiKey: z.string().optional(),
114
127
  baseUrl: z.string().default('http://localhost'),
@@ -131,17 +144,12 @@ const configInfoSchema = z.object({
131
144
  ___codeGenAPIPort: z.coerce.number().optional().default(3999),
132
145
  ___codeGenAPISubmissionDelay: z.coerce.number().optional().default(5000),
133
146
  graphqlRootPath: z.string().optional().default('/'),
134
- webClientID: z.string().optional(),
135
- tenantID: z.string().optional(),
136
147
  enableIntrospection: z.coerce.boolean().optional().default(false),
137
148
  websiteRunFromPackage: z.coerce.number().optional(),
138
149
  userEmailMap: z
139
150
  .string()
140
151
  .transform((val) => z.record(z.string()).parse(JSON.parse(val)))
141
152
  .optional(),
142
- auth0Domain: z.string().optional(),
143
- auth0WebClientID: z.string().optional(),
144
- auth0ClientSecret: z.string().optional(),
145
153
  mjCoreSchema: z.string(),
146
154
  });
147
155
 
@@ -152,6 +160,7 @@ export type RESTApiOptions = z.infer<typeof restApiOptionsSchema>;
152
160
  export type AskSkipInfo = z.infer<typeof askSkipInfoSchema>;
153
161
  export type SqlLoggingOptions = z.infer<typeof sqlLoggingOptionsSchema>;
154
162
  export type SqlLoggingInfo = z.infer<typeof sqlLoggingSchema>;
163
+ export type AuthProviderConfig = z.infer<typeof authProviderSchema>;
155
164
  export type ConfigInfo = z.infer<typeof configInfoSchema>;
156
165
 
157
166
  export const configInfo: ConfigInfo = loadConfig();
@@ -169,14 +178,9 @@ export const {
169
178
  ___codeGenAPIPort,
170
179
  ___codeGenAPISubmissionDelay,
171
180
  graphqlRootPath,
172
- webClientID,
173
- tenantID,
174
181
  enableIntrospection,
175
182
  websiteRunFromPackage,
176
183
  userEmailMap,
177
- auth0Domain,
178
- auth0WebClientID,
179
- auth0ClientSecret,
180
184
  apiKey,
181
185
  baseUrl,
182
186
  mjCoreSchema: mj_core_schema,
package/src/context.ts CHANGED
@@ -5,24 +5,33 @@ import 'reflect-metadata';
5
5
  import { Subject, firstValueFrom } from 'rxjs';
6
6
  import { AuthenticationError, AuthorizationError } from 'type-graphql';
7
7
  import sql from 'mssql';
8
- import { getSigningKeys, getSystemUser, validationOptions, verifyUserRecord } from './auth/index.js';
8
+ import { getSigningKeys, getSystemUser, getValidationOptions, verifyUserRecord, extractUserInfoFromPayload, TokenExpiredError } from './auth/index.js';
9
9
  import { authCache } from './cache.js';
10
10
  import { userEmailMap, apiKey, mj_core_schema } from './config.js';
11
11
  import { DataSourceInfo, UserPayload } from './types.js';
12
- import { TokenExpiredError } from './auth/index.js';
13
12
  import { GetReadOnlyDataSource, GetReadWriteDataSource } from './util.js';
14
13
  import { v4 as uuidv4 } from 'uuid';
15
14
  import e from 'express';
16
15
  import { DatabaseProviderBase } from '@memberjunction/core';
17
16
  import { SQLServerDataProvider, SQLServerProviderConfigData } from '@memberjunction/sqlserver-dataprovider';
17
+ import { AuthProviderFactory } from './auth/AuthProviderFactory.js';
18
18
 
19
- const verifyAsync = async (issuer: string, options: jwt.VerifyOptions, token: string): Promise<jwt.JwtPayload> =>
19
+ const verifyAsync = async (issuer: string, token: string): Promise<jwt.JwtPayload> =>
20
20
  new Promise((resolve, reject) => {
21
+ const options = getValidationOptions(issuer);
22
+
23
+ if (!options) {
24
+ reject(new Error(`No validation options found for issuer ${issuer}`));
25
+ return;
26
+ }
27
+
21
28
  jwt.verify(token, getSigningKeys(issuer), options, (err, jwt) => {
22
29
  if (jwt && typeof jwt !== 'string' && !err) {
23
30
  const payload = jwt.payload ?? jwt;
24
31
 
25
- console.log(`Valid token: ${payload.name} (${payload.email ? payload.email : payload.preferred_username})`); // temporary fix to check preferred_username if email is not present
32
+ // Use provider to extract user info for logging
33
+ const userInfo = extractUserInfoFromPayload(payload);
34
+ console.log(`Valid token: ${userInfo.fullName || 'Unknown'} (${userInfo.email || userInfo.preferredUsername || 'Unknown'})`);
26
35
  resolve(payload);
27
36
  } else {
28
37
  console.warn('Invalid token');
@@ -81,15 +90,28 @@ export const getUserPayload = async (
81
90
  throw new AuthenticationError('Missing issuer claim on token');
82
91
  }
83
92
 
84
- await verifyAsync(issuer, validationOptions[issuer], token);
93
+ // Verify issuer is supported
94
+ const factory = AuthProviderFactory.getInstance();
95
+ if (!factory.getByIssuer(issuer)) {
96
+ console.warn(`Unsupported issuer: ${issuer}`);
97
+ throw new AuthenticationError(`Unsupported authentication provider: ${issuer}`);
98
+ }
99
+
100
+ await verifyAsync(issuer, token);
85
101
  authCache.set(token, true);
86
102
  }
87
103
 
88
- const email = payload?.email ? ((userEmailMap ?? {})[payload?.email] ?? payload?.email) : payload?.preferred_username; // temporary fix to check preferred_username if email is not present
89
- const fullName = payload?.name;
90
- const firstName = payload?.given_name || fullName?.split(' ')[0];
91
- const lastName = payload?.family_name || fullName?.split(' ')[1] || fullName?.split(' ')[0];
92
- const userRecord = await verifyUserRecord(email, firstName, lastName, requestDomain, readWriteDataSource);
104
+ // Use provider to extract user information
105
+ const userInfo = extractUserInfoFromPayload(payload);
106
+ const email = userInfo.email ? ((userEmailMap ?? {})[userInfo.email] ?? userInfo.email) : userInfo.preferredUsername;
107
+
108
+ const userRecord = await verifyUserRecord(
109
+ email,
110
+ userInfo.firstName,
111
+ userInfo.lastName,
112
+ requestDomain,
113
+ readWriteDataSource
114
+ );
93
115
 
94
116
  if (!userRecord) {
95
117
  console.error(`User ${email} not found`);
@@ -99,12 +121,13 @@ export const getUserPayload = async (
99
121
  throw new AuthorizationError();
100
122
  }
101
123
 
102
- return { userRecord, email, sessionId };
103
- } catch (e) {
104
- console.error(e);
105
- if (e instanceof TokenExpiredError) {
106
- throw e;
107
- } else return {} as UserPayload;
124
+ return { userRecord, email: userRecord.Email, sessionId };
125
+ } catch (error) {
126
+ console.error(error);
127
+ if (error instanceof TokenExpiredError) {
128
+ throw error;
129
+ }
130
+ throw new AuthenticationError('Unable to authenticate user');
108
131
  }
109
132
  };
110
133
 
@@ -171,4 +194,4 @@ export const contextFunction =
171
194
  };
172
195
 
173
196
  return contextResult;
174
- };
197
+ };
@@ -37957,6 +37957,15 @@ export class Component_ {
37957
37957
  @Field(() => Int, {description: `Number of component dependencies defined in the specification. Used to assess component complexity.`})
37958
37958
  DependencyCount: number;
37959
37959
 
37960
+ @Field({nullable: true, description: `The ID of the AI model used to generate the vector embedding for the technical design`})
37961
+ TechnicalDesignVectorEmbeddingModelID?: string;
37962
+
37963
+ @Field({nullable: true, description: `The ID of the AI model used to generate the vector embedding for the functional requirements`})
37964
+ FunctionalRequirementsVectorEmbeddingModelID?: string;
37965
+
37966
+ @Field(() => Boolean, {description: `Indicates whether the component has any custom properties that are marked as required. This is auto-calculated based on the component's properties array to identify components with mandatory custom configuration.`})
37967
+ HasRequiredCustomProps: boolean;
37968
+
37960
37969
  @Field({nullable: true})
37961
37970
  @MaxLength(510)
37962
37971
  SourceRegistry?: string;
@@ -38048,6 +38057,15 @@ export class CreateComponentInput {
38048
38057
 
38049
38058
  @Field(() => Int, { nullable: true })
38050
38059
  DependencyCount?: number;
38060
+
38061
+ @Field({ nullable: true })
38062
+ TechnicalDesignVectorEmbeddingModelID: string | null;
38063
+
38064
+ @Field({ nullable: true })
38065
+ FunctionalRequirementsVectorEmbeddingModelID: string | null;
38066
+
38067
+ @Field(() => Boolean, { nullable: true })
38068
+ HasRequiredCustomProps?: boolean;
38051
38069
  }
38052
38070
 
38053
38071
 
@@ -38128,6 +38146,15 @@ export class UpdateComponentInput {
38128
38146
  @Field(() => Int, { nullable: true })
38129
38147
  DependencyCount?: number;
38130
38148
 
38149
+ @Field({ nullable: true })
38150
+ TechnicalDesignVectorEmbeddingModelID?: string | null;
38151
+
38152
+ @Field({ nullable: true })
38153
+ FunctionalRequirementsVectorEmbeddingModelID?: string | null;
38154
+
38155
+ @Field(() => Boolean, { nullable: true })
38156
+ HasRequiredCustomProps?: boolean;
38157
+
38131
38158
  @Field(() => [KeyValuePairInput], { nullable: true })
38132
38159
  OldValues___?: KeyValuePairInput[];
38133
38160
  }
@@ -39108,6 +39135,10 @@ export class ComponentLibrary_ {
39108
39135
  @MaxLength(10)
39109
39136
  _mj__UpdatedAt: Date;
39110
39137
 
39138
+ @Field({description: `Status of the component library. Active: fully supported; Deprecated: works but shows console warning; Disabled: throws error if used`})
39139
+ @MaxLength(40)
39140
+ Status: string;
39141
+
39111
39142
  @Field(() => [ComponentLibraryLink_])
39112
39143
  MJ_ComponentLibraryLinks_LibraryIDArray: ComponentLibraryLink_[]; // Link to MJ_ComponentLibraryLinks
39113
39144
 
@@ -39144,6 +39175,9 @@ export class CreateComponentLibraryInput {
39144
39175
 
39145
39176
  @Field({ nullable: true })
39146
39177
  Description: string | null;
39178
+
39179
+ @Field({ nullable: true })
39180
+ Status?: string;
39147
39181
  }
39148
39182
 
39149
39183
 
@@ -39179,6 +39213,9 @@ export class UpdateComponentLibraryInput {
39179
39213
  @Field({ nullable: true })
39180
39214
  Description?: string | null;
39181
39215
 
39216
+ @Field({ nullable: true })
39217
+ Status?: string;
39218
+
39182
39219
  @Field(() => [KeyValuePairInput], { nullable: true })
39183
39220
  OldValues___?: KeyValuePairInput[];
39184
39221
  }
@@ -16,7 +16,7 @@ import {
16
16
  RunViewResult,
17
17
  UserInfo,
18
18
  } from '@memberjunction/core';
19
- import { AuditLogEntity, ErrorLogEntity, UserViewEntity } from '@memberjunction/core-entities';
19
+ import { AuditLogEntity, ErrorLogEntity, UserViewEntityExtended } from '@memberjunction/core-entities';
20
20
  import { SQLServerDataProvider, UserCache } from '@memberjunction/sqlserver-dataprovider';
21
21
  import { PubSubEngine } from 'type-graphql';
22
22
  import { GraphQLError } from 'graphql';
@@ -117,7 +117,7 @@ export class ResolverBase {
117
117
  async RunViewByNameGeneric(viewInput: RunViewByNameInput, provider: DatabaseProviderBase, userPayload: UserPayload, pubSub: PubSubEngine) {
118
118
  try {
119
119
  const rv = provider as any as IRunViewProvider;
120
- const result = await rv.RunView<UserViewEntity>({
120
+ const result = await rv.RunView<UserViewEntityExtended>({
121
121
  EntityName: 'User Views',
122
122
  ExtraFilter: "Name='" + viewInput.ViewName + "'",
123
123
  }, userPayload.userRecord);
@@ -139,7 +139,8 @@ export class ResolverBase {
139
139
  viewInput.AuditLogDescription,
140
140
  viewInput.ResultType,
141
141
  userPayload,
142
- viewInput.MaxRows
142
+ viewInput.MaxRows,
143
+ viewInput.StartRow
143
144
  );
144
145
  }
145
146
  else {
@@ -155,7 +156,7 @@ export class ResolverBase {
155
156
  async RunViewByIDGeneric(viewInput: RunViewByIDInput, provider: DatabaseProviderBase, userPayload: UserPayload, pubSub: PubSubEngine) {
156
157
  try {
157
158
  const contextUser = this.GetUserFromPayload(userPayload);
158
- const viewInfo = await provider.GetEntityObject<UserViewEntity>('User Views', contextUser);
159
+ const viewInfo = await provider.GetEntityObject<UserViewEntityExtended>('User Views', contextUser);
159
160
  await viewInfo.Load(viewInput.ViewID);
160
161
  return this.RunViewGenericInternal(
161
162
  provider,
@@ -173,7 +174,8 @@ export class ResolverBase {
173
174
  viewInput.AuditLogDescription,
174
175
  viewInput.ResultType,
175
176
  userPayload,
176
- viewInput.MaxRows
177
+ viewInput.MaxRows,
178
+ viewInput.StartRow
177
179
  );
178
180
  } catch (err) {
179
181
  console.log(err);
@@ -187,12 +189,12 @@ export class ResolverBase {
187
189
  const entity = md.Entities.find((e) => e.Name === viewInput.EntityName);
188
190
  if (!entity) throw new Error(`Entity ${viewInput.EntityName} not found in metadata`);
189
191
 
190
- const viewInfo: UserViewEntity = {
192
+ const viewInfo: UserViewEntityExtended = {
191
193
  ID: '',
192
194
  Entity: viewInput.EntityName,
193
195
  EntityID: entity.ID,
194
196
  EntityBaseView: entity.BaseView as string,
195
- } as UserViewEntity; // only providing a few bits of data here, but it's enough to get the view to run
197
+ } as UserViewEntityExtended; // only providing a few bits of data here, but it's enough to get the view to run
196
198
 
197
199
  return this.RunViewGenericInternal(
198
200
  provider,
@@ -210,7 +212,8 @@ export class ResolverBase {
210
212
  viewInput.AuditLogDescription,
211
213
  viewInput.ResultType,
212
214
  userPayload,
213
- viewInput.MaxRows
215
+ viewInput.MaxRows,
216
+ viewInput.StartRow
214
217
  );
215
218
  } catch (err) {
216
219
  console.log(err);
@@ -228,12 +231,12 @@ export class ResolverBase {
228
231
  let params: RunViewGenericParams[] = [];
229
232
  for (const viewInput of viewInputs) {
230
233
  try {
231
- let viewInfo: UserViewEntity | null = null;
234
+ let viewInfo: UserViewEntityExtended | null = null;
232
235
 
233
236
  if (viewInput.ViewName) {
234
237
  viewInfo = this.safeFirstArrayElement(await this.findBy(provider, 'User Views', { Name: viewInput.ViewName }, userPayload.userRecord));
235
238
  } else if (viewInput.ViewID) {
236
- viewInfo = await provider.GetEntityObject<UserViewEntity>('User Views', contextUser);
239
+ viewInfo = await provider.GetEntityObject<UserViewEntityExtended>('User Views', contextUser);
237
240
  await viewInfo.Load(viewInput.ViewID);
238
241
  } else if (viewInput.EntityName) {
239
242
  const entity = md.Entities.find((e) => e.Name === viewInput.EntityName);
@@ -247,7 +250,7 @@ export class ResolverBase {
247
250
  Entity: viewInput.EntityName,
248
251
  EntityID: entity.ID,
249
252
  EntityBaseView: entity.BaseView,
250
- } as UserViewEntity;
253
+ } as UserViewEntityExtended;
251
254
  } else {
252
255
  throw new Error('Unable to determine input type');
253
256
  }
@@ -356,7 +359,7 @@ export class ResolverBase {
356
359
  */
357
360
  protected async RunViewGenericInternal(
358
361
  provider: DatabaseProviderBase,
359
- viewInfo: UserViewEntity,
362
+ viewInfo: UserViewEntityExtended,
360
363
  extraFilter: string,
361
364
  orderBy: string,
362
365
  userSearchString: string,
@@ -370,7 +373,8 @@ export class ResolverBase {
370
373
  auditLogDescription: string | undefined,
371
374
  resultType: string | undefined,
372
375
  userPayload: UserPayload | null,
373
- maxRows: number | undefined
376
+ maxRows: number | undefined,
377
+ startRow: number | undefined
374
378
  ) {
375
379
  try {
376
380
  if (!viewInfo || !userPayload) return null;
@@ -420,6 +424,7 @@ export class ResolverBase {
420
424
  ExcludeDataFromAllPriorViewRuns: excludeDataFromAllPriorViewRuns,
421
425
  IgnoreMaxRows: ignoreMaxRows,
422
426
  MaxRows: maxRows,
427
+ StartRow: startRow,
423
428
  ForceAuditLog: forceAuditLog,
424
429
  AuditLogDescription: auditLogDescription,
425
430
  ResultType: rt,
@@ -4,7 +4,7 @@ import { ResolverBase } from './ResolverBase.js';
4
4
  import { LogError, LogStatus } from '@memberjunction/core';
5
5
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
6
6
  import { GetReadOnlyProvider } from '../util.js';
7
- import { UserViewEntity } from '@memberjunction/core-entities';
7
+ import { UserViewEntityExtended } from '@memberjunction/core-entities';
8
8
 
9
9
  /********************************************************************************
10
10
  * The PURPOSE of this resolver is to provide a generic way to run a view and return the results.
@@ -468,7 +468,7 @@ export class RunViewResolver extends ResolverBase {
468
468
  if (rawData === null)
469
469
  return null;
470
470
 
471
- const viewInfo = super.safeFirstArrayElement<UserViewEntity>(await super.findBy<UserViewEntity>(provider, "User Views", { Name: input.ViewName }, userPayload.userRecord));
471
+ const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { Name: input.ViewName }, userPayload.userRecord));
472
472
  const returnData = this.processRawData(rawData.Results, viewInfo.EntityID);
473
473
  return {
474
474
  Results: returnData,
@@ -495,7 +495,7 @@ export class RunViewResolver extends ResolverBase {
495
495
  if (rawData === null)
496
496
  return null;
497
497
 
498
- const viewInfo = super.safeFirstArrayElement<UserViewEntity>(await super.findBy<UserViewEntity>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
498
+ const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
499
499
  const returnData = this.processRawData(rawData.Results, viewInfo.EntityID);
500
500
  return {
501
501
  Results: returnData,
@@ -613,7 +613,7 @@ export class RunViewResolver extends ResolverBase {
613
613
  const rawData = await super.RunViewByIDGeneric(input, provider, userPayload, pubSub);
614
614
  if (rawData === null) return null;
615
615
 
616
- const viewInfo = super.safeFirstArrayElement<UserViewEntity>(await super.findBy<UserViewEntity>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
616
+ const viewInfo = super.safeFirstArrayElement<UserViewEntityExtended>(await super.findBy<UserViewEntityExtended>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
617
617
  const returnData = this.processRawData(rawData.Results, viewInfo.EntityID);
618
618
  return {
619
619
  Results: returnData,
@@ -1441,6 +1441,9 @@ cycle.`);
1441
1441
  createdAt: q.__mj_CreatedAt,
1442
1442
  updatedAt: q.__mj_UpdatedAt,
1443
1443
  categoryID: q.CategoryID,
1444
+ embeddingVector: q.EmbeddingVector,
1445
+ embeddingModelID: q.EmbeddingModelID,
1446
+ embeddingModelName: q.EmbeddingModel,
1444
1447
  fields: q.Fields.map((f) => {
1445
1448
  return {
1446
1449
  id: f.ID,
@@ -1,7 +1,7 @@
1
1
  import { Resolver, Mutation, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID } from 'type-graphql';
2
2
  import { UserPayload } from '../types.js';
3
3
  import { LogError, LogStatus } from '@memberjunction/core';
4
- import { AIAgentEntity } from '@memberjunction/core-entities';
4
+ import { AIAgentEntityExtended } from '@memberjunction/core-entities';
5
5
  import { AgentRunner } from '@memberjunction/ai-agents';
6
6
  import { ExecuteAgentResult } from '@memberjunction/ai-core-plus';
7
7
  import { AIEngine } from '@memberjunction/aiengine';
@@ -169,12 +169,12 @@ export class RunAIAgentResolver extends ResolverBase {
169
169
  /**
170
170
  * Validate the agent entity
171
171
  */
172
- private async validateAgent(agentId: string, currentUser: any): Promise<AIAgentEntity> {
172
+ private async validateAgent(agentId: string, currentUser: any): Promise<AIAgentEntityExtended> {
173
173
  // Use AIEngine to get cached agent data
174
174
  await AIEngine.Instance.Config(false, currentUser);
175
175
 
176
176
  // Find agent in cached collection
177
- const agentEntity = AIEngine.Instance.Agents.find((a: AIAgentEntity) => a.ID === agentId);
177
+ const agentEntity = AIEngine.Instance.Agents.find((a: AIAgentEntityExtended) => a.ID === agentId);
178
178
 
179
179
  if (!agentEntity) {
180
180
  throw new Error(`AI Agent with ID ${agentId} not found`);