From 48571bb240382bd052b73cd3f2b838776b3ef09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= <20689156+shortcuts@users.noreply.github.com> Date: Tue, 22 Feb 2022 20:16:35 +0100 Subject: [PATCH] feat(javascript): remove classes usage (#156) --- .../bundlesize.config.json | 6 +- .../client-abtesting/builds/browser.ts | 4 +- .../packages/client-abtesting/builds/node.ts | 4 +- .../client-abtesting/src/abtestingApi.ts | 10 +- .../client-analytics/builds/browser.ts | 4 +- .../packages/client-analytics/builds/node.ts | 4 +- .../client-analytics/src/analyticsApi.ts | 10 +- .../packages/client-common/index.ts | 7 +- .../packages/client-common/src/Requester.ts | 8 - .../client-common/src/StatefulHost.ts | 34 ---- .../client-common/src/createMemoryCache.ts | 28 +-- .../client-common/src/createStatefulHost.ts | 22 +++ .../{Transporter.ts => createTransporter.ts} | 137 ++++++--------- .../packages/client-common/src/helpers.ts | 1 - .../packages/client-common/src/types.ts | 111 ------------ .../packages/client-common/src/types/Cache.ts | 27 +++ .../client-common/src/types/CreateClient.ts | 14 ++ .../packages/client-common/src/types/Host.ts | 12 ++ .../client-common/src/types/Requester.ts | 40 +++++ .../client-common/src/types/Transporter.ts | 162 ++++++++++++++++++ .../packages/client-common/src/types/index.ts | 5 + .../client-insights/builds/browser.ts | 4 +- .../packages/client-insights/builds/node.ts | 4 +- .../client-insights/src/insightsApi.ts | 10 +- .../client-personalization/builds/browser.ts | 4 +- .../client-personalization/builds/node.ts | 4 +- .../src/personalizationApi.ts | 10 +- .../packages/client-predict/builds/browser.ts | 4 +- .../packages/client-predict/builds/node.ts | 4 +- .../packages/client-predict/src/predictApi.ts | 10 +- .../builds/browser.ts | 4 +- .../client-query-suggestions/builds/node.ts | 4 +- .../src/querySuggestionsApi.ts | 10 +- .../packages/client-search/builds/browser.ts | 4 +- .../packages/client-search/builds/node.ts | 4 +- .../packages/client-search/src/searchApi.ts | 8 +- .../packages/client-sources/builds/browser.ts | 4 +- .../packages/client-sources/builds/node.ts | 4 +- .../packages/client-sources/src/sourcesApi.ts | 10 +- .../packages/recommend/builds/browser.ts | 4 +- .../packages/recommend/builds/node.ts | 4 +- .../packages/recommend/src/recommendApi.ts | 8 +- .../packages/requester-browser-xhr/index.ts | 2 +- ...{XhrRequester.ts => createXhrRequester.ts} | 9 +- .../packages/requester-node-http/index.ts | 2 +- ...ttpRequester.ts => createHttpRequester.ts} | 9 +- templates/javascript/api-all.mustache | 4 +- templates/javascript/api-single.mustache | 18 +- templates/javascript/api.mustache | 4 +- 49 files changed, 479 insertions(+), 341 deletions(-) delete mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/Requester.ts delete mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/StatefulHost.ts create mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/createStatefulHost.ts rename clients/algoliasearch-client-javascript/packages/client-common/src/{Transporter.ts => createTransporter.ts} (67%) delete mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/types.ts create mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/types/Cache.ts create mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/types/CreateClient.ts create mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/types/Host.ts create mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/types/Requester.ts create mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/types/Transporter.ts create mode 100644 clients/algoliasearch-client-javascript/packages/client-common/src/types/index.ts rename clients/algoliasearch-client-javascript/packages/requester-browser-xhr/src/{XhrRequester.ts => createXhrRequester.ts} (89%) rename clients/algoliasearch-client-javascript/packages/requester-node-http/src/{HttpRequester.ts => createHttpRequester.ts} (92%) diff --git a/clients/algoliasearch-client-javascript/bundlesize.config.json b/clients/algoliasearch-client-javascript/bundlesize.config.json index e218460482..1d3a665cc2 100644 --- a/clients/algoliasearch-client-javascript/bundlesize.config.json +++ b/clients/algoliasearch-client-javascript/bundlesize.config.json @@ -14,7 +14,7 @@ }, { "path": "packages/client-personalization/dist/client-personalization.umd.browser.js", - "maxSize": "3.25KB" + "maxSize": "3.00KB" }, { "path": "packages/client-query-suggestions/dist/client-query-suggestions.umd.browser.js", @@ -30,11 +30,11 @@ }, { "path": "packages/recommend/dist/recommend.umd.browser.js", - "maxSize": "3.25KB" + "maxSize": "3.00KB" }, { "path": "packages/client-common/dist/client-common.esm.node.js", - "maxSize": "3.25KB" + "maxSize": "3.00KB" }, { "path": "packages/requester-browser-xhr/dist/requester-browser-xhr.esm.node.js", diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/browser.ts index 37f81c68ae..31bbae9d49 100644 --- a/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createAbtestingApi } from '../src/abtestingApi'; import type { AbtestingApi, Region } from '../src/abtestingApi'; @@ -29,7 +29,7 @@ export function abtestingApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/node.ts index 74c0d7c77d..034c5ea5b9 100644 --- a/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createAbtestingApi } from '../src/abtestingApi'; import type { AbtestingApi, Region } from '../src/abtestingApi'; @@ -29,7 +29,7 @@ export function abtestingApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingApi.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingApi.ts index 27a49fbfaa..a1533a5e79 100644 --- a/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingApi.ts @@ -1,4 +1,9 @@ -import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, +} from '@algolia/client-common'; import type { CreateClientOptions, Headers, @@ -32,8 +37,9 @@ export function createAbtestingApi( options: CreateClientOptions & { region?: Region } ) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.region), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/client-analytics/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-analytics/builds/browser.ts index a3461d8184..ca2ad2d132 100644 --- a/clients/algoliasearch-client-javascript/packages/client-analytics/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-analytics/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createAnalyticsApi } from '../src/analyticsApi'; import type { AnalyticsApi, Region } from '../src/analyticsApi'; @@ -29,7 +29,7 @@ export function analyticsApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-analytics/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-analytics/builds/node.ts index 2c9f9353d3..10a674ef6d 100644 --- a/clients/algoliasearch-client-javascript/packages/client-analytics/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-analytics/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createAnalyticsApi } from '../src/analyticsApi'; import type { AnalyticsApi, Region } from '../src/analyticsApi'; @@ -29,7 +29,7 @@ export function analyticsApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-analytics/src/analyticsApi.ts b/clients/algoliasearch-client-javascript/packages/client-analytics/src/analyticsApi.ts index 5b8cf4f065..7486b001f1 100644 --- a/clients/algoliasearch-client-javascript/packages/client-analytics/src/analyticsApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-analytics/src/analyticsApi.ts @@ -1,4 +1,9 @@ -import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, +} from '@algolia/client-common'; import type { CreateClientOptions, Headers, @@ -47,8 +52,9 @@ export function createAnalyticsApi( options: CreateClientOptions & { region?: Region } ) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.region), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/client-common/index.ts b/clients/algoliasearch-client-javascript/packages/client-common/index.ts index 5635db4a5b..3834d850e9 100644 --- a/clients/algoliasearch-client-javascript/packages/client-common/index.ts +++ b/clients/algoliasearch-client-javascript/packages/client-common/index.ts @@ -1,13 +1,12 @@ -export * from './src/createMemoryCache'; export * from './src/createAuth'; export * from './src/createEchoRequester'; +export * from './src/createMemoryCache'; +export * from './src/createStatefulHost'; +export * from './src/createTransporter'; export * from './src/createUserAgent'; export * from './src/errors'; export * from './src/getUserAgent'; export * from './src/helpers'; -export * from './src/Requester'; export * from './src/Response'; export * from './src/stackTrace'; -export * from './src/StatefulHost'; -export * from './src/Transporter'; export * from './src/types'; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/Requester.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/Requester.ts deleted file mode 100644 index 9b4e83e5e0..0000000000 --- a/clients/algoliasearch-client-javascript/packages/client-common/src/Requester.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { EndRequest, Request, Response } from './types'; - -export abstract class Requester { - abstract send( - request: EndRequest, - originalRequest: Request - ): Promise; -} diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/StatefulHost.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/StatefulHost.ts deleted file mode 100644 index 162c4ed1c6..0000000000 --- a/clients/algoliasearch-client-javascript/packages/client-common/src/StatefulHost.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Host } from './types'; - -const EXPIRATION_DELAY = 2 * 60 * 1000; - -export class StatefulHost implements Host { - url: string; - accept: 'read' | 'readWrite' | 'write'; - protocol: 'http' | 'https'; - - private lastUpdate: number; - private status: 'down' | 'timedout' | 'up'; - - constructor(host: Host, status: StatefulHost['status'] = 'up') { - this.url = host.url; - this.accept = host.accept; - this.protocol = host.protocol; - - this.status = status; - this.lastUpdate = Date.now(); - } - - isUp(): boolean { - return ( - this.status === 'up' || Date.now() - this.lastUpdate > EXPIRATION_DELAY - ); - } - - isTimedout(): boolean { - return ( - this.status === 'timedout' && - Date.now() - this.lastUpdate <= EXPIRATION_DELAY - ); - } -} diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/createMemoryCache.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/createMemoryCache.ts index febde2f1d1..2f7af183d6 100644 --- a/clients/algoliasearch-client-javascript/packages/client-common/src/createMemoryCache.ts +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/createMemoryCache.ts @@ -1,30 +1,4 @@ -export type Cache = { - /** - * Gets the value of the given `key`. - */ - get: ( - key: Record | string, - defaultValue: () => Promise - ) => Promise; - - /** - * Sets the given value with the given `key`. - */ - set: ( - key: Record | string, - value: TValue - ) => Promise; - - /** - * Deletes the given `key`. - */ - delete: (key: Record | string) => Promise; - - /** - * Clears the cache. - */ - clear: () => Promise; -}; +import type { Cache } from './types'; export function createMemoryCache(): Cache { let cache: Record = {}; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/createStatefulHost.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/createStatefulHost.ts new file mode 100644 index 0000000000..e69f7a285f --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/createStatefulHost.ts @@ -0,0 +1,22 @@ +import type { Host, StatefulHost } from './types'; + +// By default, API Clients at Algolia have expiration delay of 5 mins. +// In the JavaScript client, we have 2 mins. +const EXPIRATION_DELAY = 2 * 60 * 1000; + +export function createStatefulHost( + host: Host, + status: StatefulHost['status'] = 'up' +): StatefulHost { + const lastUpdate = Date.now(); + + function isUp(): boolean { + return status === 'up' || Date.now() - lastUpdate > EXPIRATION_DELAY; + } + + function isTimedout(): boolean { + return status === 'timedout' && Date.now() - lastUpdate <= EXPIRATION_DELAY; + } + + return { ...host, status, lastUpdate, isUp, isTimedout }; +} diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/Transporter.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/createTransporter.ts similarity index 67% rename from clients/algoliasearch-client-javascript/packages/client-common/src/Transporter.ts rename to clients/algoliasearch-client-javascript/packages/client-common/src/createTransporter.ts index fc05e8fdf9..6f298796c2 100644 --- a/clients/algoliasearch-client-javascript/packages/client-common/src/Transporter.ts +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/createTransporter.ts @@ -1,8 +1,5 @@ -import type { Requester } from './Requester'; import { isRetryable, isSuccess } from './Response'; -import { StatefulHost } from './StatefulHost'; -import { createMemoryCache } from './createMemoryCache'; -import type { Cache } from './createMemoryCache'; +import { createStatefulHost } from './createStatefulHost'; import { RetryError } from './errors'; import { deserializeFailure, @@ -17,82 +14,49 @@ import { } from './stackTrace'; import type { EndRequest, - Headers, Host, - QueryParameters, Request, RequestOptions, Response, StackFrame, - Timeouts, - UserAgent, + TransporterOptions, + Transporter, } from './types'; -export class Transporter { - private hosts: Host[]; - private baseHeaders: Headers; - private baseQueryParameters: QueryParameters; - private hostsCache: Cache; - userAgent: UserAgent; - private timeouts: Timeouts; - private requester: Requester; - - constructor({ - hosts, - baseHeaders, - baseQueryParameters, - userAgent, - timeouts, - requester, - }: { - hosts: Host[]; - baseHeaders: Headers; - baseQueryParameters: QueryParameters; - userAgent: UserAgent; - timeouts: Timeouts; - requester: Requester; - }) { - this.hosts = hosts; - this.hostsCache = createMemoryCache(); - this.baseHeaders = baseHeaders; - this.baseQueryParameters = baseQueryParameters; - this.userAgent = userAgent; - this.timeouts = timeouts; - this.requester = requester; - } - - setHosts(hosts: Host[]): void { - this.hosts = hosts; - this.hostsCache.clear(); - } - - setRequester(requester: Requester): void { - this.requester = requester; - } - - async createRetryableOptions(compatibleHosts: Host[]): Promise<{ - hosts: Host[]; - getTimeout: (retryCount: number, timeout: number) => number; - }> { +type RetryableOptions = { + hosts: Host[]; + getTimeout: (retryCount: number, timeout: number) => number; +}; + +export function createTransporter({ + hosts, + hostsCache, + baseHeaders, + baseQueryParameters, + userAgent, + timeouts, + requester, +}: TransporterOptions): Transporter { + async function createRetryableOptions( + compatibleHosts: Host[] + ): Promise { const statefulHosts = await Promise.all( - compatibleHosts.map((statelessHost) => { - return this.hostsCache.get(statelessHost, () => { - return Promise.resolve(new StatefulHost(statelessHost)); + compatibleHosts.map((compatibleHost) => { + return hostsCache.get(compatibleHost, () => { + return Promise.resolve(createStatefulHost(compatibleHost)); }); }) ); const hostsUp = statefulHosts.filter((host) => host.isUp()); const hostsTimeouted = statefulHosts.filter((host) => host.isTimedout()); - /** - * Note, we put the hosts that previously timeouted on the end of the list. - */ + // Note, we put the hosts that previously timeouted on the end of the list. const hostsAvailable = [...hostsUp, ...hostsTimeouted]; - - const hosts = hostsAvailable.length > 0 ? hostsAvailable : compatibleHosts; + const compatibleHostsAvailable = + hostsAvailable.length > 0 ? hostsAvailable : compatibleHosts; return { - hosts, + hosts: compatibleHostsAvailable, getTimeout(timeoutsCount: number, baseTimeout: number): number { /** * Imagine that you have 4 hosts, if timeouts will increase @@ -115,19 +79,18 @@ export class Transporter { }; } - async request( + async function retryableRequest( request: Request, requestOptions: RequestOptions ): Promise { const stackTrace: StackFrame[] = []; - const isRead = request.method === 'GET'; /** * First we prepare the payload that do not depend from hosts. */ const data = serializeData(request, requestOptions); - const headers = serializeHeaders(this.baseHeaders, requestOptions); + const headers = serializeHeaders(baseHeaders, requestOptions); const method = request.method; // On `GET`, the data is proxied to query parameters. @@ -139,8 +102,8 @@ export class Transporter { : {}; const queryParameters = { - 'x-algolia-agent': this.userAgent.value, - ...this.baseQueryParameters, + 'x-algolia-agent': userAgent.value, + ...baseQueryParameters, ...dataQueryParameters, ...requestOptions.queryParameters, }; @@ -148,20 +111,20 @@ export class Transporter { let timeoutsCount = 0; const retry = async ( - hosts: Host[], + retryableHosts: Host[], getTimeout: (timeoutsCount: number, timeout: number) => number ): Promise => { /** * We iterate on each host, until there is no host left. */ - const host = hosts.pop(); + const host = retryableHosts.pop(); if (host === undefined) { throw new RetryError(stackTraceWithoutCredentials(stackTrace)); } let responseTimeout = requestOptions.timeout; if (responseTimeout === undefined) { - responseTimeout = isRead ? this.timeouts.read : this.timeouts.write; + responseTimeout = isRead ? timeouts.read : timeouts.write; } const payload: EndRequest = { @@ -169,7 +132,7 @@ export class Transporter { headers, method, url: serializeUrl(host, request.path, queryParameters), - connectTimeout: getTimeout(timeoutsCount, this.timeouts.connect), + connectTimeout: getTimeout(timeoutsCount, timeouts.connect), responseTimeout: getTimeout(timeoutsCount, responseTimeout), }; @@ -183,7 +146,7 @@ export class Transporter { request: payload, response, host, - triesLeft: hosts.length, + triesLeft: retryableHosts.length, }; stackTrace.push(stackFrame); @@ -191,7 +154,7 @@ export class Transporter { return stackFrame; }; - const response = await this.requester.send(payload, request); + const response = await requester.send(payload, request); if (isRetryable(response)) { const stackFrame = pushToStackTrace(response); @@ -205,7 +168,7 @@ export class Transporter { * the end user to debug / store stack frames even * when a retry error does not happen. */ - // eslint-disable-next-line no-console -- this will be fixed with the new `Logger` + // eslint-disable-next-line no-console -- this will be fixed by exposing a `logger` to the transporter console.log( 'Retryable failure', stackFrameWithoutCredentials(stackFrame) @@ -216,12 +179,14 @@ export class Transporter { * down it will remain down for the next 2 minutes. In a timeout situation, * this host will be added end of the list of hosts on the next request. */ - await this.hostsCache.set( + await hostsCache.set( host, - new StatefulHost(host, response.isTimedOut ? 'timedout' : 'down') + createStatefulHost(host, response.isTimedOut ? 'timedout' : 'down') ); - return retry(hosts, getTimeout); + + return retry(retryableHosts, getTimeout); } + if (isSuccess(response)) { return deserializeSuccess(response); } @@ -238,12 +203,24 @@ export class Transporter { * 2. We also get from the retryable options a timeout multiplier that is tailored * for the current context. */ - const compatibleHosts = this.hosts.filter( + const compatibleHosts = hosts.filter( (host) => host.accept === 'readWrite' || (isRead ? host.accept === 'read' : host.accept === 'write') ); - const options = await this.createRetryableOptions(compatibleHosts); + const options = await createRetryableOptions(compatibleHosts); + return retry([...options.hosts].reverse(), options.getTimeout); } + + return { + hostsCache, + requester, + timeouts, + userAgent, + baseHeaders, + baseQueryParameters, + hosts, + request: retryableRequest, + }; } diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/helpers.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/helpers.ts index 5d64ac8868..0bde126a2f 100644 --- a/clients/algoliasearch-client-javascript/packages/client-common/src/helpers.ts +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/helpers.ts @@ -112,6 +112,5 @@ export function deserializeFailure( } catch (e) { // .. } - return new ApiError(message, status, stackFrame); } diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/types.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/types.ts deleted file mode 100644 index 1f45c28816..0000000000 --- a/clients/algoliasearch-client-javascript/packages/client-common/src/types.ts +++ /dev/null @@ -1,111 +0,0 @@ -export type Method = 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT'; - -export type Request = { - method: Method; - path: string; - data?: Record; -}; - -export type RequestOptions = { - /** - * Custom timeout for the request. Note that, in normal situacions - * the given timeout will be applied. But the transporter layer may - * increase this timeout if there is need for it. - */ - timeout?: number; - - /** - * Custom headers for the request. This headers are - * going to be merged the transporter headers. - */ - headers?: Record; - - /** - * Custom query parameters for the request. This query parameters are - * going to be merged the transporter query parameters. - */ - queryParameters: Record; - data?: Record; -}; - -export type EndRequest = { - method: Method; - url: string; - connectTimeout: number; - responseTimeout: number; - headers: Headers; - data?: string; -}; - -export type Response = { - content: string; - isTimedOut: boolean; - status: number; -}; - -export type EchoResponse = Request & { - connectTimeout: number; - host: string; - headers: Record; - responseTimeout: number; - searchParams?: Record; - userAgent?: string; -}; - -export type Headers = Record; -export type QueryParameters = Record; - -export type Host = { - url: string; - accept: 'read' | 'readWrite' | 'write'; - protocol: 'http' | 'https'; -}; - -export type StackFrame = { - request: EndRequest; - response: Response; - host: Host; - triesLeft: number; -}; - -export type Timeouts = { - readonly connect: number; - readonly read: number; - readonly write: number; -}; - -export type UserAgentOptions = { - /** - * The segment. Usually the integration name. - */ - readonly segment: string; - - /** - * The version. Usually the integration version. - */ - readonly version?: string; -}; - -export type UserAgent = { - /** - * The raw value of the user agent. - */ - value: string; - - /** - * Mutates the current user agent ading the given user agent options. - */ - readonly add: (options: UserAgentOptions) => UserAgent; -}; - -export type AuthMode = 'WithinHeaders' | 'WithinQueryParameters'; - -export type CreateClientOptions = { - appId: string; - apiKey: string; - requester: any; - timeouts: Timeouts; - userAgents: UserAgentOptions[]; - hosts?: Host[]; - authMode?: AuthMode; -}; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/types/Cache.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Cache.ts new file mode 100644 index 0000000000..ad35ba9c90 --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Cache.ts @@ -0,0 +1,27 @@ +export type Cache = { + /** + * Gets the value of the given `key`. + */ + get: ( + key: Record | string, + defaultValue: () => Promise + ) => Promise; + + /** + * Sets the given value with the given `key`. + */ + set: ( + key: Record | string, + value: TValue + ) => Promise; + + /** + * Deletes the given `key`. + */ + delete: (key: Record | string) => Promise; + + /** + * Clears the cache. + */ + clear: () => Promise; +}; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/types/CreateClient.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/types/CreateClient.ts new file mode 100644 index 0000000000..21993b9a61 --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/types/CreateClient.ts @@ -0,0 +1,14 @@ +import type { Host } from './Host'; +import type { Timeouts, UserAgentOptions } from './Transporter'; + +export type AuthMode = 'WithinHeaders' | 'WithinQueryParameters'; + +export type CreateClientOptions = { + appId: string; + apiKey: string; + requester: any; + timeouts: Timeouts; + userAgents: UserAgentOptions[]; + hosts?: Host[]; + authMode?: AuthMode; +}; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/types/Host.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Host.ts new file mode 100644 index 0000000000..6c314e4591 --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Host.ts @@ -0,0 +1,12 @@ +export type Host = { + url: string; + accept: 'read' | 'readWrite' | 'write'; + protocol: 'http' | 'https'; +}; + +export type StatefulHost = Host & { + status: 'down' | 'timedout' | 'up'; + lastUpdate: number; + isUp: () => boolean; + isTimedout: () => boolean; +}; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/types/Requester.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Requester.ts new file mode 100644 index 0000000000..cac301d9a4 --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Requester.ts @@ -0,0 +1,40 @@ +import type { Headers } from './Transporter'; + +export type Method = 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT'; + +export type Request = { + method: Method; + path: string; + data?: Record; +}; + +export type EndRequest = { + method: Method; + url: string; + connectTimeout: number; + responseTimeout: number; + headers: Headers; + data?: string; +}; + +export type Response = { + content: string; + isTimedOut: boolean; + status: number; +}; + +export type Requester = { + /** + * Sends the given `request` to the server. + */ + send: (request: EndRequest, originalRequest: Request) => Promise; +}; + +export type EchoResponse = Request & { + connectTimeout: number; + host: string; + headers: Headers; + responseTimeout: number; + searchParams?: Record; + userAgent?: string; +}; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/types/Transporter.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Transporter.ts new file mode 100644 index 0000000000..d49ebf17cd --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/types/Transporter.ts @@ -0,0 +1,162 @@ +import type { Cache } from './Cache'; +import type { Host } from './Host'; +import type { Request, Requester, EndRequest, Response } from './Requester'; + +export type Headers = Record; + +export type QueryParameters = Record; + +export type RequestOptions = { + /** + * Custom timeout for the request. Note that, in normal situacions + * the given timeout will be applied. But the transporter layer may + * increase this timeout if there is need for it. + */ + timeout?: number; + + /** + * Custom headers for the request. This headers are + * going to be merged the transporter headers. + */ + headers?: Headers; + + /** + * Custom query parameters for the request. This query parameters are + * going to be merged the transporter query parameters. + */ + queryParameters: QueryParameters; + data?: Record; +}; + +export type StackFrame = { + request: EndRequest; + response: Response; + host: Host; + triesLeft: number; +}; + +export type UserAgentOptions = { + /** + * The segment. Usually the integration name. + */ + readonly segment: string; + + /** + * The version. Usually the integration version. + */ + readonly version?: string; +}; + +export type UserAgent = { + /** + * The raw value of the user agent. + */ + value: string; + + /** + * Mutates the current user agent ading the given user agent options. + */ + readonly add: (options: UserAgentOptions) => UserAgent; +}; + +export type Timeouts = { + connect: number; + read: number; + write: number; +}; + +export type TransporterOptions = { + /** + * The cache of the hosts. Usually used to persist + * the state of the host when its down. + */ + hostsCache: Cache; + + /** + * The underlying requester used. Should differ + * depending of the enviroment where the client + * will be used. + */ + requester: Requester; + + /** + * The timeouts used by the requester. The transporter + * layer may increase this timeouts as defined on the + * retry strategy. + */ + timeouts: Timeouts; + + /** + * The hosts used by the requester. + */ + hosts: Host[]; + + /** + * The headers used by the requester. The transporter + * layer may add some extra headers during the request + * for the user agent, and others. + */ + baseHeaders: Headers; + + /** + * The query parameters used by the requester. The transporter + * layer may add some extra headers during the request + * for the user agent, and others. + */ + baseQueryParameters: QueryParameters; + + /** + * The user agent used. Sent on query parameters. + */ + userAgent: UserAgent; +}; + +export type Transporter = { + /** + * The cache of the hosts. Usually used to persist + * the state of the host when its down. + */ + hostsCache: Cache; + + /** + * The underlying requester used. Should differ + * depending of the enviroment where the client + * will be used. + */ + requester: Requester; + + /** + * The timeouts used by the requester. The transporter + * layer may increase this timeouts as defined on the + * retry strategy. + */ + timeouts: Timeouts; + + /** + * The user agent used. Sent on query parameters. + */ + userAgent: UserAgent; + + /** + * The headers used on each request. + */ + baseHeaders: Headers; + + /** + * The query parameters used on each request. + */ + baseQueryParameters: QueryParameters; + + /** + * The hosts used by the retry strategy. + */ + hosts: Host[]; + + /** + * Performs a read request using read hosts. + */ + request: ( + request: Request, + requestOptions: RequestOptions + ) => Promise; +}; diff --git a/clients/algoliasearch-client-javascript/packages/client-common/src/types/index.ts b/clients/algoliasearch-client-javascript/packages/client-common/src/types/index.ts new file mode 100644 index 0000000000..ecfac34168 --- /dev/null +++ b/clients/algoliasearch-client-javascript/packages/client-common/src/types/index.ts @@ -0,0 +1,5 @@ +export * from './Cache'; +export * from './CreateClient'; +export * from './Host'; +export * from './Requester'; +export * from './Transporter'; diff --git a/clients/algoliasearch-client-javascript/packages/client-insights/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-insights/builds/browser.ts index b3181b2c0e..7a84056553 100644 --- a/clients/algoliasearch-client-javascript/packages/client-insights/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-insights/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createInsightsApi } from '../src/insightsApi'; import type { InsightsApi, Region } from '../src/insightsApi'; @@ -29,7 +29,7 @@ export function insightsApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-insights/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-insights/builds/node.ts index 5c11731747..294a12f533 100644 --- a/clients/algoliasearch-client-javascript/packages/client-insights/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-insights/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createInsightsApi } from '../src/insightsApi'; import type { InsightsApi, Region } from '../src/insightsApi'; @@ -29,7 +29,7 @@ export function insightsApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-insights/src/insightsApi.ts b/clients/algoliasearch-client-javascript/packages/client-insights/src/insightsApi.ts index 8c55c4fdf3..92a4f2ea0c 100644 --- a/clients/algoliasearch-client-javascript/packages/client-insights/src/insightsApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-insights/src/insightsApi.ts @@ -1,4 +1,9 @@ -import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, +} from '@algolia/client-common'; import type { CreateClientOptions, Headers, @@ -30,8 +35,9 @@ export function createInsightsApi( options: CreateClientOptions & { region?: Region } ) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.region), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/client-personalization/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-personalization/builds/browser.ts index 89be08d2db..1504ff76a2 100644 --- a/clients/algoliasearch-client-javascript/packages/client-personalization/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-personalization/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createPersonalizationApi } from '../src/personalizationApi'; import type { PersonalizationApi, Region } from '../src/personalizationApi'; @@ -33,7 +33,7 @@ export function personalizationApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-personalization/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-personalization/builds/node.ts index 0d5e4b0694..675a54f521 100644 --- a/clients/algoliasearch-client-javascript/packages/client-personalization/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-personalization/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createPersonalizationApi } from '../src/personalizationApi'; import type { PersonalizationApi, Region } from '../src/personalizationApi'; @@ -33,7 +33,7 @@ export function personalizationApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-personalization/src/personalizationApi.ts b/clients/algoliasearch-client-javascript/packages/client-personalization/src/personalizationApi.ts index c14ebb0589..ceeeff0aab 100644 --- a/clients/algoliasearch-client-javascript/packages/client-personalization/src/personalizationApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-personalization/src/personalizationApi.ts @@ -1,4 +1,9 @@ -import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, +} from '@algolia/client-common'; import type { CreateClientOptions, Headers, @@ -30,8 +35,9 @@ export function createPersonalizationApi( options: CreateClientOptions & { region: Region } ) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.region), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/client-predict/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-predict/builds/browser.ts index 1baeab85d4..86adb2976f 100644 --- a/clients/algoliasearch-client-javascript/packages/client-predict/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-predict/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createPredictApi } from '../src/predictApi'; import type { PredictApi } from '../src/predictApi'; @@ -27,7 +27,7 @@ export function predictApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-predict/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-predict/builds/node.ts index 2b04f48f16..9737dc6884 100644 --- a/clients/algoliasearch-client-javascript/packages/client-predict/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-predict/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createPredictApi } from '../src/predictApi'; import type { PredictApi } from '../src/predictApi'; @@ -27,7 +27,7 @@ export function predictApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-predict/src/predictApi.ts b/clients/algoliasearch-client-javascript/packages/client-predict/src/predictApi.ts index b810c46cdd..4370f36e9b 100644 --- a/clients/algoliasearch-client-javascript/packages/client-predict/src/predictApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-predict/src/predictApi.ts @@ -1,4 +1,9 @@ -import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, +} from '@algolia/client-common'; import type { CreateClientOptions, Headers, @@ -24,8 +29,9 @@ function getDefaultHosts(): Host[] { // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createPredictApi(options: CreateClientOptions) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/browser.ts index 14bd543b05..6eaf109907 100644 --- a/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createQuerySuggestionsApi } from '../src/querySuggestionsApi'; import type { QuerySuggestionsApi, Region } from '../src/querySuggestionsApi'; @@ -33,7 +33,7 @@ export function querySuggestionsApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/node.ts index 6f3ea55902..0b890d2707 100644 --- a/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-query-suggestions/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createQuerySuggestionsApi } from '../src/querySuggestionsApi'; import type { QuerySuggestionsApi, Region } from '../src/querySuggestionsApi'; @@ -33,7 +33,7 @@ export function querySuggestionsApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-query-suggestions/src/querySuggestionsApi.ts b/clients/algoliasearch-client-javascript/packages/client-query-suggestions/src/querySuggestionsApi.ts index cf183823bf..7b96119a8c 100644 --- a/clients/algoliasearch-client-javascript/packages/client-query-suggestions/src/querySuggestionsApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-query-suggestions/src/querySuggestionsApi.ts @@ -1,4 +1,9 @@ -import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, +} from '@algolia/client-common'; import type { CreateClientOptions, Headers, @@ -32,8 +37,9 @@ export function createQuerySuggestionsApi( options: CreateClientOptions & { region: Region } ) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.region), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/client-search/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-search/builds/browser.ts index 3580501c66..e1a5131532 100644 --- a/clients/algoliasearch-client-javascript/packages/client-search/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-search/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createSearchApi } from '../src/searchApi'; import type { SearchApi } from '../src/searchApi'; @@ -27,7 +27,7 @@ export function searchApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-search/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-search/builds/node.ts index 3f80488550..9f3a39c78f 100644 --- a/clients/algoliasearch-client-javascript/packages/client-search/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-search/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createSearchApi } from '../src/searchApi'; import type { SearchApi } from '../src/searchApi'; @@ -27,7 +27,7 @@ export function searchApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-search/src/searchApi.ts b/clients/algoliasearch-client-javascript/packages/client-search/src/searchApi.ts index bf4b92adda..b99e6a7f89 100644 --- a/clients/algoliasearch-client-javascript/packages/client-search/src/searchApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-search/src/searchApi.ts @@ -1,8 +1,9 @@ import { - shuffle, - Transporter, createAuth, + createMemoryCache, + createTransporter, getUserAgent, + shuffle, } from '@algolia/client-common'; import type { CreateClientOptions, @@ -108,8 +109,9 @@ function getDefaultHosts(appId: string): Host[] { // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createSearchApi(options: CreateClientOptions) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.appId), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/client-sources/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/client-sources/builds/browser.ts index b92e7c7d99..bcb97284f6 100644 --- a/clients/algoliasearch-client-javascript/packages/client-sources/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/client-sources/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createSourcesApi } from '../src/sourcesApi'; import type { SourcesApi, Region } from '../src/sourcesApi'; @@ -33,7 +33,7 @@ export function sourcesApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/client-sources/builds/node.ts b/clients/algoliasearch-client-javascript/packages/client-sources/builds/node.ts index 637376e61a..ec0d2c7b87 100644 --- a/clients/algoliasearch-client-javascript/packages/client-sources/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/client-sources/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createSourcesApi } from '../src/sourcesApi'; import type { SourcesApi, Region } from '../src/sourcesApi'; @@ -33,7 +33,7 @@ export function sourcesApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/client-sources/src/sourcesApi.ts b/clients/algoliasearch-client-javascript/packages/client-sources/src/sourcesApi.ts index 8dc535995a..2f2b15887f 100644 --- a/clients/algoliasearch-client-javascript/packages/client-sources/src/sourcesApi.ts +++ b/clients/algoliasearch-client-javascript/packages/client-sources/src/sourcesApi.ts @@ -1,4 +1,9 @@ -import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, +} from '@algolia/client-common'; import type { CreateClientOptions, Headers, @@ -28,8 +33,9 @@ export function createSourcesApi( options: CreateClientOptions & { region: Region } ) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.region), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/recommend/builds/browser.ts b/clients/algoliasearch-client-javascript/packages/recommend/builds/browser.ts index d42c18b315..290c99347f 100644 --- a/clients/algoliasearch-client-javascript/packages/recommend/builds/browser.ts +++ b/clients/algoliasearch-client-javascript/packages/recommend/builds/browser.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { createRecommendApi } from '../src/recommendApi'; import type { RecommendApi } from '../src/recommendApi'; @@ -27,7 +27,7 @@ export function recommendApi( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/clients/algoliasearch-client-javascript/packages/recommend/builds/node.ts b/clients/algoliasearch-client-javascript/packages/recommend/builds/node.ts index 4ffef76ee6..c193589bed 100644 --- a/clients/algoliasearch-client-javascript/packages/recommend/builds/node.ts +++ b/clients/algoliasearch-client-javascript/packages/recommend/builds/node.ts @@ -1,5 +1,5 @@ import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { createRecommendApi } from '../src/recommendApi'; import type { RecommendApi } from '../src/recommendApi'; @@ -27,7 +27,7 @@ export function recommendApi( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, }); diff --git a/clients/algoliasearch-client-javascript/packages/recommend/src/recommendApi.ts b/clients/algoliasearch-client-javascript/packages/recommend/src/recommendApi.ts index d4d1ae1880..8d1b336333 100644 --- a/clients/algoliasearch-client-javascript/packages/recommend/src/recommendApi.ts +++ b/clients/algoliasearch-client-javascript/packages/recommend/src/recommendApi.ts @@ -1,8 +1,9 @@ import { - shuffle, - Transporter, createAuth, + createMemoryCache, + createTransporter, getUserAgent, + shuffle, } from '@algolia/client-common'; import type { CreateClientOptions, @@ -54,8 +55,9 @@ function getDefaultHosts(appId: string): Host[] { // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function createRecommendApi(options: CreateClientOptions) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts(options.appId), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/index.ts b/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/index.ts index 845ef0adbc..073e14e3d3 100644 --- a/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/index.ts +++ b/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/index.ts @@ -1,2 +1,2 @@ +export * from './src/createXhrRequester'; export * from './src/echoRequester'; -export * from './src/XhrRequester'; diff --git a/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/src/XhrRequester.ts b/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/src/createXhrRequester.ts similarity index 89% rename from clients/algoliasearch-client-javascript/packages/requester-browser-xhr/src/XhrRequester.ts rename to clients/algoliasearch-client-javascript/packages/requester-browser-xhr/src/createXhrRequester.ts index c3c6e7d073..3177907444 100644 --- a/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/src/XhrRequester.ts +++ b/clients/algoliasearch-client-javascript/packages/requester-browser-xhr/src/createXhrRequester.ts @@ -1,8 +1,7 @@ -import { Requester } from '@algolia/client-common'; -import type { EndRequest, Response } from '@algolia/client-common'; +import type { EndRequest, Requester, Response } from '@algolia/client-common'; -export class XhrRequester extends Requester { - send(request: EndRequest): Promise { +export function createXhrRequester(): Requester { + function send(request: EndRequest): Promise { return new Promise((resolve) => { const baseRequester = new XMLHttpRequest(); baseRequester.open(request.method, request.url, true); @@ -75,4 +74,6 @@ export class XhrRequester extends Requester { baseRequester.send(request.data); }); } + + return { send }; } diff --git a/clients/algoliasearch-client-javascript/packages/requester-node-http/index.ts b/clients/algoliasearch-client-javascript/packages/requester-node-http/index.ts index 017b093982..d43eff3c7f 100644 --- a/clients/algoliasearch-client-javascript/packages/requester-node-http/index.ts +++ b/clients/algoliasearch-client-javascript/packages/requester-node-http/index.ts @@ -1,2 +1,2 @@ export * from './src/echoRequester'; -export * from './src/HttpRequester'; +export * from './src/createHttpRequester'; diff --git a/clients/algoliasearch-client-javascript/packages/requester-node-http/src/HttpRequester.ts b/clients/algoliasearch-client-javascript/packages/requester-node-http/src/createHttpRequester.ts similarity index 92% rename from clients/algoliasearch-client-javascript/packages/requester-node-http/src/HttpRequester.ts rename to clients/algoliasearch-client-javascript/packages/requester-node-http/src/createHttpRequester.ts index 1e9b2cb2b5..fc8b12818b 100644 --- a/clients/algoliasearch-client-javascript/packages/requester-node-http/src/HttpRequester.ts +++ b/clients/algoliasearch-client-javascript/packages/requester-node-http/src/createHttpRequester.ts @@ -2,16 +2,15 @@ import http from 'http'; import https from 'https'; import { URL } from 'url'; -import { Requester } from '@algolia/client-common'; -import type { EndRequest, Response } from '@algolia/client-common'; +import type { EndRequest, Requester, Response } from '@algolia/client-common'; // Global agents allow us to reuse the TCP protocol with multiple clients const agentOptions = { keepAlive: true }; const httpAgent = new http.Agent(agentOptions); const httpsAgent = new https.Agent(agentOptions); -export class HttpRequester extends Requester { - send(request: EndRequest): Promise { +export function createHttpRequester(): Requester { + function send(request: EndRequest): Promise { return new Promise((resolve) => { let responseTimeout: NodeJS.Timeout | undefined; // eslint-disable-next-line prefer-const -- linter thinks this is not reassigned @@ -91,4 +90,6 @@ export class HttpRequester extends Requester { req.end(); }); } + + return { send }; } diff --git a/templates/javascript/api-all.mustache b/templates/javascript/api-all.mustache index ac57d214ab..2615919e28 100644 --- a/templates/javascript/api-all.mustache +++ b/templates/javascript/api-all.mustache @@ -1,7 +1,7 @@ {{! This file will be renamed and moved to `builds/browser.ts` after generating the client }} import type { Host, Requester } from '@algolia/client-common'; -import { XhrRequester } from '@algolia/requester-browser-xhr'; +import { createXhrRequester } from '@algolia/requester-browser-xhr'; import { create{{capitalizedApiName}}Api } from '../src/{{apiName}}Api'; import type { {{capitalizedApiName}}Api } from '../src/{{apiName}}Api'; @@ -42,7 +42,7 @@ export function {{apiName}}Api( read: 2, write: 30, }, - requester: options?.requester ?? new XhrRequester(), + requester: options?.requester ?? createXhrRequester(), userAgents: [{ segment: 'Browser' }], authMode: 'WithinQueryParameters', ...options, diff --git a/templates/javascript/api-single.mustache b/templates/javascript/api-single.mustache index cacf452380..5c948ac60b 100644 --- a/templates/javascript/api-single.mustache +++ b/templates/javascript/api-single.mustache @@ -1,5 +1,16 @@ -import { shuffle, Transporter, createAuth, getUserAgent } from '@algolia/client-common'; -import type { CreateClientOptions, Headers, Host, Request } from '@algolia/client-common'; +import { + createAuth, + createMemoryCache, + createTransporter, + getUserAgent, + shuffle, +} from '@algolia/client-common'; +import type { + CreateClientOptions, + Headers, + Host, + Request, +} from '@algolia/client-common'; {{#imports}} import { {{classname}} } from '{{filename}}'; @@ -72,8 +83,9 @@ function getDefaultHosts(region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}} // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function create{{capitalizedApiName}}Api(options: CreateClientOptions{{#hasRegionalHost}} & {region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}: Region }{{/hasRegionalHost}}) { const auth = createAuth(options.appId, options.apiKey, options.authMode); - const transporter = new Transporter({ + const transporter = createTransporter({ hosts: options?.hosts ?? getDefaultHosts({{^hasRegionalHost}}{{^experimentalHost}}options.appId{{/experimentalHost}}{{/hasRegionalHost}}{{#hasRegionalHost}}options.region{{/hasRegionalHost}}), + hostsCache: createMemoryCache(), baseHeaders: { 'content-type': 'application/x-www-form-urlencoded', ...auth.headers(), diff --git a/templates/javascript/api.mustache b/templates/javascript/api.mustache index 0fc6980d82..72318f2069 100644 --- a/templates/javascript/api.mustache +++ b/templates/javascript/api.mustache @@ -1,7 +1,7 @@ {{! This file will be renamed and moved to `builds/node.ts` after generating the client }} import type { Host, Requester } from '@algolia/client-common'; -import { HttpRequester } from '@algolia/requester-node-http'; +import { createHttpRequester } from '@algolia/requester-node-http'; import { create{{capitalizedApiName}}Api } from '../src/{{apiName}}Api'; import type { {{capitalizedApiName}}Api } from '../src/{{apiName}}Api'; @@ -41,7 +41,7 @@ export function {{apiName}}Api( read: 5, write: 30, }, - requester: options?.requester ?? new HttpRequester(), + requester: options?.requester ?? createHttpRequester(), userAgents: [{ segment: 'Node.js', version: process.versions.node }], ...options, });