Skip to content

Commit f0f7a62

Browse files
authored
fix(fetchAlgoliaResults): safely access searchClient credentials (#1133)
It's possible to have a broken / badly copied search client without transporter, and that would throw from 1.9.2 onwards. This PR makes that access safer and throws a clear error. CR-3338
1 parent 48899d2 commit f0f7a62

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

packages/autocomplete-preset-algolia/src/search/__tests__/fetchAlgoliaResults.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,59 @@ describe('fetchAlgoliaResults', () => {
199199
'1.0.0'
200200
);
201201
});
202+
203+
describe('missing credentials', () => {
204+
test('throws dev error when searchClient has no readable appId', () => {
205+
const searchClient = {
206+
search: createSearchClient().search,
207+
};
208+
209+
expect(() => {
210+
fetchAlgoliaResults({
211+
// @ts-expect-error
212+
searchClient,
213+
queries: [],
214+
userAgents: [{ segment: 'custom-ua', version: '1.0.0' }],
215+
});
216+
}).toThrowErrorMatchingInlineSnapshot(
217+
`"[Autocomplete] The Algolia \`appId\` was not accessible from the searchClient passed."`
218+
);
219+
});
220+
221+
test('throws dev error when searchClient has no readable apiKey', () => {
222+
const searchClient = {
223+
search: createSearchClient().search,
224+
transporter: {
225+
headers: {
226+
'x-algolia-application-id': 'appId',
227+
},
228+
},
229+
};
230+
231+
expect(() => {
232+
fetchAlgoliaResults({
233+
// @ts-expect-error
234+
searchClient,
235+
queries: [],
236+
userAgents: [{ segment: 'custom-ua', version: '1.0.0' }],
237+
});
238+
}).toThrowErrorMatchingInlineSnapshot(
239+
`"[Autocomplete] The Algolia \`apiKey\` was not accessible from the searchClient passed."`
240+
);
241+
});
242+
243+
test('does not throw dev error when searchClient is copied', () => {
244+
const searchClient = {
245+
...createSearchClient(),
246+
};
247+
248+
expect(() => {
249+
fetchAlgoliaResults({
250+
searchClient,
251+
queries: [],
252+
userAgents: [{ segment: 'custom-ua', version: '1.0.0' }],
253+
});
254+
}).not.toThrow();
255+
});
256+
});
202257
});

packages/autocomplete-preset-algolia/src/search/fetchAlgoliaResults.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
userAgents as coreUserAgents,
33
UserAgent,
4+
invariant,
45
} from '@algolia/autocomplete-shared';
56

67
import { HIGHLIGHT_PRE_TAG, HIGHLIGHT_POST_TAG } from '../constants';
@@ -28,6 +29,15 @@ export function fetchAlgoliaResults<TRecord>({
2829

2930
const { appId, apiKey } = getAppIdAndApiKey(searchClient);
3031

32+
invariant(
33+
Boolean(appId),
34+
'The Algolia `appId` was not accessible from the searchClient passed.'
35+
);
36+
invariant(
37+
Boolean(apiKey),
38+
'The Algolia `apiKey` was not accessible from the searchClient passed.'
39+
);
40+
3141
return searchClient
3242
.search<TRecord>(
3343
queries.map((searchParameters) => {

packages/autocomplete-preset-algolia/src/utils/__tests__/getAppIdAndApiKey.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,14 @@ describe('getAppIdAndApiKey', () => {
1212
expect(appId).toEqual(APP_ID);
1313
expect(apiKey).toEqual(API_KEY);
1414
});
15+
16+
it('gets undefined appId and apiKey from broken search client', () => {
17+
const searchClient = {
18+
search: algoliasearchV4(APP_ID, API_KEY).search,
19+
};
20+
// @ts-expect-error
21+
const { appId, apiKey } = getAppIdAndApiKey(searchClient);
22+
expect(appId).toEqual(undefined);
23+
expect(apiKey).toEqual(undefined);
24+
});
1525
});

packages/autocomplete-preset-algolia/src/utils/getAppIdAndApiKey.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export function getAppIdAndApiKey(searchClient: SearchClient): {
44
appId: string;
55
apiKey: string;
66
} {
7-
const { headers, queryParameters } = searchClient.transporter;
7+
const { headers = {}, queryParameters = {} } = searchClient.transporter || {};
88
const APP_ID = 'x-algolia-application-id';
99
const API_KEY = 'x-algolia-api-key';
1010
const appId = headers[APP_ID] || queryParameters[APP_ID];

0 commit comments

Comments
 (0)