@memberjunction/server 2.49.0 → 2.51.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 (59) hide show
  1. package/README.md +133 -0
  2. package/dist/config.d.ts +264 -1
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +24 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/generated/generated.d.ts +3 -0
  7. package/dist/generated/generated.d.ts.map +1 -1
  8. package/dist/generated/generated.js +532 -517
  9. package/dist/generated/generated.js.map +1 -1
  10. package/dist/generic/ResolverBase.d.ts +1 -1
  11. package/dist/generic/ResolverBase.d.ts.map +1 -1
  12. package/dist/generic/ResolverBase.js +13 -11
  13. package/dist/generic/ResolverBase.js.map +1 -1
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/orm.d.ts.map +1 -1
  19. package/dist/orm.js +6 -0
  20. package/dist/orm.js.map +1 -1
  21. package/dist/resolvers/ActionResolver.d.ts +3 -3
  22. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  23. package/dist/resolvers/ActionResolver.js +13 -10
  24. package/dist/resolvers/ActionResolver.js.map +1 -1
  25. package/dist/resolvers/FileResolver.js +1 -1
  26. package/dist/resolvers/FileResolver.js.map +1 -1
  27. package/dist/resolvers/RunAIAgentResolver.d.ts +49 -8
  28. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  29. package/dist/resolvers/RunAIAgentResolver.js +389 -106
  30. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  31. package/dist/resolvers/SqlLoggingConfigResolver.d.ts +61 -0
  32. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -0
  33. package/dist/resolvers/SqlLoggingConfigResolver.js +477 -0
  34. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -0
  35. package/dist/resolvers/UserFavoriteResolver.d.ts +3 -3
  36. package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
  37. package/dist/resolvers/UserFavoriteResolver.js +6 -6
  38. package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
  39. package/dist/resolvers/UserResolver.d.ts +3 -3
  40. package/dist/resolvers/UserResolver.d.ts.map +1 -1
  41. package/dist/resolvers/UserResolver.js +6 -6
  42. package/dist/resolvers/UserResolver.js.map +1 -1
  43. package/dist/resolvers/UserViewResolver.d.ts +4 -4
  44. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  45. package/dist/resolvers/UserViewResolver.js +6 -6
  46. package/dist/resolvers/UserViewResolver.js.map +1 -1
  47. package/package.json +25 -24
  48. package/src/config.ts +28 -0
  49. package/src/generated/generated.ts +527 -518
  50. package/src/generic/ResolverBase.ts +17 -10
  51. package/src/index.ts +2 -1
  52. package/src/orm.ts +6 -0
  53. package/src/resolvers/ActionResolver.ts +21 -26
  54. package/src/resolvers/FileResolver.ts +1 -1
  55. package/src/resolvers/RunAIAgentResolver.ts +398 -100
  56. package/src/resolvers/SqlLoggingConfigResolver.ts +691 -0
  57. package/src/resolvers/UserFavoriteResolver.ts +6 -6
  58. package/src/resolvers/UserResolver.ts +6 -6
  59. package/src/resolvers/UserViewResolver.ts +6 -6
@@ -14,7 +14,7 @@ import {
14
14
  UserInfo,
15
15
  } from '@memberjunction/core';
16
16
  import { AuditLogEntity, UserViewEntity } from '@memberjunction/core-entities';
17
- import { UserCache } from '@memberjunction/sqlserver-dataprovider';
17
+ import { SQLServerDataProvider, UserCache } from '@memberjunction/sqlserver-dataprovider';
18
18
  import { PubSubEngine } from 'type-graphql';
19
19
  import { GraphQLError } from 'graphql';
20
20
  import sql from 'mssql';
@@ -80,7 +80,7 @@ export class ResolverBase {
80
80
  return dataObjectArray;
81
81
  }
82
82
 
83
- protected async findBy(dataSource: sql.ConnectionPool, entity: string, params: any) {
83
+ protected async findBy(dataSource: sql.ConnectionPool, entity: string, params: any, contextUser: UserInfo) {
84
84
  // build the SQL query based on the params passed in
85
85
  const md = new Metadata();
86
86
  const e = md.Entities.find((e) => e.Name === entity);
@@ -98,15 +98,15 @@ export class ResolverBase {
98
98
  });
99
99
 
100
100
  // ok, now we have a SQL string, run it and return the results
101
- const request = new sql.Request(dataSource);
102
- const result = await request.query(sqlQuery);
103
- return result.recordset;
101
+ // use the SQLServerDataProvider
102
+ const result = await SQLServerDataProvider.ExecuteSQLWithPool(dataSource, sqlQuery, undefined, contextUser);
103
+ return result;
104
104
  }
105
105
 
106
106
  async RunViewByNameGeneric(viewInput: RunViewByNameInput, dataSource: sql.ConnectionPool, userPayload: UserPayload, pubSub: PubSubEngine) {
107
107
  try {
108
108
  const viewInfo: UserViewEntity = this.safeFirstArrayElement(
109
- await this.findBy(dataSource, 'User Views', { Name: viewInput.ViewName })
109
+ await this.findBy(dataSource, 'User Views', { Name: viewInput.ViewName }, userPayload.userRecord)
110
110
  );
111
111
  return this.RunViewGenericInternal(
112
112
  viewInfo,
@@ -134,7 +134,7 @@ export class ResolverBase {
134
134
 
135
135
  async RunViewByIDGeneric(viewInput: RunViewByIDInput, dataSource: sql.ConnectionPool, userPayload: UserPayload, pubSub: PubSubEngine) {
136
136
  try {
137
- const viewInfo: UserViewEntity = this.safeFirstArrayElement(await this.findBy(dataSource, 'User Views', { ID: viewInput.ViewID }));
137
+ const viewInfo: UserViewEntity = this.safeFirstArrayElement(await this.findBy(dataSource, 'User Views', { ID: viewInput.ViewID }, userPayload.userRecord));
138
138
  return this.RunViewGenericInternal(
139
139
  viewInfo,
140
140
  dataSource,
@@ -209,9 +209,9 @@ export class ResolverBase {
209
209
  let viewInfo: UserViewEntity | null = null;
210
210
 
211
211
  if (viewInput.ViewName) {
212
- viewInfo = this.safeFirstArrayElement(await this.findBy(dataSource, 'User Views', { Name: viewInput.ViewName }));
212
+ viewInfo = this.safeFirstArrayElement(await this.findBy(dataSource, 'User Views', { Name: viewInput.ViewName }, userPayload.userRecord));
213
213
  } else if (viewInput.ViewID) {
214
- viewInfo = this.safeFirstArrayElement(await this.findBy(dataSource, 'User Views', { ID: viewInput.ViewID }));
214
+ viewInfo = this.safeFirstArrayElement(await this.findBy(dataSource, 'User Views', { ID: viewInput.ViewID }, userPayload.userRecord));
215
215
  } else if (viewInput.EntityName) {
216
216
  md = md || new Metadata();
217
217
  const entity = md.Entities.find((e) => e.Name === viewInput.EntityName);
@@ -612,7 +612,14 @@ export class ResolverBase {
612
612
  return UserCache.Users.find((u) => u.Email.toLowerCase().trim() === email.toLowerCase().trim());
613
613
  }
614
614
  protected GetUserFromPayload(userPayload: UserPayload): UserInfo | undefined {
615
- if (!userPayload || !userPayload.email) return undefined;
615
+ if (!userPayload)
616
+ return undefined;
617
+
618
+ if (userPayload.userRecord)
619
+ return userPayload.userRecord; // if we have a user record, use that directly
620
+
621
+ if (!userPayload.email)
622
+ return undefined;
616
623
 
617
624
  const md = new Metadata();
618
625
  return UserCache.Users.find((u) => u.Email.toLowerCase().trim() === userPayload.email.toLowerCase().trim());
package/src/index.ts CHANGED
@@ -66,6 +66,7 @@ export * from './resolvers/DatasetResolver.js';
66
66
  export * from './resolvers/EntityRecordNameResolver.js';
67
67
  export * from './resolvers/MergeRecordsResolver.js';
68
68
  export * from './resolvers/ReportResolver.js';
69
+ export * from './resolvers/SqlLoggingConfigResolver.js';
69
70
  export * from './resolvers/SyncRolesUsersResolver.js';
70
71
  export * from './resolvers/SyncDataResolver.js';
71
72
  export * from './resolvers/GetDataResolver.js';
@@ -111,7 +112,7 @@ export const serve = async (resolverPaths: Array<string>, app = createApp(), opt
111
112
  const setupComplete$ = new ReplaySubject(1);
112
113
  await pool.connect();
113
114
 
114
- const config = new SQLServerProviderConfigData(pool, '', mj_core_schema, cacheRefreshInterval);
115
+ const config = new SQLServerProviderConfigData(pool, mj_core_schema, cacheRefreshInterval);
115
116
  await setupSQLServerClient(config); // datasource is already initialized, so we can setup the client right away
116
117
  const md = new Metadata();
117
118
  console.log(`Data Source has been initialized. ${md?.Entities ? md.Entities.length : 0} entities loaded.`);
package/src/orm.ts CHANGED
@@ -10,6 +10,12 @@ const createMSSQLConfig = (): sql.config => {
10
10
  database: dbDatabase,
11
11
  requestTimeout: configInfo.databaseSettings.requestTimeout,
12
12
  connectionTimeout: configInfo.databaseSettings.connectionTimeout,
13
+ pool: {
14
+ max: configInfo.databaseSettings.connectionPool?.max ?? 50,
15
+ min: configInfo.databaseSettings.connectionPool?.min ?? 5,
16
+ idleTimeoutMillis: configInfo.databaseSettings.connectionPool?.idleTimeoutMillis ?? 30000,
17
+ acquireTimeoutMillis: configInfo.databaseSettings.connectionPool?.acquireTimeoutMillis ?? 30000,
18
+ },
13
19
  options: {
14
20
  encrypt: true, // Use encryption
15
21
  enableArithAbort: true,
@@ -2,9 +2,11 @@ import { Resolver, Mutation, Arg, Ctx } from "type-graphql";
2
2
  import { ActionEngineServer } from "@memberjunction/actions";
3
3
  import { EntityActionEngineServer } from "@memberjunction/actions";
4
4
  import { Metadata, UserInfo, BaseEntity, CompositeKey, KeyValuePair, LogError } from "@memberjunction/core";
5
- import { ActionParam } from "@memberjunction/actions-base";
5
+ import { ActionParam, ActionResult } from "@memberjunction/actions-base";
6
6
  import { Field, InputType, ObjectType } from "type-graphql";
7
7
  import { KeyValuePairInput } from "../generic/KeyValuePairInput.js";
8
+ import { AppContext } from "../types.js";
9
+ import { CopyScalarsAndArrays } from "@memberjunction/global";
8
10
 
9
11
  /**
10
12
  * Input type for action parameters
@@ -178,11 +180,14 @@ export class ActionResolver {
178
180
  @Mutation(() => ActionResultOutput)
179
181
  async RunAction(
180
182
  @Arg("input") input: RunActionInput,
181
- @Ctx() ctx: any
183
+ @Ctx() ctx: AppContext
182
184
  ): Promise<ActionResultOutput> {
183
185
  try {
184
186
  // Get the user from context
185
- const user = this.getUserFromContext(ctx);
187
+ const user = ctx.userPayload.userRecord;
188
+ if (!user) {
189
+ throw new Error("User is not authenticated");
190
+ }
186
191
 
187
192
  // Initialize the action engine
188
193
  await ActionEngineServer.Instance.Config(false, user);
@@ -265,7 +270,7 @@ export class ActionResolver {
265
270
  user: UserInfo,
266
271
  params: ActionParam[],
267
272
  skipActionLog?: boolean
268
- ): Promise<any> {
273
+ ): Promise<ActionResult> {
269
274
  return await ActionEngineServer.Instance.RunAction({
270
275
  Action: action,
271
276
  ContextUser: user,
@@ -281,12 +286,15 @@ export class ActionResolver {
281
286
  * @returns The formatted action result
282
287
  * @private
283
288
  */
284
- private createActionResult(result: any): ActionResultOutput {
289
+ private createActionResult(result: ActionResult): ActionResultOutput {
290
+ const x =(result.Params || result.RunParams.Params || [])
291
+ .filter(p => p.Type.trim().toLowerCase() === 'output' ||
292
+ p.Type.trim().toLowerCase() === 'both') ;
285
293
  return {
286
294
  Success: result.Success,
287
295
  Message: result.Message,
288
296
  ResultCode: result.Result?.ResultCode,
289
- ResultData: result.Result ? JSON.stringify(result.Result) : undefined
297
+ ResultData: x && x.length > 0 ? JSON.stringify(CopyScalarsAndArrays(x)) : undefined
290
298
  };
291
299
  }
292
300
 
@@ -314,12 +322,14 @@ export class ActionResolver {
314
322
  @Mutation(() => ActionResultOutput)
315
323
  async RunEntityAction(
316
324
  @Arg("input") input: EntityActionInput,
317
- @Ctx() ctx: any
325
+ @Ctx() ctx: AppContext
318
326
  ): Promise<ActionResultOutput> {
319
327
  try {
320
- // Get the user from context
321
- const user = this.getUserFromContext(ctx);
322
-
328
+ const user = ctx.userPayload.userRecord;
329
+ if (!user) {
330
+ throw new Error("User is not authenticated");
331
+ }
332
+
323
333
  // Initialize the entity action engine
324
334
  await EntityActionEngineServer.Instance.Config(false, user);
325
335
 
@@ -350,22 +360,7 @@ export class ActionResolver {
350
360
  return this.handleError(e);
351
361
  }
352
362
  }
353
-
354
- /**
355
- * Gets the authenticated user from the GraphQL context
356
- * @param ctx The GraphQL context
357
- * @returns The authenticated user
358
- * @throws Error if user is not authenticated
359
- * @private
360
- */
361
- private getUserFromContext(ctx: any): UserInfo {
362
- const user = ctx.user as UserInfo;
363
- if (!user) {
364
- throw new Error("User not authenticated");
365
- }
366
- return user;
367
- }
368
-
363
+
369
364
  /**
370
365
  * Gets an entity action by ID
371
366
  * @param actionID The ID of the entity action
@@ -57,7 +57,7 @@ export class FileResolver extends FileResolverBase {
57
57
  fileEntity.CheckPermissions(EntityPermissionType.Create, true);
58
58
 
59
59
  // Check to see if there's already an object with that name
60
- const [sameName] = await this.findBy(context.dataSource, 'Files', { Name: input.Name, ProviderID: input.ProviderID });
60
+ const [sameName] = await this.findBy(context.dataSource, 'Files', { Name: input.Name, ProviderID: input.ProviderID }, context.userPayload.userRecord);
61
61
  const NameExists = Boolean(sameName);
62
62
 
63
63
  const fileRecord = (await super.CreateFile({ ...input, Status: 'Pending' }, context, pubSub)) as File_;