@algolia/wizard 0.1.0
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/README.md +69 -0
- package/dist/algolia.png +0 -0
- package/dist/main.js +3597 -0
- package/docs/algolia-sdk/README.md +36 -0
- package/docs/algolia-sdk/instantsearch-setup-angular.md +80 -0
- package/docs/algolia-sdk/instantsearch-setup-js.md +33 -0
- package/docs/algolia-sdk/instantsearch-setup-react.md +39 -0
- package/docs/algolia-sdk/instantsearch-setup-vue.md +41 -0
- package/docs/algolia-sdk/save-records-js.md +39 -0
- package/docs/algolia-sdk/search-single-index.md +42 -0
- package/package.json +71 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Algolia JS SDK reference (search)
|
|
2
|
+
|
|
3
|
+
Authoritative reference for wiring **Algolia search** in JavaScript/TypeScript apps.
|
|
4
|
+
Prefer the method shapes documented here over prior knowledge — they are pinned to
|
|
5
|
+
the current stable majors and avoid known pitfalls (e.g. v5 type mismatches with
|
|
6
|
+
InstantSearch).
|
|
7
|
+
|
|
8
|
+
## Versions
|
|
9
|
+
|
|
10
|
+
- `algoliasearch` v5 (install `^5`)
|
|
11
|
+
- `react-instantsearch` v7 (install `^7`)
|
|
12
|
+
- `vue-instantsearch` v4 (install `^4`)
|
|
13
|
+
- `instantsearch.js` v4 (install `^4`) — also the recommended choice for Angular
|
|
14
|
+
- `angular-instantsearch` — DEPRECATED/archived (Sep 2024); do not use, prefer `instantsearch.js`
|
|
15
|
+
|
|
16
|
+
Always install the **latest stable** within the major (use a caret range like `^5` /
|
|
17
|
+
`^7`); never pin an exact patch.
|
|
18
|
+
|
|
19
|
+
## Golden rules
|
|
20
|
+
|
|
21
|
+
- Use a **search-only API key** in any browser/client code. It is safe to expose.
|
|
22
|
+
NEVER ship an admin or any write-capable key to the client.
|
|
23
|
+
- Read the Application ID and search-only key from **public env vars**, never hardcode
|
|
24
|
+
them inline.
|
|
25
|
+
- Instantiate the search client **once, outside your components**, and pass a stable
|
|
26
|
+
reference. Do not inline `algoliasearch(...)` as a prop value — it breaks the
|
|
27
|
+
client cache and causes re-renders.
|
|
28
|
+
- For InstantSearch, import the client from `algoliasearch/lite` (smaller bundle and
|
|
29
|
+
correct types — see `instantsearch-setup.md`).
|
|
30
|
+
|
|
31
|
+
## Files
|
|
32
|
+
|
|
33
|
+
- `instantsearch-setup.md` — framework-specific InstantSearch wiring (React, Vue,
|
|
34
|
+
Angular, vanilla). Use this for the in-app search UI.
|
|
35
|
+
- `search-single-index.md` — direct/manual search via the core client
|
|
36
|
+
(`searchSingleIndex`), for cases where InstantSearch is not used.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# InstantSearch setup
|
|
2
|
+
|
|
3
|
+
Install `instantsearch.js` (v4)
|
|
4
|
+
|
|
5
|
+
## Search client: always use the lite client
|
|
6
|
+
|
|
7
|
+
Import the client from `algoliasearch/lite` and alias it to `algoliasearch`
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
11
|
+
|
|
12
|
+
// Instantiate ONCE, outside components, with a stable reference.
|
|
13
|
+
const searchClient = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Angular (use `instantsearch.js`)
|
|
17
|
+
|
|
18
|
+
Do NOT use `angular-instantsearch`: it is deprecated and archived (last release
|
|
19
|
+
v4.4.3, Sep 2024), not compatible with Ivy / modern Angular (v13+), and receives no
|
|
20
|
+
security fixes. Algolia recommends driving `instantsearch.js` directly from an Angular
|
|
21
|
+
component instead.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import {
|
|
25
|
+
Component,
|
|
26
|
+
ElementRef,
|
|
27
|
+
OnDestroy,
|
|
28
|
+
OnInit,
|
|
29
|
+
ViewChild,
|
|
30
|
+
} from '@angular/core'
|
|
31
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
32
|
+
import instantsearch from 'instantsearch.js'
|
|
33
|
+
import { searchBox, hits } from 'instantsearch.js/es/widgets'
|
|
34
|
+
|
|
35
|
+
@Component({
|
|
36
|
+
selector: 'app-search',
|
|
37
|
+
template: `<div #searchbox></div>
|
|
38
|
+
<div #hits></div>`,
|
|
39
|
+
})
|
|
40
|
+
export class SearchComponent implements OnInit, OnDestroy {
|
|
41
|
+
@ViewChild('searchbox', { static: true }) searchbox!: ElementRef
|
|
42
|
+
@ViewChild('hits', { static: true }) hits!: ElementRef
|
|
43
|
+
|
|
44
|
+
private search = instantsearch({
|
|
45
|
+
indexName: 'INDEX_NAME',
|
|
46
|
+
searchClient: algoliasearch(APP_ID, SEARCH_ONLY_KEY),
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
ngOnInit() {
|
|
50
|
+
this.search.addWidgets([
|
|
51
|
+
searchBox({ container: this.searchbox.nativeElement }),
|
|
52
|
+
hits({ container: this.hits.nativeElement }),
|
|
53
|
+
])
|
|
54
|
+
this.search.start()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
ngOnDestroy() {
|
|
58
|
+
this.search.dispose()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Vanilla (`instantsearch.js` v4)
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
67
|
+
import instantsearch from 'instantsearch.js'
|
|
68
|
+
import { searchBox, hits } from 'instantsearch.js/es/widgets'
|
|
69
|
+
|
|
70
|
+
const searchClient = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
71
|
+
|
|
72
|
+
const search = instantsearch({ indexName: 'INDEX_NAME', searchClient })
|
|
73
|
+
|
|
74
|
+
search.addWidgets([
|
|
75
|
+
searchBox({ container: '#searchbox' }),
|
|
76
|
+
hits({ container: '#hits' }),
|
|
77
|
+
])
|
|
78
|
+
|
|
79
|
+
search.start()
|
|
80
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# InstantSearch setup
|
|
2
|
+
|
|
3
|
+
Install `instantsearch.js` (v4)
|
|
4
|
+
|
|
5
|
+
## Search client: always use the lite client
|
|
6
|
+
|
|
7
|
+
Import the client from `algoliasearch/lite` and alias it to `algoliasearch`
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
11
|
+
|
|
12
|
+
// Instantiate ONCE, outside components, with a stable reference.
|
|
13
|
+
const searchClient = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Vanilla (`instantsearch.js` v4)
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
20
|
+
import instantsearch from 'instantsearch.js'
|
|
21
|
+
import { searchBox, hits } from 'instantsearch.js/es/widgets'
|
|
22
|
+
|
|
23
|
+
const searchClient = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
24
|
+
|
|
25
|
+
const search = instantsearch({ indexName: 'INDEX_NAME', searchClient })
|
|
26
|
+
|
|
27
|
+
search.addWidgets([
|
|
28
|
+
searchBox({ container: '#searchbox' }),
|
|
29
|
+
hits({ container: '#hits' }),
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
search.start()
|
|
33
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# InstantSearch setup
|
|
2
|
+
|
|
3
|
+
Install `react-instantsearch` (v7)
|
|
4
|
+
|
|
5
|
+
## Search client: always use the lite client
|
|
6
|
+
|
|
7
|
+
Import the client from `algoliasearch/lite` and alias it to `algoliasearch`
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
11
|
+
|
|
12
|
+
// Instantiate ONCE, outside components, with a stable reference.
|
|
13
|
+
const searchClient = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## React (`react-instantsearch` v7)
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
20
|
+
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch'
|
|
21
|
+
|
|
22
|
+
// Read from PUBLIC env vars; never hardcode. (Vite shown; use the framework's
|
|
23
|
+
// convention: NEXT_PUBLIC_* for Next.js, etc.)
|
|
24
|
+
const searchClient = algoliasearch(
|
|
25
|
+
import.meta.env.VITE_ALGOLIA_APP_ID,
|
|
26
|
+
import.meta.env.VITE_ALGOLIA_SEARCH_API_KEY,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
export function Search() {
|
|
30
|
+
return (
|
|
31
|
+
<InstantSearch searchClient={searchClient} indexName="INDEX_NAME">
|
|
32
|
+
<SearchBox />
|
|
33
|
+
<Hits />
|
|
34
|
+
</InstantSearch>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Do not inline `searchClient={algoliasearch(...)}` — keep the stable reference above.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# InstantSearch setup
|
|
2
|
+
|
|
3
|
+
Install `vue-instantsearch` (v4)
|
|
4
|
+
|
|
5
|
+
## Search client: always use the lite client
|
|
6
|
+
|
|
7
|
+
Import the client from `algoliasearch/lite` and alias it to `algoliasearch`
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
11
|
+
|
|
12
|
+
// Instantiate ONCE, outside components, with a stable reference.
|
|
13
|
+
const searchClient = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Vue (`vue-instantsearch` v4)
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<template>
|
|
20
|
+
<ais-instant-search :search-client="searchClient" index-name="INDEX_NAME">
|
|
21
|
+
<ais-search-box />
|
|
22
|
+
<ais-hits />
|
|
23
|
+
</ais-instant-search>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup>
|
|
27
|
+
import { liteClient as algoliasearch } from 'algoliasearch/lite'
|
|
28
|
+
|
|
29
|
+
const searchClient = algoliasearch(
|
|
30
|
+
import.meta.env.VITE_ALGOLIA_APP_ID,
|
|
31
|
+
import.meta.env.VITE_ALGOLIA_SEARCH_API_KEY,
|
|
32
|
+
)
|
|
33
|
+
</script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Register the widgets via the InstantSearch Vue plugin in your app entry:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import InstantSearch from 'vue-instantsearch/vue3/es'
|
|
40
|
+
app.use(InstantSearch)
|
|
41
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Save records (algoliasearch v5)
|
|
2
|
+
|
|
3
|
+
Adds records to an index. Write op — use a **write key**, server-side only.
|
|
4
|
+
|
|
5
|
+
`saveObjects` adds records, auto-batching in groups of 1,000 (Batch API,
|
|
6
|
+
`addObject` action).
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
import { algoliasearch } from 'algoliasearch'
|
|
10
|
+
|
|
11
|
+
const client = algoliasearch(APP_ID, WRITE_KEY)
|
|
12
|
+
|
|
13
|
+
const response = await client.saveObjects({
|
|
14
|
+
indexName: 'playlists',
|
|
15
|
+
objects: [{ objectID: '1', name: 'Hot 100', visibility: 'public' }],
|
|
16
|
+
waitForTasks: true,
|
|
17
|
+
batchSize: 1000,
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
client.saveObjects(
|
|
23
|
+
params: {
|
|
24
|
+
indexName: string // required
|
|
25
|
+
objects: Record<string, unknown>[] // required
|
|
26
|
+
waitForTasks?: boolean // default false
|
|
27
|
+
batchSize?: number // default 1000
|
|
28
|
+
},
|
|
29
|
+
requestOptions?: RequestOptions, // optional
|
|
30
|
+
)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Returns an array (one entry per batch), not a single object — don't destructure:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
type SaveObjectsResponse = { taskID: number; objectIDs: string[] }[]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Subject to indexing rate limits.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Direct search with the core client (v5)
|
|
2
|
+
|
|
3
|
+
Use this only when NOT using InstantSearch (e.g. a custom search box, a server
|
|
4
|
+
route, or programmatic queries). For UI, prefer `instantsearch-setup-<framework>.md`.
|
|
5
|
+
|
|
6
|
+
## Client
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { algoliasearch } from 'algoliasearch'
|
|
10
|
+
|
|
11
|
+
const client = algoliasearch(APP_ID, SEARCH_ONLY_KEY)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
In v5 there is no `client.initIndex(...)`. Index methods take the index name as a
|
|
15
|
+
parameter on the client. Every method takes a single options object.
|
|
16
|
+
|
|
17
|
+
## Search a single index
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
const { hits, nbHits } = await client.searchSingleIndex({
|
|
21
|
+
indexName: 'INDEX_NAME',
|
|
22
|
+
searchParams: { query: 'shoes', hitsPerPage: 20, page: 0 },
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Search multiple indices / queries in one request
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
const { results } = await client.search({
|
|
30
|
+
requests: [
|
|
31
|
+
{ indexName: 'INDEX_NAME', query: 'shoes' },
|
|
32
|
+
{ indexName: 'OTHER_INDEX', query: 'shoes' },
|
|
33
|
+
],
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Notes
|
|
38
|
+
|
|
39
|
+
- `searchSingleIndex` returns up to 1,000 hits. For larger exports use the `browse`
|
|
40
|
+
operation instead.
|
|
41
|
+
- Keep using a **search-only** key for any client-exposed search. Use an admin key
|
|
42
|
+
only in trusted server-side code.
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@algolia/wizard",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Magically implement Algolia functionality in your codebase",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"wizard": "dist/main.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"docs"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build:proxy": "esbuild src/proxy/index.ts --bundle --platform=node --format=esm --target=node24 --banner:js='import { createRequire as __cr } from \"module\"; const require = __cr(import.meta.url);' --outfile=dist/proxy.mjs",
|
|
18
|
+
"build": "esbuild src/main.tsx --bundle --platform=node --format=esm --target=node18 --packages=external --jsx=automatic --banner:js='#!/usr/bin/env node' --outfile=dist/main.js && cp src/ui/algolia.png dist/algolia.png",
|
|
19
|
+
"dev:proxy": "NODE_OPTIONS=--use-system-ca tsx watch src/proxy/index.ts",
|
|
20
|
+
"dev": "touch .env && tsx --env-file=.env ./src/main.tsx",
|
|
21
|
+
"env:load": "pnpm exec -- varlock load",
|
|
22
|
+
"prepare": "husky",
|
|
23
|
+
"prepublishOnly": "pnpm build",
|
|
24
|
+
"reset": "tsx ./scripts/reset-state.ts",
|
|
25
|
+
"test:fixtures": "touch .env && tsx --env-file=.env ./fixtures/run-fixtures.ts",
|
|
26
|
+
"test:tools": "tsx ./tool-evals/toolEval.ts",
|
|
27
|
+
"test": "vitest",
|
|
28
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "ISC",
|
|
33
|
+
"packageManager": "pnpm@11.9.0+sha512.bd682d5d03fe525ef7c9fd6780c6884d1e756ac4c9c9fe00c538782824310dcf90e3ddc4f53835f06dfaebd5085e41855e0bcbb3b60de2ac5bbab89e5036f03b",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@clack/prompts": "^1.6.0",
|
|
36
|
+
"@types/ioredis-mock": "^8.2.7",
|
|
37
|
+
"@types/node": "^25.9.1",
|
|
38
|
+
"@types/react": "^19.2.16",
|
|
39
|
+
"esbuild": "^0.28.0",
|
|
40
|
+
"husky": "^9.1.7",
|
|
41
|
+
"ink-testing-library": "^4.0.0",
|
|
42
|
+
"ioredis-mock": "^8.13.1",
|
|
43
|
+
"lint-staged": "^17.0.8",
|
|
44
|
+
"tsx": "^4.22.3",
|
|
45
|
+
"typescript": "^6.0.3",
|
|
46
|
+
"vitest": "^4.1.8"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@ai-sdk/anthropic": "^3.0.81",
|
|
50
|
+
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
51
|
+
"@algolia/cli": "^5.11.0",
|
|
52
|
+
"@hono/node-server": "^2.0.10",
|
|
53
|
+
"@mishieck/ink-titled-box": "^0.4.2",
|
|
54
|
+
"@segment/analytics-node": "^3.1.0",
|
|
55
|
+
"ai": "^6.0.190",
|
|
56
|
+
"dotenv": "^17.4.2",
|
|
57
|
+
"hono": "^4.12.27",
|
|
58
|
+
"ink": "^7.0.5",
|
|
59
|
+
"ink-picture": "^2.1.0",
|
|
60
|
+
"ink-spinner": "^5.0.0",
|
|
61
|
+
"ink-text-input": "^6.0.0",
|
|
62
|
+
"ioredis": "^5.11.1",
|
|
63
|
+
"nanoid": "^5.1.15",
|
|
64
|
+
"pino": "^10.3.1",
|
|
65
|
+
"react": "^19.2.7",
|
|
66
|
+
"toml": "^4.1.1",
|
|
67
|
+
"varlock": "^1.5.1",
|
|
68
|
+
"zod": "^4.4.3",
|
|
69
|
+
"zustand": "^5.0.14"
|
|
70
|
+
}
|
|
71
|
+
}
|