diff --git a/.circleci/config.yml b/.circleci/config.yml index 46fc7e845f..1b99dafb67 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,7 +51,10 @@ workflows: - unit tests: requires: - build - - legacy algoliasearch: + - legacy algoliasearch v3: + requires: + - build + - legacy algoliasearch v4: requires: - build - vue v3: @@ -97,7 +100,8 @@ workflows: - lint - unit tests - examples - - legacy algoliasearch + - legacy algoliasearch v3 + - legacy algoliasearch v4 - helper docs - e2e tests filters: @@ -202,7 +206,7 @@ jobs: name: Type Checking command: yarn run type-check - legacy algoliasearch: + legacy algoliasearch v3: <<: *defaults steps: - checkout @@ -221,6 +225,28 @@ jobs: name: Type Checking command: yarn run type-check:v3 + legacy algoliasearch v4: + <<: *defaults + resource_class: large + steps: + - checkout + - *attach_workspace + - *install_yarn_version + - *restore_yarn_cache + - *run_yarn_install + - run: + name: Update dependencies + command: | + ./scripts/legacy/downgrade-algoliasearch-v4.js + - run: + name: Unit & Integration tests + command: yarn run test:ci + - store_test_results: + path: junit/jest/ + - run: + name: Type Checking + command: yarn run type-check + vue v3: <<: *defaults steps: diff --git a/examples/js/calendar-widget/app.js b/examples/js/calendar-widget/app.js index 01437a1189..80405d59d6 100644 --- a/examples/js/calendar-widget/app.js +++ b/examples/js/calendar-widget/app.js @@ -1,5 +1,5 @@ /* global moment Calendar $ */ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import instantsearch from 'instantsearch.js'; import { connectRange } from 'instantsearch.js/es/connectors'; import { searchBox, hits } from 'instantsearch.js/es/widgets'; diff --git a/examples/js/calendar-widget/package.json b/examples/js/calendar-widget/package.json index d1c32cdd7f..accc375bcc 100644 --- a/examples/js/calendar-widget/package.json +++ b/examples/js/calendar-widget/package.json @@ -8,7 +8,7 @@ "website:examples": "BABEL_ENV=parcel parcel build index.html --public-url . --dist-dir=../../../website/examples/js/calendar-widget" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.js": "4.73.4" }, "devDependencies": { diff --git a/examples/js/e-commerce-umd/package.json b/examples/js/e-commerce-umd/package.json index 072c19649f..f7747c8ae0 100644 --- a/examples/js/e-commerce-umd/package.json +++ b/examples/js/e-commerce-umd/package.json @@ -9,7 +9,7 @@ }, "browserslist": "firefox 68, chrome 78, IE 11", "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.js": "4.73.4" }, "devDependencies": { diff --git a/examples/js/e-commerce-umd/src/search.ts b/examples/js/e-commerce-umd/src/search.ts index ce30dffe36..32510323fe 100644 --- a/examples/js/e-commerce-umd/src/search.ts +++ b/examples/js/e-commerce-umd/src/search.ts @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import getRouting from './routing'; import { diff --git a/examples/js/e-commerce/package.json b/examples/js/e-commerce/package.json index 9c9a8810e2..2061bcb671 100644 --- a/examples/js/e-commerce/package.json +++ b/examples/js/e-commerce/package.json @@ -9,7 +9,7 @@ }, "browserslist": "firefox 68, chrome 78, IE 11", "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.js": "4.73.4" }, "devDependencies": { diff --git a/examples/js/e-commerce/src/search.ts b/examples/js/e-commerce/src/search.ts index 727b00a84d..dda821efbf 100644 --- a/examples/js/e-commerce/src/search.ts +++ b/examples/js/e-commerce/src/search.ts @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import instantsearch from 'instantsearch.js'; import getRouting from './routing'; diff --git a/examples/js/getting-started/package.json b/examples/js/getting-started/package.json index 43df933194..ef1effdb6e 100644 --- a/examples/js/getting-started/package.json +++ b/examples/js/getting-started/package.json @@ -9,7 +9,7 @@ "lint:fix": "npm run lint -- --fix" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.css": "8.4.0", "instantsearch.js": "4.73.4" }, diff --git a/examples/js/getting-started/products.html b/examples/js/getting-started/products.html index ae6eb06e4a..7de3f6df41 100644 --- a/examples/js/getting-started/products.html +++ b/examples/js/getting-started/products.html @@ -35,6 +35,6 @@

- + diff --git a/examples/js/getting-started/src/app.js b/examples/js/getting-started/src/app.js index 41c9cb241c..88bfc54a49 100644 --- a/examples/js/getting-started/src/app.js +++ b/examples/js/getting-started/src/app.js @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import instantsearch from 'instantsearch.js'; import { carousel } from 'instantsearch.js/es/templates'; import { diff --git a/examples/js/getting-started/src/products.js b/examples/js/getting-started/src/products.ts similarity index 92% rename from examples/js/getting-started/src/products.js rename to examples/js/getting-started/src/products.ts index add046b57f..dc7b1cf251 100644 --- a/examples/js/getting-started/src/products.js +++ b/examples/js/getting-started/src/products.ts @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import instantsearch from 'instantsearch.js'; import { carousel } from 'instantsearch.js/es/templates'; import { configure, hits, relatedProducts } from 'instantsearch.js/es/widgets'; @@ -9,6 +9,10 @@ const searchParams = new URLSearchParams(document.location.search); const pid = searchParams.get('pid'); +if (!pid) { + throw new Error('No product ID provided'); +} + const searchClient = algoliasearch( 'latency', '6be0576ff61c053d5f9a3225e2a90f76' diff --git a/examples/js/media/package.json b/examples/js/media/package.json index 3c34f07e28..8f3fc452be 100644 --- a/examples/js/media/package.json +++ b/examples/js/media/package.json @@ -8,7 +8,7 @@ "website:examples": "BABEL_ENV=parcel parcel build index.html --public-url . --dist-dir=../../../website/examples/js/media" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "date-fns": "2.25.0", "instantsearch.js": "4.73.4" }, diff --git a/examples/js/media/src/search.ts b/examples/js/media/src/search.ts index 3c284ea1ae..702764e777 100644 --- a/examples/js/media/src/search.ts +++ b/examples/js/media/src/search.ts @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import instantsearch from 'instantsearch.js'; import { singleIndex } from 'instantsearch.js/es/lib/stateMappings'; diff --git a/examples/js/tourism/package.json b/examples/js/tourism/package.json index b2ae7dc6d2..239e3ec347 100644 --- a/examples/js/tourism/package.json +++ b/examples/js/tourism/package.json @@ -8,7 +8,7 @@ "website:examples": "BABEL_ENV=parcel parcel build index.html --public-url . --dist-dir=../../../website/examples/js/tourism" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.js": "4.73.4" }, "devDependencies": { diff --git a/examples/js/tourism/search.js b/examples/js/tourism/search.js index 7e81dabce0..15b6df0b32 100644 --- a/examples/js/tourism/search.js +++ b/examples/js/tourism/search.js @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import instantsearch from 'instantsearch.js'; import { configure, diff --git a/examples/react/default-theme/package.json b/examples/react/default-theme/package.json index 567d7ab81b..59ae55698f 100644 --- a/examples/react/default-theme/package.json +++ b/examples/react/default-theme/package.json @@ -7,7 +7,7 @@ "start": "BABEL_ENV=parcel parcel index.html" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.js": "4.73.4", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/examples/react/default-theme/src/App.tsx b/examples/react/default-theme/src/App.tsx index 8da10a66ee..f3ac4516d5 100644 --- a/examples/react/default-theme/src/App.tsx +++ b/examples/react/default-theme/src/App.tsx @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { Hit as AlgoliaHit } from 'instantsearch.js'; import React from 'react'; import { diff --git a/examples/react/e-commerce/App.tsx b/examples/react/e-commerce/App.tsx index 0d7731d495..92fb9f45e7 100644 --- a/examples/react/e-commerce/App.tsx +++ b/examples/react/e-commerce/App.tsx @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import React, { useRef } from 'react'; import { Configure, diff --git a/examples/react/e-commerce/package.json b/examples/react/e-commerce/package.json index 8a3cd2c893..c29ee2e639 100644 --- a/examples/react/e-commerce/package.json +++ b/examples/react/e-commerce/package.json @@ -9,7 +9,7 @@ }, "browserslist": "firefox 68, chrome 78, IE 11", "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.js": "4.73.4", "react": "18.2.0", "react-compound-slider": "3.4.0", diff --git a/examples/react/getting-started/package.json b/examples/react/getting-started/package.json index a57010b330..63359c2126 100644 --- a/examples/react/getting-started/package.json +++ b/examples/react/getting-started/package.json @@ -7,7 +7,7 @@ "start": "BABEL_ENV=parcel parcel index.html products.html --port 3000" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.js": "4.73.4", "instantsearch.css": "8.4.0", "react": "18.2.0", diff --git a/examples/react/getting-started/src/App.tsx b/examples/react/getting-started/src/App.tsx index 88cb053cd3..87f58f61aa 100644 --- a/examples/react/getting-started/src/App.tsx +++ b/examples/react/getting-started/src/App.tsx @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { Hit } from 'instantsearch.js'; import React from 'react'; import { diff --git a/examples/react/getting-started/src/Product.tsx b/examples/react/getting-started/src/Product.tsx index 9ef899eef5..55aa2a6313 100644 --- a/examples/react/getting-started/src/Product.tsx +++ b/examples/react/getting-started/src/Product.tsx @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { type Hit } from 'instantsearch.js'; import React from 'react'; import { diff --git a/examples/react/next-app-router/app/Search.tsx b/examples/react/next-app-router/app/Search.tsx index 122275d840..caafd4fd45 100644 --- a/examples/react/next-app-router/app/Search.tsx +++ b/examples/react/next-app-router/app/Search.tsx @@ -1,6 +1,6 @@ 'use client'; -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { Hit as AlgoliaHit } from 'instantsearch.js'; import React from 'react'; import { diff --git a/examples/react/next-app-router/package.json b/examples/react/next-app-router/package.json index b137753969..e70000f6b1 100644 --- a/examples/react/next-app-router/package.json +++ b/examples/react/next-app-router/package.json @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.css": "8.4.0", "next": "13.5.1", "react": "18.2.0", diff --git a/examples/react/next-routing/package.json b/examples/react/next-routing/package.json index beb808bcac..21be3433cd 100644 --- a/examples/react/next-routing/package.json +++ b/examples/react/next-routing/package.json @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.css": "8.4.0", "next": "13.5.1", "react": "18.2.0", diff --git a/examples/react/next-routing/pages/index.tsx b/examples/react/next-routing/pages/index.tsx index 70653d61eb..8cb6260227 100644 --- a/examples/react/next-routing/pages/index.tsx +++ b/examples/react/next-routing/pages/index.tsx @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { Hit as AlgoliaHit } from 'instantsearch.js'; import { GetServerSideProps } from 'next'; import Head from 'next/head'; diff --git a/examples/react/next-routing/pages/test.tsx b/examples/react/next-routing/pages/test.tsx index d261c5579a..2ca680aecf 100644 --- a/examples/react/next-routing/pages/test.tsx +++ b/examples/react/next-routing/pages/test.tsx @@ -1,5 +1,5 @@ // This is only to test `onStateChange` does not get called twice -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { GetServerSideProps } from 'next'; import Head from 'next/head'; import Link from 'next/link'; diff --git a/examples/react/next/package.json b/examples/react/next/package.json index c99403a190..ddf515f746 100644 --- a/examples/react/next/package.json +++ b/examples/react/next/package.json @@ -9,7 +9,7 @@ "lint": "next lint" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "instantsearch.css": "8.4.0", "next": "13.5.1", "react": "18.2.0", diff --git a/examples/react/next/pages/index.tsx b/examples/react/next/pages/index.tsx index 65cd36d6a9..2ae1971f83 100644 --- a/examples/react/next/pages/index.tsx +++ b/examples/react/next/pages/index.tsx @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { Hit as AlgoliaHit } from 'instantsearch.js'; import { GetServerSideProps } from 'next'; import Head from 'next/head'; diff --git a/examples/react/react-native/App.tsx b/examples/react/react-native/App.tsx index d00d36a366..515fa74640 100644 --- a/examples/react/react-native/App.tsx +++ b/examples/react/react-native/App.tsx @@ -1,7 +1,7 @@ import React, { useRef } from 'react'; import { FlatList, SafeAreaView, StyleSheet, Text, View } from 'react-native'; import { StatusBar } from 'expo-status-bar'; -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; import { InstantSearch } from 'react-instantsearch-core'; import { InfiniteHits } from './src/InfiniteHits'; diff --git a/examples/react/react-native/package.json b/examples/react/react-native/package.json index 1302b4bcb9..c78c8e3a2d 100644 --- a/examples/react/react-native/package.json +++ b/examples/react/react-native/package.json @@ -11,7 +11,7 @@ "eject": "expo eject" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "expo": "~44.0.0", "expo-status-bar": "~1.2.0", "instantsearch.js": "4.73.4", diff --git a/examples/react/react-native/src/Highlight.tsx b/examples/react/react-native/src/Highlight.tsx index d25f35c698..f0785cf89d 100644 --- a/examples/react/react-native/src/Highlight.tsx +++ b/examples/react/react-native/src/Highlight.tsx @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import { StyleSheet, Text } from 'react-native'; -import { Hit as AlgoliaHit } from '@algolia/client-search'; +import { Hit as AlgoliaHit } from 'instantsearch.js'; import { getHighlightedParts, getPropertyByPath, @@ -26,7 +26,7 @@ type HighlightProps = { separator?: string; }; -export function Highlight>>({ +export function Highlight({ hit, attribute, separator = ', ', diff --git a/examples/react/react-native/src/InfiniteHits.tsx b/examples/react/react-native/src/InfiniteHits.tsx index b9648c08b2..becb8a0701 100644 --- a/examples/react/react-native/src/InfiniteHits.tsx +++ b/examples/react/react-native/src/InfiniteHits.tsx @@ -1,6 +1,6 @@ import React, { forwardRef } from 'react'; import { StyleSheet, View, FlatList } from 'react-native'; -import { Hit as AlgoliaHit } from '@algolia/client-search'; +import { Hit as AlgoliaHit } from 'instantsearch.js'; import { useInfiniteHits, UseInfiniteHitsProps, diff --git a/examples/react/react-native/types/ProductHit.ts b/examples/react/react-native/types/ProductHit.ts index 94883fbc6d..a41d0c54fd 100644 --- a/examples/react/react-native/types/ProductHit.ts +++ b/examples/react/react-native/types/ProductHit.ts @@ -1,4 +1,4 @@ -import { Hit as AlgoliaHit } from '@algolia/client-search'; +import { Hit as AlgoliaHit } from 'instantsearch.js'; export type ProductHit = AlgoliaHit<{ brand: string; diff --git a/examples/react/ssr/package.json b/examples/react/ssr/package.json index 422860d387..0365cc7fd1 100644 --- a/examples/react/ssr/package.json +++ b/examples/react/ssr/package.json @@ -22,7 +22,7 @@ "webpack-node-externals": "1.7.2" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "express": "4.17.1", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/examples/react/ssr/src/searchClient.js b/examples/react/ssr/src/searchClient.js index 376b339501..36f20ea227 100644 --- a/examples/react/ssr/src/searchClient.js +++ b/examples/react/ssr/src/searchClient.js @@ -1,4 +1,4 @@ -import algoliasearch from 'algoliasearch/lite'; +import { liteClient as algoliasearch } from 'algoliasearch/lite'; export const searchClient = algoliasearch( 'latency', diff --git a/examples/react/ssr/webpack.config.js b/examples/react/ssr/webpack.config.js index 8f62568efa..49f4a49e8f 100644 --- a/examples/react/ssr/webpack.config.js +++ b/examples/react/ssr/webpack.config.js @@ -26,7 +26,7 @@ module.exports = [ rules: [ { test: /\.js$/, - exclude: /node_modules/, + exclude: /node_modules\/(?!(algoliasearch)\/).*/, use: [ { loader: 'babel-loader', @@ -48,7 +48,7 @@ module.exports = [ rules: [ { test: /\.js$/, - exclude: /node_modules/, + exclude: /node_modules\/(?!(algoliasearch)\/).*/, use: [ { loader: 'babel-loader', diff --git a/examples/vue/default-theme/babel.config.js b/examples/vue/default-theme/babel.config.js index d4c2903fdc..d3cf113751 100644 --- a/examples/vue/default-theme/babel.config.js +++ b/examples/vue/default-theme/babel.config.js @@ -1,4 +1,5 @@ module.exports = { presets: ['@vue/app'], + plugins: ['@babel/plugin-proposal-optional-chaining'], sourceType: 'unambiguous', }; diff --git a/examples/vue/default-theme/package.json b/examples/vue/default-theme/package.json index 30fc1d9c8f..42d79ac2af 100644 --- a/examples/vue/default-theme/package.json +++ b/examples/vue/default-theme/package.json @@ -8,7 +8,7 @@ "website:examples": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build --dest ../../../website/examples/vue/default-theme" }, "dependencies": { - "algoliasearch": "4.23.2", + "algoliasearch": "5.0.0", "core-js": "2", "instantsearch.js": "4.73.4", "vue": "2.7.14", diff --git a/examples/vue/default-theme/src/App.vue b/examples/vue/default-theme/src/App.vue index 165b15acfe..418c118e75 100644 --- a/examples/vue/default-theme/src/App.vue +++ b/examples/vue/default-theme/src/App.vue @@ -123,7 +123,7 @@ `, + matchLevel: 'full' as const, + matchedWords: ['foobar'], }, }, objectID: '1', @@ -252,6 +254,8 @@ search.addWidgets([ _highlightResult: { foobar: { value: '<script>foobar</script>', + matchLevel: 'full', + matchedWords: ['foobar'], }, }, objectID: '1', @@ -268,7 +272,9 @@ search.addWidgets([ { indexId: 'index0', results: new SearchResults(helper.state, [ - createSingleSearchResponse({ hits }), + createSingleSearchResponse({ + hits, + }), ]), helper, }, @@ -295,9 +301,12 @@ search.addWidgets([ const hits = [ { + foobar: 'foobar', _highlightResult: { foobar: { value: ``, + matchLevel: 'full' as const, + matchedWords: ['foobar'], }, }, objectID: '1', diff --git a/packages/instantsearch.js/src/connectors/configure/__tests__/connectConfigure-test.ts b/packages/instantsearch.js/src/connectors/configure/__tests__/connectConfigure-test.ts index e3809dd910..9889d0394d 100644 --- a/packages/instantsearch.js/src/connectors/configure/__tests__/connectConfigure-test.ts +++ b/packages/instantsearch.js/src/connectors/configure/__tests__/connectConfigure-test.ts @@ -289,7 +289,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/configure/j configure: { refine() {}, widgetParams: { - searchParameters: { removeStopWords: ['group'] }, + searchParameters: { removeStopWords: ['en'] }, }, }, }, @@ -300,7 +300,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/configure/j refine: expect.any(Function), widgetParams: { searchParameters: { - removeStopWords: ['group'], + removeStopWords: ['en'], facetFilters: ['brand:Samsung'], }, }, diff --git a/packages/instantsearch.js/src/connectors/frequently-bought-together/connectFrequentlyBoughtTogether.ts b/packages/instantsearch.js/src/connectors/frequently-bought-together/connectFrequentlyBoughtTogether.ts index 4190ef67a9..14866a9c40 100644 --- a/packages/instantsearch.js/src/connectors/frequently-bought-together/connectFrequentlyBoughtTogether.ts +++ b/packages/instantsearch.js/src/connectors/frequently-bought-together/connectFrequentlyBoughtTogether.ts @@ -9,16 +9,14 @@ import { import type { Connector, TransformItems, - Hit, BaseHit, Renderer, Unmounter, UnknownWidgetParams, + RecommendResponse, + AlgoliaHit, } from '../../types'; -import type { - PlainSearchParameters, - RecommendResultItem, -} from 'algoliasearch-helper'; +import type { PlainSearchParameters } from 'algoliasearch-helper'; const withUsage = createDocumentationMessageGenerator({ name: 'frequently-bought-together', @@ -31,7 +29,7 @@ export type FrequentlyBoughtTogetherRenderState< /** * The matched recommendations from Algolia API. */ - items: Array>; + items: Array>; }; export type FrequentlyBoughtTogetherConnectorParams< @@ -70,7 +68,10 @@ export type FrequentlyBoughtTogetherConnectorParams< /** * Function to transform the items passed to the templates. */ - transformItems?: TransformItems, { results: RecommendResultItem }>; + transformItems?: TransformItems< + AlgoliaHit, + { results: RecommendResponse> } + >; }; export type FrequentlyBoughtTogetherWidgetDescription< @@ -156,9 +157,12 @@ export default (function connectFrequentlyBoughtTogether< results.hits = escapeHits(results.hits); } - const transformedItems = transformItems(results.hits, { - results: results as RecommendResultItem, - }); + const transformedItems = transformItems( + results.hits as Array>, + { + results: results as RecommendResponse>, + } + ); return { items: transformedItems, widgetParams }; }, diff --git a/packages/instantsearch.js/src/connectors/hits/__tests__/connectHits-test.ts b/packages/instantsearch.js/src/connectors/hits/__tests__/connectHits-test.ts index 971ff1a172..6185e2055a 100644 --- a/packages/instantsearch.js/src/connectors/hits/__tests__/connectHits-test.ts +++ b/packages/instantsearch.js/src/connectors/hits/__tests__/connectHits-test.ts @@ -178,21 +178,23 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits/js/#co expect.anything() ); - const hits = [ - { - objectID: '1', - _highlightResult: { - foobar: { - value: ``, - matchLevel: 'partial', - matchedWords: ['foobar'], - }, - }, - }, - ]; - const results = new SearchResults(helper.state, [ - createSingleSearchResponse(createSingleSearchResponse({ hits })), + createSingleSearchResponse( + createSingleSearchResponse({ + hits: [ + { + objectID: '1', + _highlightResult: { + foobar: { + value: ``, + matchLevel: 'partial', + matchedWords: ['foobar'], + }, + }, + }, + ], + }) + ), ]); widget.render( createRenderOptions({ diff --git a/packages/instantsearch.js/src/connectors/looking-similar/connectLookingSimilar.ts b/packages/instantsearch.js/src/connectors/looking-similar/connectLookingSimilar.ts index 34c86903c6..a487d5b8e8 100644 --- a/packages/instantsearch.js/src/connectors/looking-similar/connectLookingSimilar.ts +++ b/packages/instantsearch.js/src/connectors/looking-similar/connectLookingSimilar.ts @@ -9,16 +9,14 @@ import { import type { Connector, TransformItems, - Hit, BaseHit, Renderer, Unmounter, UnknownWidgetParams, + RecommendResponse, + AlgoliaHit, } from '../../types'; -import type { - PlainSearchParameters, - RecommendResultItem, -} from 'algoliasearch-helper'; +import type { PlainSearchParameters } from 'algoliasearch-helper'; const withUsage = createDocumentationMessageGenerator({ name: 'looking-similar', @@ -31,7 +29,7 @@ export type LookingSimilarRenderState< /** * The matched recommendations from the Algolia API. */ - items: Array>; + items: Array>; }; export type LookingSimilarConnectorParams< @@ -72,7 +70,10 @@ export type LookingSimilarConnectorParams< /** * Function to transform the items passed to the templates. */ - transformItems?: TransformItems, { results: RecommendResultItem }>; + transformItems?: TransformItems< + AlgoliaHit, + { results: RecommendResponse> } + >; }; export type LookingSimilarWidgetDescription< @@ -160,8 +161,8 @@ export default (function connectLookingSimilar< } return { - items: transformItems(results.hits, { - results: results as RecommendResultItem, + items: transformItems(results.hits as Array>, { + results: results as RecommendResponse>, }), widgetParams, }; diff --git a/packages/instantsearch.js/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts b/packages/instantsearch.js/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts index 067b47186b..6d396d715a 100644 --- a/packages/instantsearch.js/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts +++ b/packages/instantsearch.js/src/connectors/refinement-list/__tests__/connectRefinementList-test.ts @@ -1598,6 +1598,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const helper = jsHelper( createSearchClient({ + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues() { return Promise.resolve([ { @@ -1719,6 +1720,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const helper = jsHelper( createSearchClient({ + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues() { return Promise.resolve([ { @@ -1801,6 +1803,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const helper = jsHelper( createSearchClient({ + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues() { return Promise.resolve([ { @@ -1911,6 +1914,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const helper = jsHelper( createSearchClient({ + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues() { return Promise.resolve([ { @@ -2029,6 +2033,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const helper = jsHelper( createSearchClient({ + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues() { return Promise.resolve([ { diff --git a/packages/instantsearch.js/src/connectors/related-products/connectRelatedProducts.ts b/packages/instantsearch.js/src/connectors/related-products/connectRelatedProducts.ts index db6c8678c6..9e23a7401f 100644 --- a/packages/instantsearch.js/src/connectors/related-products/connectRelatedProducts.ts +++ b/packages/instantsearch.js/src/connectors/related-products/connectRelatedProducts.ts @@ -9,16 +9,14 @@ import { import type { Connector, TransformItems, - Hit, BaseHit, Renderer, Unmounter, UnknownWidgetParams, + RecommendResponse, + AlgoliaHit, } from '../../types'; -import type { - PlainSearchParameters, - RecommendResultItem, -} from 'algoliasearch-helper'; +import type { PlainSearchParameters } from 'algoliasearch-helper'; const withUsage = createDocumentationMessageGenerator({ name: 'related-products', @@ -31,7 +29,7 @@ export type RelatedProductsRenderState< /** * The matched recommendations from the Algolia API. */ - items: Array>; + items: Array>; }; export type RelatedProductsConnectorParams< @@ -72,7 +70,10 @@ export type RelatedProductsConnectorParams< /** * Function to transform the items passed to the templates. */ - transformItems?: TransformItems, { results: RecommendResultItem }>; + transformItems?: TransformItems< + AlgoliaHit, + { results: RecommendResponse> } + >; }; export type RelatedProductsWidgetDescription< @@ -160,8 +161,8 @@ export default (function connectRelatedProducts< } return { - items: transformItems(results.hits, { - results: results as RecommendResultItem, + items: transformItems(results.hits as Array>, { + results: results as RecommendResponse>, }), widgetParams, }; diff --git a/packages/instantsearch.js/src/connectors/trending-items/connectTrendingItems.ts b/packages/instantsearch.js/src/connectors/trending-items/connectTrendingItems.ts index 3e44e2bb1d..d6025a7abc 100644 --- a/packages/instantsearch.js/src/connectors/trending-items/connectTrendingItems.ts +++ b/packages/instantsearch.js/src/connectors/trending-items/connectTrendingItems.ts @@ -10,16 +10,14 @@ import { import type { Connector, TransformItems, - Hit, BaseHit, Renderer, Unmounter, UnknownWidgetParams, + RecommendResponse, + AlgoliaHit, } from '../../types'; -import type { - PlainSearchParameters, - RecommendResultItem, -} from 'algoliasearch-helper'; +import type { PlainSearchParameters } from 'algoliasearch-helper'; const withUsage = createDocumentationMessageGenerator({ name: 'trending-items', @@ -32,7 +30,7 @@ export type TrendingItemsRenderState< /** * The matched recommendations from the Algolia API. */ - items: Array>; + items: Array>; }; export type TrendingItemsConnectorParams< @@ -84,7 +82,10 @@ export type TrendingItemsConnectorParams< /** * Function to transform the items passed to the templates. */ - transformItems?: TransformItems, { results: RecommendResultItem }>; + transformItems?: TransformItems< + AlgoliaHit, + { results: RecommendResponse> } + >; }; export type TrendingItemsWidgetDescription< @@ -180,8 +181,8 @@ export default (function connectTrendingItems< } return { - items: transformItems(results.hits, { - results: results as RecommendResultItem, + items: transformItems(results.hits as Array>, { + results: results as RecommendResponse>, }), widgetParams, }; @@ -194,8 +195,8 @@ export default (function connectTrendingItems< getWidgetParameters(state) { return state.removeParams(this.$$id!).addTrendingItems({ - facetName, - facetValue, + facetName: facetName as string, + facetValue: facetValue as string, maxRecommendations: limit, threshold, fallbackParameters: { diff --git a/packages/instantsearch.js/src/connectors/voice-search/__tests__/connectVoiceSearch-test.ts b/packages/instantsearch.js/src/connectors/voice-search/__tests__/connectVoiceSearch-test.ts index a357de938e..01de808d1e 100644 --- a/packages/instantsearch.js/src/connectors/voice-search/__tests__/connectVoiceSearch-test.ts +++ b/packages/instantsearch.js/src/connectors/voice-search/__tests__/connectVoiceSearch-test.ts @@ -472,6 +472,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/voice-searc new SearchParameters({ ignorePlurals: true, removeStopWords: true, + // @ts-ignore we send optionalWords as a string optionalWords: 'query', queryLanguages: undefined, index: '', @@ -494,6 +495,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/voice-searc queryLanguages: ['en'], // regular removeStopWords: true, + // @ts-ignore we send optionalWords as a string optionalWords: 'query', ignorePlurals: true, query: 'query', @@ -516,6 +518,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/voice-searc new SearchParameters({ ignorePlurals: true, removeStopWords: true, + // @ts-ignore we send optionalWords as a string optionalWords: 'query', queryLanguages: undefined, index: '', diff --git a/packages/instantsearch.js/src/connectors/voice-search/connectVoiceSearch.ts b/packages/instantsearch.js/src/connectors/voice-search/connectVoiceSearch.ts index 22e9ebb2be..ad252d07f7 100644 --- a/packages/instantsearch.js/src/connectors/voice-search/connectVoiceSearch.ts +++ b/packages/instantsearch.js/src/connectors/voice-search/connectVoiceSearch.ts @@ -106,6 +106,7 @@ const connectVoiceSearch: VoiceSearchConnector = function connectVoiceSearch( const queryLanguages = language ? [language.split('-')[0]] : undefined; + // @ts-ignore queryLanguages is allowed to be a string, not just an array helper.setQueryParameter('queryLanguages', queryLanguages); if (typeof additionalQueryParameters === 'function') { @@ -113,7 +114,7 @@ const connectVoiceSearch: VoiceSearchConnector = function connectVoiceSearch( helper.state.setQueryParameters({ ignorePlurals: true, removeStopWords: true, - // @ts-ignore (optionalWords only allows array in v3, while string is also valid) + // @ts-ignore optionalWords is allowed to be a string too optionalWords: query, ...additionalQueryParameters({ query }), }) diff --git a/packages/instantsearch.js/src/lib/__tests__/InstantSearch-test.tsx b/packages/instantsearch.js/src/lib/__tests__/InstantSearch-test.tsx index 2c8153b42c..71c34bfcc4 100644 --- a/packages/instantsearch.js/src/lib/__tests__/InstantSearch-test.tsx +++ b/packages/instantsearch.js/src/lib/__tests__/InstantSearch-test.tsx @@ -486,7 +486,7 @@ See https://www.algolia.com/doc/api-reference/widgets/configure/js/`); ? { _automaticInsights: true } : undefined), index: request.indexName, - query: request.query, + query: (request as any).query || request.params.query, ...(request.indexName === 'indexNameWithAutomaticInsights' ? { queryID: 'queryID' } : undefined), diff --git a/packages/instantsearch.js/src/lib/server.ts b/packages/instantsearch.js/src/lib/server.ts index e92677305c..8e0009739c 100644 --- a/packages/instantsearch.js/src/lib/server.ts +++ b/packages/instantsearch.js/src/lib/server.ts @@ -24,7 +24,7 @@ export function waitForResults( helper.setClient({ ...client, search(queries) { - requestParamsList = queries.map(({ params }) => params!); + requestParamsList = queries.map(({ params }) => params); return client.search(queries); }, }); diff --git a/packages/instantsearch.js/src/lib/utils/__tests__/getAppIdAndApiKey-test.ts b/packages/instantsearch.js/src/lib/utils/__tests__/getAppIdAndApiKey-test.ts index 543dbbf865..710ea43499 100644 --- a/packages/instantsearch.js/src/lib/utils/__tests__/getAppIdAndApiKey-test.ts +++ b/packages/instantsearch.js/src/lib/utils/__tests__/getAppIdAndApiKey-test.ts @@ -1,5 +1,5 @@ -import algoliasearchV4 from 'algoliasearch'; import algoliasearchV3 from 'algoliasearch-v3'; +import algoliasearchV4 from 'algoliasearch-v4'; import { liteClient as algoliasearchV5 } from 'algoliasearch-v5/lite'; import { getAppIdAndApiKey } from '../getAppIdAndApiKey'; diff --git a/packages/instantsearch.js/src/lib/utils/hydrateSearchClient.ts b/packages/instantsearch.js/src/lib/utils/hydrateSearchClient.ts index 4092194030..4165fe411e 100644 --- a/packages/instantsearch.js/src/lib/utils/hydrateSearchClient.ts +++ b/packages/instantsearch.js/src/lib/utils/hydrateSearchClient.ts @@ -93,7 +93,7 @@ export function hydrateSearchClient( client.search = (requests, ...methodArgs) => { const requestsWithSerializedParams = requests.map((request) => ({ ...request, - params: serializeQueryParameters(request.params!), + params: serializeQueryParameters(request.params), })); return (client as ClientWithTransporter).transporter.responsesCache.get( diff --git a/packages/instantsearch.js/src/middlewares/__tests__/createMetadataMiddleware.ts b/packages/instantsearch.js/src/middlewares/__tests__/createMetadataMiddleware.ts index b886a2853a..60f85874ba 100644 --- a/packages/instantsearch.js/src/middlewares/__tests__/createMetadataMiddleware.ts +++ b/packages/instantsearch.js/src/middlewares/__tests__/createMetadataMiddleware.ts @@ -4,8 +4,9 @@ import { createSearchClient } from '@instantsearch/mocks'; import { wait } from '@instantsearch/testutils/wait'; -import algoliasearch from 'algoliasearch'; import algoliasearchV3 from 'algoliasearch-v3'; +import algoliasearchV4 from 'algoliasearch-v4'; +import { algoliasearch as algoliasearchV5 } from 'algoliasearch-v5'; import { createMetadataMiddleware } from '..'; import instantsearch from '../..'; @@ -236,10 +237,9 @@ describe('createMetadataMiddleware', () => { }); describe('fills it with user agent after start', () => { - it('for the v4 client', async () => { + it('for the v5 client', async () => { const fakeSearchClient = createSearchClient(); - const searchClient = algoliasearch('', ''); - // @ts-expect-error overriding the search method for testing + const searchClient = algoliasearchV5('qsdf', 'qsdf') as any; searchClient.search = fakeSearchClient.search; // not using createMetadataMiddleware() here, @@ -256,20 +256,109 @@ describe('createMetadataMiddleware', () => { expect(document.head.children).toHaveLength(1); expect(document.head.children[0]).toEqual(expect.any(HTMLMetaElement)); + const metadata = JSON.parse( + document.head.querySelector('meta')!.content + ); + + expect(metadata).toEqual({ + ua: expect.any(String), + widgets: expect.any(Array), + }); + expect( - JSON.parse(document.head.querySelector('meta')!.content) - ).toEqual({ - ua: expect.stringMatching( - /^Algolia for JavaScript \(4\.(\d+\.?)+\); Node\.js \((\d+\.?)+\); instantsearch\.js \((\d+\.?)+\); JS Helper \((\d+\.?)+\)$/ - ), + metadata.ua.split(';').map((part: string) => part.trim()) + ).toEqual([ + expect.stringMatching(/Algolia for JavaScript \(5\..*\)/), + expect.stringMatching(/Search \(5\..*\)/), + expect.stringMatching(/Node.js \(.*\)/), + expect.stringMatching(/instantsearch.js \(4\..*\)/), + expect.stringMatching(/JS Helper \(3\..*\)/), + ]); + }); + + it('for the v5 client with custom user agent', async () => { + const fakeSearchClient = createSearchClient(); + const searchClient = algoliasearchV5('qsdf', 'qsdf') as any; + searchClient.search = fakeSearchClient.search; + + // not using createMetadataMiddleware() here, + // since metadata is built into instantsearch + const search = instantsearch({ + searchClient, + indexName: 'test', + }); + + search.start(); + + searchClient.addAlgoliaAgent('test', 'cool'); + + await wait(100); + + expect(document.head.children).toHaveLength(1); + expect(document.head.children[0]).toEqual(expect.any(HTMLMetaElement)); + + const metadata = JSON.parse( + document.head.querySelector('meta')!.content + ); + + expect(metadata).toEqual({ + ua: expect.any(String), + widgets: expect.any(Array), + }); + + expect( + metadata.ua.split(';').map((part: string) => part.trim()) + ).toEqual([ + expect.stringMatching(/Algolia for JavaScript \(5\..*\)/), + expect.stringMatching(/Search \(5\..*\)/), + expect.stringMatching(/Node.js \(.*\)/), + expect.stringMatching(/instantsearch.js \(4\..*\)/), + expect.stringMatching(/JS Helper \(3\..*\)/), + 'test (cool)', + ]); + }); + + it('for the v4 client', async () => { + const fakeSearchClient = createSearchClient(); + const searchClient = algoliasearchV4('', '') as any; + searchClient.search = fakeSearchClient.search; + + // not using createMetadataMiddleware() here, + // since metadata is built into instantsearch + const search = instantsearch({ + searchClient, + indexName: 'test', + }); + + search.start(); + + await wait(100); + + expect(document.head.children).toHaveLength(1); + expect(document.head.children[0]).toEqual(expect.any(HTMLMetaElement)); + + const metadata = JSON.parse( + document.head.querySelector('meta')!.content + ); + + expect(metadata).toEqual({ + ua: expect.any(String), widgets: expect.any(Array), }); + + expect( + metadata.ua.split(';').map((part: string) => part.trim()) + ).toEqual([ + expect.stringMatching(/Algolia for JavaScript \(4\..*\)/), + expect.stringMatching(/Node.js \(.*\)/), + expect.stringMatching(/instantsearch.js \(4\..*\)/), + expect.stringMatching(/JS Helper \(3\..*\)/), + ]); }); it('for the v4 client with custom user agent', async () => { const fakeSearchClient = createSearchClient(); - const searchClient = algoliasearch('', ''); - // @ts-expect-error overriding the search method for testing + const searchClient = algoliasearchV4('', '') as any; searchClient.search = fakeSearchClient.search; // not using createMetadataMiddleware() here, @@ -288,14 +377,24 @@ describe('createMetadataMiddleware', () => { expect(document.head.children).toHaveLength(1); expect(document.head.children[0]).toEqual(expect.any(HTMLMetaElement)); - expect( - JSON.parse(document.head.querySelector('meta')!.content) - ).toEqual({ - ua: expect.stringMatching( - /^Algolia for JavaScript \(4\.(\d+\.?)+\); Node\.js \((\d+\.?)+\); instantsearch\.js \((\d+\.?)+\); JS Helper \((\d+\.?)+\); test \(cool\)$/ - ), + const metadata = JSON.parse( + document.head.querySelector('meta')!.content + ); + + expect(metadata).toEqual({ + ua: expect.any(String), widgets: expect.any(Array), }); + + expect( + metadata.ua.split(';').map((part: string) => part.trim()) + ).toEqual([ + expect.stringMatching(/Algolia for JavaScript \(4\..*\)/), + expect.stringMatching(/Node.js \(.*\)/), + expect.stringMatching(/instantsearch.js \(4\..*\)/), + expect.stringMatching(/JS Helper \(3\..*\)/), + 'test (cool)', + ]); }); it('for the v3 client', async () => { @@ -317,14 +416,23 @@ describe('createMetadataMiddleware', () => { expect(document.head.children).toHaveLength(1); expect(document.head.children[0]).toEqual(expect.any(HTMLMetaElement)); - expect( - JSON.parse(document.head.querySelector('meta')!.content) - ).toEqual({ - ua: expect.stringMatching( - /^Algolia for JavaScript \(3\.(\d+\.?)+\); Node\.js \((\d+\.?)+\); instantsearch\.js \((\d+\.?)+\); JS Helper \((\d+\.?)+\)$/ - ), + const metadata = JSON.parse( + document.head.querySelector('meta')!.content + ); + + expect(metadata).toEqual({ + ua: expect.any(String), widgets: expect.any(Array), }); + + expect( + metadata.ua.split(';').map((part: string) => part.trim()) + ).toEqual([ + expect.stringMatching(/Algolia for JavaScript \(3\..*\)/), + expect.stringMatching(/Node.js \(.*\)/), + expect.stringMatching(/instantsearch.js \(4\..*\)/), + expect.stringMatching(/JS Helper \(3\..*\)/), + ]); }); it('for the v3 client with custom user agent', async () => { @@ -348,14 +456,24 @@ describe('createMetadataMiddleware', () => { expect(document.head.children).toHaveLength(1); expect(document.head.children[0]).toEqual(expect.any(HTMLMetaElement)); - expect( - JSON.parse(document.head.querySelector('meta')!.content) - ).toEqual({ - ua: expect.stringMatching( - /^Algolia for JavaScript \(3\.(\d+\.?)+\); Node\.js \((\d+\.?)+\); instantsearch\.js \((\d+\.?)+\); JS Helper \((\d+\.?)+\); test \(cool\)$/ - ), + const metadata = JSON.parse( + document.head.querySelector('meta')!.content + ); + + expect(metadata).toEqual({ + ua: expect.any(String), widgets: expect.any(Array), }); + + expect( + metadata.ua.split(';').map((part: string) => part.trim()) + ).toEqual([ + expect.stringMatching(/Algolia for JavaScript \(3\..*\)/), + expect.stringMatching(/Node.js \(.*\)/), + expect.stringMatching(/instantsearch.js \(4\..*\)/), + expect.stringMatching(/JS Helper \(3\..*\)/), + 'test (cool)', + ]); }); it('for a custom client (does not error)', async () => { diff --git a/packages/instantsearch.js/src/types/widget.ts b/packages/instantsearch.js/src/types/widget.ts index 3888b0a06a..031339fc9d 100644 --- a/packages/instantsearch.js/src/types/widget.ts +++ b/packages/instantsearch.js/src/types/widget.ts @@ -1,4 +1,5 @@ import type { IndexWidget } from '../widgets'; +import type { RecommendResponse } from './algoliasearch'; import type { InstantSearch } from './instantsearch'; import type { IndexRenderState, WidgetRenderState } from './render-state'; import type { IndexUiState, UiState } from './ui-state'; @@ -8,7 +9,6 @@ import type { SearchParameters, SearchResults, RecommendParameters, - RecommendResultItem, } from 'algoliasearch-helper'; export type ScopedResult = { @@ -161,7 +161,7 @@ type SearchWidget = { }; type RecommendRenderOptions = SharedRenderOptions & { - results: RecommendResultItem; + results: RecommendResponse; }; type RecommendWidget< diff --git a/packages/instantsearch.js/src/widgets/frequently-bought-together/frequently-bought-together.tsx b/packages/instantsearch.js/src/widgets/frequently-bought-together/frequently-bought-together.tsx index d4a6402b6f..f4359e4214 100644 --- a/packages/instantsearch.js/src/widgets/frequently-bought-together/frequently-bought-together.tsx +++ b/packages/instantsearch.js/src/widgets/frequently-bought-together/frequently-bought-together.tsx @@ -20,11 +20,11 @@ import type { PreparedTemplateProps } from '../../lib/templating'; import type { Template, WidgetFactory, - Hit, + AlgoliaHit, Renderer, BaseHit, + RecommendResponse, } from '../../types'; -import type { RecommendResultItem } from 'algoliasearch-helper'; import type { RecommendClassNames, FrequentlyBoughtTogetherProps as FrequentlyBoughtTogetherUiProps, @@ -81,7 +81,7 @@ const renderer = /> ) : undefined - ) as FrequentlyBoughtTogetherUiProps['headerComponent']; + ) as FrequentlyBoughtTogetherUiProps['headerComponent']; const itemComponent = ( templates.item @@ -96,7 +96,7 @@ const renderer = ); } : undefined - ) as FrequentlyBoughtTogetherUiProps['itemComponent']; + ) as FrequentlyBoughtTogetherUiProps['itemComponent']; const emptyComponent = ( templates.empty @@ -109,7 +109,7 @@ const renderer = /> ) : undefined - ) as FrequentlyBoughtTogetherUiProps['emptyComponent']; + ) as FrequentlyBoughtTogetherUiProps['emptyComponent']; const layoutComponent = ( templates.layout @@ -122,7 +122,7 @@ const renderer = items: data.items, templates: { item: templates.item - ? ({ item }: { item: Hit }) => ( + ? ({ item }: { item: AlgoliaHit }) => ( ) : undefined - ) as FrequentlyBoughtTogetherUiProps['layout']; + ) as FrequentlyBoughtTogetherUiProps>['layout']; render( >} headerComponent={headerComponent} itemComponent={itemComponent} sendEvent={() => {}} @@ -165,7 +165,7 @@ export type FrequentlyBoughtTogetherTemplates< /** * Template to use when there are no results. */ - empty: Template>>; + empty: Template>>; /** * Template to use for the header of the widget. @@ -174,7 +174,7 @@ export type FrequentlyBoughtTogetherTemplates< Pick< Parameters< NonNullable< - FrequentlyBoughtTogetherUiProps>['headerComponent'] + FrequentlyBoughtTogetherUiProps>['headerComponent'] > >[0], 'items' @@ -184,7 +184,7 @@ export type FrequentlyBoughtTogetherTemplates< /** * Template to use for each result. This template will receive an object containing a single record. */ - item: Template>; + item: Template>; /** * Template to use to wrap all items. @@ -192,12 +192,14 @@ export type FrequentlyBoughtTogetherTemplates< layout: Template< Pick< Parameters< - NonNullable>['layout']> + NonNullable>['layout']> >[0], 'items' > & { templates: { - item: FrequentlyBoughtTogetherUiProps['itemComponent']; + item: FrequentlyBoughtTogetherUiProps< + AlgoliaHit + >['itemComponent']; }; cssClasses: Pick; } diff --git a/packages/instantsearch.js/src/widgets/index/__tests__/index-test.ts b/packages/instantsearch.js/src/widgets/index/__tests__/index-test.ts index 237ab721ea..29fe4d1bee 100644 --- a/packages/instantsearch.js/src/widgets/index/__tests__/index-test.ts +++ b/packages/instantsearch.js/src/widgets/index/__tests__/index-test.ts @@ -4,6 +4,7 @@ import { createSearchClient, + createSingleRecommendResponse, createSingleSearchResponse, } from '@instantsearch/mocks'; import { wait } from '@instantsearch/testutils'; @@ -3484,7 +3485,9 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index-widge recommendResults: { params: [{ $$id: 0, objectID: '1' }], results: { - 0: createSingleSearchResponse({ hits: [{ objectID: '1' }] }), + 0: createSingleRecommendResponse({ + hits: [{ objectID: '1', _score: 0 }], + }), }, }, }, @@ -3497,7 +3500,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index-widge 0: { exhaustiveFacetsCount: true, exhaustiveNbHits: true, - hits: [{ objectID: '1' }], + hits: [{ objectID: '1', _score: 0 }], hitsPerPage: 20, nbHits: 1, nbPages: 1, @@ -3513,7 +3516,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index-widge 0: { exhaustiveFacetsCount: true, exhaustiveNbHits: true, - hits: [{ objectID: '1' }], + hits: [{ objectID: '1', _score: 0 }], hitsPerPage: 20, nbHits: 1, nbPages: 1, diff --git a/packages/instantsearch.js/src/widgets/index/index.ts b/packages/instantsearch.js/src/widgets/index/index.ts index 79c05b938c..1818b65a19 100644 --- a/packages/instantsearch.js/src/widgets/index/index.ts +++ b/packages/instantsearch.js/src/widgets/index/index.ts @@ -21,6 +21,7 @@ import type { SearchClient, IndexRenderState, RenderOptions, + RecommendResponse, } from '../../types'; import type { AlgoliaSearchHelper as Helper, @@ -30,7 +31,6 @@ import type { SearchResults, AlgoliaSearchHelper, RecommendParameters, - RecommendResultItem, } from 'algoliasearch-helper'; const withUsage = createDocumentationMessageGenerator({ @@ -77,7 +77,7 @@ export type IndexWidget = Omit< getResults: () => SearchResults | null; getResultsForWidget: ( widget: IndexWidget | Widget - ) => SearchResults | RecommendResultItem | null; + ) => SearchResults | RecommendResponse | null; getPreviousState: () => SearchParameters | null; getScopedResults: () => ScopedResult[]; getParent: () => IndexWidget | null; diff --git a/packages/instantsearch.js/src/widgets/looking-similar/looking-similar.tsx b/packages/instantsearch.js/src/widgets/looking-similar/looking-similar.tsx index 3d73ee591c..d7ac33878d 100644 --- a/packages/instantsearch.js/src/widgets/looking-similar/looking-similar.tsx +++ b/packages/instantsearch.js/src/widgets/looking-similar/looking-similar.tsx @@ -20,11 +20,11 @@ import type { PreparedTemplateProps } from '../../lib/templating'; import type { Template, WidgetFactory, - Hit, + AlgoliaHit, Renderer, BaseHit, + RecommendResponse, } from '../../types'; -import type { RecommendResultItem } from 'algoliasearch-helper'; import type { RecommendClassNames, LookingSimilarProps as LookingSimilarUiProps, @@ -77,7 +77,7 @@ function createRenderer = BaseHit>({ /> ) : undefined - ) as LookingSimilarUiProps['headerComponent']; + ) as LookingSimilarUiProps['headerComponent']; const itemComponent = ( templates.item @@ -92,7 +92,7 @@ function createRenderer = BaseHit>({ ); } : undefined - ) as LookingSimilarUiProps['itemComponent']; + ) as LookingSimilarUiProps['itemComponent']; const emptyComponent = ( templates.empty @@ -105,7 +105,7 @@ function createRenderer = BaseHit>({ /> ) : undefined - ) as LookingSimilarUiProps['emptyComponent']; + ) as LookingSimilarUiProps['emptyComponent']; const layoutComponent = ( templates.layout @@ -118,7 +118,7 @@ function createRenderer = BaseHit>({ items: data.items, templates: { item: templates.item - ? ({ item }: { item: Hit }) => ( + ? ({ item }: { item: AlgoliaHit }) => ( = BaseHit>({ /> ) : undefined - ) as LookingSimilarUiProps['layout']; + ) as LookingSimilarUiProps>['layout']; render( >} headerComponent={headerComponent} itemComponent={itemComponent} sendEvent={() => {}} @@ -162,7 +162,7 @@ export type LookingSimilarTemplates< /** * Template to use when there are no results. */ - empty: Template>>; + empty: Template>>; /** * Template to use for the header of the widget. @@ -170,7 +170,7 @@ export type LookingSimilarTemplates< header: Template< Pick< Parameters< - NonNullable>['headerComponent']> + NonNullable>['headerComponent']> >[0], 'items' > & { cssClasses: RecommendClassNames } @@ -179,18 +179,20 @@ export type LookingSimilarTemplates< /** * Template to use for each result. This template will receive an object containing a single record. */ - item: Template>; + item: Template>; /** * Template to use to wrap all items. */ layout: Template< Pick< - Parameters>['layout']>>[0], + Parameters< + NonNullable>['layout']> + >[0], 'items' > & { templates: { - item: LookingSimilarUiProps['itemComponent']; + item: LookingSimilarUiProps>['itemComponent']; }; cssClasses: Pick; } diff --git a/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx b/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx index 058481e8e0..6580c77891 100644 --- a/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx +++ b/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx @@ -1182,6 +1182,7 @@ function createMockedSearchClient() { ) ); }), + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues: jest.fn((requests) => { return Promise.resolve([ createSFFVResponse({ diff --git a/packages/instantsearch.js/src/widgets/related-products/related-products.tsx b/packages/instantsearch.js/src/widgets/related-products/related-products.tsx index 366a6bd354..7f14f24a8e 100644 --- a/packages/instantsearch.js/src/widgets/related-products/related-products.tsx +++ b/packages/instantsearch.js/src/widgets/related-products/related-products.tsx @@ -20,11 +20,11 @@ import type { PreparedTemplateProps } from '../../lib/templating'; import type { Template, WidgetFactory, - Hit, + AlgoliaHit, Renderer, BaseHit, + RecommendResponse, } from '../../types'; -import type { RecommendResultItem } from 'algoliasearch-helper'; import type { RecommendClassNames, RelatedProductsProps as RelatedProductsUiProps, @@ -87,7 +87,7 @@ function createRenderer = BaseHit>({ /> ) : undefined - ) as RelatedProductsUiProps['headerComponent']; + ) as RelatedProductsUiProps['headerComponent']; const itemComponent = ( templates.item @@ -102,7 +102,7 @@ function createRenderer = BaseHit>({ ); } : undefined - ) as RelatedProductsUiProps['itemComponent']; + ) as RelatedProductsUiProps['itemComponent']; const emptyComponent = ( templates.empty @@ -115,7 +115,7 @@ function createRenderer = BaseHit>({ /> ) : undefined - ) as RelatedProductsUiProps['emptyComponent']; + ) as RelatedProductsUiProps['emptyComponent']; const layoutComponent = ( templates.layout @@ -128,7 +128,7 @@ function createRenderer = BaseHit>({ items: data.items, templates: { item: templates.item - ? ({ item }: { item: Hit }) => ( + ? ({ item }: { item: AlgoliaHit }) => ( = BaseHit>({ /> ) : undefined - ) as RelatedProductsUiProps['layout']; + ) as RelatedProductsUiProps>['layout']; render( >} sendEvent={() => {}} classNames={cssClasses} headerComponent={headerComponent} @@ -172,7 +172,7 @@ export type RelatedProductsTemplates< /** * Template to use when there are no results. */ - empty: Template>>; + empty: Template>>; /** * Template to use for the header of the widget. @@ -180,7 +180,7 @@ export type RelatedProductsTemplates< header: Template< Pick< Parameters< - NonNullable>['headerComponent']> + NonNullable>['headerComponent']> >[0], 'items' > & { cssClasses: RecommendClassNames } @@ -189,18 +189,20 @@ export type RelatedProductsTemplates< /** * Template to use for each result. This template will receive an object containing a single record. */ - item: Template>; + item: Template>; /** * Template to use to wrap all items. */ layout: Template< Pick< - Parameters>['layout']>>[0], + Parameters< + NonNullable>['layout']> + >[0], 'items' > & { templates: { - item: RelatedProductsUiProps['itemComponent']; + item: RelatedProductsUiProps>['itemComponent']; }; cssClasses: Pick; } diff --git a/packages/instantsearch.js/src/widgets/trending-items/trending-items.tsx b/packages/instantsearch.js/src/widgets/trending-items/trending-items.tsx index c92b883864..706a5f90e7 100644 --- a/packages/instantsearch.js/src/widgets/trending-items/trending-items.tsx +++ b/packages/instantsearch.js/src/widgets/trending-items/trending-items.tsx @@ -20,11 +20,11 @@ import type { PreparedTemplateProps } from '../../lib/templating'; import type { Template, WidgetFactory, - Hit, + AlgoliaHit, Renderer, BaseHit, + RecommendResponse, } from '../../types'; -import type { RecommendResultItem } from 'algoliasearch-helper'; import type { RecommendClassNames, TrendingItemsProps as TrendingItemsUiProps, @@ -87,7 +87,7 @@ function createRenderer = BaseHit>({ /> ) : undefined - ) as TrendingItemsUiProps['headerComponent']; + ) as TrendingItemsUiProps['headerComponent']; const itemComponent = ( templates.item @@ -102,7 +102,7 @@ function createRenderer = BaseHit>({ ); } : undefined - ) as TrendingItemsUiProps['itemComponent']; + ) as TrendingItemsUiProps['itemComponent']; const emptyComponent = ( templates.empty @@ -115,7 +115,7 @@ function createRenderer = BaseHit>({ /> ) : undefined - ) as TrendingItemsUiProps['emptyComponent']; + ) as TrendingItemsUiProps['emptyComponent']; const layoutComponent = ( templates.layout @@ -128,7 +128,7 @@ function createRenderer = BaseHit>({ items: data.items, templates: { item: templates.item - ? ({ item }: { item: Hit }) => ( + ? ({ item }: { item: AlgoliaHit }) => ( = BaseHit>({ /> ) : undefined - ) as TrendingItemsUiProps['layout']; + ) as TrendingItemsUiProps>['layout']; render( >} sendEvent={() => {}} classNames={cssClasses} headerComponent={headerComponent} @@ -171,7 +171,7 @@ export type TrendingItemsTemplates = BaseHit> = /** * Template to use when there are no results. */ - empty: Template>>; + empty: Template>>; /** * Template to use for the header of the widget. @@ -179,7 +179,7 @@ export type TrendingItemsTemplates = BaseHit> = header: Template< Pick< Parameters< - NonNullable>['headerComponent']> + NonNullable>['headerComponent']> >[0], 'items' > & { cssClasses: RecommendClassNames } @@ -188,18 +188,20 @@ export type TrendingItemsTemplates = BaseHit> = /** * Template to use for each result. This template will receive an object containing a single record. */ - item: Template>; + item: Template>; /** * Template to use to wrap all items. */ layout: Template< Pick< - Parameters>['layout']>>[0], + Parameters< + NonNullable>['layout']> + >[0], 'items' > & { templates: { - item: TrendingItemsUiProps['itemComponent']; + item: TrendingItemsUiProps>['itemComponent']; }; cssClasses: Pick; } diff --git a/packages/instantsearch.js/src/widgets/voice-search/__tests__/voice-search-test.ts b/packages/instantsearch.js/src/widgets/voice-search/__tests__/voice-search-test.ts index ea946a5bcd..210d147dc8 100644 --- a/packages/instantsearch.js/src/widgets/voice-search/__tests__/voice-search-test.ts +++ b/packages/instantsearch.js/src/widgets/voice-search/__tests__/voice-search-test.ts @@ -2,9 +2,11 @@ * @jest-environment jsdom */ -import { createSingleSearchResponse } from '@instantsearch/mocks'; +import { + createSearchClient, + createSingleSearchResponse, +} from '@instantsearch/mocks'; import { castToJestMock } from '@instantsearch/testutils/castToJestMock'; -import algoliasearch from 'algoliasearch'; import algoliasearchHelper, { SearchResults, SearchParameters, @@ -84,7 +86,7 @@ describe('voiceSearch()', () => { beforeEach(() => { render.mockClear(); - helper = algoliasearchHelper(algoliasearch('APP_ID', 'API_KEY'), '', {}); + helper = algoliasearchHelper(createSearchClient(), '', {}); helper.setQuery = jest.fn(); helper.search = jest.fn(); helper.state = new SearchParameters({ query: '' }); diff --git a/packages/instantsearch.js/stories/geo-search.stories.ts b/packages/instantsearch.js/stories/geo-search.stories.ts index 95090aa221..4ac7622906 100644 --- a/packages/instantsearch.js/stories/geo-search.stories.ts +++ b/packages/instantsearch.js/stories/geo-search.stories.ts @@ -1,6 +1,5 @@ import { action } from '@storybook/addon-actions'; import { storiesOf } from '@storybook/html'; -import algoliaPlaces from 'places.js'; import injectScript from 'scriptjs'; import { withHits, withLifecycle } from '../.storybook/decorators'; @@ -96,40 +95,6 @@ stories ) ); -// With Places -stories.add( - 'with position from Places', - withHitsAndConfigure(({ search, container, instantsearch }) => - injectGoogleMaps(() => { - const placesElement = document.createElement('input'); - const mapElement = document.createElement('div'); - mapElement.style.marginTop = '20px'; - - container.appendChild(placesElement); - container.appendChild(mapElement); - - search.addWidgets([ - instantsearch.widgets.configure({ - aroundRadius: 20000, - }), - - instantsearch.widgets.places({ - placesReference: algoliaPlaces, - container: placesElement, - defaultPosition: ['37.7793', '-122.419'], - }), - - instantsearch.widgets.geoSearch({ - googleReference: window.google, - container: mapElement, - enableClearMapRefinement: false, - initialZoom, - }), - ]); - }) - ) -); - // Only UI stories .add( diff --git a/packages/react-instantsearch-core/src/components/__tests__/InstantSearchSSRProvider.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/InstantSearchSSRProvider.test.tsx index fc9ff38d4d..8550583390 100644 --- a/packages/react-instantsearch-core/src/components/__tests__/InstantSearchSSRProvider.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/InstantSearchSSRProvider.test.tsx @@ -9,7 +9,8 @@ import { } from '@instantsearch/mocks'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import algoliasearch from 'algoliasearch'; +import algoliasearchV4 from 'algoliasearch-v4'; +import { algoliasearch as algoliasearchV5 } from 'algoliasearch-v5'; import { history } from 'instantsearch.js/es/lib/routers'; import { simple } from 'instantsearch.js/es/lib/stateMappings'; import React, { StrictMode } from 'react'; @@ -18,7 +19,7 @@ import { Hits, RefinementList, SearchBox } from 'react-instantsearch'; import { InstantSearch } from '../InstantSearch'; import { InstantSearchSSRProvider } from '../InstantSearchSSRProvider'; -import type { Hit as AlgoliaHit } from 'instantsearch.js'; +import type { Hit as AlgoliaHit, SearchClient } from 'instantsearch.js'; function HitComponent({ hit }: { hit: AlgoliaHit }) { return <>{hit.objectID}; @@ -471,66 +472,72 @@ describe('InstantSearchSSRProvider', () => { }); }); - test('caches the initial results to avoid a client-side request', async () => { - const send = jest.fn(() => - Promise.resolve({ - content: JSON.stringify(createMultiSearchResponse()), - isTimedOut: false, - status: 200, - }) - ); - const searchClient = algoliasearch('appId', 'apiKey', { - requester: { send }, - }); - const initialResults = { - indexName: { - state: {}, - results: [ - { - exhaustiveFacetsCount: true, - exhaustiveNbHits: true, - hits: [{ objectID: '1' }, { objectID: '2' }, { objectID: '3' }], - hitsPerPage: 20, - index: 'indexName', - nbHits: 0, - nbPages: 0, - page: 0, - params: '', - processingTimeMS: 0, - query: '', - }, - ], - }, - }; - - function App() { - return ( - - - - - - - + test.each([ + ['v4', algoliasearchV4], + ['v5', algoliasearchV5], + ])( + 'caches the initial results to avoid a client-side request (%s)', + async (_, ctor) => { + const send = jest.fn(() => + Promise.resolve({ + content: JSON.stringify(createMultiSearchResponse()), + isTimedOut: false, + status: 200, + }) ); - } + const searchClient = ctor('appId', 'apiKey', { + requester: { send }, + }) as unknown as SearchClient; + const initialResults = { + indexName: { + state: {}, + results: [ + { + exhaustiveFacetsCount: true, + exhaustiveNbHits: true, + hits: [{ objectID: '1' }, { objectID: '2' }, { objectID: '3' }], + hitsPerPage: 20, + index: 'indexName', + nbHits: 0, + nbPages: 0, + page: 0, + params: '', + processingTimeMS: 0, + query: '', + }, + ], + }, + }; + + function App() { + return ( + + + + + + + + ); + } - render(); + render(); - await waitFor(() => { - expect(send).toHaveBeenCalledTimes(0); - }); + await waitFor(() => { + expect(send).toHaveBeenCalledTimes(0); + }); - userEvent.type(screen.getByRole('searchbox'), 'i'); + userEvent.type(screen.getByRole('searchbox'), 'i'); - await waitFor(() => { - expect(send).toHaveBeenCalledTimes(1); - }); + await waitFor(() => { + expect(send).toHaveBeenCalledTimes(1); + }); - userEvent.clear(screen.getByRole('searchbox')); + userEvent.clear(screen.getByRole('searchbox')); - await waitFor(() => { - expect(send).toHaveBeenCalledTimes(1); - }); - }); + await waitFor(() => { + expect(send).toHaveBeenCalledTimes(1); + }); + } + ); }); diff --git a/packages/react-instantsearch-nextjs/src/InitializePromise.tsx b/packages/react-instantsearch-nextjs/src/InitializePromise.tsx index 1b98293c0e..2fb3e96509 100644 --- a/packages/react-instantsearch-nextjs/src/InitializePromise.tsx +++ b/packages/react-instantsearch-nextjs/src/InitializePromise.tsx @@ -36,7 +36,7 @@ export function InitializePromise({ nonce }: InitializePromiseProps) { search.mainHelper!.setClient({ ...search.mainHelper!.getClient(), search(queries) { - requestParamsList = queries.map(({ params }) => params!); + requestParamsList = queries.map(({ params }) => params); return search.client.search(queries); }, }); diff --git a/packages/react-instantsearch/src/widgets/FrequentlyBoughtTogether.tsx b/packages/react-instantsearch/src/widgets/FrequentlyBoughtTogether.tsx index 8d35263b55..1253726851 100644 --- a/packages/react-instantsearch/src/widgets/FrequentlyBoughtTogether.tsx +++ b/packages/react-instantsearch/src/widgets/FrequentlyBoughtTogether.tsx @@ -9,11 +9,11 @@ import type { FrequentlyBoughtTogetherProps as FrequentlyBoughtTogetherPropsUiComponentProps, Pragma, } from 'instantsearch-ui-components'; -import type { Hit, BaseHit } from 'instantsearch.js'; +import type { AlgoliaHit, BaseHit } from 'instantsearch.js'; import type { UseFrequentlyBoughtTogetherProps } from 'react-instantsearch-core'; type UiProps = Pick< - FrequentlyBoughtTogetherPropsUiComponentProps>, + FrequentlyBoughtTogetherPropsUiComponentProps>, | 'items' | 'itemComponent' | 'headerComponent' @@ -24,7 +24,7 @@ type UiProps = Pick< >; export type FrequentlyBoughtTogetherProps = Omit< - FrequentlyBoughtTogetherPropsUiComponentProps>, + FrequentlyBoughtTogetherPropsUiComponentProps>, keyof UiProps > & UseFrequentlyBoughtTogetherProps & { diff --git a/packages/react-instantsearch/src/widgets/LookingSimilar.tsx b/packages/react-instantsearch/src/widgets/LookingSimilar.tsx index 7655331b24..245aea92c0 100644 --- a/packages/react-instantsearch/src/widgets/LookingSimilar.tsx +++ b/packages/react-instantsearch/src/widgets/LookingSimilar.tsx @@ -6,11 +6,11 @@ import type { LookingSimilarProps as LookingSimilarPropsUiComponentProps, Pragma, } from 'instantsearch-ui-components'; -import type { Hit, BaseHit } from 'instantsearch.js'; +import type { AlgoliaHit, BaseHit } from 'instantsearch.js'; import type { UseLookingSimilarProps } from 'react-instantsearch-core'; type UiProps = Pick< - LookingSimilarPropsUiComponentProps>, + LookingSimilarPropsUiComponentProps>, | 'items' | 'itemComponent' | 'headerComponent' @@ -21,7 +21,7 @@ type UiProps = Pick< >; export type LookingSimilarProps = Omit< - LookingSimilarPropsUiComponentProps>, + LookingSimilarPropsUiComponentProps>, keyof UiProps > & UseLookingSimilarProps & { diff --git a/packages/react-instantsearch/src/widgets/RelatedProducts.tsx b/packages/react-instantsearch/src/widgets/RelatedProducts.tsx index 0c8cc33c04..788042bc95 100644 --- a/packages/react-instantsearch/src/widgets/RelatedProducts.tsx +++ b/packages/react-instantsearch/src/widgets/RelatedProducts.tsx @@ -6,7 +6,7 @@ import type { RelatedProductsProps as RelatedProductsUiComponentProps, Pragma, } from 'instantsearch-ui-components'; -import type { Hit, BaseHit } from 'instantsearch.js'; +import type { AlgoliaHit, BaseHit } from 'instantsearch.js'; import type { UseRelatedProductsProps } from 'react-instantsearch-core'; type UiProps = Pick< @@ -76,7 +76,7 @@ export function RelatedProducts({ : undefined; const uiProps: UiProps = { - items: items as Array>, + items: items as Array>, itemComponent, headerComponent, emptyComponent, diff --git a/packages/react-instantsearch/src/widgets/TrendingItems.tsx b/packages/react-instantsearch/src/widgets/TrendingItems.tsx index 1f245a336e..a4d22b5f37 100644 --- a/packages/react-instantsearch/src/widgets/TrendingItems.tsx +++ b/packages/react-instantsearch/src/widgets/TrendingItems.tsx @@ -6,7 +6,7 @@ import type { TrendingItemsProps as TrendingItemsUiComponentProps, Pragma, } from 'instantsearch-ui-components'; -import type { Hit, BaseHit } from 'instantsearch.js'; +import type { AlgoliaHit, BaseHit } from 'instantsearch.js'; import type { UseTrendingItemsProps } from 'react-instantsearch-core'; type UiProps = Pick< @@ -80,7 +80,7 @@ export function TrendingItems({ : undefined; const uiProps: UiProps = { - items: items as Array>, + items: items as Array>, itemComponent, headerComponent, emptyComponent, diff --git a/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx index 492fe4fad9..db939e5c7c 100644 --- a/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx @@ -104,6 +104,7 @@ function createMockedSearchClient(parameters: Record = {}) { ) ); }), + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues: jest.fn(() => Promise.resolve([ createSFFVResponse({ diff --git a/packages/vue-instantsearch/.storybook/webpack.config.js b/packages/vue-instantsearch/.storybook/webpack.config.js new file mode 100644 index 0000000000..e639745de6 --- /dev/null +++ b/packages/vue-instantsearch/.storybook/webpack.config.js @@ -0,0 +1,18 @@ +const webpack = require('webpack'); + +module.exports = ({ config, mode }) => { + config.module.rules.push({ + test: /\.(js|ts|tsx)$/, + exclude: /node_modules\/(?!(algoliasearch)\/).*/, + use: [ + { + loader: 'babel-loader', + options: { + rootMode: 'upward', + }, + }, + ], + }); + + return config; +}; diff --git a/scripts/legacy/downgrade-algoliasearch-dependency.js b/scripts/legacy/downgrade-algoliasearch-dependency.js index d79da39dd9..ac608d4007 100755 --- a/scripts/legacy/downgrade-algoliasearch-dependency.js +++ b/scripts/legacy/downgrade-algoliasearch-dependency.js @@ -23,7 +23,7 @@ console.log( // change main dependency shell.sed( '-i', - /"algoliasearch": "4.*"(,?)/, + /"algoliasearch": "5.*"(,?)/, '"algoliasearch": "3.35.1","@types/algoliasearch": "3.34.10"$1', packageJsonPaths ); @@ -31,17 +31,29 @@ shell.sed( // remove other v4 dependencies shell.sed( '-i', - /"@algolia\/(cache-.*|client-.*|logger-.*|requester-.*|transporter)": "4.*",?/, + /"@algolia\/(cache-.*|client-.*|logger-.*|requester-.*|transporter|recommend)": "(4|5).*",?/, '', packageJsonPaths ); -// remove v5 dependency +// remove resolution +shell.sed('-i', /"places.js\/algoliasearch": "5.*"(,?)/, '', packageJsonPaths); + +// replace import in examples shell.sed( '-i', - /"algoliasearch-v5": "npm:algoliasearch@5.*"(,?)/, - '', - packageJsonPaths + /import { liteClient as algoliasearch } from 'algoliasearch\/lite'/, + "import algoliasearch from 'algoliasearch/lite'", + ...shell.ls('examples/*/*/*.{js,ts,tsx,vue}'), + ...shell.ls('examples/*/*/{src,pages,app}/*.{js,ts,tsx,vue}') +); + +// replace dependency in examples +shell.sed( + '-i', + /"algoliasearch": ".*"(,)?/, + '"algoliasearch": "3.35.1","@types/algoliasearch": "3.34.10"$1', + ...shell.ls('examples/*/*/package.json') ); shell.exec('yarn install'); diff --git a/scripts/legacy/downgrade-algoliasearch-v4.js b/scripts/legacy/downgrade-algoliasearch-v4.js new file mode 100755 index 0000000000..bbf378e0a6 --- /dev/null +++ b/scripts/legacy/downgrade-algoliasearch-v4.js @@ -0,0 +1,67 @@ +#!/usr/bin/env node +const path = require('path'); + +const shell = require('shelljs'); + +const packageJsonPaths = [ + path.resolve(__dirname, '../../package.json'), + ...JSON.parse( + shell.exec( + "yarn run --silent lerna list --json --all --ignore='example-*'", + { + silent: true, + } + ).stdout + ).map(({ location }) => path.resolve(location, 'package.json')), +]; + +console.log( + `Downgrading algoliasearch dependency to v4 in: +- ${packageJsonPaths.join('\n- ')}` +); + +// change main dependency +shell.sed( + '-i', + /"algoliasearch": "5.*"(,?)/, + '"algoliasearch": "4.23.2"$1', + packageJsonPaths +); + +// Downgrade other dependency +shell.sed( + '-i', + /"@algolia\/client-search": "5.*"(,?)/, + '"@algolia/client-search": "4.23.2"$1', + packageJsonPaths +); + +// remove resolution +shell.sed('-i', /"@algolia\/client-common": "5.*"(,?)/, '', packageJsonPaths); +shell.sed( + '-i', + /"places.js\/algoliasearch": "5.*"(,?)/, + '"places.js/algoliasearch": "4.23.2"$1', + packageJsonPaths +); + +// replace import in examples +shell.sed( + '-i', + /import { liteClient as algoliasearch } from 'algoliasearch\/lite'/, + "import algoliasearch from 'algoliasearch/lite'", + ...shell.ls('examples/*/*/*.{js,ts,tsx,vue}'), + ...shell.ls('examples/*/*/{src,pages,app}/*.{js,ts,tsx,vue}') +); + +// replace dependency in examples +shell.sed( + '-i', + /"algoliasearch": ".*"(,)?/, + '"algoliasearch": "4.23.2"$1', + ...shell.ls('examples/*/*/package.json') +); + +shell.exec('yarn install'); + +shell.exec('cp -r node_modules/algoliasearch-v4 node_modules/algoliasearch'); diff --git a/tests/common/connectors/pagination/routing.ts b/tests/common/connectors/pagination/routing.ts index d39dbd88fc..7f260f0b33 100644 --- a/tests/common/connectors/pagination/routing.ts +++ b/tests/common/connectors/pagination/routing.ts @@ -41,7 +41,7 @@ export function createRoutingTests( return createMultiSearchResponse( ...requests.map(({ params }) => createSingleSearchResponse({ - page: params!.page, + page: params.page, nbPages: 20, }) ) diff --git a/tests/common/shared/insights.ts b/tests/common/shared/insights.ts index 6be8fcff88..a8cf693626 100644 --- a/tests/common/shared/insights.ts +++ b/tests/common/shared/insights.ts @@ -39,7 +39,7 @@ export function createInsightsTests( params, }: Parameters[0][number]) => createSingleSearchResponse({ - // @ts-expect-error this key is private, thus not in the types + // @ts-ignore this key doesn't exist in v3, v4 types _automaticInsights: true, hits: [{ objectID: '1' }], facets: { @@ -48,7 +48,7 @@ export function createInsightsTests( Apple: 200, }, }, - page: params!.page, + page: params.page, nbPages: 20, }) ) @@ -131,7 +131,7 @@ export function createInsightsTests( Apple: 200, }, }, - page: params!.page, + page: params.page, nbPages: 20, }) ) diff --git a/tests/common/shared/routing.ts b/tests/common/shared/routing.ts index 1b4e72c4b2..60a260e1a5 100644 --- a/tests/common/shared/routing.ts +++ b/tests/common/shared/routing.ts @@ -51,7 +51,7 @@ export function createRoutingTests( Apple: 200, }, }, - page: params!.page, + page: params.page, nbPages: 20, }) ) diff --git a/tests/common/widgets/infinite-hits/optimistic-ui.ts b/tests/common/widgets/infinite-hits/optimistic-ui.ts index d01737aab4..5a25cd014a 100644 --- a/tests/common/widgets/infinite-hits/optimistic-ui.ts +++ b/tests/common/widgets/infinite-hits/optimistic-ui.ts @@ -33,11 +33,11 @@ export function createOptimisticUiTests( createSingleSearchResponse({ hits: Array.from({ length: hitsPerPage }).map( (_, index) => ({ - objectID: `${params!.page! * hitsPerPage + index}`, + objectID: `${params.page! * hitsPerPage + index}`, }) ), - query: params!.query, - page: params!.page, + query: params.query, + page: params.page, nbPages: 20, }) ) @@ -108,11 +108,11 @@ export function createOptimisticUiTests( createSingleSearchResponse({ hits: Array.from({ length: hitsPerPage }).map( (_, index) => ({ - objectID: `${params!.page! * hitsPerPage + index}`, + objectID: `${params.page! * hitsPerPage + index}`, }) ), - query: params!.query, - page: params!.page, + query: params.query, + page: params.page, nbPages: 20, }) ) @@ -186,11 +186,11 @@ export function createOptimisticUiTests( createSingleSearchResponse({ hits: Array.from({ length: hitsPerPage }).map( (_, index) => ({ - objectID: `${params!.page! * hitsPerPage + index}`, + objectID: `${params.page! * hitsPerPage + index}`, }) ), - query: params!.query, - page: params!.page, + query: params.query, + page: params.page, nbPages: 20, }) ) diff --git a/tests/common/widgets/instantsearch/algolia-agent.ts b/tests/common/widgets/instantsearch/algolia-agent.ts index 95a97f9cd4..6abd3c3860 100644 --- a/tests/common/widgets/instantsearch/algolia-agent.ts +++ b/tests/common/widgets/instantsearch/algolia-agent.ts @@ -1,15 +1,65 @@ -import algoliasearch from 'algoliasearch'; +import algoliasearchV3 from 'algoliasearch-v3'; +import algoliasearchV4 from 'algoliasearch-v4'; +import { algoliasearch as algoliasearchV5 } from 'algoliasearch-v5'; import type { InstantSearchWidgetSetup } from '.'; import type { TestOptions } from '../../common'; +import type { SearchClient } from 'instantsearch.js'; export function createAlgoliaAgentTests( setup: InstantSearchWidgetSetup, _options: Required ) { describe('algolia agent', () => { + test('sets the correct algolia agents with v3', async () => { + const searchClient = algoliasearchV3( + 'appId', + 'apiKey' + ) as unknown as SearchClient; + const options = { + instantSearchOptions: { + indexName: 'indexName', + searchClient, + }, + widgetParams: {}, + }; + + const { algoliaAgents } = await setup(options); + + const algoliaAgent: string = getAgent(searchClient); + + expect(algoliaAgent.split(';').map((agent) => agent.trim())).toEqual( + expect.arrayContaining(algoliaAgents) + ); + }); + + test('sets the correct algolia agents with v4', async () => { + const searchClient = algoliasearchV4( + 'appId', + 'apiKey' + ) as unknown as SearchClient; + const options = { + instantSearchOptions: { + indexName: 'indexName', + searchClient, + }, + widgetParams: {}, + }; + + const { algoliaAgents } = await setup(options); + + const algoliaAgent: string = getAgent(searchClient); + + expect(algoliaAgent.split(';').map((agent) => agent.trim())).toEqual( + expect.arrayContaining(algoliaAgents) + ); + }); + test('sets the correct algolia agents', async () => { - const searchClient = algoliasearch('appId', 'apiKey'); + const searchClient = algoliasearchV5( + 'appId', + 'apiKey' + ) as unknown as SearchClient; const options = { instantSearchOptions: { indexName: 'indexName', @@ -20,9 +70,7 @@ export function createAlgoliaAgentTests( const { algoliaAgents } = await setup(options); - const algoliaAgent: string = (searchClient as any).transporter - ? (searchClient as any).transporter.userAgent.value - : (searchClient as any)._ua; + const algoliaAgent: string = getAgent(searchClient); expect(algoliaAgent.split(';').map((agent) => agent.trim())).toEqual( expect.arrayContaining(algoliaAgents) @@ -30,3 +78,17 @@ export function createAlgoliaAgentTests( }); }); } + +function getAgent(searchClient: any) { + if (searchClient.transporter && searchClient.transporter.userAgent) { + return searchClient.transporter.userAgent.value; + } + if (searchClient.transporter && searchClient.transporter.algoliaAgent) { + return searchClient.transporter.algoliaAgent.value; + } + if (searchClient._ua) { + return searchClient._ua; + } + + throw new Error('Could not find the algolia agent'); +} diff --git a/tests/common/widgets/pagination/optimistic-ui.ts b/tests/common/widgets/pagination/optimistic-ui.ts index 0665685196..39ade775d7 100644 --- a/tests/common/widgets/pagination/optimistic-ui.ts +++ b/tests/common/widgets/pagination/optimistic-ui.ts @@ -26,7 +26,7 @@ export function createOptimisticUiTests( return createMultiSearchResponse( ...requests.map(({ params }) => createSingleSearchResponse({ - page: params!.page, + page: params.page, nbPages: 20, }) ) @@ -148,7 +148,7 @@ export function createOptimisticUiTests( return createMultiSearchResponse( ...requests.map(({ params }) => createSingleSearchResponse({ - page: params!.page, + page: params.page, nbPages: 20, }) ) diff --git a/tests/common/widgets/refinement-list/options.ts b/tests/common/widgets/refinement-list/options.ts index a6691fdc80..87abf5e225 100644 --- a/tests/common/widgets/refinement-list/options.ts +++ b/tests/common/widgets/refinement-list/options.ts @@ -1,6 +1,6 @@ import { - createAlgoliaSearchClient, createMultiSearchResponse, + createSearchClient, createSFFVResponse, createSingleSearchResponse, } from '@instantsearch/mocks'; @@ -1491,7 +1491,7 @@ const FACET_HITS = [ ]; function createMockedSearchClient(parameters: Record = {}) { - return createAlgoliaSearchClient({ + return createSearchClient({ search: jest.fn((requests) => { return Promise.resolve( createMultiSearchResponse( @@ -1532,7 +1532,7 @@ function createMockedSearchClient(parameters: Record = {}) { facetHits: FACET_HITS, }), ]) - ), + ) as any, // @TODO: for now casted as any, because v5 only has `type: facet` in search ...parameters, }); } diff --git a/tests/mocks/createAPIResponse.ts b/tests/mocks/createAPIResponse.ts index 5c9058c472..5a34ab1f34 100644 --- a/tests/mocks/createAPIResponse.ts +++ b/tests/mocks/createAPIResponse.ts @@ -1,8 +1,9 @@ -import type { RecommendQueriesResponse } from '@algolia/recommend'; import type { SearchResponse, SearchResponses, SearchForFacetValuesResponse, + RecommendResponse, + RecommendResponses, } from 'instantsearch.js'; export const defaultRenderingContent: SearchResponse['renderingContent'] = @@ -88,8 +89,42 @@ export const createSFFVResponse = ( ...args, }); +export const createSingleRecommendResponse = ( + subset: Partial> = {} +): RecommendResponse => { + const { + query = '', + page = 0, + hitsPerPage = 20, + hits = [], + nbHits = hits.length, + nbPages = Math.ceil(nbHits / hitsPerPage), + params = '', + exhaustiveNbHits = true, + exhaustiveFacetsCount = true, + processingTimeMS = 0, + ...rest + } = subset; + + return { + page, + hitsPerPage, + nbHits, + nbPages, + processingTimeMS, + hits, + query, + params, + exhaustiveNbHits, + exhaustiveFacetsCount, + ...rest, + }; +}; + export const createRecommendResponse = ( - requests: readonly any[] -): RecommendQueriesResponse => { - return { results: requests.map(createSingleSearchResponse) }; + requests: any[] +): RecommendResponses => { + return { + results: requests.map(createSingleRecommendResponse), + }; }; diff --git a/tests/mocks/createAlgoliaSearchClient.ts b/tests/mocks/createAlgoliaSearchClient.ts index 9027a08594..3dbab976a3 100644 --- a/tests/mocks/createAlgoliaSearchClient.ts +++ b/tests/mocks/createAlgoliaSearchClient.ts @@ -1,14 +1,18 @@ import { createNullCache } from '@algolia/cache-common'; import { createInMemoryCache } from '@algolia/cache-in-memory'; import { createNullLogger } from '@algolia/logger-common'; -import { createNodeHttpRequester } from '@algolia/requester-node-http'; +import * as HTTPRequester from '@algolia/requester-node-http'; import { serializeQueryParameters, createTransporter, CallEnum, createUserAgent, } from '@algolia/transporter'; -import algoliasearch from 'algoliasearch'; +import { + // @ts-ignore fails in v3, v4 + algoliasearch as namedConstructor, + default as defaultConstructor, +} from 'algoliasearch'; import { createSingleSearchResponse, @@ -17,19 +21,25 @@ import { } from './createAPIResponse'; import type { HostOptions } from '@algolia/transporter'; +import type { SearchClient } from 'algoliasearch-helper/types/algoliasearch'; type OverrideKeys = TOptions extends Record ? TTarget : Omit & TOptions; -type SearchClient = ReturnType; +const algoliasearch = (namedConstructor || defaultConstructor) as unknown as ( + appId: string, + apiKey: string +) => SearchClient; export type MockSearchClient = OverrideKeys< SearchClient, - { - search: jest.Mock; - searchForFacetValues: jest.Mock; - } + SearchClient extends { searchForFacetValues: (...args: any[]) => any } + ? { + search: jest.Mock; + searchForFacetValues: jest.Mock; + } + : { search: jest.Mock } >; export function createAlgoliaSearchClient< @@ -47,7 +57,10 @@ export function createAlgoliaSearchClient< write: 30, }, userAgent: createUserAgent('test'), - requester: createNodeHttpRequester(), + requester: ( + (HTTPRequester as any) /* v4*/.createNodeHttpRequester || + (HTTPRequester as any) /* v5*/.createHttpRequester + )(), logger: createNullLogger(), responsesCache: createNullCache(), requestsCache: createNullCache(), diff --git a/tests/mocks/createSearchClient.ts b/tests/mocks/createSearchClient.ts index 2e3569377f..0df3eea977 100644 --- a/tests/mocks/createSearchClient.ts +++ b/tests/mocks/createSearchClient.ts @@ -20,6 +20,7 @@ export const createSearchClient = ( ) ) ), + // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) searchForFacetValues: jest.fn(() => Promise.resolve([createSFFVResponse()])), // @ts-ignore this allows us to test insights initialization without warning applicationID: 'appId', diff --git a/yarn.lock b/yarn.lock index 25f22e920f..c9bcdfe41f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -51,14 +51,14 @@ dependencies: "@algolia/cache-common" "4.23.2" -"@algolia/client-abtesting@5.0.0-beta.8": - version "5.0.0-beta.8" - resolved "https://registry.yarnpkg.com/@algolia/client-abtesting/-/client-abtesting-5.0.0-beta.8.tgz#07950e042e19abe473b6659660dbbaf3d5ae5750" - integrity sha512-SX9/v/1CinWhn8UyPS4zoiCuqLepAoaPiwiJvMal1q8huQzHPYgaQRGu5SwXf/jzUnXnWLiWakyZZ0WkGHj6yA== +"@algolia/client-abtesting@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/client-abtesting/-/client-abtesting-5.0.0.tgz#c6d5727ee77d8ea0eac0d545a977c19155bb1c29" + integrity sha512-pVSwJ2QZ9hNeINjSWRQGwN/zAk16E6fOM4VGayIULyiJnaIaRjGT/UfMRiGsIuBFib2zviq83uO8GOnCUBmXnA== dependencies: - "@algolia/client-common" "5.0.0-beta.9" - "@algolia/requester-browser-xhr" "5.0.0-beta.9" - "@algolia/requester-node-http" "5.0.0-beta.9" + "@algolia/client-common" "5.0.0" + "@algolia/requester-browser-xhr" "5.0.0" + "@algolia/requester-node-http" "5.0.0" "@algolia/client-account@4.23.2": version "4.23.2" @@ -79,14 +79,14 @@ "@algolia/requester-common" "4.23.2" "@algolia/transporter" "4.23.2" -"@algolia/client-analytics@5.0.0-beta.8": - version "5.0.0-beta.8" - resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-5.0.0-beta.8.tgz#86d110bed99ca28359bd4e70eaeff568cb6462bb" - integrity sha512-SzMg3FeF7do/+plUawHRw2Lr3/KebKF8rCkswdR907kUa/aMVCFzsginL3xc/k8bIxx6wU8fk5iKLeK1+Ykxnw== +"@algolia/client-analytics@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-5.0.0.tgz#582d165cf6486e441646916635e5c74487ca3226" + integrity sha512-3A4JyblLorrxkYn6uOWyo7drDi3z7+Yzm45YP1MgOvzOCt0qWlEb6neIFLDe4UrBy24JqmRx54uNMBuYMOscgw== dependencies: - "@algolia/client-common" "5.0.0-beta.9" - "@algolia/requester-browser-xhr" "5.0.0-beta.9" - "@algolia/requester-node-http" "5.0.0-beta.9" + "@algolia/client-common" "5.0.0" + "@algolia/requester-browser-xhr" "5.0.0" + "@algolia/requester-node-http" "5.0.0" "@algolia/client-common@4.23.2": version "4.23.2" @@ -96,10 +96,10 @@ "@algolia/requester-common" "4.23.2" "@algolia/transporter" "4.23.2" -"@algolia/client-common@5.0.0-beta.9": - version "5.0.0-beta.9" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.0.0-beta.9.tgz#f659c0fca45663a09f7bcf5eb36318ef5ab39b40" - integrity sha512-TWf6l4/pWMk8CgV+8A4zTe49XaygaCZ6ir8bwf4WnpDgAxx8Y5X/I6e7vPzl7sljQEEB9q1+qlkss1nxNeRJPw== +"@algolia/client-common@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.0.0.tgz#ff52d29ed81cdafaa38655fc4ee958ca49f20aaf" + integrity sha512-6N5Qygv/Z/B+rPufnPDLNWgsMf1uubMU7iS52xLcQSLiGlTS4f9eLUrmNXSzHccP33uoFi6xN9craN1sZi5MPQ== "@algolia/client-personalization@4.23.2": version "4.23.2" @@ -110,14 +110,14 @@ "@algolia/requester-common" "4.23.2" "@algolia/transporter" "4.23.2" -"@algolia/client-personalization@5.0.0-beta.8": - version "5.0.0-beta.8" - resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-5.0.0-beta.8.tgz#18b624c9e268da3c36c5416e593e778cdaca338c" - integrity sha512-8mGxWE3TA3+2ekc+rM38JAwFfpwPyWyPxjjOe33afiFkmDliLrsGDAyoCasu7w34JhpuLeR1wfgo58g9s9+OLw== +"@algolia/client-personalization@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-5.0.0.tgz#a5df3d5fce7a800145deca51cc10e8e9f037e568" + integrity sha512-Ns9pl+YGl0qZTbMqEKIO54GJqzyrMUmLfPB3/iEEkezKMMHXAsINrOuKTfhA6vyI0vhUJL3imOPo6vmXZBDZsA== dependencies: - "@algolia/client-common" "5.0.0-beta.9" - "@algolia/requester-browser-xhr" "5.0.0-beta.9" - "@algolia/requester-node-http" "5.0.0-beta.9" + "@algolia/client-common" "5.0.0" + "@algolia/requester-browser-xhr" "5.0.0" + "@algolia/requester-node-http" "5.0.0" "@algolia/client-search@4.23.2": version "4.23.2" @@ -128,14 +128,14 @@ "@algolia/requester-common" "4.23.2" "@algolia/transporter" "4.23.2" -"@algolia/client-search@5.0.0-beta.8": - version "5.0.0-beta.8" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.0.0-beta.8.tgz#5abeb90de119ee868aa6a2d898c9d98cf8292258" - integrity sha512-Ub7CEFLDvCF13tq6imE7sEKnxmo177k4euXjaKGUMlznUf9qLWT5g6HuvBH4Nrxwaotima3cRnIw3zkq4JZORw== +"@algolia/client-search@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.0.0.tgz#8d58f5daeffe9d19e0e0e9ebcdb5d23525edebe4" + integrity sha512-QdDYMzoxYZ3axzBy6CHe+M+NlOGvHEFTa2actchGnp25Uu0N6lyVNivT7nph+P1XoxgAD08cWbeJD3wWQXnpng== dependencies: - "@algolia/client-common" "5.0.0-beta.9" - "@algolia/requester-browser-xhr" "5.0.0-beta.9" - "@algolia/requester-node-http" "5.0.0-beta.9" + "@algolia/client-common" "5.0.0" + "@algolia/requester-browser-xhr" "5.0.0" + "@algolia/requester-node-http" "5.0.0" "@algolia/events@^4.0.1": version "4.0.1" @@ -171,14 +171,14 @@ "@algolia/requester-node-http" "4.23.2" "@algolia/transporter" "4.23.2" -"@algolia/recommend@5.0.0-beta.8": - version "5.0.0-beta.8" - resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-5.0.0-beta.8.tgz#eff81537479a3390a33ddbffcbf82ae194160019" - integrity sha512-B7tuqYF2YlPmRH5jfDbbC3V1sq8X3a7oadwzAOPGGC1qwi2tO8BoBLM2iIwJRAAesw4NRVeBVDDmdsdiStHeEQ== +"@algolia/recommend@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-5.0.0.tgz#df3c63f7de2ddf6658a67308a7a5f4b805c87687" + integrity sha512-aEXg4RPFIRrJjrtri782W7XFNkarxoN9X42FwYYP1bz15jKu2vrIqzGlQoNCNWuZP7WwYyUAoTtixwLRJq8grQ== dependencies: - "@algolia/client-common" "5.0.0-beta.9" - "@algolia/requester-browser-xhr" "5.0.0-beta.9" - "@algolia/requester-node-http" "5.0.0-beta.9" + "@algolia/client-common" "5.0.0" + "@algolia/requester-browser-xhr" "5.0.0" + "@algolia/requester-node-http" "5.0.0" "@algolia/requester-browser-xhr@4.23.2": version "4.23.2" @@ -187,12 +187,12 @@ dependencies: "@algolia/requester-common" "4.23.2" -"@algolia/requester-browser-xhr@5.0.0-beta.9": - version "5.0.0-beta.9" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.0.0-beta.9.tgz#7b43b57cfabe9328e54fb4a96dd10026d27329f1" - integrity sha512-zw/ZmZv/CLjLqBUfukk5kR8N/xF/TbUt6xLdXF1LkaEJDj7BWU1RqMMDeSU5SEcehPMqNumfzFjpaz8D0rZ/jw== +"@algolia/requester-browser-xhr@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.0.0.tgz#ddce386fd8635d79a1803c44b749289ff690db80" + integrity sha512-oOoQhSpg/RGiGHjn/cqtYpHBkkd+5M/DCi1jmfW+ZOvLVx21QVt6PbWIJoKJF85moNFo4UG9pMBU35R1MaxUKQ== dependencies: - "@algolia/client-common" "5.0.0-beta.9" + "@algolia/client-common" "5.0.0" "@algolia/requester-common@4.23.2": version "4.23.2" @@ -206,12 +206,12 @@ dependencies: "@algolia/requester-common" "4.23.2" -"@algolia/requester-node-http@5.0.0-beta.9": - version "5.0.0-beta.9" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.0.0-beta.9.tgz#afc04a658c1b624e03e378ea076020a51e737637" - integrity sha512-/32llTTdZ0zMNwn8I8FA12Pw4wZW93AvoHU/8Si2UR8S+FyL8dAkwgmQAvRZinNXD/Bo45Mpjwgydhx9UNZNBA== +"@algolia/requester-node-http@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.0.0.tgz#708961cb2c069e5ed3bae83aef144ec8b3300b57" + integrity sha512-FwCdugzpnW0wxbgWPauAz5vhmWGQnjZa5DCl9PBbIoDNEy/NIV8DmiL9CEA+LljQdDidG0l0ijojcTNaRRtPvQ== dependencies: - "@algolia/client-common" "5.0.0-beta.9" + "@algolia/client-common" "5.0.0" "@algolia/transporter@4.23.2": version "4.23.2" @@ -8083,21 +8083,8 @@ algoliasearch-helper@3.14.0: semver "^5.1.0" tunnel-agent "^0.6.0" -"algoliasearch-v5@npm:algoliasearch@5.0.0-beta.8": - version "5.0.0-beta.8" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-5.0.0-beta.8.tgz#df9ae7351f4d16ef20f04c7ed90203bfb8bdc9df" - integrity sha512-HeHubssxYRD9OEBySLXM8DdsrDthdyVSogncyQkxO3U+EYfg94Fxe7Kn9ooDm4sX88HS+lOaIV3I+JSwpvoy6A== - dependencies: - "@algolia/client-abtesting" "5.0.0-beta.8" - "@algolia/client-analytics" "5.0.0-beta.8" - "@algolia/client-common" "5.0.0-beta.9" - "@algolia/client-personalization" "5.0.0-beta.8" - "@algolia/client-search" "5.0.0-beta.8" - "@algolia/recommend" "5.0.0-beta.8" - "@algolia/requester-browser-xhr" "5.0.0-beta.9" - "@algolia/requester-node-http" "5.0.0-beta.9" - -algoliasearch@4, algoliasearch@4.23.2: +"algoliasearch-v4@npm:algoliasearch@4.23.2", algoliasearch@4, algoliasearch@4.23.2: + name algoliasearch-v4 version "4.23.2" resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.23.2.tgz#3b7bc93d98f3965628c73a06cbf9203531324a9d" integrity sha512-8aCl055IsokLuPU8BzLjwzXjb7ty9TPcUFFOk0pYOwsE5DMVhE3kwCMFtsCFKcnoPZK7oObm+H5mbnSO/9ioxQ== @@ -8118,26 +8105,19 @@ algoliasearch@4, algoliasearch@4.23.2: "@algolia/requester-node-http" "4.23.2" "@algolia/transporter" "4.23.2" -algoliasearch@^3.35.1: - version "3.35.1" - resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-3.35.1.tgz#297d15f534a3507cab2f5dfb996019cac7568f0c" - integrity sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ== - dependencies: - agentkeepalive "^2.2.0" - debug "^2.6.9" - envify "^4.0.0" - es6-promise "^4.1.0" - events "^1.1.0" - foreach "^2.0.5" - global "^4.3.2" - inherits "^2.0.1" - isarray "^2.0.1" - load-script "^1.0.0" - object-keys "^1.0.11" - querystring-es3 "^0.2.1" - reduce "^1.0.1" - semver "^5.1.0" - tunnel-agent "^0.6.0" +"algoliasearch-v5@npm:algoliasearch@5.0.0", algoliasearch@5.0.0, algoliasearch@^3.35.1: + version "5.0.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-5.0.0.tgz#caa7cb9a5116291763c93f3e7ca0fc284b5784f8" + integrity sha512-j/RYIyKy7D6Vu/o142+6Gka1lXtu0j/Hj/Mw5oaPpOscOcE4jn29k465pcWYNC34HMxA4W8chiDk9cqw8nszag== + dependencies: + "@algolia/client-abtesting" "5.0.0" + "@algolia/client-analytics" "5.0.0" + "@algolia/client-common" "5.0.0" + "@algolia/client-personalization" "5.0.0" + "@algolia/client-search" "5.0.0" + "@algolia/recommend" "5.0.0" + "@algolia/requester-browser-xhr" "5.0.0" + "@algolia/requester-node-http" "5.0.0" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" @@ -30990,16 +30970,16 @@ typedarray@~0.0.5: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.7.tgz#799207136a37f3b3efb8c66c40010d032714dc73" integrity sha512-ueeb9YybpjhivjbHP2LdFDAjbS948fGEPj+ACAMs4xCMmh72OCOMQWBQKlaN4ZNQ04yfLSDLSx1tGRIoWimObQ== -typescript@*, typescript@5.4.2: - version "5.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" - integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== - -typescript@5.5.2: +typescript@*, typescript@5.5.2: version "5.5.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.2.tgz#c26f023cb0054e657ce04f72583ea2d85f8d0507" integrity sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew== +typescript@5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + "typescript@^3 || ^4": version "4.9.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"