@memberjunction/server 5.26.0 → 5.27.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/server",
3
- "version": "5.26.0",
3
+ "version": "5.27.0",
4
4
  "description": "MemberJunction: This project provides API access via GraphQL to the common data store.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./src/index.ts",
@@ -27,71 +27,71 @@
27
27
  "@as-integrations/express5": "^1.0.0",
28
28
  "@graphql-tools/schema": "latest",
29
29
  "@graphql-tools/utils": "^11.0.0",
30
- "@memberjunction/actions": "5.26.0",
31
- "@memberjunction/actions-apollo": "5.26.0",
32
- "@memberjunction/actions-base": "5.26.0",
33
- "@memberjunction/actions-bizapps-accounting": "5.26.0",
34
- "@memberjunction/actions-bizapps-crm": "5.26.0",
35
- "@memberjunction/actions-bizapps-formbuilders": "5.26.0",
36
- "@memberjunction/actions-bizapps-lms": "5.26.0",
37
- "@memberjunction/actions-bizapps-social": "5.26.0",
38
- "@memberjunction/ai": "5.26.0",
39
- "@memberjunction/ai-agent-manager": "5.26.0",
40
- "@memberjunction/ai-agent-manager-actions": "5.26.0",
41
- "@memberjunction/ai-agents": "5.26.0",
42
- "@memberjunction/ai-core-plus": "5.26.0",
43
- "@memberjunction/ai-mcp-client": "5.26.0",
44
- "@memberjunction/ai-prompts": "5.26.0",
45
- "@memberjunction/ai-provider-bundle": "5.26.0",
46
- "@memberjunction/ai-vector-sync": "5.26.0",
47
- "@memberjunction/ai-vectordb": "5.26.0",
48
- "@memberjunction/ai-vectors-pinecone": "5.26.0",
49
- "@memberjunction/aiengine": "5.26.0",
50
- "@memberjunction/api-keys": "5.26.0",
51
- "@memberjunction/auth-providers": "5.26.0",
52
- "@memberjunction/codegen-lib": "5.26.0",
53
- "@memberjunction/communication-ms-graph": "5.26.0",
54
- "@memberjunction/communication-sendgrid": "5.26.0",
55
- "@memberjunction/communication-types": "5.26.0",
56
- "@memberjunction/component-registry-client-sdk": "5.26.0",
57
- "@memberjunction/computer-use-engine": "5.26.0",
58
- "@memberjunction/config": "5.26.0",
59
- "@memberjunction/core": "5.26.0",
60
- "@memberjunction/core-actions": "5.26.0",
61
- "@memberjunction/core-entities": "5.26.0",
62
- "@memberjunction/core-entities-server": "5.26.0",
63
- "@memberjunction/data-context": "5.26.0",
64
- "@memberjunction/data-context-server": "5.26.0",
65
- "@memberjunction/doc-utils": "5.26.0",
66
- "@memberjunction/encryption": "5.26.0",
67
- "@memberjunction/entity-communications-base": "5.26.0",
68
- "@memberjunction/entity-communications-server": "5.26.0",
69
- "@memberjunction/external-change-detection": "5.26.0",
70
- "@memberjunction/generic-database-provider": "5.26.0",
71
- "@memberjunction/global": "5.26.0",
72
- "@memberjunction/graphql-dataprovider": "5.26.0",
73
- "@memberjunction/integration-engine": "5.26.0",
74
- "@memberjunction/integration-schema-builder": "5.26.0",
75
- "@memberjunction/interactive-component-types": "5.26.0",
76
- "@memberjunction/notifications": "5.26.0",
77
- "@memberjunction/postgresql-dataprovider": "5.26.0",
78
- "@memberjunction/queue": "5.26.0",
79
- "@memberjunction/redis-provider": "5.26.0",
80
- "@memberjunction/scheduling-actions": "5.26.0",
81
- "@memberjunction/scheduling-base-types": "5.26.0",
82
- "@memberjunction/scheduling-engine": "5.26.0",
83
- "@memberjunction/scheduling-engine-base": "5.26.0",
84
- "@memberjunction/schema-engine": "5.26.0",
85
- "@memberjunction/search-engine": "5.26.0",
86
- "@memberjunction/server-extensions-core": "5.26.0",
87
- "@memberjunction/skip-types": "5.26.0",
88
- "@memberjunction/sql-dialect": "5.26.0",
89
- "@memberjunction/sqlserver-dataprovider": "5.26.0",
90
- "@memberjunction/storage": "5.26.0",
91
- "@memberjunction/templates": "5.26.0",
92
- "@memberjunction/testing-engine": "5.26.0",
93
- "@memberjunction/testing-engine-base": "5.26.0",
94
- "@memberjunction/version-history": "5.26.0",
30
+ "@memberjunction/actions": "5.27.0",
31
+ "@memberjunction/actions-apollo": "5.27.0",
32
+ "@memberjunction/actions-base": "5.27.0",
33
+ "@memberjunction/actions-bizapps-accounting": "5.27.0",
34
+ "@memberjunction/actions-bizapps-crm": "5.27.0",
35
+ "@memberjunction/actions-bizapps-formbuilders": "5.27.0",
36
+ "@memberjunction/actions-bizapps-lms": "5.27.0",
37
+ "@memberjunction/actions-bizapps-social": "5.27.0",
38
+ "@memberjunction/ai": "5.27.0",
39
+ "@memberjunction/ai-agent-manager": "5.27.0",
40
+ "@memberjunction/ai-agent-manager-actions": "5.27.0",
41
+ "@memberjunction/ai-agents": "5.27.0",
42
+ "@memberjunction/ai-core-plus": "5.27.0",
43
+ "@memberjunction/ai-mcp-client": "5.27.0",
44
+ "@memberjunction/ai-prompts": "5.27.0",
45
+ "@memberjunction/ai-provider-bundle": "5.27.0",
46
+ "@memberjunction/ai-vector-sync": "5.27.0",
47
+ "@memberjunction/ai-vectordb": "5.27.0",
48
+ "@memberjunction/ai-vectors-pinecone": "5.27.0",
49
+ "@memberjunction/aiengine": "5.27.0",
50
+ "@memberjunction/api-keys": "5.27.0",
51
+ "@memberjunction/auth-providers": "5.27.0",
52
+ "@memberjunction/codegen-lib": "5.27.0",
53
+ "@memberjunction/communication-ms-graph": "5.27.0",
54
+ "@memberjunction/communication-sendgrid": "5.27.0",
55
+ "@memberjunction/communication-types": "5.27.0",
56
+ "@memberjunction/component-registry-client-sdk": "5.27.0",
57
+ "@memberjunction/computer-use-engine": "5.27.0",
58
+ "@memberjunction/config": "5.27.0",
59
+ "@memberjunction/core": "5.27.0",
60
+ "@memberjunction/core-actions": "5.27.0",
61
+ "@memberjunction/core-entities": "5.27.0",
62
+ "@memberjunction/core-entities-server": "5.27.0",
63
+ "@memberjunction/data-context": "5.27.0",
64
+ "@memberjunction/data-context-server": "5.27.0",
65
+ "@memberjunction/doc-utils": "5.27.0",
66
+ "@memberjunction/encryption": "5.27.0",
67
+ "@memberjunction/entity-communications-base": "5.27.0",
68
+ "@memberjunction/entity-communications-server": "5.27.0",
69
+ "@memberjunction/external-change-detection": "5.27.0",
70
+ "@memberjunction/generic-database-provider": "5.27.0",
71
+ "@memberjunction/global": "5.27.0",
72
+ "@memberjunction/graphql-dataprovider": "5.27.0",
73
+ "@memberjunction/integration-engine": "5.27.0",
74
+ "@memberjunction/integration-schema-builder": "5.27.0",
75
+ "@memberjunction/interactive-component-types": "5.27.0",
76
+ "@memberjunction/notifications": "5.27.0",
77
+ "@memberjunction/postgresql-dataprovider": "5.27.0",
78
+ "@memberjunction/queue": "5.27.0",
79
+ "@memberjunction/redis-provider": "5.27.0",
80
+ "@memberjunction/scheduling-actions": "5.27.0",
81
+ "@memberjunction/scheduling-base-types": "5.27.0",
82
+ "@memberjunction/scheduling-engine": "5.27.0",
83
+ "@memberjunction/scheduling-engine-base": "5.27.0",
84
+ "@memberjunction/schema-engine": "5.27.0",
85
+ "@memberjunction/search-engine": "5.27.0",
86
+ "@memberjunction/server-extensions-core": "5.27.0",
87
+ "@memberjunction/skip-types": "5.27.0",
88
+ "@memberjunction/sql-dialect": "5.27.0",
89
+ "@memberjunction/sqlserver-dataprovider": "5.27.0",
90
+ "@memberjunction/storage": "5.27.0",
91
+ "@memberjunction/templates": "5.27.0",
92
+ "@memberjunction/testing-engine": "5.27.0",
93
+ "@memberjunction/testing-engine-base": "5.27.0",
94
+ "@memberjunction/version-history": "5.27.0",
95
95
  "@types/compression": "^1.8.1",
96
96
  "@types/cors": "^2.8.19",
97
97
  "@types/jsonwebtoken": "9.0.10",
@@ -17,12 +17,6 @@ import {
17
17
  SkipAPIRequestAPIKey,
18
18
  SkipQueryInfo,
19
19
  SkipQueryCatalogEntry,
20
- SkipEntityInfo,
21
- SkipEntityFieldInfo,
22
- SkipEntityFieldValueInfo,
23
- SkipEntityRelationshipInfo,
24
- SkipEntityOrganicKeyInfo,
25
- SkipEntityOrganicKeyRelatedEntityInfo,
26
20
  SkipAPIAgentNote,
27
21
  SkipAPIAgentNoteType,
28
22
  SkipAPIArtifact,
@@ -30,7 +24,7 @@ import {
30
24
  SkipAPIArtifactType
31
25
  } from '@memberjunction/skip-types';
32
26
  import { DataContext } from '@memberjunction/data-context';
33
- import { UserInfo, LogStatus, LogError, Metadata, RunQuery, EntityInfo, EntityFieldInfo, EntityRelationshipInfo, EntityOrganicKeyInfo, EntityOrganicKeyRelatedEntityInfo } from '@memberjunction/core';
27
+ import { UserInfo, LogStatus, LogError, Metadata, RunQuery, EntityInfo, EntityFieldInfo, EntityFieldValueInfo, DatabaseProviderBase } from '@memberjunction/core';
34
28
  import { request as httpRequest } from 'http';
35
29
  import { request as httpsRequest } from 'https';
36
30
  import { gzip as gzipCompress, createGunzip } from 'zlib';
@@ -206,7 +200,7 @@ export class SkipSDK {
206
200
  private config: SkipSDKConfig;
207
201
 
208
202
  // Static cache for Skip entities (shared across all instances)
209
- private static __skipEntitiesCache$: BehaviorSubject<Promise<SkipEntityInfo[]> | null> = new BehaviorSubject<Promise<SkipEntityInfo[]> | null>(null);
203
+ private static __skipEntitiesCache$: BehaviorSubject<Promise<EntityInfo[]> | null> = new BehaviorSubject<Promise<EntityInfo[]> | null>(null);
210
204
  private static __lastRefreshTime: number = 0;
211
205
 
212
206
  constructor(config?: SkipSDKConfig) {
@@ -396,7 +390,7 @@ export class SkipSDK {
396
390
  includeCallbackAuth: boolean,
397
391
  additionalTokenInfo: any = {}
398
392
  ): Promise<Partial<SkipAPIRequest>> {
399
- const entities = includeEntities ? await this.buildEntities(dataSource, forceEntityRefresh) : [];
393
+ const entities = includeEntities ? await this.buildEntities(forceEntityRefresh) : [];
400
394
  const queries = includeQueries ? this.buildQueries() : [];
401
395
  // Always build the lightweight query catalog for collision detection,
402
396
  // regardless of whether full queries are included
@@ -442,7 +436,7 @@ export class SkipSDK {
442
436
  * Build entity metadata for Skip
443
437
  * Copied from AskSkipResolver.BuildSkipEntities - uses cached metadata with refresh logic
444
438
  */
445
- private async buildEntities(dataSource: mssql.ConnectionPool, forceRefresh: boolean, refreshIntervalMinutes: number = 15): Promise<SkipEntityInfo[]> {
439
+ private async buildEntities(forceRefresh: boolean, refreshIntervalMinutes: number = 15): Promise<EntityInfo[]> {
446
440
  try {
447
441
  const now = Date.now();
448
442
  const cacheExpired = (now - SkipSDK.__lastRefreshTime) > (refreshIntervalMinutes * 60 * 1000);
@@ -450,7 +444,7 @@ export class SkipSDK {
450
444
  // If force refresh is requested OR cache expired OR cache is empty, refresh
451
445
  if (forceRefresh || cacheExpired || SkipSDK.__skipEntitiesCache$.value === null) {
452
446
  LogStatus(`[SkipSDK] Refreshing Skip entities cache (force: ${forceRefresh}, expired: ${cacheExpired})`);
453
- const newData = this.refreshSkipEntities(dataSource);
447
+ const newData = this.refreshSkipEntities();
454
448
  SkipSDK.__skipEntitiesCache$.next(newData);
455
449
  }
456
450
 
@@ -856,9 +850,11 @@ export class SkipSDK {
856
850
  /**
857
851
  * Refreshes the Skip entities cache
858
852
  * Rebuilds the entity information that is provided to Skip
859
- * Copied from AskSkipResolver.refreshSkipEntities
853
+ * Refreshes the entity metadata cache. Filters entities by schema/scope config,
854
+ * filters fields by AI scope, and enriches field values from the database.
855
+ * Returns EntityInfo objects directly — no intermediate Skip-specific types needed.
860
856
  */
861
- private async refreshSkipEntities(dataSource: mssql.ConnectionPool): Promise<SkipEntityInfo[]> {
857
+ private async refreshSkipEntities(): Promise<EntityInfo[]> {
862
858
  try {
863
859
  const md = new Metadata();
864
860
 
@@ -891,12 +887,12 @@ export class SkipSDK {
891
887
  LogError(`[SkipSDK.refreshSkipEntities] WARNING: No entities passed filtering! This will result in empty Skip entities list.`);
892
888
  }
893
889
 
894
- // Now we have our list of entities, pack em up
895
- const result = await Promise.all(entities.map((e) => this.packSingleSkipEntityInfo(e, dataSource)));
890
+ // Build enriched EntityInfo objects with filtered fields and packed values
891
+ const result = await Promise.all(entities.map((e) => this.buildEntityForSkip(e)));
896
892
 
897
893
  LogStatus(`[SkipSDK.refreshSkipEntities] Successfully packed ${result.length} entities for Skip`);
898
894
 
899
- SkipSDK.__lastRefreshTime = Date.now(); // Update last refresh time
895
+ SkipSDK.__lastRefreshTime = Date.now();
900
896
  return result;
901
897
  }
902
898
  catch (e) {
@@ -906,258 +902,95 @@ export class SkipSDK {
906
902
  }
907
903
 
908
904
  /**
909
- * Packs information about a single entity for Skip
910
- * Includes fields, relationships, and sample data
911
- * Copied from AskSkipResolver.PackSingleSkipEntityInfo
905
+ * Builds an EntityInfo object for Skip, filtering fields by AI scope and
906
+ * enriching field values from the database. Returns a new EntityInfo
907
+ * constructed from a plain object so it serializes cleanly via toJSON().
912
908
  */
913
- private async packSingleSkipEntityInfo(e: EntityInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityInfo> {
909
+ private async buildEntityForSkip(e: EntityInfo): Promise<EntityInfo> {
914
910
  try {
915
- const ret: SkipEntityInfo = {
916
- id: e.ID,
917
- name: e.Name,
918
- schemaName: e.SchemaName,
919
- baseView: e.BaseView,
920
- description: e.Description,
921
-
922
- fields: await Promise.all(e.Fields.filter(f => {
923
- // we want to check the scopes for the field level and make sure it is either All or AI or has both
924
- const scopes = f.ScopeDefault?.split(',').map((s) => s.trim().toLowerCase());
925
- return !scopes || scopes.length === 0 || scopes.includes('all') || scopes.includes('ai');
926
- }).map(f => {
927
- return this.packSingleSkipEntityField(f, dataSource);
928
- })),
929
-
930
- relatedEntities: e.RelatedEntities.map((r) => {
931
- return this.packSingleSkipEntityRelationship(r);
932
- }),
933
-
934
- organicKeys: (e.OrganicKeys ?? [])
935
- .filter((ok) => ok.Status === 'Active')
936
- .map((ok) => this.packSingleSkipOrganicKey(ok))
937
- .filter((ok): ok is SkipEntityOrganicKeyInfo => ok !== null)
938
- };
939
- return ret;
940
- }
941
- catch (e) {
942
- LogError(`[SkipSDK] packSingleSkipEntityInfo error: ${e}`);
943
- return null;
944
- }
945
- }
946
-
947
- /**
948
- * Packs information about a single organic key for Skip.
949
- * Organic keys express cross-entity relationships via shared business data
950
- * (email, acronym, etc.) rather than database FK constraints.
951
- */
952
- private packSingleSkipOrganicKey(ok: EntityOrganicKeyInfo): SkipEntityOrganicKeyInfo | null {
953
- try {
954
- return {
955
- id: ok.ID,
956
- name: ok.Name,
957
- description: ok.Description ?? undefined,
958
- matchFieldNames: ok.MatchFieldNamesArray,
959
- normalizationStrategy: ok.NormalizationStrategy,
960
- customNormalizationExpression: ok.CustomNormalizationExpression ?? undefined,
961
- sequence: ok.Sequence,
962
- relatedEntities: ok.RelatedEntities
963
- .map((re) => this.packSingleSkipOrganicKeyRelatedEntity(re))
964
- .filter((re): re is SkipEntityOrganicKeyRelatedEntityInfo => re !== null)
965
- };
966
- }
967
- catch (e) {
968
- LogError(`[SkipSDK] packSingleSkipOrganicKey error: ${e}`);
969
- return null;
970
- }
971
- }
911
+ // Filter fields by scope (only include fields visible to AI)
912
+ const filteredFields = e.Fields.filter(f => {
913
+ const scopes = f.ScopeDefault?.split(',').map((s) => s.trim().toLowerCase());
914
+ return !scopes || scopes.length === 0 || scopes.includes('all') || scopes.includes('ai');
915
+ });
972
916
 
973
- /**
974
- * Packs information about a single organic key related entity for Skip.
975
- * Looks up schema name and base view from metadata since they are not
976
- * stored on EntityOrganicKeyRelatedEntityInfo directly.
977
- */
978
- private packSingleSkipOrganicKeyRelatedEntity(
979
- re: EntityOrganicKeyRelatedEntityInfo
980
- ): SkipEntityOrganicKeyRelatedEntityInfo | null {
981
- try {
982
- // Look up the related entity to obtain schema name and base view, which
983
- // Skip needs in order to generate schema-qualified SQL.
984
- const relatedEntity = Metadata.Provider.Entities.find(
985
- (ent) => UUIDsEqual(ent.ID, re.RelatedEntityID)
986
- );
987
- if (!relatedEntity) {
988
- LogError(
989
- `[SkipSDK] packSingleSkipOrganicKeyRelatedEntity: related entity not found for ID ${re.RelatedEntityID}`
990
- );
991
- return null;
992
- }
917
+ // Enrich each field with packed possible values
918
+ const enrichedFields = await Promise.all(filteredFields.map(f => this.enrichFieldValues(f)));
993
919
 
994
- return {
995
- id: re.ID,
996
- relatedEntityID: re.RelatedEntityID,
997
- relatedEntityName: relatedEntity.Name,
998
- relatedEntitySchemaName: relatedEntity.SchemaName,
999
- relatedEntityBaseView: relatedEntity.BaseView,
1000
- isDirectMatch: re.IsDirectMatch,
1001
- isTransitiveMatch: re.IsTransitiveMatch,
1002
- relatedEntityFieldNames: re.IsDirectMatch
1003
- ? re.RelatedEntityFieldNamesArray
1004
- : undefined,
1005
- transitiveObjectName: re.TransitiveObjectName ?? undefined,
1006
- transitiveObjectMatchFieldNames: re.IsTransitiveMatch
1007
- ? re.TransitiveObjectMatchFieldNamesArray
1008
- : undefined,
1009
- transitiveObjectOutputFieldName: re.TransitiveObjectOutputFieldName ?? undefined,
1010
- relatedEntityJoinFieldName: re.RelatedEntityJoinFieldName ?? undefined,
1011
- displayName: re.DisplayName ?? undefined,
1012
- sequence: re.Sequence
1013
- };
1014
- }
1015
- catch (e) {
1016
- LogError(`[SkipSDK] packSingleSkipOrganicKeyRelatedEntity error: ${e}`);
1017
- return null;
1018
- }
1019
- }
1020
-
1021
- /**
1022
- * Packs information about a single entity relationship
1023
- * These relationships help Skip understand the data model
1024
- * Copied from AskSkipResolver.PackSingleSkipEntityRelationship
1025
- */
1026
- private packSingleSkipEntityRelationship(r: EntityRelationshipInfo): SkipEntityRelationshipInfo {
1027
- try {
1028
- return {
1029
- entityID: r.EntityID,
1030
- relatedEntityID: r.RelatedEntityID,
1031
- type: r.Type,
1032
- entityKeyField: r.EntityKeyField,
1033
- relatedEntityJoinField: r.RelatedEntityJoinField,
1034
- joinView: r.JoinView,
1035
- joinEntityJoinField: r.JoinEntityJoinField,
1036
- joinEntityInverseJoinField: r.JoinEntityInverseJoinField,
1037
- entity: r.Entity,
1038
- entityBaseView: r.EntityBaseView,
1039
- relatedEntity: r.RelatedEntity,
1040
- relatedEntityBaseView: r.RelatedEntityBaseView,
1041
- };
920
+ // Clone the entity via toJSON, then swap in filtered+enriched fields and Skip-specific
921
+ // Active-only organic keys. Any future EntityInfo properties flow through automatically.
922
+ return new EntityInfo({
923
+ ...e.toJSON(),
924
+ Fields: enrichedFields,
925
+ OrganicKeys: e.OrganicKeys.filter(ok => ok.Status === 'Active'),
926
+ });
1042
927
  }
1043
- catch (e) {
1044
- LogError(`[SkipSDK] packSingleSkipEntityRelationship error: ${e}`);
928
+ catch (err) {
929
+ LogError(`[SkipSDK] buildEntityForSkip error: ${err}`);
1045
930
  return null;
1046
931
  }
1047
932
  }
1048
933
 
1049
934
  /**
1050
- * Packs information about a single entity field
1051
- * Includes metadata and possible values
1052
- * Copied from AskSkipResolver.PackSingleSkipEntityField
935
+ * Enriches a field's EntityFieldValues with possible values from the database.
936
+ * Returns a plain object that can be used to construct an EntityFieldInfo.
1053
937
  */
1054
- private async packSingleSkipEntityField(f: EntityFieldInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityFieldInfo> {
1055
- try {
1056
- return {
1057
- entityID: f.EntityID,
1058
- sequence: f.Sequence,
1059
- name: f.Name,
1060
- displayName: f.DisplayName,
1061
- category: f.Category,
1062
- type: f.Type,
1063
- description: f.Description,
1064
- isPrimaryKey: f.IsPrimaryKey,
1065
- allowsNull: f.AllowsNull,
1066
- isUnique: f.IsUnique,
1067
- length: f.Length,
1068
- precision: f.Precision,
1069
- scale: f.Scale,
1070
- sqlFullType: f.SQLFullType,
1071
- defaultValue: f.DefaultValue,
1072
- autoIncrement: f.AutoIncrement,
1073
- valueListType: f.ValueListType,
1074
- extendedType: f.ExtendedType,
1075
- defaultInView: f.DefaultInView,
1076
- defaultColumnWidth: f.DefaultColumnWidth,
1077
- isVirtual: f.IsVirtual,
1078
- isNameField: f.IsNameField,
1079
- relatedEntityID: f.RelatedEntityID,
1080
- relatedEntityFieldName: f.RelatedEntityFieldName,
1081
- relatedEntity: f.RelatedEntity,
1082
- relatedEntitySchemaName: f.RelatedEntitySchemaName,
1083
- relatedEntityBaseView: f.RelatedEntityBaseView,
1084
- possibleValues: await this.packFieldPossibleValues(f, dataSource),
1085
- };
1086
- }
1087
- catch (e) {
1088
- LogError(`[SkipSDK] packSingleSkipEntityField error: ${e}`);
1089
- return null;
1090
- }
938
+ private async enrichFieldValues(f: EntityFieldInfo): Promise<Record<string, unknown>> {
939
+ return {
940
+ ...f.toJSON(),
941
+ EntityFieldValues: await this.packFieldValues(f),
942
+ };
1091
943
  }
1092
944
 
1093
945
  /**
1094
- * Packs possible values for an entity field
1095
- * These values help Skip understand the domain and valid values for fields
1096
- * Copied from AskSkipResolver.PackFieldPossibleValues
946
+ * Packs possible values for an entity field based on the ValuesToPackWithSchema setting.
947
+ * Returns EntityFieldValueInfo-compatible objects.
1097
948
  */
1098
- private async packFieldPossibleValues(f: EntityFieldInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityFieldValueInfo[]> {
949
+ private async packFieldValues(f: EntityFieldInfo): Promise<EntityFieldValueInfo[]> {
1099
950
  try {
1100
951
  if (f.ValuesToPackWithSchema === 'None') {
1101
- return []; // don't pack anything
952
+ return [];
1102
953
  }
1103
954
  else if (f.ValuesToPackWithSchema === 'All') {
1104
- // wants ALL of the distinct values
1105
- return await this.getFieldDistinctValues(f, dataSource);
955
+ return await this.getFieldDistinctValues(f);
1106
956
  }
1107
957
  else if (f.ValuesToPackWithSchema === 'Auto') {
1108
- // default setting - pack based on the ValueListType
1109
958
  if (f.ValueListTypeEnum === 'List') {
1110
- // simple list of values in the Entity Field Values table
1111
- return f.EntityFieldValues.map((v) => {
1112
- return { value: v.Value, displayValue: v.Value };
1113
- });
959
+ return f.EntityFieldValues.map((v) => new EntityFieldValueInfo({ Value: v.Value, Code: v.Value }));
1114
960
  }
1115
961
  else if (f.ValueListTypeEnum === 'ListOrUserEntry') {
1116
- // could be a user provided value, OR the values in the list of possible values.
1117
- // get the distinct list of values from the DB and concat that with the f.EntityFieldValues array - deduped and return
1118
- const values = await this.getFieldDistinctValues(f, dataSource);
962
+ const values = await this.getFieldDistinctValues(f);
1119
963
  if (!values || values.length === 0) {
1120
- // no result, just return the EntityFieldValues
1121
- return f.EntityFieldValues.map((v) => {
1122
- return { value: v.Value, displayValue: v.Value };
1123
- });
964
+ return f.EntityFieldValues.map((v) => new EntityFieldValueInfo({ Value: v.Value, Code: v.Value }));
1124
965
  }
1125
966
  else {
1126
- return [...new Set([...f.EntityFieldValues.map((v) => {
1127
- return { value: v.Value, displayValue: v.Value };
1128
- }), ...values])];
967
+ const fromEntityFieldValues = f.EntityFieldValues.map((v) => new EntityFieldValueInfo({ Value: v.Value, Code: v.Value }));
968
+ return [...new Set([...fromEntityFieldValues, ...values])];
1129
969
  }
1130
970
  }
1131
971
  }
1132
- return []; // if we get here, nothing to pack
972
+ return [];
1133
973
  }
1134
974
  catch (e) {
1135
- LogError(`[SkipSDK] packFieldPossibleValues error: ${e}`);
975
+ LogError(`[SkipSDK] packFieldValues error: ${e}`);
1136
976
  return [];
1137
977
  }
1138
978
  }
1139
979
 
1140
980
  /**
1141
- * Gets distinct values for a field from the database
1142
- * Used to provide Skip with information about the possible values
1143
- * Copied from AskSkipResolver.GetFieldDistinctValues
981
+ * Gets distinct values for a field from the database.
982
+ * Returns EntityFieldValueInfo objects.
1144
983
  */
1145
- private async getFieldDistinctValues(f: EntityFieldInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityFieldValueInfo[]> {
984
+ private async getFieldDistinctValues(f: EntityFieldInfo): Promise<EntityFieldValueInfo[]> {
1146
985
  try {
986
+ // Uses the provider's ExecuteSQL so this works on both SQL Server and PostgreSQL.
987
+ const provider = Metadata.Provider as DatabaseProviderBase;
1147
988
  const sql = `SELECT DISTINCT ${f.Name} FROM ${f.SchemaName}.${f.BaseView}`;
1148
- const request = new mssql.Request(dataSource);
1149
- const result = await request.query(sql);
1150
- if (!result || !result.recordset) {
989
+ const rows = await provider.ExecuteSQL<Record<string, unknown>>(sql);
990
+ if (!rows || rows.length === 0) {
1151
991
  return [];
1152
992
  }
1153
- else {
1154
- return result.recordset.map((r) => {
1155
- return {
1156
- value: r[f.Name],
1157
- displayValue: r[f.Name]
1158
- };
1159
- });
1160
- }
993
+ return rows.map((r) => new EntityFieldValueInfo({ Value: r[f.Name] as string, Code: r[f.Name] as string }));
1161
994
  }
1162
995
  catch (e) {
1163
996
  LogError(`[SkipSDK] getFieldDistinctValues error: ${e}`);
@@ -2,7 +2,6 @@ import { EntitySaveOptions, IRunReportProvider, Metadata, RunReport } from '@mem
2
2
  import { Arg, Ctx, Field, Int, Mutation, ObjectType, Query, Resolver } from 'type-graphql';
3
3
  import { AppContext } from '../types.js';
4
4
  import { MJConversationDetailEntity, MJReportEntity } from '@memberjunction/core-entities';
5
- import { SkipAPIAnalysisCompleteResponse } from '@memberjunction/skip-types';
6
5
  import { DataContext } from '@memberjunction/data-context';
7
6
  import { UserCache } from '@memberjunction/sqlserver-dataprovider';
8
7
  import { z } from 'zod';
@@ -104,7 +103,7 @@ export class ReportResolverExtended extends ResolverBase {
104
103
  const request = new mssql.Request(dataSource);
105
104
  const result = await request.query(sql);
106
105
  if (!result || !result.recordset || result.recordset.length === 0) throw new Error('Unable to retrieve converation details');
107
- const skipData = <SkipAPIAnalysisCompleteResponse>JSON.parse(result.recordset[0].Message);
106
+ const skipData: { title?: string; reportTitle?: string; userExplanation?: string; messages?: unknown[] } = JSON.parse(result.recordset[0].Message);
108
107
 
109
108
  const report = await md.GetEntityObject<MJReportEntity>('MJ: Reports', u);
110
109
  report.NewRecord();