@memberjunction/server 5.23.0 → 5.25.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/dist/agents/skip-sdk.d.ts +12 -0
- package/dist/agents/skip-sdk.d.ts.map +1 -1
- package/dist/agents/skip-sdk.js +70 -1
- package/dist/agents/skip-sdk.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -1
- package/dist/generated/generated.d.ts +954 -0
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +26108 -20749
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts +15 -0
- package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -0
- package/dist/resolvers/ArtifactFileResolver.js +74 -0
- package/dist/resolvers/ArtifactFileResolver.js.map +1 -0
- package/dist/resolvers/AutotagPipelineResolver.d.ts +23 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.js +197 -13
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
- package/dist/resolvers/FetchEntityVectorsResolver.js +6 -2
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +12 -32
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GeoResolver.d.ts +58 -0
- package/dist/resolvers/GeoResolver.d.ts.map +1 -0
- package/dist/resolvers/GeoResolver.js +302 -0
- package/dist/resolvers/GeoResolver.js.map +1 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts +34 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +183 -48
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.d.ts +23 -41
- package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.js +133 -382
- package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.d.ts +19 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.d.ts.map +1 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js +149 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js.map +1 -0
- package/package.json +63 -63
- package/src/__tests__/search-knowledge-tags.test.ts +255 -0
- package/src/__tests__/skip-sdk-organic-keys.test.ts +274 -0
- package/src/agents/skip-sdk.ts +83 -2
- package/src/config.ts +11 -0
- package/src/generated/generated.ts +3690 -1
- package/src/generic/RunViewResolver.ts +1 -0
- package/src/index.ts +2 -0
- package/src/resolvers/ArtifactFileResolver.ts +71 -0
- package/src/resolvers/AutotagPipelineResolver.ts +213 -10
- package/src/resolvers/FetchEntityVectorsResolver.ts +6 -2
- package/src/resolvers/FileResolver.ts +12 -41
- package/src/resolvers/GeoResolver.ts +258 -0
- package/src/resolvers/RunAIAgentResolver.ts +229 -76
- package/src/resolvers/SearchKnowledgeResolver.ts +118 -462
- package/src/resolvers/SearchKnowledgeSystemUserResolver.ts +138 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AppContext } from '../types.js';
|
|
2
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
3
|
+
import { SearchKnowledgeResult, SearchFiltersInput } from './SearchKnowledgeResolver.js';
|
|
4
|
+
/**
|
|
5
|
+
* System-user-only resolver for search operations. Mirrors {@link SearchKnowledgeResolver}
|
|
6
|
+
* but is gated by the `@RequireSystemUser` directive so that server-to-server callers
|
|
7
|
+
* (e.g. Skip-Brain's `RemoteMJUtilities`) can invoke search without a user JWT.
|
|
8
|
+
*
|
|
9
|
+
* Both mutations delegate directly to `SearchEngine.Instance` — the same singleton
|
|
10
|
+
* the user-context resolver uses — so behavior, scoring, and permission filtering
|
|
11
|
+
* are identical.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SearchKnowledgeSystemUserResolver extends ResolverBase {
|
|
14
|
+
SearchKnowledgeAsSystemUser(query: string, maxResults: number | undefined, filters: SearchFiltersInput | undefined, minScore: number | undefined, context: AppContext): Promise<SearchKnowledgeResult>;
|
|
15
|
+
PreviewSearchAsSystemUser(query: string, maxResults: number, context: AppContext): Promise<SearchKnowledgeResult>;
|
|
16
|
+
private mapSearchResult;
|
|
17
|
+
private errorResult;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=SearchKnowledgeSystemUserResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchKnowledgeSystemUserResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/SearchKnowledgeSystemUserResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,OAAO,EACH,qBAAqB,EAGrB,kBAAkB,EACrB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;GAQG;AACH,qBACa,iCAAkC,SAAQ,YAAY;IAIzD,2BAA2B,CACf,KAAK,EAAE,MAAM,EACyB,UAAU,EAAE,MAAM,GAAG,SAAS,EACpB,OAAO,EAAE,kBAAkB,GAAG,SAAS,EACnD,QAAQ,EAAE,MAAM,GAAG,SAAS,EACvE,OAAO,EAAE,UAAU,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IA6B3B,yBAAyB,CACb,KAAK,EAAE,MAAM,EAC0C,UAAU,EAAE,MAAM,EAChF,OAAO,EAAE,UAAU,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IAkBjC,OAAO,CAAC,eAAe;IA0CvB,OAAO,CAAC,WAAW;CAWtB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { Resolver, Mutation, Arg, Ctx, Float } from 'type-graphql';
|
|
14
|
+
import { LogError } from '@memberjunction/core';
|
|
15
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
16
|
+
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
17
|
+
import { SearchEngine } from '@memberjunction/search-engine';
|
|
18
|
+
import { SearchKnowledgeResult, SearchFiltersInput } from './SearchKnowledgeResolver.js';
|
|
19
|
+
/**
|
|
20
|
+
* System-user-only resolver for search operations. Mirrors {@link SearchKnowledgeResolver}
|
|
21
|
+
* but is gated by the `@RequireSystemUser` directive so that server-to-server callers
|
|
22
|
+
* (e.g. Skip-Brain's `RemoteMJUtilities`) can invoke search without a user JWT.
|
|
23
|
+
*
|
|
24
|
+
* Both mutations delegate directly to `SearchEngine.Instance` — the same singleton
|
|
25
|
+
* the user-context resolver uses — so behavior, scoring, and permission filtering
|
|
26
|
+
* are identical.
|
|
27
|
+
*/
|
|
28
|
+
let SearchKnowledgeSystemUserResolver = class SearchKnowledgeSystemUserResolver extends ResolverBase {
|
|
29
|
+
async SearchKnowledgeAsSystemUser(query, maxResults, filters, minScore, context) {
|
|
30
|
+
const startTime = Date.now();
|
|
31
|
+
try {
|
|
32
|
+
const currentUser = context.userPayload.userRecord;
|
|
33
|
+
if (!currentUser) {
|
|
34
|
+
return this.errorResult('Unable to determine system user', startTime);
|
|
35
|
+
}
|
|
36
|
+
const result = await SearchEngine.Instance.Search({
|
|
37
|
+
Query: query,
|
|
38
|
+
MaxResults: maxResults,
|
|
39
|
+
MinScore: minScore,
|
|
40
|
+
Filters: filters ? {
|
|
41
|
+
EntityNames: filters.EntityNames,
|
|
42
|
+
SourceTypes: filters.SourceTypes,
|
|
43
|
+
Tags: filters.Tags
|
|
44
|
+
} : undefined
|
|
45
|
+
}, currentUser);
|
|
46
|
+
return this.mapSearchResult(result);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
50
|
+
LogError(`SearchKnowledgeAsSystemUser mutation failed: ${msg}`);
|
|
51
|
+
return this.errorResult(msg, startTime);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async PreviewSearchAsSystemUser(query, maxResults, context) {
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
try {
|
|
57
|
+
const currentUser = context.userPayload.userRecord;
|
|
58
|
+
if (!currentUser) {
|
|
59
|
+
return this.errorResult('Unable to determine system user', startTime);
|
|
60
|
+
}
|
|
61
|
+
const result = await SearchEngine.Instance.PreviewSearch(query, maxResults, currentUser);
|
|
62
|
+
return this.mapSearchResult(result);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
66
|
+
LogError(`PreviewSearchAsSystemUser mutation failed: ${msg}`);
|
|
67
|
+
return this.errorResult(msg, startTime);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
mapSearchResult(result) {
|
|
71
|
+
return {
|
|
72
|
+
Success: result.Success,
|
|
73
|
+
Results: result.Results.map((r) => ({
|
|
74
|
+
ID: r.ID,
|
|
75
|
+
EntityName: r.EntityName,
|
|
76
|
+
RecordID: r.RecordID,
|
|
77
|
+
SourceType: r.SourceType,
|
|
78
|
+
ResultType: r.ResultType,
|
|
79
|
+
Title: r.Title,
|
|
80
|
+
Snippet: r.Snippet,
|
|
81
|
+
Score: r.Score,
|
|
82
|
+
ScoreBreakdown: r.ScoreBreakdown,
|
|
83
|
+
Tags: r.Tags || [],
|
|
84
|
+
EntityIcon: r.EntityIcon,
|
|
85
|
+
RecordName: r.RecordName,
|
|
86
|
+
MatchedAt: r.MatchedAt,
|
|
87
|
+
RawMetadata: r.RawMetadata,
|
|
88
|
+
ProviderId: r.ProviderId,
|
|
89
|
+
ProviderLabel: r.ProviderLabel,
|
|
90
|
+
ProviderIcon: r.ProviderIcon,
|
|
91
|
+
})),
|
|
92
|
+
TotalCount: result.TotalCount,
|
|
93
|
+
ElapsedMs: result.ElapsedMs,
|
|
94
|
+
SourceCounts: {
|
|
95
|
+
Vector: result.SourceCounts.Vector,
|
|
96
|
+
FullText: result.SourceCounts.FullText,
|
|
97
|
+
Entity: result.SourceCounts.Entity,
|
|
98
|
+
Storage: result.SourceCounts.Storage,
|
|
99
|
+
},
|
|
100
|
+
Providers: (result.Providers || []).map((p) => ({
|
|
101
|
+
ID: p.ID,
|
|
102
|
+
Name: p.Name,
|
|
103
|
+
DisplayName: p.DisplayName,
|
|
104
|
+
Icon: p.Icon,
|
|
105
|
+
SourceType: p.SourceType,
|
|
106
|
+
Priority: p.Priority,
|
|
107
|
+
})),
|
|
108
|
+
ErrorMessage: result.ErrorMessage,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
errorResult(message, startTime) {
|
|
112
|
+
return {
|
|
113
|
+
Success: false,
|
|
114
|
+
Results: [],
|
|
115
|
+
TotalCount: 0,
|
|
116
|
+
ElapsedMs: Date.now() - startTime,
|
|
117
|
+
SourceCounts: { Vector: 0, FullText: 0, Entity: 0, Storage: 0 },
|
|
118
|
+
Providers: [],
|
|
119
|
+
ErrorMessage: message
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
__decorate([
|
|
124
|
+
RequireSystemUser(),
|
|
125
|
+
Mutation(() => SearchKnowledgeResult),
|
|
126
|
+
__param(0, Arg('query')),
|
|
127
|
+
__param(1, Arg('maxResults', () => Float, { nullable: true })),
|
|
128
|
+
__param(2, Arg('filters', () => SearchFiltersInput, { nullable: true })),
|
|
129
|
+
__param(3, Arg('minScore', () => Float, { nullable: true })),
|
|
130
|
+
__param(4, Ctx()),
|
|
131
|
+
__metadata("design:type", Function),
|
|
132
|
+
__metadata("design:paramtypes", [String, Number, SearchFiltersInput, Number, Object]),
|
|
133
|
+
__metadata("design:returntype", Promise)
|
|
134
|
+
], SearchKnowledgeSystemUserResolver.prototype, "SearchKnowledgeAsSystemUser", null);
|
|
135
|
+
__decorate([
|
|
136
|
+
RequireSystemUser(),
|
|
137
|
+
Mutation(() => SearchKnowledgeResult),
|
|
138
|
+
__param(0, Arg('query')),
|
|
139
|
+
__param(1, Arg('maxResults', () => Float, { nullable: true, defaultValue: 8 })),
|
|
140
|
+
__param(2, Ctx()),
|
|
141
|
+
__metadata("design:type", Function),
|
|
142
|
+
__metadata("design:paramtypes", [String, Number, Object]),
|
|
143
|
+
__metadata("design:returntype", Promise)
|
|
144
|
+
], SearchKnowledgeSystemUserResolver.prototype, "PreviewSearchAsSystemUser", null);
|
|
145
|
+
SearchKnowledgeSystemUserResolver = __decorate([
|
|
146
|
+
Resolver()
|
|
147
|
+
], SearchKnowledgeSystemUserResolver);
|
|
148
|
+
export { SearchKnowledgeSystemUserResolver };
|
|
149
|
+
//# sourceMappingURL=SearchKnowledgeSystemUserResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchKnowledgeSystemUserResolver.js","sourceRoot":"","sources":["../../src/resolvers/SearchKnowledgeSystemUserResolver.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/server",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.25.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,68 +27,68 @@
|
|
|
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.
|
|
31
|
-
"@memberjunction/actions-apollo": "5.
|
|
32
|
-
"@memberjunction/actions-base": "5.
|
|
33
|
-
"@memberjunction/actions-bizapps-accounting": "5.
|
|
34
|
-
"@memberjunction/actions-bizapps-crm": "5.
|
|
35
|
-
"@memberjunction/actions-bizapps-formbuilders": "5.
|
|
36
|
-
"@memberjunction/actions-bizapps-lms": "5.
|
|
37
|
-
"@memberjunction/actions-bizapps-social": "5.
|
|
38
|
-
"@memberjunction/ai": "5.
|
|
39
|
-
"@memberjunction/ai-agent-manager": "5.
|
|
40
|
-
"@memberjunction/ai-agent-manager-actions": "5.
|
|
41
|
-
"@memberjunction/ai-agents": "5.
|
|
42
|
-
"@memberjunction/ai-core-plus": "5.
|
|
43
|
-
"@memberjunction/ai-mcp-client": "5.
|
|
44
|
-
"@memberjunction/ai-prompts": "5.
|
|
45
|
-
"@memberjunction/ai-provider-bundle": "5.
|
|
46
|
-
"@memberjunction/ai-vector-sync": "5.
|
|
47
|
-
"@memberjunction/ai-vectors-pinecone": "5.
|
|
48
|
-
"@memberjunction/aiengine": "5.
|
|
49
|
-
"@memberjunction/api-keys": "5.
|
|
50
|
-
"@memberjunction/auth-providers": "5.
|
|
51
|
-
"@memberjunction/codegen-lib": "5.
|
|
52
|
-
"@memberjunction/communication-ms-graph": "5.
|
|
53
|
-
"@memberjunction/communication-sendgrid": "5.
|
|
54
|
-
"@memberjunction/communication-types": "5.
|
|
55
|
-
"@memberjunction/component-registry-client-sdk": "5.
|
|
56
|
-
"@memberjunction/computer-use-engine": "5.
|
|
57
|
-
"@memberjunction/config": "5.
|
|
58
|
-
"@memberjunction/core": "5.
|
|
59
|
-
"@memberjunction/core-actions": "5.
|
|
60
|
-
"@memberjunction/core-entities": "5.
|
|
61
|
-
"@memberjunction/core-entities-server": "5.
|
|
62
|
-
"@memberjunction/data-context": "5.
|
|
63
|
-
"@memberjunction/data-context-server": "5.
|
|
64
|
-
"@memberjunction/doc-utils": "5.
|
|
65
|
-
"@memberjunction/encryption": "5.
|
|
66
|
-
"@memberjunction/entity-communications-base": "5.
|
|
67
|
-
"@memberjunction/entity-communications-server": "5.
|
|
68
|
-
"@memberjunction/external-change-detection": "5.
|
|
69
|
-
"@memberjunction/generic-database-provider": "5.
|
|
70
|
-
"@memberjunction/global": "5.
|
|
71
|
-
"@memberjunction/graphql-dataprovider": "5.
|
|
72
|
-
"@memberjunction/integration-engine": "5.
|
|
73
|
-
"@memberjunction/integration-schema-builder": "5.
|
|
74
|
-
"@memberjunction/interactive-component-types": "5.
|
|
75
|
-
"@memberjunction/notifications": "5.
|
|
76
|
-
"@memberjunction/postgresql-dataprovider": "5.
|
|
77
|
-
"@memberjunction/queue": "5.
|
|
78
|
-
"@memberjunction/redis-provider": "5.
|
|
79
|
-
"@memberjunction/scheduling-actions": "5.
|
|
80
|
-
"@memberjunction/scheduling-base-types": "5.
|
|
81
|
-
"@memberjunction/scheduling-engine": "5.
|
|
82
|
-
"@memberjunction/scheduling-engine-base": "5.
|
|
83
|
-
"@memberjunction/server-extensions-core": "5.
|
|
84
|
-
"@memberjunction/skip-types": "5.
|
|
85
|
-
"@memberjunction/sql-dialect": "5.
|
|
86
|
-
"@memberjunction/sqlserver-dataprovider": "5.
|
|
87
|
-
"@memberjunction/storage": "5.
|
|
88
|
-
"@memberjunction/templates": "5.
|
|
89
|
-
"@memberjunction/testing-engine": "5.
|
|
90
|
-
"@memberjunction/testing-engine-base": "5.
|
|
91
|
-
"@memberjunction/version-history": "5.
|
|
30
|
+
"@memberjunction/actions": "5.25.0",
|
|
31
|
+
"@memberjunction/actions-apollo": "5.25.0",
|
|
32
|
+
"@memberjunction/actions-base": "5.25.0",
|
|
33
|
+
"@memberjunction/actions-bizapps-accounting": "5.25.0",
|
|
34
|
+
"@memberjunction/actions-bizapps-crm": "5.25.0",
|
|
35
|
+
"@memberjunction/actions-bizapps-formbuilders": "5.25.0",
|
|
36
|
+
"@memberjunction/actions-bizapps-lms": "5.25.0",
|
|
37
|
+
"@memberjunction/actions-bizapps-social": "5.25.0",
|
|
38
|
+
"@memberjunction/ai": "5.25.0",
|
|
39
|
+
"@memberjunction/ai-agent-manager": "5.25.0",
|
|
40
|
+
"@memberjunction/ai-agent-manager-actions": "5.25.0",
|
|
41
|
+
"@memberjunction/ai-agents": "5.25.0",
|
|
42
|
+
"@memberjunction/ai-core-plus": "5.25.0",
|
|
43
|
+
"@memberjunction/ai-mcp-client": "5.25.0",
|
|
44
|
+
"@memberjunction/ai-prompts": "5.25.0",
|
|
45
|
+
"@memberjunction/ai-provider-bundle": "5.25.0",
|
|
46
|
+
"@memberjunction/ai-vector-sync": "5.25.0",
|
|
47
|
+
"@memberjunction/ai-vectors-pinecone": "5.25.0",
|
|
48
|
+
"@memberjunction/aiengine": "5.25.0",
|
|
49
|
+
"@memberjunction/api-keys": "5.25.0",
|
|
50
|
+
"@memberjunction/auth-providers": "5.25.0",
|
|
51
|
+
"@memberjunction/codegen-lib": "5.25.0",
|
|
52
|
+
"@memberjunction/communication-ms-graph": "5.25.0",
|
|
53
|
+
"@memberjunction/communication-sendgrid": "5.25.0",
|
|
54
|
+
"@memberjunction/communication-types": "5.25.0",
|
|
55
|
+
"@memberjunction/component-registry-client-sdk": "5.25.0",
|
|
56
|
+
"@memberjunction/computer-use-engine": "5.25.0",
|
|
57
|
+
"@memberjunction/config": "5.25.0",
|
|
58
|
+
"@memberjunction/core": "5.25.0",
|
|
59
|
+
"@memberjunction/core-actions": "5.25.0",
|
|
60
|
+
"@memberjunction/core-entities": "5.25.0",
|
|
61
|
+
"@memberjunction/core-entities-server": "5.25.0",
|
|
62
|
+
"@memberjunction/data-context": "5.25.0",
|
|
63
|
+
"@memberjunction/data-context-server": "5.25.0",
|
|
64
|
+
"@memberjunction/doc-utils": "5.25.0",
|
|
65
|
+
"@memberjunction/encryption": "5.25.0",
|
|
66
|
+
"@memberjunction/entity-communications-base": "5.25.0",
|
|
67
|
+
"@memberjunction/entity-communications-server": "5.25.0",
|
|
68
|
+
"@memberjunction/external-change-detection": "5.25.0",
|
|
69
|
+
"@memberjunction/generic-database-provider": "5.25.0",
|
|
70
|
+
"@memberjunction/global": "5.25.0",
|
|
71
|
+
"@memberjunction/graphql-dataprovider": "5.25.0",
|
|
72
|
+
"@memberjunction/integration-engine": "5.25.0",
|
|
73
|
+
"@memberjunction/integration-schema-builder": "5.25.0",
|
|
74
|
+
"@memberjunction/interactive-component-types": "5.25.0",
|
|
75
|
+
"@memberjunction/notifications": "5.25.0",
|
|
76
|
+
"@memberjunction/postgresql-dataprovider": "5.25.0",
|
|
77
|
+
"@memberjunction/queue": "5.25.0",
|
|
78
|
+
"@memberjunction/redis-provider": "5.25.0",
|
|
79
|
+
"@memberjunction/scheduling-actions": "5.25.0",
|
|
80
|
+
"@memberjunction/scheduling-base-types": "5.25.0",
|
|
81
|
+
"@memberjunction/scheduling-engine": "5.25.0",
|
|
82
|
+
"@memberjunction/scheduling-engine-base": "5.25.0",
|
|
83
|
+
"@memberjunction/server-extensions-core": "5.25.0",
|
|
84
|
+
"@memberjunction/skip-types": "5.25.0",
|
|
85
|
+
"@memberjunction/sql-dialect": "5.25.0",
|
|
86
|
+
"@memberjunction/sqlserver-dataprovider": "5.25.0",
|
|
87
|
+
"@memberjunction/storage": "5.25.0",
|
|
88
|
+
"@memberjunction/templates": "5.25.0",
|
|
89
|
+
"@memberjunction/testing-engine": "5.25.0",
|
|
90
|
+
"@memberjunction/testing-engine-base": "5.25.0",
|
|
91
|
+
"@memberjunction/version-history": "5.25.0",
|
|
92
92
|
"@types/compression": "^1.8.1",
|
|
93
93
|
"@types/cors": "^2.8.19",
|
|
94
94
|
"@types/jsonwebtoken": "9.0.10",
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tests for SearchKnowledgeResolver — the thin wrapper that delegates
|
|
5
|
+
* to SearchEngine.Instance.Search() and maps results to GraphQL types.
|
|
6
|
+
*
|
|
7
|
+
* The actual search logic (providers, fusion, enrichment, permissions)
|
|
8
|
+
* is tested in the @memberjunction/search-engine package.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ── Mocks ──────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const { mockSearch, mockPreviewSearch } = vi.hoisted(() => ({
|
|
14
|
+
mockSearch: vi.fn(),
|
|
15
|
+
mockPreviewSearch: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
vi.mock('@memberjunction/search-engine', () => ({
|
|
19
|
+
SearchEngine: {
|
|
20
|
+
Instance: {
|
|
21
|
+
Config: vi.fn().mockResolvedValue(undefined),
|
|
22
|
+
Search: (...args: unknown[]) => mockSearch(...args),
|
|
23
|
+
PreviewSearch: (...args: unknown[]) => mockPreviewSearch(...args),
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
vi.mock('@memberjunction/global', async (importOriginal) => {
|
|
29
|
+
const actual = await importOriginal<Record<string, unknown>>();
|
|
30
|
+
return { ...actual };
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
vi.mock('@memberjunction/core', async (importOriginal) => {
|
|
34
|
+
const actual = await importOriginal<Record<string, unknown>>();
|
|
35
|
+
return {
|
|
36
|
+
...actual,
|
|
37
|
+
LogError: vi.fn(),
|
|
38
|
+
LogStatus: vi.fn(),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
vi.mock('@memberjunction/core-entities', async (importOriginal) => {
|
|
43
|
+
const actual = await importOriginal<Record<string, unknown>>();
|
|
44
|
+
return { ...actual };
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Mock type-graphql to avoid reflect-metadata dependency
|
|
48
|
+
vi.mock('type-graphql', () => {
|
|
49
|
+
const noop = () => () => undefined;
|
|
50
|
+
const passthrough = () => (target: unknown) => target;
|
|
51
|
+
return {
|
|
52
|
+
Resolver: passthrough,
|
|
53
|
+
Mutation: noop,
|
|
54
|
+
Query: noop,
|
|
55
|
+
Subscription: noop,
|
|
56
|
+
Arg: noop,
|
|
57
|
+
Args: noop,
|
|
58
|
+
Ctx: noop,
|
|
59
|
+
ObjectType: passthrough,
|
|
60
|
+
InputType: passthrough,
|
|
61
|
+
ArgsType: passthrough,
|
|
62
|
+
Field: noop,
|
|
63
|
+
Float: Number,
|
|
64
|
+
Int: Number,
|
|
65
|
+
ID: String,
|
|
66
|
+
Authorized: noop,
|
|
67
|
+
PubSub: noop,
|
|
68
|
+
Root: noop,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// ── Import after mocks ─────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
import { SearchKnowledgeResolver } from '../resolvers/SearchKnowledgeResolver.js';
|
|
75
|
+
|
|
76
|
+
// ── Helpers ─────────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
function createResolver(): SearchKnowledgeResolver {
|
|
79
|
+
const resolver = new SearchKnowledgeResolver();
|
|
80
|
+
// Mock GetUserFromPayload to return a fake user
|
|
81
|
+
(resolver as Record<string, unknown>)['GetUserFromPayload'] = vi.fn().mockReturnValue({
|
|
82
|
+
ID: 'test-user-id',
|
|
83
|
+
Email: 'test@test.com',
|
|
84
|
+
Name: 'Test User'
|
|
85
|
+
});
|
|
86
|
+
return resolver;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function createMockSearchResult(overrides: Record<string, unknown> = {}) {
|
|
90
|
+
return {
|
|
91
|
+
Success: true,
|
|
92
|
+
Results: [
|
|
93
|
+
{
|
|
94
|
+
ID: 'result-1',
|
|
95
|
+
EntityName: 'Contacts',
|
|
96
|
+
RecordID: 'abc-123',
|
|
97
|
+
SourceType: 'entity',
|
|
98
|
+
ResultType: 'entity-record',
|
|
99
|
+
Title: 'John Smith',
|
|
100
|
+
Snippet: 'A contact record',
|
|
101
|
+
Score: 0.85,
|
|
102
|
+
ScoreBreakdown: { Entity: 0.85 },
|
|
103
|
+
Tags: ['VIP'],
|
|
104
|
+
EntityIcon: 'fa-solid fa-user',
|
|
105
|
+
RecordName: 'John Smith',
|
|
106
|
+
MatchedAt: new Date(),
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
TotalCount: 1,
|
|
110
|
+
ElapsedMs: 42,
|
|
111
|
+
SourceCounts: { Vector: 0, FullText: 0, Entity: 1, Storage: 0 },
|
|
112
|
+
...overrides
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fakeContext = { userPayload: { email: 'test@test.com' } };
|
|
117
|
+
|
|
118
|
+
// ── Tests ───────────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
describe('SearchKnowledgeResolver', () => {
|
|
121
|
+
beforeEach(() => {
|
|
122
|
+
vi.clearAllMocks();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('SearchKnowledge mutation', () => {
|
|
126
|
+
it('should delegate to SearchEngine.Instance.Search()', async () => {
|
|
127
|
+
const resolver = createResolver();
|
|
128
|
+
mockSearch.mockResolvedValueOnce(createMockSearchResult());
|
|
129
|
+
|
|
130
|
+
const result = await resolver.SearchKnowledge('test query', 20, undefined, undefined, fakeContext as never);
|
|
131
|
+
|
|
132
|
+
expect(mockSearch).toHaveBeenCalledOnce();
|
|
133
|
+
expect(result.Success).toBe(true);
|
|
134
|
+
expect(result.TotalCount).toBe(1);
|
|
135
|
+
expect(result.Results).toHaveLength(1);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should pass query and maxResults to SearchEngine', async () => {
|
|
139
|
+
const resolver = createResolver();
|
|
140
|
+
mockSearch.mockResolvedValueOnce(createMockSearchResult());
|
|
141
|
+
|
|
142
|
+
await resolver.SearchKnowledge('cheese', 50, undefined, undefined, fakeContext as never);
|
|
143
|
+
|
|
144
|
+
const searchParams = mockSearch.mock.calls[0][0];
|
|
145
|
+
expect(searchParams.Query).toBe('cheese');
|
|
146
|
+
expect(searchParams.MaxResults).toBe(50);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should pass filters when provided', async () => {
|
|
150
|
+
const resolver = createResolver();
|
|
151
|
+
mockSearch.mockResolvedValueOnce(createMockSearchResult());
|
|
152
|
+
|
|
153
|
+
const filters = { EntityNames: ['Contacts'], SourceTypes: undefined, Tags: ['VIP'] };
|
|
154
|
+
await resolver.SearchKnowledge('test', 20, filters as never, undefined, fakeContext as never);
|
|
155
|
+
|
|
156
|
+
const searchParams = mockSearch.mock.calls[0][0];
|
|
157
|
+
expect(searchParams.Filters).toEqual({
|
|
158
|
+
EntityNames: ['Contacts'],
|
|
159
|
+
SourceTypes: undefined,
|
|
160
|
+
Tags: ['VIP']
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should pass minScore when provided', async () => {
|
|
165
|
+
const resolver = createResolver();
|
|
166
|
+
mockSearch.mockResolvedValueOnce(createMockSearchResult());
|
|
167
|
+
|
|
168
|
+
await resolver.SearchKnowledge('test', 20, undefined, 0.5, fakeContext as never);
|
|
169
|
+
|
|
170
|
+
const searchParams = mockSearch.mock.calls[0][0];
|
|
171
|
+
expect(searchParams.MinScore).toBe(0.5);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should map result fields correctly', async () => {
|
|
175
|
+
const resolver = createResolver();
|
|
176
|
+
mockSearch.mockResolvedValueOnce(createMockSearchResult());
|
|
177
|
+
|
|
178
|
+
const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
|
|
179
|
+
|
|
180
|
+
const item = result.Results[0];
|
|
181
|
+
expect(item.ID).toBe('result-1');
|
|
182
|
+
expect(item.EntityName).toBe('Contacts');
|
|
183
|
+
expect(item.RecordID).toBe('abc-123');
|
|
184
|
+
expect(item.Title).toBe('John Smith');
|
|
185
|
+
expect(item.Score).toBe(0.85);
|
|
186
|
+
expect(item.Tags).toEqual(['VIP']);
|
|
187
|
+
expect(item.EntityIcon).toBe('fa-solid fa-user');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should map source counts correctly', async () => {
|
|
191
|
+
const resolver = createResolver();
|
|
192
|
+
mockSearch.mockResolvedValueOnce(createMockSearchResult({
|
|
193
|
+
SourceCounts: { Vector: 5, FullText: 3, Entity: 10, Storage: 0 }
|
|
194
|
+
}));
|
|
195
|
+
|
|
196
|
+
const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
|
|
197
|
+
|
|
198
|
+
expect(result.SourceCounts.Vector).toBe(5);
|
|
199
|
+
expect(result.SourceCounts.FullText).toBe(3);
|
|
200
|
+
expect(result.SourceCounts.Entity).toBe(10);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should pass empty query through to SearchEngine (validation happens there)', async () => {
|
|
204
|
+
const resolver = createResolver();
|
|
205
|
+
mockSearch.mockResolvedValueOnce(createMockSearchResult({ Success: false, ErrorMessage: 'Query cannot be empty' }));
|
|
206
|
+
|
|
207
|
+
const result = await resolver.SearchKnowledge(' ', 20, undefined, undefined, fakeContext as never);
|
|
208
|
+
|
|
209
|
+
expect(mockSearch).toHaveBeenCalled();
|
|
210
|
+
expect(result.Success).toBe(false);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should return error when user cannot be determined', async () => {
|
|
214
|
+
const resolver = new SearchKnowledgeResolver();
|
|
215
|
+
(resolver as Record<string, unknown>)['GetUserFromPayload'] = vi.fn().mockReturnValue(null);
|
|
216
|
+
|
|
217
|
+
const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
|
|
218
|
+
|
|
219
|
+
expect(result.Success).toBe(false);
|
|
220
|
+
expect(result.ErrorMessage).toContain('current user');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should handle SearchEngine errors gracefully', async () => {
|
|
224
|
+
const resolver = createResolver();
|
|
225
|
+
mockSearch.mockRejectedValueOnce(new Error('Connection failed'));
|
|
226
|
+
|
|
227
|
+
const result = await resolver.SearchKnowledge('test', 20, undefined, undefined, fakeContext as never);
|
|
228
|
+
|
|
229
|
+
expect(result.Success).toBe(false);
|
|
230
|
+
expect(result.ErrorMessage).toContain('Connection failed');
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe('PreviewSearch mutation', () => {
|
|
235
|
+
it('should delegate to SearchEngine.Instance.PreviewSearch()', async () => {
|
|
236
|
+
const resolver = createResolver();
|
|
237
|
+
mockPreviewSearch.mockResolvedValueOnce(createMockSearchResult());
|
|
238
|
+
|
|
239
|
+
const result = await resolver.PreviewSearch('test', 8, fakeContext as never);
|
|
240
|
+
|
|
241
|
+
expect(mockPreviewSearch).toHaveBeenCalledOnce();
|
|
242
|
+
expect(mockPreviewSearch).toHaveBeenCalledWith('test', 8, expect.anything());
|
|
243
|
+
expect(result.Success).toBe(true);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should default maxResults to 8', async () => {
|
|
247
|
+
const resolver = createResolver();
|
|
248
|
+
mockPreviewSearch.mockResolvedValueOnce(createMockSearchResult());
|
|
249
|
+
|
|
250
|
+
await resolver.PreviewSearch('test', 8, fakeContext as never);
|
|
251
|
+
|
|
252
|
+
expect(mockPreviewSearch).toHaveBeenCalledWith('test', 8, expect.anything());
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|