> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alana.shopping/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK TypeScript

> SDK com tipagem completa para a Search API da Alana (Canal 2). Zero dependências, funciona em Node.js, Edge e browser.

## Instalação

```bash theme={null}
npm install @alana-shopping/search-sdk
```

## Quick Start

<CodeGroup>
  ```typescript Node.js theme={null}
  import { AlanaSearchClient } from "@alana-shopping/search-sdk";

  const client = new AlanaSearchClient({ apiKey: "sua-chave-api" });

  const results = await client.search({ query: "tênis de corrida" });
  console.log(results.hits);
  ```

  ```javascript CommonJS theme={null}
  const { AlanaSearchClient } = require("@alana-shopping/search-sdk");

  const client = new AlanaSearchClient({ apiKey: "sua-chave-api" });

  const results = await client.search({ query: "tênis de corrida" });
  console.log(results.hits);
  ```
</CodeGroup>

## Construtor

```typescript theme={null}
const client = new AlanaSearchClient({
  apiKey?: string;    // cabeçalho x-api-key (auth via chave de API)
  m2mToken?: string;  // Bearer token (Auth0 M2M — service-to-service)
  baseUrl?: string;   // Sobrescreve a URL base (padrão: https://app.alana.shopping)
});
```

Se `apiKey` e `m2mToken` forem fornecidos, `m2mToken` tem precedência.

## Métodos

### `search(params)`

Busca full-text de produtos com facetamento, ordenação e personalização.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const { hits, nbHits, page, nbPages, facets } = await client.search({
    query: "tênis de corrida",  // obrigatório
    page: 0,
    hitsPerPage: 20,
    sortBy: "price_asc",
    facets: ["brand", "size"],
    facetFilters: ["brand:Nike"],
    userId: "user-123",
    personalize: true,
  });
  ```

  ```bash cURL equivalente theme={null}
  curl -X POST https://app.alana.shopping/api/v1/search \
    -H "x-api-key: sua-chave-api" \
    -H "Content-Type: application/json" \
    -d '{"query": "tênis de corrida", "page": 0, "hitsPerPage": 20}'
  ```
</CodeGroup>

### `autocomplete(params)`

Sugestões de query com previews de produtos para search-as-you-type.

```typescript theme={null}
const { suggestions, products } = await client.autocomplete({
  query: "tên",
  limit: 5,
  includeProducts: true,
});
```

### `browse(params)`

Listagem de produtos por categoria — sem necessidade de query de texto livre.

```typescript theme={null}
const { hits, nbHits } = await client.browse({
  categoryPath: "calcados/tenis",
  page: 0,
  hitsPerPage: 24,
  sortBy: "price_asc",
  facets: ["brand", "color"],
  facetFilters: [["color:vermelho", "color:azul"]],
});
```

### `recommend(params)`

Recomendações de produtos alimentadas por ML.

```typescript theme={null}
const { hits, model, fallback } = await client.recommend({
  model: "related-products",
  productId: "sku-123",
  userId: "user-456",
  limit: 10,
});
```

**Modelos disponíveis:** `related-products`, `frequently-bought-together`, `trending-items`, `trending-facet-values`, `personalized-trending`, `recently-viewed`, `bought-together`, `visually-similar`

### `trackEvent(params)`

Rastreie interações de usuários para personalização e analytics.

<CodeGroup>
  ```typescript Evento de busca theme={null}
  await client.trackEvent({
    events: [{ type: "search", query: "tênis de corrida", userId: "u1" }],
  });
  ```

  ```typescript Visualização de produto theme={null}
  await client.trackEvent({
    events: [{ type: "detail-page-view", objectID: "sku-123", userId: "u1" }],
  });
  ```

  ```typescript Compra theme={null}
  await client.trackEvent({
    events: [{
      type: "purchase-complete",
      orderID: "ord-789",
      items: [{ objectID: "sku-123", quantity: 1, price: 99.99 }],
      revenue: 99.99,
      currency: "BRL",
      userId: "u1",
    }],
  });
  ```
</CodeGroup>

**Tipos de evento suportados:** `home-page-view`, `search`, `category-view`, `detail-page-view`, `add-to-cart`, `shopping-cart-page-view`, `purchase-complete`

## Tratamento de Erros

```typescript theme={null}
import { AlanaSearchClient, AlanaApiError } from "@alana-shopping/search-sdk";

const client = new AlanaSearchClient({ apiKey: "sua-chave" });

try {
  const results = await client.search({ query: "tênis" });
} catch (err) {
  if (err instanceof AlanaApiError) {
    console.error(`Erro de API ${err.status}:`, err.message);
    // err.body contém o corpo completo da resposta
  } else {
    // Erro de rede, timeout de requisição, etc.
    console.error("Erro de rede:", err);
  }
}
```

## Comportamento de Retry

O SDK faz retry automaticamente:

| Status                     | Comportamento                                                            |
| -------------------------- | ------------------------------------------------------------------------ |
| `429 Too Many Requests`    | Retry usando o valor do cabeçalho `Retry-After` (ou backoff exponencial) |
| `500`, `502`, `503`, `504` | Retry com backoff exponencial                                            |
| `400`, `401`, `403`, `404` | Lança imediatamente — sem retry                                          |
| Erros de rede              | Retry com backoff exponencial                                            |

Sequência de backoff (sem `Retry-After`): 100ms → 400ms → 1600ms (máx 3 tentativas).

## Tipos TypeScript

Todos os parâmetros de requisição e shapes de resposta são totalmente tipados:

```typescript theme={null}
import type {
  SearchParams,
  SearchResponse,
  SearchHit,
  AutocompleteParams,
  AutocompleteResponse,
  BrowseParams,
  BrowseResponse,
  RecommendModel,
  RecommendParams,
  RecommendResponse,
  TrackEventParams,
  TrackEvent,
} from "@alana-shopping/search-sdk";
```

## Pacote

* **npm:** [`@alana-shopping/search-sdk`](https://www.npmjs.com/package/@alana-shopping/search-sdk)
* **Zero dependências em runtime** — usa `fetch` nativo (Node 18+, Edge, browser)
* **ESM + CJS dual** — funciona com `import` e `require`
