@open-mercato/search 0.4.2-canary-c02407ff85
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/AGENTS.md +678 -0
- package/build.mjs +92 -0
- package/dist/di.js +157 -0
- package/dist/di.js.map +7 -0
- package/dist/fulltext/drivers/index.js +21 -0
- package/dist/fulltext/drivers/index.js.map +7 -0
- package/dist/fulltext/drivers/meilisearch/index.js +320 -0
- package/dist/fulltext/drivers/meilisearch/index.js.map +7 -0
- package/dist/fulltext/index.js +7 -0
- package/dist/fulltext/index.js.map +7 -0
- package/dist/fulltext/types.js +1 -0
- package/dist/fulltext/types.js.map +7 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +7 -0
- package/dist/indexer/index.js +8 -0
- package/dist/indexer/index.js.map +7 -0
- package/dist/indexer/search-indexer.js +848 -0
- package/dist/indexer/search-indexer.js.map +7 -0
- package/dist/indexer/subscribers/delete.js +41 -0
- package/dist/indexer/subscribers/delete.js.map +7 -0
- package/dist/lib/debug.js +34 -0
- package/dist/lib/debug.js.map +7 -0
- package/dist/lib/fallback-presenter.js +107 -0
- package/dist/lib/fallback-presenter.js.map +7 -0
- package/dist/lib/field-policy.js +75 -0
- package/dist/lib/field-policy.js.map +7 -0
- package/dist/lib/index.js +19 -0
- package/dist/lib/index.js.map +7 -0
- package/dist/lib/merger.js +93 -0
- package/dist/lib/merger.js.map +7 -0
- package/dist/lib/presenter-enricher.js +192 -0
- package/dist/lib/presenter-enricher.js.map +7 -0
- package/dist/modules/search/acl.js +14 -0
- package/dist/modules/search/acl.js.map +7 -0
- package/dist/modules/search/ai-tools.js +284 -0
- package/dist/modules/search/ai-tools.js.map +7 -0
- package/dist/modules/search/api/embeddings/reindex/cancel/route.js +65 -0
- package/dist/modules/search/api/embeddings/reindex/cancel/route.js.map +7 -0
- package/dist/modules/search/api/embeddings/reindex/route.js +165 -0
- package/dist/modules/search/api/embeddings/reindex/route.js.map +7 -0
- package/dist/modules/search/api/embeddings/route.js +246 -0
- package/dist/modules/search/api/embeddings/route.js.map +7 -0
- package/dist/modules/search/api/index/route.js +245 -0
- package/dist/modules/search/api/index/route.js.map +7 -0
- package/dist/modules/search/api/reindex/cancel/route.js +65 -0
- package/dist/modules/search/api/reindex/cancel/route.js.map +7 -0
- package/dist/modules/search/api/reindex/route.js +332 -0
- package/dist/modules/search/api/reindex/route.js.map +7 -0
- package/dist/modules/search/api/search/global/route.js +100 -0
- package/dist/modules/search/api/search/global/route.js.map +7 -0
- package/dist/modules/search/api/search/route.js +101 -0
- package/dist/modules/search/api/search/route.js.map +7 -0
- package/dist/modules/search/api/settings/fulltext/route.js +55 -0
- package/dist/modules/search/api/settings/fulltext/route.js.map +7 -0
- package/dist/modules/search/api/settings/global-search/route.js +80 -0
- package/dist/modules/search/api/settings/global-search/route.js.map +7 -0
- package/dist/modules/search/api/settings/route.js +118 -0
- package/dist/modules/search/api/settings/route.js.map +7 -0
- package/dist/modules/search/api/settings/vector-store/route.js +77 -0
- package/dist/modules/search/api/settings/vector-store/route.js.map +7 -0
- package/dist/modules/search/backend/config/search/page.js +10 -0
- package/dist/modules/search/backend/config/search/page.js.map +7 -0
- package/dist/modules/search/backend/config/search/page.meta.js +24 -0
- package/dist/modules/search/backend/config/search/page.meta.js.map +7 -0
- package/dist/modules/search/cli.js +698 -0
- package/dist/modules/search/cli.js.map +7 -0
- package/dist/modules/search/di.js +32 -0
- package/dist/modules/search/di.js.map +7 -0
- package/dist/modules/search/frontend/components/GlobalSearchDialog.js +357 -0
- package/dist/modules/search/frontend/components/GlobalSearchDialog.js.map +7 -0
- package/dist/modules/search/frontend/components/HybridSearchTable.js +343 -0
- package/dist/modules/search/frontend/components/HybridSearchTable.js.map +7 -0
- package/dist/modules/search/frontend/components/SearchSettingsPageClient.js +303 -0
- package/dist/modules/search/frontend/components/SearchSettingsPageClient.js.map +7 -0
- package/dist/modules/search/frontend/components/sections/FulltextSearchSection.js +360 -0
- package/dist/modules/search/frontend/components/sections/FulltextSearchSection.js.map +7 -0
- package/dist/modules/search/frontend/components/sections/GlobalSearchSection.js +101 -0
- package/dist/modules/search/frontend/components/sections/GlobalSearchSection.js.map +7 -0
- package/dist/modules/search/frontend/components/sections/VectorSearchSection.js +608 -0
- package/dist/modules/search/frontend/components/sections/VectorSearchSection.js.map +7 -0
- package/dist/modules/search/frontend/index.js +9 -0
- package/dist/modules/search/frontend/index.js.map +7 -0
- package/dist/modules/search/frontend/utils.js +41 -0
- package/dist/modules/search/frontend/utils.js.map +7 -0
- package/dist/modules/search/i18n/de.json +61 -0
- package/dist/modules/search/i18n/en.json +72 -0
- package/dist/modules/search/i18n/es.json +61 -0
- package/dist/modules/search/i18n/pl.json +61 -0
- package/dist/modules/search/index.js +11 -0
- package/dist/modules/search/index.js.map +7 -0
- package/dist/modules/search/lib/auto-indexing.js +29 -0
- package/dist/modules/search/lib/auto-indexing.js.map +7 -0
- package/dist/modules/search/lib/embedding-config.js +131 -0
- package/dist/modules/search/lib/embedding-config.js.map +7 -0
- package/dist/modules/search/lib/global-search-config.js +45 -0
- package/dist/modules/search/lib/global-search-config.js.map +7 -0
- package/dist/modules/search/lib/reindex-lock.js +99 -0
- package/dist/modules/search/lib/reindex-lock.js.map +7 -0
- package/dist/modules/search/subscribers/fulltext_upsert.js +64 -0
- package/dist/modules/search/subscribers/fulltext_upsert.js.map +7 -0
- package/dist/modules/search/subscribers/vector_delete.js +58 -0
- package/dist/modules/search/subscribers/vector_delete.js.map +7 -0
- package/dist/modules/search/subscribers/vector_purge.js +142 -0
- package/dist/modules/search/subscribers/vector_purge.js.map +7 -0
- package/dist/modules/search/subscribers/vector_upsert.js +58 -0
- package/dist/modules/search/subscribers/vector_upsert.js.map +7 -0
- package/dist/modules/search/workers/fulltext-index.worker.js +240 -0
- package/dist/modules/search/workers/fulltext-index.worker.js.map +7 -0
- package/dist/modules/search/workers/vector-index.worker.js +234 -0
- package/dist/modules/search/workers/vector-index.worker.js.map +7 -0
- package/dist/queue/fulltext-indexing.js +15 -0
- package/dist/queue/fulltext-indexing.js.map +7 -0
- package/dist/queue/index.js +3 -0
- package/dist/queue/index.js.map +7 -0
- package/dist/queue/vector-indexing.js +15 -0
- package/dist/queue/vector-indexing.js.map +7 -0
- package/dist/service.js +286 -0
- package/dist/service.js.map +7 -0
- package/dist/strategies/fulltext.strategy.js +116 -0
- package/dist/strategies/fulltext.strategy.js.map +7 -0
- package/dist/strategies/index.js +12 -0
- package/dist/strategies/index.js.map +7 -0
- package/dist/strategies/token.strategy.js +80 -0
- package/dist/strategies/token.strategy.js.map +7 -0
- package/dist/strategies/vector.strategy.js +137 -0
- package/dist/strategies/vector.strategy.js.map +7 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +7 -0
- package/dist/vector/drivers/chromadb/index.js +44 -0
- package/dist/vector/drivers/chromadb/index.js.map +7 -0
- package/dist/vector/drivers/index.js +9 -0
- package/dist/vector/drivers/index.js.map +7 -0
- package/dist/vector/drivers/pgvector/index.js +509 -0
- package/dist/vector/drivers/pgvector/index.js.map +7 -0
- package/dist/vector/drivers/qdrant/index.js +44 -0
- package/dist/vector/drivers/qdrant/index.js.map +7 -0
- package/dist/vector/index.js +4 -0
- package/dist/vector/index.js.map +7 -0
- package/dist/vector/lib/vector-logs.js +33 -0
- package/dist/vector/lib/vector-logs.js.map +7 -0
- package/dist/vector/services/checksum.js +20 -0
- package/dist/vector/services/checksum.js.map +7 -0
- package/dist/vector/services/embedding.js +222 -0
- package/dist/vector/services/embedding.js.map +7 -0
- package/dist/vector/services/index.js +4 -0
- package/dist/vector/services/index.js.map +7 -0
- package/dist/vector/services/vector-index.service.js +960 -0
- package/dist/vector/services/vector-index.service.js.map +7 -0
- package/dist/vector/types/pg.d.js +1 -0
- package/dist/vector/types/pg.d.js.map +7 -0
- package/dist/vector/types.js +75 -0
- package/dist/vector/types.js.map +7 -0
- package/jest.config.cjs +19 -0
- package/package.json +142 -0
- package/src/__tests__/queue.test.ts +148 -0
- package/src/__tests__/service.test.ts +345 -0
- package/src/__tests__/workers.test.ts +319 -0
- package/src/di.ts +291 -0
- package/src/fulltext/drivers/index.ts +41 -0
- package/src/fulltext/drivers/meilisearch/index.ts +410 -0
- package/src/fulltext/index.ts +13 -0
- package/src/fulltext/types.ts +115 -0
- package/src/index.ts +36 -0
- package/src/indexer/index.ts +13 -0
- package/src/indexer/search-indexer.ts +1141 -0
- package/src/indexer/subscribers/delete.ts +49 -0
- package/src/lib/debug.ts +46 -0
- package/src/lib/fallback-presenter.ts +106 -0
- package/src/lib/field-policy.ts +169 -0
- package/src/lib/index.ts +13 -0
- package/src/lib/merger.ts +159 -0
- package/src/lib/presenter-enricher.ts +323 -0
- package/src/modules/search/README.md +694 -0
- package/src/modules/search/acl.ts +10 -0
- package/src/modules/search/ai-tools.ts +467 -0
- package/src/modules/search/api/embeddings/reindex/cancel/route.ts +77 -0
- package/src/modules/search/api/embeddings/reindex/route.ts +197 -0
- package/src/modules/search/api/embeddings/route.ts +304 -0
- package/src/modules/search/api/index/route.ts +297 -0
- package/src/modules/search/api/reindex/cancel/route.ts +77 -0
- package/src/modules/search/api/reindex/route.ts +419 -0
- package/src/modules/search/api/search/global/route.ts +120 -0
- package/src/modules/search/api/search/route.ts +121 -0
- package/src/modules/search/api/settings/fulltext/route.ts +82 -0
- package/src/modules/search/api/settings/global-search/route.ts +91 -0
- package/src/modules/search/api/settings/route.ts +187 -0
- package/src/modules/search/api/settings/vector-store/route.ts +105 -0
- package/src/modules/search/backend/config/search/page.meta.ts +22 -0
- package/src/modules/search/backend/config/search/page.tsx +12 -0
- package/src/modules/search/cli.ts +818 -0
- package/src/modules/search/di.ts +50 -0
- package/src/modules/search/frontend/components/GlobalSearchDialog.tsx +436 -0
- package/src/modules/search/frontend/components/HybridSearchTable.tsx +418 -0
- package/src/modules/search/frontend/components/SearchSettingsPageClient.tsx +476 -0
- package/src/modules/search/frontend/components/sections/FulltextSearchSection.tsx +624 -0
- package/src/modules/search/frontend/components/sections/GlobalSearchSection.tsx +124 -0
- package/src/modules/search/frontend/components/sections/VectorSearchSection.tsx +943 -0
- package/src/modules/search/frontend/index.ts +3 -0
- package/src/modules/search/frontend/utils.ts +82 -0
- package/src/modules/search/i18n/de.json +61 -0
- package/src/modules/search/i18n/en.json +72 -0
- package/src/modules/search/i18n/es.json +61 -0
- package/src/modules/search/i18n/pl.json +61 -0
- package/src/modules/search/index.ts +9 -0
- package/src/modules/search/lib/auto-indexing.ts +35 -0
- package/src/modules/search/lib/embedding-config.ts +161 -0
- package/src/modules/search/lib/global-search-config.ts +69 -0
- package/src/modules/search/lib/reindex-lock.ts +201 -0
- package/src/modules/search/subscribers/fulltext_upsert.ts +83 -0
- package/src/modules/search/subscribers/vector_delete.ts +75 -0
- package/src/modules/search/subscribers/vector_purge.ts +161 -0
- package/src/modules/search/subscribers/vector_upsert.ts +75 -0
- package/src/modules/search/workers/fulltext-index.worker.ts +318 -0
- package/src/modules/search/workers/vector-index.worker.ts +292 -0
- package/src/queue/fulltext-indexing.ts +87 -0
- package/src/queue/index.ts +2 -0
- package/src/queue/vector-indexing.ts +66 -0
- package/src/service.ts +397 -0
- package/src/strategies/fulltext.strategy.ts +155 -0
- package/src/strategies/index.ts +17 -0
- package/src/strategies/token.strategy.ts +153 -0
- package/src/strategies/vector.strategy.ts +234 -0
- package/src/types.ts +38 -0
- package/src/vector/drivers/chromadb/index.ts +49 -0
- package/src/vector/drivers/index.ts +4 -0
- package/src/vector/drivers/pgvector/index.ts +627 -0
- package/src/vector/drivers/qdrant/index.ts +49 -0
- package/src/vector/index.ts +3 -0
- package/src/vector/lib/vector-logs.ts +46 -0
- package/src/vector/services/checksum.ts +18 -0
- package/src/vector/services/embedding.ts +275 -0
- package/src/vector/services/index.ts +3 -0
- package/src/vector/services/vector-index.service.ts +1234 -0
- package/src/vector/types/pg.d.ts +1 -0
- package/src/vector/types.ts +220 -0
- package/tsconfig.json +9 -0
- package/watch.mjs +6 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import { searchDebugWarn } from "../lib/debug.js";
|
|
3
|
+
class VectorSearchStrategy {
|
|
4
|
+
constructor(embeddingService, vectorDriver, config) {
|
|
5
|
+
this.embeddingService = embeddingService;
|
|
6
|
+
this.vectorDriver = vectorDriver;
|
|
7
|
+
this.id = "vector";
|
|
8
|
+
this.name = "Vector Search";
|
|
9
|
+
this.priority = 20;
|
|
10
|
+
this.ready = false;
|
|
11
|
+
this.readyPromise = null;
|
|
12
|
+
this.defaultLimit = config?.defaultLimit ?? 20;
|
|
13
|
+
}
|
|
14
|
+
async isAvailable() {
|
|
15
|
+
return this.embeddingService.available;
|
|
16
|
+
}
|
|
17
|
+
async ensureReady() {
|
|
18
|
+
if (this.ready) return;
|
|
19
|
+
if (!this.readyPromise) {
|
|
20
|
+
this.readyPromise = this.vectorDriver.ensureReady().then(() => {
|
|
21
|
+
this.ready = true;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return this.readyPromise;
|
|
25
|
+
}
|
|
26
|
+
async search(query, options) {
|
|
27
|
+
await this.ensureReady();
|
|
28
|
+
const embedding = await this.embeddingService.createEmbedding(query);
|
|
29
|
+
const filter = {
|
|
30
|
+
tenantId: options.tenantId,
|
|
31
|
+
entityIds: options.entityTypes
|
|
32
|
+
};
|
|
33
|
+
if (options.organizationId) {
|
|
34
|
+
filter.organizationId = options.organizationId;
|
|
35
|
+
}
|
|
36
|
+
const results = await this.vectorDriver.query({
|
|
37
|
+
vector: embedding,
|
|
38
|
+
limit: options.limit ?? this.defaultLimit,
|
|
39
|
+
filter
|
|
40
|
+
});
|
|
41
|
+
return results.map((hit) => ({
|
|
42
|
+
entityId: hit.entityId,
|
|
43
|
+
recordId: hit.recordId,
|
|
44
|
+
score: hit.score,
|
|
45
|
+
source: this.id,
|
|
46
|
+
presenter: hit.presenter ?? void 0,
|
|
47
|
+
url: hit.primaryLinkHref ?? hit.url ?? void 0,
|
|
48
|
+
links: hit.links?.map((link) => ({
|
|
49
|
+
href: link.href,
|
|
50
|
+
label: link.label ?? "",
|
|
51
|
+
kind: link.kind
|
|
52
|
+
})),
|
|
53
|
+
metadata: hit.payload ?? void 0
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
async index(record) {
|
|
57
|
+
await this.ensureReady();
|
|
58
|
+
const textContent = record.text ? Array.isArray(record.text) ? record.text.join("\n") : record.text : this.buildTextContent(record);
|
|
59
|
+
if (!textContent) return;
|
|
60
|
+
const embedding = await this.embeddingService.createEmbedding(textContent);
|
|
61
|
+
const doc = {
|
|
62
|
+
entityId: record.entityId,
|
|
63
|
+
recordId: record.recordId,
|
|
64
|
+
tenantId: record.tenantId,
|
|
65
|
+
organizationId: record.organizationId,
|
|
66
|
+
checksum: this.computeChecksum(record),
|
|
67
|
+
embedding,
|
|
68
|
+
url: record.url,
|
|
69
|
+
presenter: record.presenter,
|
|
70
|
+
links: record.links,
|
|
71
|
+
driverId: this.vectorDriver.id,
|
|
72
|
+
resultTitle: record.presenter?.title ?? record.recordId,
|
|
73
|
+
resultSubtitle: record.presenter?.subtitle,
|
|
74
|
+
resultIcon: record.presenter?.icon,
|
|
75
|
+
resultBadge: record.presenter?.badge
|
|
76
|
+
};
|
|
77
|
+
await this.vectorDriver.upsert(doc);
|
|
78
|
+
}
|
|
79
|
+
async delete(entityId, recordId, tenantId) {
|
|
80
|
+
await this.ensureReady();
|
|
81
|
+
await this.vectorDriver.delete(entityId, recordId, tenantId);
|
|
82
|
+
}
|
|
83
|
+
async purge(entityId, tenantId) {
|
|
84
|
+
await this.ensureReady();
|
|
85
|
+
if (this.vectorDriver.purge) {
|
|
86
|
+
await this.vectorDriver.purge(entityId, tenantId);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Build text content from record fields for embedding.
|
|
91
|
+
*/
|
|
92
|
+
buildTextContent(record) {
|
|
93
|
+
const parts = [];
|
|
94
|
+
if (record.presenter?.title) {
|
|
95
|
+
parts.push(record.presenter.title);
|
|
96
|
+
}
|
|
97
|
+
if (record.presenter?.subtitle) {
|
|
98
|
+
parts.push(record.presenter.subtitle);
|
|
99
|
+
}
|
|
100
|
+
for (const [, value] of Object.entries(record.fields)) {
|
|
101
|
+
if (typeof value === "string" && value.trim()) {
|
|
102
|
+
parts.push(value);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return parts.join(" ").trim();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Compute a checksum for change detection using SHA-256.
|
|
109
|
+
* Uses checksumSource from buildSource if available, otherwise uses fields/presenter/url.
|
|
110
|
+
*/
|
|
111
|
+
computeChecksum(record) {
|
|
112
|
+
const source = record.checksumSource !== void 0 ? record.checksumSource : {
|
|
113
|
+
fields: record.fields,
|
|
114
|
+
presenter: record.presenter,
|
|
115
|
+
url: record.url
|
|
116
|
+
};
|
|
117
|
+
const content = JSON.stringify(source);
|
|
118
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* List entries in the vector index (for admin/debugging).
|
|
122
|
+
*/
|
|
123
|
+
async listEntries(options) {
|
|
124
|
+
await this.ensureReady();
|
|
125
|
+
const listMethod = this.vectorDriver.list;
|
|
126
|
+
if (typeof listMethod === "function") {
|
|
127
|
+
const entries = await listMethod.call(this.vectorDriver, options);
|
|
128
|
+
return entries;
|
|
129
|
+
}
|
|
130
|
+
searchDebugWarn("VectorSearchStrategy", "Vector driver does not support listing entries");
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
VectorSearchStrategy
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=vector.strategy.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/strategies/vector.strategy.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash } from 'crypto'\nimport type {\n SearchStrategy,\n SearchStrategyId,\n SearchOptions,\n SearchResult,\n IndexableRecord,\n} from '../types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { VectorDriver, VectorDriverDocument } from '../vector/types'\nimport { searchDebugWarn } from '../lib/debug'\n\n/**\n * Embedding service interface - minimal subset needed by VectorSearchStrategy.\n */\nexport interface EmbeddingService {\n createEmbedding(text: string): Promise<number[]>\n available: boolean\n}\n\n/**\n * Configuration for VectorSearchStrategy.\n */\nexport type VectorStrategyConfig = {\n /** Default limit for search results */\n defaultLimit?: number\n}\n\n/**\n * VectorSearchStrategy provides semantic search using embeddings.\n * It wraps the existing vector module infrastructure.\n */\nexport class VectorSearchStrategy implements SearchStrategy {\n readonly id: SearchStrategyId = 'vector'\n readonly name = 'Vector Search'\n readonly priority = 20 // Medium priority\n\n private readonly defaultLimit: number\n private ready = false\n private readyPromise: Promise<void> | null = null\n\n constructor(\n private readonly embeddingService: EmbeddingService,\n private readonly vectorDriver: VectorDriver,\n config?: VectorStrategyConfig,\n ) {\n this.defaultLimit = config?.defaultLimit ?? 20\n }\n\n async isAvailable(): Promise<boolean> {\n return this.embeddingService.available\n }\n\n async ensureReady(): Promise<void> {\n if (this.ready) return\n if (!this.readyPromise) {\n this.readyPromise = this.vectorDriver.ensureReady().then(() => {\n this.ready = true\n })\n }\n return this.readyPromise\n }\n\n async search(query: string, options: SearchOptions): Promise<SearchResult[]> {\n await this.ensureReady()\n const embedding = await this.embeddingService.createEmbedding(query)\n\n // Build filter - only include organizationId if it's a real value\n // The pgvector driver treats null as \"only records with null org_id\",\n // but we want null/undefined to mean \"no organization filter\"\n const filter: {\n tenantId: string\n organizationId?: string | null\n entityIds?: EntityId[]\n } = {\n tenantId: options.tenantId,\n entityIds: options.entityTypes as EntityId[],\n }\n\n // Only add organizationId filter if it's a real org ID\n if (options.organizationId) {\n filter.organizationId = options.organizationId\n }\n\n const results = await this.vectorDriver.query({\n vector: embedding,\n limit: options.limit ?? this.defaultLimit,\n filter,\n })\n\n return results.map((hit) => ({\n entityId: hit.entityId,\n recordId: hit.recordId,\n score: hit.score,\n source: this.id,\n presenter: hit.presenter ?? undefined,\n url: hit.primaryLinkHref ?? hit.url ?? undefined,\n links: hit.links?.map((link) => ({\n href: link.href,\n label: link.label ?? '',\n kind: link.kind,\n })),\n metadata: hit.payload ?? undefined,\n }))\n }\n\n async index(record: IndexableRecord): Promise<void> {\n await this.ensureReady()\n // Use text from buildSource if available, otherwise fall back to generic extraction\n const textContent = record.text\n ? (Array.isArray(record.text) ? record.text.join('\\n') : record.text)\n : this.buildTextContent(record)\n if (!textContent) return\n\n const embedding = await this.embeddingService.createEmbedding(textContent)\n\n const doc: VectorDriverDocument = {\n entityId: record.entityId as EntityId,\n recordId: record.recordId,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n checksum: this.computeChecksum(record),\n embedding,\n url: record.url,\n presenter: record.presenter,\n links: record.links,\n driverId: this.vectorDriver.id,\n resultTitle: record.presenter?.title ?? record.recordId,\n resultSubtitle: record.presenter?.subtitle,\n resultIcon: record.presenter?.icon,\n resultBadge: record.presenter?.badge,\n }\n\n await this.vectorDriver.upsert(doc)\n }\n\n async delete(entityId: EntityId, recordId: string, tenantId: string): Promise<void> {\n await this.ensureReady()\n await this.vectorDriver.delete(entityId, recordId, tenantId)\n }\n\n async purge(entityId: EntityId, tenantId: string): Promise<void> {\n await this.ensureReady()\n if (this.vectorDriver.purge) {\n await this.vectorDriver.purge(entityId, tenantId)\n }\n }\n\n /**\n * Build text content from record fields for embedding.\n */\n private buildTextContent(record: IndexableRecord): string {\n const parts: string[] = []\n\n // Add presenter info\n if (record.presenter?.title) {\n parts.push(record.presenter.title)\n }\n if (record.presenter?.subtitle) {\n parts.push(record.presenter.subtitle)\n }\n\n // Add string fields from record\n for (const [, value] of Object.entries(record.fields)) {\n if (typeof value === 'string' && value.trim()) {\n parts.push(value)\n }\n }\n\n return parts.join(' ').trim()\n }\n\n /**\n * Compute a checksum for change detection using SHA-256.\n * Uses checksumSource from buildSource if available, otherwise uses fields/presenter/url.\n */\n private computeChecksum(record: IndexableRecord): string {\n const source = record.checksumSource !== undefined\n ? record.checksumSource\n : {\n fields: record.fields,\n presenter: record.presenter,\n url: record.url,\n }\n const content = JSON.stringify(source)\n return createHash('sha256').update(content).digest('hex').slice(0, 16)\n }\n\n /**\n * List entries in the vector index (for admin/debugging).\n */\n async listEntries(options: {\n tenantId: string\n organizationId?: string | null\n entityId?: string\n limit?: number\n offset?: number\n }): Promise<Array<{\n entityId: string\n recordId: string\n tenantId: string\n organizationId: string | null\n presenter?: unknown\n url?: string\n }>> {\n await this.ensureReady()\n // Delegate to vector driver's list method if available\n const listMethod = (this.vectorDriver as unknown as {\n list?: (options: {\n tenantId: string\n organizationId?: string | null\n entityId?: string\n limit?: number\n offset?: number\n }) => Promise<unknown[]>\n }).list\n\n if (typeof listMethod === 'function') {\n const entries = await listMethod.call(this.vectorDriver, options)\n return entries as Array<{\n entityId: string\n recordId: string\n tenantId: string\n organizationId: string | null\n presenter?: unknown\n url?: string\n }>\n }\n\n // Fallback: return empty array if driver doesn't support listing\n searchDebugWarn('VectorSearchStrategy', 'Vector driver does not support listing entries')\n return []\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function notImplemented(method) {
|
|
2
|
+
throw new Error(`[vector.chromadb] ${method} not implemented yet`);
|
|
3
|
+
}
|
|
4
|
+
function createChromaDbDriver() {
|
|
5
|
+
return {
|
|
6
|
+
id: "chromadb",
|
|
7
|
+
async ensureReady() {
|
|
8
|
+
notImplemented("ensureReady");
|
|
9
|
+
},
|
|
10
|
+
async upsert(doc) {
|
|
11
|
+
void doc;
|
|
12
|
+
notImplemented("upsert");
|
|
13
|
+
},
|
|
14
|
+
async delete(entityId, recordId, tenantId) {
|
|
15
|
+
void entityId;
|
|
16
|
+
void recordId;
|
|
17
|
+
void tenantId;
|
|
18
|
+
notImplemented("delete");
|
|
19
|
+
},
|
|
20
|
+
async getChecksum(entityId, recordId, tenantId) {
|
|
21
|
+
void entityId;
|
|
22
|
+
void recordId;
|
|
23
|
+
void tenantId;
|
|
24
|
+
notImplemented("getChecksum");
|
|
25
|
+
},
|
|
26
|
+
async query(input) {
|
|
27
|
+
void input;
|
|
28
|
+
notImplemented("query");
|
|
29
|
+
},
|
|
30
|
+
async purge(entityId, tenantId) {
|
|
31
|
+
void entityId;
|
|
32
|
+
void tenantId;
|
|
33
|
+
notImplemented("purge");
|
|
34
|
+
},
|
|
35
|
+
async count(params) {
|
|
36
|
+
void params;
|
|
37
|
+
notImplemented("count");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
createChromaDbDriver
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/vector/drivers/chromadb/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n VectorDriver,\n VectorDriverDocument,\n VectorDriverQuery,\n VectorDriverQueryResult,\n VectorDriverCountParams,\n} from '../../types'\n\nfunction notImplemented(method: string): never {\n throw new Error(`[vector.chromadb] ${method} not implemented yet`)\n}\n\nexport function createChromaDbDriver(): VectorDriver {\n return {\n id: 'chromadb',\n async ensureReady() {\n notImplemented('ensureReady')\n },\n async upsert(doc: VectorDriverDocument) {\n void doc\n notImplemented('upsert')\n },\n async delete(entityId: string, recordId: string, tenantId: string) {\n void entityId\n void recordId\n void tenantId\n notImplemented('delete')\n },\n async getChecksum(entityId: string, recordId: string, tenantId: string) {\n void entityId\n void recordId\n void tenantId\n notImplemented('getChecksum')\n },\n async query(input: VectorDriverQuery): Promise<VectorDriverQueryResult[]> {\n void input\n notImplemented('query')\n },\n async purge(entityId: string, tenantId: string) {\n void entityId\n void tenantId\n notImplemented('purge')\n },\n async count(params: VectorDriverCountParams) {\n void params\n notImplemented('count')\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,eAAe,QAAuB;AAC7C,QAAM,IAAI,MAAM,qBAAqB,MAAM,sBAAsB;AACnE;AAEO,SAAS,uBAAqC;AACnD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM,cAAc;AAClB,qBAAe,aAAa;AAAA,IAC9B;AAAA,IACA,MAAM,OAAO,KAA2B;AACtC,WAAK;AACL,qBAAe,QAAQ;AAAA,IACzB;AAAA,IACA,MAAM,OAAO,UAAkB,UAAkB,UAAkB;AACjE,WAAK;AACL,WAAK;AACL,WAAK;AACL,qBAAe,QAAQ;AAAA,IACzB;AAAA,IACA,MAAM,YAAY,UAAkB,UAAkB,UAAkB;AACtE,WAAK;AACL,WAAK;AACL,WAAK;AACL,qBAAe,aAAa;AAAA,IAC9B;AAAA,IACA,MAAM,MAAM,OAA8D;AACxE,WAAK;AACL,qBAAe,OAAO;AAAA,IACxB;AAAA,IACA,MAAM,MAAM,UAAkB,UAAkB;AAC9C,WAAK;AACL,WAAK;AACL,qBAAe,OAAO;AAAA,IACxB;AAAA,IACA,MAAM,MAAM,QAAiC;AAC3C,WAAK;AACL,qBAAe,OAAO;AAAA,IACxB;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createPgVectorDriver } from "./pgvector/index.js";
|
|
2
|
+
import { createQdrantDriver } from "./qdrant/index.js";
|
|
3
|
+
import { createChromaDbDriver } from "./chromadb/index.js";
|
|
4
|
+
export {
|
|
5
|
+
createChromaDbDriver,
|
|
6
|
+
createPgVectorDriver,
|
|
7
|
+
createQdrantDriver
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/vector/drivers/index.ts"],
|
|
4
|
+
"sourcesContent": ["export { createPgVectorDriver } from './pgvector'\nexport { createQdrantDriver } from './qdrant'\nexport { createChromaDbDriver } from './chromadb'\nexport type { VectorDriver } from '../types'\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,4BAA4B;AACrC,SAAS,0BAA0B;AACnC,SAAS,4BAA4B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|