Core & UI: bump to algolia search v5

This commit is contained in:
Fuma Nama
2025-05-24 18:08:59 +08:00
parent 0bdfab9728
commit 961b67e791
14 changed files with 310 additions and 276 deletions
+46
View File
@@ -0,0 +1,46 @@
---
'fumadocs-core': minor
'fumadocs-ui': minor
---
**Bump algolia search to v5**
This also introduced changes to some APIs since `algoliasearch` v4 and v5 has many differences.
Now we highly recommend to pass an index name to `sync()`:
```ts
import { algoliasearch } from 'algoliasearch';
import { sync } from 'fumadocs-core/search/algolia';
const client = algoliasearch('id', 'key');
void sync(client, {
indexName: 'document',
documents: records,
});
```
For search client, pass them to `searchOptions`:
```tsx
'use client';
import { liteClient } from 'algoliasearch/lite';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
import SearchDialog from 'fumadocs-ui/components/dialog/search-algolia';
const client = liteClient(appId, apiKey);
export default function CustomSearchDialog(props: SharedProps) {
return (
<SearchDialog
searchOptions={{
client,
indexName: 'document',
}}
{...props}
showAlgolia
/>
);
}
```
@@ -45,28 +45,35 @@ credentials in environment variables.
Export the search indexes from Next.js using a route handler, this way we can access the search indexes after production build:
<include cwd meta='title="app/static.json/route.ts"'>
../../examples/next-mdx/app/static.json/algolia.ts
</include>
```ts title="app/static.json/route.ts"
import { NextResponse } from 'next/server';
import { type DocumentRecord } from 'fumadocs-core/search/algolia';
import { source } from '@/lib/source';
export const revalidate = false;
export function GET() {
const results: DocumentRecord[] = [];
for (const page of source.getPages()) {
results.push({
_id: page.url,
structured: page.data.structuredData,
url: page.url,
title: page.data.title,
description: page.data.description,
});
}
return NextResponse.json(results);
}
```
Make a script to sync search indexes:
```js title="update-index.mjs"
import algosearch from 'algoliasearch';
import { sync } from 'fumadocs-core/search/algolia';
import * as fs from 'node:fs';
const content = fs.readFileSync('.next/server/app/static.json.body');
/** @type {import('fumadocs-core/search/algolia').DocumentRecord[]} **/
const indexes = JSON.parse(content.toString());
const client = algosearch('id', 'key');
sync(client, {
documents: indexes, // search indexes, can be provided by your content source too [!code highlight]
});
```
<include lang="js" meta='title="update-index.mjs"'>
./sync-algolia.mjs
</include>
The `sync` function will update the index settings and sync search indexes.
@@ -98,17 +105,16 @@ You can consider different options for implementing the UI:
- [Fumadocs UI Usage](/docs/ui/search#algolia)
- Build your own using the built-in search client hook:
```ts
import algosearch from 'algoliasearch';
```ts twoslash
import { liteClient } from 'algoliasearch/lite';
import { useDocsSearch } from 'fumadocs-core/search/client';
const index = algosearch('id', 'key').initIndex('document');
const client = liteClient('id', 'key');
const { search, setSearch, query } = useDocsSearch({
type: 'algolia',
index,
distinct: 5,
hitsPerPage: 10,
indexName: 'document',
client,
});
```
@@ -119,15 +125,13 @@ You can consider different options for implementing the UI:
To configure tag filtering, add a `tag` value to indexes.
```js
import algosearch from 'algoliasearch';
import { sync } from 'fumadocs-core/search/algolia';
const client = algosearch('id', 'key');
sync(client, {
documents: indexes.map((index) => ({
void sync(client, {
indexName: 'document',
documents: records.map((index) => ({
...index,
tag: 'value', // [!code highlight]
tag: 'value', // [!code ++]
})),
});
```
@@ -138,40 +142,13 @@ And update your search client:
- **Search Client**: You can add the tag filter like:
```ts
import algosearch from 'algoliasearch';
import { useDocsSearch } from 'fumadocs-core/search/client';
const index = algosearch('id', 'key').initIndex('document');
const { search, setSearch, query } = useDocsSearch(
{
type: 'algolia',
index,
},
{ ... },
undefined,
'<your tag value>',
'<your tag value>', // [!code ++]
);
```
The `tag` field is an attribute for faceting. You can also use the filter `tag:value` on Algolia search clients.
### Customise Attributes & Settings
While the default attributes might not suit your case, you can pass `extra_data`
to index options for adding extra fields to each record.
```js
import { sync } from 'fumadocs-core/search/algolia';
sync(client, {
documents: indexes.map((docs) => ({
...docs,
extra_data: {
value: 'hello world',
},
})),
});
```
To customize the default index settings, set index settings, and update
documents with `updateDocuments(...)` separately.
@@ -146,23 +146,20 @@ export const source = loader({
../../examples/i18n/app/api/search/route-full.ts
</include>
### Update Search Client
and update your search clients:
<Callout type="info" title="For Fumadocs UI">
You can ignore this, Fumadocs UI handles this when you have i18n configured
correctly.
</Callout>
- **Fumadocs UI**: No changes needed, Fumadocs UI handles this when you have i18n configured correctly.
- **Search Client**:
Add `locale` to the search client, this will only allow pages with specified locale to be searchable by the user.
Add `locale` to the search client, this will only allow pages with specified locale to be searchable by the user.
```ts
const { search, setSearch, query } = useDocsSearch(
{
type: 'fetch',
},
locale,
);
```
```ts
const { search, setSearch, query } = useDocsSearch(
{
type: 'fetch',
},
locale,
);
```
## Static Export
@@ -203,8 +200,7 @@ and update your search clients:
Static Search requires clients to download the exported search indexes.
For large docs sites, its size can be really big.
Especially with i18n (e.g. Chinese tokenizers), the bundle size of tokenizers can exceed ~500MB.
You should use 3rd party solutions like Algolia for these cases.
You should use cloud solutions like Orama Cloud or Algolia for these cases.
</Callout>
@@ -1,4 +1,5 @@
import algosearch from 'algoliasearch';
// @ts-check
import { algoliasearch } from 'algoliasearch';
import { sync } from 'fumadocs-core/search/algolia';
import * as fs from 'node:fs';
@@ -8,8 +9,9 @@ const content = fs.readFileSync('.next/server/app/static.json.body');
/** @type {import('fumadocs-core/search/algolia').DocumentRecord[]} **/
const records = JSON.parse(content.toString());
const client = algosearch('id', 'key');
const client = algoliasearch('id', 'key');
void sync(client, {
indexName: 'document',
documents: records, // [!code highlight]
});
+15 -9
View File
@@ -1,19 +1,25 @@
'use client';
import algo from 'algoliasearch/lite';
import { liteClient } from 'algoliasearch/lite';
import type { SharedProps } from 'fumadocs-ui/components/dialog/search';
import SearchDialog from 'fumadocs-ui/components/dialog/search-algolia';
const appId = process.env.NEXT_PUBLIC_ALGOLIA_APP_ID;
const apiKey = process.env.NEXT_PUBLIC_ALGOLIA_API_KEY;
const indexName = process.env.NEXT_PUBLIC_ALGOLIA_INDEX;
const appId = process.env.NEXT_PUBLIC_ALGOLIA_APP_ID!;
const apiKey = process.env.NEXT_PUBLIC_ALGOLIA_API_KEY!;
if (!appId || !apiKey || !indexName) throw new Error('Algolia credentials');
if (!appId || !apiKey) throw new Error('Missing Algolia credentials');
const client = algo(appId, apiKey);
const index = client.initIndex(indexName);
const client = liteClient(appId, apiKey);
export default function CustomSearchDialog(props: SharedProps) {
return <SearchDialog index={index} {...props} showAlgolia />;
return (
<SearchDialog
searchOptions={{
client,
indexName: 'document',
}}
{...props}
showAlgolia
/>
);
}
+1 -1
View File
@@ -64,7 +64,7 @@
"@types/node": "22.15.21",
"@types/react": "^19.1.5",
"@types/react-dom": "^19.1.5",
"algoliasearch": "4.24.0",
"algoliasearch": "5.25.0",
"eslint-config-custom": "workspace:*",
"gray-matter": "^4.0.3",
"next-validate-link": "^1.5.2",
@@ -1,21 +0,0 @@
import { NextResponse } from 'next/server';
import { type DocumentRecord } from 'fumadocs-core/search/algolia';
import { source } from '@/lib/source';
export const revalidate = false;
export function GET() {
const results: DocumentRecord[] = [];
for (const page of source.getPages()) {
results.push({
_id: page.url,
structured: page.data.structuredData,
url: page.url,
title: page.data.title,
description: page.data.description,
});
}
return NextResponse.json(results);
}
+2 -3
View File
@@ -101,7 +101,6 @@
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@algolia/client-search": "4.24.0",
"@mdx-js/mdx": "^3.1.0",
"@oramacloud/client": "^2.1.4",
"@tanstack/react-router": "^1.120.9",
@@ -112,7 +111,7 @@
"@types/node": "22.15.21",
"@types/react": "^19.1.5",
"@types/react-dom": "^19.1.5",
"algoliasearch": "4.24.0",
"algoliasearch": "5.25.0",
"eslint-config-custom": "workspace:*",
"mdast-util-mdx-jsx": "^3.2.0",
"mdast-util-mdxjs-esm": "^2.0.1",
@@ -127,7 +126,7 @@
},
"peerDependencies": {
"@oramacloud/client": "1.x.x || 2.x.x",
"algoliasearch": "4.24.0",
"algoliasearch": "5.x.x",
"next": "14.x.x || 15.x.x",
"react": "18.x.x || 19.x.x",
"react-dom": "18.x.x || 19.x.x"
+42 -21
View File
@@ -1,4 +1,4 @@
import type { SearchClient, SearchIndex } from 'algoliasearch';
import type { Algoliasearch } from 'algoliasearch';
import type { StructuredData } from '@/mdx-plugins/remark-structure';
export interface DocumentRecord {
@@ -29,10 +29,17 @@ export interface DocumentRecord {
export interface SyncOptions {
/**
* Index Name for documents
* Index Name for documents.
*
* @deprecated Use `indexName` instead
*/
document?: string;
/**
* Index Name for documents.
*/
indexName?: string;
/**
* Search indexes
*/
@@ -46,22 +53,33 @@ export interface SyncOptions {
* @param options - Index Options
*/
export async function sync(
client: SearchClient,
client: Algoliasearch,
options: SyncOptions,
): Promise<void> {
const { document = 'document', documents } = options;
const index = client.initIndex(document);
await setIndexSettings(index);
await updateDocuments(index, documents);
const { document = 'document', indexName = document, documents } = options;
await setIndexSettings(client, indexName);
await updateDocuments(client, indexName, documents);
}
export async function setIndexSettings(index: SearchIndex): Promise<void> {
await index.setSettings({
attributeForDistinct: 'page_id',
attributesToRetrieve: ['title', 'section', 'content', 'url', 'section_id'],
searchableAttributes: ['title', 'section', 'content'],
attributesToSnippet: [],
attributesForFaceting: ['tag'],
export async function setIndexSettings(
client: Algoliasearch,
indexName: string,
): Promise<void> {
await client.setSettings({
indexName,
indexSettings: {
attributeForDistinct: 'page_id',
attributesToRetrieve: [
'title',
'section',
'content',
'url',
'section_id',
],
searchableAttributes: ['title', 'section', 'content'],
attributesToSnippet: [],
attributesForFaceting: ['tag'],
},
});
}
@@ -90,11 +108,10 @@ function toIndex(page: DocumentRecord): BaseIndex[] {
if (page.description)
indexes.push(createIndex(undefined, undefined, page.description));
const { headings, contents } = page.structured;
page.structured.contents.forEach((p) => {
const heading = p.heading
? page.structured.headings.find((h) => p.heading === h.id)
: null;
for (const p of contents) {
const heading = p.heading ? headings.find((h) => p.heading === h.id) : null;
const index = createIndex(heading?.content, heading?.id, p.content);
@@ -105,18 +122,22 @@ function toIndex(page: DocumentRecord): BaseIndex[] {
}
indexes.push(index);
});
}
return indexes;
}
export async function updateDocuments(
index: SearchIndex,
client: Algoliasearch,
indexName: string,
documents: DocumentRecord[],
): Promise<void> {
const objects = documents.flatMap(toIndex);
await index.replaceAllObjects(objects);
await client.replaceAllObjects({
indexName,
objects: objects as unknown as Record<string, unknown>[],
});
}
export interface BaseIndex {
+1 -2
View File
@@ -77,10 +77,9 @@ export function useDocsSearch(
}
if (client.type === 'algolia') {
const { index, type: _, ...rest } = client;
const { searchDocs } = await import('./client/algolia');
return searchDocs(index, debouncedValue, tag, rest);
return searchDocs(debouncedValue, tag, locale, client);
}
if (client.type === 'orama-cloud') {
+34 -26
View File
@@ -1,10 +1,18 @@
import type { Hit, SearchOptions } from '@algolia/client-search';
import type { SearchIndex } from 'algoliasearch/lite';
import type { SortedResult } from '@/server/types';
import type { BaseIndex } from '@/search/algolia';
import type { Hit, LiteClient, SearchResponse } from 'algoliasearch/lite';
export interface AlgoliaOptions extends SearchOptions {
index: SearchIndex;
export interface AlgoliaOptions {
indexName: string;
client: LiteClient;
onSearch?: (
query: string,
tag?: string,
locale?: string,
) => Promise<{
results: SearchResponse<BaseIndex>[];
}>;
}
export function groupResults(hits: Hit<BaseIndex>[]): SortedResult[] {
@@ -35,31 +43,31 @@ export function groupResults(hits: Hit<BaseIndex>[]): SortedResult[] {
}
export async function searchDocs(
index: SearchIndex,
query: string,
tag?: string,
options?: SearchOptions,
tag: string | undefined,
locale: string | undefined,
{ indexName, onSearch, client }: AlgoliaOptions,
): Promise<SortedResult[]> {
let filters = options?.filters;
if (tag) filters = filters ? `tag:${tag} AND (${filters})` : `tag:${tag}`;
if (query.length > 0) {
const result = onSearch
? await onSearch(query, tag, locale)
: await client.searchForHits<BaseIndex>({
requests: [
{
type: 'default',
indexName,
query,
distinct: 5,
hitsPerPage: 10,
filters: tag ? `tag:${tag}` : undefined,
},
],
});
if (query.length === 0) {
const result = await index.search<BaseIndex>(query, {
distinct: 1,
hitsPerPage: 8,
...options,
filters,
});
return groupResults(result.hits).filter((hit) => hit.type === 'page');
return groupResults(result.results[0].hits).filter(
(hit) => hit.type === 'page',
);
}
const result = await index.search<BaseIndex>(query, {
distinct: 5,
hitsPerPage: 10,
...options,
filters,
});
return groupResults(result.hits);
return [];
}
-1
View File
@@ -2,7 +2,6 @@ import { defineConfig } from 'tsup';
export default defineConfig({
external: [
'@algolia/client-search',
'algoliasearch',
'unified',
'next',
@@ -15,8 +15,8 @@ import {
} from './search';
export interface AlgoliaSearchDialogProps extends SharedProps {
index: AlgoliaOptions['index'];
searchOptions?: Omit<AlgoliaOptions, 'index'>;
searchOptions: AlgoliaOptions;
footer?: ReactNode;
defaultTag?: string;
@@ -38,7 +38,6 @@ export interface AlgoliaSearchDialogProps extends SharedProps {
}
export default function AlgoliaSearchDialog({
index,
searchOptions,
tags,
defaultTag,
@@ -50,7 +49,6 @@ export default function AlgoliaSearchDialog({
const { search, setSearch, query } = useDocsSearch(
{
type: 'algolia',
index,
...searchOptions,
},
undefined,
+113 -109
View File
@@ -208,8 +208,8 @@ importers:
specifier: ^19.1.5
version: 19.1.5(@types/[email protected])
algoliasearch:
specifier: 4.24.0
version: 4.24.0
specifier: 5.25.0
version: 5.25.0
eslint-config-custom:
specifier: workspace:*
version: link:../../packages/eslint-config-custom
@@ -748,9 +748,6 @@ importers:
specifier: ^5.0.0
version: 5.0.0
devDependencies:
'@algolia/client-search':
specifier: 4.24.0
version: 4.24.0
'@mdx-js/mdx':
specifier: ^3.1.0
version: 3.1.0([email protected])
@@ -782,8 +779,8 @@ importers:
specifier: ^19.1.5
version: 19.1.5(@types/[email protected])
algoliasearch:
specifier: 4.24.0
version: 4.24.0
specifier: 5.25.0
version: 5.25.0
eslint-config-custom:
specifier: workspace:*
version: link:../eslint-config-custom
@@ -1519,50 +1516,57 @@ packages:
peerDependencies:
zod: ^3.23.8
'@algolia/cache-browser-local-storage@4.24.0':
resolution: {integrity: sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==}
'@algolia/client-abtesting@5.25.0':
resolution: {integrity: sha512-1pfQulNUYNf1Tk/svbfjfkLBS36zsuph6m+B6gDkPEivFmso/XnRgwDvjAx80WNtiHnmeNjIXdF7Gos8+OLHqQ==}
engines: {node: '>= 14.0.0'}
'@algolia/cache-common@4.24.0':
resolution: {integrity: sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==}
'@algolia/client-analytics@5.25.0':
resolution: {integrity: sha512-AFbG6VDJX/o2vDd9hqncj1B6B4Tulk61mY0pzTtzKClyTDlNP0xaUiEKhl6E7KO9I/x0FJF5tDCm0Hn6v5x18A==}
engines: {node: '>= 14.0.0'}
'@algolia/cache-in-memory@4.24.0':
resolution: {integrity: sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==}
'@algolia/client-common@5.25.0':
resolution: {integrity: sha512-il1zS/+Rc6la6RaCdSZ2YbJnkQC6W1wiBO8+SH+DE6CPMWBU6iDVzH0sCKSAtMWl9WBxoN6MhNjGBnCv9Yy2bA==}
engines: {node: '>= 14.0.0'}
'@algolia/client-account@4.24.0':
resolution: {integrity: sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==}
'@algolia/client-insights@5.25.0':
resolution: {integrity: sha512-blbjrUH1siZNfyCGeq0iLQu00w3a4fBXm0WRIM0V8alcAPo7rWjLbMJMrfBtzL9X5ic6wgxVpDADXduGtdrnkw==}
engines: {node: '>= 14.0.0'}
'@algolia/client-analytics@4.24.0':
resolution: {integrity: sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==}
'@algolia/client-personalization@5.25.0':
resolution: {integrity: sha512-aywoEuu1NxChBcHZ1pWaat0Plw7A8jDMwjgRJ00Mcl7wGlwuPt5dJ/LTNcg3McsEUbs2MBNmw0ignXBw9Tbgow==}
engines: {node: '>= 14.0.0'}
'@algolia/client-common@4.24.0':
resolution: {integrity: sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==}
'@algolia/client-query-suggestions@5.25.0':
resolution: {integrity: sha512-a/W2z6XWKjKjIW1QQQV8PTTj1TXtaKx79uR3NGBdBdGvVdt24KzGAaN7sCr5oP8DW4D3cJt44wp2OY/fZcPAVA==}
engines: {node: '>= 14.0.0'}
'@algolia/client-personalization@4.24.0':
resolution: {integrity: sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==}
'@algolia/client-search@5.25.0':
resolution: {integrity: sha512-9rUYcMIBOrCtYiLX49djyzxqdK9Dya/6Z/8sebPn94BekT+KLOpaZCuc6s0Fpfq7nx5J6YY5LIVFQrtioK9u0g==}
engines: {node: '>= 14.0.0'}
'@algolia/client-search@4.24.0':
resolution: {integrity: sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==}
'@algolia/ingestion@1.25.0':
resolution: {integrity: sha512-jJeH/Hk+k17Vkokf02lkfYE4A+EJX+UgnMhTLR/Mb+d1ya5WhE+po8p5a/Nxb6lo9OLCRl6w3Hmk1TX1e9gVbQ==}
engines: {node: '>= 14.0.0'}
'@algolia/logger-common@4.24.0':
resolution: {integrity: sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==}
'@algolia/monitoring@1.25.0':
resolution: {integrity: sha512-Ls3i1AehJ0C6xaHe7kK9vPmzImOn5zBg7Kzj8tRYIcmCWVyuuFwCIsbuIIz/qzUf1FPSWmw0TZrGeTumk2fqXg==}
engines: {node: '>= 14.0.0'}
'@algolia/logger-console@4.24.0':
resolution: {integrity: sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==}
'@algolia/recommend@5.25.0':
resolution: {integrity: sha512-79sMdHpiRLXVxSjgw7Pt4R1aNUHxFLHiaTDnN2MQjHwJ1+o3wSseb55T9VXU4kqy3m7TUme3pyRhLk5ip/S4Mw==}
engines: {node: '>= 14.0.0'}
'@algolia/recommend@4.24.0':
resolution: {integrity: sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==}
'@algolia/requester-browser-xhr@5.25.0':
resolution: {integrity: sha512-JLaF23p1SOPBmfEqozUAgKHQrGl3z/Z5RHbggBu6s07QqXXcazEsub5VLonCxGVqTv6a61AAPr8J1G5HgGGjEw==}
engines: {node: '>= 14.0.0'}
'@algolia/requester-browser-xhr@4.24.0':
resolution: {integrity: sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==}
'@algolia/requester-fetch@5.25.0':
resolution: {integrity: sha512-rtzXwqzFi1edkOF6sXxq+HhmRKDy7tz84u0o5t1fXwz0cwx+cjpmxu/6OQKTdOJFS92JUYHsG51Iunie7xbqfQ==}
engines: {node: '>= 14.0.0'}
'@algolia/requester-common@4.24.0':
resolution: {integrity: sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==}
'@algolia/[email protected]':
resolution: {integrity: sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==}
'@algolia/[email protected]':
resolution: {integrity: sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==}
'@algolia/requester-node-http@5.25.0':
resolution: {integrity: sha512-ZO0UKvDyEFvyeJQX0gmZDQEvhLZ2X10K+ps6hViMo1HgE2V8em00SwNsQ+7E/52a+YiBkVWX61pJJJE44juDMQ==}
engines: {node: '>= 14.0.0'}
'@alloc/[email protected]':
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
@@ -4801,8 +4805,9 @@ packages:
[email protected]:
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
algoliasearch@4.24.0:
resolution: {integrity: sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==}
algoliasearch@5.25.0:
resolution: {integrity: sha512-n73BVorL4HIwKlfJKb4SEzAYkR3Buwfwbh+MYxg2mloFph2fFGV58E90QTzdbfzWrLn4HE5Czx/WTjI8fcHaMg==}
engines: {node: '>= 14.0.0'}
[email protected]:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
@@ -10063,81 +10068,82 @@ snapshots:
zod: 3.25.28
zod-to-json-schema: 3.24.5([email protected])
'@algolia/cache-browser-local-storage@4.24.0':
'@algolia/client-abtesting@5.25.0':
dependencies:
'@algolia/cache-common': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/cache-common@4.24.0': {}
'@algolia/[email protected]':
'@algolia/client-analytics@5.25.0':
dependencies:
'@algolia/cache-common': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/client-account@4.24.0':
'@algolia/client-common@5.25.0': {}
'@algolia/[email protected]':
dependencies:
'@algolia/client-common': 4.24.0
'@algolia/client-search': 4.24.0
'@algolia/transporter': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/client-analytics@4.24.0':
'@algolia/client-personalization@5.25.0':
dependencies:
'@algolia/client-common': 4.24.0
'@algolia/client-search': 4.24.0
'@algolia/requester-common': 4.24.0
'@algolia/transporter': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/client-common@4.24.0':
'@algolia/client-query-suggestions@5.25.0':
dependencies:
'@algolia/requester-common': 4.24.0
'@algolia/transporter': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/client-personalization@4.24.0':
'@algolia/client-search@5.25.0':
dependencies:
'@algolia/client-common': 4.24.0
'@algolia/requester-common': 4.24.0
'@algolia/transporter': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/client-search@4.24.0':
'@algolia/ingestion@1.25.0':
dependencies:
'@algolia/client-common': 4.24.0
'@algolia/requester-common': 4.24.0
'@algolia/transporter': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/logger-common@4.24.0': {}
'@algolia/[email protected]':
'@algolia/monitoring@1.25.0':
dependencies:
'@algolia/logger-common': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/recommend@4.24.0':
'@algolia/recommend@5.25.0':
dependencies:
'@algolia/cache-browser-local-storage': 4.24.0
'@algolia/cache-common': 4.24.0
'@algolia/cache-in-memory': 4.24.0
'@algolia/client-common': 4.24.0
'@algolia/client-search': 4.24.0
'@algolia/logger-common': 4.24.0
'@algolia/logger-console': 4.24.0
'@algolia/requester-browser-xhr': 4.24.0
'@algolia/requester-common': 4.24.0
'@algolia/requester-node-http': 4.24.0
'@algolia/transporter': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
'@algolia/requester-browser-xhr@4.24.0':
'@algolia/requester-browser-xhr@5.25.0':
dependencies:
'@algolia/requester-common': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/requester-common@4.24.0': {}
'@algolia/[email protected]':
'@algolia/requester-fetch@5.25.0':
dependencies:
'@algolia/requester-common': 4.24.0
'@algolia/client-common': 5.25.0
'@algolia/transporter@4.24.0':
'@algolia/requester-node-http@5.25.0':
dependencies:
'@algolia/cache-common': 4.24.0
'@algolia/logger-common': 4.24.0
'@algolia/requester-common': 4.24.0
'@algolia/client-common': 5.25.0
'@alloc/[email protected]': {}
@@ -14273,23 +14279,21 @@ snapshots:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
algoliasearch@4.24.0:
algoliasearch@5.25.0:
dependencies:
'@algolia/cache-browser-local-storage': 4.24.0
'@algolia/cache-common': 4.24.0
'@algolia/cache-in-memory': 4.24.0
'@algolia/client-account': 4.24.0
'@algolia/client-analytics': 4.24.0
'@algolia/client-common': 4.24.0
'@algolia/client-personalization': 4.24.0
'@algolia/client-search': 4.24.0
'@algolia/logger-common': 4.24.0
'@algolia/logger-console': 4.24.0
'@algolia/recommend': 4.24.0
'@algolia/requester-browser-xhr': 4.24.0
'@algolia/requester-common': 4.24.0
'@algolia/requester-node-http': 4.24.0
'@algolia/transporter': 4.24.0
'@algolia/client-abtesting': 5.25.0
'@algolia/client-analytics': 5.25.0
'@algolia/client-common': 5.25.0
'@algolia/client-insights': 5.25.0
'@algolia/client-personalization': 5.25.0
'@algolia/client-query-suggestions': 5.25.0
'@algolia/client-search': 5.25.0
'@algolia/ingestion': 1.25.0
'@algolia/monitoring': 1.25.0
'@algolia/recommend': 5.25.0
'@algolia/requester-browser-xhr': 5.25.0
'@algolia/requester-fetch': 5.25.0
'@algolia/requester-node-http': 5.25.0
[email protected]:
dependencies: