@memberjunction/server 2.127.0 → 2.129.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 (56) hide show
  1. package/dist/agents/skip-sdk.d.ts.map +1 -1
  2. package/dist/agents/skip-sdk.js +5 -1
  3. package/dist/agents/skip-sdk.js.map +1 -1
  4. package/dist/auth/index.d.ts.map +1 -1
  5. package/dist/auth/index.js +2 -3
  6. package/dist/auth/index.js.map +1 -1
  7. package/dist/config.d.ts +33 -0
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +5 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/generated/generated.d.ts +9533 -9130
  12. package/dist/generated/generated.d.ts.map +1 -1
  13. package/dist/generated/generated.js +49272 -46753
  14. package/dist/generated/generated.js.map +1 -1
  15. package/dist/generic/ResolverBase.d.ts +4 -2
  16. package/dist/generic/ResolverBase.d.ts.map +1 -1
  17. package/dist/generic/ResolverBase.js +122 -10
  18. package/dist/generic/ResolverBase.js.map +1 -1
  19. package/dist/generic/RunViewResolver.d.ts +22 -0
  20. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  21. package/dist/generic/RunViewResolver.js +171 -0
  22. package/dist/generic/RunViewResolver.js.map +1 -1
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +20 -4
  26. package/dist/index.js.map +1 -1
  27. package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
  28. package/dist/resolvers/AskSkipResolver.js +5 -1
  29. package/dist/resolvers/AskSkipResolver.js.map +1 -1
  30. package/dist/resolvers/QueryResolver.d.ts +37 -0
  31. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  32. package/dist/resolvers/QueryResolver.js +304 -2
  33. package/dist/resolvers/QueryResolver.js.map +1 -1
  34. package/dist/resolvers/SyncDataResolver.js +5 -5
  35. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  36. package/dist/resolvers/TelemetryResolver.d.ts +120 -0
  37. package/dist/resolvers/TelemetryResolver.d.ts.map +1 -0
  38. package/dist/resolvers/TelemetryResolver.js +731 -0
  39. package/dist/resolvers/TelemetryResolver.js.map +1 -0
  40. package/dist/services/TaskOrchestrator.d.ts.map +1 -1
  41. package/dist/services/TaskOrchestrator.js.map +1 -1
  42. package/package.json +43 -42
  43. package/src/agents/skip-sdk.ts +5 -1
  44. package/src/auth/index.ts +2 -3
  45. package/src/config.ts +9 -0
  46. package/src/generated/generated.ts +28162 -26567
  47. package/src/generic/ResolverBase.ts +201 -12
  48. package/src/generic/RunViewResolver.ts +157 -3
  49. package/src/index.ts +25 -5
  50. package/src/resolvers/AskSkipResolver.ts +18 -20
  51. package/src/resolvers/QueryResolver.ts +276 -2
  52. package/src/resolvers/RunAIAgentResolver.ts +2 -2
  53. package/src/resolvers/RunAIPromptResolver.ts +1 -1
  54. package/src/resolvers/SyncDataResolver.ts +5 -5
  55. package/src/resolvers/TelemetryResolver.ts +567 -0
  56. package/src/services/TaskOrchestrator.ts +2 -1
@@ -1,10 +1,44 @@
1
- import { Arg, Ctx, ObjectType, Query, Resolver, Field, Int } from 'type-graphql';
2
- import { RunQuery, QueryInfo, IRunQueryProvider, IMetadataProvider } from '@memberjunction/core';
1
+ import { Arg, Ctx, ObjectType, Query, Resolver, Field, Int, InputType } from 'type-graphql';
2
+ import { RunQuery, QueryInfo, IRunQueryProvider, IMetadataProvider, RunQueryParams, LogError, RunQueryWithCacheCheckParams, RunQueriesWithCacheCheckResponse, RunQueryWithCacheCheckResult } 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
7
  import { GetReadOnlyProvider } from '../util.js';
8
+ import { SQLServerDataProvider } from '@memberjunction/sqlserver-dataprovider';
9
+
10
+ /**
11
+ * Input type for batch query execution - allows running multiple queries in a single network call
12
+ */
13
+ @InputType()
14
+ export class RunQueryInput {
15
+ @Field(() => String, { nullable: true, description: 'Query ID to run - either QueryID or QueryName must be provided' })
16
+ QueryID?: string;
17
+
18
+ @Field(() => String, { nullable: true, description: 'Query Name to run - either QueryID or QueryName must be provided' })
19
+ QueryName?: string;
20
+
21
+ @Field(() => String, { nullable: true, description: 'Category ID to help disambiguate queries with the same name' })
22
+ CategoryID?: string;
23
+
24
+ @Field(() => String, { nullable: true, description: 'Category path to help disambiguate queries with the same name' })
25
+ CategoryPath?: string;
26
+
27
+ @Field(() => GraphQLJSONObject, { nullable: true, description: 'Parameters to pass to the query' })
28
+ Parameters?: Record<string, unknown>;
29
+
30
+ @Field(() => Int, { nullable: true, description: 'Maximum number of rows to return' })
31
+ MaxRows?: number;
32
+
33
+ @Field(() => Int, { nullable: true, description: 'Starting row offset for pagination' })
34
+ StartRow?: number;
35
+
36
+ @Field(() => Boolean, { nullable: true, description: 'Force audit logging regardless of query settings' })
37
+ ForceAuditLog?: boolean;
38
+
39
+ @Field(() => String, { nullable: true, description: 'Description to use in audit log' })
40
+ AuditLogDescription?: string;
41
+ }
8
42
 
9
43
  @ObjectType()
10
44
  export class RunQueryResultType {
@@ -42,6 +76,70 @@ export class RunQueryResultType {
42
76
  CacheTTLRemaining?: number;
43
77
  }
44
78
 
79
+ //****************************************************************************
80
+ // INPUT/OUTPUT TYPES for RunQueriesWithCacheCheck
81
+ //****************************************************************************
82
+
83
+ @InputType()
84
+ export class RunQueryCacheStatusInput {
85
+ @Field(() => String, { description: 'The maximum __mj_UpdatedAt value from cached results' })
86
+ maxUpdatedAt: string;
87
+
88
+ @Field(() => Int, { description: 'The number of rows in cached results' })
89
+ rowCount: number;
90
+ }
91
+
92
+ @InputType()
93
+ export class RunQueryWithCacheCheckInput {
94
+ @Field(() => RunQueryInput, { description: 'The RunQuery parameters' })
95
+ params: RunQueryInput;
96
+
97
+ @Field(() => RunQueryCacheStatusInput, {
98
+ nullable: true,
99
+ description: 'Optional cache status - if provided, server will check if cache is current'
100
+ })
101
+ cacheStatus?: RunQueryCacheStatusInput;
102
+ }
103
+
104
+ @ObjectType()
105
+ export class RunQueryWithCacheCheckResultOutput {
106
+ @Field(() => Int, { description: 'The index of this query in the batch request' })
107
+ queryIndex: number;
108
+
109
+ @Field(() => String, { description: 'The query ID' })
110
+ queryId: string;
111
+
112
+ @Field(() => String, { description: "'current', 'stale', 'no_validation', or 'error'" })
113
+ status: string;
114
+
115
+ @Field(() => String, {
116
+ nullable: true,
117
+ description: 'JSON-stringified results - only populated when status is stale or no_validation'
118
+ })
119
+ Results?: string;
120
+
121
+ @Field(() => String, { nullable: true, description: 'Max __mj_UpdatedAt from results when stale' })
122
+ maxUpdatedAt?: string;
123
+
124
+ @Field(() => Int, { nullable: true, description: 'Row count of results when stale' })
125
+ rowCount?: number;
126
+
127
+ @Field(() => String, { nullable: true, description: 'Error message if status is error' })
128
+ errorMessage?: string;
129
+ }
130
+
131
+ @ObjectType()
132
+ export class RunQueriesWithCacheCheckOutput {
133
+ @Field(() => Boolean, { description: 'Whether the overall operation succeeded' })
134
+ success: boolean;
135
+
136
+ @Field(() => [RunQueryWithCacheCheckResultOutput], { description: 'Results for each query in the batch' })
137
+ results: RunQueryWithCacheCheckResultOutput[];
138
+
139
+ @Field(() => String, { nullable: true, description: 'Overall error message if success is false' })
140
+ errorMessage?: string;
141
+ }
142
+
45
143
  @Resolver()
46
144
  export class RunQueryResolver {
47
145
  private async findQuery(md: IMetadataProvider, QueryID: string, QueryName?: string, CategoryID?: string, CategoryPath?: string, refreshMetadataIfNotFound: boolean = false): Promise<QueryInfo | null> {
@@ -273,4 +371,180 @@ export class RunQueryResolver {
273
371
  CacheTTLRemaining: (result as any).CacheTTLRemaining
274
372
  };
275
373
  }
374
+
375
+ /**
376
+ * Batch query execution - runs multiple queries in a single network call
377
+ * This is more efficient than making multiple individual query calls
378
+ */
379
+ @Query(() => [RunQueryResultType])
380
+ async RunQueries(
381
+ @Arg('input', () => [RunQueryInput]) input: RunQueryInput[],
382
+ @Ctx() context: AppContext
383
+ ): Promise<RunQueryResultType[]> {
384
+ const provider = GetReadOnlyProvider(context.providers, { allowFallbackToReadWrite: true });
385
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
386
+
387
+ // Convert input to RunQueryParams array
388
+ const params: RunQueryParams[] = input.map(i => ({
389
+ QueryID: i.QueryID,
390
+ QueryName: i.QueryName,
391
+ CategoryID: i.CategoryID,
392
+ CategoryPath: i.CategoryPath,
393
+ Parameters: i.Parameters,
394
+ MaxRows: i.MaxRows,
395
+ StartRow: i.StartRow,
396
+ ForceAuditLog: i.ForceAuditLog,
397
+ AuditLogDescription: i.AuditLogDescription
398
+ }));
399
+
400
+ // Execute all queries in parallel using the batch method
401
+ const results = await rq.RunQueries(params, context.userPayload.userRecord);
402
+
403
+ // Map results to output format
404
+ return results.map((result, index) => {
405
+ const inputItem = input[index];
406
+ return {
407
+ QueryID: result.QueryID || inputItem.QueryID || '',
408
+ QueryName: result.QueryName || inputItem.QueryName || 'Unknown Query',
409
+ Success: result.Success ?? false,
410
+ Results: JSON.stringify(result.Results ?? null),
411
+ RowCount: result.RowCount ?? 0,
412
+ TotalRowCount: result.TotalRowCount ?? 0,
413
+ ExecutionTime: result.ExecutionTime ?? 0,
414
+ ErrorMessage: result.ErrorMessage || '',
415
+ AppliedParameters: result.AppliedParameters ? JSON.stringify(result.AppliedParameters) : undefined,
416
+ CacheHit: (result as Record<string, unknown>).CacheHit as boolean | undefined,
417
+ CacheTTLRemaining: (result as Record<string, unknown>).CacheTTLRemaining as number | undefined
418
+ };
419
+ });
420
+ }
421
+
422
+ /**
423
+ * Batch query execution with system user privileges
424
+ */
425
+ @RequireSystemUser()
426
+ @Query(() => [RunQueryResultType])
427
+ async RunQueriesSystemUser(
428
+ @Arg('input', () => [RunQueryInput]) input: RunQueryInput[],
429
+ @Ctx() context: AppContext
430
+ ): Promise<RunQueryResultType[]> {
431
+ const provider = GetReadOnlyProvider(context.providers, { allowFallbackToReadWrite: true });
432
+ const rq = new RunQuery(provider as unknown as IRunQueryProvider);
433
+
434
+ // Convert input to RunQueryParams array
435
+ const params: RunQueryParams[] = input.map(i => ({
436
+ QueryID: i.QueryID,
437
+ QueryName: i.QueryName,
438
+ CategoryID: i.CategoryID,
439
+ CategoryPath: i.CategoryPath,
440
+ Parameters: i.Parameters,
441
+ MaxRows: i.MaxRows,
442
+ StartRow: i.StartRow,
443
+ ForceAuditLog: i.ForceAuditLog,
444
+ AuditLogDescription: i.AuditLogDescription
445
+ }));
446
+
447
+ // Execute all queries in parallel using the batch method
448
+ const results = await rq.RunQueries(params, context.userPayload.userRecord);
449
+
450
+ // Map results to output format
451
+ return results.map((result, index) => {
452
+ const inputItem = input[index];
453
+ return {
454
+ QueryID: result.QueryID || inputItem.QueryID || '',
455
+ QueryName: result.QueryName || inputItem.QueryName || 'Unknown Query',
456
+ Success: result.Success ?? false,
457
+ Results: JSON.stringify(result.Results ?? null),
458
+ RowCount: result.RowCount ?? 0,
459
+ TotalRowCount: result.TotalRowCount ?? 0,
460
+ ExecutionTime: result.ExecutionTime ?? 0,
461
+ ErrorMessage: result.ErrorMessage || '',
462
+ AppliedParameters: result.AppliedParameters ? JSON.stringify(result.AppliedParameters) : undefined,
463
+ CacheHit: (result as Record<string, unknown>).CacheHit as boolean | undefined,
464
+ CacheTTLRemaining: (result as Record<string, unknown>).CacheTTLRemaining as number | undefined
465
+ };
466
+ });
467
+ }
468
+
469
+ /**
470
+ * RunQueriesWithCacheCheck - Smart cache validation for batch RunQueries.
471
+ * For each query, if cacheStatus is provided, the server checks if the cache is current
472
+ * using the Query's CacheValidationSQL. If current, returns status='current' with no data.
473
+ * If stale, returns status='stale' with fresh data.
474
+ * If the Query doesn't have CacheValidationSQL configured, returns 'no_validation' with data.
475
+ */
476
+ @Query(() => RunQueriesWithCacheCheckOutput)
477
+ async RunQueriesWithCacheCheck(
478
+ @Arg('input', () => [RunQueryWithCacheCheckInput]) input: RunQueryWithCacheCheckInput[],
479
+ @Ctx() context: AppContext
480
+ ): Promise<RunQueriesWithCacheCheckOutput> {
481
+ try {
482
+ const provider = GetReadOnlyProvider(context.providers, { allowFallbackToReadWrite: true });
483
+
484
+ // Cast provider to SQLServerDataProvider to access RunQueriesWithCacheCheck method
485
+ const sqlProvider = provider as unknown as SQLServerDataProvider;
486
+ if (!sqlProvider.RunQueriesWithCacheCheck) {
487
+ throw new Error('Provider does not support RunQueriesWithCacheCheck');
488
+ }
489
+
490
+ // Convert GraphQL input types to core types
491
+ const coreParams: RunQueryWithCacheCheckParams[] = input.map(item => ({
492
+ params: {
493
+ QueryID: item.params.QueryID,
494
+ QueryName: item.params.QueryName,
495
+ CategoryID: item.params.CategoryID,
496
+ CategoryPath: item.params.CategoryPath,
497
+ Parameters: item.params.Parameters,
498
+ MaxRows: item.params.MaxRows,
499
+ StartRow: item.params.StartRow,
500
+ ForceAuditLog: item.params.ForceAuditLog,
501
+ AuditLogDescription: item.params.AuditLogDescription,
502
+ },
503
+ cacheStatus: item.cacheStatus ? {
504
+ maxUpdatedAt: item.cacheStatus.maxUpdatedAt,
505
+ rowCount: item.cacheStatus.rowCount,
506
+ } : undefined,
507
+ }));
508
+
509
+ const response = await sqlProvider.RunQueriesWithCacheCheck(coreParams, context.userPayload.userRecord);
510
+
511
+ // Transform results to GraphQL output format
512
+ const transformedResults: RunQueryWithCacheCheckResultOutput[] = response.results.map(result => ({
513
+ queryIndex: result.queryIndex,
514
+ queryId: result.queryId,
515
+ status: result.status,
516
+ Results: result.results ? JSON.stringify(result.results) : undefined,
517
+ maxUpdatedAt: result.maxUpdatedAt,
518
+ rowCount: result.rowCount,
519
+ errorMessage: result.errorMessage,
520
+ }));
521
+
522
+ return {
523
+ success: response.success,
524
+ results: transformedResults,
525
+ errorMessage: response.errorMessage,
526
+ };
527
+ } catch (err) {
528
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
529
+ LogError(err);
530
+ return {
531
+ success: false,
532
+ results: [],
533
+ errorMessage,
534
+ };
535
+ }
536
+ }
537
+
538
+ /**
539
+ * RunQueriesWithCacheCheck with system user privileges
540
+ */
541
+ @RequireSystemUser()
542
+ @Query(() => RunQueriesWithCacheCheckOutput)
543
+ async RunQueriesWithCacheCheckSystemUser(
544
+ @Arg('input', () => [RunQueryWithCacheCheckInput]) input: RunQueryWithCacheCheckInput[],
545
+ @Ctx() context: AppContext
546
+ ): Promise<RunQueriesWithCacheCheckOutput> {
547
+ // Same implementation as regular version - RequireSystemUser handles auth
548
+ return this.RunQueriesWithCacheCheck(input, context);
549
+ }
276
550
  }
@@ -1,9 +1,9 @@
1
1
  import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID } from 'type-graphql';
2
2
  import { AppContext, UserPayload } from '../types.js';
3
3
  import { DatabaseProviderBase, LogError, LogStatus, Metadata, UserInfo } from '@memberjunction/core';
4
- import { AIAgentEntityExtended, ConversationDetailEntity, UserNotificationEntity, AIAgentRunEntityExtended } from '@memberjunction/core-entities';
4
+ import { ConversationDetailEntity, UserNotificationEntity } from '@memberjunction/core-entities';
5
5
  import { AgentRunner } from '@memberjunction/ai-agents';
6
- import { ExecuteAgentResult } from '@memberjunction/ai-core-plus';
6
+ import { AIAgentEntityExtended, AIAgentRunEntityExtended, ExecuteAgentResult } from '@memberjunction/ai-core-plus';
7
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';
@@ -1,7 +1,7 @@
1
1
  import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, Int } from 'type-graphql';
2
2
  import { AppContext, UserPayload } from '../types.js';
3
3
  import { DatabaseProviderBase, LogError, LogStatus, Metadata } from '@memberjunction/core';
4
- import { AIPromptEntityExtended, AIModelEntityExtended } from '@memberjunction/core-entities';
4
+ import { AIPromptEntityExtended, AIModelEntityExtended } from '@memberjunction/ai-core-plus';
5
5
  import { AIPromptRunner } from '@memberjunction/ai-prompts';
6
6
  import { AIPromptParams } from '@memberjunction/ai-core-plus';
7
7
  import { ResolverBase } from '../generic/ResolverBase.js';
@@ -226,7 +226,7 @@ export class SyncDataResolver {
226
226
  for (const entityObject of data.Results) {
227
227
  if (!await entityObject.Delete()) {
228
228
  overallSuccess = false;
229
- combinedErrorMessage += 'Failed to delete the item :' + entityObject.LatestResult.Message + '\n';
229
+ combinedErrorMessage += 'Failed to delete the item :' + entityObject.LatestResult.CompleteMessage + '\n';
230
230
  }
231
231
  }
232
232
  result.Success = overallSuccess
@@ -316,7 +316,7 @@ export class SyncDataResolver {
316
316
  result.Success = true;
317
317
  }
318
318
  else {
319
- result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.Message;
319
+ result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.CompleteMessage;
320
320
  }
321
321
  }
322
322
  }
@@ -334,7 +334,7 @@ export class SyncDataResolver {
334
334
  result.Success = true;
335
335
  }
336
336
  else {
337
- result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.Message;
337
+ result.ErrorMessage = 'Failed to delete the item :' + entityObject.LatestResult.CompleteMessage;
338
338
  }
339
339
  }
340
340
  else {
@@ -363,7 +363,7 @@ export class SyncDataResolver {
363
363
  });
364
364
  }
365
365
  else {
366
- result.ErrorMessage = 'Failed to create the item :' + entityObject.LatestResult.Message;
366
+ result.ErrorMessage = 'Failed to create the item :' + entityObject.LatestResult.CompleteMessage;
367
367
  }
368
368
  }
369
369
 
@@ -406,7 +406,7 @@ export class SyncDataResolver {
406
406
  });
407
407
  }
408
408
  else {
409
- result.ErrorMessage = 'Failed to update the item :' + entityObject.LatestResult.Message;
409
+ result.ErrorMessage = 'Failed to update the item :' + entityObject.LatestResult.CompleteMessage;
410
410
  }
411
411
  }
412
412
  }