Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions docs/codedocs/api-reference/search-cloudflare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: "Search (Cloudflare Workers)"
description: "API reference for the Cloudflare Workers Search client entry point."
---

The Cloudflare entry point exports `Search` and `ClientConfig`. It expects credentials to be provided explicitly and sets platform telemetry to `cloudflare` by default.

**Source**: `src/platforms/cloudflare.ts`

## Constructor
```ts
new Search(config: ClientConfig)
```

### ClientConfig
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| url | `string \| undefined` | — | REST URL for Upstash Search. Required in Cloudflare Workers. |
| token | `string \| undefined` | — | REST token for Upstash Search. Required in Cloudflare Workers. |
| enableTelemetry | `boolean \| undefined` | `true` | When `false`, telemetry headers are not sent. |
| retry | `false \| { retries?: number; backoff?: (retryCount: number) => number }` | default retries/backoff | Controls retry behavior for network errors. |
| cache | `"default" \| "force-cache" \| "no-cache" \| "no-store" \| "only-if-cached" \| "reload" \| false \| undefined` | Fetch default | Controls Fetch API cache behavior. |

## Static factory
```ts
Search.fromEnv(
env?: { UPSTASH_SEARCH_REST_URL: string; UPSTASH_SEARCH_REST_TOKEN: string },
config?: Omit<ClientConfig, "url" | "token">
): Search
```

This helper mirrors the Node.js API but is often used with Worker `env` bindings instead of `process.env`.

## Methods
### index
```ts
index<TContent extends Dict = Dict, TIndexMetadata extends Dict = Dict>(indexName: string): SearchIndex<TContent, TIndexMetadata>
```
Creates a `SearchIndex` scoped to the provided index name.

### listIndexes
```ts
listIndexes(): Promise<string[]>
```
Returns a list of index names (namespaces) available in the database.

### info
```ts
info(): Promise<{
diskSize: number;
pendingDocumentCount: number;
documentCount: number;
indexes: Record<string, { pendingDocumentCount: number; documentCount: number }>;
}>
```
Returns storage and document counts for the entire database and per index.

## Usage example (Cloudflare Workers)
```ts worker.ts
import { Search } from "@upstash/search/cloudflare";

export default {
async fetch(request: Request, env: { UPSTASH_SEARCH_REST_URL: string; UPSTASH_SEARCH_REST_TOKEN: string }) {
const client = new Search({
url: env.UPSTASH_SEARCH_REST_URL,
token: env.UPSTASH_SEARCH_REST_TOKEN,
});

const index = client.index<{ text: string }>("notes");
const results = await index.search({ query: "hello", limit: 3 });

return new Response(JSON.stringify(results), { headers: { "Content-Type": "application/json" } });
},
};
```

**Related**: [SearchIndex](./search-index), [Types](../types)
142 changes: 142 additions & 0 deletions docs/codedocs/api-reference/search-index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
title: "SearchIndex"
description: "API reference for index-level operations like upsert, search, fetch, and range."
---

`SearchIndex` is created by calling `Search.index(name)`. It scopes all document operations to a single index (namespace).

**Source**: `src/search-index.ts`

## Constructor
```ts
new SearchIndex<TContent, TIndexMetadata>(httpClient, vectorIndex, indexName)
```

You typically do not instantiate this class directly. Use `Search.index()` instead.

## Methods
### upsert
```ts
upsert(
params: UpsertParameters<TContent, TIndexMetadata> | UpsertParameters<TContent, TIndexMetadata>[]
): Promise<string>
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| params | `UpsertParameters<TContent, TIndexMetadata>` \| `UpsertParameters<TContent, TIndexMetadata>[]` | — | Single document or array of documents with `id`, `content`, and optional `metadata`. |

Returns a string status from the REST API.

```ts index.ts
await index.upsert({ id: "doc-1", content: { title: "Hello" } });
```

### search
```ts
search(params: {
query: string;
limit?: number;
filter?: string | TreeNode<TContent, TIndexMetadata>;
reranking?: boolean;
semanticWeight?: number;
inputEnrichment?: boolean;
keepOriginalQueryAfterEnrichment?: boolean;
}): Promise<SearchResult<TContent, TIndexMetadata>>
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| query | string | — | Search query text. |
| limit | number \| undefined | `5` | Maximum number of results. |
| filter | string \| `TreeNode<TContent, TIndexMetadata>` \| undefined | — | Filter expression or typed filter tree. |
| reranking | boolean \| undefined | `false` | Enable reranking for higher‑quality results. |
| semanticWeight | number \| undefined | `0.75` | Balance between semantic and full‑text relevance (0–1). |
| inputEnrichment | boolean \| undefined | `true` | Enable query enrichment. |
| keepOriginalQueryAfterEnrichment | boolean \| undefined | `false` | Keep original query alongside enriched query. |

```ts index.ts
const results = await index.search({
query: "edge runtime",
limit: 5,
reranking: true,
filter: { AND: [{ category: { equals: "docs" } }] },
});
```

### fetch
```ts
fetch(params: Parameters<VectorIndex["fetch"]>[0]): Promise<(Document<TContent, TIndexMetadata> | null)[]>
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| params | `Parameters<VectorIndex["fetch"]>[0]` | — | Fetch options from `@upstash/vector` (e.g., `{ ids: string[] }`). |

```ts index.ts
const docs = await index.fetch({ ids: ["doc-1", "doc-2"] });
```

### delete
```ts
delete(params: Parameters<VectorIndex["delete"]>[0]): Promise<{ deleted: number }>
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| params | `Parameters<VectorIndex["delete"]>[0]` | — | Delete options from `@upstash/vector` (e.g., `{ ids: string[] }`). |

```ts index.ts
await index.delete({ ids: ["doc-1"] });
```

### range
```ts
range(params: { cursor: string; limit: number; prefix?: string }): Promise<{ nextCursor: string; documents: Document<TContent, TIndexMetadata>[] }>
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| cursor | string | — | Cursor string for pagination. Use "0" to start. |
| limit | number | — | Max documents to return. |
| prefix | string \| undefined | — | Only return IDs with this prefix. |

```ts index.ts
const { nextCursor, documents } = await index.range({ cursor: "0", limit: 20, prefix: "doc_" });
```

### reset
```ts
reset(): Promise<{ success: boolean }>
```

Clears all documents in the index.

```ts index.ts
await index.reset();
```

### deleteIndex
```ts
deleteIndex(): Promise<{ success: boolean }>
```

Deletes the entire index and all documents.

```ts index.ts
await index.deleteIndex();
```

### info
```ts
info(): Promise<{ pendingDocumentCount: number; documentCount: number }>
```

Returns document counts for the index.

```ts index.ts
const info = await index.info();
console.log(info.documentCount);
```

**Related**: [Search (Node.js)](./search-nodejs), [Filters](../filters)
72 changes: 72 additions & 0 deletions docs/codedocs/api-reference/search-nodejs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: "Search (Node.js)"
description: "API reference for the Node.js Search client entry point."
---

The Node.js entry point exports `Search` and `ClientConfig`. It reads credentials from environment variables by default and injects runtime telemetry headers unless disabled.

**Source**: `src/platforms/nodejs.ts`

## Constructor
```ts
new Search(config: ClientConfig)
```

### ClientConfig
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| url | `string \| undefined` | — | REST URL for Upstash Search. If omitted, the client checks `NEXT_PUBLIC_UPSTASH_SEARCH_REST_URL` and `UPSTASH_SEARCH_REST_URL`. |
| token | `string \| undefined` | — | REST token for Upstash Search. If omitted, the client checks `NEXT_PUBLIC_UPSTASH_SEARCH_REST_TOKEN` and `UPSTASH_SEARCH_REST_TOKEN`. |
| enableTelemetry | `boolean \| undefined` | `true` | When `false`, telemetry headers are not sent. Disabled automatically if `UPSTASH_DISABLE_TELEMETRY` is set. |
| retry | `false \| { retries?: number; backoff?: (retryCount: number) => number }` | default retries/backoff | Controls retry behavior for network errors. |
| cache | `"default" \| "force-cache" \| "no-cache" \| "no-store" \| "only-if-cached" \| "reload" \| false \| undefined` | `"no-store"` | Controls Fetch API cache behavior. |

## Static factory
```ts
Search.fromEnv(
env?: { UPSTASH_SEARCH_REST_URL: string; UPSTASH_SEARCH_REST_TOKEN: string },
config?: Omit<ClientConfig, "url" | "token">
): Search
```

Use this when you want to explicitly pass environment variables (useful in serverless frameworks) but still allow retry/cache overrides.

## Methods
### index
```ts
index<TContent extends Dict = Dict, TIndexMetadata extends Dict = Dict>(indexName: string): SearchIndex<TContent, TIndexMetadata>
```
Creates a `SearchIndex` scoped to the provided index name.

### listIndexes
```ts
listIndexes(): Promise<string[]>
```
Returns a list of index names (namespaces) available in the database.

### info
```ts
info(): Promise<{
diskSize: number;
pendingDocumentCount: number;
documentCount: number;
indexes: Record<string, { pendingDocumentCount: number; documentCount: number }>;
}>
```
Returns storage and document counts for the entire database and per index.

## Usage example
```ts index.ts
import { Search } from "@upstash/search";

const client = new Search({
url: process.env.UPSTASH_SEARCH_REST_URL!,
token: process.env.UPSTASH_SEARCH_REST_TOKEN!,
});

const index = client.index("movies");
const stats = await client.info();
console.log(stats.documentCount);
```

**Related**: [SearchIndex](./search-index), [Types](../types)
49 changes: 49 additions & 0 deletions docs/codedocs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: "Architecture"
description: "How Upstash Search JS is structured internally and how requests flow through the SDK."
---

Upstash Search JS is a thin HTTP client built around a few focused modules: a platform-specific `Search` wrapper, a shared `Search` core that composes a `SearchIndex`, a small HTTP client with retry and cache controls, and a filter builder that turns typed filter trees into the string syntax expected by the REST API.

```mermaid
graph TD
A[platforms/nodejs.ts] -->|extends| B[search.ts]
C[platforms/cloudflare.ts] -->|extends| B[search.ts]
B --> D[search-index.ts]
B --> E[@upstash/vector Index]
D --> F[client/search-client.ts]
D --> G[client/metadata.ts]
F --> H[fetch + REST API]
```

**Key Design Decisions**
- **Platform-specific entry points**: `src/platforms/nodejs.ts` and `src/platforms/cloudflare.ts` create a `Search` instance with runtime-appropriate defaults for telemetry and cache. This keeps the core `Search` class (`src/search.ts`) clean and portable, while letting each platform decide how to read credentials and detect runtime details.
- **Composition over duplication**: The core `Search` class constructs a `@upstash/vector` `Index` (`src/search.ts`) and shares the same underlying HTTP client. `SearchIndex` (`src/search-index.ts`) receives both the raw HTTP client and the vector index so it can use REST endpoints for search and the Vector SDK for fetch/delete/range/reset APIs. This avoids duplicating REST utilities while still exposing a concise Search‑specific API.
- **Typed filter trees**: The filter system in `src/client/metadata.ts` defines a `TreeNode` type that merges content and metadata fields and enforces mutually exclusive operations at the type level. It then translates that type-safe structure into a single REST filter string via `constructFilterString`. This lets you build complex filters without manually concatenating strings.
- **Retry and cache as first-class config**: `src/client/search-client.ts` defines `RequesterConfig` and `RetryConfig`, then normalizes them into a concrete retry plan. The implementation explicitly sets a default exponential backoff (e.g., `Math.exp(retryCount) * 50`) and keeps cache policy in the request options.

**How the Pieces Fit Together**
1. **Search instance creation**: You instantiate `Search` from `src/platforms/nodejs.ts` or `src/platforms/cloudflare.ts`. These constructors validate credentials, set telemetry headers, and create an `HttpClient` with retry/cache options.
2. **Index selection**: `Search.index()` from `src/search.ts` creates a `SearchIndex` that is scoped to a namespace (index name). This isolates document operations per index.
3. **Document operations**: `SearchIndex` provides `upsert`, `fetch`, `search`, `range`, `reset`, and `deleteIndex`. Search requests are sent directly via `HttpClient` to REST endpoints (`/search/{index}` or `/upsert-data/{index}`). Fetch/range/delete/reset use the `@upstash/vector` `Index` with a namespace set to the index name.
4. **Filtering**: If you pass a structured filter object to `SearchIndex.search`, it is converted to the REST filter expression by `constructFilterString` (`src/client/metadata.ts`). The resulting string is included in the POST body for the search request.

**Request Lifecycle (Search)**
```mermaid
sequenceDiagram
participant App
participant SearchIndex
participant HttpClient
participant UpstashAPI

App->>SearchIndex: search({ query, filter, ... })
SearchIndex->>SearchIndex: validate semanticWeight
SearchIndex->>SearchIndex: construct filter string (optional)
SearchIndex->>HttpClient: request({ path: ["search", index], body })
HttpClient->>UpstashAPI: POST /search/{index}
UpstashAPI-->>HttpClient: JSON result
HttpClient-->>SearchIndex: result array
SearchIndex-->>App: normalized documents with score
```

The result is a compact, predictable SDK surface that stays close to the REST API while still giving you typed documents and helper methods for common index tasks.
Loading