@memberjunction/search-engine 5.33.0 → 5.34.1

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 (87) hide show
  1. package/dist/generic/BaseReRanker.d.ts +164 -0
  2. package/dist/generic/BaseReRanker.d.ts.map +1 -0
  3. package/dist/generic/BaseReRanker.js +209 -0
  4. package/dist/generic/BaseReRanker.js.map +1 -0
  5. package/dist/generic/EntitySearchProvider.d.ts +36 -4
  6. package/dist/generic/EntitySearchProvider.d.ts.map +1 -1
  7. package/dist/generic/EntitySearchProvider.js +95 -19
  8. package/dist/generic/EntitySearchProvider.js.map +1 -1
  9. package/dist/generic/FullTextSearchProvider.d.ts +2 -2
  10. package/dist/generic/FullTextSearchProvider.d.ts.map +1 -1
  11. package/dist/generic/FullTextSearchProvider.js +14 -3
  12. package/dist/generic/FullTextSearchProvider.js.map +1 -1
  13. package/dist/generic/ISearchProvider.d.ts +44 -2
  14. package/dist/generic/ISearchProvider.d.ts.map +1 -1
  15. package/dist/generic/ISearchProvider.js +35 -1
  16. package/dist/generic/ISearchProvider.js.map +1 -1
  17. package/dist/generic/NoopReRanker.d.ts +28 -0
  18. package/dist/generic/NoopReRanker.d.ts.map +1 -0
  19. package/dist/generic/NoopReRanker.js +49 -0
  20. package/dist/generic/NoopReRanker.js.map +1 -0
  21. package/dist/generic/ScopeTemplateRenderer.d.ts +36 -0
  22. package/dist/generic/ScopeTemplateRenderer.d.ts.map +1 -0
  23. package/dist/generic/ScopeTemplateRenderer.js +110 -0
  24. package/dist/generic/ScopeTemplateRenderer.js.map +1 -0
  25. package/dist/generic/SearchEngine.d.ts +154 -12
  26. package/dist/generic/SearchEngine.d.ts.map +1 -1
  27. package/dist/generic/SearchEngine.js +662 -39
  28. package/dist/generic/SearchEngine.js.map +1 -1
  29. package/dist/generic/SearchFusion.d.ts +40 -6
  30. package/dist/generic/SearchFusion.d.ts.map +1 -1
  31. package/dist/generic/SearchFusion.js +139 -18
  32. package/dist/generic/SearchFusion.js.map +1 -1
  33. package/dist/generic/StorageSearchProvider.d.ts +9 -2
  34. package/dist/generic/StorageSearchProvider.d.ts.map +1 -1
  35. package/dist/generic/StorageSearchProvider.js +44 -12
  36. package/dist/generic/StorageSearchProvider.js.map +1 -1
  37. package/dist/generic/VectorSearchProvider.d.ts +9 -2
  38. package/dist/generic/VectorSearchProvider.d.ts.map +1 -1
  39. package/dist/generic/VectorSearchProvider.js +83 -13
  40. package/dist/generic/VectorSearchProvider.js.map +1 -1
  41. package/dist/generic/search.types.d.ts +206 -0
  42. package/dist/generic/search.types.d.ts.map +1 -1
  43. package/dist/index.d.ts +13 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +18 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/permissions/SearchScopePermissionResolver.d.ts +109 -0
  48. package/dist/permissions/SearchScopePermissionResolver.d.ts.map +1 -0
  49. package/dist/permissions/SearchScopePermissionResolver.js +159 -0
  50. package/dist/permissions/SearchScopePermissionResolver.js.map +1 -0
  51. package/dist/providers/AzureAISearchProvider.d.ts +37 -0
  52. package/dist/providers/AzureAISearchProvider.d.ts.map +1 -0
  53. package/dist/providers/AzureAISearchProvider.js +180 -0
  54. package/dist/providers/AzureAISearchProvider.js.map +1 -0
  55. package/dist/providers/ElasticsearchSearchProvider.d.ts +43 -0
  56. package/dist/providers/ElasticsearchSearchProvider.d.ts.map +1 -0
  57. package/dist/providers/ElasticsearchSearchProvider.js +200 -0
  58. package/dist/providers/ElasticsearchSearchProvider.js.map +1 -0
  59. package/dist/providers/OpenSearchSearchProvider.d.ts +36 -0
  60. package/dist/providers/OpenSearchSearchProvider.d.ts.map +1 -0
  61. package/dist/providers/OpenSearchSearchProvider.js +167 -0
  62. package/dist/providers/OpenSearchSearchProvider.js.map +1 -0
  63. package/dist/providers/TypesenseSearchProvider.d.ts +36 -0
  64. package/dist/providers/TypesenseSearchProvider.d.ts.map +1 -0
  65. package/dist/providers/TypesenseSearchProvider.js +161 -0
  66. package/dist/providers/TypesenseSearchProvider.js.map +1 -0
  67. package/dist/rerankers/BGEReRanker.d.ts +57 -0
  68. package/dist/rerankers/BGEReRanker.d.ts.map +1 -0
  69. package/dist/rerankers/BGEReRanker.js +193 -0
  70. package/dist/rerankers/BGEReRanker.js.map +1 -0
  71. package/dist/rerankers/CohereReRanker.d.ts +65 -0
  72. package/dist/rerankers/CohereReRanker.d.ts.map +1 -0
  73. package/dist/rerankers/CohereReRanker.js +155 -0
  74. package/dist/rerankers/CohereReRanker.js.map +1 -0
  75. package/dist/rerankers/OpenAIReRanker.d.ts +62 -0
  76. package/dist/rerankers/OpenAIReRanker.d.ts.map +1 -0
  77. package/dist/rerankers/OpenAIReRanker.js +197 -0
  78. package/dist/rerankers/OpenAIReRanker.js.map +1 -0
  79. package/dist/rerankers/RerankerBudgetGuard.d.ts +54 -0
  80. package/dist/rerankers/RerankerBudgetGuard.d.ts.map +1 -0
  81. package/dist/rerankers/RerankerBudgetGuard.js +67 -0
  82. package/dist/rerankers/RerankerBudgetGuard.js.map +1 -0
  83. package/dist/rerankers/VoyageReRanker.d.ts +59 -0
  84. package/dist/rerankers/VoyageReRanker.d.ts.map +1 -0
  85. package/dist/rerankers/VoyageReRanker.js +184 -0
  86. package/dist/rerankers/VoyageReRanker.js.map +1 -0
  87. package/package.json +13 -8
@@ -0,0 +1,200 @@
1
+ /**
2
+ * @fileoverview Elasticsearch search provider for the SearchEngine (P5.1).
3
+ *
4
+ * Translates a query plus a SearchScope's `ExternalIndexes` constraint into an
5
+ * Elasticsearch search request. Each `MJ: Search Scope External Indexes` row
6
+ * with `IndexType='Elasticsearch'` and a non-empty `ExternalIndexName` becomes
7
+ * a target index in the request. The scope's rendered `MetadataFilter` (a JSON
8
+ * object the scope author authored as ES filter DSL) is composed into the
9
+ * top-level `bool.filter` so permission predicates and tenant-scoping push down
10
+ * to the engine — no post-fusion filtering.
11
+ *
12
+ * **Connection.** Reads from `SearchProviderConfig.ProviderConfig`:
13
+ * - `node` — Elasticsearch node URL (e.g. `https://es.example.internal:9200`)
14
+ * - `apiKey` — base64-encoded API key (preferred)
15
+ * - `username` + `password` — basic auth fallback
16
+ * - `cloudId` — Elastic Cloud deployment ID, when used in place of `node`
17
+ * - `defaultField` — field to match against when the scope/provider doesn't
18
+ * specify one (default: `content`)
19
+ *
20
+ * **Optional peer dep.** `@elastic/elasticsearch` is in `optionalDependencies`
21
+ * and loaded via dynamic import per CLAUDE.md rule #8 case 2 — consumers who
22
+ * don't use Elasticsearch don't pay the bundle cost.
23
+ *
24
+ * @module @memberjunction/search-engine
25
+ */
26
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
27
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
28
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
29
+ 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;
30
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
31
+ };
32
+ import { LogError } from '@memberjunction/core';
33
+ import { RegisterClass } from '@memberjunction/global';
34
+ import { BaseSearchProvider } from '../generic/ISearchProvider.js';
35
+ /**
36
+ * Lazy-loader for the Elasticsearch SDK. Memoized so the dynamic import cost is
37
+ * paid once per process even when many SearchProvider records reference the
38
+ * same driver.
39
+ */
40
+ let clientCtorPromise = null;
41
+ async function loadElasticsearchClient() {
42
+ if (!clientCtorPromise) {
43
+ clientCtorPromise = (async () => {
44
+ try {
45
+ const mod = await import('@elastic/elasticsearch');
46
+ return mod.Client;
47
+ }
48
+ catch (err) {
49
+ throw new Error(`ElasticsearchSearchProvider: '@elastic/elasticsearch' is not installed. Add it to your project's dependencies if you intend to use this provider. Underlying error: ${err instanceof Error ? err.message : String(err)}`);
50
+ }
51
+ })();
52
+ }
53
+ return clientCtorPromise;
54
+ }
55
+ let ElasticsearchSearchProvider = class ElasticsearchSearchProvider extends BaseSearchProvider {
56
+ constructor() {
57
+ super(...arguments);
58
+ this.SourceType = 'fulltext';
59
+ this.client = null;
60
+ this.available = false;
61
+ this.parsedConfig = null;
62
+ }
63
+ async Initialize(config, contextUser) {
64
+ await super.Initialize(config, contextUser);
65
+ this.parsedConfig = config.ProviderConfig ?? null;
66
+ if (!this.parsedConfig) {
67
+ LogError('ElasticsearchSearchProvider: ProviderConfig is empty — set node + apiKey/username+password in the SearchProvider record.');
68
+ return;
69
+ }
70
+ try {
71
+ const Client = await loadElasticsearchClient();
72
+ const opts = {};
73
+ if (this.parsedConfig.cloudId) {
74
+ opts.cloud = { id: this.parsedConfig.cloudId };
75
+ }
76
+ else if (this.parsedConfig.node) {
77
+ opts.node = this.parsedConfig.node;
78
+ }
79
+ if (this.parsedConfig.apiKey) {
80
+ opts.auth = { apiKey: this.parsedConfig.apiKey };
81
+ }
82
+ else if (this.parsedConfig.username && this.parsedConfig.password) {
83
+ opts.auth = { username: this.parsedConfig.username, password: this.parsedConfig.password };
84
+ }
85
+ this.client = new Client(opts);
86
+ }
87
+ catch (err) {
88
+ const msg = err instanceof Error ? err.message : String(err);
89
+ LogError(`ElasticsearchSearchProvider: Initialize failed — ${msg}`);
90
+ this.client = null;
91
+ }
92
+ }
93
+ async CheckAvailability(_contextUser) {
94
+ if (!this.client) {
95
+ this.available = false;
96
+ return;
97
+ }
98
+ try {
99
+ await this.client.ping();
100
+ this.available = true;
101
+ }
102
+ catch (err) {
103
+ const msg = err instanceof Error ? err.message : String(err);
104
+ LogError(`ElasticsearchSearchProvider: ping failed — ${msg}`);
105
+ this.available = false;
106
+ }
107
+ }
108
+ IsAvailable() {
109
+ return this.available;
110
+ }
111
+ async Search(query, topK, _filters, _contextUser, scopeConstraints) {
112
+ if (!this.client || !this.parsedConfig)
113
+ return [];
114
+ // Determine target indexes: prefer scope-supplied, else providerConfig.defaultIndex
115
+ const scopedIndexes = scopeConstraints?.ExternalIndexes
116
+ ?.filter(r => r.IndexType === 'Elasticsearch' && r.ExternalIndexName)
117
+ .map(r => r.ExternalIndexName) ?? [];
118
+ const target = scopedIndexes.length > 0
119
+ ? scopedIndexes
120
+ : (this.parsedConfig.defaultIndex ? [this.parsedConfig.defaultIndex] : []);
121
+ if (target.length === 0) {
122
+ // No index to query — fail closed (silently empty), matching VectorSearchProvider's pattern.
123
+ return [];
124
+ }
125
+ // Honor per-provider query rewrite from the scope.
126
+ const effectiveQuery = scopeConstraints?.QueryTransforms?.[this.SourceType] ?? query;
127
+ const defaultField = this.parsedConfig.defaultField ?? 'content';
128
+ // Build the query: a multi_match across name + content by default. Scope's
129
+ // MetadataFilter (already-rendered ES filter DSL) is composed into bool.filter
130
+ // for permission / tenant push-down.
131
+ const filterClauses = [];
132
+ for (const idx of scopeConstraints?.ExternalIndexes ?? []) {
133
+ if (idx.IndexType !== 'Elasticsearch')
134
+ continue;
135
+ if (idx.MetadataFilter && typeof idx.MetadataFilter === 'object') {
136
+ filterClauses.push(idx.MetadataFilter);
137
+ }
138
+ }
139
+ const queryBody = {
140
+ bool: {
141
+ must: [
142
+ { match: { [defaultField]: effectiveQuery } },
143
+ ],
144
+ ...(filterClauses.length > 0 ? { filter: filterClauses } : {}),
145
+ },
146
+ };
147
+ try {
148
+ const response = await this.client.search({
149
+ index: target,
150
+ size: topK,
151
+ query: queryBody,
152
+ });
153
+ // Normalize ES _score to [0, 1] with a soft cap so RRF fusion sees comparable
154
+ // values across providers. The cap is `topResultScore || 1` — preserves rank
155
+ // order and gives fusion a roughly-comparable distribution.
156
+ const hits = response.hits.hits;
157
+ const topScore = Math.max(1, hits[0]?._score ?? 1);
158
+ return hits.map((hit, idx) => {
159
+ const src = hit._source ?? {};
160
+ const title = src['title'] ?? src[defaultField] ?? hit._id;
161
+ const snippet = src[defaultField] ?? '';
162
+ return {
163
+ ID: `es-${hit._index}-${hit._id}`,
164
+ EntityName: hit._index,
165
+ RecordID: hit._id,
166
+ SourceType: this.SourceType,
167
+ ResultType: 'entity-record',
168
+ Title: title.slice(0, 200),
169
+ Snippet: snippet.slice(0, 500),
170
+ Score: hit._score / topScore,
171
+ ScoreBreakdown: { FullText: hit._score / topScore },
172
+ Tags: [],
173
+ MatchedAt: new Date(),
174
+ EntityIcon: 'fa-solid fa-database',
175
+ RecordName: title.slice(0, 200),
176
+ RawMetadata: JSON.stringify({ _index: hit._index, _id: hit._id, _rank: idx, _rawScore: hit._score }),
177
+ };
178
+ });
179
+ }
180
+ catch (err) {
181
+ const msg = err instanceof Error ? err.message : String(err);
182
+ LogError(`ElasticsearchSearchProvider.Search failed: ${msg}`);
183
+ return [];
184
+ }
185
+ }
186
+ };
187
+ ElasticsearchSearchProvider = __decorate([
188
+ RegisterClass(BaseSearchProvider, 'ElasticsearchSearchProvider')
189
+ ], ElasticsearchSearchProvider);
190
+ export { ElasticsearchSearchProvider };
191
+ /** Tree-shake prevention helper. */
192
+ export function LoadElasticsearchSearchProvider() {
193
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
194
+ const _ref = ElasticsearchSearchProvider;
195
+ }
196
+ /** Test-only: clear the memoized SDK loader so each test installs its own mock. */
197
+ export function __resetElasticsearchClientLoaderForTests() {
198
+ clientCtorPromise = null;
199
+ }
200
+ //# sourceMappingURL=ElasticsearchSearchProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ElasticsearchSearchProvider.js","sourceRoot":"","sources":["../../src/providers/ElasticsearchSearchProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @fileoverview OpenSearch search provider for the SearchEngine (P5.4).
3
+ *
4
+ * Calls OpenSearch's _search REST endpoint via fetch. OpenSearch's query DSL
5
+ * is largely identical to Elasticsearch 7.x — bool/must/filter trees compose
6
+ * the same way — so the provider mirrors {@link ElasticsearchSearchProvider}'s
7
+ * shape. Distinct class so admins can register and configure each cluster
8
+ * independently and so future divergence (knn vector search, neural search,
9
+ * pipeline aggregations) can land here without touching the ES path.
10
+ *
11
+ * **Connection options** (from `SearchProviderConfig.ProviderConfig`):
12
+ * - `node` — OpenSearch node URL (e.g. `https://os.example:9200`)
13
+ * - `username` + `password` — basic auth
14
+ * - `awsAuthHeader` — pre-signed AWS SigV4 Authorization header for
15
+ * Amazon OpenSearch Service deployments (caller responsible for
16
+ * refreshing before expiry)
17
+ * - `defaultIndex`, `defaultField` — fallbacks when scope is silent
18
+ *
19
+ * @module @memberjunction/search-engine
20
+ */
21
+ import { UserInfo } from '@memberjunction/core';
22
+ import { BaseSearchProvider, SearchProviderConfig } from '../generic/ISearchProvider.js';
23
+ import { SearchSource, SearchFilters, SearchResultItem, ScopeConstraints } from '../generic/search.types.js';
24
+ export declare class OpenSearchSearchProvider extends BaseSearchProvider {
25
+ readonly SourceType: SearchSource;
26
+ private parsedConfig;
27
+ private available;
28
+ Initialize(config: SearchProviderConfig, contextUser: UserInfo): Promise<void>;
29
+ CheckAvailability(_contextUser: UserInfo): Promise<void>;
30
+ IsAvailable(): boolean;
31
+ Search(query: string, topK: number, _filters: SearchFilters | undefined, _contextUser: UserInfo, scopeConstraints?: ScopeConstraints): Promise<SearchResultItem[]>;
32
+ private buildAuthHeaders;
33
+ }
34
+ /** Tree-shake prevention helper. */
35
+ export declare function LoadOpenSearchSearchProvider(): void;
36
+ //# sourceMappingURL=OpenSearchSearchProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenSearchSearchProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OpenSearchSearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,EACH,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EACnB,MAAM,yBAAyB,CAAC;AAqBjC,qBACa,wBAAyB,SAAQ,kBAAkB;IAC5D,SAAgB,UAAU,EAAE,YAAY,CAAc;IAEtD,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,SAAS,CAAS;IAEJ,UAAU,CAAC,MAAM,EAAE,oBAAoB,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9E,iBAAiB,CAAC,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9D,WAAW,IAAI,OAAO;IAIzB,MAAM,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,YAAY,EAAE,QAAQ,EACtB,gBAAgB,CAAC,EAAE,gBAAgB,GACpC,OAAO,CAAC,gBAAgB,EAAE,CAAC;IA6E9B,OAAO,CAAC,gBAAgB;CAc3B;AAED,oCAAoC;AACpC,wBAAgB,4BAA4B,IAAI,IAAI,CAGnD"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * @fileoverview OpenSearch search provider for the SearchEngine (P5.4).
3
+ *
4
+ * Calls OpenSearch's _search REST endpoint via fetch. OpenSearch's query DSL
5
+ * is largely identical to Elasticsearch 7.x — bool/must/filter trees compose
6
+ * the same way — so the provider mirrors {@link ElasticsearchSearchProvider}'s
7
+ * shape. Distinct class so admins can register and configure each cluster
8
+ * independently and so future divergence (knn vector search, neural search,
9
+ * pipeline aggregations) can land here without touching the ES path.
10
+ *
11
+ * **Connection options** (from `SearchProviderConfig.ProviderConfig`):
12
+ * - `node` — OpenSearch node URL (e.g. `https://os.example:9200`)
13
+ * - `username` + `password` — basic auth
14
+ * - `awsAuthHeader` — pre-signed AWS SigV4 Authorization header for
15
+ * Amazon OpenSearch Service deployments (caller responsible for
16
+ * refreshing before expiry)
17
+ * - `defaultIndex`, `defaultField` — fallbacks when scope is silent
18
+ *
19
+ * @module @memberjunction/search-engine
20
+ */
21
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
22
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
23
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
24
+ 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;
25
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
26
+ };
27
+ import { LogError } from '@memberjunction/core';
28
+ import { RegisterClass } from '@memberjunction/global';
29
+ import { BaseSearchProvider } from '../generic/ISearchProvider.js';
30
+ let OpenSearchSearchProvider = class OpenSearchSearchProvider extends BaseSearchProvider {
31
+ constructor() {
32
+ super(...arguments);
33
+ this.SourceType = 'fulltext';
34
+ this.parsedConfig = null;
35
+ this.available = false;
36
+ }
37
+ async Initialize(config, contextUser) {
38
+ await super.Initialize(config, contextUser);
39
+ this.parsedConfig = config.ProviderConfig ?? null;
40
+ if (!this.parsedConfig?.node) {
41
+ LogError('OpenSearchSearchProvider: ProviderConfig must include a node URL.');
42
+ return;
43
+ }
44
+ }
45
+ async CheckAvailability(_contextUser) {
46
+ if (!this.parsedConfig?.node) {
47
+ this.available = false;
48
+ return;
49
+ }
50
+ try {
51
+ const response = await fetch(`${this.parsedConfig.node.replace(/\/$/, '')}/`, {
52
+ headers: this.buildAuthHeaders(),
53
+ });
54
+ // OpenSearch returns 200 + cluster info on the root endpoint when reachable.
55
+ // 401 means host is up but auth is wrong — operationally available.
56
+ this.available = response.ok || response.status === 401;
57
+ if (!this.available)
58
+ LogError(`OpenSearchSearchProvider: probe returned ${response.status}`);
59
+ }
60
+ catch (err) {
61
+ const msg = err instanceof Error ? err.message : String(err);
62
+ LogError(`OpenSearchSearchProvider: probe failed — ${msg}`);
63
+ this.available = false;
64
+ }
65
+ }
66
+ IsAvailable() {
67
+ return this.available;
68
+ }
69
+ async Search(query, topK, _filters, _contextUser, scopeConstraints) {
70
+ if (!this.parsedConfig?.node)
71
+ return [];
72
+ const effectiveQuery = scopeConstraints?.QueryTransforms?.[this.SourceType] ?? query;
73
+ const defaultField = this.parsedConfig.defaultField ?? 'content';
74
+ const node = this.parsedConfig.node.replace(/\/$/, '');
75
+ const scopedRows = scopeConstraints?.ExternalIndexes
76
+ ?.filter(r => r.IndexType === 'OpenSearch' && r.ExternalIndexName) ?? [];
77
+ const indexNames = scopedRows.length > 0
78
+ ? scopedRows.map(r => r.ExternalIndexName)
79
+ : (this.parsedConfig.defaultIndex ? [this.parsedConfig.defaultIndex] : []);
80
+ if (indexNames.length === 0)
81
+ return [];
82
+ const filterClauses = [];
83
+ for (const idx of scopedRows) {
84
+ if (idx.MetadataFilter && typeof idx.MetadataFilter === 'object') {
85
+ filterClauses.push(idx.MetadataFilter);
86
+ }
87
+ }
88
+ const url = `${node}/${indexNames.map(encodeURIComponent).join(',')}/_search`;
89
+ const body = {
90
+ size: topK,
91
+ query: {
92
+ bool: {
93
+ must: [{ match: { [defaultField]: effectiveQuery } }],
94
+ ...(filterClauses.length > 0 ? { filter: filterClauses } : {}),
95
+ },
96
+ },
97
+ };
98
+ try {
99
+ const response = await fetch(url, {
100
+ method: 'POST',
101
+ headers: { ...this.buildAuthHeaders(), 'Content-Type': 'application/json' },
102
+ body: JSON.stringify(body),
103
+ });
104
+ if (!response.ok) {
105
+ const text = await response.text().catch(() => '');
106
+ LogError(`OpenSearchSearchProvider: ${indexNames.join(',')} returned ${response.status}: ${text || response.statusText}`);
107
+ return [];
108
+ }
109
+ const json = await response.json();
110
+ const hits = json.hits?.hits ?? [];
111
+ if (hits.length === 0)
112
+ return [];
113
+ const topScore = Math.max(1, hits[0]._score);
114
+ return hits.slice(0, topK).map((hit, idx) => {
115
+ const src = hit._source ?? {};
116
+ const title = String(src['title'] ?? src[defaultField] ?? hit._id);
117
+ const snippet = String(src[defaultField] ?? '');
118
+ const normalized = hit._score / topScore;
119
+ return {
120
+ ID: `os-${hit._index}-${hit._id}`,
121
+ EntityName: hit._index,
122
+ RecordID: hit._id,
123
+ SourceType: this.SourceType,
124
+ ResultType: 'entity-record',
125
+ Title: title.slice(0, 200),
126
+ Snippet: snippet.slice(0, 500),
127
+ Score: normalized,
128
+ ScoreBreakdown: { FullText: normalized },
129
+ Tags: [],
130
+ MatchedAt: new Date(),
131
+ EntityIcon: 'fa-solid fa-database',
132
+ RecordName: title.slice(0, 200),
133
+ RawMetadata: JSON.stringify({ _index: hit._index, _id: hit._id, _rank: idx, _rawScore: hit._score }),
134
+ };
135
+ });
136
+ }
137
+ catch (err) {
138
+ const msg = err instanceof Error ? err.message : String(err);
139
+ LogError(`OpenSearchSearchProvider.Search failed: ${msg}`);
140
+ return [];
141
+ }
142
+ }
143
+ buildAuthHeaders() {
144
+ const headers = { Accept: 'application/json' };
145
+ if (this.parsedConfig?.awsAuthHeader) {
146
+ headers['Authorization'] = this.parsedConfig.awsAuthHeader;
147
+ return headers;
148
+ }
149
+ if (this.parsedConfig?.username && this.parsedConfig.password) {
150
+ const encoded = Buffer
151
+ .from(`${this.parsedConfig.username}:${this.parsedConfig.password}`)
152
+ .toString('base64');
153
+ headers['Authorization'] = `Basic ${encoded}`;
154
+ }
155
+ return headers;
156
+ }
157
+ };
158
+ OpenSearchSearchProvider = __decorate([
159
+ RegisterClass(BaseSearchProvider, 'OpenSearchSearchProvider')
160
+ ], OpenSearchSearchProvider);
161
+ export { OpenSearchSearchProvider };
162
+ /** Tree-shake prevention helper. */
163
+ export function LoadOpenSearchSearchProvider() {
164
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
165
+ const _ref = OpenSearchSearchProvider;
166
+ }
167
+ //# sourceMappingURL=OpenSearchSearchProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenSearchSearchProvider.js","sourceRoot":"","sources":["../../src/providers/OpenSearchSearchProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @fileoverview Typesense search provider for the SearchEngine (P5.2).
3
+ *
4
+ * Calls Typesense's REST API directly via fetch — Typesense's surface is small
5
+ * enough that adding the `typesense` SDK as another optional peer would be
6
+ * overhead. Per-collection requests are run concurrently when a scope lists
7
+ * multiple ExternalIndexes; results are merged and returned in score order.
8
+ *
9
+ * **Connection options** (from `SearchProviderConfig.ProviderConfig`):
10
+ * - `nodeUrl` — Single Typesense node URL (e.g. `https://ts.example:8108`)
11
+ * - `apiKey` — Typesense API key (sent via `X-TYPESENSE-API-KEY`)
12
+ * - `defaultCollection` — Fallback when scope doesn't list ExternalIndexes
13
+ * - `defaultQueryBy` — Comma-separated fields, default `'content,title'`
14
+ *
15
+ * **Scope constraints.** `ExternalIndexes` rows with `IndexType='Typesense'`
16
+ * supply per-collection `ExternalIndexName` and an optional `MetadataFilter`
17
+ * (a Typesense `filter_by` string — already-rendered with SearchContext
18
+ * values via the scope's Nunjucks step).
19
+ *
20
+ * @module @memberjunction/search-engine
21
+ */
22
+ import { UserInfo } from '@memberjunction/core';
23
+ import { BaseSearchProvider, SearchProviderConfig } from '../generic/ISearchProvider.js';
24
+ import { SearchSource, SearchFilters, SearchResultItem, ScopeConstraints } from '../generic/search.types.js';
25
+ export declare class TypesenseSearchProvider extends BaseSearchProvider {
26
+ readonly SourceType: SearchSource;
27
+ private parsedConfig;
28
+ private available;
29
+ Initialize(config: SearchProviderConfig, contextUser: UserInfo): Promise<void>;
30
+ CheckAvailability(_contextUser: UserInfo): Promise<void>;
31
+ IsAvailable(): boolean;
32
+ Search(query: string, topK: number, _filters: SearchFilters | undefined, _contextUser: UserInfo, scopeConstraints?: ScopeConstraints): Promise<SearchResultItem[]>;
33
+ }
34
+ /** Tree-shake prevention helper. */
35
+ export declare function LoadTypesenseSearchProvider(): void;
36
+ //# sourceMappingURL=TypesenseSearchProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TypesenseSearchProvider.d.ts","sourceRoot":"","sources":["../../src/providers/TypesenseSearchProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,EACH,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EACnB,MAAM,yBAAyB,CAAC;AAmBjC,qBACa,uBAAwB,SAAQ,kBAAkB;IAC3D,SAAgB,UAAU,EAAE,YAAY,CAAc;IAEtD,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,SAAS,CAAS;IAEJ,UAAU,CAAC,MAAM,EAAE,oBAAoB,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9E,iBAAiB,CAAC,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9D,WAAW,IAAI,OAAO;IAIzB,MAAM,CACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,YAAY,EAAE,QAAQ,EACtB,gBAAgB,CAAC,EAAE,gBAAgB,GACpC,OAAO,CAAC,gBAAgB,EAAE,CAAC;CA0FjC;AAED,oCAAoC;AACpC,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @fileoverview Typesense search provider for the SearchEngine (P5.2).
3
+ *
4
+ * Calls Typesense's REST API directly via fetch — Typesense's surface is small
5
+ * enough that adding the `typesense` SDK as another optional peer would be
6
+ * overhead. Per-collection requests are run concurrently when a scope lists
7
+ * multiple ExternalIndexes; results are merged and returned in score order.
8
+ *
9
+ * **Connection options** (from `SearchProviderConfig.ProviderConfig`):
10
+ * - `nodeUrl` — Single Typesense node URL (e.g. `https://ts.example:8108`)
11
+ * - `apiKey` — Typesense API key (sent via `X-TYPESENSE-API-KEY`)
12
+ * - `defaultCollection` — Fallback when scope doesn't list ExternalIndexes
13
+ * - `defaultQueryBy` — Comma-separated fields, default `'content,title'`
14
+ *
15
+ * **Scope constraints.** `ExternalIndexes` rows with `IndexType='Typesense'`
16
+ * supply per-collection `ExternalIndexName` and an optional `MetadataFilter`
17
+ * (a Typesense `filter_by` string — already-rendered with SearchContext
18
+ * values via the scope's Nunjucks step).
19
+ *
20
+ * @module @memberjunction/search-engine
21
+ */
22
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
23
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
24
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
25
+ 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;
26
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
27
+ };
28
+ import { LogError } from '@memberjunction/core';
29
+ import { RegisterClass } from '@memberjunction/global';
30
+ import { BaseSearchProvider } from '../generic/ISearchProvider.js';
31
+ let TypesenseSearchProvider = class TypesenseSearchProvider extends BaseSearchProvider {
32
+ constructor() {
33
+ super(...arguments);
34
+ this.SourceType = 'fulltext';
35
+ this.parsedConfig = null;
36
+ this.available = false;
37
+ }
38
+ async Initialize(config, contextUser) {
39
+ await super.Initialize(config, contextUser);
40
+ this.parsedConfig = config.ProviderConfig ?? null;
41
+ if (!this.parsedConfig?.nodeUrl || !this.parsedConfig.apiKey) {
42
+ LogError('TypesenseSearchProvider: ProviderConfig must include nodeUrl and apiKey.');
43
+ return;
44
+ }
45
+ }
46
+ async CheckAvailability(_contextUser) {
47
+ if (!this.parsedConfig?.nodeUrl || !this.parsedConfig.apiKey) {
48
+ this.available = false;
49
+ return;
50
+ }
51
+ try {
52
+ const response = await fetch(`${this.parsedConfig.nodeUrl.replace(/\/$/, '')}/health`, {
53
+ headers: { 'X-TYPESENSE-API-KEY': this.parsedConfig.apiKey },
54
+ });
55
+ this.available = response.ok;
56
+ }
57
+ catch (err) {
58
+ const msg = err instanceof Error ? err.message : String(err);
59
+ LogError(`TypesenseSearchProvider: health check failed — ${msg}`);
60
+ this.available = false;
61
+ }
62
+ }
63
+ IsAvailable() {
64
+ return this.available;
65
+ }
66
+ async Search(query, topK, _filters, _contextUser, scopeConstraints) {
67
+ if (!this.parsedConfig?.nodeUrl || !this.parsedConfig.apiKey)
68
+ return [];
69
+ const effectiveQuery = scopeConstraints?.QueryTransforms?.[this.SourceType] ?? query;
70
+ const queryBy = this.parsedConfig.defaultQueryBy ?? 'content,title';
71
+ const node = this.parsedConfig.nodeUrl.replace(/\/$/, '');
72
+ // Resolve target collections from scope ExternalIndexes; fall back to defaultCollection.
73
+ const scopedTypesenseRows = scopeConstraints?.ExternalIndexes
74
+ ?.filter(r => r.IndexType === 'Typesense' && r.ExternalIndexName) ?? [];
75
+ const targets = scopedTypesenseRows.length > 0
76
+ ? scopedTypesenseRows
77
+ : (this.parsedConfig.defaultCollection
78
+ ? [{
79
+ IndexType: 'Typesense',
80
+ ExternalIndexName: this.parsedConfig.defaultCollection,
81
+ MetadataFilter: undefined,
82
+ }]
83
+ : []);
84
+ if (targets.length === 0)
85
+ return [];
86
+ // Run all configured collection searches in parallel and merge by text_match score.
87
+ const requests = targets.map(async (idx) => {
88
+ const params = new URLSearchParams({
89
+ q: effectiveQuery,
90
+ query_by: queryBy,
91
+ per_page: String(topK),
92
+ });
93
+ if (idx.MetadataFilter && typeof idx.MetadataFilter === 'string') {
94
+ params.set('filter_by', idx.MetadataFilter);
95
+ }
96
+ const url = `${node}/collections/${encodeURIComponent(idx.ExternalIndexName)}/documents/search?${params.toString()}`;
97
+ try {
98
+ const response = await fetch(url, {
99
+ headers: { 'X-TYPESENSE-API-KEY': this.parsedConfig.apiKey },
100
+ });
101
+ if (!response.ok) {
102
+ const body = await response.text().catch(() => '');
103
+ LogError(`TypesenseSearchProvider: ${idx.ExternalIndexName} returned ${response.status}: ${body || response.statusText}`);
104
+ return { collection: idx.ExternalIndexName, hits: [] };
105
+ }
106
+ const json = await response.json();
107
+ return { collection: idx.ExternalIndexName, hits: json.hits ?? [] };
108
+ }
109
+ catch (err) {
110
+ const msg = err instanceof Error ? err.message : String(err);
111
+ LogError(`TypesenseSearchProvider: ${idx.ExternalIndexName} fetch failed — ${msg}`);
112
+ return { collection: idx.ExternalIndexName, hits: [] };
113
+ }
114
+ });
115
+ const results = await Promise.all(requests);
116
+ const merged = results.flatMap(r => r.hits.map(h => ({ collection: r.collection, hit: h })));
117
+ if (merged.length === 0)
118
+ return [];
119
+ // Normalize text_match to [0, 1] across the merged set so RRF fusion sees
120
+ // comparable scores. text_match is a 64-bit Typesense match score — divide
121
+ // by the top to keep rank order while bounding range.
122
+ const topMatch = Math.max(1, ...merged.map(m => m.hit.text_match));
123
+ return merged
124
+ .sort((a, b) => b.hit.text_match - a.hit.text_match)
125
+ .slice(0, topK)
126
+ .map((m, idx) => {
127
+ const doc = m.hit.document;
128
+ const id = String(doc['id'] ?? `${m.collection}-${idx}`);
129
+ const title = String(doc['title'] ?? doc['name'] ?? id);
130
+ const snippetField = (this.parsedConfig?.defaultQueryBy ?? 'content,title').split(',')[0].trim();
131
+ const snippet = String(doc[snippetField] ?? '');
132
+ const normalized = m.hit.text_match / topMatch;
133
+ return {
134
+ ID: `ts-${m.collection}-${id}`,
135
+ EntityName: m.collection,
136
+ RecordID: id,
137
+ SourceType: this.SourceType,
138
+ ResultType: 'entity-record',
139
+ Title: title.slice(0, 200),
140
+ Snippet: snippet.slice(0, 500),
141
+ Score: normalized,
142
+ ScoreBreakdown: { FullText: normalized },
143
+ Tags: [],
144
+ MatchedAt: new Date(),
145
+ EntityIcon: 'fa-solid fa-database',
146
+ RecordName: title.slice(0, 200),
147
+ RawMetadata: JSON.stringify({ collection: m.collection, id, _rawMatch: m.hit.text_match }),
148
+ };
149
+ });
150
+ }
151
+ };
152
+ TypesenseSearchProvider = __decorate([
153
+ RegisterClass(BaseSearchProvider, 'TypesenseSearchProvider')
154
+ ], TypesenseSearchProvider);
155
+ export { TypesenseSearchProvider };
156
+ /** Tree-shake prevention helper. */
157
+ export function LoadTypesenseSearchProvider() {
158
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
159
+ const _ref = TypesenseSearchProvider;
160
+ }
161
+ //# sourceMappingURL=TypesenseSearchProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TypesenseSearchProvider.js","sourceRoot":"","sources":["../../src/providers/TypesenseSearchProvider.ts"],"names":[],"mappings":"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"}