@open-mercato/search 0.7.1-develop.7137.1.26575786c0 → 0.7.1-develop.7148.1.3076e5ccf7
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.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseDecryptedFieldValue } from "@open-mercato/shared/lib/encryption/tenantDataEncryptionService";
|
|
1
2
|
import { computeChecksum } from "./checksum.js";
|
|
2
3
|
import { logVectorOperation } from "../lib/vector-logs.js";
|
|
3
4
|
import { searchDebug, searchDebugWarn } from "../../lib/debug.js";
|
|
@@ -165,6 +166,8 @@ class VectorIndexService {
|
|
|
165
166
|
args.tenantId,
|
|
166
167
|
args.organizationId
|
|
167
168
|
);
|
|
169
|
+
const decryptedLinks = decrypted.links ?? args.links;
|
|
170
|
+
const decryptedPayload = decrypted.payload ?? args.payload;
|
|
168
171
|
return {
|
|
169
172
|
resultTitle: String(decrypted.resultTitle ?? args.resultTitle),
|
|
170
173
|
resultSubtitle: decrypted.resultSubtitle ?? args.resultSubtitle,
|
|
@@ -172,8 +175,8 @@ class VectorIndexService {
|
|
|
172
175
|
resultSnapshot: decrypted.resultSnapshot ?? args.resultSnapshot,
|
|
173
176
|
primaryLinkHref: decrypted.primaryLinkHref ?? args.primaryLinkHref,
|
|
174
177
|
primaryLinkLabel: decrypted.primaryLinkLabel ?? args.primaryLinkLabel,
|
|
175
|
-
links:
|
|
176
|
-
payload:
|
|
178
|
+
links: typeof decryptedLinks === "string" ? parseDecryptedFieldValue(decryptedLinks) : decryptedLinks,
|
|
179
|
+
payload: typeof decryptedPayload === "string" ? parseDecryptedFieldValue(decryptedPayload) : decryptedPayload
|
|
177
180
|
};
|
|
178
181
|
} catch (err) {
|
|
179
182
|
searchDebugWarn("vector.index", "Vector entry decryption failed; refusing to return ciphertext as plaintext", {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/vector/services/vector-index.service.ts"],
|
|
4
|
-
"sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport {\n type VectorModuleConfig,\n type VectorEntityConfig,\n type VectorQueryRequest,\n type VectorSearchHit,\n type VectorIndexSource,\n type VectorDriverId,\n type VectorLinkDescriptor,\n type VectorResultPresenter,\n type VectorIndexEntry,\n} from '../types'\nimport type { VectorDriver } from '../types'\nimport type { SearchFieldPolicy } from '@open-mercato/shared/modules/search'\nimport { computeChecksum } from './checksum'\nimport { EmbeddingService } from './embedding'\nimport { logVectorOperation } from '../lib/vector-logs'\nimport { searchDebug, searchDebugWarn } from '../../lib/debug'\n\ntype ContainerResolver = () => unknown\nconst VECTOR_ENTRY_ENCRYPTION_ENTITY_ID = 'vector:vector_search'\n\nconst DEFAULT_SOURCE_SCOPE_FIELDS = new Set<string>([\n 'id',\n 'tenant_id',\n 'tenantId',\n 'organization_id',\n 'organizationId',\n 'created_at',\n 'createdAt',\n 'updated_at',\n 'updatedAt',\n 'deleted_at',\n 'deletedAt',\n])\n\nconst ENRICHMENT_FIELD_HINTS: Record<EntityId, string[]> = {\n 'customers:customer_entity': [\n 'id',\n 'organization_id',\n 'tenant_id',\n 'display_name',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'primary_email',\n 'primary_phone',\n 'kind',\n 'customer_kind',\n ],\n 'customers:customer_comment': ['id', 'organization_id', 'tenant_id', 'entity_id', 'body', 'appearance_icon', 'appearance_color'],\n 'customers:customer_activity': ['id', 'organization_id', 'tenant_id', 'entity_id', 'activity_type', 'subject', 'body', 'deal_id'],\n 'customers:customer_deal': ['id', 'organization_id', 'tenant_id', 'title', 'pipeline_stage', 'status', 'value_amount', 'value_currency'],\n 'customers:customer_todo_link': ['id', 'organization_id', 'tenant_id', 'entity_id', 'todo_id', 'todo_source'],\n 'customers:customer_person_profile': [\n 'id',\n 'organization_id',\n 'tenant_id',\n 'entity_id',\n 'first_name',\n 'last_name',\n 'preferred_name',\n 'job_title',\n 'department',\n ],\n 'customers:customer_company_profile': [\n 'id',\n 'organization_id',\n 'tenant_id',\n 'entity_id',\n 'brand_name',\n 'legal_name',\n 'domain',\n 'industry',\n 'size_bucket',\n ],\n}\n\nexport type VectorIndexServiceOptions = {\n drivers: VectorDriver[]\n embeddingService: EmbeddingService\n queryEngine: QueryEngine\n moduleConfigs: VectorModuleConfig[]\n defaultDriverId?: VectorDriverId\n containerResolver?: ContainerResolver\n eventBus?: {\n emitEvent(event: string, payload: any, options?: any): Promise<void>\n }\n}\n\ntype IndexRecordArgs = {\n entityId: EntityId\n recordId: string\n tenantId: string\n organizationId?: string | null\n}\n\ntype DeleteRecordArgs = {\n entityId: EntityId\n recordId: string\n tenantId: string\n organizationId?: string | null\n}\n\nexport type VectorIndexOperationResult = {\n action: 'indexed' | 'deleted' | 'skipped'\n created?: boolean\n existed?: boolean\n tenantId: string\n organizationId: string | null\n reason?: 'unsupported' | 'missing_record' | 'checksum_match'\n}\n\nexport class VectorIndexService {\n private readonly driverMap = new Map<VectorDriverId, VectorDriver>()\n private readonly entityConfig = new Map<EntityId, { config: VectorEntityConfig; driverId: VectorDriverId }>()\n private readonly defaultDriverId: VectorDriverId\n\n constructor(private readonly opts: VectorIndexServiceOptions) {\n for (const driver of opts.drivers) {\n this.driverMap.set(driver.id, driver)\n }\n this.defaultDriverId = opts.defaultDriverId ?? 'pgvector'\n for (const moduleConfig of opts.moduleConfigs) {\n const driverId = moduleConfig.defaultDriverId ?? this.defaultDriverId\n for (const entity of moduleConfig.entities ?? []) {\n if (!entity?.entityId) continue\n if (entity.enabled === false) continue\n const targetDriver = entity.driverId ?? driverId\n this.entityConfig.set(entity.entityId, { config: entity, driverId: targetDriver })\n }\n }\n }\n\n private resolveEncryptionService(): TenantDataEncryptionService | null {\n if (!this.opts.containerResolver) return null\n try {\n const container = this.opts.containerResolver() as any\n if (!container || typeof container.resolve !== 'function') return null\n return container.resolve('tenantEncryptionService') as TenantDataEncryptionService\n } catch {\n return null\n }\n }\n\n private async encryptResultFields(args: {\n tenantId: string\n organizationId: string | null\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }): Promise<{\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }> {\n const service = this.resolveEncryptionService()\n if (!service || !service.isEnabled?.()) {\n return {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n }\n }\n try {\n const encrypted = await service.encryptEntityPayload(\n VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n },\n args.tenantId,\n args.organizationId,\n )\n return {\n resultTitle: String((encrypted as any).resultTitle ?? args.resultTitle),\n resultSubtitle: ((encrypted as any).resultSubtitle ?? args.resultSubtitle) as any,\n resultIcon: ((encrypted as any).resultIcon ?? args.resultIcon) as any,\n resultSnapshot: ((encrypted as any).resultSnapshot ?? args.resultSnapshot) as any,\n primaryLinkHref: ((encrypted as any).primaryLinkHref ?? args.primaryLinkHref) as any,\n primaryLinkLabel: ((encrypted as any).primaryLinkLabel ?? args.primaryLinkLabel) as any,\n links: ((encrypted as any).links ?? args.links) as any,\n payload: ((encrypted as any).payload ?? args.payload) as any,\n }\n } catch (err) {\n searchDebugWarn('vector.index', 'Vector entry encryption failed; refusing to persist plaintext', {\n entityId: VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n error: err instanceof Error ? err.message : String(err),\n })\n throw err instanceof Error\n ? err\n : new Error('[internal] Vector entry encryption failed')\n }\n }\n\n private async decryptResultFields(args: {\n tenantId: string\n organizationId: string | null\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }): Promise<{\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }> {\n const service = this.resolveEncryptionService()\n if (!service || !service.isEnabled?.() || typeof service.decryptEntityPayload !== 'function') {\n return {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n }\n }\n try {\n const decrypted = await service.decryptEntityPayload(\n VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n },\n args.tenantId,\n args.organizationId,\n )\n return {\n resultTitle: String((decrypted as any).resultTitle ?? args.resultTitle),\n resultSubtitle: ((decrypted as any).resultSubtitle ?? args.resultSubtitle) as any,\n resultIcon: ((decrypted as any).resultIcon ?? args.resultIcon) as any,\n resultSnapshot: ((decrypted as any).resultSnapshot ?? args.resultSnapshot) as any,\n primaryLinkHref: ((decrypted as any).primaryLinkHref ?? args.primaryLinkHref) as any,\n primaryLinkLabel: ((decrypted as any).primaryLinkLabel ?? args.primaryLinkLabel) as any,\n links: ((decrypted as any).links ?? args.links) as any,\n payload: ((decrypted as any).payload ?? args.payload) as any,\n }\n } catch (err) {\n searchDebugWarn('vector.index', 'Vector entry decryption failed; refusing to return ciphertext as plaintext', {\n entityId: VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n error: err instanceof Error ? err.message : String(err),\n })\n throw err instanceof Error\n ? err\n : new Error('[internal] Vector entry decryption failed')\n }\n }\n\n listEnabledEntities(): EntityId[] {\n return Array.from(this.entityConfig.keys())\n }\n\n async ensureDriverReady(entityId?: EntityId): Promise<void> {\n if (entityId) {\n const entry = this.entityConfig.get(entityId)\n if (!entry) return\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n return\n }\n const uniqueDrivers = new Set<VectorDriverId>()\n for (const entry of this.entityConfig.values()) {\n uniqueDrivers.add(entry.driverId)\n }\n if (!uniqueDrivers.size) uniqueDrivers.add(this.defaultDriverId)\n await Promise.all(Array.from(uniqueDrivers).map(async (driverId) => {\n try {\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n } catch (err) {\n searchDebugWarn('vector', 'Failed to ensure driver readiness', { driverId, error: err instanceof Error ? err.message : err })\n }\n }))\n }\n\n private getDriver(driverId: VectorDriverId): VectorDriver {\n const driver = this.driverMap.get(driverId)\n if (!driver) {\n throw new Error(`[vector] Driver ${driverId} is not registered`)\n }\n return driver\n }\n\n private getEnrichmentFields(entityId: EntityId): string[] | undefined {\n const hints = ENRICHMENT_FIELD_HINTS[entityId]\n if (!hints) return undefined\n const unique = new Set<string>(['id', ...hints])\n return Array.from(unique)\n }\n\n private async fetchRecord(entityId: EntityId, recordIds: string[], tenantId: string, organizationId?: string | null) {\n const filters: Record<string, any> = { id: { $in: recordIds } }\n const result = await this.opts.queryEngine.query(entityId, {\n tenantId,\n organizationId: organizationId ?? undefined,\n filters,\n includeCustomFields: true,\n fields: this.getEnrichmentFields(entityId),\n skipAutoReindex: true,\n })\n const byId = new Map<string, Record<string, any>>()\n for (const item of result.items) {\n const key = String((item as any).id ?? '')\n if (!key) continue\n byId.set(key, item as Record<string, any>)\n }\n return byId\n }\n\n private extractRecordPayload(entityId: EntityId, raw: Record<string, any>) {\n const record: Record<string, any> = {}\n const customFields: Record<string, any> = {}\n const multiMap = new Map<string, boolean>()\n\n for (const [key, value] of Object.entries(raw)) {\n if (key.startsWith('cf:') && key.endsWith('__is_multi')) {\n const base = key.replace(/__is_multi$/, '')\n multiMap.set(base, Boolean(value))\n continue\n }\n if (key.startsWith('cf:')) {\n customFields[key.slice(3)] = value\n continue\n }\n record[key] = value\n }\n\n for (const [key, isMulti] of multiMap.entries()) {\n const bare = key.slice(3)\n if (bare && customFields[bare] != null && !Array.isArray(customFields[bare]) && isMulti) {\n customFields[bare] = [customFields[bare]]\n }\n }\n\n if (record.entity_id == null && record.entityId == null && entityId.endsWith('_company_profile')) {\n searchDebugWarn('vector.index', 'company profile missing entity id in payload', {\n id: record.id,\n keys: Object.keys(record),\n })\n }\n\n return { record, customFields }\n }\n\n private async indexExisting(\n entry: { config: VectorEntityConfig; driverId: VectorDriverId },\n driver: VectorDriver,\n args: IndexRecordArgs,\n raw: Record<string, any>,\n opts: { skipDelete?: boolean } = {},\n ): Promise<VectorIndexOperationResult> {\n const scopeOrg = args.organizationId ?? null\n const { record, customFields } = this.extractRecordPayload(args.entityId, raw)\n const resolvedOrgId = scopeOrg ?? (record.organization_id ?? record.organizationId ?? null)\n const source = await this.resolveSource(args.entityId, entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n })\n if (!source) {\n const existing = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (!opts.skipDelete && existing) {\n await driver.delete(args.entityId, args.recordId, args.tenantId)\n return {\n action: 'deleted',\n existed: true,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }\n }\n return {\n action: 'skipped',\n existed: Boolean(existing),\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n reason: 'missing_record',\n }\n }\n\n const checksumSource = source.checksumSource ?? { record, customFields }\n const checksum = computeChecksum(checksumSource)\n const current = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (current && current === checksum) {\n return {\n action: 'skipped',\n existed: true,\n tenantId: args.tenantId,\n organizationId: scopeOrg,\n reason: 'checksum_match',\n }\n }\n if (!this.opts.embeddingService.available) {\n throw new Error('[vector] Embedding service unavailable (missing OPENAI_API_KEY)')\n }\n const embedding = await this.opts.embeddingService.createEmbedding(source.input)\n const presenter = await this.resolvePresenter(entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }, source.presenter ?? null)\n if (!presenter?.title) {\n searchDebugWarn('vector.index', 'missing presenter title', {\n entityId: args.entityId,\n recordId: args.recordId,\n recordSample: {\n display_name: record.display_name,\n displayName: record.displayName,\n name: record.name,\n title: record.title,\n subject: record.subject,\n kind: record.kind,\n },\n })\n }\n const links = await this.resolveLinks(entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }, source.links ?? null)\n const url = await this.resolveUrl(entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n })\n\n const normalizedPresenter = this.ensurePresenter(presenter, record, customFields, args.recordId, args.entityId)\n const normalizedLinks = Array.isArray(links) && links.length ? links : null\n const snapshot = this.deriveSnapshot(record, customFields)\n const rawResultTitle = this.resolveResultTitle(normalizedPresenter, record, customFields, args.recordId)\n const rawResultSubtitle = normalizedPresenter.subtitle ?? snapshot ?? null\n const rawResultIcon = normalizedPresenter.icon ?? this.mapDefaultIcon(args.entityId)\n const resultBadge = normalizedPresenter.badge ?? null\n const primaryLink = this.resolvePrimaryLink(normalizedLinks, url, rawResultTitle)\n\n const encryptedResult = await this.encryptResultFields({\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n resultTitle: rawResultTitle,\n resultSubtitle: rawResultSubtitle,\n resultIcon: rawResultIcon ?? null,\n resultSnapshot: snapshot ?? null,\n primaryLinkHref: primaryLink?.href ?? null,\n primaryLinkLabel: primaryLink?.label ?? null,\n links: normalizedLinks,\n payload: source.payload ?? null,\n })\n\n const presenterForStorage: VectorResultPresenter = {\n title: encryptedResult.resultTitle,\n subtitle: encryptedResult.resultSubtitle ?? undefined,\n icon: encryptedResult.resultIcon ?? undefined,\n badge: resultBadge ?? undefined,\n }\n\n searchDebug('VectorIndexService', 'Storing vector index entry', {\n entityId: args.entityId,\n recordId: args.recordId,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n })\n await driver.upsert({\n driverId: entry.driverId,\n entityId: args.entityId,\n recordId: args.recordId,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n checksum,\n embedding,\n url: url ?? null,\n presenter: presenterForStorage,\n links: (encryptedResult.links as any) ?? normalizedLinks,\n payload: (encryptedResult.payload as any) ?? source.payload ?? null,\n resultTitle: encryptedResult.resultTitle,\n resultSubtitle: encryptedResult.resultSubtitle,\n resultIcon: encryptedResult.resultIcon ?? null,\n resultBadge,\n resultSnapshot: encryptedResult.resultSnapshot ?? snapshot,\n primaryLinkHref: encryptedResult.primaryLinkHref ?? primaryLink?.href ?? null,\n primaryLinkLabel: encryptedResult.primaryLinkLabel ?? null,\n })\n\n return {\n action: 'indexed',\n created: !current,\n existed: true,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }\n }\n\n private ensurePresenter(\n presenter: VectorResultPresenter | null,\n record: Record<string, any>,\n customFields: Record<string, any>,\n recordId: string,\n entityId: EntityId,\n ): VectorResultPresenter {\n if (presenter?.title) return presenter\n const fallback = this.buildFallbackPresenter(record, customFields, recordId, entityId)\n return fallback\n }\n\n private resolveResultTitle(\n presenter: VectorResultPresenter,\n record: Record<string, any>,\n customFields: Record<string, any>,\n recordId: string,\n ): string {\n const candidate =\n presenter.title ??\n record.display_name ??\n record.displayName ??\n record.name ??\n record.title ??\n record.subject ??\n customFields.title ??\n customFields.name ??\n recordId\n const text = String(candidate).trim()\n return text.length ? text : recordId\n }\n\n private buildFallbackPresenter(\n record: Record<string, any>,\n customFields: Record<string, any>,\n recordId: string,\n entityId: EntityId,\n ): VectorResultPresenter {\n const titleCandidate =\n record.display_name ??\n record.displayName ??\n record.name ??\n record.title ??\n record.subject ??\n recordId\n const subtitleCandidate =\n record.description ??\n record.summary ??\n record.body ??\n customFields.summary ??\n customFields.description ??\n null\n const icon = typeof record.kind === 'string'\n ? this.mapEntityIcon(record.kind)\n : this.mapDefaultIcon(entityId)\n return {\n title: String(titleCandidate),\n subtitle: subtitleCandidate ? String(subtitleCandidate) : undefined,\n icon: icon ?? undefined,\n }\n }\n\n private mapEntityIcon(kind?: string | null): string | null {\n if (!kind) return null\n const normalized = kind.toLowerCase()\n if (normalized === 'person') return 'user'\n if (normalized === 'company' || normalized === 'organization') return 'building'\n return null\n }\n\n private mapDefaultIcon(entityId: EntityId): string | null {\n if (entityId.startsWith('customers:customer_deal')) return 'briefcase'\n if (entityId.startsWith('customers:customer_comment')) return 'sticky-note'\n if (entityId.startsWith('customers:customer_activity')) return 'bolt'\n if (entityId.startsWith('customers:customer_todo')) return 'check-square'\n return null\n }\n\n private resolvePrimaryLink(\n links: VectorLinkDescriptor[] | null,\n url: string | null,\n fallbackLabel: string,\n ): { href: string; label: string } | null {\n if (links?.length) {\n const primary = links.find((link) => link.kind === 'primary') ?? links[0]\n if (primary?.href) {\n return { href: primary.href, label: primary.label ?? fallbackLabel }\n }\n }\n if (url) {\n return { href: url, label: fallbackLabel }\n }\n return null\n }\n\n private deriveSnapshot(\n record: Record<string, any>,\n customFields: Record<string, any>,\n ): string | null {\n const candidates = [\n record.summary,\n record.description,\n record.body,\n customFields.summary,\n customFields.description,\n customFields.body,\n ]\n for (const value of candidates) {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed.length) return trimmed\n }\n }\n return null\n }\n\n private buildDefaultSource(\n entityId: EntityId,\n payload: { record: Record<string, any>; customFields: Record<string, any> },\n fieldPolicy?: SearchFieldPolicy,\n ): VectorIndexSource {\n const { record, customFields } = payload\n const lines: string[] = []\n\n const searchableWhitelist = fieldPolicy?.searchable ? new Set(fieldPolicy.searchable) : null\n const excludedFields = new Set<string>([\n ...(fieldPolicy?.excluded ?? []),\n ...(fieldPolicy?.hashOnly ?? []),\n ])\n\n const isEligibleField = (field: string): boolean => {\n if (DEFAULT_SOURCE_SCOPE_FIELDS.has(field)) return false\n if (excludedFields.has(field)) return false\n if (searchableWhitelist && !searchableWhitelist.has(field)) return false\n return true\n }\n\n const pushEntry = (label: string, value: unknown) => {\n if (value === null || value === undefined) return\n if (typeof value === 'string' && value.trim().length === 0) return\n if (typeof value === 'object') {\n lines.push(`${label}: ${JSON.stringify(value)}`)\n } else {\n lines.push(`${label}: ${value}`)\n }\n }\n\n const preferredFields = ['title', 'name', 'displayName', 'summary', 'subject']\n for (const field of preferredFields) {\n if (!isEligibleField(field)) continue\n if (record[field] != null) pushEntry(field, record[field])\n }\n\n for (const [key, value] of Object.entries(record)) {\n if (preferredFields.includes(key)) continue\n if (!isEligibleField(key)) continue\n pushEntry(key, value)\n }\n\n for (const [key, value] of Object.entries(customFields)) {\n if (!isEligibleField(key)) continue\n pushEntry(`custom.${key}`, value)\n }\n\n if (lines.length === 0) {\n lines.push(`${entityId}#${record.id ?? ''}`)\n }\n\n return {\n input: lines,\n payload: null,\n checksumSource: { record, customFields },\n }\n }\n\n private async resolveSource(entityId: EntityId, config: VectorEntityConfig, ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n }): Promise<VectorIndexSource | null> {\n const baseCtx = {\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n }\n if (config.buildSource) {\n const built = await config.buildSource(baseCtx)\n if (built) return built\n return null\n }\n return this.buildDefaultSource(entityId, { record: ctx.record, customFields: ctx.customFields }, config.fieldPolicy)\n }\n\n private async resolvePresenter(\n config: VectorEntityConfig,\n ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n },\n fallback?: VectorResultPresenter | null,\n ): Promise<VectorResultPresenter | null> {\n const baseCtx = {\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n }\n if (config.formatResult) {\n const formatted = await config.formatResult(baseCtx)\n if (formatted) return formatted\n }\n if (fallback) return fallback\n const nameLike = ctx.record.displayName || ctx.record.title || ctx.record.name\n if (typeof nameLike === 'string' && nameLike.trim().length > 0) {\n const subtitle = ctx.record.description || ctx.record.summary\n return {\n title: nameLike,\n subtitle: typeof subtitle === 'string' ? subtitle : undefined,\n }\n }\n return null\n }\n\n private async resolveLinks(\n config: VectorEntityConfig,\n ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n },\n fallback?: VectorLinkDescriptor[] | null,\n ): Promise<VectorLinkDescriptor[] | null> {\n const baseCtx = {\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n }\n if (config.resolveLinks) {\n const resolved = await config.resolveLinks(baseCtx)\n if (resolved?.length) return resolved\n }\n return fallback ?? null\n }\n\n private async resolveUrl(\n config: VectorEntityConfig,\n ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n },\n fallback?: string | null,\n ): Promise<string | null> {\n if (config.resolveUrl) {\n const candidate = await config.resolveUrl({\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n })\n if (candidate) return candidate\n }\n return fallback ?? null\n }\n\n async indexRecord(args: IndexRecordArgs): Promise<VectorIndexOperationResult> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) {\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n reason: 'unsupported',\n }\n }\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n\n const records = await this.fetchRecord(args.entityId, [args.recordId], args.tenantId, args.organizationId)\n const raw = records.get(args.recordId)\n if (!raw) {\n const existing = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (existing) {\n await driver.delete(args.entityId, args.recordId, args.tenantId)\n return {\n action: 'deleted',\n existed: true,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n }\n }\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n reason: 'missing_record',\n }\n }\n return this.indexExisting(entry, driver, args, raw as Record<string, any>)\n }\n\n async deleteRecord(args: DeleteRecordArgs): Promise<VectorIndexOperationResult> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) {\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n reason: 'unsupported',\n }\n }\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n const scopeOrg = args.organizationId ?? null\n const existing = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (existing) {\n await driver.delete(args.entityId, args.recordId, args.tenantId)\n return {\n action: 'deleted',\n existed: true,\n tenantId: args.tenantId,\n organizationId: scopeOrg,\n }\n }\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: scopeOrg,\n reason: 'missing_record',\n }\n }\n\n async reindexEntity(args: { entityId: EntityId; tenantId?: string | null; organizationId?: string | null; purgeFirst?: boolean }): Promise<void> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) return\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n\n const shouldPurge = args.purgeFirst === true\n const reindexStartedAt = new Date()\n\n if (this.opts.eventBus) {\n if (shouldPurge && driver.purge && args.tenantId) {\n await driver.purge(args.entityId, args.tenantId, args.organizationId)\n } else if (shouldPurge && !args.tenantId) {\n searchDebugWarn('vector', 'Skipping purge for multi-tenant reindex (tenant not provided)')\n }\n const payload: Record<string, unknown> = {\n entityType: args.entityId,\n }\n if (shouldPurge) {\n payload.force = true\n payload.resetCoverage = true\n }\n if (args.tenantId !== undefined) payload.tenantId = args.tenantId\n else payload.allowAllTenants = true\n if (args.organizationId !== undefined) payload.organizationId = args.organizationId\n await this.opts.eventBus.emitEvent('query_index.reindex', payload)\n return\n }\n\n if (!args.tenantId) {\n throw new Error('[vector] Reindex without tenantId requires event bus integration')\n }\n\n if (shouldPurge && driver.purge) {\n await driver.purge(args.entityId, args.tenantId, args.organizationId)\n }\n\n const pageSize = 50\n let page = 1\n const loggingEm = this.resolveEntityManager()\n for (;;) {\n const result = await this.opts.queryEngine.query(args.entityId, {\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? undefined,\n page: { page, pageSize },\n includeCustomFields: true,\n fields: this.getEnrichmentFields(args.entityId),\n skipAutoReindex: true,\n })\n if (!result.items.length) break\n for (const raw of result.items) {\n const recordId = String((raw as any).id ?? '')\n if (!recordId) continue\n const opResult = await this.indexExisting(\n entry,\n driver,\n {\n entityId: args.entityId,\n recordId,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n },\n raw as Record<string, any>,\n { skipDelete: true },\n )\n await logVectorOperation({\n em: loggingEm,\n handler: 'service:vector.reindex',\n entityType: args.entityId,\n recordId,\n result: opResult,\n })\n }\n if (result.items.length < pageSize) break\n page += 1\n }\n\n if (shouldPurge) {\n await this.removeOrphans({\n entityId: args.entityId,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n olderThan: reindexStartedAt,\n })\n }\n }\n\n async reindexAll(args: { tenantId?: string | null; organizationId?: string | null; purgeFirst?: boolean }): Promise<void> {\n for (const entityId of this.listEnabledEntities()) {\n await this.reindexEntity({ entityId, tenantId: args.tenantId, organizationId: args.organizationId ?? null, purgeFirst: args.purgeFirst })\n }\n }\n\n private resolveEntityManager(): EntityManager | null {\n if (!this.opts.containerResolver) return null\n try {\n const container = this.opts.containerResolver()\n if (!container || typeof (container as any).resolve !== 'function') return null\n const resolver = container as { resolve(name: string): unknown }\n const em = resolver.resolve('em')\n return (em as EntityManager | null) ?? null\n } catch {\n return null\n }\n }\n\n async purgeIndex(args: { tenantId: string; organizationId?: string | null; entityId?: EntityId | null }): Promise<void> {\n const targets = args.entityId ? [args.entityId] : this.listEnabledEntities()\n if (!targets.length) return\n\n const grouped = new Map<VectorDriverId, EntityId[]>()\n for (const entityId of targets) {\n const cfg = this.entityConfig.get(entityId)\n if (!cfg) continue\n const driver = this.getDriver(cfg.driverId)\n if (typeof driver.purge !== 'function') {\n throw new Error(`[vector] Driver ${cfg.driverId} does not support purging entities`)\n }\n if (!grouped.has(cfg.driverId)) grouped.set(cfg.driverId, [])\n grouped.get(cfg.driverId)!.push(entityId)\n }\n\n for (const [driverId, entityIds] of grouped.entries()) {\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n for (const entityId of entityIds) {\n await driver.purge!(entityId, args.tenantId)\n }\n }\n }\n\n async removeOrphans(args: {\n entityId: EntityId\n tenantId?: string | null\n organizationId?: string | null\n olderThan: Date\n }): Promise<number> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) return 0\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n\n const driverAny = driver as VectorDriver & {\n removeOrphans?: (params: {\n entityId: EntityId\n tenantId?: string | null\n organizationId?: string | null\n olderThan: Date\n }) => Promise<number | void>\n }\n\n if (typeof driverAny.removeOrphans === 'function') {\n const deleted = await driverAny.removeOrphans({\n entityId: args.entityId,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n olderThan: args.olderThan,\n })\n return typeof deleted === 'number' ? deleted : 0\n }\n\n searchDebugWarn('vector', 'Driver does not support orphan cleanup', { driverId: entry.driverId })\n return 0\n }\n\n async countIndexEntries(args: {\n tenantId: string\n organizationId?: string | null\n entityId?: EntityId\n driverId?: VectorDriverId\n }): Promise<number> {\n if (!args.tenantId) return 0\n const targetEntity = args.entityId ? this.entityConfig.get(args.entityId) : null\n if (args.entityId && !targetEntity) {\n return 0\n }\n const driverId =\n args.driverId ??\n (targetEntity ? targetEntity.driverId : this.defaultDriverId)\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n const countParams = {\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n entityId: args.entityId,\n }\n if (typeof driver.count === 'function') {\n try {\n return await driver.count(countParams)\n } catch (err) {\n searchDebugWarn('vector', 'Driver count failed, falling back to list', {\n driverId,\n error: err instanceof Error ? err.message : err,\n })\n }\n }\n if (typeof driver.list === 'function') {\n const limit = 1000\n let offset = 0\n let total = 0\n for (;;) {\n const batch = await driver.list({\n tenantId: countParams.tenantId,\n organizationId: countParams.organizationId,\n entityId: countParams.entityId,\n limit,\n offset,\n orderBy: 'created',\n })\n const size = batch.length\n total += size\n if (size < limit) break\n offset += limit\n }\n return total\n }\n searchDebugWarn('vector', 'Driver does not support counting or listing index entries', { driverId })\n return 0\n }\n\n async listIndexEntries(args: {\n tenantId: string\n organizationId?: string | null\n entityId?: EntityId\n limit?: number\n offset?: number\n driverId?: VectorDriverId\n }): Promise<VectorIndexEntry[]> {\n const targetEntity = args.entityId ? this.entityConfig.get(args.entityId) : null\n if (args.entityId && !targetEntity) {\n return []\n }\n const driverId =\n args.driverId ??\n (targetEntity ? targetEntity.driverId : this.defaultDriverId)\n const driver = this.getDriver(driverId)\n if (typeof driver.list !== 'function') {\n throw new Error(`[vector] Driver ${driverId} does not support listing index entries`)\n }\n await driver.ensureReady()\n const list = await driver.list({\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n entityId: args.entityId,\n limit: args.limit,\n offset: args.offset,\n orderBy: 'updated',\n })\n if (!list.length) {\n return []\n }\n\n const decrypted = await Promise.all(\n list.map(async (entry) => {\n const decryptedResult = await this.decryptResultFields({\n tenantId: args.tenantId,\n organizationId: entry.organizationId ?? null,\n resultTitle: entry.resultTitle,\n resultSubtitle: entry.resultSubtitle ?? null,\n resultIcon: entry.resultIcon ?? null,\n resultSnapshot: entry.resultSnapshot ?? null,\n primaryLinkHref: entry.primaryLinkHref ?? null,\n primaryLinkLabel: entry.primaryLinkLabel ?? null,\n links: (entry.links as any) ?? null,\n payload: (entry.payload as any) ?? null,\n })\n return {\n ...entry,\n resultTitle: decryptedResult.resultTitle,\n resultSubtitle: decryptedResult.resultSubtitle,\n resultIcon: decryptedResult.resultIcon,\n resultSnapshot: decryptedResult.resultSnapshot,\n primaryLinkHref: decryptedResult.primaryLinkHref,\n primaryLinkLabel: decryptedResult.primaryLinkLabel,\n links: decryptedResult.links as any,\n payload: decryptedResult.payload as any,\n metadata: (decryptedResult.payload as any) ?? null,\n }\n }),\n )\n\n return decrypted.map((entry) => {\n const presenter = {\n title: entry.resultTitle,\n subtitle: entry.resultSubtitle ?? undefined,\n icon: entry.resultIcon ?? undefined,\n badge: entry.presenter?.badge ?? entry.resultBadge ?? undefined,\n }\n const links = entry.links ?? (entry.primaryLinkHref\n ? [{ href: entry.primaryLinkHref, label: entry.primaryLinkLabel ?? entry.resultTitle, kind: 'primary' as const }]\n : null)\n const url = entry.url ?? entry.primaryLinkHref ?? null\n const metadata = entry.metadata ?? (entry.resultSnapshot ? { snapshot: entry.resultSnapshot } : null)\n return {\n ...entry,\n driverId,\n presenter,\n links,\n url,\n metadata,\n score: entry.score ?? null,\n }\n })\n }\n\n async search(request: VectorQueryRequest): Promise<VectorSearchHit[]> {\n const driverId = request.driverId ?? this.defaultDriverId\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n if (!this.opts.embeddingService.available) {\n throw new Error('[vector] Embedding service unavailable (missing OPENAI_API_KEY)')\n }\n const embedding = await this.opts.embeddingService.createEmbedding(request.query)\n const hits = await driver.query({\n vector: embedding,\n limit: request.limit ?? 10,\n filter: {\n tenantId: request.tenantId,\n organizationId: request.organizationId ?? null,\n entityIds: undefined,\n },\n })\n\n if (!hits.length) return []\n\n const decrypted = await Promise.all(\n hits.map(async (hit) => {\n const decryptedResult = await this.decryptResultFields({\n tenantId: request.tenantId,\n organizationId: hit.organizationId ?? request.organizationId ?? null,\n resultTitle: hit.resultTitle,\n resultSubtitle: hit.resultSubtitle ?? null,\n resultIcon: hit.resultIcon ?? null,\n resultSnapshot: hit.resultSnapshot ?? null,\n primaryLinkHref: hit.primaryLinkHref ?? null,\n primaryLinkLabel: hit.primaryLinkLabel ?? null,\n links: (hit.links as any) ?? null,\n payload: (hit.payload as any) ?? null,\n })\n return {\n ...hit,\n resultTitle: decryptedResult.resultTitle,\n resultSubtitle: decryptedResult.resultSubtitle,\n resultIcon: decryptedResult.resultIcon,\n resultSnapshot: decryptedResult.resultSnapshot,\n primaryLinkHref: decryptedResult.primaryLinkHref,\n primaryLinkLabel: decryptedResult.primaryLinkLabel,\n links: decryptedResult.links as any,\n payload: decryptedResult.payload as any,\n }\n }),\n )\n\n return decrypted.map((hit) => {\n const presenter = {\n title: hit.resultTitle,\n subtitle: hit.resultSubtitle ?? undefined,\n icon: hit.resultIcon ?? undefined,\n badge: hit.presenter?.badge ?? hit.resultBadge ?? undefined,\n }\n const links = hit.links ?? (hit.primaryLinkHref\n ? [{ href: hit.primaryLinkHref, label: hit.primaryLinkLabel ?? hit.resultTitle, kind: 'primary' as const }]\n : null)\n const url = hit.url ?? hit.primaryLinkHref ?? null\n const metadata = hit.payload ?? (hit.resultSnapshot ? { snapshot: hit.resultSnapshot } : null)\n return {\n entityId: hit.entityId,\n recordId: hit.recordId,\n score: hit.score,\n url,\n presenter,\n links,\n driverId,\n metadata,\n }\n })\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\nimport {\n type VectorModuleConfig,\n type VectorEntityConfig,\n type VectorQueryRequest,\n type VectorSearchHit,\n type VectorIndexSource,\n type VectorDriverId,\n type VectorLinkDescriptor,\n type VectorResultPresenter,\n type VectorIndexEntry,\n} from '../types'\nimport type { VectorDriver } from '../types'\nimport type { SearchFieldPolicy } from '@open-mercato/shared/modules/search'\nimport { computeChecksum } from './checksum'\nimport { EmbeddingService } from './embedding'\nimport { logVectorOperation } from '../lib/vector-logs'\nimport { searchDebug, searchDebugWarn } from '../../lib/debug'\n\ntype ContainerResolver = () => unknown\nconst VECTOR_ENTRY_ENCRYPTION_ENTITY_ID = 'vector:vector_search'\n\nconst DEFAULT_SOURCE_SCOPE_FIELDS = new Set<string>([\n 'id',\n 'tenant_id',\n 'tenantId',\n 'organization_id',\n 'organizationId',\n 'created_at',\n 'createdAt',\n 'updated_at',\n 'updatedAt',\n 'deleted_at',\n 'deletedAt',\n])\n\nconst ENRICHMENT_FIELD_HINTS: Record<EntityId, string[]> = {\n 'customers:customer_entity': [\n 'id',\n 'organization_id',\n 'tenant_id',\n 'display_name',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'primary_email',\n 'primary_phone',\n 'kind',\n 'customer_kind',\n ],\n 'customers:customer_comment': ['id', 'organization_id', 'tenant_id', 'entity_id', 'body', 'appearance_icon', 'appearance_color'],\n 'customers:customer_activity': ['id', 'organization_id', 'tenant_id', 'entity_id', 'activity_type', 'subject', 'body', 'deal_id'],\n 'customers:customer_deal': ['id', 'organization_id', 'tenant_id', 'title', 'pipeline_stage', 'status', 'value_amount', 'value_currency'],\n 'customers:customer_todo_link': ['id', 'organization_id', 'tenant_id', 'entity_id', 'todo_id', 'todo_source'],\n 'customers:customer_person_profile': [\n 'id',\n 'organization_id',\n 'tenant_id',\n 'entity_id',\n 'first_name',\n 'last_name',\n 'preferred_name',\n 'job_title',\n 'department',\n ],\n 'customers:customer_company_profile': [\n 'id',\n 'organization_id',\n 'tenant_id',\n 'entity_id',\n 'brand_name',\n 'legal_name',\n 'domain',\n 'industry',\n 'size_bucket',\n ],\n}\n\nexport type VectorIndexServiceOptions = {\n drivers: VectorDriver[]\n embeddingService: EmbeddingService\n queryEngine: QueryEngine\n moduleConfigs: VectorModuleConfig[]\n defaultDriverId?: VectorDriverId\n containerResolver?: ContainerResolver\n eventBus?: {\n emitEvent(event: string, payload: any, options?: any): Promise<void>\n }\n}\n\ntype IndexRecordArgs = {\n entityId: EntityId\n recordId: string\n tenantId: string\n organizationId?: string | null\n}\n\ntype DeleteRecordArgs = {\n entityId: EntityId\n recordId: string\n tenantId: string\n organizationId?: string | null\n}\n\nexport type VectorIndexOperationResult = {\n action: 'indexed' | 'deleted' | 'skipped'\n created?: boolean\n existed?: boolean\n tenantId: string\n organizationId: string | null\n reason?: 'unsupported' | 'missing_record' | 'checksum_match'\n}\n\nexport class VectorIndexService {\n private readonly driverMap = new Map<VectorDriverId, VectorDriver>()\n private readonly entityConfig = new Map<EntityId, { config: VectorEntityConfig; driverId: VectorDriverId }>()\n private readonly defaultDriverId: VectorDriverId\n\n constructor(private readonly opts: VectorIndexServiceOptions) {\n for (const driver of opts.drivers) {\n this.driverMap.set(driver.id, driver)\n }\n this.defaultDriverId = opts.defaultDriverId ?? 'pgvector'\n for (const moduleConfig of opts.moduleConfigs) {\n const driverId = moduleConfig.defaultDriverId ?? this.defaultDriverId\n for (const entity of moduleConfig.entities ?? []) {\n if (!entity?.entityId) continue\n if (entity.enabled === false) continue\n const targetDriver = entity.driverId ?? driverId\n this.entityConfig.set(entity.entityId, { config: entity, driverId: targetDriver })\n }\n }\n }\n\n private resolveEncryptionService(): TenantDataEncryptionService | null {\n if (!this.opts.containerResolver) return null\n try {\n const container = this.opts.containerResolver() as any\n if (!container || typeof container.resolve !== 'function') return null\n return container.resolve('tenantEncryptionService') as TenantDataEncryptionService\n } catch {\n return null\n }\n }\n\n private async encryptResultFields(args: {\n tenantId: string\n organizationId: string | null\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }): Promise<{\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }> {\n const service = this.resolveEncryptionService()\n if (!service || !service.isEnabled?.()) {\n return {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n }\n }\n try {\n const encrypted = await service.encryptEntityPayload(\n VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n },\n args.tenantId,\n args.organizationId,\n )\n return {\n resultTitle: String((encrypted as any).resultTitle ?? args.resultTitle),\n resultSubtitle: ((encrypted as any).resultSubtitle ?? args.resultSubtitle) as any,\n resultIcon: ((encrypted as any).resultIcon ?? args.resultIcon) as any,\n resultSnapshot: ((encrypted as any).resultSnapshot ?? args.resultSnapshot) as any,\n primaryLinkHref: ((encrypted as any).primaryLinkHref ?? args.primaryLinkHref) as any,\n primaryLinkLabel: ((encrypted as any).primaryLinkLabel ?? args.primaryLinkLabel) as any,\n links: ((encrypted as any).links ?? args.links) as any,\n payload: ((encrypted as any).payload ?? args.payload) as any,\n }\n } catch (err) {\n searchDebugWarn('vector.index', 'Vector entry encryption failed; refusing to persist plaintext', {\n entityId: VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n error: err instanceof Error ? err.message : String(err),\n })\n throw err instanceof Error\n ? err\n : new Error('[internal] Vector entry encryption failed')\n }\n }\n\n private async decryptResultFields(args: {\n tenantId: string\n organizationId: string | null\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }): Promise<{\n resultTitle: string\n resultSubtitle: string | null\n resultIcon: string | null\n resultSnapshot: string | null\n primaryLinkHref: string | null\n primaryLinkLabel: string | null\n links: VectorLinkDescriptor[] | string | null\n payload: Record<string, unknown> | string | null\n }> {\n const service = this.resolveEncryptionService()\n if (!service || !service.isEnabled?.() || typeof service.decryptEntityPayload !== 'function') {\n return {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n }\n }\n try {\n const decrypted = await service.decryptEntityPayload(\n VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n {\n resultTitle: args.resultTitle,\n resultSubtitle: args.resultSubtitle,\n resultIcon: args.resultIcon,\n resultSnapshot: args.resultSnapshot,\n primaryLinkHref: args.primaryLinkHref,\n primaryLinkLabel: args.primaryLinkLabel,\n links: args.links,\n payload: args.payload,\n },\n args.tenantId,\n args.organizationId,\n )\n const decryptedLinks = (decrypted as any).links ?? args.links\n const decryptedPayload = (decrypted as any).payload ?? args.payload\n return {\n resultTitle: String((decrypted as any).resultTitle ?? args.resultTitle),\n resultSubtitle: ((decrypted as any).resultSubtitle ?? args.resultSubtitle) as any,\n resultIcon: ((decrypted as any).resultIcon ?? args.resultIcon) as any,\n resultSnapshot: ((decrypted as any).resultSnapshot ?? args.resultSnapshot) as any,\n primaryLinkHref: ((decrypted as any).primaryLinkHref ?? args.primaryLinkHref) as any,\n primaryLinkLabel: ((decrypted as any).primaryLinkLabel ?? args.primaryLinkLabel) as any,\n links: (typeof decryptedLinks === 'string' ? parseDecryptedFieldValue(decryptedLinks) : decryptedLinks) as any,\n payload: (typeof decryptedPayload === 'string' ? parseDecryptedFieldValue(decryptedPayload) : decryptedPayload) as any,\n }\n } catch (err) {\n searchDebugWarn('vector.index', 'Vector entry decryption failed; refusing to return ciphertext as plaintext', {\n entityId: VECTOR_ENTRY_ENCRYPTION_ENTITY_ID,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n error: err instanceof Error ? err.message : String(err),\n })\n throw err instanceof Error\n ? err\n : new Error('[internal] Vector entry decryption failed')\n }\n }\n\n listEnabledEntities(): EntityId[] {\n return Array.from(this.entityConfig.keys())\n }\n\n async ensureDriverReady(entityId?: EntityId): Promise<void> {\n if (entityId) {\n const entry = this.entityConfig.get(entityId)\n if (!entry) return\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n return\n }\n const uniqueDrivers = new Set<VectorDriverId>()\n for (const entry of this.entityConfig.values()) {\n uniqueDrivers.add(entry.driverId)\n }\n if (!uniqueDrivers.size) uniqueDrivers.add(this.defaultDriverId)\n await Promise.all(Array.from(uniqueDrivers).map(async (driverId) => {\n try {\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n } catch (err) {\n searchDebugWarn('vector', 'Failed to ensure driver readiness', { driverId, error: err instanceof Error ? err.message : err })\n }\n }))\n }\n\n private getDriver(driverId: VectorDriverId): VectorDriver {\n const driver = this.driverMap.get(driverId)\n if (!driver) {\n throw new Error(`[vector] Driver ${driverId} is not registered`)\n }\n return driver\n }\n\n private getEnrichmentFields(entityId: EntityId): string[] | undefined {\n const hints = ENRICHMENT_FIELD_HINTS[entityId]\n if (!hints) return undefined\n const unique = new Set<string>(['id', ...hints])\n return Array.from(unique)\n }\n\n private async fetchRecord(entityId: EntityId, recordIds: string[], tenantId: string, organizationId?: string | null) {\n const filters: Record<string, any> = { id: { $in: recordIds } }\n const result = await this.opts.queryEngine.query(entityId, {\n tenantId,\n organizationId: organizationId ?? undefined,\n filters,\n includeCustomFields: true,\n fields: this.getEnrichmentFields(entityId),\n skipAutoReindex: true,\n })\n const byId = new Map<string, Record<string, any>>()\n for (const item of result.items) {\n const key = String((item as any).id ?? '')\n if (!key) continue\n byId.set(key, item as Record<string, any>)\n }\n return byId\n }\n\n private extractRecordPayload(entityId: EntityId, raw: Record<string, any>) {\n const record: Record<string, any> = {}\n const customFields: Record<string, any> = {}\n const multiMap = new Map<string, boolean>()\n\n for (const [key, value] of Object.entries(raw)) {\n if (key.startsWith('cf:') && key.endsWith('__is_multi')) {\n const base = key.replace(/__is_multi$/, '')\n multiMap.set(base, Boolean(value))\n continue\n }\n if (key.startsWith('cf:')) {\n customFields[key.slice(3)] = value\n continue\n }\n record[key] = value\n }\n\n for (const [key, isMulti] of multiMap.entries()) {\n const bare = key.slice(3)\n if (bare && customFields[bare] != null && !Array.isArray(customFields[bare]) && isMulti) {\n customFields[bare] = [customFields[bare]]\n }\n }\n\n if (record.entity_id == null && record.entityId == null && entityId.endsWith('_company_profile')) {\n searchDebugWarn('vector.index', 'company profile missing entity id in payload', {\n id: record.id,\n keys: Object.keys(record),\n })\n }\n\n return { record, customFields }\n }\n\n private async indexExisting(\n entry: { config: VectorEntityConfig; driverId: VectorDriverId },\n driver: VectorDriver,\n args: IndexRecordArgs,\n raw: Record<string, any>,\n opts: { skipDelete?: boolean } = {},\n ): Promise<VectorIndexOperationResult> {\n const scopeOrg = args.organizationId ?? null\n const { record, customFields } = this.extractRecordPayload(args.entityId, raw)\n const resolvedOrgId = scopeOrg ?? (record.organization_id ?? record.organizationId ?? null)\n const source = await this.resolveSource(args.entityId, entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n })\n if (!source) {\n const existing = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (!opts.skipDelete && existing) {\n await driver.delete(args.entityId, args.recordId, args.tenantId)\n return {\n action: 'deleted',\n existed: true,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }\n }\n return {\n action: 'skipped',\n existed: Boolean(existing),\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n reason: 'missing_record',\n }\n }\n\n const checksumSource = source.checksumSource ?? { record, customFields }\n const checksum = computeChecksum(checksumSource)\n const current = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (current && current === checksum) {\n return {\n action: 'skipped',\n existed: true,\n tenantId: args.tenantId,\n organizationId: scopeOrg,\n reason: 'checksum_match',\n }\n }\n if (!this.opts.embeddingService.available) {\n throw new Error('[vector] Embedding service unavailable (missing OPENAI_API_KEY)')\n }\n const embedding = await this.opts.embeddingService.createEmbedding(source.input)\n const presenter = await this.resolvePresenter(entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }, source.presenter ?? null)\n if (!presenter?.title) {\n searchDebugWarn('vector.index', 'missing presenter title', {\n entityId: args.entityId,\n recordId: args.recordId,\n recordSample: {\n display_name: record.display_name,\n displayName: record.displayName,\n name: record.name,\n title: record.title,\n subject: record.subject,\n kind: record.kind,\n },\n })\n }\n const links = await this.resolveLinks(entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }, source.links ?? null)\n const url = await this.resolveUrl(entry.config, {\n record,\n customFields,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n })\n\n const normalizedPresenter = this.ensurePresenter(presenter, record, customFields, args.recordId, args.entityId)\n const normalizedLinks = Array.isArray(links) && links.length ? links : null\n const snapshot = this.deriveSnapshot(record, customFields)\n const rawResultTitle = this.resolveResultTitle(normalizedPresenter, record, customFields, args.recordId)\n const rawResultSubtitle = normalizedPresenter.subtitle ?? snapshot ?? null\n const rawResultIcon = normalizedPresenter.icon ?? this.mapDefaultIcon(args.entityId)\n const resultBadge = normalizedPresenter.badge ?? null\n const primaryLink = this.resolvePrimaryLink(normalizedLinks, url, rawResultTitle)\n\n const encryptedResult = await this.encryptResultFields({\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n resultTitle: rawResultTitle,\n resultSubtitle: rawResultSubtitle,\n resultIcon: rawResultIcon ?? null,\n resultSnapshot: snapshot ?? null,\n primaryLinkHref: primaryLink?.href ?? null,\n primaryLinkLabel: primaryLink?.label ?? null,\n links: normalizedLinks,\n payload: source.payload ?? null,\n })\n\n const presenterForStorage: VectorResultPresenter = {\n title: encryptedResult.resultTitle,\n subtitle: encryptedResult.resultSubtitle ?? undefined,\n icon: encryptedResult.resultIcon ?? undefined,\n badge: resultBadge ?? undefined,\n }\n\n searchDebug('VectorIndexService', 'Storing vector index entry', {\n entityId: args.entityId,\n recordId: args.recordId,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n })\n await driver.upsert({\n driverId: entry.driverId,\n entityId: args.entityId,\n recordId: args.recordId,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n checksum,\n embedding,\n url: url ?? null,\n presenter: presenterForStorage,\n links: (encryptedResult.links as any) ?? normalizedLinks,\n payload: (encryptedResult.payload as any) ?? source.payload ?? null,\n resultTitle: encryptedResult.resultTitle,\n resultSubtitle: encryptedResult.resultSubtitle,\n resultIcon: encryptedResult.resultIcon ?? null,\n resultBadge,\n resultSnapshot: encryptedResult.resultSnapshot ?? snapshot,\n primaryLinkHref: encryptedResult.primaryLinkHref ?? primaryLink?.href ?? null,\n primaryLinkLabel: encryptedResult.primaryLinkLabel ?? null,\n })\n\n return {\n action: 'indexed',\n created: !current,\n existed: true,\n tenantId: args.tenantId,\n organizationId: resolvedOrgId,\n }\n }\n\n private ensurePresenter(\n presenter: VectorResultPresenter | null,\n record: Record<string, any>,\n customFields: Record<string, any>,\n recordId: string,\n entityId: EntityId,\n ): VectorResultPresenter {\n if (presenter?.title) return presenter\n const fallback = this.buildFallbackPresenter(record, customFields, recordId, entityId)\n return fallback\n }\n\n private resolveResultTitle(\n presenter: VectorResultPresenter,\n record: Record<string, any>,\n customFields: Record<string, any>,\n recordId: string,\n ): string {\n const candidate =\n presenter.title ??\n record.display_name ??\n record.displayName ??\n record.name ??\n record.title ??\n record.subject ??\n customFields.title ??\n customFields.name ??\n recordId\n const text = String(candidate).trim()\n return text.length ? text : recordId\n }\n\n private buildFallbackPresenter(\n record: Record<string, any>,\n customFields: Record<string, any>,\n recordId: string,\n entityId: EntityId,\n ): VectorResultPresenter {\n const titleCandidate =\n record.display_name ??\n record.displayName ??\n record.name ??\n record.title ??\n record.subject ??\n recordId\n const subtitleCandidate =\n record.description ??\n record.summary ??\n record.body ??\n customFields.summary ??\n customFields.description ??\n null\n const icon = typeof record.kind === 'string'\n ? this.mapEntityIcon(record.kind)\n : this.mapDefaultIcon(entityId)\n return {\n title: String(titleCandidate),\n subtitle: subtitleCandidate ? String(subtitleCandidate) : undefined,\n icon: icon ?? undefined,\n }\n }\n\n private mapEntityIcon(kind?: string | null): string | null {\n if (!kind) return null\n const normalized = kind.toLowerCase()\n if (normalized === 'person') return 'user'\n if (normalized === 'company' || normalized === 'organization') return 'building'\n return null\n }\n\n private mapDefaultIcon(entityId: EntityId): string | null {\n if (entityId.startsWith('customers:customer_deal')) return 'briefcase'\n if (entityId.startsWith('customers:customer_comment')) return 'sticky-note'\n if (entityId.startsWith('customers:customer_activity')) return 'bolt'\n if (entityId.startsWith('customers:customer_todo')) return 'check-square'\n return null\n }\n\n private resolvePrimaryLink(\n links: VectorLinkDescriptor[] | null,\n url: string | null,\n fallbackLabel: string,\n ): { href: string; label: string } | null {\n if (links?.length) {\n const primary = links.find((link) => link.kind === 'primary') ?? links[0]\n if (primary?.href) {\n return { href: primary.href, label: primary.label ?? fallbackLabel }\n }\n }\n if (url) {\n return { href: url, label: fallbackLabel }\n }\n return null\n }\n\n private deriveSnapshot(\n record: Record<string, any>,\n customFields: Record<string, any>,\n ): string | null {\n const candidates = [\n record.summary,\n record.description,\n record.body,\n customFields.summary,\n customFields.description,\n customFields.body,\n ]\n for (const value of candidates) {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed.length) return trimmed\n }\n }\n return null\n }\n\n private buildDefaultSource(\n entityId: EntityId,\n payload: { record: Record<string, any>; customFields: Record<string, any> },\n fieldPolicy?: SearchFieldPolicy,\n ): VectorIndexSource {\n const { record, customFields } = payload\n const lines: string[] = []\n\n const searchableWhitelist = fieldPolicy?.searchable ? new Set(fieldPolicy.searchable) : null\n const excludedFields = new Set<string>([\n ...(fieldPolicy?.excluded ?? []),\n ...(fieldPolicy?.hashOnly ?? []),\n ])\n\n const isEligibleField = (field: string): boolean => {\n if (DEFAULT_SOURCE_SCOPE_FIELDS.has(field)) return false\n if (excludedFields.has(field)) return false\n if (searchableWhitelist && !searchableWhitelist.has(field)) return false\n return true\n }\n\n const pushEntry = (label: string, value: unknown) => {\n if (value === null || value === undefined) return\n if (typeof value === 'string' && value.trim().length === 0) return\n if (typeof value === 'object') {\n lines.push(`${label}: ${JSON.stringify(value)}`)\n } else {\n lines.push(`${label}: ${value}`)\n }\n }\n\n const preferredFields = ['title', 'name', 'displayName', 'summary', 'subject']\n for (const field of preferredFields) {\n if (!isEligibleField(field)) continue\n if (record[field] != null) pushEntry(field, record[field])\n }\n\n for (const [key, value] of Object.entries(record)) {\n if (preferredFields.includes(key)) continue\n if (!isEligibleField(key)) continue\n pushEntry(key, value)\n }\n\n for (const [key, value] of Object.entries(customFields)) {\n if (!isEligibleField(key)) continue\n pushEntry(`custom.${key}`, value)\n }\n\n if (lines.length === 0) {\n lines.push(`${entityId}#${record.id ?? ''}`)\n }\n\n return {\n input: lines,\n payload: null,\n checksumSource: { record, customFields },\n }\n }\n\n private async resolveSource(entityId: EntityId, config: VectorEntityConfig, ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n }): Promise<VectorIndexSource | null> {\n const baseCtx = {\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n }\n if (config.buildSource) {\n const built = await config.buildSource(baseCtx)\n if (built) return built\n return null\n }\n return this.buildDefaultSource(entityId, { record: ctx.record, customFields: ctx.customFields }, config.fieldPolicy)\n }\n\n private async resolvePresenter(\n config: VectorEntityConfig,\n ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n },\n fallback?: VectorResultPresenter | null,\n ): Promise<VectorResultPresenter | null> {\n const baseCtx = {\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n }\n if (config.formatResult) {\n const formatted = await config.formatResult(baseCtx)\n if (formatted) return formatted\n }\n if (fallback) return fallback\n const nameLike = ctx.record.displayName || ctx.record.title || ctx.record.name\n if (typeof nameLike === 'string' && nameLike.trim().length > 0) {\n const subtitle = ctx.record.description || ctx.record.summary\n return {\n title: nameLike,\n subtitle: typeof subtitle === 'string' ? subtitle : undefined,\n }\n }\n return null\n }\n\n private async resolveLinks(\n config: VectorEntityConfig,\n ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n },\n fallback?: VectorLinkDescriptor[] | null,\n ): Promise<VectorLinkDescriptor[] | null> {\n const baseCtx = {\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n }\n if (config.resolveLinks) {\n const resolved = await config.resolveLinks(baseCtx)\n if (resolved?.length) return resolved\n }\n return fallback ?? null\n }\n\n private async resolveUrl(\n config: VectorEntityConfig,\n ctx: {\n record: Record<string, any>\n customFields: Record<string, any>\n organizationId?: string | null\n tenantId: string\n },\n fallback?: string | null,\n ): Promise<string | null> {\n if (config.resolveUrl) {\n const candidate = await config.resolveUrl({\n record: ctx.record,\n customFields: ctx.customFields,\n organizationId: ctx.organizationId ?? null,\n tenantId: ctx.tenantId,\n queryEngine: this.opts.queryEngine,\n container: this.opts.containerResolver ? this.opts.containerResolver() : undefined,\n })\n if (candidate) return candidate\n }\n return fallback ?? null\n }\n\n async indexRecord(args: IndexRecordArgs): Promise<VectorIndexOperationResult> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) {\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n reason: 'unsupported',\n }\n }\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n\n const records = await this.fetchRecord(args.entityId, [args.recordId], args.tenantId, args.organizationId)\n const raw = records.get(args.recordId)\n if (!raw) {\n const existing = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (existing) {\n await driver.delete(args.entityId, args.recordId, args.tenantId)\n return {\n action: 'deleted',\n existed: true,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n }\n }\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n reason: 'missing_record',\n }\n }\n return this.indexExisting(entry, driver, args, raw as Record<string, any>)\n }\n\n async deleteRecord(args: DeleteRecordArgs): Promise<VectorIndexOperationResult> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) {\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n reason: 'unsupported',\n }\n }\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n const scopeOrg = args.organizationId ?? null\n const existing = await driver.getChecksum(args.entityId, args.recordId, args.tenantId)\n if (existing) {\n await driver.delete(args.entityId, args.recordId, args.tenantId)\n return {\n action: 'deleted',\n existed: true,\n tenantId: args.tenantId,\n organizationId: scopeOrg,\n }\n }\n return {\n action: 'skipped',\n existed: false,\n tenantId: args.tenantId,\n organizationId: scopeOrg,\n reason: 'missing_record',\n }\n }\n\n async reindexEntity(args: { entityId: EntityId; tenantId?: string | null; organizationId?: string | null; purgeFirst?: boolean }): Promise<void> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) return\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n\n const shouldPurge = args.purgeFirst === true\n const reindexStartedAt = new Date()\n\n if (this.opts.eventBus) {\n if (shouldPurge && driver.purge && args.tenantId) {\n await driver.purge(args.entityId, args.tenantId, args.organizationId)\n } else if (shouldPurge && !args.tenantId) {\n searchDebugWarn('vector', 'Skipping purge for multi-tenant reindex (tenant not provided)')\n }\n const payload: Record<string, unknown> = {\n entityType: args.entityId,\n }\n if (shouldPurge) {\n payload.force = true\n payload.resetCoverage = true\n }\n if (args.tenantId !== undefined) payload.tenantId = args.tenantId\n else payload.allowAllTenants = true\n if (args.organizationId !== undefined) payload.organizationId = args.organizationId\n await this.opts.eventBus.emitEvent('query_index.reindex', payload)\n return\n }\n\n if (!args.tenantId) {\n throw new Error('[vector] Reindex without tenantId requires event bus integration')\n }\n\n if (shouldPurge && driver.purge) {\n await driver.purge(args.entityId, args.tenantId, args.organizationId)\n }\n\n const pageSize = 50\n let page = 1\n const loggingEm = this.resolveEntityManager()\n for (;;) {\n const result = await this.opts.queryEngine.query(args.entityId, {\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? undefined,\n page: { page, pageSize },\n includeCustomFields: true,\n fields: this.getEnrichmentFields(args.entityId),\n skipAutoReindex: true,\n })\n if (!result.items.length) break\n for (const raw of result.items) {\n const recordId = String((raw as any).id ?? '')\n if (!recordId) continue\n const opResult = await this.indexExisting(\n entry,\n driver,\n {\n entityId: args.entityId,\n recordId,\n tenantId: args.tenantId,\n organizationId: args.organizationId ?? null,\n },\n raw as Record<string, any>,\n { skipDelete: true },\n )\n await logVectorOperation({\n em: loggingEm,\n handler: 'service:vector.reindex',\n entityType: args.entityId,\n recordId,\n result: opResult,\n })\n }\n if (result.items.length < pageSize) break\n page += 1\n }\n\n if (shouldPurge) {\n await this.removeOrphans({\n entityId: args.entityId,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n olderThan: reindexStartedAt,\n })\n }\n }\n\n async reindexAll(args: { tenantId?: string | null; organizationId?: string | null; purgeFirst?: boolean }): Promise<void> {\n for (const entityId of this.listEnabledEntities()) {\n await this.reindexEntity({ entityId, tenantId: args.tenantId, organizationId: args.organizationId ?? null, purgeFirst: args.purgeFirst })\n }\n }\n\n private resolveEntityManager(): EntityManager | null {\n if (!this.opts.containerResolver) return null\n try {\n const container = this.opts.containerResolver()\n if (!container || typeof (container as any).resolve !== 'function') return null\n const resolver = container as { resolve(name: string): unknown }\n const em = resolver.resolve('em')\n return (em as EntityManager | null) ?? null\n } catch {\n return null\n }\n }\n\n async purgeIndex(args: { tenantId: string; organizationId?: string | null; entityId?: EntityId | null }): Promise<void> {\n const targets = args.entityId ? [args.entityId] : this.listEnabledEntities()\n if (!targets.length) return\n\n const grouped = new Map<VectorDriverId, EntityId[]>()\n for (const entityId of targets) {\n const cfg = this.entityConfig.get(entityId)\n if (!cfg) continue\n const driver = this.getDriver(cfg.driverId)\n if (typeof driver.purge !== 'function') {\n throw new Error(`[vector] Driver ${cfg.driverId} does not support purging entities`)\n }\n if (!grouped.has(cfg.driverId)) grouped.set(cfg.driverId, [])\n grouped.get(cfg.driverId)!.push(entityId)\n }\n\n for (const [driverId, entityIds] of grouped.entries()) {\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n for (const entityId of entityIds) {\n await driver.purge!(entityId, args.tenantId)\n }\n }\n }\n\n async removeOrphans(args: {\n entityId: EntityId\n tenantId?: string | null\n organizationId?: string | null\n olderThan: Date\n }): Promise<number> {\n const entry = this.entityConfig.get(args.entityId)\n if (!entry) return 0\n const driver = this.getDriver(entry.driverId)\n await driver.ensureReady()\n\n const driverAny = driver as VectorDriver & {\n removeOrphans?: (params: {\n entityId: EntityId\n tenantId?: string | null\n organizationId?: string | null\n olderThan: Date\n }) => Promise<number | void>\n }\n\n if (typeof driverAny.removeOrphans === 'function') {\n const deleted = await driverAny.removeOrphans({\n entityId: args.entityId,\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n olderThan: args.olderThan,\n })\n return typeof deleted === 'number' ? deleted : 0\n }\n\n searchDebugWarn('vector', 'Driver does not support orphan cleanup', { driverId: entry.driverId })\n return 0\n }\n\n async countIndexEntries(args: {\n tenantId: string\n organizationId?: string | null\n entityId?: EntityId\n driverId?: VectorDriverId\n }): Promise<number> {\n if (!args.tenantId) return 0\n const targetEntity = args.entityId ? this.entityConfig.get(args.entityId) : null\n if (args.entityId && !targetEntity) {\n return 0\n }\n const driverId =\n args.driverId ??\n (targetEntity ? targetEntity.driverId : this.defaultDriverId)\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n const countParams = {\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n entityId: args.entityId,\n }\n if (typeof driver.count === 'function') {\n try {\n return await driver.count(countParams)\n } catch (err) {\n searchDebugWarn('vector', 'Driver count failed, falling back to list', {\n driverId,\n error: err instanceof Error ? err.message : err,\n })\n }\n }\n if (typeof driver.list === 'function') {\n const limit = 1000\n let offset = 0\n let total = 0\n for (;;) {\n const batch = await driver.list({\n tenantId: countParams.tenantId,\n organizationId: countParams.organizationId,\n entityId: countParams.entityId,\n limit,\n offset,\n orderBy: 'created',\n })\n const size = batch.length\n total += size\n if (size < limit) break\n offset += limit\n }\n return total\n }\n searchDebugWarn('vector', 'Driver does not support counting or listing index entries', { driverId })\n return 0\n }\n\n async listIndexEntries(args: {\n tenantId: string\n organizationId?: string | null\n entityId?: EntityId\n limit?: number\n offset?: number\n driverId?: VectorDriverId\n }): Promise<VectorIndexEntry[]> {\n const targetEntity = args.entityId ? this.entityConfig.get(args.entityId) : null\n if (args.entityId && !targetEntity) {\n return []\n }\n const driverId =\n args.driverId ??\n (targetEntity ? targetEntity.driverId : this.defaultDriverId)\n const driver = this.getDriver(driverId)\n if (typeof driver.list !== 'function') {\n throw new Error(`[vector] Driver ${driverId} does not support listing index entries`)\n }\n await driver.ensureReady()\n const list = await driver.list({\n tenantId: args.tenantId,\n organizationId: args.organizationId,\n entityId: args.entityId,\n limit: args.limit,\n offset: args.offset,\n orderBy: 'updated',\n })\n if (!list.length) {\n return []\n }\n\n const decrypted = await Promise.all(\n list.map(async (entry) => {\n const decryptedResult = await this.decryptResultFields({\n tenantId: args.tenantId,\n organizationId: entry.organizationId ?? null,\n resultTitle: entry.resultTitle,\n resultSubtitle: entry.resultSubtitle ?? null,\n resultIcon: entry.resultIcon ?? null,\n resultSnapshot: entry.resultSnapshot ?? null,\n primaryLinkHref: entry.primaryLinkHref ?? null,\n primaryLinkLabel: entry.primaryLinkLabel ?? null,\n links: (entry.links as any) ?? null,\n payload: (entry.payload as any) ?? null,\n })\n return {\n ...entry,\n resultTitle: decryptedResult.resultTitle,\n resultSubtitle: decryptedResult.resultSubtitle,\n resultIcon: decryptedResult.resultIcon,\n resultSnapshot: decryptedResult.resultSnapshot,\n primaryLinkHref: decryptedResult.primaryLinkHref,\n primaryLinkLabel: decryptedResult.primaryLinkLabel,\n links: decryptedResult.links as any,\n payload: decryptedResult.payload as any,\n metadata: (decryptedResult.payload as any) ?? null,\n }\n }),\n )\n\n return decrypted.map((entry) => {\n const presenter = {\n title: entry.resultTitle,\n subtitle: entry.resultSubtitle ?? undefined,\n icon: entry.resultIcon ?? undefined,\n badge: entry.presenter?.badge ?? entry.resultBadge ?? undefined,\n }\n const links = entry.links ?? (entry.primaryLinkHref\n ? [{ href: entry.primaryLinkHref, label: entry.primaryLinkLabel ?? entry.resultTitle, kind: 'primary' as const }]\n : null)\n const url = entry.url ?? entry.primaryLinkHref ?? null\n const metadata = entry.metadata ?? (entry.resultSnapshot ? { snapshot: entry.resultSnapshot } : null)\n return {\n ...entry,\n driverId,\n presenter,\n links,\n url,\n metadata,\n score: entry.score ?? null,\n }\n })\n }\n\n async search(request: VectorQueryRequest): Promise<VectorSearchHit[]> {\n const driverId = request.driverId ?? this.defaultDriverId\n const driver = this.getDriver(driverId)\n await driver.ensureReady()\n if (!this.opts.embeddingService.available) {\n throw new Error('[vector] Embedding service unavailable (missing OPENAI_API_KEY)')\n }\n const embedding = await this.opts.embeddingService.createEmbedding(request.query)\n const hits = await driver.query({\n vector: embedding,\n limit: request.limit ?? 10,\n filter: {\n tenantId: request.tenantId,\n organizationId: request.organizationId ?? null,\n entityIds: undefined,\n },\n })\n\n if (!hits.length) return []\n\n const decrypted = await Promise.all(\n hits.map(async (hit) => {\n const decryptedResult = await this.decryptResultFields({\n tenantId: request.tenantId,\n organizationId: hit.organizationId ?? request.organizationId ?? null,\n resultTitle: hit.resultTitle,\n resultSubtitle: hit.resultSubtitle ?? null,\n resultIcon: hit.resultIcon ?? null,\n resultSnapshot: hit.resultSnapshot ?? null,\n primaryLinkHref: hit.primaryLinkHref ?? null,\n primaryLinkLabel: hit.primaryLinkLabel ?? null,\n links: (hit.links as any) ?? null,\n payload: (hit.payload as any) ?? null,\n })\n return {\n ...hit,\n resultTitle: decryptedResult.resultTitle,\n resultSubtitle: decryptedResult.resultSubtitle,\n resultIcon: decryptedResult.resultIcon,\n resultSnapshot: decryptedResult.resultSnapshot,\n primaryLinkHref: decryptedResult.primaryLinkHref,\n primaryLinkLabel: decryptedResult.primaryLinkLabel,\n links: decryptedResult.links as any,\n payload: decryptedResult.payload as any,\n }\n }),\n )\n\n return decrypted.map((hit) => {\n const presenter = {\n title: hit.resultTitle,\n subtitle: hit.resultSubtitle ?? undefined,\n icon: hit.resultIcon ?? undefined,\n badge: hit.presenter?.badge ?? hit.resultBadge ?? undefined,\n }\n const links = hit.links ?? (hit.primaryLinkHref\n ? [{ href: hit.primaryLinkHref, label: hit.primaryLinkLabel ?? hit.resultTitle, kind: 'primary' as const }]\n : null)\n const url = hit.url ?? hit.primaryLinkHref ?? null\n const metadata = hit.payload ?? (hit.resultSnapshot ? { snapshot: hit.resultSnapshot } : null)\n return {\n entityId: hit.entityId,\n recordId: hit.recordId,\n score: hit.score,\n url,\n presenter,\n links,\n driverId,\n metadata,\n }\n })\n }\n}\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,gCAAgC;AAczC,SAAS,uBAAuB;AAEhC,SAAS,0BAA0B;AACnC,SAAS,aAAa,uBAAuB;AAG7C,MAAM,oCAAoC;AAE1C,MAAM,8BAA8B,oBAAI,IAAY;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,MAAM,yBAAqD;AAAA,EACzD,6BAA6B;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,8BAA8B,CAAC,MAAM,mBAAmB,aAAa,aAAa,QAAQ,mBAAmB,kBAAkB;AAAA,EAC/H,+BAA+B,CAAC,MAAM,mBAAmB,aAAa,aAAa,iBAAiB,WAAW,QAAQ,SAAS;AAAA,EAChI,2BAA2B,CAAC,MAAM,mBAAmB,aAAa,SAAS,kBAAkB,UAAU,gBAAgB,gBAAgB;AAAA,EACvI,gCAAgC,CAAC,MAAM,mBAAmB,aAAa,aAAa,WAAW,aAAa;AAAA,EAC5G,qCAAqC;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,sCAAsC;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAqCO,MAAM,mBAAmB;AAAA,EAK9B,YAA6B,MAAiC;AAAjC;AAJ7B,SAAiB,YAAY,oBAAI,IAAkC;AACnE,SAAiB,eAAe,oBAAI,IAAwE;AAI1G,eAAW,UAAU,KAAK,SAAS;AACjC,WAAK,UAAU,IAAI,OAAO,IAAI,MAAM;AAAA,IACtC;AACA,SAAK,kBAAkB,KAAK,mBAAmB;AAC/C,eAAW,gBAAgB,KAAK,eAAe;AAC7C,YAAM,WAAW,aAAa,mBAAmB,KAAK;AACtD,iBAAW,UAAU,aAAa,YAAY,CAAC,GAAG;AAChD,YAAI,CAAC,QAAQ,SAAU;AACvB,YAAI,OAAO,YAAY,MAAO;AAC9B,cAAM,eAAe,OAAO,YAAY;AACxC,aAAK,aAAa,IAAI,OAAO,UAAU,EAAE,QAAQ,QAAQ,UAAU,aAAa,CAAC;AAAA,MACnF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAA+D;AACrE,QAAI,CAAC,KAAK,KAAK,kBAAmB,QAAO;AACzC,QAAI;AACF,YAAM,YAAY,KAAK,KAAK,kBAAkB;AAC9C,UAAI,CAAC,aAAa,OAAO,UAAU,YAAY,WAAY,QAAO;AAClE,aAAO,UAAU,QAAQ,yBAAyB;AAAA,IACpD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB,MAoB/B;AACD,UAAM,UAAU,KAAK,yBAAyB;AAC9C,QAAI,CAAC,WAAW,CAAC,QAAQ,YAAY,GAAG;AACtC,aAAO;AAAA,QACL,aAAa,KAAK;AAAA,QAClB,gBAAgB,KAAK;AAAA,QACrB,YAAY,KAAK;AAAA,QACjB,gBAAgB,KAAK;AAAA,QACrB,iBAAiB,KAAK;AAAA,QACtB,kBAAkB,KAAK;AAAA,QACvB,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MAChB;AAAA,IACF;AACA,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ;AAAA,QAC9B;AAAA,QACA;AAAA,UACE,aAAa,KAAK;AAAA,UAClB,gBAAgB,KAAK;AAAA,UACrB,YAAY,KAAK;AAAA,UACjB,gBAAgB,KAAK;AAAA,UACrB,iBAAiB,KAAK;AAAA,UACtB,kBAAkB,KAAK;AAAA,UACvB,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AACA,aAAO;AAAA,QACL,aAAa,OAAQ,UAAkB,eAAe,KAAK,WAAW;AAAA,QACtE,gBAAkB,UAAkB,kBAAkB,KAAK;AAAA,QAC3D,YAAc,UAAkB,cAAc,KAAK;AAAA,QACnD,gBAAkB,UAAkB,kBAAkB,KAAK;AAAA,QAC3D,iBAAmB,UAAkB,mBAAmB,KAAK;AAAA,QAC7D,kBAAoB,UAAkB,oBAAoB,KAAK;AAAA,QAC/D,OAAS,UAAkB,SAAS,KAAK;AAAA,QACzC,SAAW,UAAkB,WAAW,KAAK;AAAA,MAC/C;AAAA,IACF,SAAS,KAAK;AACZ,sBAAgB,gBAAgB,iEAAiE;AAAA,QAC/F,UAAU;AAAA,QACV,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AACD,YAAM,eAAe,QACjB,MACA,IAAI,MAAM,2CAA2C;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB,MAoB/B;AACD,UAAM,UAAU,KAAK,yBAAyB;AAC9C,QAAI,CAAC,WAAW,CAAC,QAAQ,YAAY,KAAK,OAAO,QAAQ,yBAAyB,YAAY;AAC5F,aAAO;AAAA,QACL,aAAa,KAAK;AAAA,QAClB,gBAAgB,KAAK;AAAA,QACrB,YAAY,KAAK;AAAA,QACjB,gBAAgB,KAAK;AAAA,QACrB,iBAAiB,KAAK;AAAA,QACtB,kBAAkB,KAAK;AAAA,QACvB,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MAChB;AAAA,IACF;AACA,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ;AAAA,QAC9B;AAAA,QACA;AAAA,UACE,aAAa,KAAK;AAAA,UAClB,gBAAgB,KAAK;AAAA,UACrB,YAAY,KAAK;AAAA,UACjB,gBAAgB,KAAK;AAAA,UACrB,iBAAiB,KAAK;AAAA,UACtB,kBAAkB,KAAK;AAAA,UACvB,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AACA,YAAM,iBAAkB,UAAkB,SAAS,KAAK;AACxD,YAAM,mBAAoB,UAAkB,WAAW,KAAK;AAC5D,aAAO;AAAA,QACL,aAAa,OAAQ,UAAkB,eAAe,KAAK,WAAW;AAAA,QACtE,gBAAkB,UAAkB,kBAAkB,KAAK;AAAA,QAC3D,YAAc,UAAkB,cAAc,KAAK;AAAA,QACnD,gBAAkB,UAAkB,kBAAkB,KAAK;AAAA,QAC3D,iBAAmB,UAAkB,mBAAmB,KAAK;AAAA,QAC7D,kBAAoB,UAAkB,oBAAoB,KAAK;AAAA,QAC/D,OAAQ,OAAO,mBAAmB,WAAW,yBAAyB,cAAc,IAAI;AAAA,QACxF,SAAU,OAAO,qBAAqB,WAAW,yBAAyB,gBAAgB,IAAI;AAAA,MAChG;AAAA,IACF,SAAS,KAAK;AACZ,sBAAgB,gBAAgB,8EAA8E;AAAA,QAC5G,UAAU;AAAA,QACV,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AACD,YAAM,eAAe,QACjB,MACA,IAAI,MAAM,2CAA2C;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,sBAAkC;AAChC,WAAO,MAAM,KAAK,KAAK,aAAa,KAAK,CAAC;AAAA,EAC5C;AAAA,EAEA,MAAM,kBAAkB,UAAoC;AAC1D,QAAI,UAAU;AACZ,YAAM,QAAQ,KAAK,aAAa,IAAI,QAAQ;AAC5C,UAAI,CAAC,MAAO;AACZ,YAAM,SAAS,KAAK,UAAU,MAAM,QAAQ;AAC5C,YAAM,OAAO,YAAY;AACzB;AAAA,IACF;AACA,UAAM,gBAAgB,oBAAI,IAAoB;AAC9C,eAAW,SAAS,KAAK,aAAa,OAAO,GAAG;AAC9C,oBAAc,IAAI,MAAM,QAAQ;AAAA,IAClC;AACA,QAAI,CAAC,cAAc,KAAM,eAAc,IAAI,KAAK,eAAe;AAC/D,UAAM,QAAQ,IAAI,MAAM,KAAK,aAAa,EAAE,IAAI,OAAO,aAAa;AAClE,UAAI;AACF,cAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,cAAM,OAAO,YAAY;AAAA,MAC3B,SAAS,KAAK;AACZ,wBAAgB,UAAU,qCAAqC,EAAE,UAAU,OAAO,eAAe,QAAQ,IAAI,UAAU,IAAI,CAAC;AAAA,MAC9H;AAAA,IACF,CAAC,CAAC;AAAA,EACJ;AAAA,EAEQ,UAAU,UAAwC;AACxD,UAAM,SAAS,KAAK,UAAU,IAAI,QAAQ;AAC1C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,mBAAmB,QAAQ,oBAAoB;AAAA,IACjE;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,UAA0C;AACpE,UAAM,QAAQ,uBAAuB,QAAQ;AAC7C,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,SAAS,oBAAI,IAAY,CAAC,MAAM,GAAG,KAAK,CAAC;AAC/C,WAAO,MAAM,KAAK,MAAM;AAAA,EAC1B;AAAA,EAEA,MAAc,YAAY,UAAoB,WAAqB,UAAkB,gBAAgC;AACnH,UAAM,UAA+B,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE;AAC9D,UAAM,SAAS,MAAM,KAAK,KAAK,YAAY,MAAM,UAAU;AAAA,MACzD;AAAA,MACA,gBAAgB,kBAAkB;AAAA,MAClC;AAAA,MACA,qBAAqB;AAAA,MACrB,QAAQ,KAAK,oBAAoB,QAAQ;AAAA,MACzC,iBAAiB;AAAA,IACnB,CAAC;AACD,UAAM,OAAO,oBAAI,IAAiC;AAClD,eAAW,QAAQ,OAAO,OAAO;AAC/B,YAAM,MAAM,OAAQ,KAAa,MAAM,EAAE;AACzC,UAAI,CAAC,IAAK;AACV,WAAK,IAAI,KAAK,IAA2B;AAAA,IAC3C;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,qBAAqB,UAAoB,KAA0B;AACzE,UAAM,SAA8B,CAAC;AACrC,UAAM,eAAoC,CAAC;AAC3C,UAAM,WAAW,oBAAI,IAAqB;AAE1C,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,UAAI,IAAI,WAAW,KAAK,KAAK,IAAI,SAAS,YAAY,GAAG;AACvD,cAAM,OAAO,IAAI,QAAQ,eAAe,EAAE;AAC1C,iBAAS,IAAI,MAAM,QAAQ,KAAK,CAAC;AACjC;AAAA,MACF;AACA,UAAI,IAAI,WAAW,KAAK,GAAG;AACzB,qBAAa,IAAI,MAAM,CAAC,CAAC,IAAI;AAC7B;AAAA,MACF;AACA,aAAO,GAAG,IAAI;AAAA,IAChB;AAEA,eAAW,CAAC,KAAK,OAAO,KAAK,SAAS,QAAQ,GAAG;AAC/C,YAAM,OAAO,IAAI,MAAM,CAAC;AACxB,UAAI,QAAQ,aAAa,IAAI,KAAK,QAAQ,CAAC,MAAM,QAAQ,aAAa,IAAI,CAAC,KAAK,SAAS;AACvF,qBAAa,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC;AAAA,MAC1C;AAAA,IACF;AAEA,QAAI,OAAO,aAAa,QAAQ,OAAO,YAAY,QAAQ,SAAS,SAAS,kBAAkB,GAAG;AAChG,sBAAgB,gBAAgB,gDAAgD;AAAA,QAC9E,IAAI,OAAO;AAAA,QACX,MAAM,OAAO,KAAK,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH;AAEA,WAAO,EAAE,QAAQ,aAAa;AAAA,EAChC;AAAA,EAEA,MAAc,cACZ,OACA,QACA,MACA,KACA,OAAiC,CAAC,GACG;AACrC,UAAM,WAAW,KAAK,kBAAkB;AACxC,UAAM,EAAE,QAAQ,aAAa,IAAI,KAAK,qBAAqB,KAAK,UAAU,GAAG;AAC7E,UAAM,gBAAgB,aAAa,OAAO,mBAAmB,OAAO,kBAAkB;AACtF,UAAM,SAAS,MAAM,KAAK,cAAc,KAAK,UAAU,MAAM,QAAQ;AAAA,MACnE;AAAA,MACA;AAAA,MACA,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,IAClB,CAAC;AACD,QAAI,CAAC,QAAQ;AACX,YAAM,WAAW,MAAM,OAAO,YAAY,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ;AACrF,UAAI,CAAC,KAAK,cAAc,UAAU;AAChC,cAAM,OAAO,OAAO,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ;AAC/D,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,UAAU,KAAK;AAAA,UACf,gBAAgB;AAAA,QAClB;AAAA,MACF;AACA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS,QAAQ,QAAQ;AAAA,QACzB,UAAU,KAAK;AAAA,QACf,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,UAAM,iBAAiB,OAAO,kBAAkB,EAAE,QAAQ,aAAa;AACvE,UAAM,WAAW,gBAAgB,cAAc;AAC/C,UAAM,UAAU,MAAM,OAAO,YAAY,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ;AACpF,QAAI,WAAW,YAAY,UAAU;AACnC,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU,KAAK;AAAA,QACf,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,IACF;AACA,QAAI,CAAC,KAAK,KAAK,iBAAiB,WAAW;AACzC,YAAM,IAAI,MAAM,iEAAiE;AAAA,IACnF;AACA,UAAM,YAAY,MAAM,KAAK,KAAK,iBAAiB,gBAAgB,OAAO,KAAK;AAC/E,UAAM,YAAY,MAAM,KAAK,iBAAiB,MAAM,QAAQ;AAAA,MAC1D;AAAA,MACA;AAAA,MACA,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,IAClB,GAAG,OAAO,aAAa,IAAI;AAC3B,QAAI,CAAC,WAAW,OAAO;AACrB,sBAAgB,gBAAgB,2BAA2B;AAAA,QACzD,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,QACf,cAAc;AAAA,UACZ,cAAc,OAAO;AAAA,UACrB,aAAa,OAAO;AAAA,UACpB,MAAM,OAAO;AAAA,UACb,OAAO,OAAO;AAAA,UACd,SAAS,OAAO;AAAA,UAChB,MAAM,OAAO;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,QAAQ,MAAM,KAAK,aAAa,MAAM,QAAQ;AAAA,MAClD;AAAA,MACA;AAAA,MACA,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,IAClB,GAAG,OAAO,SAAS,IAAI;AACvB,UAAM,MAAM,MAAM,KAAK,WAAW,MAAM,QAAQ;AAAA,MAC9C;AAAA,MACA;AAAA,MACA,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,IAClB,CAAC;AAED,UAAM,sBAAsB,KAAK,gBAAgB,WAAW,QAAQ,cAAc,KAAK,UAAU,KAAK,QAAQ;AAC9G,UAAM,kBAAkB,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,QAAQ;AACvE,UAAM,WAAW,KAAK,eAAe,QAAQ,YAAY;AACzD,UAAM,iBAAiB,KAAK,mBAAmB,qBAAqB,QAAQ,cAAc,KAAK,QAAQ;AACvG,UAAM,oBAAoB,oBAAoB,YAAY,YAAY;AACtE,UAAM,gBAAgB,oBAAoB,QAAQ,KAAK,eAAe,KAAK,QAAQ;AACnF,UAAM,cAAc,oBAAoB,SAAS;AACjD,UAAM,cAAc,KAAK,mBAAmB,iBAAiB,KAAK,cAAc;AAEhF,UAAM,kBAAkB,MAAM,KAAK,oBAAoB;AAAA,MACrD,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,YAAY,iBAAiB;AAAA,MAC7B,gBAAgB,YAAY;AAAA,MAC5B,iBAAiB,aAAa,QAAQ;AAAA,MACtC,kBAAkB,aAAa,SAAS;AAAA,MACxC,OAAO;AAAA,MACP,SAAS,OAAO,WAAW;AAAA,IAC7B,CAAC;AAED,UAAM,sBAA6C;AAAA,MACjD,OAAO,gBAAgB;AAAA,MACvB,UAAU,gBAAgB,kBAAkB;AAAA,MAC5C,MAAM,gBAAgB,cAAc;AAAA,MACpC,OAAO,eAAe;AAAA,IACxB;AAEA,gBAAY,sBAAsB,8BAA8B;AAAA,MAC9D,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,IAClB,CAAC;AACD,UAAM,OAAO,OAAO;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,MACA,KAAK,OAAO;AAAA,MACZ,WAAW;AAAA,MACX,OAAQ,gBAAgB,SAAiB;AAAA,MACzC,SAAU,gBAAgB,WAAmB,OAAO,WAAW;AAAA,MAC/D,aAAa,gBAAgB;AAAA,MAC7B,gBAAgB,gBAAgB;AAAA,MAChC,YAAY,gBAAgB,cAAc;AAAA,MAC1C;AAAA,MACA,gBAAgB,gBAAgB,kBAAkB;AAAA,MAClD,iBAAiB,gBAAgB,mBAAmB,aAAa,QAAQ;AAAA,MACzE,kBAAkB,gBAAgB,oBAAoB;AAAA,IACxD,CAAC;AAED,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS,CAAC;AAAA,MACV,SAAS;AAAA,MACT,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ,gBACN,WACA,QACA,cACA,UACA,UACuB;AACvB,QAAI,WAAW,MAAO,QAAO;AAC7B,UAAM,WAAW,KAAK,uBAAuB,QAAQ,cAAc,UAAU,QAAQ;AACrF,WAAO;AAAA,EACT;AAAA,EAEQ,mBACN,WACA,QACA,cACA,UACQ;AACR,UAAM,YACJ,UAAU,SACV,OAAO,gBACP,OAAO,eACP,OAAO,QACP,OAAO,SACP,OAAO,WACP,aAAa,SACb,aAAa,QACb;AACF,UAAM,OAAO,OAAO,SAAS,EAAE,KAAK;AACpC,WAAO,KAAK,SAAS,OAAO;AAAA,EAC9B;AAAA,EAEQ,uBACN,QACA,cACA,UACA,UACuB;AACvB,UAAM,iBACJ,OAAO,gBACP,OAAO,eACP,OAAO,QACP,OAAO,SACP,OAAO,WACP;AACF,UAAM,oBACJ,OAAO,eACP,OAAO,WACP,OAAO,QACP,aAAa,WACb,aAAa,eACb;AACF,UAAM,OAAO,OAAO,OAAO,SAAS,WAChC,KAAK,cAAc,OAAO,IAAI,IAC9B,KAAK,eAAe,QAAQ;AAChC,WAAO;AAAA,MACL,OAAO,OAAO,cAAc;AAAA,MAC5B,UAAU,oBAAoB,OAAO,iBAAiB,IAAI;AAAA,MAC1D,MAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,cAAc,MAAqC;AACzD,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,aAAa,KAAK,YAAY;AACpC,QAAI,eAAe,SAAU,QAAO;AACpC,QAAI,eAAe,aAAa,eAAe,eAAgB,QAAO;AACtE,WAAO;AAAA,EACT;AAAA,EAEQ,eAAe,UAAmC;AACxD,QAAI,SAAS,WAAW,yBAAyB,EAAG,QAAO;AAC3D,QAAI,SAAS,WAAW,4BAA4B,EAAG,QAAO;AAC9D,QAAI,SAAS,WAAW,6BAA6B,EAAG,QAAO;AAC/D,QAAI,SAAS,WAAW,yBAAyB,EAAG,QAAO;AAC3D,WAAO;AAAA,EACT;AAAA,EAEQ,mBACN,OACA,KACA,eACwC;AACxC,QAAI,OAAO,QAAQ;AACjB,YAAM,UAAU,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,SAAS,KAAK,MAAM,CAAC;AACxE,UAAI,SAAS,MAAM;AACjB,eAAO,EAAE,MAAM,QAAQ,MAAM,OAAO,QAAQ,SAAS,cAAc;AAAA,MACrE;AAAA,IACF;AACA,QAAI,KAAK;AACP,aAAO,EAAE,MAAM,KAAK,OAAO,cAAc;AAAA,IAC3C;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,eACN,QACA,cACe;AACf,UAAM,aAAa;AAAA,MACjB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AACA,eAAW,SAAS,YAAY;AAC9B,UAAI,OAAO,UAAU,UAAU;AAC7B,cAAM,UAAU,MAAM,KAAK;AAC3B,YAAI,QAAQ,OAAQ,QAAO;AAAA,MAC7B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBACN,UACA,SACA,aACmB;AACnB,UAAM,EAAE,QAAQ,aAAa,IAAI;AACjC,UAAM,QAAkB,CAAC;AAEzB,UAAM,sBAAsB,aAAa,aAAa,IAAI,IAAI,YAAY,UAAU,IAAI;AACxF,UAAM,iBAAiB,oBAAI,IAAY;AAAA,MACrC,GAAI,aAAa,YAAY,CAAC;AAAA,MAC9B,GAAI,aAAa,YAAY,CAAC;AAAA,IAChC,CAAC;AAED,UAAM,kBAAkB,CAAC,UAA2B;AAClD,UAAI,4BAA4B,IAAI,KAAK,EAAG,QAAO;AACnD,UAAI,eAAe,IAAI,KAAK,EAAG,QAAO;AACtC,UAAI,uBAAuB,CAAC,oBAAoB,IAAI,KAAK,EAAG,QAAO;AACnE,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,CAAC,OAAe,UAAmB;AACnD,UAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,UAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,WAAW,EAAG;AAC5D,UAAI,OAAO,UAAU,UAAU;AAC7B,cAAM,KAAK,GAAG,KAAK,KAAK,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,MACjD,OAAO;AACL,cAAM,KAAK,GAAG,KAAK,KAAK,KAAK,EAAE;AAAA,MACjC;AAAA,IACF;AAEA,UAAM,kBAAkB,CAAC,SAAS,QAAQ,eAAe,WAAW,SAAS;AAC7E,eAAW,SAAS,iBAAiB;AACnC,UAAI,CAAC,gBAAgB,KAAK,EAAG;AAC7B,UAAI,OAAO,KAAK,KAAK,KAAM,WAAU,OAAO,OAAO,KAAK,CAAC;AAAA,IAC3D;AAEA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAI,gBAAgB,SAAS,GAAG,EAAG;AACnC,UAAI,CAAC,gBAAgB,GAAG,EAAG;AAC3B,gBAAU,KAAK,KAAK;AAAA,IACtB;AAEA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACvD,UAAI,CAAC,gBAAgB,GAAG,EAAG;AAC3B,gBAAU,UAAU,GAAG,IAAI,KAAK;AAAA,IAClC;AAEA,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,KAAK,GAAG,QAAQ,IAAI,OAAO,MAAM,EAAE,EAAE;AAAA,IAC7C;AAEA,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,MACT,gBAAgB,EAAE,QAAQ,aAAa;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,UAAoB,QAA4B,KAKtC;AACpC,UAAM,UAAU;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,MAClB,gBAAgB,IAAI,kBAAkB;AAAA,MACtC,UAAU,IAAI;AAAA,MACd,aAAa,KAAK,KAAK;AAAA,MACvB,WAAW,KAAK,KAAK,oBAAoB,KAAK,KAAK,kBAAkB,IAAI;AAAA,IAC3E;AACA,QAAI,OAAO,aAAa;AACtB,YAAM,QAAQ,MAAM,OAAO,YAAY,OAAO;AAC9C,UAAI,MAAO,QAAO;AAClB,aAAO;AAAA,IACT;AACA,WAAO,KAAK,mBAAmB,UAAU,EAAE,QAAQ,IAAI,QAAQ,cAAc,IAAI,aAAa,GAAG,OAAO,WAAW;AAAA,EACrH;AAAA,EAEA,MAAc,iBACZ,QACA,KAMA,UACuC;AACvC,UAAM,UAAU;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,MAClB,gBAAgB,IAAI,kBAAkB;AAAA,MACtC,UAAU,IAAI;AAAA,MACd,aAAa,KAAK,KAAK;AAAA,MACvB,WAAW,KAAK,KAAK,oBAAoB,KAAK,KAAK,kBAAkB,IAAI;AAAA,IAC3E;AACA,QAAI,OAAO,cAAc;AACvB,YAAM,YAAY,MAAM,OAAO,aAAa,OAAO;AACnD,UAAI,UAAW,QAAO;AAAA,IACxB;AACA,QAAI,SAAU,QAAO;AACrB,UAAM,WAAW,IAAI,OAAO,eAAe,IAAI,OAAO,SAAS,IAAI,OAAO;AAC1E,QAAI,OAAO,aAAa,YAAY,SAAS,KAAK,EAAE,SAAS,GAAG;AAC9D,YAAM,WAAW,IAAI,OAAO,eAAe,IAAI,OAAO;AACtD,aAAO;AAAA,QACL,OAAO;AAAA,QACP,UAAU,OAAO,aAAa,WAAW,WAAW;AAAA,MACtD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,aACZ,QACA,KAMA,UACwC;AACxC,UAAM,UAAU;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,cAAc,IAAI;AAAA,MAClB,gBAAgB,IAAI,kBAAkB;AAAA,MACtC,UAAU,IAAI;AAAA,MACd,aAAa,KAAK,KAAK;AAAA,MACvB,WAAW,KAAK,KAAK,oBAAoB,KAAK,KAAK,kBAAkB,IAAI;AAAA,IAC3E;AACA,QAAI,OAAO,cAAc;AACvB,YAAM,WAAW,MAAM,OAAO,aAAa,OAAO;AAClD,UAAI,UAAU,OAAQ,QAAO;AAAA,IAC/B;AACA,WAAO,YAAY;AAAA,EACrB;AAAA,EAEA,MAAc,WACZ,QACA,KAMA,UACwB;AACxB,QAAI,OAAO,YAAY;AACrB,YAAM,YAAY,MAAM,OAAO,WAAW;AAAA,QACxC,QAAQ,IAAI;AAAA,QACZ,cAAc,IAAI;AAAA,QAClB,gBAAgB,IAAI,kBAAkB;AAAA,QACtC,UAAU,IAAI;AAAA,QACd,aAAa,KAAK,KAAK;AAAA,QACvB,WAAW,KAAK,KAAK,oBAAoB,KAAK,KAAK,kBAAkB,IAAI;AAAA,MAC3E,CAAC;AACD,UAAI,UAAW,QAAO;AAAA,IACxB;AACA,WAAO,YAAY;AAAA,EACrB;AAAA,EAEA,MAAM,YAAY,MAA4D;AAC5E,UAAM,QAAQ,KAAK,aAAa,IAAI,KAAK,QAAQ;AACjD,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK,kBAAkB;AAAA,QACvC,QAAQ;AAAA,MACV;AAAA,IACF;AACA,UAAM,SAAS,KAAK,UAAU,MAAM,QAAQ;AAC5C,UAAM,OAAO,YAAY;AAEzB,UAAM,UAAU,MAAM,KAAK,YAAY,KAAK,UAAU,CAAC,KAAK,QAAQ,GAAG,KAAK,UAAU,KAAK,cAAc;AACzG,UAAM,MAAM,QAAQ,IAAI,KAAK,QAAQ;AACrC,QAAI,CAAC,KAAK;AACR,YAAM,WAAW,MAAM,OAAO,YAAY,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ;AACrF,UAAI,UAAU;AACZ,cAAM,OAAO,OAAO,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ;AAC/D,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,UAAU,KAAK;AAAA,UACf,gBAAgB,KAAK,kBAAkB;AAAA,QACzC;AAAA,MACF;AACA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK,kBAAkB;AAAA,QACvC,QAAQ;AAAA,MACV;AAAA,IACF;AACA,WAAO,KAAK,cAAc,OAAO,QAAQ,MAAM,GAA0B;AAAA,EAC3E;AAAA,EAEA,MAAM,aAAa,MAA6D;AAC9E,UAAM,QAAQ,KAAK,aAAa,IAAI,KAAK,QAAQ;AACjD,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK,kBAAkB;AAAA,QACvC,QAAQ;AAAA,MACV;AAAA,IACF;AACA,UAAM,SAAS,KAAK,UAAU,MAAM,QAAQ;AAC5C,UAAM,OAAO,YAAY;AACzB,UAAM,WAAW,KAAK,kBAAkB;AACxC,UAAM,WAAW,MAAM,OAAO,YAAY,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ;AACrF,QAAI,UAAU;AACZ,YAAM,OAAO,OAAO,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ;AAC/D,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU,KAAK;AAAA,QACf,gBAAgB;AAAA,MAClB;AAAA,IACF;AACA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,MAA6H;AAC/I,UAAM,QAAQ,KAAK,aAAa,IAAI,KAAK,QAAQ;AACjD,QAAI,CAAC,MAAO;AACZ,UAAM,SAAS,KAAK,UAAU,MAAM,QAAQ;AAC5C,UAAM,OAAO,YAAY;AAEzB,UAAM,cAAc,KAAK,eAAe;AACxC,UAAM,mBAAmB,oBAAI,KAAK;AAElC,QAAI,KAAK,KAAK,UAAU;AACtB,UAAI,eAAe,OAAO,SAAS,KAAK,UAAU;AAChD,cAAM,OAAO,MAAM,KAAK,UAAU,KAAK,UAAU,KAAK,cAAc;AAAA,MACtE,WAAW,eAAe,CAAC,KAAK,UAAU;AACxC,wBAAgB,UAAU,+DAA+D;AAAA,MAC3F;AACA,YAAM,UAAmC;AAAA,QACvC,YAAY,KAAK;AAAA,MACnB;AACA,UAAI,aAAa;AACf,gBAAQ,QAAQ;AAChB,gBAAQ,gBAAgB;AAAA,MAC1B;AACA,UAAI,KAAK,aAAa,OAAW,SAAQ,WAAW,KAAK;AAAA,UACpD,SAAQ,kBAAkB;AAC/B,UAAI,KAAK,mBAAmB,OAAW,SAAQ,iBAAiB,KAAK;AACrE,YAAM,KAAK,KAAK,SAAS,UAAU,uBAAuB,OAAO;AACjE;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,UAAU;AAClB,YAAM,IAAI,MAAM,kEAAkE;AAAA,IACpF;AAEA,QAAI,eAAe,OAAO,OAAO;AAC/B,YAAM,OAAO,MAAM,KAAK,UAAU,KAAK,UAAU,KAAK,cAAc;AAAA,IACtE;AAEA,UAAM,WAAW;AACjB,QAAI,OAAO;AACX,UAAM,YAAY,KAAK,qBAAqB;AAC5C,eAAS;AACP,YAAM,SAAS,MAAM,KAAK,KAAK,YAAY,MAAM,KAAK,UAAU;AAAA,QAC9D,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK,kBAAkB;AAAA,QACvC,MAAM,EAAE,MAAM,SAAS;AAAA,QACvB,qBAAqB;AAAA,QACrB,QAAQ,KAAK,oBAAoB,KAAK,QAAQ;AAAA,QAC9C,iBAAiB;AAAA,MACnB,CAAC;AACD,UAAI,CAAC,OAAO,MAAM,OAAQ;AAC1B,iBAAW,OAAO,OAAO,OAAO;AAC9B,cAAM,WAAW,OAAQ,IAAY,MAAM,EAAE;AAC7C,YAAI,CAAC,SAAU;AACf,cAAM,WAAW,MAAM,KAAK;AAAA,UAC1B;AAAA,UACA;AAAA,UACA;AAAA,YACE,UAAU,KAAK;AAAA,YACf;AAAA,YACA,UAAU,KAAK;AAAA,YACf,gBAAgB,KAAK,kBAAkB;AAAA,UACzC;AAAA,UACA;AAAA,UACA,EAAE,YAAY,KAAK;AAAA,QACrB;AACA,cAAM,mBAAmB;AAAA,UACvB,IAAI;AAAA,UACJ,SAAS;AAAA,UACT,YAAY,KAAK;AAAA,UACjB;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AACA,UAAI,OAAO,MAAM,SAAS,SAAU;AACpC,cAAQ;AAAA,IACV;AAEA,QAAI,aAAa;AACf,YAAM,KAAK,cAAc;AAAA,QACvB,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,MAAyG;AACxH,eAAW,YAAY,KAAK,oBAAoB,GAAG;AACjD,YAAM,KAAK,cAAc,EAAE,UAAU,UAAU,KAAK,UAAU,gBAAgB,KAAK,kBAAkB,MAAM,YAAY,KAAK,WAAW,CAAC;AAAA,IAC1I;AAAA,EACF;AAAA,EAEQ,uBAA6C;AACnD,QAAI,CAAC,KAAK,KAAK,kBAAmB,QAAO;AACzC,QAAI;AACF,YAAM,YAAY,KAAK,KAAK,kBAAkB;AAC9C,UAAI,CAAC,aAAa,OAAQ,UAAkB,YAAY,WAAY,QAAO;AAC3E,YAAM,WAAW;AACjB,YAAM,KAAK,SAAS,QAAQ,IAAI;AAChC,aAAQ,MAA+B;AAAA,IACzC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,MAAuG;AACtH,UAAM,UAAU,KAAK,WAAW,CAAC,KAAK,QAAQ,IAAI,KAAK,oBAAoB;AAC3E,QAAI,CAAC,QAAQ,OAAQ;AAErB,UAAM,UAAU,oBAAI,IAAgC;AACpD,eAAW,YAAY,SAAS;AAC9B,YAAM,MAAM,KAAK,aAAa,IAAI,QAAQ;AAC1C,UAAI,CAAC,IAAK;AACV,YAAM,SAAS,KAAK,UAAU,IAAI,QAAQ;AAC1C,UAAI,OAAO,OAAO,UAAU,YAAY;AACtC,cAAM,IAAI,MAAM,mBAAmB,IAAI,QAAQ,oCAAoC;AAAA,MACrF;AACA,UAAI,CAAC,QAAQ,IAAI,IAAI,QAAQ,EAAG,SAAQ,IAAI,IAAI,UAAU,CAAC,CAAC;AAC5D,cAAQ,IAAI,IAAI,QAAQ,EAAG,KAAK,QAAQ;AAAA,IAC1C;AAEA,eAAW,CAAC,UAAU,SAAS,KAAK,QAAQ,QAAQ,GAAG;AACrD,YAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,YAAM,OAAO,YAAY;AACzB,iBAAW,YAAY,WAAW;AAChC,cAAM,OAAO,MAAO,UAAU,KAAK,QAAQ;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,MAKA;AAClB,UAAM,QAAQ,KAAK,aAAa,IAAI,KAAK,QAAQ;AACjD,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,SAAS,KAAK,UAAU,MAAM,QAAQ;AAC5C,UAAM,OAAO,YAAY;AAEzB,UAAM,YAAY;AASlB,QAAI,OAAO,UAAU,kBAAkB,YAAY;AACjD,YAAM,UAAU,MAAM,UAAU,cAAc;AAAA,QAC5C,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,WAAW,KAAK;AAAA,MAClB,CAAC;AACD,aAAO,OAAO,YAAY,WAAW,UAAU;AAAA,IACjD;AAEA,oBAAgB,UAAU,0CAA0C,EAAE,UAAU,MAAM,SAAS,CAAC;AAChG,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,kBAAkB,MAKJ;AAClB,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,UAAM,eAAe,KAAK,WAAW,KAAK,aAAa,IAAI,KAAK,QAAQ,IAAI;AAC5E,QAAI,KAAK,YAAY,CAAC,cAAc;AAClC,aAAO;AAAA,IACT;AACA,UAAM,WACJ,KAAK,aACJ,eAAe,aAAa,WAAW,KAAK;AAC/C,UAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,UAAM,OAAO,YAAY;AACzB,UAAM,cAAc;AAAA,MAClB,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,UAAU,KAAK;AAAA,IACjB;AACA,QAAI,OAAO,OAAO,UAAU,YAAY;AACtC,UAAI;AACF,eAAO,MAAM,OAAO,MAAM,WAAW;AAAA,MACvC,SAAS,KAAK;AACZ,wBAAgB,UAAU,6CAA6C;AAAA,UACrE;AAAA,UACA,OAAO,eAAe,QAAQ,IAAI,UAAU;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA,IACF;AACA,QAAI,OAAO,OAAO,SAAS,YAAY;AACrC,YAAM,QAAQ;AACd,UAAI,SAAS;AACb,UAAI,QAAQ;AACZ,iBAAS;AACP,cAAM,QAAQ,MAAM,OAAO,KAAK;AAAA,UAC9B,UAAU,YAAY;AAAA,UACtB,gBAAgB,YAAY;AAAA,UAC5B,UAAU,YAAY;AAAA,UACtB;AAAA,UACA;AAAA,UACA,SAAS;AAAA,QACX,CAAC;AACD,cAAM,OAAO,MAAM;AACnB,iBAAS;AACT,YAAI,OAAO,MAAO;AAClB,kBAAU;AAAA,MACZ;AACA,aAAO;AAAA,IACT;AACA,oBAAgB,UAAU,6DAA6D,EAAE,SAAS,CAAC;AACnG,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,iBAAiB,MAOS;AAC9B,UAAM,eAAe,KAAK,WAAW,KAAK,aAAa,IAAI,KAAK,QAAQ,IAAI;AAC5E,QAAI,KAAK,YAAY,CAAC,cAAc;AAClC,aAAO,CAAC;AAAA,IACV;AACA,UAAM,WACJ,KAAK,aACJ,eAAe,aAAa,WAAW,KAAK;AAC/C,UAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,QAAI,OAAO,OAAO,SAAS,YAAY;AACrC,YAAM,IAAI,MAAM,mBAAmB,QAAQ,yCAAyC;AAAA,IACtF;AACA,UAAM,OAAO,YAAY;AACzB,UAAM,OAAO,MAAM,OAAO,KAAK;AAAA,MAC7B,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,KAAK,QAAQ;AAChB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,KAAK,IAAI,OAAO,UAAU;AACxB,cAAM,kBAAkB,MAAM,KAAK,oBAAoB;AAAA,UACrD,UAAU,KAAK;AAAA,UACf,gBAAgB,MAAM,kBAAkB;AAAA,UACxC,aAAa,MAAM;AAAA,UACnB,gBAAgB,MAAM,kBAAkB;AAAA,UACxC,YAAY,MAAM,cAAc;AAAA,UAChC,gBAAgB,MAAM,kBAAkB;AAAA,UACxC,iBAAiB,MAAM,mBAAmB;AAAA,UAC1C,kBAAkB,MAAM,oBAAoB;AAAA,UAC5C,OAAQ,MAAM,SAAiB;AAAA,UAC/B,SAAU,MAAM,WAAmB;AAAA,QACrC,CAAC;AACD,eAAO;AAAA,UACL,GAAG;AAAA,UACH,aAAa,gBAAgB;AAAA,UAC7B,gBAAgB,gBAAgB;AAAA,UAChC,YAAY,gBAAgB;AAAA,UAC5B,gBAAgB,gBAAgB;AAAA,UAChC,iBAAiB,gBAAgB;AAAA,UACjC,kBAAkB,gBAAgB;AAAA,UAClC,OAAO,gBAAgB;AAAA,UACvB,SAAS,gBAAgB;AAAA,UACzB,UAAW,gBAAgB,WAAmB;AAAA,QAChD;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO,UAAU,IAAI,CAAC,UAAU;AAC9B,YAAM,YAAY;AAAA,QAChB,OAAO,MAAM;AAAA,QACb,UAAU,MAAM,kBAAkB;AAAA,QAClC,MAAM,MAAM,cAAc;AAAA,QAC1B,OAAO,MAAM,WAAW,SAAS,MAAM,eAAe;AAAA,MACxD;AACA,YAAM,QAAQ,MAAM,UAAU,MAAM,kBAChC,CAAC,EAAE,MAAM,MAAM,iBAAiB,OAAO,MAAM,oBAAoB,MAAM,aAAa,MAAM,UAAmB,CAAC,IAC9G;AACJ,YAAM,MAAM,MAAM,OAAO,MAAM,mBAAmB;AAClD,YAAM,WAAW,MAAM,aAAa,MAAM,iBAAiB,EAAE,UAAU,MAAM,eAAe,IAAI;AAChG,aAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,MAAM,SAAS;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,SAAyD;AACpE,UAAM,WAAW,QAAQ,YAAY,KAAK;AAC1C,UAAM,SAAS,KAAK,UAAU,QAAQ;AACtC,UAAM,OAAO,YAAY;AACzB,QAAI,CAAC,KAAK,KAAK,iBAAiB,WAAW;AACzC,YAAM,IAAI,MAAM,iEAAiE;AAAA,IACnF;AACA,UAAM,YAAY,MAAM,KAAK,KAAK,iBAAiB,gBAAgB,QAAQ,KAAK;AAChF,UAAM,OAAO,MAAM,OAAO,MAAM;AAAA,MAC9B,QAAQ;AAAA,MACR,OAAO,QAAQ,SAAS;AAAA,MACxB,QAAQ;AAAA,QACN,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ,kBAAkB;AAAA,QAC1C,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAED,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAE1B,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,KAAK,IAAI,OAAO,QAAQ;AACtB,cAAM,kBAAkB,MAAM,KAAK,oBAAoB;AAAA,UACrD,UAAU,QAAQ;AAAA,UAClB,gBAAgB,IAAI,kBAAkB,QAAQ,kBAAkB;AAAA,UAChE,aAAa,IAAI;AAAA,UACjB,gBAAgB,IAAI,kBAAkB;AAAA,UACtC,YAAY,IAAI,cAAc;AAAA,UAC9B,gBAAgB,IAAI,kBAAkB;AAAA,UACtC,iBAAiB,IAAI,mBAAmB;AAAA,UACxC,kBAAkB,IAAI,oBAAoB;AAAA,UAC1C,OAAQ,IAAI,SAAiB;AAAA,UAC7B,SAAU,IAAI,WAAmB;AAAA,QACnC,CAAC;AACD,eAAO;AAAA,UACL,GAAG;AAAA,UACH,aAAa,gBAAgB;AAAA,UAC7B,gBAAgB,gBAAgB;AAAA,UAChC,YAAY,gBAAgB;AAAA,UAC5B,gBAAgB,gBAAgB;AAAA,UAChC,iBAAiB,gBAAgB;AAAA,UACjC,kBAAkB,gBAAgB;AAAA,UAClC,OAAO,gBAAgB;AAAA,UACvB,SAAS,gBAAgB;AAAA,QAC3B;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO,UAAU,IAAI,CAAC,QAAQ;AAC5B,YAAM,YAAY;AAAA,QAChB,OAAO,IAAI;AAAA,QACX,UAAU,IAAI,kBAAkB;AAAA,QAChC,MAAM,IAAI,cAAc;AAAA,QACxB,OAAO,IAAI,WAAW,SAAS,IAAI,eAAe;AAAA,MACpD;AACA,YAAM,QAAQ,IAAI,UAAU,IAAI,kBAC5B,CAAC,EAAE,MAAM,IAAI,iBAAiB,OAAO,IAAI,oBAAoB,IAAI,aAAa,MAAM,UAAmB,CAAC,IACxG;AACJ,YAAM,MAAM,IAAI,OAAO,IAAI,mBAAmB;AAC9C,YAAM,WAAW,IAAI,YAAY,IAAI,iBAAiB,EAAE,UAAU,IAAI,eAAe,IAAI;AACzF,aAAO;AAAA,QACL,UAAU,IAAI;AAAA,QACd,UAAU,IAAI;AAAA,QACd,OAAO,IAAI;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/search",
|
|
3
|
-
"version": "0.7.1-develop.
|
|
3
|
+
"version": "0.7.1-develop.7148.1.3076e5ccf7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
"zod": "^4.4.3"
|
|
128
128
|
},
|
|
129
129
|
"peerDependencies": {
|
|
130
|
-
"@open-mercato/core": "0.7.1-develop.
|
|
131
|
-
"@open-mercato/queue": "0.7.1-develop.
|
|
132
|
-
"@open-mercato/shared": "0.7.1-develop.
|
|
130
|
+
"@open-mercato/core": "0.7.1-develop.7148.1.3076e5ccf7",
|
|
131
|
+
"@open-mercato/queue": "0.7.1-develop.7148.1.3076e5ccf7",
|
|
132
|
+
"@open-mercato/shared": "0.7.1-develop.7148.1.3076e5ccf7"
|
|
133
133
|
},
|
|
134
134
|
"devDependencies": {
|
|
135
135
|
"@types/jest": "^30.0.0",
|
|
@@ -228,3 +228,48 @@ describe('VectorIndexService encryption fail-closed (issue #2716)', () => {
|
|
|
228
228
|
expect(driver.upsertCalls[0].resultTitle).toBe('Title')
|
|
229
229
|
})
|
|
230
230
|
})
|
|
231
|
+
|
|
232
|
+
describe('VectorIndexService decrypted result parse-back (issue #5789)', () => {
|
|
233
|
+
const passthroughEncryptionService = (): TenantDataEncryptionService =>
|
|
234
|
+
({
|
|
235
|
+
isEnabled: () => true,
|
|
236
|
+
decryptEntityPayload: async (_entityId: string, payload: Record<string, unknown>) => payload,
|
|
237
|
+
}) as unknown as TenantDataEncryptionService
|
|
238
|
+
|
|
239
|
+
it('parses links/payload back to objects when decryptEntityPayload returns sealed JSON strings', async () => {
|
|
240
|
+
const driver = createDriver({
|
|
241
|
+
query: async () => [
|
|
242
|
+
{
|
|
243
|
+
entityId: 'demo:item',
|
|
244
|
+
recordId: 'rec-6',
|
|
245
|
+
organizationId: null,
|
|
246
|
+
score: 0.9,
|
|
247
|
+
checksum: 'abc',
|
|
248
|
+
resultTitle: 'Visible Title',
|
|
249
|
+
resultSubtitle: null,
|
|
250
|
+
resultIcon: null,
|
|
251
|
+
resultBadge: null,
|
|
252
|
+
resultSnapshot: null,
|
|
253
|
+
primaryLinkHref: null,
|
|
254
|
+
primaryLinkLabel: null,
|
|
255
|
+
links: '[{"href":"/backend/demo/rec-6","label":"View","kind":"primary"}]',
|
|
256
|
+
payload: '{"foo":"bar"}',
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
})
|
|
260
|
+
const captured: CapturedEmbeddingInput = { value: null }
|
|
261
|
+
const service = createService({
|
|
262
|
+
driver,
|
|
263
|
+
embeddingService: createEmbeddingService(captured),
|
|
264
|
+
queryEngine: createQueryEngine({ id: 'rec-6' }),
|
|
265
|
+
moduleConfigs: [{ entities: [{ entityId: 'demo:item' }] }],
|
|
266
|
+
encryptionService: passthroughEncryptionService(),
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
const results = await service.search({ tenantId: 'tenant-1', query: 'anything' })
|
|
270
|
+
|
|
271
|
+
expect(results).toHaveLength(1)
|
|
272
|
+
expect(results[0].links).toEqual([{ href: '/backend/demo/rec-6', label: 'View', kind: 'primary' }])
|
|
273
|
+
expect(results[0].metadata).toEqual({ foo: 'bar' })
|
|
274
|
+
})
|
|
275
|
+
})
|
|
@@ -2,6 +2,7 @@ import type { QueryEngine } from '@open-mercato/shared/lib/query/types'
|
|
|
2
2
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
3
3
|
import type { EntityId } from '@open-mercato/shared/modules/entities'
|
|
4
4
|
import type { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'
|
|
5
|
+
import { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'
|
|
5
6
|
import {
|
|
6
7
|
type VectorModuleConfig,
|
|
7
8
|
type VectorEntityConfig,
|
|
@@ -269,6 +270,8 @@ export class VectorIndexService {
|
|
|
269
270
|
args.tenantId,
|
|
270
271
|
args.organizationId,
|
|
271
272
|
)
|
|
273
|
+
const decryptedLinks = (decrypted as any).links ?? args.links
|
|
274
|
+
const decryptedPayload = (decrypted as any).payload ?? args.payload
|
|
272
275
|
return {
|
|
273
276
|
resultTitle: String((decrypted as any).resultTitle ?? args.resultTitle),
|
|
274
277
|
resultSubtitle: ((decrypted as any).resultSubtitle ?? args.resultSubtitle) as any,
|
|
@@ -276,8 +279,8 @@ export class VectorIndexService {
|
|
|
276
279
|
resultSnapshot: ((decrypted as any).resultSnapshot ?? args.resultSnapshot) as any,
|
|
277
280
|
primaryLinkHref: ((decrypted as any).primaryLinkHref ?? args.primaryLinkHref) as any,
|
|
278
281
|
primaryLinkLabel: ((decrypted as any).primaryLinkLabel ?? args.primaryLinkLabel) as any,
|
|
279
|
-
links: (
|
|
280
|
-
payload: (
|
|
282
|
+
links: (typeof decryptedLinks === 'string' ? parseDecryptedFieldValue(decryptedLinks) : decryptedLinks) as any,
|
|
283
|
+
payload: (typeof decryptedPayload === 'string' ? parseDecryptedFieldValue(decryptedPayload) : decryptedPayload) as any,
|
|
281
284
|
}
|
|
282
285
|
} catch (err) {
|
|
283
286
|
searchDebugWarn('vector.index', 'Vector entry decryption failed; refusing to return ciphertext as plaintext', {
|