@memberjunction/server 2.94.0 → 2.96.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 (97) hide show
  1. package/dist/config.d.ts +5 -1
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +2 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/context.d.ts.map +1 -1
  6. package/dist/context.js +4 -0
  7. package/dist/context.js.map +1 -1
  8. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  9. package/dist/resolvers/ActionResolver.js +5 -4
  10. package/dist/resolvers/ActionResolver.js.map +1 -1
  11. package/dist/resolvers/AskSkipResolver.d.ts +8 -3
  12. package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
  13. package/dist/resolvers/AskSkipResolver.js +241 -25
  14. package/dist/resolvers/AskSkipResolver.js.map +1 -1
  15. package/dist/resolvers/CreateQueryResolver.d.ts +2 -2
  16. package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
  17. package/dist/resolvers/CreateQueryResolver.js +25 -17
  18. package/dist/resolvers/CreateQueryResolver.js.map +1 -1
  19. package/dist/resolvers/DatasetResolver.d.ts +2 -2
  20. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  21. package/dist/resolvers/DatasetResolver.js +6 -5
  22. package/dist/resolvers/DatasetResolver.js.map +1 -1
  23. package/dist/resolvers/EntityRecordNameResolver.d.ts +4 -4
  24. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  25. package/dist/resolvers/EntityRecordNameResolver.js +6 -5
  26. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  27. package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
  28. package/dist/resolvers/FileCategoryResolver.js +10 -11
  29. package/dist/resolvers/FileCategoryResolver.js.map +1 -1
  30. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  31. package/dist/resolvers/FileResolver.js +5 -6
  32. package/dist/resolvers/FileResolver.js.map +1 -1
  33. package/dist/resolvers/GetDataContextDataResolver.js +2 -2
  34. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  35. package/dist/resolvers/GetDataResolver.js +3 -3
  36. package/dist/resolvers/GetDataResolver.js.map +1 -1
  37. package/dist/resolvers/MergeRecordsResolver.d.ts +3 -3
  38. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  39. package/dist/resolvers/MergeRecordsResolver.js +8 -7
  40. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  41. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +1 -1
  42. package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
  43. package/dist/resolvers/PotentialDuplicateRecordResolver.js +4 -3
  44. package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
  45. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  46. package/dist/resolvers/QueryResolver.js +19 -14
  47. package/dist/resolvers/QueryResolver.js.map +1 -1
  48. package/dist/resolvers/ReportResolver.d.ts +2 -2
  49. package/dist/resolvers/ReportResolver.d.ts.map +1 -1
  50. package/dist/resolvers/ReportResolver.js +8 -6
  51. package/dist/resolvers/ReportResolver.js.map +1 -1
  52. package/dist/resolvers/RunAIAgentResolver.d.ts +3 -7
  53. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  54. package/dist/resolvers/RunAIAgentResolver.js +8 -5
  55. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  56. package/dist/resolvers/RunAIPromptResolver.d.ts +3 -7
  57. package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
  58. package/dist/resolvers/RunAIPromptResolver.js +10 -8
  59. package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
  60. package/dist/resolvers/RunTemplateResolver.d.ts +2 -4
  61. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  62. package/dist/resolvers/RunTemplateResolver.js +5 -4
  63. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  64. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  65. package/dist/resolvers/SqlLoggingConfigResolver.js +7 -7
  66. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  67. package/dist/resolvers/UserFavoriteResolver.d.ts +3 -4
  68. package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
  69. package/dist/resolvers/UserFavoriteResolver.js +10 -68
  70. package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
  71. package/dist/resolvers/UserViewResolver.d.ts +1 -1
  72. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  73. package/dist/resolvers/UserViewResolver.js +3 -4
  74. package/dist/resolvers/UserViewResolver.js.map +1 -1
  75. package/package.json +39 -39
  76. package/src/config.ts +2 -0
  77. package/src/context.ts +5 -0
  78. package/src/resolvers/ActionResolver.ts +5 -4
  79. package/src/resolvers/AskSkipResolver.ts +300 -29
  80. package/src/resolvers/CreateQueryResolver.ts +28 -17
  81. package/src/resolvers/DatasetResolver.ts +5 -4
  82. package/src/resolvers/EntityRecordNameResolver.ts +8 -6
  83. package/src/resolvers/FileCategoryResolver.ts +9 -10
  84. package/src/resolvers/FileResolver.ts +6 -7
  85. package/src/resolvers/GetDataContextDataResolver.ts +2 -2
  86. package/src/resolvers/GetDataResolver.ts +2 -2
  87. package/src/resolvers/InfoResolver.ts +1 -1
  88. package/src/resolvers/MergeRecordsResolver.ts +7 -6
  89. package/src/resolvers/PotentialDuplicateRecordResolver.ts +3 -2
  90. package/src/resolvers/QueryResolver.ts +22 -15
  91. package/src/resolvers/ReportResolver.ts +9 -6
  92. package/src/resolvers/RunAIAgentResolver.ts +12 -4
  93. package/src/resolvers/RunAIPromptResolver.ts +12 -8
  94. package/src/resolvers/RunTemplateResolver.ts +5 -5
  95. package/src/resolvers/SqlLoggingConfigResolver.ts +7 -6
  96. package/src/resolvers/UserFavoriteResolver.ts +8 -67
  97. package/src/resolvers/UserViewResolver.ts +3 -3
@@ -16,16 +16,15 @@ export class FileResolver extends FileCategoryResolverBase {
16
16
  ) {
17
17
  const key = new CompositeKey();
18
18
  key.LoadFromSingleKeyValuePair('ID', ID);
19
- const provider = GetReadWriteProvider(providers);
19
+ const p = GetReadWriteProvider(providers);
20
20
 
21
- if (!(await this.BeforeDelete(provider, key))) {
21
+ if (!(await this.BeforeDelete(p, key))) {
22
22
  return null;
23
23
  }
24
24
 
25
- const md = new Metadata();
26
25
  const user = this.GetUserFromPayload(userPayload);
27
- const fileEntity = await md.GetEntityObject<FileEntity>('Files', user);
28
- const fileCategoryEntity = await md.GetEntityObject<FileCategoryEntity>('File Categories', user);
26
+ const fileEntity = await p.GetEntityObject<FileEntity>('Files', user);
27
+ const fileCategoryEntity = await p.GetEntityObject<FileCategoryEntity>('File Categories', user);
29
28
 
30
29
  fileEntity.CheckPermissions(EntityPermissionType.Update, true);
31
30
  fileCategoryEntity.CheckPermissions(EntityPermissionType.Delete, true);
@@ -34,7 +33,7 @@ export class FileResolver extends FileCategoryResolverBase {
34
33
  const returnValue = fileCategoryEntity.GetAll();
35
34
 
36
35
  // Any files using the deleted category fall back to its parent
37
- await provider.BeginTransaction();
36
+ await p.BeginTransaction();
38
37
  try {
39
38
  // SHOULD USE BaseEntity for each of these records to ensure object model
40
39
  // is used everywhere - new code below. The below is SLOWER than a single
@@ -60,20 +59,20 @@ export class FileResolver extends FileCategoryResolverBase {
60
59
  // iterate through each of the files in filesResult.Results
61
60
  // and update the CategoryID to fileCategoryEntity.ParentID
62
61
  for (const file of filesResult.Results) {
63
- const fileEntity = await md.GetEntityObject<FileEntity>('Files', user);
62
+ const fileEntity = await p.GetEntityObject<FileEntity>('Files', user);
64
63
  await fileEntity.Load(file.ID);
65
64
  fileEntity.CategoryID = fileCategoryEntity.ParentID;
66
65
  await fileEntity.Save();
67
66
  }
68
67
  }
69
68
  await fileCategoryEntity.Delete(options);
70
- await provider.CommitTransaction();
69
+ await p.CommitTransaction();
71
70
  } catch (error) {
72
- await provider.RollbackTransaction();
71
+ await p.RollbackTransaction();
73
72
  throw error;
74
73
  }
75
74
 
76
- await this.AfterDelete(provider, key); // fire event
75
+ await this.AfterDelete(p, key); // fire event
77
76
  return returnValue;
78
77
  }
79
78
  }
@@ -51,14 +51,13 @@ export class FileResolver extends FileResolverBase {
51
51
  @Ctx() context: AppContext,
52
52
  @PubSub() pubSub: PubSubEngine
53
53
  ) {
54
- const md = new Metadata();
54
+ // Check to see if there's already an object with that name
55
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true})
55
56
  const user = this.GetUserFromPayload(context.userPayload);
56
- const fileEntity = await md.GetEntityObject<FileEntity>('Files', user);
57
- const providerEntity = await md.GetEntityObject<FileStorageProviderEntity>('File Storage Providers', user);
57
+ const fileEntity = await provider.GetEntityObject<FileEntity>('Files', user);
58
+ const providerEntity = await provider.GetEntityObject<FileStorageProviderEntity>('File Storage Providers', user);
58
59
  fileEntity.CheckPermissions(EntityPermissionType.Create, true);
59
60
 
60
- // Check to see if there's already an object with that name
61
- const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true})
62
61
  const [sameName] = await this.findBy(
63
62
  provider,
64
63
  'Files',
@@ -108,7 +107,7 @@ export class FileResolver extends FileResolverBase {
108
107
  @PubSub() pubSub: PubSubEngine
109
108
  ) {
110
109
  // if the name is changing, rename the target object as well
111
- const md = new Metadata();
110
+ const md = GetReadOnlyProvider(context.providers);
112
111
  const user = this.GetUserFromPayload(context.userPayload);
113
112
  const fileEntity = await md.GetEntityObject<FileEntity>('Files', user);
114
113
  fileEntity.CheckPermissions(EntityPermissionType.Update, true);
@@ -136,7 +135,7 @@ export class FileResolver extends FileResolverBase {
136
135
  @Ctx() context: AppContext,
137
136
  @PubSub() pubSub: PubSubEngine
138
137
  ) {
139
- const md = new Metadata();
138
+ const md = GetReadOnlyProvider(context.providers);
140
139
  const userInfo = this.GetUserFromPayload(context.userPayload);
141
140
 
142
141
  const fileEntity = await md.GetEntityObject<FileEntity>('Files', userInfo);
@@ -1,7 +1,7 @@
1
1
  import { Arg, Ctx, Field, ObjectType, Query } from "type-graphql";
2
2
  import { AppContext } from "../types.js";
3
3
  import { DataContext } from "@memberjunction/data-context";
4
- import { GetReadOnlyDataSource } from "../util.js";
4
+ import { GetReadOnlyDataSource, GetReadOnlyProvider } from "../util.js";
5
5
  import { Metadata } from "@memberjunction/core";
6
6
  import { DataContextItemEntity } from "@memberjunction/core-entities";
7
7
 
@@ -53,7 +53,7 @@ export class GetDataContextDataResolver {
53
53
  const ds = GetReadOnlyDataSource(appCtx.dataSources, {
54
54
  allowFallbackToReadWrite: true,
55
55
  })
56
- const md = new Metadata();
56
+ const md = GetReadOnlyProvider(appCtx.providers, {allowFallbackToReadWrite: true});
57
57
  const dciData = await md.GetEntityObject<DataContextItemEntity>("Data Context Items", appCtx.userPayload.userRecord);
58
58
  if (await dciData.Load(DataContextItemID)) {
59
59
  const dci = DataContext.CreateDataContextItem(); // use class factory to get whatever lowest level sub-class is registered
@@ -3,7 +3,7 @@ import { AppContext } from '../types.js';
3
3
  import { LogError, LogStatus, Metadata } from '@memberjunction/core';
4
4
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
5
5
  import { v4 as uuidv4 } from 'uuid';
6
- import { GetReadOnlyDataSource } from '../util.js';
6
+ import { GetReadOnlyDataSource, GetReadOnlyProvider } from '../util.js';
7
7
  import sql from 'mssql';
8
8
 
9
9
  @InputType()
@@ -169,7 +169,7 @@ export class GetDataResolver {
169
169
  @Ctx() context: AppContext
170
170
  ): Promise<SimpleEntityResultType> {
171
171
  try {
172
- const md = new Metadata();
172
+ const md = GetReadOnlyProvider(context.providers);
173
173
  const result = md.Entities.map((e) => {
174
174
  return {
175
175
  ID: e.ID,
@@ -30,7 +30,7 @@ export class Info {
30
30
  }
31
31
 
32
32
  @Resolver(Info)
33
- export class InfoResolver {
33
+ export class InfoResolver {
34
34
  @Public()
35
35
  @Query(() => Info)
36
36
  Info(@Ctx() context: AppContext): Info {
@@ -3,6 +3,7 @@ import { Arg, Ctx, Field, InputType, Int, Mutation, ObjectType, PubSub, PubSubEn
3
3
  import { AppContext } from '../types.js';
4
4
  import { CompositeKeyInputType, CompositeKeyOutputType } from '../generic/KeyInputOutputTypes.js';
5
5
  import { z } from 'zod';
6
+ import { GetReadOnlyProvider, GetReadWriteProvider } from '../util.js';
6
7
 
7
8
  @ObjectType()
8
9
  export class EntityDependencyResult {
@@ -21,11 +22,11 @@ export class EntityDependencyResolver {
21
22
  @Query(() => [EntityDependencyResult])
22
23
  async GetEntityDependencies(
23
24
  @Arg('entityName', () => String) entityName: string,
24
- @Ctx() { dataSource, userPayload }: AppContext,
25
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
25
26
  @PubSub() pubSub: PubSubEngine
26
27
  ) {
27
28
  try {
28
- const md = new Metadata();
29
+ const md = GetReadOnlyProvider(providers);
29
30
  return md.GetEntityDependencies(entityName);
30
31
  } catch (err) {
31
32
  LogError(err);
@@ -57,11 +58,11 @@ export class RecordDependencyResolver {
57
58
  async GetRecordDependencies(
58
59
  @Arg('entityName', () => String) entityName: string,
59
60
  @Arg('CompositeKey', () => CompositeKeyInputType) ckInput: CompositeKeyInputType,
60
- @Ctx() { dataSource, userPayload }: AppContext,
61
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
61
62
  @PubSub() pubSub: PubSubEngine
62
63
  ) {
63
64
  try {
64
- const md = new Metadata();
65
+ const md = GetReadOnlyProvider(providers);
65
66
  const ck = new CompositeKey(ckInput.KeyValuePairs);
66
67
  const result = await md.GetRecordDependencies(entityName, ck);
67
68
 
@@ -165,11 +166,11 @@ export class RecordMergeResolver {
165
166
  @Mutation(() => RecordMergeResult)
166
167
  async MergeRecords(
167
168
  @Arg('request', () => RecordMergeRequest) request: RecordMergeRequest,
168
- @Ctx() { dataSource, userPayload }: AppContext,
169
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
169
170
  @PubSub() pubSub: PubSubEngine
170
171
  ) {
171
172
  try {
172
- const md = new Metadata();
173
+ const md = GetReadWriteProvider(providers);
173
174
  const options = {};
174
175
  const result = await md.MergeRecords(request, userPayload.userRecord, options);
175
176
  return result;
@@ -14,6 +14,7 @@ import { UserCache } from '@memberjunction/sqlserver-dataprovider';
14
14
  import { LoadMistralEmbedding } from '@memberjunction/ai-mistral';
15
15
  import { LoadPineconeVectorDB } from '@memberjunction/ai-vectors-pinecone';
16
16
  import { CompositeKeyInputType, CompositeKeyOutputType, KeyValuePairOutputType } from '../generic/KeyInputOutputTypes.js';
17
+ import { GetReadOnlyProvider } from '../util.js';
17
18
  LoadMistralEmbedding();
18
19
  LoadPineconeVectorDB();
19
20
 
@@ -75,10 +76,10 @@ export class PotentialDuplicateResponseType extends PotentialDuplicateResponse {
75
76
  export class DuplicateRecordResolver {
76
77
  @Query(() => PotentialDuplicateResponseType)
77
78
  async GetRecordDuplicates(
78
- @Ctx() { dataSource, userPayload }: AppContext,
79
+ @Ctx() { dataSource, userPayload, providers }: AppContext,
79
80
  @Arg('params') params: PotentialDuplicateRequestType
80
81
  ): Promise<PotentialDuplicateResponseType> {
81
- const md = new Metadata();
82
+ const md = GetReadOnlyProvider(providers);
82
83
 
83
84
  const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email.trim().toLowerCase());
84
85
  if (!user) {
@@ -1,9 +1,10 @@
1
1
  import { Arg, Ctx, ObjectType, Query, Resolver, Field, Int } from 'type-graphql';
2
- import { RunQuery, QueryInfo } from '@memberjunction/core';
2
+ import { RunQuery, QueryInfo, IRunQueryProvider, IMetadataProvider } from '@memberjunction/core';
3
3
  import { AppContext } from '../types.js';
4
4
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
5
5
  import { GraphQLJSONObject } from 'graphql-type-json';
6
6
  import { Metadata } from '@memberjunction/core';
7
+ import { GetReadOnlyProvider } from '../util.js';
7
8
 
8
9
  @ObjectType()
9
10
  export class RunQueryResultType {
@@ -43,9 +44,7 @@ export class RunQueryResultType {
43
44
 
44
45
  @Resolver()
45
46
  export class RunQueryResolver {
46
- private async findQuery(QueryID: string, QueryName?: string, CategoryID?: string, CategoryPath?: string, refreshMetadataIfNotFound: boolean = false): Promise<QueryInfo | null> {
47
- const md = new Metadata();
48
-
47
+ private async findQuery(md: IMetadataProvider, QueryID: string, QueryName?: string, CategoryID?: string, CategoryPath?: string, refreshMetadataIfNotFound: boolean = false): Promise<QueryInfo | null> {
49
48
  // Filter queries based on provided criteria
50
49
  const queries = md.Queries.filter(q => {
51
50
  if (QueryID) {
@@ -67,7 +66,7 @@ export class RunQueryResolver {
67
66
  if (refreshMetadataIfNotFound) {
68
67
  // If we didn't find the query, refresh metadata and try again
69
68
  await md.Refresh();
70
- return this.findQuery(QueryID, QueryName, CategoryID, CategoryPath, false); // change the refresh flag to false so we don't loop infinitely
69
+ return this.findQuery(md, QueryID, QueryName, CategoryID, CategoryPath, false); // change the refresh flag to false so we don't loop infinitely
71
70
  }
72
71
  else {
73
72
  return null; // No query found and not refreshing metadata
@@ -87,9 +86,11 @@ export class RunQueryResolver {
87
86
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
88
87
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
89
88
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
90
- const runQuery = new RunQuery();
89
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
90
+ const md = provider as unknown as IMetadataProvider;
91
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
91
92
  console.log('GetQueryData called with:', { QueryID, Parameters, MaxRows, StartRow, ForceAuditLog, AuditLogDescription });
92
- const result = await runQuery.RunQuery(
93
+ const result = await rq.RunQuery(
93
94
  {
94
95
  QueryID: QueryID,
95
96
  CategoryID: CategoryID,
@@ -111,7 +112,7 @@ export class RunQueryResolver {
111
112
  let queryName = result.QueryName;
112
113
  if (!queryName) {
113
114
  try {
114
- const queryInfo = await this.findQuery(QueryID, undefined, CategoryID, CategoryPath, true);
115
+ const queryInfo = await this.findQuery(md, QueryID, undefined, CategoryID, CategoryPath, true);
115
116
  if (queryInfo) {
116
117
  queryName = queryInfo.Name;
117
118
  }
@@ -145,8 +146,9 @@ export class RunQueryResolver {
145
146
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
146
147
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
147
148
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
148
- const runQuery = new RunQuery();
149
- const result = await runQuery.RunQuery(
149
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
150
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
151
+ const result = await rq.RunQuery(
150
152
  {
151
153
  QueryName: QueryName,
152
154
  CategoryID: CategoryID,
@@ -185,8 +187,11 @@ export class RunQueryResolver {
185
187
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
186
188
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
187
189
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
188
- const runQuery = new RunQuery();
189
- const result = await runQuery.RunQuery(
190
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
191
+ const md = provider as unknown as IMetadataProvider;
192
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
193
+
194
+ const result = await rq.RunQuery(
190
195
  {
191
196
  QueryID: QueryID,
192
197
  CategoryID: CategoryID,
@@ -203,7 +208,7 @@ export class RunQueryResolver {
203
208
  let queryName = result.QueryName;
204
209
  if (!queryName) {
205
210
  try {
206
- const queryInfo = await this.findQuery(QueryID, undefined, CategoryID, CategoryPath, true);
211
+ const queryInfo = await this.findQuery(md, QueryID, undefined, CategoryID, CategoryPath, true);
207
212
  if (queryInfo) {
208
213
  queryName = queryInfo.Name;
209
214
  }
@@ -238,8 +243,10 @@ export class RunQueryResolver {
238
243
  @Arg('StartRow', () => Int, {nullable: true}) StartRow?: number,
239
244
  @Arg('ForceAuditLog', () => Boolean, {nullable: true}) ForceAuditLog?: boolean,
240
245
  @Arg('AuditLogDescription', () => String, {nullable: true}) AuditLogDescription?: string): Promise<RunQueryResultType> {
241
- const runQuery = new RunQuery();
242
- const result = await runQuery.RunQuery(
246
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
247
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
248
+
249
+ const result = await rq.RunQuery(
243
250
  {
244
251
  QueryName: QueryName,
245
252
  CategoryID: CategoryID,
@@ -1,4 +1,4 @@
1
- import { EntitySaveOptions, Metadata, RunReport } from '@memberjunction/core';
1
+ import { EntitySaveOptions, IRunReportProvider, Metadata, RunReport } from '@memberjunction/core';
2
2
  import { Arg, Ctx, Field, Int, Mutation, ObjectType, Query, Resolver } from 'type-graphql';
3
3
  import { AppContext } from '../types.js';
4
4
  import { ConversationDetailEntity, ReportEntity } from '@memberjunction/core-entities';
@@ -7,6 +7,7 @@ import { DataContext } from '@memberjunction/data-context';
7
7
  import { UserCache } from '@memberjunction/sqlserver-dataprovider';
8
8
  import { z } from 'zod';
9
9
  import mssql from 'mssql';
10
+ import { GetReadOnlyProvider, GetReadWriteProvider } from '../util.js';
10
11
 
11
12
  @ObjectType()
12
13
  export class RunReportResultType {
@@ -47,9 +48,11 @@ export class CreateReportResultType {
47
48
  @Resolver(RunReportResultType)
48
49
  export class ReportResolverExtended {
49
50
  @Query(() => RunReportResultType)
50
- async GetReportData(@Arg('ReportID', () => String) ReportID: string, @Ctx() {}: AppContext): Promise<RunReportResultType> {
51
- const runReport = new RunReport();
52
- const result = await runReport.RunReport({ ReportID: ReportID });
51
+ async GetReportData(@Arg('ReportID', () => String) ReportID: string, @Ctx() context: AppContext): Promise<RunReportResultType> {
52
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true});
53
+ const rp = new RunReport(provider as unknown as IRunReportProvider);
54
+
55
+ const result = await rp.RunReport({ ReportID: ReportID });
53
56
  return {
54
57
  ReportID: ReportID,
55
58
  Success: result.Success,
@@ -66,10 +69,10 @@ export class ReportResolverExtended {
66
69
  @Mutation(() => CreateReportResultType)
67
70
  async CreateReportFromConversationDetailID(
68
71
  @Arg('ConversationDetailID', () => String) ConversationDetailID: string,
69
- @Ctx() { dataSource, userPayload }: AppContext
72
+ @Ctx() { dataSource, userPayload, providers }: AppContext
70
73
  ): Promise<CreateReportResultType> {
71
74
  try {
72
- const md = new Metadata();
75
+ const md = GetReadWriteProvider(providers);
73
76
 
74
77
  const u = UserCache.Users.find((u) => u.Email?.trim().toLowerCase() === userPayload?.email?.trim().toLowerCase());
75
78
  if (!u) throw new Error('Unable to find user');
@@ -1,6 +1,6 @@
1
1
  import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID } from 'type-graphql';
2
- import { UserPayload } from '../types.js';
3
- import { LogError, LogStatus } from '@memberjunction/core';
2
+ import { AppContext, UserPayload } from '../types.js';
3
+ import { DatabaseProviderBase, LogError, LogStatus } from '@memberjunction/core';
4
4
  import { AIAgentEntityExtended } from '@memberjunction/core-entities';
5
5
  import { AgentRunner } from '@memberjunction/ai-agents';
6
6
  import { ExecuteAgentResult } from '@memberjunction/ai-core-plus';
@@ -8,6 +8,7 @@ import { AIEngine } from '@memberjunction/aiengine';
8
8
  import { ResolverBase } from '../generic/ResolverBase.js';
9
9
  import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
10
10
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
11
+ import { GetReadWriteProvider } from '../util.js';
11
12
 
12
13
  @ObjectType()
13
14
  export class AIAgentRunResult {
@@ -304,6 +305,7 @@ export class RunAIAgentResolver extends ResolverBase {
304
305
  * @private
305
306
  */
306
307
  private async executeAIAgent(
308
+ p: DatabaseProviderBase,
307
309
  agentId: string,
308
310
  userPayload: UserPayload,
309
311
  messagesJson: string,
@@ -339,6 +341,8 @@ export class RunAIAgentResolver extends ResolverBase {
339
341
  // Validate agent
340
342
  const agentEntity = await this.validateAgent(agentId, currentUser);
341
343
 
344
+ // @jordanfanapour IMPORTANT TO-DO for various engine classes (via base engine class) and here for AI Agent Runner and for AI Prompt Runner, need to be able to pass in a IMetadataProvider for it to use
345
+ // for multi-user server environments like this one
342
346
  // Create AI agent runner
343
347
  const agentRunner = new AgentRunner();
344
348
 
@@ -453,7 +457,7 @@ export class RunAIAgentResolver extends ResolverBase {
453
457
  @Mutation(() => AIAgentRunResult)
454
458
  async RunAIAgent(
455
459
  @Arg('agentId') agentId: string,
456
- @Ctx() { userPayload }: { userPayload: UserPayload },
460
+ @Ctx() { userPayload, providers }: AppContext,
457
461
  @Arg('messages') messagesJson: string,
458
462
  @Arg('sessionId') sessionId: string,
459
463
  @PubSub() pubSub: PubSubEngine,
@@ -463,7 +467,9 @@ export class RunAIAgentResolver extends ResolverBase {
463
467
  @Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
464
468
  @Arg('configurationId', { nullable: true }) configurationId?: string
465
469
  ): Promise<AIAgentRunResult> {
470
+ const p = GetReadWriteProvider(providers);
466
471
  return this.executeAIAgent(
472
+ p,
467
473
  agentId,
468
474
  userPayload,
469
475
  messagesJson,
@@ -485,7 +491,7 @@ export class RunAIAgentResolver extends ResolverBase {
485
491
  @Query(() => AIAgentRunResult)
486
492
  async RunAIAgentSystemUser(
487
493
  @Arg('agentId') agentId: string,
488
- @Ctx() { userPayload }: { userPayload: UserPayload },
494
+ @Ctx() { userPayload, providers }: AppContext,
489
495
  @Arg('messages') messagesJson: string,
490
496
  @Arg('sessionId') sessionId: string,
491
497
  @PubSub() pubSub: PubSubEngine,
@@ -495,7 +501,9 @@ export class RunAIAgentResolver extends ResolverBase {
495
501
  @Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
496
502
  @Arg('configurationId', { nullable: true }) configurationId?: string
497
503
  ): Promise<AIAgentRunResult> {
504
+ const p = GetReadWriteProvider(providers);
498
505
  return this.executeAIAgent(
506
+ p,
499
507
  agentId,
500
508
  userPayload,
501
509
  messagesJson,
@@ -1,6 +1,6 @@
1
1
  import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, Int } from 'type-graphql';
2
- import { UserPayload } from '../types.js';
3
- import { LogError, LogStatus, Metadata } from '@memberjunction/core';
2
+ import { AppContext, UserPayload } from '../types.js';
3
+ import { DatabaseProviderBase, LogError, LogStatus, Metadata } from '@memberjunction/core';
4
4
  import { AIPromptEntityExtended, AIModelEntityExtended } from '@memberjunction/core-entities';
5
5
  import { AIPromptRunner } from '@memberjunction/ai-prompts';
6
6
  import { AIPromptParams } from '@memberjunction/ai-core-plus';
@@ -9,6 +9,7 @@ import { RequireSystemUser } from '../directives/RequireSystemUser.js';
9
9
  import { AIEngine } from '@memberjunction/aiengine';
10
10
  import { ChatParams, ChatMessage, ChatMessageRole, GetAIAPIKey, BaseLLM } from '@memberjunction/ai';
11
11
  import { MJGlobal } from '@memberjunction/global';
12
+ import { GetReadWriteProvider } from '../util.js';
12
13
 
13
14
  @ObjectType()
14
15
  export class AIPromptRunResult {
@@ -87,6 +88,7 @@ export class RunAIPromptResolver extends ResolverBase {
87
88
  * @private
88
89
  */
89
90
  private async executeAIPrompt(
91
+ p: DatabaseProviderBase,
90
92
  promptId: string,
91
93
  userPayload: UserPayload,
92
94
  data?: string,
@@ -152,11 +154,9 @@ export class RunAIPromptResolver extends ResolverBase {
152
154
  executionTimeMs: Date.now() - startTime
153
155
  };
154
156
  }
155
-
156
- const md = new Metadata();
157
-
157
+
158
158
  // Load the AI prompt entity
159
- const promptEntity = await md.GetEntityObject<AIPromptEntityExtended>('AI Prompts', currentUser);
159
+ const promptEntity = await p.GetEntityObject<AIPromptEntityExtended>('AI Prompts', currentUser);
160
160
  await promptEntity.Load(promptId);
161
161
 
162
162
  if (!promptEntity.IsSaved) {
@@ -283,7 +283,7 @@ export class RunAIPromptResolver extends ResolverBase {
283
283
  @Mutation(() => AIPromptRunResult)
284
284
  async RunAIPrompt(
285
285
  @Arg('promptId') promptId: string,
286
- @Ctx() { userPayload }: { userPayload: UserPayload },
286
+ @Ctx() { userPayload, providers }: AppContext,
287
287
  @Arg('data', { nullable: true }) data?: string,
288
288
  @Arg('overrideModelId', { nullable: true }) overrideModelId?: string,
289
289
  @Arg('overrideVendorId', { nullable: true }) overrideVendorId?: string,
@@ -305,7 +305,9 @@ export class RunAIPromptResolver extends ResolverBase {
305
305
  @Arg('rerunFromPromptRunID', { nullable: true }) rerunFromPromptRunID?: string,
306
306
  @Arg('systemPromptOverride', { nullable: true }) systemPromptOverride?: string
307
307
  ): Promise<AIPromptRunResult> {
308
+ const p = GetReadWriteProvider(providers);
308
309
  return this.executeAIPrompt(
310
+ p,
309
311
  promptId,
310
312
  userPayload,
311
313
  data,
@@ -339,7 +341,7 @@ export class RunAIPromptResolver extends ResolverBase {
339
341
  @Query(() => AIPromptRunResult)
340
342
  async RunAIPromptSystemUser(
341
343
  @Arg('promptId') promptId: string,
342
- @Ctx() { userPayload }: { userPayload: UserPayload },
344
+ @Ctx() { userPayload, providers }: AppContext,
343
345
  @Arg('data', { nullable: true }) data?: string,
344
346
  @Arg('overrideModelId', { nullable: true }) overrideModelId?: string,
345
347
  @Arg('overrideVendorId', { nullable: true }) overrideVendorId?: string,
@@ -361,7 +363,9 @@ export class RunAIPromptResolver extends ResolverBase {
361
363
  @Arg('rerunFromPromptRunID', { nullable: true }) rerunFromPromptRunID?: string,
362
364
  @Arg('systemPromptOverride', { nullable: true }) systemPromptOverride?: string
363
365
  ): Promise<AIPromptRunResult> {
366
+ const p = GetReadWriteProvider(providers);
364
367
  return this.executeAIPrompt(
368
+ p,
365
369
  promptId,
366
370
  userPayload,
367
371
  data,
@@ -1,10 +1,11 @@
1
1
  import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
2
- import { UserPayload } from '../types.js';
2
+ import { AppContext, UserPayload } from '../types.js';
3
3
  import { LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
4
4
  import { TemplateContentEntity } from '@memberjunction/core-entities';
5
5
  import { TemplateEngineServer } from '@memberjunction/templates';
6
6
  import { TemplateEntityExtended } from '@memberjunction/templates-base-types';
7
7
  import { ResolverBase } from '../generic/ResolverBase.js';
8
+ import { GetReadWriteProvider } from '../util.js';
8
9
 
9
10
  @ObjectType()
10
11
  export class TemplateRunResult {
@@ -26,7 +27,7 @@ export class RunTemplateResolver extends ResolverBase {
26
27
  @Mutation(() => TemplateRunResult)
27
28
  async RunTemplate(
28
29
  @Arg('templateId') templateId: string,
29
- @Ctx() { userPayload }: { userPayload: UserPayload },
30
+ @Ctx() { userPayload, providers }: AppContext,
30
31
  @Arg('contextData', { nullable: true }) contextData?: string
31
32
  ): Promise<TemplateRunResult> {
32
33
  const startTime = Date.now();
@@ -58,10 +59,9 @@ export class RunTemplateResolver extends ResolverBase {
58
59
  };
59
60
  }
60
61
 
61
- const md = new Metadata();
62
-
62
+ const p = GetReadWriteProvider(providers);
63
63
  // Load the template entity
64
- const templateEntity = await md.GetEntityObject<TemplateEntityExtended>('Templates', currentUser);
64
+ const templateEntity = await p.GetEntityObject<TemplateEntityExtended>('Templates', currentUser);
65
65
  await templateEntity.Load(templateId);
66
66
 
67
67
  if (!templateEntity.IsSaved) {
@@ -8,6 +8,7 @@ import * as path from 'path';
8
8
  import * as fs from 'fs/promises';
9
9
  import { loadConfig } from '../config.js';
10
10
  import { ResolverBase } from '../generic/ResolverBase.js';
11
+ import { GetReadOnlyProvider } from '../util.js';
11
12
 
12
13
  /**
13
14
  * Configuration options for SQL logging sessions.
@@ -279,7 +280,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
279
280
  async sqlLoggingConfig(@Ctx() context: AppContext): Promise<SqlLoggingConfig> {
280
281
  await this.checkOwnerAccess(context);
281
282
  const config = await loadConfig();
282
- const provider = Metadata.Provider as SQLServerDataProvider;
283
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
283
284
  const activeSessions = provider.GetActiveSqlLoggingSessions();
284
285
 
285
286
  return {
@@ -334,7 +335,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
334
335
  @Query(() => [SqlLoggingSession])
335
336
  async activeSqlLoggingSessions(@Ctx() context: AppContext): Promise<SqlLoggingSession[]> {
336
337
  await this.checkOwnerAccess(context);
337
- const provider = Metadata.Provider as SQLServerDataProvider;
338
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
338
339
  const sessions = provider.GetActiveSqlLoggingSessions();
339
340
 
340
341
  return sessions.map(session => ({
@@ -399,7 +400,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
399
400
  }
400
401
 
401
402
  // Check max active sessions
402
- const provider = Metadata.Provider as SQLServerDataProvider;
403
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
403
404
  const activeSessions = provider.GetActiveSqlLoggingSessions();
404
405
  if (activeSessions.length >= (config.sqlLogging.maxActiveSessions ?? 5)) {
405
406
  throw new Error(`Maximum number of active SQL logging sessions (${config.sqlLogging.maxActiveSessions}) reached`);
@@ -480,7 +481,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
480
481
  @Ctx() context: AppContext
481
482
  ): Promise<boolean> {
482
483
  await this.checkOwnerAccess(context);
483
- const provider = Metadata.Provider as SQLServerDataProvider;
484
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
484
485
 
485
486
  // Get the actual session from the private map to call dispose
486
487
  const sessionMap = (provider as any)._sqlLoggingSessions as Map<string, any>;
@@ -517,7 +518,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
517
518
  @Mutation(() => Boolean)
518
519
  async stopAllSqlLogging(@Ctx() context: AppContext): Promise<boolean> {
519
520
  await this.checkOwnerAccess(context);
520
- const provider = Metadata.Provider as SQLServerDataProvider;
521
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
521
522
  await provider.DisposeAllSqlLoggingSessions();
522
523
  return true;
523
524
  }
@@ -607,7 +608,7 @@ export class SqlLoggingConfigResolver extends ResolverBase {
607
608
  }
608
609
 
609
610
  // Find the session
610
- const provider = Metadata.Provider as SQLServerDataProvider;
611
+ const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true}) as SQLServerDataProvider;
611
612
  const sessions = provider.GetActiveSqlLoggingSessions();
612
613
  const session = sessions.find(s => s.id === sessionId);
613
614