@memberjunction/server 2.35.0 → 2.36.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 (52) hide show
  1. package/README.md +15 -1
  2. package/dist/config.d.ts +69 -1
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +11 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/generated/generated.d.ts +15 -12
  7. package/dist/generated/generated.d.ts.map +1 -1
  8. package/dist/generated/generated.js +73 -58
  9. package/dist/generated/generated.js.map +1 -1
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +41 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/resolvers/AskSkipResolver.d.ts +60 -5
  15. package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
  16. package/dist/resolvers/AskSkipResolver.js +587 -31
  17. package/dist/resolvers/AskSkipResolver.js.map +1 -1
  18. package/dist/rest/EntityCRUDHandler.d.ts +29 -0
  19. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -0
  20. package/dist/rest/EntityCRUDHandler.js +197 -0
  21. package/dist/rest/EntityCRUDHandler.js.map +1 -0
  22. package/dist/rest/RESTEndpointHandler.d.ts +41 -0
  23. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -0
  24. package/dist/rest/RESTEndpointHandler.js +537 -0
  25. package/dist/rest/RESTEndpointHandler.js.map +1 -0
  26. package/dist/rest/ViewOperationsHandler.d.ts +21 -0
  27. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -0
  28. package/dist/rest/ViewOperationsHandler.js +144 -0
  29. package/dist/rest/ViewOperationsHandler.js.map +1 -0
  30. package/dist/rest/index.d.ts +5 -0
  31. package/dist/rest/index.d.ts.map +1 -0
  32. package/dist/rest/index.js +5 -0
  33. package/dist/rest/index.js.map +1 -0
  34. package/dist/rest/setupRESTEndpoints.d.ts +12 -0
  35. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -0
  36. package/dist/rest/setupRESTEndpoints.js +27 -0
  37. package/dist/rest/setupRESTEndpoints.js.map +1 -0
  38. package/dist/scheduler/LearningCycleScheduler.d.ts +44 -0
  39. package/dist/scheduler/LearningCycleScheduler.d.ts.map +1 -0
  40. package/dist/scheduler/LearningCycleScheduler.js +188 -0
  41. package/dist/scheduler/LearningCycleScheduler.js.map +1 -0
  42. package/package.json +24 -26
  43. package/src/config.ts +15 -1
  44. package/src/generated/generated.ts +53 -44
  45. package/src/index.ts +56 -1
  46. package/src/resolvers/AskSkipResolver.ts +787 -51
  47. package/src/rest/EntityCRUDHandler.ts +279 -0
  48. package/src/rest/RESTEndpointHandler.ts +834 -0
  49. package/src/rest/ViewOperationsHandler.ts +207 -0
  50. package/src/rest/index.ts +4 -0
  51. package/src/rest/setupRESTEndpoints.ts +89 -0
  52. package/src/scheduler/LearningCycleScheduler.ts +312 -0
@@ -1402,13 +1402,13 @@ export class AIAgentNote_ {
1402
1402
  @MaxLength(16)
1403
1403
  ID: string;
1404
1404
 
1405
- @Field({nullable: true})
1405
+ @Field()
1406
1406
  @MaxLength(16)
1407
- AgentID?: string;
1407
+ AgentID: string;
1408
1408
 
1409
- @Field({nullable: true})
1409
+ @Field()
1410
1410
  @MaxLength(16)
1411
- AgentNoteTypeID?: string;
1411
+ AgentNoteTypeID: string;
1412
1412
 
1413
1413
  @Field({nullable: true})
1414
1414
  Note?: string;
@@ -1449,10 +1449,10 @@ export class AIAgentNote_ {
1449
1449
  @InputType()
1450
1450
  export class CreateAIAgentNoteInput {
1451
1451
  @Field({ nullable: true })
1452
- AgentID: string | null;
1452
+ AgentID?: string;
1453
1453
 
1454
1454
  @Field({ nullable: true })
1455
- AgentNoteTypeID: string | null;
1455
+ AgentNoteTypeID?: string;
1456
1456
 
1457
1457
  @Field({ nullable: true })
1458
1458
  Note: string | null;
@@ -1474,10 +1474,10 @@ export class UpdateAIAgentNoteInput {
1474
1474
  ID: string;
1475
1475
 
1476
1476
  @Field({ nullable: true })
1477
- AgentID?: string | null;
1477
+ AgentID?: string;
1478
1478
 
1479
1479
  @Field({ nullable: true })
1480
- AgentNoteTypeID?: string | null;
1480
+ AgentNoteTypeID?: string;
1481
1481
 
1482
1482
  @Field({ nullable: true })
1483
1483
  Note?: string | null;
@@ -6271,9 +6271,6 @@ export class User_ {
6271
6271
  @Field(() => [UserFavorite_])
6272
6272
  UserFavorites_UserIDArray: UserFavorite_[]; // Link to UserFavorites
6273
6273
 
6274
- @Field(() => [ResourceLink_])
6275
- ResourceLinks_UserIDArray: ResourceLink_[]; // Link to ResourceLinks
6276
-
6277
6274
  @Field(() => [ListCategory_])
6278
6275
  ListCategories_UserIDArray: ListCategory_[]; // Link to ListCategories
6279
6276
 
@@ -6283,21 +6280,24 @@ export class User_ {
6283
6280
  @Field(() => [AIAgentRequest_])
6284
6281
  AIAgentRequests_ResponseByUserIDArray: AIAgentRequest_[]; // Link to AIAgentRequests
6285
6282
 
6283
+ @Field(() => [ResourceLink_])
6284
+ ResourceLinks_UserIDArray: ResourceLink_[]; // Link to ResourceLinks
6285
+
6286
6286
  @Field(() => [ReportUserState_])
6287
6287
  MJ_ReportUserStates_UserIDArray: ReportUserState_[]; // Link to MJ_ReportUserStates
6288
6288
 
6289
6289
  @Field(() => [AIAgentNote_])
6290
6290
  AIAgentNotes_UserIDArray: AIAgentNote_[]; // Link to AIAgentNotes
6291
6291
 
6292
- @Field(() => [ResourcePermission_])
6293
- ResourcePermissions_UserIDArray: ResourcePermission_[]; // Link to ResourcePermissions
6294
-
6295
6292
  @Field(() => [AIAgentRequest_])
6296
6293
  AIAgentRequests_RequestForUserIDArray: AIAgentRequest_[]; // Link to AIAgentRequests
6297
6294
 
6298
6295
  @Field(() => [ConversationDetail_])
6299
6296
  ConversationDetails_UserIDArray: ConversationDetail_[]; // Link to ConversationDetails
6300
6297
 
6298
+ @Field(() => [ResourcePermission_])
6299
+ ResourcePermissions_UserIDArray: ResourcePermission_[]; // Link to ResourcePermissions
6300
+
6301
6301
  }
6302
6302
 
6303
6303
  //****************************************************************************
@@ -6720,15 +6720,6 @@ export class UserResolverBase extends ResolverBase {
6720
6720
  return result;
6721
6721
  }
6722
6722
 
6723
- @FieldResolver(() => [ResourceLink_])
6724
- async ResourceLinks_UserIDArray(@Root() user_: User_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
6725
- this.CheckUserReadPermissions('Resource Links', userPayload);
6726
- const dataSource = GetReadOnlyDataSource(dataSources, { allowFallbackToReadWrite: true });
6727
- const sSQL = `SELECT * FROM [${Metadata.Provider.ConfigData.MJCoreSchemaName}].[vwResourceLinks] WHERE [UserID]='${user_.ID}' ` + this.getRowLevelSecurityWhereClause('Resource Links', userPayload, EntityPermissionType.Read, 'AND');
6728
- const result = this.ArrayMapFieldNamesToCodeNames('Resource Links', await dataSource.query(sSQL));
6729
- return result;
6730
- }
6731
-
6732
6723
  @FieldResolver(() => [ListCategory_])
6733
6724
  async ListCategories_UserIDArray(@Root() user_: User_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
6734
6725
  this.CheckUserReadPermissions('List Categories', userPayload);
@@ -6756,6 +6747,15 @@ export class UserResolverBase extends ResolverBase {
6756
6747
  return result;
6757
6748
  }
6758
6749
 
6750
+ @FieldResolver(() => [ResourceLink_])
6751
+ async ResourceLinks_UserIDArray(@Root() user_: User_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
6752
+ this.CheckUserReadPermissions('Resource Links', userPayload);
6753
+ const dataSource = GetReadOnlyDataSource(dataSources, { allowFallbackToReadWrite: true });
6754
+ const sSQL = `SELECT * FROM [${Metadata.Provider.ConfigData.MJCoreSchemaName}].[vwResourceLinks] WHERE [UserID]='${user_.ID}' ` + this.getRowLevelSecurityWhereClause('Resource Links', userPayload, EntityPermissionType.Read, 'AND');
6755
+ const result = this.ArrayMapFieldNamesToCodeNames('Resource Links', await dataSource.query(sSQL));
6756
+ return result;
6757
+ }
6758
+
6759
6759
  @FieldResolver(() => [ReportUserState_])
6760
6760
  async MJ_ReportUserStates_UserIDArray(@Root() user_: User_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
6761
6761
  this.CheckUserReadPermissions('MJ: Report User States', userPayload);
@@ -6774,15 +6774,6 @@ export class UserResolverBase extends ResolverBase {
6774
6774
  return result;
6775
6775
  }
6776
6776
 
6777
- @FieldResolver(() => [ResourcePermission_])
6778
- async ResourcePermissions_UserIDArray(@Root() user_: User_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
6779
- this.CheckUserReadPermissions('Resource Permissions', userPayload);
6780
- const dataSource = GetReadOnlyDataSource(dataSources, { allowFallbackToReadWrite: true });
6781
- const sSQL = `SELECT * FROM [${Metadata.Provider.ConfigData.MJCoreSchemaName}].[vwResourcePermissions] WHERE [UserID]='${user_.ID}' ` + this.getRowLevelSecurityWhereClause('Resource Permissions', userPayload, EntityPermissionType.Read, 'AND');
6782
- const result = this.ArrayMapFieldNamesToCodeNames('Resource Permissions', await dataSource.query(sSQL));
6783
- return result;
6784
- }
6785
-
6786
6777
  @FieldResolver(() => [AIAgentRequest_])
6787
6778
  async AIAgentRequests_RequestForUserIDArray(@Root() user_: User_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
6788
6779
  this.CheckUserReadPermissions('AI Agent Requests', userPayload);
@@ -6801,6 +6792,15 @@ export class UserResolverBase extends ResolverBase {
6801
6792
  return result;
6802
6793
  }
6803
6794
 
6795
+ @FieldResolver(() => [ResourcePermission_])
6796
+ async ResourcePermissions_UserIDArray(@Root() user_: User_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
6797
+ this.CheckUserReadPermissions('Resource Permissions', userPayload);
6798
+ const dataSource = GetReadOnlyDataSource(dataSources, { allowFallbackToReadWrite: true });
6799
+ const sSQL = `SELECT * FROM [${Metadata.Provider.ConfigData.MJCoreSchemaName}].[vwResourcePermissions] WHERE [UserID]='${user_.ID}' ` + this.getRowLevelSecurityWhereClause('Resource Permissions', userPayload, EntityPermissionType.Read, 'AND');
6800
+ const result = this.ArrayMapFieldNamesToCodeNames('Resource Permissions', await dataSource.query(sSQL));
6801
+ return result;
6802
+ }
6803
+
6804
6804
  @Mutation(() => User_)
6805
6805
  async CreateUser(
6806
6806
  @Arg('input', () => CreateUserInput) input: CreateUserInput,
@@ -12023,6 +12023,9 @@ export class AIModel_ {
12023
12023
  @MaxLength(200)
12024
12024
  SupportedResponseFormats: string;
12025
12025
 
12026
+ @Field(() => Boolean, {description: `Specifies if the model supports the concept of an effort level. For example, for a reasoning model, the options often include low, medium, and high.`})
12027
+ SupportsEffortLevel: boolean;
12028
+
12026
12029
  @Field()
12027
12030
  @MaxLength(100)
12028
12031
  AIModelType: string;
@@ -12039,15 +12042,15 @@ export class AIModel_ {
12039
12042
  @Field(() => [VectorIndex_])
12040
12043
  VectorIndexes_EmbeddingModelIDArray: VectorIndex_[]; // Link to VectorIndexes
12041
12044
 
12042
- @Field(() => [ContentType_])
12043
- ContentTypes_AIModelIDArray: ContentType_[]; // Link to ContentTypes
12044
-
12045
12045
  @Field(() => [AIResultCache_])
12046
12046
  AIResultCache_AIModelIDArray: AIResultCache_[]; // Link to AIResultCache
12047
12047
 
12048
12048
  @Field(() => [EntityAIAction_])
12049
12049
  EntityAIActions_AIModelIDArray: EntityAIAction_[]; // Link to EntityAIActions
12050
12050
 
12051
+ @Field(() => [ContentType_])
12052
+ ContentTypes_AIModelIDArray: ContentType_[]; // Link to ContentTypes
12053
+
12051
12054
  @Field(() => [AIAgentModel_])
12052
12055
  AIAgentModels_ModelIDArray: AIAgentModel_[]; // Link to AIAgentModels
12053
12056
 
@@ -12102,6 +12105,9 @@ export class CreateAIModelInput {
12102
12105
 
12103
12106
  @Field({ nullable: true })
12104
12107
  SupportedResponseFormats?: string;
12108
+
12109
+ @Field(() => Boolean, { nullable: true })
12110
+ SupportsEffortLevel?: boolean;
12105
12111
  }
12106
12112
 
12107
12113
 
@@ -12155,6 +12161,9 @@ export class UpdateAIModelInput {
12155
12161
  @Field({ nullable: true })
12156
12162
  SupportedResponseFormats?: string;
12157
12163
 
12164
+ @Field(() => Boolean, { nullable: true })
12165
+ SupportsEffortLevel?: boolean;
12166
+
12158
12167
  @Field(() => [KeyValuePairInput], { nullable: true })
12159
12168
  OldValues___?: KeyValuePairInput[];
12160
12169
  }
@@ -12260,15 +12269,6 @@ export class AIModelResolver extends ResolverBase {
12260
12269
  return result;
12261
12270
  }
12262
12271
 
12263
- @FieldResolver(() => [ContentType_])
12264
- async ContentTypes_AIModelIDArray(@Root() aimodel_: AIModel_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
12265
- this.CheckUserReadPermissions('Content Types', userPayload);
12266
- const dataSource = GetReadOnlyDataSource(dataSources, { allowFallbackToReadWrite: true });
12267
- const sSQL = `SELECT * FROM [${Metadata.Provider.ConfigData.MJCoreSchemaName}].[vwContentTypes] WHERE [AIModelID]='${aimodel_.ID}' ` + this.getRowLevelSecurityWhereClause('Content Types', userPayload, EntityPermissionType.Read, 'AND');
12268
- const result = this.ArrayMapFieldNamesToCodeNames('Content Types', await dataSource.query(sSQL));
12269
- return result;
12270
- }
12271
-
12272
12272
  @FieldResolver(() => [AIResultCache_])
12273
12273
  async AIResultCache_AIModelIDArray(@Root() aimodel_: AIModel_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
12274
12274
  this.CheckUserReadPermissions('AI Result Cache', userPayload);
@@ -12287,6 +12287,15 @@ export class AIModelResolver extends ResolverBase {
12287
12287
  return result;
12288
12288
  }
12289
12289
 
12290
+ @FieldResolver(() => [ContentType_])
12291
+ async ContentTypes_AIModelIDArray(@Root() aimodel_: AIModel_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
12292
+ this.CheckUserReadPermissions('Content Types', userPayload);
12293
+ const dataSource = GetReadOnlyDataSource(dataSources, { allowFallbackToReadWrite: true });
12294
+ const sSQL = `SELECT * FROM [${Metadata.Provider.ConfigData.MJCoreSchemaName}].[vwContentTypes] WHERE [AIModelID]='${aimodel_.ID}' ` + this.getRowLevelSecurityWhereClause('Content Types', userPayload, EntityPermissionType.Read, 'AND');
12295
+ const result = this.ArrayMapFieldNamesToCodeNames('Content Types', await dataSource.query(sSQL));
12296
+ return result;
12297
+ }
12298
+
12290
12299
  @FieldResolver(() => [AIAgentModel_])
12291
12300
  async AIAgentModels_ModelIDArray(@Root() aimodel_: AIModel_, @Ctx() { dataSources, userPayload }: AppContext, @PubSub() pubSub: PubSubEngine) {
12292
12301
  this.CheckUserReadPermissions('AI Agent Models', userPayload);
package/src/index.ts CHANGED
@@ -21,10 +21,11 @@ import { BuildSchemaOptions, buildSchemaSync, GraphQLTimestamp } from 'type-grap
21
21
  import { DataSource } from 'typeorm';
22
22
  import { WebSocketServer } from 'ws';
23
23
  import buildApolloServer from './apolloServer/index.js';
24
- import { configInfo, dbDatabase, dbHost, dbPort, dbUsername, graphqlPort, graphqlRootPath, mj_core_schema, websiteRunFromPackage } from './config.js';
24
+ import { configInfo, dbDatabase, dbHost, dbPort, dbUsername, graphqlPort, graphqlRootPath, mj_core_schema, websiteRunFromPackage, RESTApiOptions } from './config.js';
25
25
  import { contextFunction, getUserPayload } from './context.js';
26
26
  import { requireSystemUserDirective, publicDirective } from './directives/index.js';
27
27
  import orm from './orm.js';
28
+ import { setupRESTEndpoints } from './rest/setupRESTEndpoints.js';
28
29
 
29
30
  import { LoadActionEntityServer } from '@memberjunction/actions';
30
31
  LoadActionEntityServer(); // prevent tree shaking for this dynamic module
@@ -76,6 +77,7 @@ import { DataSourceInfo, raiseEvent } from './types.js';
76
77
 
77
78
  export type MJServerOptions = {
78
79
  onBeforeServe?: () => void | Promise<void>;
80
+ restApiOptions?: Partial<RESTApiOptions>; // Options for REST API configuration
79
81
  };
80
82
 
81
83
  const localPath = (p: string) => {
@@ -225,6 +227,59 @@ export const serve = async (resolverPaths: Array<string>, app = createApp(), opt
225
227
  }),
226
228
  })
227
229
  );
230
+
231
+ // Setup REST API endpoints
232
+ const authMiddleware = async (req, res, next) => {
233
+ try {
234
+ const sessionIdRaw = req.headers['x-session-id'];
235
+ const requestDomain = new URL(req.headers.origin || '').hostname;
236
+ const sessionId = sessionIdRaw ? sessionIdRaw.toString() : '';
237
+ const bearerToken = req.headers.authorization ?? '';
238
+ const apiKey = String(req.headers['x-mj-api-key']);
239
+
240
+ const userPayload = await getUserPayload(bearerToken, sessionId, dataSources, requestDomain, apiKey);
241
+ if (!userPayload) {
242
+ return res.status(401).json({ error: 'Invalid token' });
243
+ }
244
+
245
+ req.user = userPayload;
246
+ next();
247
+ } catch (error) {
248
+ console.error('Auth error:', error);
249
+ return res.status(401).json({ error: 'Authentication failed' });
250
+ }
251
+ };
252
+
253
+ // Get REST API configuration from the config file
254
+ const restApiConfig: RESTApiOptions = {
255
+ enabled: configInfo.restApiOptions?.enabled ?? true,
256
+ includeEntities: configInfo.restApiOptions?.includeEntities,
257
+ excludeEntities: configInfo.restApiOptions?.excludeEntities
258
+ };
259
+
260
+ // Apply options from server options if provided (these override the config file)
261
+ if (options?.restApiOptions) {
262
+ Object.assign(restApiConfig, options.restApiOptions);
263
+ }
264
+
265
+ // Get REST API configuration from environment variables if present (env vars override everything)
266
+ if (process.env.MJ_REST_API_ENABLED !== undefined) {
267
+ restApiConfig.enabled = process.env.MJ_REST_API_ENABLED === 'true';
268
+ if (restApiConfig.enabled) {
269
+ console.log('REST API is enabled via environment variable');
270
+ }
271
+ }
272
+
273
+ if (process.env.MJ_REST_API_INCLUDE_ENTITIES) {
274
+ restApiConfig.includeEntities = process.env.MJ_REST_API_INCLUDE_ENTITIES.split(',').map(e => e.trim());
275
+ }
276
+
277
+ if (process.env.MJ_REST_API_EXCLUDE_ENTITIES) {
278
+ restApiConfig.excludeEntities = process.env.MJ_REST_API_EXCLUDE_ENTITIES.split(',').map(e => e.trim());
279
+ }
280
+
281
+ // Set up REST endpoints with the configured options and auth middleware
282
+ setupRESTEndpoints(app, restApiConfig, authMiddleware);
228
283
 
229
284
  if (options?.onBeforeServe) {
230
285
  await Promise.resolve(options.onBeforeServe());