@opengeni/documents 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Settings } from \"@opengeni/config\";\nimport type {\n AddDocumentRequest,\n CreateDocumentBaseRequest,\n Document,\n DocumentBase,\n DocumentSearchMode,\n DocumentSearchResult,\n FileAsset,\n KnowledgeSourceKind,\n} from \"@opengeni/contracts\";\nimport { requireFile, withRlsContext, withWorkspaceRls, type Database } from \"@opengeni/db\";\nimport * as schema from \"@opengeni/db/schema\";\nimport type { ObjectStorage } from \"@opengeni/storage\";\nimport { LiteParse } from \"@llamaindex/liteparse\";\nimport { and, asc, desc, eq, inArray, sql, type SQL } from \"drizzle-orm\";\nimport OpenAI from \"openai\";\n\nexport const DEFAULT_DOCUMENT_PARSER = \"liteparse\";\nexport const DEFAULT_DOCUMENT_EMBEDDING_MODEL = \"text-embedding-3-large\";\nexport const DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS = 3072;\nexport const DEFAULT_DOCUMENT_CHUNK_SIZE = 1200;\nexport const DEFAULT_DOCUMENT_CHUNK_OVERLAP = 160;\n\nexport type ParsedDocument = {\n text: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type DocumentChunk = {\n text: string;\n metadata: Record<string, unknown>;\n};\n\nexport type DocumentParser = {\n name: string;\n parse: (bytes: Uint8Array, file: FileAsset) => Promise<ParsedDocument>;\n};\n\nexport type DocumentChunker = {\n chunk: (parsed: ParsedDocument, file: FileAsset) => DocumentChunk[];\n};\n\nexport type DocumentEmbedder = {\n model: string;\n dimensions: number;\n embedMany: (texts: string[]) => Promise<number[][]>;\n embedQuery: (text: string) => Promise<number[]>;\n};\n\nexport type DocumentServices = {\n parser: DocumentParser;\n chunker: DocumentChunker;\n embedder: DocumentEmbedder;\n};\n\nexport type DocumentSearchInput = {\n workspaceId: string;\n query: string;\n baseIds?: string[] | undefined;\n limit?: number | undefined;\n mode?: DocumentSearchMode | undefined;\n sourceKinds?: KnowledgeSourceKind[] | undefined;\n aclTags?: string[] | undefined;\n};\n\nexport type DocumentIndexHooks = {\n beforeEmbed?: (input: {\n accountId: string;\n workspaceId: string;\n documentId: string;\n chunkCount: number;\n }) => Promise<void>;\n};\n\nexport class LiteParseDocumentParser implements DocumentParser {\n readonly name = DEFAULT_DOCUMENT_PARSER;\n private parseQueue: Promise<void> = Promise.resolve();\n\n async parse(bytes: Uint8Array, file: FileAsset): Promise<ParsedDocument> {\n const text = isTextLike(file)\n ? Buffer.from(bytes).toString(\"utf8\").replace(/\\0/g, \" \").trim()\n : await this.parseWithLiteParse(bytes);\n if (!text.trim()) {\n throw new Error(`Parsed document is empty: ${file.filename}`);\n }\n return {\n text: text.trim(),\n metadata: {\n parser: this.name,\n filename: file.filename,\n contentType: file.contentType,\n },\n };\n }\n\n private async parseWithLiteParse(bytes: Uint8Array): Promise<string> {\n return await this.enqueueParse(async () => {\n const parser = new LiteParse({ ocrEnabled: true, numWorkers: 1 });\n const result = await parser.parse(Buffer.from(bytes), true);\n const text = typeof result?.text === \"string\" ? result.text : \"\";\n return text.replace(/\\0/g, \" \").trim();\n });\n }\n\n private async enqueueParse<T>(task: () => Promise<T>): Promise<T> {\n const previous = this.parseQueue;\n let release: () => void = () => undefined;\n this.parseQueue = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous.catch(() => undefined);\n try {\n return await task();\n } finally {\n release();\n }\n }\n}\n\nexport class RecursiveTextChunker implements DocumentChunker {\n constructor(\n private readonly maxChars = DEFAULT_DOCUMENT_CHUNK_SIZE,\n private readonly overlapChars = DEFAULT_DOCUMENT_CHUNK_OVERLAP,\n ) {\n if (overlapChars >= maxChars) {\n throw new Error(\"document chunk overlap must be smaller than chunk size\");\n }\n }\n\n chunk(parsed: ParsedDocument, file: FileAsset): DocumentChunk[] {\n return chunkText(parsed.text, this.maxChars, this.overlapChars).map((text, index) => ({\n text,\n metadata: {\n ...parsed.metadata,\n filename: file.filename,\n contentType: file.contentType,\n chunkIndex: index,\n },\n }));\n }\n}\n\nexport class OpenAIEmbeddingProvider implements DocumentEmbedder {\n private client: OpenAI | null = null;\n private readonly apiKey: string | undefined;\n private readonly baseURL: string | undefined;\n\n constructor(args: {\n apiKey?: string | undefined;\n baseURL?: string | undefined;\n defaultHeaders?: Record<string, string> | undefined;\n defaultQuery?: Record<string, string> | undefined;\n model?: string | undefined;\n dimensions?: number | undefined;\n }) {\n this.apiKey = args.apiKey ?? process.env.OPENAI_API_KEY;\n this.baseURL = args.baseURL;\n this.defaultHeaders = args.defaultHeaders;\n this.defaultQuery = args.defaultQuery;\n this.model = args.model ?? DEFAULT_DOCUMENT_EMBEDDING_MODEL;\n this.dimensions = args.dimensions ?? DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS;\n }\n\n readonly model: string;\n readonly dimensions: number;\n private readonly defaultHeaders: Record<string, string> | undefined;\n private readonly defaultQuery: Record<string, string> | undefined;\n\n async embedMany(texts: string[]): Promise<number[][]> {\n if (texts.length === 0) return [];\n const out: number[][] = [];\n for (let start = 0; start < texts.length; start += 64) {\n const batch = texts.slice(start, start + 64);\n const response = await this.openai().embeddings.create({\n model: this.model,\n input: batch,\n dimensions: this.dimensions,\n });\n for (const item of response.data) {\n out.push(validateEmbedding(item.embedding, this.dimensions, this.model));\n }\n }\n return out;\n }\n\n async embedQuery(text: string): Promise<number[]> {\n const [embedding] = await this.embedMany([text]);\n if (!embedding) {\n throw new Error(\"Embedding provider returned no query embedding\");\n }\n return embedding;\n }\n\n private openai(): OpenAI {\n if (!this.apiKey) {\n throw new Error(\"OpenAI document embeddings require an API key\");\n }\n this.client ??= new OpenAI({\n apiKey: this.apiKey,\n ...(this.baseURL ? { baseURL: this.baseURL } : {}),\n ...(this.defaultQuery ? { defaultQuery: this.defaultQuery } : {}),\n ...(this.defaultHeaders ? { defaultHeaders: this.defaultHeaders } : {}),\n });\n return this.client;\n }\n}\n\nexport class DeterministicEmbeddingProvider implements DocumentEmbedder {\n constructor(\n readonly dimensions = DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS,\n readonly model = `deterministic-local-${dimensions}`,\n ) {}\n\n async embedMany(texts: string[]): Promise<number[][]> {\n return texts.map((text) => deterministicEmbedding(text, this.dimensions));\n }\n\n async embedQuery(text: string): Promise<number[]> {\n return deterministicEmbedding(text, this.dimensions);\n }\n}\n\nexport function createDocumentServices(settings?: Settings, overrides: Partial<DocumentServices> = {}): DocumentServices {\n const dimensions = settings?.documentEmbeddingDimensions ?? DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS;\n const openAIEmbeddingConfig = documentOpenAIEmbeddingConfig(settings);\n return {\n parser: overrides.parser ?? new LiteParseDocumentParser(),\n chunker: overrides.chunker ?? new RecursiveTextChunker(\n settings?.documentChunkSize ?? DEFAULT_DOCUMENT_CHUNK_SIZE,\n settings?.documentChunkOverlap ?? DEFAULT_DOCUMENT_CHUNK_OVERLAP,\n ),\n embedder: overrides.embedder ?? (\n settings?.documentEmbeddingProvider === \"deterministic\"\n ? new DeterministicEmbeddingProvider(dimensions, settings.documentEmbeddingModel)\n : new OpenAIEmbeddingProvider({\n ...openAIEmbeddingConfig,\n model: settings?.documentEmbeddingModel ?? DEFAULT_DOCUMENT_EMBEDDING_MODEL,\n dimensions,\n })\n ),\n };\n}\n\nexport function documentOpenAIEmbeddingConfig(settings?: Settings): {\n apiKey?: string | undefined;\n baseURL?: string | undefined;\n defaultHeaders?: Record<string, string> | undefined;\n defaultQuery?: Record<string, string> | undefined;\n} {\n if (!settings) return {};\n if (settings.documentEmbeddingApiKey || settings.documentEmbeddingBaseUrl) {\n return {\n apiKey: settings.documentEmbeddingApiKey ?? settings.openaiApiKey ?? settings.azureOpenaiApiKey,\n baseURL: settings.documentEmbeddingBaseUrl ?? settings.openaiBaseUrl ?? settings.azureOpenaiBaseUrl,\n };\n }\n if (settings.openaiProvider === \"azure\") {\n const baseURL = settings.azureOpenaiBaseUrl ?? azureDeploymentBaseUrl(settings);\n return {\n apiKey: settings.azureOpenaiApiKey ?? settings.azureOpenaiAdToken ?? \"azure-ad-token\",\n baseURL,\n defaultQuery: azureOpenAIDefaultQuery(settings, baseURL),\n defaultHeaders: settings.azureOpenaiAdToken && !settings.azureOpenaiApiKey\n ? { Authorization: `Bearer ${settings.azureOpenaiAdToken}` }\n : undefined,\n };\n }\n return {\n apiKey: settings.openaiApiKey,\n baseURL: settings.openaiBaseUrl,\n };\n}\n\nfunction azureDeploymentBaseUrl(settings: Settings): string {\n const endpoint = settings.azureOpenaiEndpoint?.replace(/\\/+$/, \"\");\n if (!endpoint || !settings.azureOpenaiDeployment) {\n throw new Error(\"Azure OpenAI endpoint/deployment settings are incomplete\");\n }\n return `${endpoint}/openai/deployments/${settings.azureOpenaiDeployment}`;\n}\n\nfunction azureOpenAIDefaultQuery(\n settings: Pick<Settings, \"azureOpenaiApiVersion\">,\n baseURL: string,\n): Record<string, string> | undefined {\n if (!settings.azureOpenaiApiVersion) return undefined;\n const normalized = baseURL.replace(/\\/+$/, \"\").toLowerCase();\n if (normalized.endsWith(\"/openai/v1\")) {\n return undefined;\n }\n return { \"api-version\": settings.azureOpenaiApiVersion };\n}\n\nexport async function createDocumentBase(db: Database, input: CreateDocumentBaseRequest & { accountId: string; workspaceId: string }): Promise<DocumentBase> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [row] = await scopedDb.insert(schema.documentBases).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n name: input.name.trim(),\n description: input.description?.trim() || null,\n }).returning();\n if (!row) throw new Error(\"Failed to create document base\");\n return mapDocumentBase(row);\n });\n}\n\nexport async function listDocumentBases(db: Database, workspaceId: string): Promise<DocumentBase[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.documentBases)\n .where(eq(schema.documentBases.workspaceId, workspaceId))\n .orderBy(desc(schema.documentBases.createdAt));\n return rows.map(mapDocumentBase);\n });\n}\n\nexport async function getDocumentBase(db: Database, workspaceId: string, baseId: string): Promise<DocumentBase | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.documentBases).where(and(eq(schema.documentBases.workspaceId, workspaceId), eq(schema.documentBases.id, baseId))).limit(1);\n return row ? mapDocumentBase(row) : null;\n });\n}\n\nexport async function addDocumentToBase(db: Database, input: AddDocumentRequest & { accountId: string; workspaceId: string; baseId: string }): Promise<Document> {\n return await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const base = await getDocumentBase(scopedDb, input.workspaceId, input.baseId);\n if (!base) throw new Error(`Document base not found: ${input.baseId}`);\n const file = await requireReadyFile(scopedDb, input.workspaceId, input.fileId);\n const now = new Date();\n const [existing] = await scopedDb.select().from(schema.documents)\n .where(and(eq(schema.documents.workspaceId, input.workspaceId), eq(schema.documents.baseId, input.baseId), eq(schema.documents.fileId, input.fileId)))\n .limit(1);\n if (existing) {\n // Idempotent re-add: refresh caller-supplied source metadata on the\n // existing row instead of silently discarding it (aclTags especially —\n // a re-add that tightens tags must not be a no-op).\n const [updated] = await scopedDb.update(schema.documents).set({\n title: cleanString(input.title) ?? cleanString(input.sourceTitle) ?? existing.title,\n ...(input.sourceKind !== undefined ? { sourceKind: input.sourceKind } : {}),\n sourceUri: cleanString(input.sourceUri) ?? existing.sourceUri,\n sourceExternalId: cleanString(input.sourceExternalId) ?? existing.sourceExternalId,\n sourceTitle: cleanString(input.sourceTitle) ?? existing.sourceTitle,\n sourceAuthor: cleanString(input.sourceAuthor) ?? existing.sourceAuthor,\n sourceCreatedAt: parseOptionalDate(input.sourceCreatedAt) ?? existing.sourceCreatedAt,\n sourceUpdatedAt: parseOptionalDate(input.sourceUpdatedAt) ?? existing.sourceUpdatedAt,\n sourceVersion: cleanString(input.sourceVersion) ?? existing.sourceVersion,\n ...(input.aclTags !== undefined ? { aclTags: cleanStringArray(input.aclTags) } : {}),\n updatedAt: now,\n }).where(and(eq(schema.documents.workspaceId, input.workspaceId), eq(schema.documents.id, existing.id))).returning();\n return mapDocument(updated ?? existing);\n }\n const [row] = await scopedDb.insert(schema.documents).values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n baseId: input.baseId,\n fileId: input.fileId,\n status: \"queued\",\n title: cleanString(input.title) ?? cleanString(input.sourceTitle) ?? file.filename,\n parser: DEFAULT_DOCUMENT_PARSER,\n sourceKind: input.sourceKind ?? \"manual_upload\",\n sourceUri: cleanString(input.sourceUri) ?? null,\n sourceExternalId: cleanString(input.sourceExternalId) ?? null,\n sourceTitle: cleanString(input.sourceTitle) ?? null,\n sourceAuthor: cleanString(input.sourceAuthor) ?? null,\n sourceCreatedAt: parseOptionalDate(input.sourceCreatedAt),\n sourceUpdatedAt: parseOptionalDate(input.sourceUpdatedAt),\n sourceVersion: cleanString(input.sourceVersion) ?? null,\n aclTags: cleanStringArray(input.aclTags),\n updatedAt: now,\n }).returning();\n if (!row) throw new Error(\"Failed to create document\");\n return mapDocument(row);\n });\n}\n\nexport async function deleteDocumentFromBase(\n db: Database,\n input: { accountId: string; workspaceId: string; baseId: string; documentId: string },\n): Promise<void> {\n await withRlsContext(db, { accountId: input.accountId, workspaceId: input.workspaceId }, async (scopedDb) => {\n const [document] = await scopedDb.select().from(schema.documents)\n .where(and(eq(schema.documents.workspaceId, input.workspaceId), eq(schema.documents.id, input.documentId)))\n .limit(1);\n if (!document) {\n throw new Error(`Document not found: ${input.documentId}`);\n }\n if (document.baseId !== input.baseId) {\n throw new Error(`Document not found: ${input.documentId}`);\n }\n await scopedDb.delete(schema.documents)\n .where(and(eq(schema.documents.workspaceId, input.workspaceId), eq(schema.documents.id, input.documentId)));\n });\n}\n\nexport async function listDocuments(db: Database, workspaceId: string, baseId: string): Promise<Document[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb.select().from(schema.documents)\n .where(and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.baseId, baseId)))\n .orderBy(asc(schema.documents.createdAt));\n return rows.map(mapDocument);\n });\n}\n\nexport async function getDocument(db: Database, workspaceId: string, documentId: string): Promise<Document | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.select().from(schema.documents).where(and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))).limit(1);\n return row ? mapDocument(row) : null;\n });\n}\n\nexport async function queueDocumentForReindex(db: Database, workspaceId: string, documentId: string): Promise<Document> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb.update(schema.documents).set({\n status: \"queued\",\n error: null,\n updatedAt: new Date(),\n }).where(and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))).returning();\n if (!row) throw new Error(`Document not found: ${documentId}`);\n return mapDocument(row);\n });\n}\n\nexport async function indexDocumentNow(\n db: Database,\n objectStorage: ObjectStorage,\n workspaceId: string,\n documentId: string,\n services: DocumentServices = createDocumentServices(),\n hooks: DocumentIndexHooks = {},\n): Promise<Document> {\n const [document] = await withWorkspaceRls(db, workspaceId, async (scopedDb) =>\n await scopedDb.select().from(schema.documents).where(and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))).limit(1)\n );\n if (!document) throw new Error(`Document not found: ${documentId}`);\n const file = await requireReadyFile(db, workspaceId, document.fileId);\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb.update(schema.documents).set({\n status: \"indexing\",\n parser: services.parser.name,\n error: null,\n updatedAt: new Date(),\n }).where(and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId)));\n });\n try {\n const bytes = await objectStorage.getFileBytes(file);\n const parsed = await services.parser.parse(bytes, file);\n const chunks = services.chunker.chunk(parsed, file);\n await hooks.beforeEmbed?.({\n accountId: document.accountId,\n workspaceId: document.workspaceId,\n documentId,\n chunkCount: chunks.length,\n });\n const embeddings = await services.embedder.embedMany(chunks.map((chunk) => chunk.text));\n if (embeddings.length !== chunks.length) {\n throw new Error(`Embedding provider returned ${embeddings.length} embeddings for ${chunks.length} chunks`);\n }\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => await scopedDb.transaction(async (tx) => {\n await tx.delete(schema.documentChunks).where(and(eq(schema.documentChunks.workspaceId, workspaceId), eq(schema.documentChunks.documentId, documentId)));\n if (chunks.length > 0) {\n await tx.insert(schema.documentChunks).values(chunks.map((chunk, index) => ({\n accountId: document.accountId,\n workspaceId: document.workspaceId,\n documentId,\n baseId: document.baseId,\n fileId: file.id,\n chunkIndex: index,\n text: chunk.text,\n metadata: {\n ...chunk.metadata,\n documentTitle: document.title,\n sourceKind: document.sourceKind,\n sourceUri: document.sourceUri,\n sourceExternalId: document.sourceExternalId,\n sourceTitle: document.sourceTitle,\n sourceAuthor: document.sourceAuthor,\n sourceCreatedAt: document.sourceCreatedAt?.toISOString() ?? null,\n sourceUpdatedAt: document.sourceUpdatedAt?.toISOString() ?? null,\n sourceVersion: document.sourceVersion,\n aclTags: document.aclTags,\n },\n embedding: validateEmbedding(embeddings[index] ?? [], services.embedder.dimensions, services.embedder.model),\n embeddingModel: services.embedder.model,\n })));\n }\n await tx.update(schema.documents).set({\n status: \"ready\",\n parser: services.parser.name,\n chunkCount: chunks.length,\n error: null,\n updatedAt: new Date(),\n }).where(and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId)));\n }));\n } catch (error) {\n const [failed] = await withWorkspaceRls(db, workspaceId, async (scopedDb) =>\n await scopedDb.update(schema.documents).set({\n status: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n updatedAt: new Date(),\n }).where(and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId))).returning()\n );\n if (!failed) throw error;\n return mapDocument(failed);\n }\n const updated = await getDocument(db, workspaceId, documentId);\n if (!updated) throw new Error(`Document disappeared after indexing: ${documentId}`);\n return updated;\n}\n\nexport async function searchDocuments(\n db: Database,\n input: DocumentSearchInput,\n services: Pick<DocumentServices, \"embedder\"> = createDocumentServices(),\n): Promise<DocumentSearchResult[]> {\n const mode = input.mode ?? \"hybrid\";\n const limit = Math.min(Math.max(input.limit ?? 5, 1), 50);\n const candidateLimit = mode === \"hybrid\" ? Math.min(limit * 4, 100) : limit;\n const rows: CombinedSearchRow[] = [];\n if (mode === \"vector\" || mode === \"hybrid\") {\n try {\n rows.push(...await vectorSearchDocuments(db, input, candidateLimit, services));\n } catch (error) {\n if (mode === \"vector\") {\n throw error;\n }\n console.warn(\"document hybrid search vector component failed; falling back to keyword search\", {\n workspaceId: input.workspaceId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n if (mode === \"keyword\" || mode === \"hybrid\") {\n rows.push(...await keywordSearchDocuments(db, input, candidateLimit));\n }\n return mergeDocumentSearchRows(rows, mode).slice(0, limit);\n}\n\nasync function vectorSearchDocuments(\n db: Database,\n input: DocumentSearchInput,\n limit: number,\n services: Pick<DocumentServices, \"embedder\">,\n): Promise<CombinedSearchRow[]> {\n const queryEmbedding = await services.embedder.embedQuery(input.query);\n validateEmbedding(queryEmbedding, services.embedder.dimensions, services.embedder.model);\n const distance = sql<number>`${schema.documentChunks.embedding} <=> ${vectorLiteral(queryEmbedding)}::vector`;\n const rows = await withWorkspaceRls(db, input.workspaceId, async (scopedDb) =>\n await scopedDb.select({\n chunkId: schema.documentChunks.id,\n documentId: schema.documentChunks.documentId,\n baseId: schema.documentChunks.baseId,\n fileId: schema.documentChunks.fileId,\n title: schema.documents.title,\n text: schema.documentChunks.text,\n chunkIndex: schema.documentChunks.chunkIndex,\n metadata: schema.documentChunks.metadata,\n sourceKind: schema.documents.sourceKind,\n sourceUri: schema.documents.sourceUri,\n sourceExternalId: schema.documents.sourceExternalId,\n sourceTitle: schema.documents.sourceTitle,\n sourceAuthor: schema.documents.sourceAuthor,\n sourceCreatedAt: schema.documents.sourceCreatedAt,\n sourceUpdatedAt: schema.documents.sourceUpdatedAt,\n sourceVersion: schema.documents.sourceVersion,\n aclTags: schema.documents.aclTags,\n distance,\n }).from(schema.documentChunks)\n .innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id))\n .where(and(...documentSearchConditions(input, services.embedder.model)))\n .orderBy(distance)\n .limit(limit)\n );\n return rows.map((row) => ({\n ...mapSearchRowBase(row, input.workspaceId),\n vectorScore: 1 / (1 + Number(row.distance)),\n keywordScore: null,\n }));\n}\n\nasync function keywordSearchDocuments(db: Database, input: DocumentSearchInput, limit: number): Promise<CombinedSearchRow[]> {\n const rank = sql<number>`ts_rank_cd(to_tsvector('simple', ${schema.documentChunks.text}), plainto_tsquery('simple', ${input.query}))`;\n const rows = await withWorkspaceRls(db, input.workspaceId, async (scopedDb) =>\n await scopedDb.select({\n chunkId: schema.documentChunks.id,\n documentId: schema.documentChunks.documentId,\n baseId: schema.documentChunks.baseId,\n fileId: schema.documentChunks.fileId,\n title: schema.documents.title,\n text: schema.documentChunks.text,\n chunkIndex: schema.documentChunks.chunkIndex,\n metadata: schema.documentChunks.metadata,\n sourceKind: schema.documents.sourceKind,\n sourceUri: schema.documents.sourceUri,\n sourceExternalId: schema.documents.sourceExternalId,\n sourceTitle: schema.documents.sourceTitle,\n sourceAuthor: schema.documents.sourceAuthor,\n sourceCreatedAt: schema.documents.sourceCreatedAt,\n sourceUpdatedAt: schema.documents.sourceUpdatedAt,\n sourceVersion: schema.documents.sourceVersion,\n aclTags: schema.documents.aclTags,\n rank,\n }).from(schema.documentChunks)\n .innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id))\n .where(and(\n ...documentSearchConditions(input),\n sql`to_tsvector('simple', ${schema.documentChunks.text}) @@ plainto_tsquery('simple', ${input.query})`,\n ))\n .orderBy(desc(rank))\n .limit(limit)\n );\n return rows.map((row) => ({\n ...mapSearchRowBase(row, input.workspaceId),\n vectorScore: null,\n keywordScore: normalizeKeywordScore(Number(row.rank)),\n }));\n}\n\nexport async function getDocumentChunk(db: Database, workspaceId: string, chunkId: string): Promise<DocumentSearchResult | null> {\n const [row] = await withWorkspaceRls(db, workspaceId, async (scopedDb) =>\n await scopedDb.select({\n chunkId: schema.documentChunks.id,\n documentId: schema.documentChunks.documentId,\n baseId: schema.documentChunks.baseId,\n fileId: schema.documentChunks.fileId,\n title: schema.documents.title,\n text: schema.documentChunks.text,\n chunkIndex: schema.documentChunks.chunkIndex,\n metadata: schema.documentChunks.metadata,\n sourceKind: schema.documents.sourceKind,\n sourceUri: schema.documents.sourceUri,\n sourceExternalId: schema.documents.sourceExternalId,\n sourceTitle: schema.documents.sourceTitle,\n sourceAuthor: schema.documents.sourceAuthor,\n sourceCreatedAt: schema.documents.sourceCreatedAt,\n sourceUpdatedAt: schema.documents.sourceUpdatedAt,\n sourceVersion: schema.documents.sourceVersion,\n aclTags: schema.documents.aclTags,\n }).from(schema.documentChunks)\n .innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id))\n .where(and(eq(schema.documentChunks.workspaceId, workspaceId), eq(schema.documentChunks.id, chunkId), eq(schema.documents.status, \"ready\")))\n .limit(1)\n );\n if (!row) return null;\n return {\n ...mapSearchRowBase(row, workspaceId),\n score: 1,\n matchType: \"hybrid\",\n vectorScore: null,\n keywordScore: null,\n };\n}\n\ntype SearchRowBase = Omit<DocumentSearchResult, \"score\" | \"matchType\" | \"vectorScore\" | \"keywordScore\">;\ntype CombinedSearchRow = SearchRowBase & {\n vectorScore: number | null;\n keywordScore: number | null;\n};\n\nfunction documentSearchConditions(input: DocumentSearchInput, embeddingModel?: string): SQL[] {\n const conditions: SQL[] = [\n eq(schema.documents.status, \"ready\"),\n eq(schema.documentChunks.workspaceId, input.workspaceId),\n ];\n if (embeddingModel) {\n conditions.push(eq(schema.documentChunks.embeddingModel, embeddingModel));\n }\n if (input.baseIds?.length) {\n conditions.push(inArray(schema.documentChunks.baseId, input.baseIds));\n }\n if (input.sourceKinds?.length) {\n conditions.push(inArray(schema.documents.sourceKind, input.sourceKinds));\n }\n const aclTags = cleanStringArray(input.aclTags);\n if (aclTags.length > 0) {\n conditions.push(sql`${schema.documents.aclTags} @> ${JSON.stringify(aclTags)}::jsonb`);\n }\n return conditions;\n}\n\nfunction mapSearchRowBase(row: {\n chunkId: string;\n documentId: string;\n baseId: string;\n fileId: string;\n title: string;\n text: string;\n chunkIndex: number;\n metadata: Record<string, unknown>;\n sourceKind: string;\n sourceUri: string | null;\n sourceExternalId: string | null;\n sourceTitle: string | null;\n sourceAuthor: string | null;\n sourceCreatedAt: Date | null;\n sourceUpdatedAt: Date | null;\n sourceVersion: string | null;\n aclTags: string[];\n}, workspaceId: string): SearchRowBase {\n return {\n chunkId: row.chunkId,\n workspaceId,\n documentId: row.documentId,\n baseId: row.baseId,\n fileId: row.fileId,\n title: row.title,\n text: row.text,\n chunkIndex: row.chunkIndex,\n metadata: row.metadata,\n sourceKind: normalizeKnowledgeSourceKind(row.sourceKind),\n sourceUri: row.sourceUri,\n sourceExternalId: row.sourceExternalId,\n sourceTitle: row.sourceTitle,\n sourceAuthor: row.sourceAuthor,\n sourceCreatedAt: row.sourceCreatedAt?.toISOString() ?? null,\n sourceUpdatedAt: row.sourceUpdatedAt?.toISOString() ?? null,\n sourceVersion: row.sourceVersion,\n aclTags: cleanStringArray(row.aclTags),\n };\n}\n\nfunction mergeDocumentSearchRows(rows: CombinedSearchRow[], mode: DocumentSearchMode): DocumentSearchResult[] {\n const byChunk = new Map<string, CombinedSearchRow>();\n for (const row of rows) {\n const existing = byChunk.get(row.chunkId);\n if (!existing) {\n byChunk.set(row.chunkId, row);\n continue;\n }\n byChunk.set(row.chunkId, {\n ...existing,\n vectorScore: Math.max(existing.vectorScore ?? 0, row.vectorScore ?? 0) || null,\n keywordScore: Math.max(existing.keywordScore ?? 0, row.keywordScore ?? 0) || null,\n });\n }\n return [...byChunk.values()].map((row) => {\n const vectorScore = row.vectorScore;\n const keywordScore = row.keywordScore;\n const matchType: DocumentSearchMode = vectorScore !== null && keywordScore !== null\n ? \"hybrid\"\n : vectorScore !== null\n ? \"vector\"\n : \"keyword\";\n return {\n ...row,\n score: combinedSearchScore(mode, vectorScore, keywordScore, matchType),\n matchType,\n };\n }).sort((left, right) =>\n right.score - left.score\n || (right.vectorScore ?? 0) - (left.vectorScore ?? 0)\n || (right.keywordScore ?? 0) - (left.keywordScore ?? 0)\n || left.chunkIndex - right.chunkIndex\n );\n}\n\nfunction combinedSearchScore(\n mode: DocumentSearchMode,\n vectorScore: number | null,\n keywordScore: number | null,\n matchType: DocumentSearchMode,\n): number {\n const vector = vectorScore ?? 0;\n const keyword = keywordScore ?? 0;\n if (mode === \"vector\") return roundScore(vector);\n if (mode === \"keyword\") return roundScore(keyword);\n return roundScore(Math.min(1, (0.65 * vector) + (0.35 * keyword) + (matchType === \"hybrid\" ? 0.1 : 0)));\n}\n\nfunction normalizeKeywordScore(rank: number): number {\n if (!Number.isFinite(rank) || rank <= 0) {\n return 0;\n }\n return rank / (rank + 1);\n}\n\nfunction roundScore(value: number): number {\n return Number(value.toFixed(6));\n}\n\nexport async function parseDocumentBytes(bytes: Uint8Array, file: FileAsset, parser: DocumentParser = new LiteParseDocumentParser()): Promise<ParsedDocument> {\n return await parser.parse(bytes, file);\n}\n\nexport function chunkText(text: string, maxChars = DEFAULT_DOCUMENT_CHUNK_SIZE, overlapChars = DEFAULT_DOCUMENT_CHUNK_OVERLAP): string[] {\n if (overlapChars >= maxChars) {\n throw new Error(\"chunk overlap must be smaller than chunk size\");\n }\n const normalized = text.replace(/\\r\\n/g, \"\\n\").replace(/[ \\t]+/g, \" \").trim();\n if (!normalized) return [];\n const paragraphs = normalized.split(/\\n{2,}/).map((part) => part.replace(/\\s+/g, \" \").trim()).filter(Boolean);\n const chunks: string[] = [];\n let current = \"\";\n for (const paragraph of paragraphs.length > 0 ? paragraphs : [normalized.replace(/\\s+/g, \" \")]) {\n for (const part of splitOversizedText(paragraph, maxChars)) {\n if (!current) {\n current = part;\n } else if (current.length + 1 + part.length <= maxChars) {\n current = `${current} ${part}`;\n } else {\n chunks.push(current);\n current = withOverlap(current, overlapChars, part, maxChars);\n }\n }\n }\n if (current) chunks.push(current);\n return chunks.map((chunk) => chunk.trim()).filter(Boolean);\n}\n\nexport function deterministicEmbedding(text: string, dimensions = DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS): number[] {\n const values = new Array(dimensions).fill(0);\n const tokens = text.toLowerCase().match(/[\\p{L}\\p{N}_-]+/gu) ?? [];\n for (const token of tokens) {\n let hash = 2166136261;\n for (const char of token) {\n hash ^= char.codePointAt(0) ?? 0;\n hash = Math.imul(hash, 16777619);\n }\n values[Math.abs(hash) % dimensions] += 1;\n }\n const norm = Math.hypot(...values) || 1;\n return values.map((value) => Number((value / norm).toFixed(6)));\n}\n\nasync function requireReadyFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset> {\n const file = await requireFile(db, workspaceId, fileId);\n if (file.status !== \"ready\") {\n throw new Error(`File ${fileId} is ${file.status}`);\n }\n return file;\n}\n\nfunction validateEmbedding(values: number[], dimensions: number, model: string): number[] {\n if (values.length !== dimensions) {\n throw new Error(`Embedding model ${model} returned ${values.length} dimensions; expected ${dimensions}`);\n }\n if (values.some((value) => !Number.isFinite(value))) {\n throw new Error(`Embedding model ${model} returned non-finite values`);\n }\n return values;\n}\n\nfunction isTextLike(file: FileAsset): boolean {\n const contentType = file.contentType.toLowerCase();\n const filename = file.filename.toLowerCase();\n return contentType.startsWith(\"text/\")\n || contentType === \"application/json\"\n || contentType === \"application/xml\"\n || contentType === \"application/x-yaml\"\n || filename.endsWith(\".md\")\n || filename.endsWith(\".markdown\")\n || filename.endsWith(\".json\")\n || filename.endsWith(\".yaml\")\n || filename.endsWith(\".yml\")\n || filename.endsWith(\".csv\")\n || filename.endsWith(\".tsv\")\n || filename.endsWith(\".xml\");\n}\n\nfunction splitOversizedText(text: string, maxChars: number): string[] {\n if (text.length <= maxChars) return [text];\n const out: string[] = [];\n let remaining = text;\n while (remaining.length > maxChars) {\n const window = remaining.slice(0, maxChars + 1);\n const breakAt = Math.max(\n window.lastIndexOf(\". \"),\n window.lastIndexOf(\"? \"),\n window.lastIndexOf(\"! \"),\n window.lastIndexOf(\"; \"),\n window.lastIndexOf(\", \"),\n window.lastIndexOf(\" \"),\n );\n const end = breakAt > Math.floor(maxChars * 0.5) ? breakAt + 1 : maxChars;\n out.push(remaining.slice(0, end).trim());\n remaining = remaining.slice(end).trim();\n }\n if (remaining) out.push(remaining);\n return out;\n}\n\nfunction withOverlap(previous: string, overlapChars: number, next: string, maxChars: number): string {\n if (overlapChars <= 0) return next;\n const overlap = previous.slice(Math.max(0, previous.length - overlapChars)).replace(/^\\S+\\s+/, \"\").trim();\n const candidate = overlap ? `${overlap} ${next}` : next;\n return candidate.length <= maxChars ? candidate : next;\n}\n\nfunction cleanString(value: string | undefined | null): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction cleanStringArray(values: string[] | undefined | null): string[] {\n return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];\n}\n\nfunction parseOptionalDate(value: string | undefined): Date | null {\n const trimmed = cleanString(value);\n if (!trimmed) {\n return null;\n }\n const date = new Date(trimmed);\n if (Number.isNaN(date.getTime())) {\n throw new Error(`Invalid source timestamp: ${trimmed}`);\n }\n return date;\n}\n\nfunction normalizeKnowledgeSourceKind(value: string): KnowledgeSourceKind {\n switch (value) {\n case \"manual_upload\":\n case \"meeting_transcript\":\n case \"repository\":\n case \"email\":\n case \"chat\":\n case \"document\":\n case \"web\":\n case \"other\":\n return value;\n default:\n return \"other\";\n }\n}\n\nfunction vectorLiteral(values: number[]): string {\n return `[${values.join(\",\")}]`;\n}\n\nfunction mapDocumentBase(row: typeof schema.documentBases.$inferSelect): DocumentBase {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n name: row.name,\n description: row.description,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapDocument(row: typeof schema.documents.$inferSelect): Document {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n baseId: row.baseId,\n fileId: row.fileId,\n status: row.status as Document[\"status\"],\n title: row.title,\n parser: row.parser,\n chunkCount: row.chunkCount,\n error: row.error,\n sourceKind: normalizeKnowledgeSourceKind(row.sourceKind),\n sourceUri: row.sourceUri,\n sourceExternalId: row.sourceExternalId,\n sourceTitle: row.sourceTitle,\n sourceAuthor: row.sourceAuthor,\n sourceCreatedAt: row.sourceCreatedAt?.toISOString() ?? null,\n sourceUpdatedAt: row.sourceUpdatedAt?.toISOString() ?? null,\n sourceVersion: row.sourceVersion,\n aclTags: cleanStringArray(row.aclTags),\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Settings } from \"@opengeni/config\";\nimport type {\n AddDocumentRequest,\n CreateDocumentBaseRequest,\n Document,\n DocumentBase,\n DocumentSearchMode,\n DocumentSearchResult,\n FileAsset,\n KnowledgeSourceKind,\n} from \"@opengeni/contracts\";\nimport { requireFile, withRlsContext, withWorkspaceRls, type Database } from \"@opengeni/db\";\nimport * as schema from \"@opengeni/db/schema\";\nimport type { ObjectStorage } from \"@opengeni/storage\";\nimport { LiteParse } from \"@llamaindex/liteparse\";\nimport { and, asc, desc, eq, inArray, sql, type SQL } from \"drizzle-orm\";\nimport OpenAI from \"openai\";\n\nexport const DEFAULT_DOCUMENT_PARSER = \"liteparse\";\nexport const DEFAULT_DOCUMENT_EMBEDDING_MODEL = \"text-embedding-3-large\";\nexport const DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS = 3072;\nexport const DEFAULT_DOCUMENT_CHUNK_SIZE = 1200;\nexport const DEFAULT_DOCUMENT_CHUNK_OVERLAP = 160;\n\nexport type ParsedDocument = {\n text: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type DocumentChunk = {\n text: string;\n metadata: Record<string, unknown>;\n};\n\nexport type DocumentParser = {\n name: string;\n parse: (bytes: Uint8Array, file: FileAsset) => Promise<ParsedDocument>;\n};\n\nexport type DocumentChunker = {\n chunk: (parsed: ParsedDocument, file: FileAsset) => DocumentChunk[];\n};\n\nexport type DocumentEmbedder = {\n model: string;\n dimensions: number;\n embedMany: (texts: string[]) => Promise<number[][]>;\n embedQuery: (text: string) => Promise<number[]>;\n};\n\nexport type DocumentServices = {\n parser: DocumentParser;\n chunker: DocumentChunker;\n embedder: DocumentEmbedder;\n};\n\nexport type DocumentSearchInput = {\n workspaceId: string;\n query: string;\n baseIds?: string[] | undefined;\n limit?: number | undefined;\n mode?: DocumentSearchMode | undefined;\n sourceKinds?: KnowledgeSourceKind[] | undefined;\n aclTags?: string[] | undefined;\n};\n\nexport type DocumentIndexHooks = {\n beforeEmbed?: (input: {\n accountId: string;\n workspaceId: string;\n documentId: string;\n chunkCount: number;\n }) => Promise<void>;\n};\n\nexport class LiteParseDocumentParser implements DocumentParser {\n readonly name = DEFAULT_DOCUMENT_PARSER;\n private parseQueue: Promise<void> = Promise.resolve();\n\n async parse(bytes: Uint8Array, file: FileAsset): Promise<ParsedDocument> {\n const text = isTextLike(file)\n ? Buffer.from(bytes).toString(\"utf8\").replace(/\\0/g, \" \").trim()\n : await this.parseWithLiteParse(bytes);\n if (!text.trim()) {\n throw new Error(`Parsed document is empty: ${file.filename}`);\n }\n return {\n text: text.trim(),\n metadata: {\n parser: this.name,\n filename: file.filename,\n contentType: file.contentType,\n },\n };\n }\n\n private async parseWithLiteParse(bytes: Uint8Array): Promise<string> {\n return await this.enqueueParse(async () => {\n const parser = new LiteParse({ ocrEnabled: true, numWorkers: 1 });\n const result = await parser.parse(Buffer.from(bytes), true);\n const text = typeof result?.text === \"string\" ? result.text : \"\";\n return text.replace(/\\0/g, \" \").trim();\n });\n }\n\n private async enqueueParse<T>(task: () => Promise<T>): Promise<T> {\n const previous = this.parseQueue;\n let release: () => void = () => undefined;\n this.parseQueue = new Promise<void>((resolve) => {\n release = resolve;\n });\n await previous.catch(() => undefined);\n try {\n return await task();\n } finally {\n release();\n }\n }\n}\n\nexport class RecursiveTextChunker implements DocumentChunker {\n constructor(\n private readonly maxChars = DEFAULT_DOCUMENT_CHUNK_SIZE,\n private readonly overlapChars = DEFAULT_DOCUMENT_CHUNK_OVERLAP,\n ) {\n if (overlapChars >= maxChars) {\n throw new Error(\"document chunk overlap must be smaller than chunk size\");\n }\n }\n\n chunk(parsed: ParsedDocument, file: FileAsset): DocumentChunk[] {\n return chunkText(parsed.text, this.maxChars, this.overlapChars).map((text, index) => ({\n text,\n metadata: {\n ...parsed.metadata,\n filename: file.filename,\n contentType: file.contentType,\n chunkIndex: index,\n },\n }));\n }\n}\n\nexport class OpenAIEmbeddingProvider implements DocumentEmbedder {\n private client: OpenAI | null = null;\n private readonly apiKey: string | undefined;\n private readonly baseURL: string | undefined;\n\n constructor(args: {\n apiKey?: string | undefined;\n baseURL?: string | undefined;\n defaultHeaders?: Record<string, string> | undefined;\n defaultQuery?: Record<string, string> | undefined;\n model?: string | undefined;\n dimensions?: number | undefined;\n }) {\n this.apiKey = args.apiKey ?? process.env.OPENAI_API_KEY;\n this.baseURL = args.baseURL;\n this.defaultHeaders = args.defaultHeaders;\n this.defaultQuery = args.defaultQuery;\n this.model = args.model ?? DEFAULT_DOCUMENT_EMBEDDING_MODEL;\n this.dimensions = args.dimensions ?? DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS;\n }\n\n readonly model: string;\n readonly dimensions: number;\n private readonly defaultHeaders: Record<string, string> | undefined;\n private readonly defaultQuery: Record<string, string> | undefined;\n\n async embedMany(texts: string[]): Promise<number[][]> {\n if (texts.length === 0) return [];\n const out: number[][] = [];\n for (let start = 0; start < texts.length; start += 64) {\n const batch = texts.slice(start, start + 64);\n const response = await this.openai().embeddings.create({\n model: this.model,\n input: batch,\n dimensions: this.dimensions,\n });\n for (const item of response.data) {\n out.push(validateEmbedding(item.embedding, this.dimensions, this.model));\n }\n }\n return out;\n }\n\n async embedQuery(text: string): Promise<number[]> {\n const [embedding] = await this.embedMany([text]);\n if (!embedding) {\n throw new Error(\"Embedding provider returned no query embedding\");\n }\n return embedding;\n }\n\n private openai(): OpenAI {\n if (!this.apiKey) {\n throw new Error(\"OpenAI document embeddings require an API key\");\n }\n this.client ??= new OpenAI({\n apiKey: this.apiKey,\n ...(this.baseURL ? { baseURL: this.baseURL } : {}),\n ...(this.defaultQuery ? { defaultQuery: this.defaultQuery } : {}),\n ...(this.defaultHeaders ? { defaultHeaders: this.defaultHeaders } : {}),\n });\n return this.client;\n }\n}\n\nexport class DeterministicEmbeddingProvider implements DocumentEmbedder {\n constructor(\n readonly dimensions = DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS,\n readonly model = `deterministic-local-${dimensions}`,\n ) {}\n\n async embedMany(texts: string[]): Promise<number[][]> {\n return texts.map((text) => deterministicEmbedding(text, this.dimensions));\n }\n\n async embedQuery(text: string): Promise<number[]> {\n return deterministicEmbedding(text, this.dimensions);\n }\n}\n\nexport function createDocumentServices(\n settings?: Settings,\n overrides: Partial<DocumentServices> = {},\n): DocumentServices {\n const dimensions = settings?.documentEmbeddingDimensions ?? DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS;\n const openAIEmbeddingConfig = documentOpenAIEmbeddingConfig(settings);\n return {\n parser: overrides.parser ?? new LiteParseDocumentParser(),\n chunker:\n overrides.chunker ??\n new RecursiveTextChunker(\n settings?.documentChunkSize ?? DEFAULT_DOCUMENT_CHUNK_SIZE,\n settings?.documentChunkOverlap ?? DEFAULT_DOCUMENT_CHUNK_OVERLAP,\n ),\n embedder:\n overrides.embedder ??\n (settings?.documentEmbeddingProvider === \"deterministic\"\n ? new DeterministicEmbeddingProvider(dimensions, settings.documentEmbeddingModel)\n : new OpenAIEmbeddingProvider({\n ...openAIEmbeddingConfig,\n model: settings?.documentEmbeddingModel ?? DEFAULT_DOCUMENT_EMBEDDING_MODEL,\n dimensions,\n })),\n };\n}\n\nexport function documentOpenAIEmbeddingConfig(settings?: Settings): {\n apiKey?: string | undefined;\n baseURL?: string | undefined;\n defaultHeaders?: Record<string, string> | undefined;\n defaultQuery?: Record<string, string> | undefined;\n} {\n if (!settings) return {};\n if (settings.documentEmbeddingApiKey || settings.documentEmbeddingBaseUrl) {\n return {\n apiKey:\n settings.documentEmbeddingApiKey ?? settings.openaiApiKey ?? settings.azureOpenaiApiKey,\n baseURL:\n settings.documentEmbeddingBaseUrl ?? settings.openaiBaseUrl ?? settings.azureOpenaiBaseUrl,\n };\n }\n if (settings.openaiProvider === \"azure\") {\n const baseURL = settings.azureOpenaiBaseUrl ?? azureDeploymentBaseUrl(settings);\n return {\n apiKey: settings.azureOpenaiApiKey ?? settings.azureOpenaiAdToken ?? \"azure-ad-token\",\n baseURL,\n defaultQuery: azureOpenAIDefaultQuery(settings, baseURL),\n defaultHeaders:\n settings.azureOpenaiAdToken && !settings.azureOpenaiApiKey\n ? { Authorization: `Bearer ${settings.azureOpenaiAdToken}` }\n : undefined,\n };\n }\n return {\n apiKey: settings.openaiApiKey,\n baseURL: settings.openaiBaseUrl,\n };\n}\n\nfunction azureDeploymentBaseUrl(settings: Settings): string {\n const endpoint = settings.azureOpenaiEndpoint?.replace(/\\/+$/, \"\");\n if (!endpoint || !settings.azureOpenaiDeployment) {\n throw new Error(\"Azure OpenAI endpoint/deployment settings are incomplete\");\n }\n return `${endpoint}/openai/deployments/${settings.azureOpenaiDeployment}`;\n}\n\nfunction azureOpenAIDefaultQuery(\n settings: Pick<Settings, \"azureOpenaiApiVersion\">,\n baseURL: string,\n): Record<string, string> | undefined {\n if (!settings.azureOpenaiApiVersion) return undefined;\n const normalized = baseURL.replace(/\\/+$/, \"\").toLowerCase();\n if (normalized.endsWith(\"/openai/v1\")) {\n return undefined;\n }\n return { \"api-version\": settings.azureOpenaiApiVersion };\n}\n\nexport async function createDocumentBase(\n db: Database,\n input: CreateDocumentBaseRequest & { accountId: string; workspaceId: string },\n): Promise<DocumentBase> {\n return await withRlsContext(\n db,\n { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const [row] = await scopedDb\n .insert(schema.documentBases)\n .values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n name: input.name.trim(),\n description: input.description?.trim() || null,\n })\n .returning();\n if (!row) throw new Error(\"Failed to create document base\");\n return mapDocumentBase(row);\n },\n );\n}\n\nexport async function listDocumentBases(\n db: Database,\n workspaceId: string,\n): Promise<DocumentBase[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb\n .select()\n .from(schema.documentBases)\n .where(eq(schema.documentBases.workspaceId, workspaceId))\n .orderBy(desc(schema.documentBases.createdAt));\n return rows.map(mapDocumentBase);\n });\n}\n\nexport async function getDocumentBase(\n db: Database,\n workspaceId: string,\n baseId: string,\n): Promise<DocumentBase | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb\n .select()\n .from(schema.documentBases)\n .where(\n and(eq(schema.documentBases.workspaceId, workspaceId), eq(schema.documentBases.id, baseId)),\n )\n .limit(1);\n return row ? mapDocumentBase(row) : null;\n });\n}\n\nexport async function addDocumentToBase(\n db: Database,\n input: AddDocumentRequest & { accountId: string; workspaceId: string; baseId: string },\n): Promise<Document> {\n return await withRlsContext(\n db,\n { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const base = await getDocumentBase(scopedDb, input.workspaceId, input.baseId);\n if (!base) throw new Error(`Document base not found: ${input.baseId}`);\n const file = await requireReadyFile(scopedDb, input.workspaceId, input.fileId);\n const now = new Date();\n const [existing] = await scopedDb\n .select()\n .from(schema.documents)\n .where(\n and(\n eq(schema.documents.workspaceId, input.workspaceId),\n eq(schema.documents.baseId, input.baseId),\n eq(schema.documents.fileId, input.fileId),\n ),\n )\n .limit(1);\n if (existing) {\n // Idempotent re-add: refresh caller-supplied source metadata on the\n // existing row instead of silently discarding it (aclTags especially —\n // a re-add that tightens tags must not be a no-op).\n const [updated] = await scopedDb\n .update(schema.documents)\n .set({\n title: cleanString(input.title) ?? cleanString(input.sourceTitle) ?? existing.title,\n ...(input.sourceKind !== undefined ? { sourceKind: input.sourceKind } : {}),\n sourceUri: cleanString(input.sourceUri) ?? existing.sourceUri,\n sourceExternalId: cleanString(input.sourceExternalId) ?? existing.sourceExternalId,\n sourceTitle: cleanString(input.sourceTitle) ?? existing.sourceTitle,\n sourceAuthor: cleanString(input.sourceAuthor) ?? existing.sourceAuthor,\n sourceCreatedAt: parseOptionalDate(input.sourceCreatedAt) ?? existing.sourceCreatedAt,\n sourceUpdatedAt: parseOptionalDate(input.sourceUpdatedAt) ?? existing.sourceUpdatedAt,\n sourceVersion: cleanString(input.sourceVersion) ?? existing.sourceVersion,\n ...(input.aclTags !== undefined ? { aclTags: cleanStringArray(input.aclTags) } : {}),\n updatedAt: now,\n })\n .where(\n and(\n eq(schema.documents.workspaceId, input.workspaceId),\n eq(schema.documents.id, existing.id),\n ),\n )\n .returning();\n return mapDocument(updated ?? existing);\n }\n const [row] = await scopedDb\n .insert(schema.documents)\n .values({\n accountId: input.accountId,\n workspaceId: input.workspaceId,\n baseId: input.baseId,\n fileId: input.fileId,\n status: \"queued\",\n title: cleanString(input.title) ?? cleanString(input.sourceTitle) ?? file.filename,\n parser: DEFAULT_DOCUMENT_PARSER,\n sourceKind: input.sourceKind ?? \"manual_upload\",\n sourceUri: cleanString(input.sourceUri) ?? null,\n sourceExternalId: cleanString(input.sourceExternalId) ?? null,\n sourceTitle: cleanString(input.sourceTitle) ?? null,\n sourceAuthor: cleanString(input.sourceAuthor) ?? null,\n sourceCreatedAt: parseOptionalDate(input.sourceCreatedAt),\n sourceUpdatedAt: parseOptionalDate(input.sourceUpdatedAt),\n sourceVersion: cleanString(input.sourceVersion) ?? null,\n aclTags: cleanStringArray(input.aclTags),\n updatedAt: now,\n })\n .returning();\n if (!row) throw new Error(\"Failed to create document\");\n return mapDocument(row);\n },\n );\n}\n\nexport async function deleteDocumentFromBase(\n db: Database,\n input: { accountId: string; workspaceId: string; baseId: string; documentId: string },\n): Promise<void> {\n await withRlsContext(\n db,\n { accountId: input.accountId, workspaceId: input.workspaceId },\n async (scopedDb) => {\n const [document] = await scopedDb\n .select()\n .from(schema.documents)\n .where(\n and(\n eq(schema.documents.workspaceId, input.workspaceId),\n eq(schema.documents.id, input.documentId),\n ),\n )\n .limit(1);\n if (!document) {\n throw new Error(`Document not found: ${input.documentId}`);\n }\n if (document.baseId !== input.baseId) {\n throw new Error(`Document not found: ${input.documentId}`);\n }\n await scopedDb\n .delete(schema.documents)\n .where(\n and(\n eq(schema.documents.workspaceId, input.workspaceId),\n eq(schema.documents.id, input.documentId),\n ),\n );\n },\n );\n}\n\nexport async function listDocuments(\n db: Database,\n workspaceId: string,\n baseId: string,\n): Promise<Document[]> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const rows = await scopedDb\n .select()\n .from(schema.documents)\n .where(\n and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.baseId, baseId)),\n )\n .orderBy(asc(schema.documents.createdAt));\n return rows.map(mapDocument);\n });\n}\n\nexport async function getDocument(\n db: Database,\n workspaceId: string,\n documentId: string,\n): Promise<Document | null> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb\n .select()\n .from(schema.documents)\n .where(\n and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId)),\n )\n .limit(1);\n return row ? mapDocument(row) : null;\n });\n}\n\nexport async function queueDocumentForReindex(\n db: Database,\n workspaceId: string,\n documentId: string,\n): Promise<Document> {\n return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n const [row] = await scopedDb\n .update(schema.documents)\n .set({\n status: \"queued\",\n error: null,\n updatedAt: new Date(),\n })\n .where(\n and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId)),\n )\n .returning();\n if (!row) throw new Error(`Document not found: ${documentId}`);\n return mapDocument(row);\n });\n}\n\nexport async function indexDocumentNow(\n db: Database,\n objectStorage: ObjectStorage,\n workspaceId: string,\n documentId: string,\n services: DocumentServices = createDocumentServices(),\n hooks: DocumentIndexHooks = {},\n): Promise<Document> {\n const [document] = await withWorkspaceRls(\n db,\n workspaceId,\n async (scopedDb) =>\n await scopedDb\n .select()\n .from(schema.documents)\n .where(\n and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId)),\n )\n .limit(1),\n );\n if (!document) throw new Error(`Document not found: ${documentId}`);\n const file = await requireReadyFile(db, workspaceId, document.fileId);\n await withWorkspaceRls(db, workspaceId, async (scopedDb) => {\n await scopedDb\n .update(schema.documents)\n .set({\n status: \"indexing\",\n parser: services.parser.name,\n error: null,\n updatedAt: new Date(),\n })\n .where(\n and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId)),\n );\n });\n try {\n const bytes = await objectStorage.getFileBytes(file);\n const parsed = await services.parser.parse(bytes, file);\n const chunks = services.chunker.chunk(parsed, file);\n await hooks.beforeEmbed?.({\n accountId: document.accountId,\n workspaceId: document.workspaceId,\n documentId,\n chunkCount: chunks.length,\n });\n const embeddings = await services.embedder.embedMany(chunks.map((chunk) => chunk.text));\n if (embeddings.length !== chunks.length) {\n throw new Error(\n `Embedding provider returned ${embeddings.length} embeddings for ${chunks.length} chunks`,\n );\n }\n await withWorkspaceRls(\n db,\n workspaceId,\n async (scopedDb) =>\n await scopedDb.transaction(async (tx) => {\n await tx\n .delete(schema.documentChunks)\n .where(\n and(\n eq(schema.documentChunks.workspaceId, workspaceId),\n eq(schema.documentChunks.documentId, documentId),\n ),\n );\n if (chunks.length > 0) {\n await tx.insert(schema.documentChunks).values(\n chunks.map((chunk, index) => ({\n accountId: document.accountId,\n workspaceId: document.workspaceId,\n documentId,\n baseId: document.baseId,\n fileId: file.id,\n chunkIndex: index,\n text: chunk.text,\n metadata: {\n ...chunk.metadata,\n documentTitle: document.title,\n sourceKind: document.sourceKind,\n sourceUri: document.sourceUri,\n sourceExternalId: document.sourceExternalId,\n sourceTitle: document.sourceTitle,\n sourceAuthor: document.sourceAuthor,\n sourceCreatedAt: document.sourceCreatedAt?.toISOString() ?? null,\n sourceUpdatedAt: document.sourceUpdatedAt?.toISOString() ?? null,\n sourceVersion: document.sourceVersion,\n aclTags: document.aclTags,\n },\n embedding: validateEmbedding(\n embeddings[index] ?? [],\n services.embedder.dimensions,\n services.embedder.model,\n ),\n embeddingModel: services.embedder.model,\n })),\n );\n }\n await tx\n .update(schema.documents)\n .set({\n status: \"ready\",\n parser: services.parser.name,\n chunkCount: chunks.length,\n error: null,\n updatedAt: new Date(),\n })\n .where(\n and(\n eq(schema.documents.workspaceId, workspaceId),\n eq(schema.documents.id, documentId),\n ),\n );\n }),\n );\n } catch (error) {\n const [failed] = await withWorkspaceRls(\n db,\n workspaceId,\n async (scopedDb) =>\n await scopedDb\n .update(schema.documents)\n .set({\n status: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n updatedAt: new Date(),\n })\n .where(\n and(eq(schema.documents.workspaceId, workspaceId), eq(schema.documents.id, documentId)),\n )\n .returning(),\n );\n if (!failed) throw error;\n return mapDocument(failed);\n }\n const updated = await getDocument(db, workspaceId, documentId);\n if (!updated) throw new Error(`Document disappeared after indexing: ${documentId}`);\n return updated;\n}\n\nexport async function searchDocuments(\n db: Database,\n input: DocumentSearchInput,\n services: Pick<DocumentServices, \"embedder\"> = createDocumentServices(),\n): Promise<DocumentSearchResult[]> {\n const mode = input.mode ?? \"hybrid\";\n const limit = Math.min(Math.max(input.limit ?? 5, 1), 50);\n const candidateLimit = mode === \"hybrid\" ? Math.min(limit * 4, 100) : limit;\n const rows: CombinedSearchRow[] = [];\n if (mode === \"vector\" || mode === \"hybrid\") {\n try {\n rows.push(...(await vectorSearchDocuments(db, input, candidateLimit, services)));\n } catch (error) {\n if (mode === \"vector\") {\n throw error;\n }\n console.warn(\n \"document hybrid search vector component failed; falling back to keyword search\",\n {\n workspaceId: input.workspaceId,\n error: error instanceof Error ? error.message : String(error),\n },\n );\n }\n }\n if (mode === \"keyword\" || mode === \"hybrid\") {\n rows.push(...(await keywordSearchDocuments(db, input, candidateLimit)));\n }\n return mergeDocumentSearchRows(rows, mode).slice(0, limit);\n}\n\nasync function vectorSearchDocuments(\n db: Database,\n input: DocumentSearchInput,\n limit: number,\n services: Pick<DocumentServices, \"embedder\">,\n): Promise<CombinedSearchRow[]> {\n const queryEmbedding = await services.embedder.embedQuery(input.query);\n validateEmbedding(queryEmbedding, services.embedder.dimensions, services.embedder.model);\n const distance = sql<number>`${schema.documentChunks.embedding} <=> ${vectorLiteral(queryEmbedding)}::vector`;\n const rows = await withWorkspaceRls(\n db,\n input.workspaceId,\n async (scopedDb) =>\n await scopedDb\n .select({\n chunkId: schema.documentChunks.id,\n documentId: schema.documentChunks.documentId,\n baseId: schema.documentChunks.baseId,\n fileId: schema.documentChunks.fileId,\n title: schema.documents.title,\n text: schema.documentChunks.text,\n chunkIndex: schema.documentChunks.chunkIndex,\n metadata: schema.documentChunks.metadata,\n sourceKind: schema.documents.sourceKind,\n sourceUri: schema.documents.sourceUri,\n sourceExternalId: schema.documents.sourceExternalId,\n sourceTitle: schema.documents.sourceTitle,\n sourceAuthor: schema.documents.sourceAuthor,\n sourceCreatedAt: schema.documents.sourceCreatedAt,\n sourceUpdatedAt: schema.documents.sourceUpdatedAt,\n sourceVersion: schema.documents.sourceVersion,\n aclTags: schema.documents.aclTags,\n distance,\n })\n .from(schema.documentChunks)\n .innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id))\n .where(and(...documentSearchConditions(input, services.embedder.model)))\n .orderBy(distance)\n .limit(limit),\n );\n return rows.map((row) => ({\n ...mapSearchRowBase(row, input.workspaceId),\n vectorScore: 1 / (1 + Number(row.distance)),\n keywordScore: null,\n }));\n}\n\nasync function keywordSearchDocuments(\n db: Database,\n input: DocumentSearchInput,\n limit: number,\n): Promise<CombinedSearchRow[]> {\n const rank = sql<number>`ts_rank_cd(to_tsvector('simple', ${schema.documentChunks.text}), plainto_tsquery('simple', ${input.query}))`;\n const rows = await withWorkspaceRls(\n db,\n input.workspaceId,\n async (scopedDb) =>\n await scopedDb\n .select({\n chunkId: schema.documentChunks.id,\n documentId: schema.documentChunks.documentId,\n baseId: schema.documentChunks.baseId,\n fileId: schema.documentChunks.fileId,\n title: schema.documents.title,\n text: schema.documentChunks.text,\n chunkIndex: schema.documentChunks.chunkIndex,\n metadata: schema.documentChunks.metadata,\n sourceKind: schema.documents.sourceKind,\n sourceUri: schema.documents.sourceUri,\n sourceExternalId: schema.documents.sourceExternalId,\n sourceTitle: schema.documents.sourceTitle,\n sourceAuthor: schema.documents.sourceAuthor,\n sourceCreatedAt: schema.documents.sourceCreatedAt,\n sourceUpdatedAt: schema.documents.sourceUpdatedAt,\n sourceVersion: schema.documents.sourceVersion,\n aclTags: schema.documents.aclTags,\n rank,\n })\n .from(schema.documentChunks)\n .innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id))\n .where(\n and(\n ...documentSearchConditions(input),\n sql`to_tsvector('simple', ${schema.documentChunks.text}) @@ plainto_tsquery('simple', ${input.query})`,\n ),\n )\n .orderBy(desc(rank))\n .limit(limit),\n );\n return rows.map((row) => ({\n ...mapSearchRowBase(row, input.workspaceId),\n vectorScore: null,\n keywordScore: normalizeKeywordScore(Number(row.rank)),\n }));\n}\n\nexport async function getDocumentChunk(\n db: Database,\n workspaceId: string,\n chunkId: string,\n): Promise<DocumentSearchResult | null> {\n const [row] = await withWorkspaceRls(\n db,\n workspaceId,\n async (scopedDb) =>\n await scopedDb\n .select({\n chunkId: schema.documentChunks.id,\n documentId: schema.documentChunks.documentId,\n baseId: schema.documentChunks.baseId,\n fileId: schema.documentChunks.fileId,\n title: schema.documents.title,\n text: schema.documentChunks.text,\n chunkIndex: schema.documentChunks.chunkIndex,\n metadata: schema.documentChunks.metadata,\n sourceKind: schema.documents.sourceKind,\n sourceUri: schema.documents.sourceUri,\n sourceExternalId: schema.documents.sourceExternalId,\n sourceTitle: schema.documents.sourceTitle,\n sourceAuthor: schema.documents.sourceAuthor,\n sourceCreatedAt: schema.documents.sourceCreatedAt,\n sourceUpdatedAt: schema.documents.sourceUpdatedAt,\n sourceVersion: schema.documents.sourceVersion,\n aclTags: schema.documents.aclTags,\n })\n .from(schema.documentChunks)\n .innerJoin(schema.documents, eq(schema.documentChunks.documentId, schema.documents.id))\n .where(\n and(\n eq(schema.documentChunks.workspaceId, workspaceId),\n eq(schema.documentChunks.id, chunkId),\n eq(schema.documents.status, \"ready\"),\n ),\n )\n .limit(1),\n );\n if (!row) return null;\n return {\n ...mapSearchRowBase(row, workspaceId),\n score: 1,\n matchType: \"hybrid\",\n vectorScore: null,\n keywordScore: null,\n };\n}\n\ntype SearchRowBase = Omit<\n DocumentSearchResult,\n \"score\" | \"matchType\" | \"vectorScore\" | \"keywordScore\"\n>;\ntype CombinedSearchRow = SearchRowBase & {\n vectorScore: number | null;\n keywordScore: number | null;\n};\n\nfunction documentSearchConditions(input: DocumentSearchInput, embeddingModel?: string): SQL[] {\n const conditions: SQL[] = [\n eq(schema.documents.status, \"ready\"),\n eq(schema.documentChunks.workspaceId, input.workspaceId),\n ];\n if (embeddingModel) {\n conditions.push(eq(schema.documentChunks.embeddingModel, embeddingModel));\n }\n if (input.baseIds?.length) {\n conditions.push(inArray(schema.documentChunks.baseId, input.baseIds));\n }\n if (input.sourceKinds?.length) {\n conditions.push(inArray(schema.documents.sourceKind, input.sourceKinds));\n }\n const aclTags = cleanStringArray(input.aclTags);\n if (aclTags.length > 0) {\n conditions.push(sql`${schema.documents.aclTags} @> ${JSON.stringify(aclTags)}::jsonb`);\n }\n return conditions;\n}\n\nfunction mapSearchRowBase(\n row: {\n chunkId: string;\n documentId: string;\n baseId: string;\n fileId: string;\n title: string;\n text: string;\n chunkIndex: number;\n metadata: Record<string, unknown>;\n sourceKind: string;\n sourceUri: string | null;\n sourceExternalId: string | null;\n sourceTitle: string | null;\n sourceAuthor: string | null;\n sourceCreatedAt: Date | null;\n sourceUpdatedAt: Date | null;\n sourceVersion: string | null;\n aclTags: string[];\n },\n workspaceId: string,\n): SearchRowBase {\n return {\n chunkId: row.chunkId,\n workspaceId,\n documentId: row.documentId,\n baseId: row.baseId,\n fileId: row.fileId,\n title: row.title,\n text: row.text,\n chunkIndex: row.chunkIndex,\n metadata: row.metadata,\n sourceKind: normalizeKnowledgeSourceKind(row.sourceKind),\n sourceUri: row.sourceUri,\n sourceExternalId: row.sourceExternalId,\n sourceTitle: row.sourceTitle,\n sourceAuthor: row.sourceAuthor,\n sourceCreatedAt: row.sourceCreatedAt?.toISOString() ?? null,\n sourceUpdatedAt: row.sourceUpdatedAt?.toISOString() ?? null,\n sourceVersion: row.sourceVersion,\n aclTags: cleanStringArray(row.aclTags),\n };\n}\n\nfunction mergeDocumentSearchRows(\n rows: CombinedSearchRow[],\n mode: DocumentSearchMode,\n): DocumentSearchResult[] {\n const byChunk = new Map<string, CombinedSearchRow>();\n for (const row of rows) {\n const existing = byChunk.get(row.chunkId);\n if (!existing) {\n byChunk.set(row.chunkId, row);\n continue;\n }\n byChunk.set(row.chunkId, {\n ...existing,\n vectorScore: Math.max(existing.vectorScore ?? 0, row.vectorScore ?? 0) || null,\n keywordScore: Math.max(existing.keywordScore ?? 0, row.keywordScore ?? 0) || null,\n });\n }\n return [...byChunk.values()]\n .map((row) => {\n const vectorScore = row.vectorScore;\n const keywordScore = row.keywordScore;\n const matchType: DocumentSearchMode =\n vectorScore !== null && keywordScore !== null\n ? \"hybrid\"\n : vectorScore !== null\n ? \"vector\"\n : \"keyword\";\n return {\n ...row,\n score: combinedSearchScore(mode, vectorScore, keywordScore, matchType),\n matchType,\n };\n })\n .sort(\n (left, right) =>\n right.score - left.score ||\n (right.vectorScore ?? 0) - (left.vectorScore ?? 0) ||\n (right.keywordScore ?? 0) - (left.keywordScore ?? 0) ||\n left.chunkIndex - right.chunkIndex,\n );\n}\n\nfunction combinedSearchScore(\n mode: DocumentSearchMode,\n vectorScore: number | null,\n keywordScore: number | null,\n matchType: DocumentSearchMode,\n): number {\n const vector = vectorScore ?? 0;\n const keyword = keywordScore ?? 0;\n if (mode === \"vector\") return roundScore(vector);\n if (mode === \"keyword\") return roundScore(keyword);\n return roundScore(\n Math.min(1, 0.65 * vector + 0.35 * keyword + (matchType === \"hybrid\" ? 0.1 : 0)),\n );\n}\n\nfunction normalizeKeywordScore(rank: number): number {\n if (!Number.isFinite(rank) || rank <= 0) {\n return 0;\n }\n return rank / (rank + 1);\n}\n\nfunction roundScore(value: number): number {\n return Number(value.toFixed(6));\n}\n\nexport async function parseDocumentBytes(\n bytes: Uint8Array,\n file: FileAsset,\n parser: DocumentParser = new LiteParseDocumentParser(),\n): Promise<ParsedDocument> {\n return await parser.parse(bytes, file);\n}\n\nexport function chunkText(\n text: string,\n maxChars = DEFAULT_DOCUMENT_CHUNK_SIZE,\n overlapChars = DEFAULT_DOCUMENT_CHUNK_OVERLAP,\n): string[] {\n if (overlapChars >= maxChars) {\n throw new Error(\"chunk overlap must be smaller than chunk size\");\n }\n const normalized = text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/[ \\t]+/g, \" \")\n .trim();\n if (!normalized) return [];\n const paragraphs = normalized\n .split(/\\n{2,}/)\n .map((part) => part.replace(/\\s+/g, \" \").trim())\n .filter(Boolean);\n const chunks: string[] = [];\n let current = \"\";\n for (const paragraph of paragraphs.length > 0 ? paragraphs : [normalized.replace(/\\s+/g, \" \")]) {\n for (const part of splitOversizedText(paragraph, maxChars)) {\n if (!current) {\n current = part;\n } else if (current.length + 1 + part.length <= maxChars) {\n current = `${current} ${part}`;\n } else {\n chunks.push(current);\n current = withOverlap(current, overlapChars, part, maxChars);\n }\n }\n }\n if (current) chunks.push(current);\n return chunks.map((chunk) => chunk.trim()).filter(Boolean);\n}\n\nexport function deterministicEmbedding(\n text: string,\n dimensions = DEFAULT_DOCUMENT_EMBEDDING_DIMENSIONS,\n): number[] {\n const values = new Array(dimensions).fill(0);\n const tokens = text.toLowerCase().match(/[\\p{L}\\p{N}_-]+/gu) ?? [];\n for (const token of tokens) {\n let hash = 2166136261;\n for (const char of token) {\n hash ^= char.codePointAt(0) ?? 0;\n hash = Math.imul(hash, 16777619);\n }\n values[Math.abs(hash) % dimensions] += 1;\n }\n const norm = Math.hypot(...values) || 1;\n return values.map((value) => Number((value / norm).toFixed(6)));\n}\n\nasync function requireReadyFile(\n db: Database,\n workspaceId: string,\n fileId: string,\n): Promise<FileAsset> {\n const file = await requireFile(db, workspaceId, fileId);\n if (file.status !== \"ready\") {\n throw new Error(`File ${fileId} is ${file.status}`);\n }\n return file;\n}\n\nfunction validateEmbedding(values: number[], dimensions: number, model: string): number[] {\n if (values.length !== dimensions) {\n throw new Error(\n `Embedding model ${model} returned ${values.length} dimensions; expected ${dimensions}`,\n );\n }\n if (values.some((value) => !Number.isFinite(value))) {\n throw new Error(`Embedding model ${model} returned non-finite values`);\n }\n return values;\n}\n\nfunction isTextLike(file: FileAsset): boolean {\n const contentType = file.contentType.toLowerCase();\n const filename = file.filename.toLowerCase();\n return (\n contentType.startsWith(\"text/\") ||\n contentType === \"application/json\" ||\n contentType === \"application/xml\" ||\n contentType === \"application/x-yaml\" ||\n filename.endsWith(\".md\") ||\n filename.endsWith(\".markdown\") ||\n filename.endsWith(\".json\") ||\n filename.endsWith(\".yaml\") ||\n filename.endsWith(\".yml\") ||\n filename.endsWith(\".csv\") ||\n filename.endsWith(\".tsv\") ||\n filename.endsWith(\".xml\")\n );\n}\n\nfunction splitOversizedText(text: string, maxChars: number): string[] {\n if (text.length <= maxChars) return [text];\n const out: string[] = [];\n let remaining = text;\n while (remaining.length > maxChars) {\n const window = remaining.slice(0, maxChars + 1);\n const breakAt = Math.max(\n window.lastIndexOf(\". \"),\n window.lastIndexOf(\"? \"),\n window.lastIndexOf(\"! \"),\n window.lastIndexOf(\"; \"),\n window.lastIndexOf(\", \"),\n window.lastIndexOf(\" \"),\n );\n const end = breakAt > Math.floor(maxChars * 0.5) ? breakAt + 1 : maxChars;\n out.push(remaining.slice(0, end).trim());\n remaining = remaining.slice(end).trim();\n }\n if (remaining) out.push(remaining);\n return out;\n}\n\nfunction withOverlap(\n previous: string,\n overlapChars: number,\n next: string,\n maxChars: number,\n): string {\n if (overlapChars <= 0) return next;\n const overlap = previous\n .slice(Math.max(0, previous.length - overlapChars))\n .replace(/^\\S+\\s+/, \"\")\n .trim();\n const candidate = overlap ? `${overlap} ${next}` : next;\n return candidate.length <= maxChars ? candidate : next;\n}\n\nfunction cleanString(value: string | undefined | null): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction cleanStringArray(values: string[] | undefined | null): string[] {\n return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];\n}\n\nfunction parseOptionalDate(value: string | undefined): Date | null {\n const trimmed = cleanString(value);\n if (!trimmed) {\n return null;\n }\n const date = new Date(trimmed);\n if (Number.isNaN(date.getTime())) {\n throw new Error(`Invalid source timestamp: ${trimmed}`);\n }\n return date;\n}\n\nfunction normalizeKnowledgeSourceKind(value: string): KnowledgeSourceKind {\n switch (value) {\n case \"manual_upload\":\n case \"meeting_transcript\":\n case \"repository\":\n case \"email\":\n case \"chat\":\n case \"document\":\n case \"web\":\n case \"other\":\n return value;\n default:\n return \"other\";\n }\n}\n\nfunction vectorLiteral(values: number[]): string {\n return `[${values.join(\",\")}]`;\n}\n\nfunction mapDocumentBase(row: typeof schema.documentBases.$inferSelect): DocumentBase {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n name: row.name,\n description: row.description,\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n\nfunction mapDocument(row: typeof schema.documents.$inferSelect): Document {\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n baseId: row.baseId,\n fileId: row.fileId,\n status: row.status as Document[\"status\"],\n title: row.title,\n parser: row.parser,\n chunkCount: row.chunkCount,\n error: row.error,\n sourceKind: normalizeKnowledgeSourceKind(row.sourceKind),\n sourceUri: row.sourceUri,\n sourceExternalId: row.sourceExternalId,\n sourceTitle: row.sourceTitle,\n sourceAuthor: row.sourceAuthor,\n sourceCreatedAt: row.sourceCreatedAt?.toISOString() ?? null,\n sourceUpdatedAt: row.sourceUpdatedAt?.toISOString() ?? null,\n sourceVersion: row.sourceVersion,\n aclTags: cleanStringArray(row.aclTags),\n createdAt: row.createdAt.toISOString(),\n updatedAt: row.updatedAt.toISOString(),\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,8 +1,17 @@
1
1
  {
2
2
  "name": "@opengeni/documents",
3
- "version": "0.2.8",
4
- "type": "module",
3
+ "version": "0.2.9",
5
4
  "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Cloudgeni-ai/opengeni.git",
8
+ "directory": "packages/documents"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "src"
13
+ ],
14
+ "type": "module",
6
15
  "main": "./dist/index.js",
7
16
  "module": "./dist/index.js",
8
17
  "types": "./dist/index.d.ts",
@@ -12,31 +21,22 @@
12
21
  "import": "./dist/index.js"
13
22
  }
14
23
  },
15
- "files": [
16
- "dist",
17
- "src"
18
- ],
19
24
  "publishConfig": {
20
25
  "access": "public",
21
26
  "provenance": true
22
27
  },
23
28
  "scripts": {
24
29
  "build": "tsup",
25
- "typecheck": "tsc --noEmit",
30
+ "typecheck": "tsgo --noEmit",
26
31
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
27
32
  },
28
33
  "dependencies": {
29
- "@opengeni/config": "^0.4.0",
30
- "@opengeni/contracts": "^0.9.0",
31
- "@opengeni/db": "^0.6.1",
32
- "@opengeni/storage": "^0.2.8",
33
34
  "@llamaindex/liteparse": "^1.5.3",
35
+ "@opengeni/config": "^0.5.0",
36
+ "@opengeni/contracts": "^0.10.0",
37
+ "@opengeni/db": "^0.7.0",
38
+ "@opengeni/storage": "^0.2.9",
34
39
  "drizzle-orm": "^0.45.2",
35
40
  "openai": "6.36.0"
36
- },
37
- "repository": {
38
- "type": "git",
39
- "url": "git+https://github.com/Cloudgeni-ai/opengeni.git",
40
- "directory": "packages/documents"
41
41
  }
42
42
  }