AACsearch
Начало работы

Поиск в коде (SDK)

Встройте поиск в приложение с помощью JavaScript.

Если вам нужен кастомный поиск (не виджет), используйте SDK.

Что это?

SDK — это набор функций на JavaScript для поиска. Вы вызываете функции и получаете результаты.

Это нужно, если:

  • Вам нужен кастомный дизайн поиска
  • Вы делаете мобильное приложение
  • Вы интегрируете в свою систему

Установка

npm install @aacsearch/search-client

Или если у вас в package.json:

"@aacsearch/search-client": "latest"

Простой поиск

import { SearchClient } from '@aacsearch/search-client';

const client = new SearchClient({
  apiKey: 'ss_search_xxx',
  baseUrl: 'https://api.aacsearch.com'
});

// Выполнить поиск
const results = await client.search({
  indexSlug: 'товары',
  q: 'красная рубашка',
  limit: 10
});

console.log(results.documents); // массив товаров
console.log(results.total); // всего товаров найдено

React компонент

import { useSearch } from '@aacsearch/search-client/react';

export function SearchComponent() {
  const [query, setQuery] = useState('');
  const { results, loading } = useSearch({
    apiKey: 'ss_search_xxx',
    indexSlug: 'товары',
    query
  });

  return (
    <div>
      <input 
        value={query} 
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Найти товар..."
      />
      
      {loading && <p>Загрузка...</p>}
      
      <div>
        {results.map(doc => (
          <div key={doc.id}>
            <h3>{doc.title}</h3>
            <p>{doc.description}</p>
            <p>₽ {doc.price}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

С фильтрами

const results = await client.search({
  indexSlug: 'товары',
  q: 'рубашка',
  filters: {
    price: { min: 1000, max: 3000 },
    brand: 'Nike'
  }
});

Сортировка

const results = await client.search({
  indexSlug: 'товары',
  q: 'рубашка',
  sort: 'price_asc' // или 'price_desc', 'relevance'
});

Автозаполнение (подсказки)

const suggestions = await client.suggest({
  indexSlug: 'товары',
  q: 'кра', // пользователь печатает "кра"
  limit: 5
});

// Возвращает:
// ['красная рубашка', 'краска', 'крайние сроки']

Обработка ошибок

try {
  const results = await client.search({
    indexSlug: 'товары',
    q: 'рубашка'
  });
} catch (error) {
  if (error.code === 'auth_failed') {
    console.log('Ключ неверный или истёк');
  } else if (error.code === 'rate_limited') {
    console.log('Много запросов. Подождите 60 секунд');
  } else {
    console.log('Ошибка:', error.message);
  }
}

Аналитика

SDK автоматически отправляет статистику:

  • Какие товары кликают
  • Какие запросы не дали результатов
  • Сколько времени занял поиск

Всё это видно в панели управления.

Документация

Полную документацию смотрите в GitHub репозитории: https://github.com/aacsearch/search-client

Там же примеры для:

  • Vue.js
  • Angular
  • Svelte
  • Next.js
  • Python
  • Java

Установка

SDK является пакетом воркспейса. В внешних проектах (после публикации):

npm install @aacsearch/search-client
# или: yarn add @aacsearch/search-client

Внутри монорепозитория:

{
	"dependencies": {
		"@repo/search-client": "workspace:*"
	}
}

Инициализация клиента

import { AacSearchClient } from "@repo/search-client";

const client = new AacSearchClient({
	baseUrl: "https://your-app.com", // ваш эндпоинт AACsearch
	apiKey: "ss_search_your_key", // ключ только для поиска
	indexSlug: "products", // индекс по умолчанию
});

Базовый поиск

const results = await client.search({
	q: "wireless headphones",
	queryBy: "title,description,brand",
	page: 1,
	perPage: 20,
});

// results.hits: массив совпадающих документов
// results.found: общее количество
// results.facetCounts: значения фасетов (если запрошены)

Поиск с фильтрами

const results = await client.search({
	q: "headphones",
	queryBy: "title,brand",
	filterBy: "availability:=in_stock && price:<200",
	sortBy: "price:asc",
	facetBy: "brand,categories",
	page: 1,
	perPage: 20,
});

Синтаксис фильтров соответствует синтаксису фильтров AACSearch.

Мульти-поиск

Мульти-поиск выполняет несколько запросов за один HTTP-вызов. Полезен для автодополнения (один запрос на тип подсказки) и федеративного поиска по различным наборам результатов.

const [productResults, categoryResults] = await client.multiSearch([
	{
		indexSlug: "products",
		q: "shoes",
		queryBy: "title,brand",
		perPage: 5,
	},
	{
		indexSlug: "categories",
		q: "shoes",
		queryBy: "name",
		perPage: 3,
	},
]);

Использование ограниченных токенов

Для ограничений на уровне пользователя (например, показывать только товары в наличии), генерируйте ограниченный токен на стороне сервера и передавайте его клиенту:

// Сервер: генерация ограниченного токена (например, в Server Action или API route Next.js)
const scopedToken = await orpc.search.createScopedToken.call({
	organizationId: session.organizationId,
	indexSlug: "products",
	scopedFilter: "availability:=in_stock",
	expiresInSeconds: 3600,
});

// Клиент: используйте ограниченный токен как API-ключ
const client = new AacSearchClient({
	baseUrl: process.env.NEXT_PUBLIC_API_URL,
	apiKey: scopedToken,
	indexSlug: "products",
});

Ограниченный фильтр объединяется через AND с любыми фильтрами клиента. Он не может быть удалён вызывающей стороной.

Шаблон автодополнения

Для отзывчивого поиска по мере ввода текста используйте дебаунсинг запросов и мульти-поиск:

import { useDeferredValue, useEffect, useState } from "react";

function useSearch(query: string) {
	const deferredQuery = useDeferredValue(query);
	const [results, setResults] = useState(null);

	useEffect(() => {
		if (!deferredQuery.trim()) return;

		client
			.search({
				q: deferredQuery,
				queryBy: "title,sku",
				perPage: 5,
				highlightFields: "title",
			})
			.then(setResults);
	}, [deferredQuery]);

	return results;
}

Обработка ошибок

SDK выбрасывает типизированные ошибки из каталога ошибок:

import { AacSearchError } from "@repo/search-client";

try {
	const results = await client.search({ q: "test" });
} catch (err) {
	if (err instanceof AacSearchError) {
		switch (err.code) {
			case "unauthorized": // недействительный или истёкший ключ
			case "quota_exceeded": // достигнут лимит плана
			case "rate_limit": // слишком много запросов
			case "search_failed": // ошибка AACSearch на стороне сервера
			case "index_not_found": // неверный indexSlug
		}
	}
}

Сырые сообщения об ошибках AACSearch никогда не пересылаются клиентам — они сопоставляются с типизированными кодами на стороне сервера.

Интеграции с фреймворками

Next.js App Router

// app/search/page.tsx — Server Component
import { AacSearchClient } from "@repo/search-client";

const client = new AacSearchClient({
  baseUrl: process.env.NEXT_PUBLIC_API_URL!,
  apiKey: process.env.SEARCH_API_KEY!,  // ключ только для поиска из переменной окружения
  indexSlug: "products",
});

export default async function SearchPage({ searchParams }: { searchParams: { q?: string } }) {
  const results = await client.search({ q: searchParams.q ?? "" });
  return <ResultsList results={results} />;
}

Клиентский React-компонент

"use client";
import { useQuery } from "@tanstack/react-query";

function SearchResults({ query }: { query: string }) {
  const { data, isLoading } = useQuery({
    queryKey: ["search", query],
    queryFn: () => client.search({ q: query, perPage: 20 }),
    enabled: query.length > 1,
  });

  if (isLoading) return <Skeleton />;
  return <ResultsList results={data} />;
}

On this page