@peam-ai/search 0.1.2 → 0.1.3

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.d.mts CHANGED
@@ -63,6 +63,13 @@ declare class SearchEngine {
63
63
  import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void>;
64
64
  }
65
65
 
66
+ type ExportOptions = {
67
+ /**
68
+ * Whether to override existing index data
69
+ * @default false
70
+ */
71
+ override?: boolean;
72
+ };
66
73
  /**
67
74
  * Interface for exporting and importing search indexes
68
75
  */
@@ -75,19 +82,26 @@ interface SearchIndexExporter {
75
82
  /**
76
83
  * Export a search index to storage
77
84
  * @param data The search index data to save
85
+ * @param options Exporter options
78
86
  */
79
- export(data: SearchIndexData): Promise<void>;
87
+ export(data: SearchIndexData, options?: ExportOptions): Promise<void>;
88
+ /**
89
+ * Synchronous export of search index to storage
90
+ * @param data
91
+ * @param options Exporter options
92
+ */
93
+ exportSync?(data: SearchIndexData, options?: ExportOptions): void;
80
94
  }
81
95
 
82
96
  interface FileBasedSearchIndexExporterOptions {
83
- /**
84
- * The directory where the index file is located
85
- */
86
- baseDir: string;
87
97
  /**
88
98
  * The path to the index file relative to baseDir
89
99
  */
90
100
  indexPath: string;
101
+ /**
102
+ * The directory where the index file is located
103
+ */
104
+ baseDir?: string;
91
105
  }
92
106
  /**
93
107
  * File-based implementation of SearchIndexExporter
@@ -101,7 +115,8 @@ declare class FileBasedSearchIndexExporter implements SearchIndexExporter {
101
115
  private getFullPath;
102
116
  private loadData;
103
117
  import(): Promise<SearchIndexData | null>;
104
- export(data: SearchIndexData): Promise<void>;
118
+ export(data: SearchIndexData, options?: ExportOptions): Promise<void>;
119
+ exportSync(data: SearchIndexData, options?: ExportOptions): void;
105
120
  }
106
121
 
107
122
  type SearchExporterConfig = {
package/dist/index.d.ts CHANGED
@@ -63,6 +63,13 @@ declare class SearchEngine {
63
63
  import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void>;
64
64
  }
65
65
 
66
+ type ExportOptions = {
67
+ /**
68
+ * Whether to override existing index data
69
+ * @default false
70
+ */
71
+ override?: boolean;
72
+ };
66
73
  /**
67
74
  * Interface for exporting and importing search indexes
68
75
  */
@@ -75,19 +82,26 @@ interface SearchIndexExporter {
75
82
  /**
76
83
  * Export a search index to storage
77
84
  * @param data The search index data to save
85
+ * @param options Exporter options
78
86
  */
79
- export(data: SearchIndexData): Promise<void>;
87
+ export(data: SearchIndexData, options?: ExportOptions): Promise<void>;
88
+ /**
89
+ * Synchronous export of search index to storage
90
+ * @param data
91
+ * @param options Exporter options
92
+ */
93
+ exportSync?(data: SearchIndexData, options?: ExportOptions): void;
80
94
  }
81
95
 
82
96
  interface FileBasedSearchIndexExporterOptions {
83
- /**
84
- * The directory where the index file is located
85
- */
86
- baseDir: string;
87
97
  /**
88
98
  * The path to the index file relative to baseDir
89
99
  */
90
100
  indexPath: string;
101
+ /**
102
+ * The directory where the index file is located
103
+ */
104
+ baseDir?: string;
91
105
  }
92
106
  /**
93
107
  * File-based implementation of SearchIndexExporter
@@ -101,7 +115,8 @@ declare class FileBasedSearchIndexExporter implements SearchIndexExporter {
101
115
  private getFullPath;
102
116
  private loadData;
103
117
  import(): Promise<SearchIndexData | null>;
104
- export(data: SearchIndexData): Promise<void>;
118
+ export(data: SearchIndexData, options?: ExportOptions): Promise<void>;
119
+ exportSync(data: SearchIndexData, options?: ExportOptions): void;
105
120
  }
106
121
 
107
122
  type SearchExporterConfig = {
package/dist/index.js CHANGED
@@ -311,13 +311,15 @@ function buildSearchIndex(pages) {
311
311
 
312
312
  // src/exporters/FileBasedSearchIndexExporter.ts
313
313
  var import_logger3 = require("@peam-ai/logger");
314
+ var fsSync = __toESM(require("fs"));
314
315
  var fs = __toESM(require("fs/promises"));
315
316
  var path = __toESM(require("path"));
316
317
  var log3 = import_logger3.loggers.search;
317
318
  var FileBasedSearchIndexExporter = class {
318
319
  constructor(options) {
319
320
  this.cachedData = null;
320
- this.baseDir = options.baseDir;
321
+ var _a;
322
+ this.baseDir = (_a = options.baseDir) != null ? _a : process.cwd();
321
323
  this.indexPath = options.indexPath;
322
324
  }
323
325
  getFullPath() {
@@ -355,10 +357,18 @@ var FileBasedSearchIndexExporter = class {
355
357
  return data;
356
358
  });
357
359
  }
358
- export(data) {
359
- return __async(this, null, function* () {
360
+ export(_0) {
361
+ return __async(this, arguments, function* (data, options = { override: true }) {
360
362
  const fullPath = this.getFullPath();
361
363
  try {
364
+ if (!(options == null ? void 0 : options.override)) {
365
+ try {
366
+ yield fs.access(fullPath);
367
+ log3.debug("Search index file already exists and override is false, skipping export:", fullPath);
368
+ return;
369
+ } catch (e) {
370
+ }
371
+ }
362
372
  const dir = path.dirname(fullPath);
363
373
  yield fs.mkdir(dir, { recursive: true });
364
374
  yield fs.writeFile(fullPath, JSON.stringify(data, null, 2), "utf-8");
@@ -369,6 +379,26 @@ var FileBasedSearchIndexExporter = class {
369
379
  }
370
380
  });
371
381
  }
382
+ exportSync(data, options = { override: true }) {
383
+ const fullPath = this.getFullPath();
384
+ try {
385
+ if (!(options == null ? void 0 : options.override)) {
386
+ try {
387
+ fsSync.accessSync(fullPath);
388
+ log3.debug("Search index file already exists and override is false, skipping export:", fullPath);
389
+ return;
390
+ } catch (e) {
391
+ }
392
+ }
393
+ const dir = path.dirname(fullPath);
394
+ fsSync.mkdirSync(dir, { recursive: true });
395
+ fsSync.writeFileSync(fullPath, JSON.stringify(data, null, 2), "utf-8");
396
+ log3.debug("Search index saved to file:", fullPath, "with", data.keys.length, "keys");
397
+ } catch (error) {
398
+ log3.error("Failed to save search index to file:", fullPath, error);
399
+ throw error;
400
+ }
401
+ }
372
402
  };
373
403
 
374
404
  // src/exporters/config.ts
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/searchEngine.ts","../src/textSearch.ts","../src/indexBuilder.ts","../src/exporters/FileBasedSearchIndexExporter.ts","../src/exporters/config.ts"],"sourcesContent":["export { buildSearchIndex, type PageToIndex, type SearchIndexData } from './indexBuilder';\nexport { SearchEngine } from './searchEngine';\nexport { TextSearch } from './textSearch';\n\nexport type { StructuredPageDocumentData } from './types';\n\nexport type { SearchEngineConfig } from './searchEngine';\n\nexport {\n FileBasedSearchIndexExporter,\n createExporterFromConfig,\n type FileBasedSearchIndexExporterOptions,\n type SearchExporterConfig,\n type SearchIndexExporter,\n} from './exporters';\n","import { loggers } from '@peam-ai/logger';\nimport type { StructuredPage } from '@peam-ai/parser';\nimport { TextSearch, type TextSearchOptions } from './textSearch';\nimport type { StructuredPageDocumentData } from './types';\n\nconst log = loggers.search;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface SearchEngineConfig {\n // Reserved for future configuration options\n}\n\nexport class SearchEngine {\n private textSearch: TextSearch;\n private initialized: boolean;\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n constructor(_config?: SearchEngineConfig) {\n this.textSearch = new TextSearch();\n this.initialized = false;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n log.debug('Initializing search engine');\n await this.textSearch.initialize();\n this.initialized = true;\n }\n\n async addPage(path: string, content: StructuredPage): Promise<void> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n const document: StructuredPageDocumentData = {\n id: path,\n path,\n content,\n };\n\n await this.textSearch.addDocument(document);\n log.debug('Page added to search engine:', path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n log.debug('Performing text search:', query);\n return this.textSearch.search(query, options);\n }\n\n count(): number {\n return this.textSearch.count();\n }\n\n getDocument(path: string) {\n return this.textSearch.getDocument(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n return this.textSearch.getAllDocuments(limit);\n }\n\n clear(): void {\n this.textSearch.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n return this.textSearch.export(handler);\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n await this.textSearch.import(handler, keys);\n this.initialized = true;\n log.debug('Search engine initialized from imported data');\n }\n}\n","import { loggers } from '@peam-ai/logger';\nimport { Charset, Document } from 'flexsearch';\nimport type { StructuredPageDocumentData } from './types';\n\nexport interface TextSearchOptions {\n limit?: number;\n offset?: number;\n suggest?: boolean;\n}\n\nconst PEAM_DOCUMENT_IDS_KEY = 'peam.documentIds';\nconst MAX_DOCUMENTS_RETRIEVE = 25;\nconst log = loggers.search;\n\nexport class TextSearch {\n private index: Document<StructuredPageDocumentData>;\n private initialized: boolean;\n private documentIds: Set<string>;\n\n constructor() {\n this.initialized = false;\n this.index = this.getIndex();\n this.documentIds = new Set();\n }\n\n private getIndex() {\n return new Document<StructuredPageDocumentData>({\n worker: false,\n document: {\n id: 'path',\n index: ['content:title', 'content:description', 'content:textContent', 'content:author', 'content:keywords'],\n store: true,\n },\n tokenize: 'forward',\n resolution: 9,\n context: {\n resolution: 3,\n depth: 2,\n bidirectional: true,\n },\n cache: 100,\n encoder: Charset.LatinExtra,\n });\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n log.debug('Text search already initialized');\n return;\n }\n\n this.initialized = true;\n }\n\n async addDocument(document: StructuredPageDocumentData): Promise<void> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n log.debug('Adding document to text search:', document.path);\n\n this.index.add(document);\n this.documentIds.add(document.path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n const limit = options.limit || MAX_DOCUMENTS_RETRIEVE;\n const offset = options.offset || 0;\n\n log.debug('Searching for:', query);\n\n const results = await this.index.search(query, {\n limit: limit + offset,\n suggest: options.suggest,\n enrich: true,\n });\n\n const pathSet = new Set<string>();\n const documents: StructuredPageDocumentData[] = [];\n\n for (const fieldResults of results) {\n if (Array.isArray(fieldResults.result)) {\n for (const result of fieldResults.result) {\n const id = typeof result === 'object' && 'id' in result ? result.id : result;\n const doc = typeof result === 'object' && 'doc' in result ? result.doc : null;\n\n if (!pathSet.has(id as string) && doc) {\n pathSet.add(id as string);\n documents.push(doc);\n }\n }\n }\n }\n\n const pagedResults = documents.slice(offset, offset + limit);\n\n return pagedResults;\n }\n\n count(): number {\n return this.documentIds.size;\n }\n\n getDocument(path: string) {\n return this.index.get(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n const documents: StructuredPageDocumentData[] = [];\n let count = 0;\n limit = limit || MAX_DOCUMENTS_RETRIEVE;\n\n for (const id of this.documentIds) {\n if (count >= limit) {\n break;\n }\n\n const doc = this.index.get(id);\n if (doc) {\n documents.push(doc);\n count++;\n }\n }\n\n log.debug('Retrieved documents from store (limit):', documents.length, limit);\n return documents;\n }\n\n clear(): void {\n this.index.clear();\n this.index = this.getIndex();\n this.documentIds.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n const keys: string[] = [];\n\n await handler(PEAM_DOCUMENT_IDS_KEY, JSON.stringify(Array.from(this.documentIds)));\n keys.push(PEAM_DOCUMENT_IDS_KEY);\n\n await this.index.export(async (key: string, data: string) => {\n keys.push(key);\n await handler(key, data);\n });\n\n log.debug('Exported keys:', keys.length);\n\n return { keys };\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n const documentIdsData = await handler(PEAM_DOCUMENT_IDS_KEY);\n if (documentIdsData) {\n const parsed = typeof documentIdsData === 'string' ? JSON.parse(documentIdsData) : documentIdsData;\n this.documentIds = new Set(parsed);\n }\n\n for (const key of keys) {\n if (key === PEAM_DOCUMENT_IDS_KEY) {\n continue;\n }\n\n try {\n const data = await handler(key);\n if (data) {\n this.index.import(key, data);\n }\n } catch (error) {\n log.error('Error importing key:', key, error);\n }\n }\n\n this.initialized = true;\n log.debug('Import completed with keys:', keys.length);\n }\n}\n","import type { StructuredPage } from '@peam-ai/parser';\nimport { SearchEngine } from './searchEngine';\n\nexport interface PageToIndex {\n path: string;\n structuredPage: StructuredPage;\n}\n\nexport interface SearchIndexData {\n keys: string[];\n data: Record<string, string>;\n}\n\n/**\n * Build a search index from structured pages\n */\nexport async function buildSearchIndex(pages: PageToIndex[]): Promise<SearchIndexData> {\n const searchEngine = new SearchEngine();\n await searchEngine.initialize();\n\n for (const page of pages) {\n await searchEngine.addPage(page.path, page.structuredPage);\n }\n\n const exportedData: Record<string, string> = {};\n const result = await searchEngine.export(async (key, data) => {\n exportedData[key] = data;\n });\n\n return {\n keys: result.keys,\n data: exportedData,\n };\n}\n","import { loggers } from '@peam-ai/logger';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport type { SearchIndexData } from '../indexBuilder';\nimport type { SearchIndexExporter } from './SearchIndexExporter';\n\nconst log = loggers.search;\n\nexport interface FileBasedSearchIndexExporterOptions {\n /**\n * The directory where the index file is located\n */\n baseDir: string;\n\n /**\n * The path to the index file relative to baseDir\n */\n indexPath: string;\n}\n\n/**\n * File-based implementation of SearchIndexExporter\n * Reads and writes search index data to/from a JSON file\n */\nexport class FileBasedSearchIndexExporter implements SearchIndexExporter {\n private baseDir: string;\n private indexPath: string;\n private cachedData: SearchIndexData | null = null;\n\n constructor(options: FileBasedSearchIndexExporterOptions) {\n this.baseDir = options.baseDir;\n this.indexPath = options.indexPath;\n }\n\n private getFullPath(): string {\n return path.join(this.baseDir, this.indexPath);\n }\n\n private async loadData(): Promise<SearchIndexData | null> {\n if (this.cachedData) {\n return this.cachedData;\n }\n\n const fullPath = this.getFullPath();\n\n try {\n const fileContent = await fs.readFile(fullPath, 'utf-8');\n const data = JSON.parse(fileContent) as SearchIndexData;\n\n if (!data || !data.keys || !Array.isArray(data.keys) || !data.data) {\n log.warn('Invalid search index structure in file:', fullPath);\n return null;\n }\n\n if (data.keys.length === 0) {\n log.debug('Search index is empty:', fullPath);\n return null;\n }\n\n this.cachedData = data;\n log.debug('Search index loaded from file:', fullPath, 'with', data.keys.length, 'keys');\n return data;\n } catch (error) {\n log.error('Failed to load search index from file:', fullPath, error);\n return null;\n }\n }\n\n async import(): Promise<SearchIndexData | null> {\n const data = await this.loadData();\n return data;\n }\n\n async export(data: SearchIndexData): Promise<void> {\n const fullPath = this.getFullPath();\n\n try {\n const dir = path.dirname(fullPath);\n await fs.mkdir(dir, { recursive: true });\n\n await fs.writeFile(fullPath, JSON.stringify(data, null, 2), 'utf-8');\n\n log.debug('Search index saved to file:', fullPath, 'with', data.keys.length, 'keys');\n } catch (error) {\n log.error('Failed to save search index to file:', fullPath, error);\n throw error;\n }\n }\n}\n","import { FileBasedSearchIndexExporter, FileBasedSearchIndexExporterOptions } from './FileBasedSearchIndexExporter';\nimport { SearchIndexExporter } from './SearchIndexExporter';\n\nexport type SearchExporterConfig = {\n type: 'fileBased';\n config: FileBasedSearchIndexExporterOptions;\n};\n\n/**\n * Creates a SearchIndexExporter instance from a SearchExporterConfig\n */\nexport function createExporterFromConfig(exporterConfig: SearchExporterConfig): SearchIndexExporter {\n if (exporterConfig.type === 'fileBased') {\n return new FileBasedSearchIndexExporter({\n ...exporterConfig.config,\n });\n }\n\n throw new Error(`Unknown exporter type: ${exporterConfig.type}`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,iBAAwB;;;ACAxB,oBAAwB;AACxB,wBAAkC;AASlC,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,MAAM,sBAAQ;AAEb,IAAM,aAAN,MAAiB;AAAA,EAKtB,cAAc;AACZ,SAAK,cAAc;AACnB,SAAK,QAAQ,KAAK,SAAS;AAC3B,SAAK,cAAc,oBAAI,IAAI;AAAA,EAC7B;AAAA,EAEQ,WAAW;AACjB,WAAO,IAAI,2BAAqC;AAAA,MAC9C,QAAQ;AAAA,MACR,UAAU;AAAA,QACR,IAAI;AAAA,QACJ,OAAO,CAAC,iBAAiB,uBAAuB,uBAAuB,kBAAkB,kBAAkB;AAAA,QAC3G,OAAO;AAAA,MACT;AAAA,MACA,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,SAAS;AAAA,QACP,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,eAAe;AAAA,MACjB;AAAA,MACA,OAAO;AAAA,MACP,SAAS,0BAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEM,aAA4B;AAAA;AAChC,UAAI,KAAK,aAAa;AACpB,YAAI,MAAM,iCAAiC;AAC3C;AAAA,MACF;AAEA,WAAK,cAAc;AAAA,IACrB;AAAA;AAAA,EAEM,YAAY,UAAqD;AAAA;AACrE,UAAI,CAAC,KAAK,aAAa;AACrB,cAAM,IAAI,MAAM,sDAAsD;AAAA,MACxE;AAEA,UAAI,MAAM,mCAAmC,SAAS,IAAI;AAE1D,WAAK,MAAM,IAAI,QAAQ;AACvB,WAAK,YAAY,IAAI,SAAS,IAAI;AAAA,IACpC;AAAA;AAAA,EAEM,OAAO,IAAuF;AAAA,+CAAvF,OAAe,UAA6B,CAAC,GAA0C;AAClG,UAAI,CAAC,KAAK,aAAa;AACrB,cAAM,IAAI,MAAM,sDAAsD;AAAA,MACxE;AAEA,YAAM,QAAQ,QAAQ,SAAS;AAC/B,YAAM,SAAS,QAAQ,UAAU;AAEjC,UAAI,MAAM,kBAAkB,KAAK;AAEjC,YAAM,UAAU,MAAM,KAAK,MAAM,OAAO,OAAO;AAAA,QAC7C,OAAO,QAAQ;AAAA,QACf,SAAS,QAAQ;AAAA,QACjB,QAAQ;AAAA,MACV,CAAC;AAED,YAAM,UAAU,oBAAI,IAAY;AAChC,YAAM,YAA0C,CAAC;AAEjD,iBAAW,gBAAgB,SAAS;AAClC,YAAI,MAAM,QAAQ,aAAa,MAAM,GAAG;AACtC,qBAAW,UAAU,aAAa,QAAQ;AACxC,kBAAM,KAAK,OAAO,WAAW,YAAY,QAAQ,SAAS,OAAO,KAAK;AACtE,kBAAM,MAAM,OAAO,WAAW,YAAY,SAAS,SAAS,OAAO,MAAM;AAEzE,gBAAI,CAAC,QAAQ,IAAI,EAAY,KAAK,KAAK;AACrC,sBAAQ,IAAI,EAAY;AACxB,wBAAU,KAAK,GAAG;AAAA,YACpB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,eAAe,UAAU,MAAM,QAAQ,SAAS,KAAK;AAE3D,aAAO;AAAA,IACT;AAAA;AAAA,EAEA,QAAgB;AACd,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEA,YAAYC,OAAc;AACxB,WAAO,KAAK,MAAM,IAAIA,KAAI;AAAA,EAC5B;AAAA,EAEA,gBAAgB,OAA8C;AAC5D,UAAM,YAA0C,CAAC;AACjD,QAAI,QAAQ;AACZ,YAAQ,SAAS;AAEjB,eAAW,MAAM,KAAK,aAAa;AACjC,UAAI,SAAS,OAAO;AAClB;AAAA,MACF;AAEA,YAAM,MAAM,KAAK,MAAM,IAAI,EAAE;AAC7B,UAAI,KAAK;AACP,kBAAU,KAAK,GAAG;AAClB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,2CAA2C,UAAU,QAAQ,KAAK;AAC5E,WAAO;AAAA,EACT;AAAA,EAEA,QAAc;AACZ,SAAK,MAAM,MAAM;AACjB,SAAK,QAAQ,KAAK,SAAS;AAC3B,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA,EAEM,OAAO,SAAoF;AAAA;AAC/F,YAAM,OAAiB,CAAC;AAExB,YAAM,QAAQ,uBAAuB,KAAK,UAAU,MAAM,KAAK,KAAK,WAAW,CAAC,CAAC;AACjF,WAAK,KAAK,qBAAqB;AAE/B,YAAM,KAAK,MAAM,OAAO,CAAO,KAAa,SAAiB;AAC3D,aAAK,KAAK,GAAG;AACb,cAAM,QAAQ,KAAK,IAAI;AAAA,MACzB,EAAC;AAED,UAAI,MAAM,kBAAkB,KAAK,MAAM;AAEvC,aAAO,EAAE,KAAK;AAAA,IAChB;AAAA;AAAA,EAEM,OAAO,SAA2C,MAA+B;AAAA;AACrF,YAAM,kBAAkB,MAAM,QAAQ,qBAAqB;AAC3D,UAAI,iBAAiB;AACnB,cAAM,SAAS,OAAO,oBAAoB,WAAW,KAAK,MAAM,eAAe,IAAI;AACnF,aAAK,cAAc,IAAI,IAAI,MAAM;AAAA,MACnC;AAEA,iBAAW,OAAO,MAAM;AACtB,YAAI,QAAQ,uBAAuB;AACjC;AAAA,QACF;AAEA,YAAI;AACF,gBAAM,OAAO,MAAM,QAAQ,GAAG;AAC9B,cAAI,MAAM;AACR,iBAAK,MAAM,OAAO,KAAK,IAAI;AAAA,UAC7B;AAAA,QACF,SAAS,OAAO;AACd,cAAI,MAAM,wBAAwB,KAAK,KAAK;AAAA,QAC9C;AAAA,MACF;AAEA,WAAK,cAAc;AACnB,UAAI,MAAM,+BAA+B,KAAK,MAAM;AAAA,IACtD;AAAA;AACF;;;AD9KA,IAAMC,OAAM,uBAAQ;AAOb,IAAM,eAAN,MAAmB;AAAA;AAAA,EAKxB,YAAY,SAA8B;AACxC,SAAK,aAAa,IAAI,WAAW;AACjC,SAAK,cAAc;AAAA,EACrB;AAAA,EAEM,aAA4B;AAAA;AAChC,UAAI,KAAK,aAAa;AACpB;AAAA,MACF;AAEA,MAAAA,KAAI,MAAM,4BAA4B;AACtC,YAAM,KAAK,WAAW,WAAW;AACjC,WAAK,cAAc;AAAA,IACrB;AAAA;AAAA,EAEM,QAAQC,OAAc,SAAwC;AAAA;AAClE,UAAI,CAAC,KAAK,aAAa;AACrB,cAAM,IAAI,MAAM,yDAAyD;AAAA,MAC3E;AAEA,YAAM,WAAuC;AAAA,QAC3C,IAAIA;AAAA,QACJ,MAAAA;AAAA,QACA;AAAA,MACF;AAEA,YAAM,KAAK,WAAW,YAAY,QAAQ;AAC1C,MAAAD,KAAI,MAAM,gCAAgCC,KAAI;AAAA,IAChD;AAAA;AAAA,EAEM,OAAO,IAAuF;AAAA,+CAAvF,OAAe,UAA6B,CAAC,GAA0C;AAClG,UAAI,CAAC,KAAK,aAAa;AACrB,cAAM,IAAI,MAAM,yDAAyD;AAAA,MAC3E;AAEA,MAAAD,KAAI,MAAM,2BAA2B,KAAK;AAC1C,aAAO,KAAK,WAAW,OAAO,OAAO,OAAO;AAAA,IAC9C;AAAA;AAAA,EAEA,QAAgB;AACd,WAAO,KAAK,WAAW,MAAM;AAAA,EAC/B;AAAA,EAEA,YAAYC,OAAc;AACxB,WAAO,KAAK,WAAW,YAAYA,KAAI;AAAA,EACzC;AAAA,EAEA,gBAAgB,OAA8C;AAC5D,WAAO,KAAK,WAAW,gBAAgB,KAAK;AAAA,EAC9C;AAAA,EAEA,QAAc;AACZ,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA,EAEM,OAAO,SAAoF;AAAA;AAC/F,aAAO,KAAK,WAAW,OAAO,OAAO;AAAA,IACvC;AAAA;AAAA,EAEM,OAAO,SAA2C,MAA+B;AAAA;AACrF,YAAM,KAAK,WAAW,OAAO,SAAS,IAAI;AAC1C,WAAK,cAAc;AACnB,MAAAD,KAAI,MAAM,8CAA8C;AAAA,IAC1D;AAAA;AACF;;;AEjEA,SAAsB,iBAAiB,OAAgD;AAAA;AACrF,UAAM,eAAe,IAAI,aAAa;AACtC,UAAM,aAAa,WAAW;AAE9B,eAAW,QAAQ,OAAO;AACxB,YAAM,aAAa,QAAQ,KAAK,MAAM,KAAK,cAAc;AAAA,IAC3D;AAEA,UAAM,eAAuC,CAAC;AAC9C,UAAM,SAAS,MAAM,aAAa,OAAO,CAAO,KAAK,SAAS;AAC5D,mBAAa,GAAG,IAAI;AAAA,IACtB,EAAC;AAED,WAAO;AAAA,MACL,MAAM,OAAO;AAAA,MACb,MAAM;AAAA,IACR;AAAA,EACF;AAAA;;;ACjCA,IAAAE,iBAAwB;AACxB,SAAoB;AACpB,WAAsB;AAItB,IAAMC,OAAM,uBAAQ;AAkBb,IAAM,+BAAN,MAAkE;AAAA,EAKvE,YAAY,SAA8C;AAF1D,SAAQ,aAAqC;AAG3C,SAAK,UAAU,QAAQ;AACvB,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA,EAEQ,cAAsB;AAC5B,WAAY,UAAK,KAAK,SAAS,KAAK,SAAS;AAAA,EAC/C;AAAA,EAEc,WAA4C;AAAA;AACxD,UAAI,KAAK,YAAY;AACnB,eAAO,KAAK;AAAA,MACd;AAEA,YAAM,WAAW,KAAK,YAAY;AAElC,UAAI;AACF,cAAM,cAAc,MAAS,YAAS,UAAU,OAAO;AACvD,cAAM,OAAO,KAAK,MAAM,WAAW;AAEnC,YAAI,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAAI,KAAK,CAAC,KAAK,MAAM;AAClE,UAAAA,KAAI,KAAK,2CAA2C,QAAQ;AAC5D,iBAAO;AAAA,QACT;AAEA,YAAI,KAAK,KAAK,WAAW,GAAG;AAC1B,UAAAA,KAAI,MAAM,0BAA0B,QAAQ;AAC5C,iBAAO;AAAA,QACT;AAEA,aAAK,aAAa;AAClB,QAAAA,KAAI,MAAM,kCAAkC,UAAU,QAAQ,KAAK,KAAK,QAAQ,MAAM;AACtF,eAAO;AAAA,MACT,SAAS,OAAO;AACd,QAAAA,KAAI,MAAM,0CAA0C,UAAU,KAAK;AACnE,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA,EAEM,SAA0C;AAAA;AAC9C,YAAM,OAAO,MAAM,KAAK,SAAS;AACjC,aAAO;AAAA,IACT;AAAA;AAAA,EAEM,OAAO,MAAsC;AAAA;AACjD,YAAM,WAAW,KAAK,YAAY;AAElC,UAAI;AACF,cAAM,MAAW,aAAQ,QAAQ;AACjC,cAAS,SAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAEvC,cAAS,aAAU,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAEnE,QAAAA,KAAI,MAAM,+BAA+B,UAAU,QAAQ,KAAK,KAAK,QAAQ,MAAM;AAAA,MACrF,SAAS,OAAO;AACd,QAAAA,KAAI,MAAM,wCAAwC,UAAU,KAAK;AACjE,cAAM;AAAA,MACR;AAAA,IACF;AAAA;AACF;;;AC7EO,SAAS,yBAAyB,gBAA2D;AAClG,MAAI,eAAe,SAAS,aAAa;AACvC,WAAO,IAAI,6BAA6B,mBACnC,eAAe,OACnB;AAAA,EACH;AAEA,QAAM,IAAI,MAAM,0BAA0B,eAAe,IAAI,EAAE;AACjE;","names":["import_logger","path","log","path","import_logger","log"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/searchEngine.ts","../src/textSearch.ts","../src/indexBuilder.ts","../src/exporters/FileBasedSearchIndexExporter.ts","../src/exporters/config.ts"],"sourcesContent":["export { buildSearchIndex, type PageToIndex, type SearchIndexData } from './indexBuilder';\nexport { SearchEngine } from './searchEngine';\nexport { TextSearch } from './textSearch';\n\nexport type { StructuredPageDocumentData } from './types';\n\nexport type { SearchEngineConfig } from './searchEngine';\n\nexport {\n FileBasedSearchIndexExporter,\n createExporterFromConfig,\n type FileBasedSearchIndexExporterOptions,\n type SearchExporterConfig,\n type SearchIndexExporter,\n} from './exporters';\n","import { loggers } from '@peam-ai/logger';\nimport type { StructuredPage } from '@peam-ai/parser';\nimport { TextSearch, type TextSearchOptions } from './textSearch';\nimport type { StructuredPageDocumentData } from './types';\n\nconst log = loggers.search;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface SearchEngineConfig {\n // Reserved for future configuration options\n}\n\nexport class SearchEngine {\n private textSearch: TextSearch;\n private initialized: boolean;\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n constructor(_config?: SearchEngineConfig) {\n this.textSearch = new TextSearch();\n this.initialized = false;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n log.debug('Initializing search engine');\n await this.textSearch.initialize();\n this.initialized = true;\n }\n\n async addPage(path: string, content: StructuredPage): Promise<void> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n const document: StructuredPageDocumentData = {\n id: path,\n path,\n content,\n };\n\n await this.textSearch.addDocument(document);\n log.debug('Page added to search engine:', path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n log.debug('Performing text search:', query);\n return this.textSearch.search(query, options);\n }\n\n count(): number {\n return this.textSearch.count();\n }\n\n getDocument(path: string) {\n return this.textSearch.getDocument(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n return this.textSearch.getAllDocuments(limit);\n }\n\n clear(): void {\n this.textSearch.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n return this.textSearch.export(handler);\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n await this.textSearch.import(handler, keys);\n this.initialized = true;\n log.debug('Search engine initialized from imported data');\n }\n}\n","import { loggers } from '@peam-ai/logger';\nimport { Charset, Document } from 'flexsearch';\nimport type { StructuredPageDocumentData } from './types';\n\nexport interface TextSearchOptions {\n limit?: number;\n offset?: number;\n suggest?: boolean;\n}\n\nconst PEAM_DOCUMENT_IDS_KEY = 'peam.documentIds';\nconst MAX_DOCUMENTS_RETRIEVE = 25;\nconst log = loggers.search;\n\nexport class TextSearch {\n private index: Document<StructuredPageDocumentData>;\n private initialized: boolean;\n private documentIds: Set<string>;\n\n constructor() {\n this.initialized = false;\n this.index = this.getIndex();\n this.documentIds = new Set();\n }\n\n private getIndex() {\n return new Document<StructuredPageDocumentData>({\n worker: false,\n document: {\n id: 'path',\n index: ['content:title', 'content:description', 'content:textContent', 'content:author', 'content:keywords'],\n store: true,\n },\n tokenize: 'forward',\n resolution: 9,\n context: {\n resolution: 3,\n depth: 2,\n bidirectional: true,\n },\n cache: 100,\n encoder: Charset.LatinExtra,\n });\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n log.debug('Text search already initialized');\n return;\n }\n\n this.initialized = true;\n }\n\n async addDocument(document: StructuredPageDocumentData): Promise<void> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n log.debug('Adding document to text search:', document.path);\n\n this.index.add(document);\n this.documentIds.add(document.path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n const limit = options.limit || MAX_DOCUMENTS_RETRIEVE;\n const offset = options.offset || 0;\n\n log.debug('Searching for:', query);\n\n const results = await this.index.search(query, {\n limit: limit + offset,\n suggest: options.suggest,\n enrich: true,\n });\n\n const pathSet = new Set<string>();\n const documents: StructuredPageDocumentData[] = [];\n\n for (const fieldResults of results) {\n if (Array.isArray(fieldResults.result)) {\n for (const result of fieldResults.result) {\n const id = typeof result === 'object' && 'id' in result ? result.id : result;\n const doc = typeof result === 'object' && 'doc' in result ? result.doc : null;\n\n if (!pathSet.has(id as string) && doc) {\n pathSet.add(id as string);\n documents.push(doc);\n }\n }\n }\n }\n\n const pagedResults = documents.slice(offset, offset + limit);\n\n return pagedResults;\n }\n\n count(): number {\n return this.documentIds.size;\n }\n\n getDocument(path: string) {\n return this.index.get(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n const documents: StructuredPageDocumentData[] = [];\n let count = 0;\n limit = limit || MAX_DOCUMENTS_RETRIEVE;\n\n for (const id of this.documentIds) {\n if (count >= limit) {\n break;\n }\n\n const doc = this.index.get(id);\n if (doc) {\n documents.push(doc);\n count++;\n }\n }\n\n log.debug('Retrieved documents from store (limit):', documents.length, limit);\n return documents;\n }\n\n clear(): void {\n this.index.clear();\n this.index = this.getIndex();\n this.documentIds.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n const keys: string[] = [];\n\n await handler(PEAM_DOCUMENT_IDS_KEY, JSON.stringify(Array.from(this.documentIds)));\n keys.push(PEAM_DOCUMENT_IDS_KEY);\n\n await this.index.export(async (key: string, data: string) => {\n keys.push(key);\n await handler(key, data);\n });\n\n log.debug('Exported keys:', keys.length);\n\n return { keys };\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n const documentIdsData = await handler(PEAM_DOCUMENT_IDS_KEY);\n if (documentIdsData) {\n const parsed = typeof documentIdsData === 'string' ? JSON.parse(documentIdsData) : documentIdsData;\n this.documentIds = new Set(parsed);\n }\n\n for (const key of keys) {\n if (key === PEAM_DOCUMENT_IDS_KEY) {\n continue;\n }\n\n try {\n const data = await handler(key);\n if (data) {\n this.index.import(key, data);\n }\n } catch (error) {\n log.error('Error importing key:', key, error);\n }\n }\n\n this.initialized = true;\n log.debug('Import completed with keys:', keys.length);\n }\n}\n","import type { StructuredPage } from '@peam-ai/parser';\nimport { SearchEngine } from './searchEngine';\n\nexport interface PageToIndex {\n path: string;\n structuredPage: StructuredPage;\n}\n\nexport interface SearchIndexData {\n keys: string[];\n data: Record<string, string>;\n}\n\n/**\n * Build a search index from structured pages\n */\nexport async function buildSearchIndex(pages: PageToIndex[]): Promise<SearchIndexData> {\n const searchEngine = new SearchEngine();\n await searchEngine.initialize();\n\n for (const page of pages) {\n await searchEngine.addPage(page.path, page.structuredPage);\n }\n\n const exportedData: Record<string, string> = {};\n const result = await searchEngine.export(async (key, data) => {\n exportedData[key] = data;\n });\n\n return {\n keys: result.keys,\n data: exportedData,\n };\n}\n","import { loggers } from '@peam-ai/logger';\nimport * as fsSync from 'fs';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport type { SearchIndexData } from '../indexBuilder';\nimport type { ExportOptions, SearchIndexExporter } from './SearchIndexExporter';\n\nconst log = loggers.search;\n\nexport interface FileBasedSearchIndexExporterOptions {\n /**\n * The path to the index file relative to baseDir\n */\n indexPath: string;\n\n /**\n * The directory where the index file is located\n */\n baseDir?: string;\n}\n\n/**\n * File-based implementation of SearchIndexExporter\n * Reads and writes search index data to/from a JSON file\n */\nexport class FileBasedSearchIndexExporter implements SearchIndexExporter {\n private baseDir: string;\n private indexPath: string;\n private cachedData: SearchIndexData | null = null;\n\n constructor(options: FileBasedSearchIndexExporterOptions) {\n this.baseDir = options.baseDir ?? process.cwd();\n this.indexPath = options.indexPath;\n }\n\n private getFullPath(): string {\n return path.join(this.baseDir, this.indexPath);\n }\n\n private async loadData(): Promise<SearchIndexData | null> {\n if (this.cachedData) {\n return this.cachedData;\n }\n\n const fullPath = this.getFullPath();\n\n try {\n const fileContent = await fs.readFile(fullPath, 'utf-8');\n const data = JSON.parse(fileContent) as SearchIndexData;\n\n if (!data || !data.keys || !Array.isArray(data.keys) || !data.data) {\n log.warn('Invalid search index structure in file:', fullPath);\n return null;\n }\n\n if (data.keys.length === 0) {\n log.debug('Search index is empty:', fullPath);\n return null;\n }\n\n this.cachedData = data;\n log.debug('Search index loaded from file:', fullPath, 'with', data.keys.length, 'keys');\n return data;\n } catch (error) {\n log.error('Failed to load search index from file:', fullPath, error);\n return null;\n }\n }\n\n async import(): Promise<SearchIndexData | null> {\n const data = await this.loadData();\n return data;\n }\n\n async export(data: SearchIndexData, options: ExportOptions = { override: true }): Promise<void> {\n const fullPath = this.getFullPath();\n\n try {\n if (!options?.override) {\n try {\n await fs.access(fullPath);\n log.debug('Search index file already exists and override is false, skipping export:', fullPath);\n return;\n } catch {\n // noop\n }\n }\n\n const dir = path.dirname(fullPath);\n await fs.mkdir(dir, { recursive: true });\n\n await fs.writeFile(fullPath, JSON.stringify(data, null, 2), 'utf-8');\n\n log.debug('Search index saved to file:', fullPath, 'with', data.keys.length, 'keys');\n } catch (error) {\n log.error('Failed to save search index to file:', fullPath, error);\n throw error;\n }\n }\n\n exportSync(data: SearchIndexData, options: ExportOptions = { override: true }): void {\n const fullPath = this.getFullPath();\n\n try {\n if (!options?.override) {\n try {\n fsSync.accessSync(fullPath);\n log.debug('Search index file already exists and override is false, skipping export:', fullPath);\n return;\n } catch {\n // noop\n }\n }\n\n const dir = path.dirname(fullPath);\n fsSync.mkdirSync(dir, { recursive: true });\n\n fsSync.writeFileSync(fullPath, JSON.stringify(data, null, 2), 'utf-8');\n\n log.debug('Search index saved to file:', fullPath, 'with', data.keys.length, 'keys');\n } catch (error) {\n log.error('Failed to save search index to file:', fullPath, error);\n throw error;\n }\n }\n}\n","import { FileBasedSearchIndexExporter, FileBasedSearchIndexExporterOptions } from './FileBasedSearchIndexExporter';\nimport { SearchIndexExporter } from './SearchIndexExporter';\n\nexport type SearchExporterConfig = {\n type: 'fileBased';\n config: FileBasedSearchIndexExporterOptions;\n};\n\n/**\n * Creates a SearchIndexExporter instance from a SearchExporterConfig\n */\nexport function createExporterFromConfig(exporterConfig: SearchExporterConfig): SearchIndexExporter {\n if (exporterConfig.type === 'fileBased') {\n return new FileBasedSearchIndexExporter({\n ...exporterConfig.config,\n });\n }\n\n throw new Error(`Unknown exporter type: ${exporterConfig.type}`);\n}\n"],"mappings":"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","names":["import_logger","path","log","path","import_logger","log"]}
package/dist/index.mjs CHANGED
@@ -274,13 +274,15 @@ function buildSearchIndex(pages) {
274
274
 
275
275
  // src/exporters/FileBasedSearchIndexExporter.ts
276
276
  import { loggers as loggers3 } from "@peam-ai/logger";
277
+ import * as fsSync from "fs";
277
278
  import * as fs from "fs/promises";
278
279
  import * as path from "path";
279
280
  var log3 = loggers3.search;
280
281
  var FileBasedSearchIndexExporter = class {
281
282
  constructor(options) {
282
283
  this.cachedData = null;
283
- this.baseDir = options.baseDir;
284
+ var _a;
285
+ this.baseDir = (_a = options.baseDir) != null ? _a : process.cwd();
284
286
  this.indexPath = options.indexPath;
285
287
  }
286
288
  getFullPath() {
@@ -318,10 +320,18 @@ var FileBasedSearchIndexExporter = class {
318
320
  return data;
319
321
  });
320
322
  }
321
- export(data) {
322
- return __async(this, null, function* () {
323
+ export(_0) {
324
+ return __async(this, arguments, function* (data, options = { override: true }) {
323
325
  const fullPath = this.getFullPath();
324
326
  try {
327
+ if (!(options == null ? void 0 : options.override)) {
328
+ try {
329
+ yield fs.access(fullPath);
330
+ log3.debug("Search index file already exists and override is false, skipping export:", fullPath);
331
+ return;
332
+ } catch (e) {
333
+ }
334
+ }
325
335
  const dir = path.dirname(fullPath);
326
336
  yield fs.mkdir(dir, { recursive: true });
327
337
  yield fs.writeFile(fullPath, JSON.stringify(data, null, 2), "utf-8");
@@ -332,6 +342,26 @@ var FileBasedSearchIndexExporter = class {
332
342
  }
333
343
  });
334
344
  }
345
+ exportSync(data, options = { override: true }) {
346
+ const fullPath = this.getFullPath();
347
+ try {
348
+ if (!(options == null ? void 0 : options.override)) {
349
+ try {
350
+ fsSync.accessSync(fullPath);
351
+ log3.debug("Search index file already exists and override is false, skipping export:", fullPath);
352
+ return;
353
+ } catch (e) {
354
+ }
355
+ }
356
+ const dir = path.dirname(fullPath);
357
+ fsSync.mkdirSync(dir, { recursive: true });
358
+ fsSync.writeFileSync(fullPath, JSON.stringify(data, null, 2), "utf-8");
359
+ log3.debug("Search index saved to file:", fullPath, "with", data.keys.length, "keys");
360
+ } catch (error) {
361
+ log3.error("Failed to save search index to file:", fullPath, error);
362
+ throw error;
363
+ }
364
+ }
335
365
  };
336
366
 
337
367
  // src/exporters/config.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/searchEngine.ts","../src/textSearch.ts","../src/indexBuilder.ts","../src/exporters/FileBasedSearchIndexExporter.ts","../src/exporters/config.ts"],"sourcesContent":["import { loggers } from '@peam-ai/logger';\nimport type { StructuredPage } from '@peam-ai/parser';\nimport { TextSearch, type TextSearchOptions } from './textSearch';\nimport type { StructuredPageDocumentData } from './types';\n\nconst log = loggers.search;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface SearchEngineConfig {\n // Reserved for future configuration options\n}\n\nexport class SearchEngine {\n private textSearch: TextSearch;\n private initialized: boolean;\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n constructor(_config?: SearchEngineConfig) {\n this.textSearch = new TextSearch();\n this.initialized = false;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n log.debug('Initializing search engine');\n await this.textSearch.initialize();\n this.initialized = true;\n }\n\n async addPage(path: string, content: StructuredPage): Promise<void> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n const document: StructuredPageDocumentData = {\n id: path,\n path,\n content,\n };\n\n await this.textSearch.addDocument(document);\n log.debug('Page added to search engine:', path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n log.debug('Performing text search:', query);\n return this.textSearch.search(query, options);\n }\n\n count(): number {\n return this.textSearch.count();\n }\n\n getDocument(path: string) {\n return this.textSearch.getDocument(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n return this.textSearch.getAllDocuments(limit);\n }\n\n clear(): void {\n this.textSearch.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n return this.textSearch.export(handler);\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n await this.textSearch.import(handler, keys);\n this.initialized = true;\n log.debug('Search engine initialized from imported data');\n }\n}\n","import { loggers } from '@peam-ai/logger';\nimport { Charset, Document } from 'flexsearch';\nimport type { StructuredPageDocumentData } from './types';\n\nexport interface TextSearchOptions {\n limit?: number;\n offset?: number;\n suggest?: boolean;\n}\n\nconst PEAM_DOCUMENT_IDS_KEY = 'peam.documentIds';\nconst MAX_DOCUMENTS_RETRIEVE = 25;\nconst log = loggers.search;\n\nexport class TextSearch {\n private index: Document<StructuredPageDocumentData>;\n private initialized: boolean;\n private documentIds: Set<string>;\n\n constructor() {\n this.initialized = false;\n this.index = this.getIndex();\n this.documentIds = new Set();\n }\n\n private getIndex() {\n return new Document<StructuredPageDocumentData>({\n worker: false,\n document: {\n id: 'path',\n index: ['content:title', 'content:description', 'content:textContent', 'content:author', 'content:keywords'],\n store: true,\n },\n tokenize: 'forward',\n resolution: 9,\n context: {\n resolution: 3,\n depth: 2,\n bidirectional: true,\n },\n cache: 100,\n encoder: Charset.LatinExtra,\n });\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n log.debug('Text search already initialized');\n return;\n }\n\n this.initialized = true;\n }\n\n async addDocument(document: StructuredPageDocumentData): Promise<void> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n log.debug('Adding document to text search:', document.path);\n\n this.index.add(document);\n this.documentIds.add(document.path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n const limit = options.limit || MAX_DOCUMENTS_RETRIEVE;\n const offset = options.offset || 0;\n\n log.debug('Searching for:', query);\n\n const results = await this.index.search(query, {\n limit: limit + offset,\n suggest: options.suggest,\n enrich: true,\n });\n\n const pathSet = new Set<string>();\n const documents: StructuredPageDocumentData[] = [];\n\n for (const fieldResults of results) {\n if (Array.isArray(fieldResults.result)) {\n for (const result of fieldResults.result) {\n const id = typeof result === 'object' && 'id' in result ? result.id : result;\n const doc = typeof result === 'object' && 'doc' in result ? result.doc : null;\n\n if (!pathSet.has(id as string) && doc) {\n pathSet.add(id as string);\n documents.push(doc);\n }\n }\n }\n }\n\n const pagedResults = documents.slice(offset, offset + limit);\n\n return pagedResults;\n }\n\n count(): number {\n return this.documentIds.size;\n }\n\n getDocument(path: string) {\n return this.index.get(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n const documents: StructuredPageDocumentData[] = [];\n let count = 0;\n limit = limit || MAX_DOCUMENTS_RETRIEVE;\n\n for (const id of this.documentIds) {\n if (count >= limit) {\n break;\n }\n\n const doc = this.index.get(id);\n if (doc) {\n documents.push(doc);\n count++;\n }\n }\n\n log.debug('Retrieved documents from store (limit):', documents.length, limit);\n return documents;\n }\n\n clear(): void {\n this.index.clear();\n this.index = this.getIndex();\n this.documentIds.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n const keys: string[] = [];\n\n await handler(PEAM_DOCUMENT_IDS_KEY, JSON.stringify(Array.from(this.documentIds)));\n keys.push(PEAM_DOCUMENT_IDS_KEY);\n\n await this.index.export(async (key: string, data: string) => {\n keys.push(key);\n await handler(key, data);\n });\n\n log.debug('Exported keys:', keys.length);\n\n return { keys };\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n const documentIdsData = await handler(PEAM_DOCUMENT_IDS_KEY);\n if (documentIdsData) {\n const parsed = typeof documentIdsData === 'string' ? JSON.parse(documentIdsData) : documentIdsData;\n this.documentIds = new Set(parsed);\n }\n\n for (const key of keys) {\n if (key === PEAM_DOCUMENT_IDS_KEY) {\n continue;\n }\n\n try {\n const data = await handler(key);\n if (data) {\n this.index.import(key, data);\n }\n } catch (error) {\n log.error('Error importing key:', key, error);\n }\n }\n\n this.initialized = true;\n log.debug('Import completed with keys:', keys.length);\n }\n}\n","import type { StructuredPage } from '@peam-ai/parser';\nimport { SearchEngine } from './searchEngine';\n\nexport interface PageToIndex {\n path: string;\n structuredPage: StructuredPage;\n}\n\nexport interface SearchIndexData {\n keys: string[];\n data: Record<string, string>;\n}\n\n/**\n * Build a search index from structured pages\n */\nexport async function buildSearchIndex(pages: PageToIndex[]): Promise<SearchIndexData> {\n const searchEngine = new SearchEngine();\n await searchEngine.initialize();\n\n for (const page of pages) {\n await searchEngine.addPage(page.path, page.structuredPage);\n }\n\n const exportedData: Record<string, string> = {};\n const result = await searchEngine.export(async (key, data) => {\n exportedData[key] = data;\n });\n\n return {\n keys: result.keys,\n data: exportedData,\n };\n}\n","import { loggers } from '@peam-ai/logger';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport type { SearchIndexData } from '../indexBuilder';\nimport type { SearchIndexExporter } from './SearchIndexExporter';\n\nconst log = loggers.search;\n\nexport interface FileBasedSearchIndexExporterOptions {\n /**\n * The directory where the index file is located\n */\n baseDir: string;\n\n /**\n * The path to the index file relative to baseDir\n */\n indexPath: string;\n}\n\n/**\n * File-based implementation of SearchIndexExporter\n * Reads and writes search index data to/from a JSON file\n */\nexport class FileBasedSearchIndexExporter implements SearchIndexExporter {\n private baseDir: string;\n private indexPath: string;\n private cachedData: SearchIndexData | null = null;\n\n constructor(options: FileBasedSearchIndexExporterOptions) {\n this.baseDir = options.baseDir;\n this.indexPath = options.indexPath;\n }\n\n private getFullPath(): string {\n return path.join(this.baseDir, this.indexPath);\n }\n\n private async loadData(): Promise<SearchIndexData | null> {\n if (this.cachedData) {\n return this.cachedData;\n }\n\n const fullPath = this.getFullPath();\n\n try {\n const fileContent = await fs.readFile(fullPath, 'utf-8');\n const data = JSON.parse(fileContent) as SearchIndexData;\n\n if (!data || !data.keys || !Array.isArray(data.keys) || !data.data) {\n log.warn('Invalid search index structure in file:', fullPath);\n return null;\n }\n\n if (data.keys.length === 0) {\n log.debug('Search index is empty:', fullPath);\n return null;\n }\n\n this.cachedData = data;\n log.debug('Search index loaded from file:', fullPath, 'with', data.keys.length, 'keys');\n return data;\n } catch (error) {\n log.error('Failed to load search index from file:', fullPath, error);\n return null;\n }\n }\n\n async import(): Promise<SearchIndexData | null> {\n const data = await this.loadData();\n return data;\n }\n\n async export(data: SearchIndexData): Promise<void> {\n const fullPath = this.getFullPath();\n\n try {\n const dir = path.dirname(fullPath);\n await fs.mkdir(dir, { recursive: true });\n\n await fs.writeFile(fullPath, JSON.stringify(data, null, 2), 'utf-8');\n\n log.debug('Search index saved to file:', fullPath, 'with', data.keys.length, 'keys');\n } catch (error) {\n log.error('Failed to save search index to file:', fullPath, error);\n throw error;\n }\n }\n}\n","import { FileBasedSearchIndexExporter, FileBasedSearchIndexExporterOptions } from './FileBasedSearchIndexExporter';\nimport { SearchIndexExporter } from './SearchIndexExporter';\n\nexport type SearchExporterConfig = {\n type: 'fileBased';\n config: FileBasedSearchIndexExporterOptions;\n};\n\n/**\n * Creates a SearchIndexExporter instance from a SearchExporterConfig\n */\nexport function createExporterFromConfig(exporterConfig: SearchExporterConfig): SearchIndexExporter {\n if (exporterConfig.type === 'fileBased') {\n return new FileBasedSearchIndexExporter({\n ...exporterConfig.config,\n });\n }\n\n throw new Error(`Unknown exporter type: ${exporterConfig.type}`);\n}\n"],"mappings":"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","names":["loggers","path","log","loggers","path","loggers","log","loggers"]}
1
+ {"version":3,"sources":["../src/searchEngine.ts","../src/textSearch.ts","../src/indexBuilder.ts","../src/exporters/FileBasedSearchIndexExporter.ts","../src/exporters/config.ts"],"sourcesContent":["import { loggers } from '@peam-ai/logger';\nimport type { StructuredPage } from '@peam-ai/parser';\nimport { TextSearch, type TextSearchOptions } from './textSearch';\nimport type { StructuredPageDocumentData } from './types';\n\nconst log = loggers.search;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface SearchEngineConfig {\n // Reserved for future configuration options\n}\n\nexport class SearchEngine {\n private textSearch: TextSearch;\n private initialized: boolean;\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n constructor(_config?: SearchEngineConfig) {\n this.textSearch = new TextSearch();\n this.initialized = false;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n log.debug('Initializing search engine');\n await this.textSearch.initialize();\n this.initialized = true;\n }\n\n async addPage(path: string, content: StructuredPage): Promise<void> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n const document: StructuredPageDocumentData = {\n id: path,\n path,\n content,\n };\n\n await this.textSearch.addDocument(document);\n log.debug('Page added to search engine:', path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('Search engine not initialized. Call initialize() first.');\n }\n\n log.debug('Performing text search:', query);\n return this.textSearch.search(query, options);\n }\n\n count(): number {\n return this.textSearch.count();\n }\n\n getDocument(path: string) {\n return this.textSearch.getDocument(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n return this.textSearch.getAllDocuments(limit);\n }\n\n clear(): void {\n this.textSearch.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n return this.textSearch.export(handler);\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n await this.textSearch.import(handler, keys);\n this.initialized = true;\n log.debug('Search engine initialized from imported data');\n }\n}\n","import { loggers } from '@peam-ai/logger';\nimport { Charset, Document } from 'flexsearch';\nimport type { StructuredPageDocumentData } from './types';\n\nexport interface TextSearchOptions {\n limit?: number;\n offset?: number;\n suggest?: boolean;\n}\n\nconst PEAM_DOCUMENT_IDS_KEY = 'peam.documentIds';\nconst MAX_DOCUMENTS_RETRIEVE = 25;\nconst log = loggers.search;\n\nexport class TextSearch {\n private index: Document<StructuredPageDocumentData>;\n private initialized: boolean;\n private documentIds: Set<string>;\n\n constructor() {\n this.initialized = false;\n this.index = this.getIndex();\n this.documentIds = new Set();\n }\n\n private getIndex() {\n return new Document<StructuredPageDocumentData>({\n worker: false,\n document: {\n id: 'path',\n index: ['content:title', 'content:description', 'content:textContent', 'content:author', 'content:keywords'],\n store: true,\n },\n tokenize: 'forward',\n resolution: 9,\n context: {\n resolution: 3,\n depth: 2,\n bidirectional: true,\n },\n cache: 100,\n encoder: Charset.LatinExtra,\n });\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n log.debug('Text search already initialized');\n return;\n }\n\n this.initialized = true;\n }\n\n async addDocument(document: StructuredPageDocumentData): Promise<void> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n log.debug('Adding document to text search:', document.path);\n\n this.index.add(document);\n this.documentIds.add(document.path);\n }\n\n async search(query: string, options: TextSearchOptions = {}): Promise<StructuredPageDocumentData[]> {\n if (!this.initialized) {\n throw new Error('TextSearch not initialized. Call initialize() first.');\n }\n\n const limit = options.limit || MAX_DOCUMENTS_RETRIEVE;\n const offset = options.offset || 0;\n\n log.debug('Searching for:', query);\n\n const results = await this.index.search(query, {\n limit: limit + offset,\n suggest: options.suggest,\n enrich: true,\n });\n\n const pathSet = new Set<string>();\n const documents: StructuredPageDocumentData[] = [];\n\n for (const fieldResults of results) {\n if (Array.isArray(fieldResults.result)) {\n for (const result of fieldResults.result) {\n const id = typeof result === 'object' && 'id' in result ? result.id : result;\n const doc = typeof result === 'object' && 'doc' in result ? result.doc : null;\n\n if (!pathSet.has(id as string) && doc) {\n pathSet.add(id as string);\n documents.push(doc);\n }\n }\n }\n }\n\n const pagedResults = documents.slice(offset, offset + limit);\n\n return pagedResults;\n }\n\n count(): number {\n return this.documentIds.size;\n }\n\n getDocument(path: string) {\n return this.index.get(path);\n }\n\n getAllDocuments(limit?: number): StructuredPageDocumentData[] {\n const documents: StructuredPageDocumentData[] = [];\n let count = 0;\n limit = limit || MAX_DOCUMENTS_RETRIEVE;\n\n for (const id of this.documentIds) {\n if (count >= limit) {\n break;\n }\n\n const doc = this.index.get(id);\n if (doc) {\n documents.push(doc);\n count++;\n }\n }\n\n log.debug('Retrieved documents from store (limit):', documents.length, limit);\n return documents;\n }\n\n clear(): void {\n this.index.clear();\n this.index = this.getIndex();\n this.documentIds.clear();\n }\n\n async export(handler: (key: string, data: string) => Promise<void>): Promise<{ keys: string[] }> {\n const keys: string[] = [];\n\n await handler(PEAM_DOCUMENT_IDS_KEY, JSON.stringify(Array.from(this.documentIds)));\n keys.push(PEAM_DOCUMENT_IDS_KEY);\n\n await this.index.export(async (key: string, data: string) => {\n keys.push(key);\n await handler(key, data);\n });\n\n log.debug('Exported keys:', keys.length);\n\n return { keys };\n }\n\n async import(handler: (key: string) => Promise<string>, keys: string[]): Promise<void> {\n const documentIdsData = await handler(PEAM_DOCUMENT_IDS_KEY);\n if (documentIdsData) {\n const parsed = typeof documentIdsData === 'string' ? JSON.parse(documentIdsData) : documentIdsData;\n this.documentIds = new Set(parsed);\n }\n\n for (const key of keys) {\n if (key === PEAM_DOCUMENT_IDS_KEY) {\n continue;\n }\n\n try {\n const data = await handler(key);\n if (data) {\n this.index.import(key, data);\n }\n } catch (error) {\n log.error('Error importing key:', key, error);\n }\n }\n\n this.initialized = true;\n log.debug('Import completed with keys:', keys.length);\n }\n}\n","import type { StructuredPage } from '@peam-ai/parser';\nimport { SearchEngine } from './searchEngine';\n\nexport interface PageToIndex {\n path: string;\n structuredPage: StructuredPage;\n}\n\nexport interface SearchIndexData {\n keys: string[];\n data: Record<string, string>;\n}\n\n/**\n * Build a search index from structured pages\n */\nexport async function buildSearchIndex(pages: PageToIndex[]): Promise<SearchIndexData> {\n const searchEngine = new SearchEngine();\n await searchEngine.initialize();\n\n for (const page of pages) {\n await searchEngine.addPage(page.path, page.structuredPage);\n }\n\n const exportedData: Record<string, string> = {};\n const result = await searchEngine.export(async (key, data) => {\n exportedData[key] = data;\n });\n\n return {\n keys: result.keys,\n data: exportedData,\n };\n}\n","import { loggers } from '@peam-ai/logger';\nimport * as fsSync from 'fs';\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\nimport type { SearchIndexData } from '../indexBuilder';\nimport type { ExportOptions, SearchIndexExporter } from './SearchIndexExporter';\n\nconst log = loggers.search;\n\nexport interface FileBasedSearchIndexExporterOptions {\n /**\n * The path to the index file relative to baseDir\n */\n indexPath: string;\n\n /**\n * The directory where the index file is located\n */\n baseDir?: string;\n}\n\n/**\n * File-based implementation of SearchIndexExporter\n * Reads and writes search index data to/from a JSON file\n */\nexport class FileBasedSearchIndexExporter implements SearchIndexExporter {\n private baseDir: string;\n private indexPath: string;\n private cachedData: SearchIndexData | null = null;\n\n constructor(options: FileBasedSearchIndexExporterOptions) {\n this.baseDir = options.baseDir ?? process.cwd();\n this.indexPath = options.indexPath;\n }\n\n private getFullPath(): string {\n return path.join(this.baseDir, this.indexPath);\n }\n\n private async loadData(): Promise<SearchIndexData | null> {\n if (this.cachedData) {\n return this.cachedData;\n }\n\n const fullPath = this.getFullPath();\n\n try {\n const fileContent = await fs.readFile(fullPath, 'utf-8');\n const data = JSON.parse(fileContent) as SearchIndexData;\n\n if (!data || !data.keys || !Array.isArray(data.keys) || !data.data) {\n log.warn('Invalid search index structure in file:', fullPath);\n return null;\n }\n\n if (data.keys.length === 0) {\n log.debug('Search index is empty:', fullPath);\n return null;\n }\n\n this.cachedData = data;\n log.debug('Search index loaded from file:', fullPath, 'with', data.keys.length, 'keys');\n return data;\n } catch (error) {\n log.error('Failed to load search index from file:', fullPath, error);\n return null;\n }\n }\n\n async import(): Promise<SearchIndexData | null> {\n const data = await this.loadData();\n return data;\n }\n\n async export(data: SearchIndexData, options: ExportOptions = { override: true }): Promise<void> {\n const fullPath = this.getFullPath();\n\n try {\n if (!options?.override) {\n try {\n await fs.access(fullPath);\n log.debug('Search index file already exists and override is false, skipping export:', fullPath);\n return;\n } catch {\n // noop\n }\n }\n\n const dir = path.dirname(fullPath);\n await fs.mkdir(dir, { recursive: true });\n\n await fs.writeFile(fullPath, JSON.stringify(data, null, 2), 'utf-8');\n\n log.debug('Search index saved to file:', fullPath, 'with', data.keys.length, 'keys');\n } catch (error) {\n log.error('Failed to save search index to file:', fullPath, error);\n throw error;\n }\n }\n\n exportSync(data: SearchIndexData, options: ExportOptions = { override: true }): void {\n const fullPath = this.getFullPath();\n\n try {\n if (!options?.override) {\n try {\n fsSync.accessSync(fullPath);\n log.debug('Search index file already exists and override is false, skipping export:', fullPath);\n return;\n } catch {\n // noop\n }\n }\n\n const dir = path.dirname(fullPath);\n fsSync.mkdirSync(dir, { recursive: true });\n\n fsSync.writeFileSync(fullPath, JSON.stringify(data, null, 2), 'utf-8');\n\n log.debug('Search index saved to file:', fullPath, 'with', data.keys.length, 'keys');\n } catch (error) {\n log.error('Failed to save search index to file:', fullPath, error);\n throw error;\n }\n }\n}\n","import { FileBasedSearchIndexExporter, FileBasedSearchIndexExporterOptions } from './FileBasedSearchIndexExporter';\nimport { SearchIndexExporter } from './SearchIndexExporter';\n\nexport type SearchExporterConfig = {\n type: 'fileBased';\n config: FileBasedSearchIndexExporterOptions;\n};\n\n/**\n * Creates a SearchIndexExporter instance from a SearchExporterConfig\n */\nexport function createExporterFromConfig(exporterConfig: SearchExporterConfig): SearchIndexExporter {\n if (exporterConfig.type === 'fileBased') {\n return new FileBasedSearchIndexExporter({\n ...exporterConfig.config,\n });\n }\n\n throw new Error(`Unknown exporter type: ${exporterConfig.type}`);\n}\n"],"mappings":"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","names":["loggers","path","log","loggers","path","loggers","log","loggers"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peam-ai/search",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Vector database and search functionality for Peam",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "flexsearch": "^0.8.212",
32
- "@peam-ai/logger": "0.1.2",
33
- "@peam-ai/parser": "0.1.2"
32
+ "@peam-ai/logger": "0.1.3",
33
+ "@peam-ai/parser": "0.1.3"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^22.10.2",