@memberjunction/search-engine 0.0.1 → 5.26.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 (42) hide show
  1. package/dist/generic/EntitySearchProvider.d.ts +54 -0
  2. package/dist/generic/EntitySearchProvider.d.ts.map +1 -0
  3. package/dist/generic/EntitySearchProvider.js +207 -0
  4. package/dist/generic/EntitySearchProvider.js.map +1 -0
  5. package/dist/generic/FullTextSearchProvider.d.ts +35 -0
  6. package/dist/generic/FullTextSearchProvider.d.ts.map +1 -0
  7. package/dist/generic/FullTextSearchProvider.js +89 -0
  8. package/dist/generic/FullTextSearchProvider.js.map +1 -0
  9. package/dist/generic/ISearchProvider.d.ts +90 -0
  10. package/dist/generic/ISearchProvider.d.ts.map +1 -0
  11. package/dist/generic/ISearchProvider.js +62 -0
  12. package/dist/generic/ISearchProvider.js.map +1 -0
  13. package/dist/generic/SearchEngine.d.ts +140 -0
  14. package/dist/generic/SearchEngine.d.ts.map +1 -0
  15. package/dist/generic/SearchEngine.js +446 -0
  16. package/dist/generic/SearchEngine.js.map +1 -0
  17. package/dist/generic/SearchEnricher.d.ts +69 -0
  18. package/dist/generic/SearchEnricher.d.ts.map +1 -0
  19. package/dist/generic/SearchEnricher.js +241 -0
  20. package/dist/generic/SearchEnricher.js.map +1 -0
  21. package/dist/generic/SearchFusion.d.ts +62 -0
  22. package/dist/generic/SearchFusion.d.ts.map +1 -0
  23. package/dist/generic/SearchFusion.js +147 -0
  24. package/dist/generic/SearchFusion.js.map +1 -0
  25. package/dist/generic/StorageSearchProvider.d.ts +87 -0
  26. package/dist/generic/StorageSearchProvider.d.ts.map +1 -0
  27. package/dist/generic/StorageSearchProvider.js +322 -0
  28. package/dist/generic/StorageSearchProvider.js.map +1 -0
  29. package/dist/generic/VectorSearchProvider.d.ts +65 -0
  30. package/dist/generic/VectorSearchProvider.d.ts.map +1 -0
  31. package/dist/generic/VectorSearchProvider.js +347 -0
  32. package/dist/generic/VectorSearchProvider.js.map +1 -0
  33. package/dist/generic/search.types.d.ts +151 -0
  34. package/dist/generic/search.types.d.ts.map +1 -0
  35. package/dist/generic/search.types.js +11 -0
  36. package/dist/generic/search.types.js.map +1 -0
  37. package/dist/index.d.ts +10 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +10 -0
  40. package/dist/index.js.map +1 -0
  41. package/package.json +32 -7
  42. package/README.md +0 -45
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @fileoverview Entity search provider using RunView with UserSearchString.
3
+ *
4
+ * Searches entities where AllowUserSearchAPI=true using the database-native
5
+ * LIKE-based search infrastructure. Returns scored candidates suitable for
6
+ * RRF fusion with vector and full-text results.
7
+ *
8
+ * @module @memberjunction/search-engine
9
+ */
10
+ import { UserInfo } from '@memberjunction/core';
11
+ import { BaseSearchProvider } from './ISearchProvider.js';
12
+ import { SearchSource, SearchFilters, SearchResultItem } from './search.types.js';
13
+ /**
14
+ * Provides entity-level LIKE-based search using RunView + UserSearchString.
15
+ * Searches all entities where AllowUserSearchAPI=true, returning results
16
+ * with rank-based scores.
17
+ */
18
+ export declare class EntitySearchProvider extends BaseSearchProvider {
19
+ readonly SourceType: SearchSource;
20
+ /**
21
+ * Execute an entity search across all entities with AllowUserSearchAPI=true.
22
+ *
23
+ * @param query - The search query text
24
+ * @param topK - Maximum number of results per entity
25
+ * @param filters - Optional filters (EntityNames to restrict search scope)
26
+ * @param contextUser - The user performing the search
27
+ * @returns Scored result items from entity search
28
+ */
29
+ Search(query: string, topK: number, filters: SearchFilters | undefined, contextUser: UserInfo): Promise<SearchResultItem[]>;
30
+ /**
31
+ * Get the list of entities eligible for search, optionally filtered by name.
32
+ */
33
+ private getSearchableEntities;
34
+ /**
35
+ * Search a single entity using RunView with UserSearchString.
36
+ */
37
+ private searchOneEntity;
38
+ /**
39
+ * Convert RunView results to SearchResultItem format with field-match relevance scores.
40
+ * Score is based on how many searchable fields contain the query and whether
41
+ * the match is in a name/title field (higher weight) vs description/other fields.
42
+ */
43
+ private convertResults;
44
+ /**
45
+ * Extract a display title from record data using entity metadata.
46
+ * Combines IsNameField fields in Sequence order.
47
+ */
48
+ private extractTitle;
49
+ /**
50
+ * Extract a display snippet from record data using entity metadata.
51
+ */
52
+ private extractSnippet;
53
+ }
54
+ //# sourceMappingURL=EntitySearchProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntitySearchProvider.d.ts","sourceRoot":"","sources":["../../src/generic/EntitySearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAA0C,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAExF,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAoB,MAAM,gBAAgB,CAAC;AAEjG;;;;GAIG;AACH,qBACa,oBAAqB,SAAQ,kBAAkB;IACxD,SAAgB,UAAU,EAAE,YAAY,CAAY;IAEpD;;;;;;;;OAQG;IACU,MAAM,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAyC9B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;YACW,eAAe;IA4B7B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAwDtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAmCpB;;OAEG;IACH,OAAO,CAAC,cAAc;CAczB"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * @fileoverview Entity search provider using RunView with UserSearchString.
3
+ *
4
+ * Searches entities where AllowUserSearchAPI=true using the database-native
5
+ * LIKE-based search infrastructure. Returns scored candidates suitable for
6
+ * RRF fusion with vector and full-text results.
7
+ *
8
+ * @module @memberjunction/search-engine
9
+ */
10
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
11
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13
+ 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;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ import { LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
17
+ import { RegisterClass } from '@memberjunction/global';
18
+ import { BaseSearchProvider } from './ISearchProvider.js';
19
+ /**
20
+ * Provides entity-level LIKE-based search using RunView + UserSearchString.
21
+ * Searches all entities where AllowUserSearchAPI=true, returning results
22
+ * with rank-based scores.
23
+ */
24
+ let EntitySearchProvider = class EntitySearchProvider extends BaseSearchProvider {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.SourceType = 'entity';
28
+ }
29
+ /**
30
+ * Execute an entity search across all entities with AllowUserSearchAPI=true.
31
+ *
32
+ * @param query - The search query text
33
+ * @param topK - Maximum number of results per entity
34
+ * @param filters - Optional filters (EntityNames to restrict search scope)
35
+ * @param contextUser - The user performing the search
36
+ * @returns Scored result items from entity search
37
+ */
38
+ async Search(query, topK, filters, contextUser) {
39
+ try {
40
+ const md = new Metadata();
41
+ const searchableEntities = this.getSearchableEntities(md, filters);
42
+ if (searchableEntities.length === 0) {
43
+ LogStatus('EntitySearchProvider: No searchable entities found');
44
+ return [];
45
+ }
46
+ // Debug: log searchable entities and their search fields
47
+ LogStatus(`EntitySearchProvider: Searching ${searchableEntities.length} entities for "${query}"`);
48
+ for (const e of searchableEntities.slice(0, 3)) {
49
+ const entity = md.Entities.find(ent => ent.Name === e.Name);
50
+ if (entity) {
51
+ const searchFields = entity.Fields.filter(f => f.IncludeInUserSearchAPI);
52
+ LogStatus(` Entity "${e.Name}": ${searchFields.length} searchable fields [${searchFields.slice(0, 5).map(f => f.Name).join(', ')}${searchFields.length > 5 ? '...' : ''}]`);
53
+ }
54
+ }
55
+ // Calculate per-entity limit: distribute topK across entities
56
+ const perEntityLimit = Math.max(3, Math.ceil(topK / Math.max(1, searchableEntities.length)));
57
+ // Search all entities in parallel
58
+ const searchPromises = searchableEntities.map(entity => this.searchOneEntity(entity.Name, query, perEntityLimit, contextUser));
59
+ const results = await Promise.all(searchPromises);
60
+ const allResults = results.flat();
61
+ // Sort by score descending and limit to topK
62
+ allResults.sort((a, b) => b.Score - a.Score);
63
+ return allResults.slice(0, topK);
64
+ }
65
+ catch (error) {
66
+ const msg = error instanceof Error ? error.message : String(error);
67
+ LogError(`EntitySearchProvider: Search failed: ${msg}`);
68
+ return [];
69
+ }
70
+ }
71
+ /**
72
+ * Get the list of entities eligible for search, optionally filtered by name.
73
+ */
74
+ getSearchableEntities(md, filters) {
75
+ let entities = md.Entities.filter(e => e.AllowUserSearchAPI);
76
+ if (filters?.EntityNames?.length) {
77
+ const allowedNames = new Set(filters.EntityNames.map(n => n.toLowerCase()));
78
+ entities = entities.filter(e => allowedNames.has(e.Name.toLowerCase()));
79
+ }
80
+ return entities;
81
+ }
82
+ /**
83
+ * Search a single entity using RunView with UserSearchString.
84
+ */
85
+ async searchOneEntity(entityName, query, maxRows, contextUser) {
86
+ try {
87
+ const rv = new RunView();
88
+ const result = await rv.RunView({
89
+ EntityName: entityName,
90
+ UserSearchString: query,
91
+ MaxRows: maxRows,
92
+ ResultType: 'simple'
93
+ }, contextUser);
94
+ if (!result.Success) {
95
+ LogError(`EntitySearchProvider: Failed to search "${entityName}": ${result.ErrorMessage}`);
96
+ return [];
97
+ }
98
+ return this.convertResults(result.Results, entityName, query);
99
+ }
100
+ catch (error) {
101
+ const msg = error instanceof Error ? error.message : String(error);
102
+ LogError(`EntitySearchProvider: Error searching "${entityName}": ${msg}`);
103
+ return [];
104
+ }
105
+ }
106
+ /**
107
+ * Convert RunView results to SearchResultItem format with field-match relevance scores.
108
+ * Score is based on how many searchable fields contain the query and whether
109
+ * the match is in a name/title field (higher weight) vs description/other fields.
110
+ */
111
+ convertResults(records, entityName, query) {
112
+ const md = new Metadata();
113
+ const entityInfo = md.Entities.find(e => e.Name === entityName);
114
+ const queryLower = query.toLowerCase();
115
+ // Get searchable fields and classify them by importance
116
+ const searchFields = entityInfo?.Fields.filter(f => f.IncludeInUserSearchAPI) ?? [];
117
+ const nameFields = searchFields.filter(f => f.IsNameField);
118
+ const totalSearchableFields = Math.max(searchFields.length, 1);
119
+ return records.map((record) => {
120
+ const recordID = String(record.ID ?? '');
121
+ const title = this.extractTitle(record, entityInfo);
122
+ const snippet = this.extractSnippet(record, entityInfo);
123
+ // Calculate relevance: check how many fields match the query
124
+ let matchedFields = 0;
125
+ let nameFieldMatch = false;
126
+ for (const field of searchFields) {
127
+ const val = record[field.Name];
128
+ if (val != null && String(val).toLowerCase().includes(queryLower)) {
129
+ matchedFields++;
130
+ if (nameFields.some(nf => nf.Name === field.Name)) {
131
+ nameFieldMatch = true;
132
+ }
133
+ }
134
+ }
135
+ // Score: base from field match ratio, boost for name field matches
136
+ // Range: ~0.15 (weak match in one field) to ~0.95 (name field + multiple fields)
137
+ const fieldRatio = matchedFields / totalSearchableFields;
138
+ const baseScore = 0.15 + (fieldRatio * 0.45); // 0.15 to 0.60
139
+ const nameBoost = nameFieldMatch ? 0.35 : 0; // +0.35 for name field match
140
+ const score = Math.min(baseScore + nameBoost, 0.95);
141
+ return {
142
+ ID: recordID,
143
+ EntityName: entityName,
144
+ RecordID: recordID,
145
+ SourceType: 'entity',
146
+ ResultType: 'entity-record',
147
+ Title: title,
148
+ Snippet: snippet,
149
+ Score: Math.round(score * 100) / 100, // Round to 2 decimal places
150
+ ScoreBreakdown: { Entity: Math.round(score * 100) / 100 },
151
+ Tags: [],
152
+ EntityIcon: entityInfo?.Icon ?? undefined,
153
+ MatchedAt: new Date()
154
+ };
155
+ });
156
+ }
157
+ /**
158
+ * Extract a display title from record data using entity metadata.
159
+ * Combines IsNameField fields in Sequence order.
160
+ */
161
+ extractTitle(record, entityInfo) {
162
+ if (entityInfo) {
163
+ // Try IsNameField fields first
164
+ const nameFields = entityInfo.Fields
165
+ .filter(f => f.IsNameField)
166
+ .sort((a, b) => (a.Sequence ?? 9999) - (b.Sequence ?? 9999));
167
+ if (nameFields.length > 0) {
168
+ const parts = nameFields
169
+ .map(f => record[f.Name])
170
+ .filter(v => v != null && String(v).trim() !== '')
171
+ .map(v => String(v));
172
+ if (parts.length > 0)
173
+ return parts.join(' ');
174
+ }
175
+ // Single NameField fallback
176
+ if (entityInfo.NameField && record[entityInfo.NameField.Name]) {
177
+ return String(record[entityInfo.NameField.Name]);
178
+ }
179
+ }
180
+ // Heuristic fallbacks
181
+ const heuristicFields = ['Name', 'Title', 'Subject', 'Label', 'DisplayName'];
182
+ for (const field of heuristicFields) {
183
+ if (record[field] && typeof record[field] === 'string') {
184
+ return record[field];
185
+ }
186
+ }
187
+ return `Record`;
188
+ }
189
+ /**
190
+ * Extract a display snippet from record data using entity metadata.
191
+ */
192
+ extractSnippet(record, entityInfo) {
193
+ const descFields = ['Description', 'Summary', 'Body', 'Content', 'Text', 'Notes'];
194
+ for (const field of descFields) {
195
+ if (record[field] && typeof record[field] === 'string') {
196
+ const val = record[field];
197
+ return val.length > 200 ? val.substring(0, 200) + '...' : val;
198
+ }
199
+ }
200
+ return entityInfo ? `Matched in ${entityInfo.Name}` : 'Matched record';
201
+ }
202
+ };
203
+ EntitySearchProvider = __decorate([
204
+ RegisterClass(BaseSearchProvider, 'EntitySearchProvider')
205
+ ], EntitySearchProvider);
206
+ export { EntitySearchProvider };
207
+ //# sourceMappingURL=EntitySearchProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntitySearchProvider.js","sourceRoot":"","sources":["../../src/generic/EntitySearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;;;;;;;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAY,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD;;;;GAIG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,kBAAkB;IAArD;;QACa,eAAU,GAAiB,QAAQ,CAAC;IA8NxD,CAAC;IA5NG;;;;;;;;OAQG;IACI,KAAK,CAAC,MAAM,CACf,KAAa,EACb,IAAY,EACZ,OAAkC,EAClC,WAAqB;QAErB,IAAI,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,kBAAkB,GAAG,IAAI,CAAC,qBAAqB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAEnE,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,SAAS,CAAC,oDAAoD,CAAC,CAAC;gBAChE,OAAO,EAAE,CAAC;YACd,CAAC;YAED,yDAAyD;YACzD,SAAS,CAAC,mCAAmC,kBAAkB,CAAC,MAAM,kBAAkB,KAAK,GAAG,CAAC,CAAC;YAClG,KAAK,MAAM,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC7C,MAAM,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC5D,IAAI,MAAM,EAAE,CAAC;oBACT,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;oBACzE,SAAS,CAAC,aAAa,CAAC,CAAC,IAAI,MAAM,YAAY,CAAC,MAAM,uBAAuB,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBACjL,CAAC;YACL,CAAC;YAED,8DAA8D;YAC9D,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAE7F,kCAAkC;YAClC,MAAM,cAAc,GAAG,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CACnD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,CAAC,CACxE,CAAC;YAEF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAClD,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAElC,6CAA6C;YAC7C,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,QAAQ,CAAC,wCAAwC,GAAG,EAAE,CAAC,CAAC;YACxD,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC;IAED;;OAEG;IACK,qBAAqB,CACzB,EAAY,EACZ,OAAkC;QAElC,IAAI,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAE7D,IAAI,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;YAC/B,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YAC5E,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;QAED,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CACzB,UAAkB,EAClB,KAAa,EACb,OAAe,EACf,WAAqB;QAErB,IAAI,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAA0B;gBACrD,UAAU,EAAE,UAAU;gBACtB,gBAAgB,EAAE,KAAK;gBACvB,OAAO,EAAE,OAAO;gBAChB,UAAU,EAAE,QAAQ;aACvB,EAAE,WAAW,CAAC,CAAC;YAEhB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAClB,QAAQ,CAAC,2CAA2C,UAAU,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;gBAC3F,OAAO,EAAE,CAAC;YACd,CAAC;YAED,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,QAAQ,CAAC,0CAA0C,UAAU,MAAM,GAAG,EAAE,CAAC,CAAC;YAC1E,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC;IAED;;;;OAIG;IACK,cAAc,CAClB,OAAkC,EAClC,UAAkB,EAClB,KAAa;QAEb,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAEvC,wDAAwD;QACxD,MAAM,YAAY,GAAG,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC;QACpF,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QAC3D,MAAM,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAE/D,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAExD,6DAA6D;YAC7D,IAAI,aAAa,GAAG,CAAC,CAAC;YACtB,IAAI,cAAc,GAAG,KAAK,CAAC;YAC3B,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChE,aAAa,EAAE,CAAC;oBAChB,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBAChD,cAAc,GAAG,IAAI,CAAC;oBAC1B,CAAC;gBACL,CAAC;YACL,CAAC;YAED,mEAAmE;YACnE,iFAAiF;YACjF,MAAM,UAAU,GAAG,aAAa,GAAG,qBAAqB,CAAC;YACzD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,eAAe;YAC7D,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,6BAA6B;YAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,EAAE,IAAI,CAAC,CAAC;YAEpD,OAAO;gBACH,EAAE,EAAE,QAAQ;gBACZ,UAAU,EAAE,UAAU;gBACtB,QAAQ,EAAE,QAAQ;gBAClB,UAAU,EAAE,QAAQ;gBACpB,UAAU,EAAE,eAAmC;gBAC/C,KAAK,EAAE,KAAK;gBACZ,OAAO,EAAE,OAAO;gBAChB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,4BAA4B;gBAClE,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE;gBACzD,IAAI,EAAE,EAAE;gBACR,UAAU,EAAE,UAAU,EAAE,IAAI,IAAI,SAAS;gBACzC,SAAS,EAAE,IAAI,IAAI,EAAE;aACxB,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACK,YAAY,CAChB,MAA+B,EAC/B,UAAkI;QAElI,IAAI,UAAU,EAAE,CAAC;YACb,+BAA+B;YAC/B,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM;iBAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;iBAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC;YAEjE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,KAAK,GAAG,UAAU;qBACnB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;qBACxB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;qBACjD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjD,CAAC;YAED,4BAA4B;YAC5B,IAAI,UAAU,CAAC,SAAS,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5D,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACrD,CAAC;QACL,CAAC;QAED,sBAAsB;QACtB,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;QAC7E,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACrD,OAAO,MAAM,CAAC,KAAK,CAAW,CAAC;YACnC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED;;OAEG;IACK,cAAc,CAClB,MAA+B,EAC/B,UAAwC;QAExC,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAClF,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACrD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAW,CAAC;gBACpC,OAAO,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;YAClE,CAAC;QACL,CAAC;QAED,OAAO,UAAU,CAAC,CAAC,CAAC,cAAc,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;IAC3E,CAAC;CACJ,CAAA;AA/NY,oBAAoB;IADhC,aAAa,CAAC,kBAAkB,EAAE,sBAAsB,CAAC;GAC7C,oBAAoB,CA+NhC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @fileoverview Full-text search provider for the SearchEngine.
3
+ *
4
+ * Uses Metadata.FullTextSearch() which delegates to the database-native FTS
5
+ * capabilities (SQL Server FREETEXT, PostgreSQL tsvector) via RunView +
6
+ * UserSearchString. Enriches results with tags from TaggedItems and
7
+ * ContentItemTags entities.
8
+ *
9
+ * @module @memberjunction/search-engine
10
+ */
11
+ import { UserInfo } from '@memberjunction/core';
12
+ import { BaseSearchProvider } from './ISearchProvider.js';
13
+ import { SearchSource, SearchFilters, SearchResultItem } from './search.types.js';
14
+ import { SearchEnricher } from './SearchEnricher.js';
15
+ /**
16
+ * Provides full-text search using the MJ Metadata.FullTextSearch() method.
17
+ * Always available since it relies on the standard MJ provider infrastructure.
18
+ */
19
+ export declare class FullTextSearchProvider extends BaseSearchProvider {
20
+ readonly SourceType: SearchSource;
21
+ private enricher;
22
+ /** Set the enricher instance. Called by SearchEngine after construction. */
23
+ SetEnricher(enricher: SearchEnricher): void;
24
+ /**
25
+ * Execute a full-text search across all FTS-enabled entities.
26
+ *
27
+ * @param query - The search query text
28
+ * @param topK - Maximum number of results
29
+ * @param filters - Optional filters (EntityNames, Tags)
30
+ * @param contextUser - The user performing the search
31
+ * @returns Scored result items from full-text search
32
+ */
33
+ Search(query: string, topK: number, filters: SearchFilters | undefined, contextUser: UserInfo): Promise<SearchResultItem[]>;
34
+ }
35
+ //# sourceMappingURL=FullTextSearchProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FullTextSearchProvider.d.ts","sourceRoot":"","sources":["../../src/generic/FullTextSearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAsB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAwB,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAoB,MAAM,gBAAgB,CAAC;AACjG,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;GAGG;AACH,qBACa,sBAAuB,SAAQ,kBAAkB;IAC1D,SAAgB,UAAU,EAAE,YAAY,CAAc;IAEtD,OAAO,CAAC,QAAQ,CAA+B;IAE/C,4EAA4E;IACrE,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAIlD;;;;;;;;OAQG;IACU,MAAM,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,gBAAgB,EAAE,CAAC;CA6CjC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @fileoverview Full-text search provider for the SearchEngine.
3
+ *
4
+ * Uses Metadata.FullTextSearch() which delegates to the database-native FTS
5
+ * capabilities (SQL Server FREETEXT, PostgreSQL tsvector) via RunView +
6
+ * UserSearchString. Enriches results with tags from TaggedItems and
7
+ * ContentItemTags entities.
8
+ *
9
+ * @module @memberjunction/search-engine
10
+ */
11
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
12
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
13
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
14
+ 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;
15
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
16
+ };
17
+ import { LogError, Metadata } from '@memberjunction/core';
18
+ import { RegisterClass } from '@memberjunction/global';
19
+ import { BaseSearchProvider } from './ISearchProvider.js';
20
+ /**
21
+ * Provides full-text search using the MJ Metadata.FullTextSearch() method.
22
+ * Always available since it relies on the standard MJ provider infrastructure.
23
+ */
24
+ let FullTextSearchProvider = class FullTextSearchProvider extends BaseSearchProvider {
25
+ constructor() {
26
+ super(...arguments);
27
+ this.SourceType = 'fulltext';
28
+ this.enricher = null;
29
+ }
30
+ /** Set the enricher instance. Called by SearchEngine after construction. */
31
+ SetEnricher(enricher) {
32
+ this.enricher = enricher;
33
+ }
34
+ /**
35
+ * Execute a full-text search across all FTS-enabled entities.
36
+ *
37
+ * @param query - The search query text
38
+ * @param topK - Maximum number of results
39
+ * @param filters - Optional filters (EntityNames, Tags)
40
+ * @param contextUser - The user performing the search
41
+ * @returns Scored result items from full-text search
42
+ */
43
+ async Search(query, topK, filters, contextUser) {
44
+ try {
45
+ const md = new Metadata();
46
+ const ftsResult = await md.FullTextSearch({
47
+ SearchText: query,
48
+ EntityNames: filters?.EntityNames,
49
+ MaxRowsPerEntity: Math.max(3, Math.ceil(topK / 10))
50
+ }, contextUser);
51
+ if (!ftsResult.Success) {
52
+ LogError(`FullTextSearchProvider: FTS error: ${ftsResult.ErrorMessage}`);
53
+ return [];
54
+ }
55
+ const results = ftsResult.Results.map(r => ({
56
+ ID: r.RecordID,
57
+ EntityName: r.EntityName,
58
+ RecordID: r.RecordID,
59
+ SourceType: 'fulltext',
60
+ ResultType: 'entity-record',
61
+ Title: r.Title,
62
+ Snippet: r.Snippet,
63
+ Score: r.Score,
64
+ ScoreBreakdown: { FullText: r.Score },
65
+ Tags: [],
66
+ MatchedAt: new Date()
67
+ }));
68
+ // Batch-load tags for FTS results
69
+ if (this.enricher) {
70
+ await this.enricher.EnrichWithTags(results, contextUser);
71
+ // Apply tag filter if specified
72
+ if (filters?.Tags?.length) {
73
+ return this.enricher.FilterByTags(results, filters.Tags);
74
+ }
75
+ }
76
+ return results;
77
+ }
78
+ catch (error) {
79
+ const msg = error instanceof Error ? error.message : String(error);
80
+ LogError(`FullTextSearchProvider: Full-text search error: ${msg}`);
81
+ return [];
82
+ }
83
+ }
84
+ };
85
+ FullTextSearchProvider = __decorate([
86
+ RegisterClass(BaseSearchProvider, 'FullTextSearchProvider')
87
+ ], FullTextSearchProvider);
88
+ export { FullTextSearchProvider };
89
+ //# sourceMappingURL=FullTextSearchProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FullTextSearchProvider.js","sourceRoot":"","sources":["../../src/generic/FullTextSearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;;;;;;;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAY,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAwB,MAAM,mBAAmB,CAAC;AAI7E;;;GAGG;AAEI,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,kBAAkB;IAAvD;;QACa,eAAU,GAAiB,UAAU,CAAC;QAE9C,aAAQ,GAA0B,IAAI,CAAC;IAkEnD,CAAC;IAhEG,4EAA4E;IACrE,WAAW,CAAC,QAAwB;QACvC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,MAAM,CACf,KAAa,EACb,IAAY,EACZ,OAAkC,EAClC,WAAqB;QAErB,IAAI,CAAC;YACD,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,cAAc,CAAC;gBACtC,UAAU,EAAE,KAAK;gBACjB,WAAW,EAAE,OAAO,EAAE,WAAW;gBACjC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;aACtD,EAAE,WAAW,CAAC,CAAC;YAEhB,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;gBACrB,QAAQ,CAAC,sCAAsC,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;gBACzE,OAAO,EAAE,CAAC;YACd,CAAC;YAED,MAAM,OAAO,GAAuB,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC5D,EAAE,EAAE,CAAC,CAAC,QAAQ;gBACd,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,UAAU,EAAE,UAAU;gBACtB,UAAU,EAAE,eAAmC;gBAC/C,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE;gBACrC,IAAI,EAAE,EAAc;gBACpB,SAAS,EAAE,IAAI,IAAI,EAAE;aACxB,CAAC,CAAC,CAAC;YAEJ,kCAAkC;YAClC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;gBAEzD,gCAAgC;gBAChC,IAAI,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oBACxB,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC7D,CAAC;YACL,CAAC;YAED,OAAO,OAAO,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,QAAQ,CAAC,mDAAmD,GAAG,EAAE,CAAC,CAAC;YACnE,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC;CACJ,CAAA;AArEY,sBAAsB;IADlC,aAAa,CAAC,kBAAkB,EAAE,wBAAwB,CAAC;GAC/C,sBAAsB,CAqElC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @fileoverview Base class and interface for search providers.
3
+ *
4
+ * Each search provider implements a single retrieval strategy
5
+ * (vector similarity, full-text, entity LIKE-search, storage, etc.)
6
+ * and returns scored candidates suitable for RRF fusion.
7
+ *
8
+ * Providers are discovered at runtime via @RegisterClass and the
9
+ * SearchProvider metadata entity. The DriverClass column in the
10
+ * SearchProvider table maps to the @RegisterClass key.
11
+ *
12
+ * @module @memberjunction/search-engine
13
+ */
14
+ import { UserInfo } from '@memberjunction/core';
15
+ import { SearchSource, SearchFilters, SearchResultItem } from './search.types.js';
16
+ /**
17
+ * Configuration passed to a search provider during initialization.
18
+ * Populated from the SearchProvider entity record.
19
+ */
20
+ export interface SearchProviderConfig {
21
+ /** The provider's display name from the metadata record */
22
+ Name: string;
23
+ /** Optional JSON config blob from ProviderConfig column (already parsed) */
24
+ ProviderConfig: Record<string, unknown> | null;
25
+ /** Optional credential ID for providers that need authentication */
26
+ CredentialID: string | null;
27
+ /** Per-provider max results override (null = use engine default) */
28
+ MaxResultsOverride: number | null;
29
+ /** Whether this provider should participate in preview/autocomplete searches */
30
+ SupportsPreview: boolean;
31
+ /** Priority value from the metadata record (lower = higher priority) */
32
+ Priority: number;
33
+ }
34
+ /**
35
+ * Abstract base class for search providers. Subclasses must be registered
36
+ * with @RegisterClass(BaseSearchProvider, 'DriverClassName') to be
37
+ * discoverable by the SearchEngine.
38
+ *
39
+ * Lifecycle:
40
+ * 1. SearchEngine loads active SearchProvider records from the database
41
+ * 2. For each record, ClassFactory creates an instance using DriverClass
42
+ * 3. Initialize() is called with the provider's config from the DB record
43
+ * 4. CheckAvailability() is called to verify the provider is operational
44
+ * 5. If IsAvailable(), the provider participates in searches
45
+ */
46
+ export declare abstract class BaseSearchProvider {
47
+ /** Which search source this provider represents */
48
+ abstract readonly SourceType: SearchSource;
49
+ /** Config from the SearchProvider metadata record, set during Initialize() */
50
+ protected config: SearchProviderConfig | null;
51
+ /**
52
+ * Initialize the provider with configuration from the SearchProvider entity.
53
+ * Called once during SearchEngine.Config(). Override to perform provider-specific
54
+ * setup (e.g., connecting to external APIs using credentials).
55
+ *
56
+ * @param config - Configuration from the SearchProvider metadata record
57
+ * @param contextUser - The user context for initialization
58
+ */
59
+ Initialize(config: SearchProviderConfig, contextUser: UserInfo): Promise<void>;
60
+ /**
61
+ * Check and cache whether this provider is operational.
62
+ * Called after Initialize(). Override for providers that need to verify
63
+ * external dependencies (e.g., vector indexes exist, API keys are valid).
64
+ *
65
+ * The default implementation returns true (always available).
66
+ *
67
+ * @param contextUser - The user context for availability checks
68
+ */
69
+ CheckAvailability(contextUser: UserInfo): Promise<void>;
70
+ /**
71
+ * Whether this provider is currently available (configured and operational).
72
+ * The SearchEngine will skip providers that return false.
73
+ */
74
+ IsAvailable(): boolean;
75
+ /**
76
+ * Execute a search and return result items with scores.
77
+ *
78
+ * @param query - The search query text
79
+ * @param topK - Maximum number of results to retrieve
80
+ * @param filters - Optional filters to narrow results
81
+ * @param contextUser - The user performing the search
82
+ * @returns Scored result items from this provider
83
+ */
84
+ abstract Search(query: string, topK: number, filters: SearchFilters | undefined, contextUser: UserInfo): Promise<SearchResultItem[]>;
85
+ }
86
+ /**
87
+ * @deprecated Use BaseSearchProvider instead. Kept for backwards compatibility.
88
+ */
89
+ export type ISearchProvider = BaseSearchProvider;
90
+ //# sourceMappingURL=ISearchProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISearchProvider.d.ts","sourceRoot":"","sources":["../../src/generic/ISearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAE/E;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACjC,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC/C,oEAAoE;IACpE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,eAAe,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,8BAAsB,kBAAkB;IACpC,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC;IAE3C,8EAA8E;IAC9E,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAQ;IAErD;;;;;;;OAOG;IACU,UAAU,CAAC,MAAM,EAAE,oBAAoB,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3F;;;;;;;;OAQG;IACU,iBAAiB,CAAC,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE;;;OAGG;IACI,WAAW,IAAI,OAAO;IAI7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,CACX,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,GAAG,SAAS,EAClC,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,gBAAgB,EAAE,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,kBAAkB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview Base class and interface for search providers.
3
+ *
4
+ * Each search provider implements a single retrieval strategy
5
+ * (vector similarity, full-text, entity LIKE-search, storage, etc.)
6
+ * and returns scored candidates suitable for RRF fusion.
7
+ *
8
+ * Providers are discovered at runtime via @RegisterClass and the
9
+ * SearchProvider metadata entity. The DriverClass column in the
10
+ * SearchProvider table maps to the @RegisterClass key.
11
+ *
12
+ * @module @memberjunction/search-engine
13
+ */
14
+ /**
15
+ * Abstract base class for search providers. Subclasses must be registered
16
+ * with @RegisterClass(BaseSearchProvider, 'DriverClassName') to be
17
+ * discoverable by the SearchEngine.
18
+ *
19
+ * Lifecycle:
20
+ * 1. SearchEngine loads active SearchProvider records from the database
21
+ * 2. For each record, ClassFactory creates an instance using DriverClass
22
+ * 3. Initialize() is called with the provider's config from the DB record
23
+ * 4. CheckAvailability() is called to verify the provider is operational
24
+ * 5. If IsAvailable(), the provider participates in searches
25
+ */
26
+ export class BaseSearchProvider {
27
+ constructor() {
28
+ /** Config from the SearchProvider metadata record, set during Initialize() */
29
+ this.config = null;
30
+ }
31
+ /**
32
+ * Initialize the provider with configuration from the SearchProvider entity.
33
+ * Called once during SearchEngine.Config(). Override to perform provider-specific
34
+ * setup (e.g., connecting to external APIs using credentials).
35
+ *
36
+ * @param config - Configuration from the SearchProvider metadata record
37
+ * @param contextUser - The user context for initialization
38
+ */
39
+ async Initialize(config, contextUser) {
40
+ this.config = config;
41
+ }
42
+ /**
43
+ * Check and cache whether this provider is operational.
44
+ * Called after Initialize(). Override for providers that need to verify
45
+ * external dependencies (e.g., vector indexes exist, API keys are valid).
46
+ *
47
+ * The default implementation returns true (always available).
48
+ *
49
+ * @param contextUser - The user context for availability checks
50
+ */
51
+ async CheckAvailability(contextUser) {
52
+ // Default: no-op, provider is always available
53
+ }
54
+ /**
55
+ * Whether this provider is currently available (configured and operational).
56
+ * The SearchEngine will skip providers that return false.
57
+ */
58
+ IsAvailable() {
59
+ return true;
60
+ }
61
+ }
62
+ //# sourceMappingURL=ISearchProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISearchProvider.js","sourceRoot":"","sources":["../../src/generic/ISearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAwBH;;;;;;;;;;;GAWG;AACH,MAAM,OAAgB,kBAAkB;IAAxC;QAII,8EAA8E;QACpE,WAAM,GAAgC,IAAI,CAAC;IAkDzD,CAAC;IAhDG;;;;;;;OAOG;IACI,KAAK,CAAC,UAAU,CAAC,MAA4B,EAAE,WAAqB;QACvE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,iBAAiB,CAAC,WAAqB;QAChD,+CAA+C;IACnD,CAAC;IAED;;;OAGG;IACI,WAAW;QACd,OAAO,IAAI,CAAC;IAChB,CAAC;CAiBJ"}