118 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { MeiliSearch } from 'meilisearch';
 | 
						|
import { MEILI_HOST, MEILI_API_KEY, VAULT_PATH as CFG_VAULT_PATH } from './config.mjs';
 | 
						|
 | 
						|
const MEILI_KEY = MEILI_API_KEY;
 | 
						|
 | 
						|
console.log('[Meili] Config:', {
 | 
						|
  host: MEILI_HOST,
 | 
						|
  keyLength: MEILI_KEY?.length,
 | 
						|
  keyPreview: MEILI_KEY ? `${MEILI_KEY.slice(0, 8)}...` : 'none'
 | 
						|
});
 | 
						|
 | 
						|
if (!MEILI_KEY) {
 | 
						|
  console.warn('[Meili] No API key provided; running without authentication. Set MEILI_API_KEY or MEILI_MASTER_KEY when securing Meilisearch.');
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Create and return a Meilisearch client instance
 | 
						|
 */
 | 
						|
export function meiliClient() {
 | 
						|
  const options = MEILI_KEY ? { host: MEILI_HOST, apiKey: MEILI_KEY } : { host: MEILI_HOST };
 | 
						|
  console.log('[Meili] Creating client with options:', {
 | 
						|
    host: options.host,
 | 
						|
    hasApiKey: !!options.apiKey,
 | 
						|
    apiKeyLength: options.apiKey?.length,
 | 
						|
    apiKeyHex: options.apiKey ? Buffer.from(options.apiKey).toString('hex') : 'none'
 | 
						|
  });
 | 
						|
  return new MeiliSearch(options);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generate index name from vault path (supports multi-vault)
 | 
						|
 */
 | 
						|
export function vaultIndexName(vaultPath = CFG_VAULT_PATH ?? './vault') {
 | 
						|
  // Simple safe name generation; adjust to hash if paths can collide
 | 
						|
  const safe = vaultPath.replace(/[^a-z0-9]+/gi, '_').toLowerCase();
 | 
						|
  return `notes_${safe}`;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Ensure index exists and configure settings for optimal search
 | 
						|
 */
 | 
						|
export async function ensureIndexSettings(client, indexUid) {
 | 
						|
  // Create the index if it doesn't exist, then fetch it.
 | 
						|
  // Some Meilisearch operations are task-based; we wait for completion to avoid 404s.
 | 
						|
  let index;
 | 
						|
  try {
 | 
						|
    index = await client.getIndex(indexUid);
 | 
						|
  } catch (e) {
 | 
						|
    const task = await client.createIndex(indexUid, { primaryKey: 'id' });
 | 
						|
    if (task?.taskUid !== undefined) {
 | 
						|
      await client.waitForTask(task.taskUid, { timeOutMs: 30_000 });
 | 
						|
    }
 | 
						|
    index = await client.getIndex(indexUid);
 | 
						|
  }
 | 
						|
 | 
						|
  // Configure searchable, filterable, sortable, and faceted attributes
 | 
						|
  const settingsTask = await index.updateSettings({
 | 
						|
    searchableAttributes: [
 | 
						|
      'title',
 | 
						|
      'content',
 | 
						|
      'file',
 | 
						|
      'path',
 | 
						|
      'tags',
 | 
						|
      'properties.*',
 | 
						|
      'headings'
 | 
						|
    ],
 | 
						|
    displayedAttributes: [
 | 
						|
      'id',
 | 
						|
      'title',
 | 
						|
      'path',
 | 
						|
      'file',
 | 
						|
      'tags',
 | 
						|
      'properties',
 | 
						|
      'updatedAt',
 | 
						|
      'createdAt',
 | 
						|
      'excerpt'
 | 
						|
    ],
 | 
						|
    filterableAttributes: [
 | 
						|
      'tags',
 | 
						|
      'file',
 | 
						|
      'path',
 | 
						|
      'parentDirs',
 | 
						|
      'properties.*',
 | 
						|
      'year',
 | 
						|
      'month',
 | 
						|
      'favoris',
 | 
						|
      'template',
 | 
						|
      'task'
 | 
						|
    ],
 | 
						|
    sortableAttributes: [
 | 
						|
      'updatedAt',
 | 
						|
      'createdAt',
 | 
						|
      'title',
 | 
						|
      'file',
 | 
						|
      'path'
 | 
						|
    ],
 | 
						|
    faceting: {
 | 
						|
      maxValuesPerFacet: 1000
 | 
						|
    },
 | 
						|
    typoTolerance: {
 | 
						|
      enabled: true,
 | 
						|
      minWordSizeForTypos: {
 | 
						|
        oneTypo: 3,
 | 
						|
        twoTypos: 6
 | 
						|
      }
 | 
						|
    },
 | 
						|
    pagination: {
 | 
						|
      maxTotalHits: 10000
 | 
						|
    }
 | 
						|
  });
 | 
						|
  if (settingsTask?.taskUid !== undefined) {
 | 
						|
    await client.waitForTask(settingsTask.taskUid, { timeOutMs: 30_000 });
 | 
						|
  }
 | 
						|
 | 
						|
  console.log(`[Meili] Index "${indexUid}" configured successfully`);
 | 
						|
  return index;
 | 
						|
}
 |