diff --git a/.eslintrc.js b/.eslintrc.js index 1c753ed834..bddc0f5770 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -64,6 +64,10 @@ module.exports = { 'no-continue': 0, '@typescript-eslint/prefer-enum-initializers': 0, + // in the meantime of finding an alternative, we warn + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': ['warn'], + '@typescript-eslint/no-unused-vars': 2, 'unused-imports/no-unused-imports-ts': 2, '@typescript-eslint/member-ordering': [ diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 35832800a4..60fad58e4e 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -30,7 +30,19 @@ runs: uses: actions/cache@v2 with: path: /home/runner/work/api-clients-automation/api-clients-automation/clients/algoliasearch-client-javascript/client-common/dist - key: ${{ runner.os }}-1-js-client-common-${{ hashFiles('clients/common-client-javascript/client-common/**') }} + key: ${{ runner.os }}-1-js-client-common-${{ hashFiles('clients/algoliasearch-client-javascript/client-common/**') }} + + - name: Restore built JavaScript node requester + uses: actions/cache@v2 + with: + path: /home/runner/work/api-clients-automation/api-clients-automation/clients/algoliasearch-client-javascript/requester-node-http/dist + key: ${{ runner.os }}-1-js-node-requester-${{ hashFiles('clients/algoliasearch-client-javascript/requester-node-http/**') }} + + - name: Restore built JavaScript browser requester + uses: actions/cache@v2 + with: + path: /home/runner/work/api-clients-automation/api-clients-automation/clients/algoliasearch-client-javascript/requester-browser-xhr/dist + key: ${{ runner.os }}-1-js-browser-requester-${{ hashFiles('clients/algoliasearch-client-javascript/requester-browser-xhr/**') }} - name: Restore built JavaScript search client if: ${{ inputs.job == 'cts' }} diff --git a/clients/README.md b/clients/README.md index 39e463e08c..cb4a2a30dd 100644 --- a/clients/README.md +++ b/clients/README.md @@ -18,7 +18,6 @@ This folder hosts the generated clients. - [@algolia/client-search](./algoliasearch-client-javascript/client-search/): The Algolia search client. - [@algolia/recommend](./algoliasearch-client-javascript/recommend/): The Algolia recommend client. - [@algolia/sources](./algoliasearch-client-javascript/client-sources/): The Algolia sources client. - -#### Utils - -- [JavaScript](./algoliasearch-client-javascript/client-common/): The JavaScript clients common files. +- [@algolia/client-common](./algoliasearch-client-javascript/client-common/): The JavaScript clients common files. +- [@algolia/requester-browser-xhr](./algoliasearch-client-javascript/requester-browser-xhr/): Browser XHR requester for the Algolia JavaScript clients. +- [@algolia/requester-node-http](./algoliasearch-client-javascript/requester-node-http/): Node.js HTTP requester for the Algolia JavaScript clients. diff --git a/clients/algoliasearch-client-javascript/client-abtesting/api.ts b/clients/algoliasearch-client-javascript/client-abtesting/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/client-abtesting/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/client-abtesting/browser.ts b/clients/algoliasearch-client-javascript/client-abtesting/browser.ts new file mode 100644 index 0000000000..9e88d794a9 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-abtesting/browser.ts @@ -0,0 +1,38 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createAbtestingApi } from './src/abtestingApi'; +import type { AbtestingApi, Region } from './src/abtestingApi'; + +export * from './src/abtestingApi'; +export * from '@algolia/client-common'; + +export function abtestingApi( + appId: string, + apiKey: string, + region?: Region, + options?: { requester?: Requester; hosts?: Host[] } +): AbtestingApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createAbtestingApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-abtesting/node.ts b/clients/algoliasearch-client-javascript/client-abtesting/node.ts new file mode 100644 index 0000000000..efe09f497e --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-abtesting/node.ts @@ -0,0 +1,37 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createAbtestingApi } from './src/abtestingApi'; +import type { AbtestingApi, Region } from './src/abtestingApi'; + +export * from './src/abtestingApi'; +export * from '@algolia/client-common'; + +export function abtestingApi( + appId: string, + apiKey: string, + region?: Region, + options?: { requester?: Requester; hosts?: Host[] } +): AbtestingApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createAbtestingApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-abtesting/package.json b/clients/algoliasearch-client-javascript/client-abtesting/package.json index 16529da4c3..d3f2fba1a6 100644 --- a/clients/algoliasearch-client-javascript/client-abtesting/package.json +++ b/clients/algoliasearch-client-javascript/client-abtesting/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/client-abtesting/src/abtestingApi.ts b/clients/algoliasearch-client-javascript/client-abtesting/src/abtestingApi.ts index 87ad7188fa..6b634a7800 100644 --- a/clients/algoliasearch-client-javascript/client-abtesting/src/abtestingApi.ts +++ b/clients/algoliasearch-client-javascript/client-abtesting/src/abtestingApi.ts @@ -1,10 +1,9 @@ -import { Transporter } from '@algolia/client-common'; +import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { ABTest } from '../model/aBTest'; @@ -14,98 +13,38 @@ import type { ListABTestsResponse } from '../model/listABTestsResponse'; export const version = '5.0.0'; -export class AbtestingApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; - - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - region?: 'de' | 'us', - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } - - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } +export type Region = 'de' | 'us'; - this.setAuthentication({ appId, apiKey }); +function getDefaultHosts(region?: Region): Host[] { + const regionHost = region ? `.${region}.` : '.'; - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(region), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', - }, - userAgent: 'Algolia for Javascript (5.0.0)', - timeouts: { - connect: 2, - read: 5, - write: 30, - }, - requester: options?.requester, - }); - } - - getDefaultHosts(region?: 'de' | 'us'): Host[] { - const regionHost = region ? `.${region}.` : '.'; - - return [ - { - url: `analytics${regionHost}algolia.com`, - accept: 'readWrite', - protocol: 'https', - }, - ]; - } - - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } - - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } + return [ + { + url: `analytics${regionHost}algolia.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]; +} - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createAbtestingApi = ( + options: CreateClientOptions & { region?: Region } +) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.region), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'Abtesting', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * Creates a new A/B test with provided configuration. You can set an A/B test on two different indices with different settings, or on the same index with different search parameters by providing a customSearchParameters setting on one of the variants. @@ -113,7 +52,9 @@ export class AbtestingApi { * @summary Creates a new A/B test with provided configuration. * @param addABTestsRequest - The addABTestsRequest object. */ - addABTests(addABTestsRequest: AddABTestsRequest): Promise { + function addABTests( + addABTestsRequest: AddABTestsRequest + ): Promise { const path = '/2/abtests'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -146,13 +87,15 @@ export class AbtestingApi { data: addABTestsRequest, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Deletes the A/B Test and removes all associated metadata & metrics. * @@ -160,7 +103,7 @@ export class AbtestingApi { * @param deleteABTest - The deleteABTest object. * @param deleteABTest.id - The A/B test ID. */ - deleteABTest({ id }: DeleteABTestProps): Promise { + function deleteABTest({ id }: DeleteABTestProps): Promise { const path = '/2/abtests/{id}'.replace( '{id}', encodeURIComponent(String(id)) @@ -179,13 +122,15 @@ export class AbtestingApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns metadata and metrics for A/B test id. Behaves in the same way as GET /2/abtests however the endpoint will return 403. * @@ -193,7 +138,7 @@ export class AbtestingApi { * @param getABTest - The getABTest object. * @param getABTest.id - The A/B test ID. */ - getABTest({ id }: GetABTestProps): Promise { + function getABTest({ id }: GetABTestProps): Promise { const path = '/2/abtests/{id}'.replace( '{id}', encodeURIComponent(String(id)) @@ -210,13 +155,15 @@ export class AbtestingApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Fetch all existing A/B tests for App that are available for the current API Key. Returns an array of metadata and metrics. When no data has been processed, the metrics will be returned as null. * @@ -225,7 +172,7 @@ export class AbtestingApi { * @param listABTests.offset - Position of the starting record. Used for paging. 0 is the first record. * @param listABTests.limit - Number of records to return. Limit is the size of the page. */ - listABTests({ + function listABTests({ offset, limit, }: ListABTestsProps): Promise { @@ -246,13 +193,15 @@ export class AbtestingApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Marks the A/B test as stopped. At this point, the test is over and cannot be restarted. As a result, your application is back to normal: index A will perform as usual, receiving 100% of all search requests. Associated metadata and metrics are still stored. * @@ -260,7 +209,7 @@ export class AbtestingApi { * @param stopABTest - The stopABTest object. * @param stopABTest.id - The A/B test ID. */ - stopABTest({ id }: StopABTestProps): Promise { + function stopABTest({ id }: StopABTestProps): Promise { const path = '/2/abtests/{id}/stop'.replace( '{id}', encodeURIComponent(String(id)) @@ -277,14 +226,19 @@ export class AbtestingApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { addABTests, deleteABTest, getABTest, listABTests, stopABTest }; +}; + +export type AbtestingApi = ReturnType; export type DeleteABTestProps = { /** diff --git a/clients/algoliasearch-client-javascript/client-abtesting/src/apis.ts b/clients/algoliasearch-client-javascript/client-abtesting/src/apis.ts deleted file mode 100644 index f61ac9a013..0000000000 --- a/clients/algoliasearch-client-javascript/client-abtesting/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AbtestingApi } from './abtestingApi'; - -export * from './abtestingApi'; -export * from '@algolia/client-common'; - -export const APIS = [AbtestingApi]; diff --git a/clients/algoliasearch-client-javascript/client-abtesting/tsconfig.json b/clients/algoliasearch-client-javascript/client-abtesting/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/client-abtesting/tsconfig.json +++ b/clients/algoliasearch-client-javascript/client-abtesting/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/client-analytics/api.ts b/clients/algoliasearch-client-javascript/client-analytics/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/client-analytics/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/client-analytics/browser.ts b/clients/algoliasearch-client-javascript/client-analytics/browser.ts new file mode 100644 index 0000000000..57aa6ee421 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-analytics/browser.ts @@ -0,0 +1,38 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createAnalyticsApi } from './src/analyticsApi'; +import type { AnalyticsApi, Region } from './src/analyticsApi'; + +export * from './src/analyticsApi'; +export * from '@algolia/client-common'; + +export function analyticsApi( + appId: string, + apiKey: string, + region?: Region, + options?: { requester?: Requester; hosts?: Host[] } +): AnalyticsApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createAnalyticsApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-analytics/node.ts b/clients/algoliasearch-client-javascript/client-analytics/node.ts new file mode 100644 index 0000000000..0adfd8f249 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-analytics/node.ts @@ -0,0 +1,37 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createAnalyticsApi } from './src/analyticsApi'; +import type { AnalyticsApi, Region } from './src/analyticsApi'; + +export * from './src/analyticsApi'; +export * from '@algolia/client-common'; + +export function analyticsApi( + appId: string, + apiKey: string, + region?: Region, + options?: { requester?: Requester; hosts?: Host[] } +): AnalyticsApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createAnalyticsApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-analytics/package.json b/clients/algoliasearch-client-javascript/client-analytics/package.json index 8152c8d9f8..917749d0f9 100644 --- a/clients/algoliasearch-client-javascript/client-analytics/package.json +++ b/clients/algoliasearch-client-javascript/client-analytics/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/client-analytics/src/analyticsApi.ts b/clients/algoliasearch-client-javascript/client-analytics/src/analyticsApi.ts index 0649d7e8f4..2e8475a53a 100644 --- a/clients/algoliasearch-client-javascript/client-analytics/src/analyticsApi.ts +++ b/clients/algoliasearch-client-javascript/client-analytics/src/analyticsApi.ts @@ -1,10 +1,9 @@ -import { Transporter } from '@algolia/client-common'; +import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { GetAverageClickPositionResponse } from '../model/getAverageClickPositionResponse'; @@ -29,98 +28,38 @@ import type { GetUsersCountResponse } from '../model/getUsersCountResponse'; export const version = '5.0.0'; -export class AnalyticsApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; - - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - region?: 'de' | 'us', - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } - - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(region), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', - }, - userAgent: 'Algolia for Javascript (5.0.0)', - timeouts: { - connect: 2, - read: 5, - write: 30, - }, - requester: options?.requester, - }); - } +export type Region = 'de' | 'us'; - getDefaultHosts(region?: 'de' | 'us'): Host[] { - const regionHost = region ? `.${region}.` : '.'; +function getDefaultHosts(region?: Region): Host[] { + const regionHost = region ? `.${region}.` : '.'; - return [ - { - url: `analytics${regionHost}algolia.com`, - accept: 'readWrite', - protocol: 'https', - }, - ]; - } - - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } + return [ + { + url: `analytics${regionHost}algolia.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]; +} - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } - - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createAnalyticsApi = ( + options: CreateClientOptions & { region?: Region } +) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.region), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'Analytics', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * Returns the average click position. The endpoint returns a value for the complete given time range, as well as a value per day. @@ -132,7 +71,7 @@ export class AnalyticsApi { * @param getAverageClickPosition.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getAverageClickPosition.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getAverageClickPosition({ + function getAverageClickPosition({ index, startDate, endDate, @@ -169,13 +108,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns the distribution of clicks per range of positions. * @@ -186,7 +127,7 @@ export class AnalyticsApi { * @param getClickPositions.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getClickPositions.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getClickPositions({ + function getClickPositions({ index, startDate, endDate, @@ -223,13 +164,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns a click-through rate (CTR). The endpoint returns a value for the complete given time range, as well as a value per day. It also returns the count of clicks and searches used to compute the rates. * @@ -240,7 +183,7 @@ export class AnalyticsApi { * @param getClickThroughRate.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getClickThroughRate.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getClickThroughRate({ + function getClickThroughRate({ index, startDate, endDate, @@ -277,13 +220,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns a conversion rate (CR). The endpoint returns a value for the complete given time range, as well as a value per day. It also returns the count of conversion and searches used to compute the rates. * @@ -294,7 +239,7 @@ export class AnalyticsApi { * @param getConversationRate.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getConversationRate.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getConversationRate({ + function getConversationRate({ index, startDate, endDate, @@ -331,13 +276,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns the rate at which searches didn\'t lead to any clicks. The endpoint returns a value for the complete given time range, as well as a value per day. It also returns the count of searches and searches without clicks. * @@ -348,7 +295,7 @@ export class AnalyticsApi { * @param getNoClickRate.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getNoClickRate.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getNoClickRate({ + function getNoClickRate({ index, startDate, endDate, @@ -385,13 +332,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns the rate at which searches didn\'t return any results. The endpoint returns a value for the complete given time range, as well as a value per day. It also returns the count of searches and searches without results used to compute the rates. * @@ -402,7 +351,7 @@ export class AnalyticsApi { * @param getNoResultsRate.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getNoResultsRate.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getNoResultsRate({ + function getNoResultsRate({ index, startDate, endDate, @@ -439,13 +388,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns the number of searches across the given time range. The endpoint returns a value for the complete given time range, as well as a value per day. * @@ -456,7 +407,7 @@ export class AnalyticsApi { * @param getSearchesCount.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getSearchesCount.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getSearchesCount({ + function getSearchesCount({ index, startDate, endDate, @@ -493,13 +444,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top searches that didn\'t lead to any clicks. Limited to the 1000 most frequent ones. For each search, also returns the average number of found hits. * @@ -512,7 +465,7 @@ export class AnalyticsApi { * @param getSearchesNoClicks.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getSearchesNoClicks.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getSearchesNoClicks({ + function getSearchesNoClicks({ index, startDate, endDate, @@ -559,13 +512,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top searches that didn\'t return any results. Limited to the 1000 most frequent ones. * @@ -578,7 +533,7 @@ export class AnalyticsApi { * @param getSearchesNoResults.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getSearchesNoResults.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getSearchesNoResults({ + function getSearchesNoResults({ index, startDate, endDate, @@ -625,13 +580,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns the latest update time of the analytics API for a given index. If the index has been recently created and/or no search has been performed yet the updated time will be null. * @@ -639,7 +596,7 @@ export class AnalyticsApi { * @param getStatus - The getStatus object. * @param getStatus.index - The index name to target. */ - getStatus({ index }: GetStatusProps): Promise { + function getStatus({ index }: GetStatusProps): Promise { const path = '/2/status'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -659,13 +616,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top countries. Limited to the 1000 most frequent ones. * @@ -678,7 +637,7 @@ export class AnalyticsApi { * @param getTopCountries.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getTopCountries.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getTopCountries({ + function getTopCountries({ index, startDate, endDate, @@ -725,13 +684,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top filter attributes. Limited to the 1000 most used filters. * @@ -745,7 +706,7 @@ export class AnalyticsApi { * @param getTopFilterAttributes.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getTopFilterAttributes.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getTopFilterAttributes({ + function getTopFilterAttributes({ index, search, startDate, @@ -797,13 +758,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top filters for the given attribute. Limited to the 1000 most used filters. * @@ -818,7 +781,7 @@ export class AnalyticsApi { * @param getTopFilterForAttribute.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getTopFilterForAttribute.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getTopFilterForAttribute({ + function getTopFilterForAttribute({ attribute, index, search, @@ -880,13 +843,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top filters with no results. Limited to the 1000 most used filters. * @@ -900,7 +865,7 @@ export class AnalyticsApi { * @param getTopFiltersNoResults.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getTopFiltersNoResults.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getTopFiltersNoResults({ + function getTopFiltersNoResults({ index, search, startDate, @@ -952,13 +917,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top hits. Limited to the 1000 most frequent ones. * @@ -973,7 +940,7 @@ export class AnalyticsApi { * @param getTopHits.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getTopHits.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getTopHits({ + function getTopHits({ index, search, clickAnalytics, @@ -1032,13 +999,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns top searches. Limited to the 1000 most frequent ones. For each search, also returns the average number of hits returned. * @@ -1054,7 +1023,7 @@ export class AnalyticsApi { * @param getTopSearches.offset - Position of the starting record. Used for paging. 0 is the first record. * @param getTopSearches.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getTopSearches({ + function getTopSearches({ index, clickAnalytics, startDate, @@ -1118,13 +1087,15 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns the distinct count of users across the given time range. The endpoint returns a value for the complete given time range, as well as a value per day. * @@ -1135,7 +1106,7 @@ export class AnalyticsApi { * @param getUsersCount.endDate - The upper bound timestamp (a date, a string like \"2006-01-02\") of the period to analyze. * @param getUsersCount.tags - Filter metrics on the provided tags. Each tag must correspond to an analyticsTags set at search time. Multiple tags can be combined with the operators OR and AND. If a tag contains characters like spaces or parentheses, it should be URL encoded. */ - getUsersCount({ + function getUsersCount({ index, startDate, endDate, @@ -1172,14 +1143,37 @@ export class AnalyticsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { + getAverageClickPosition, + getClickPositions, + getClickThroughRate, + getConversationRate, + getNoClickRate, + getNoResultsRate, + getSearchesCount, + getSearchesNoClicks, + getSearchesNoResults, + getStatus, + getTopCountries, + getTopFilterAttributes, + getTopFilterForAttribute, + getTopFiltersNoResults, + getTopHits, + getTopSearches, + getUsersCount, + }; +}; + +export type AnalyticsApi = ReturnType; export type GetAverageClickPositionProps = { /** diff --git a/clients/algoliasearch-client-javascript/client-analytics/src/apis.ts b/clients/algoliasearch-client-javascript/client-analytics/src/apis.ts deleted file mode 100644 index ddc6ef0ece..0000000000 --- a/clients/algoliasearch-client-javascript/client-analytics/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AnalyticsApi } from './analyticsApi'; - -export * from './analyticsApi'; -export * from '@algolia/client-common'; - -export const APIS = [AnalyticsApi]; diff --git a/clients/algoliasearch-client-javascript/client-analytics/tsconfig.json b/clients/algoliasearch-client-javascript/client-analytics/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/client-analytics/tsconfig.json +++ b/clients/algoliasearch-client-javascript/client-analytics/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/client-common/index.ts b/clients/algoliasearch-client-javascript/client-common/index.ts index 74854d5114..c345b4ad6f 100644 --- a/clients/algoliasearch-client-javascript/client-common/index.ts +++ b/clients/algoliasearch-client-javascript/client-common/index.ts @@ -1,5 +1,8 @@ export * from './src/cache'; +export * from './src/createAuth'; +export * from './src/createUserAgent'; export * from './src/errors'; +export * from './src/getUserAgent'; export * from './src/helpers'; export * from './src/requester'; export * from './src/Response'; diff --git a/clients/algoliasearch-client-javascript/client-common/package.json b/clients/algoliasearch-client-javascript/client-common/package.json index ef64f26e23..df841ee432 100644 --- a/clients/algoliasearch-client-javascript/client-common/package.json +++ b/clients/algoliasearch-client-javascript/client-common/package.json @@ -13,7 +13,7 @@ "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "devDependencies": { diff --git a/clients/algoliasearch-client-javascript/client-common/src/Transporter.ts b/clients/algoliasearch-client-javascript/client-common/src/Transporter.ts index 48b4edebfd..a37614c817 100644 --- a/clients/algoliasearch-client-javascript/client-common/src/Transporter.ts +++ b/clients/algoliasearch-client-javascript/client-common/src/Transporter.ts @@ -10,7 +10,6 @@ import { serializeHeaders, serializeUrl, } from './helpers'; -import { HttpRequester } from './requester/HttpRequester'; import type { Requester } from './requester/Requester'; import { stackTraceWithoutCredentials, @@ -25,13 +24,14 @@ import type { Timeouts, Response, EndRequest, + UserAgent, } from './types'; export class Transporter { private hosts: Host[]; private baseHeaders: Headers; private hostsCache: Cache; - private userAgent: string; + private userAgent: UserAgent; private timeouts: Timeouts; private requester: Requester; @@ -40,13 +40,13 @@ export class Transporter { baseHeaders, userAgent, timeouts, - requester = new HttpRequester(), + requester, }: { hosts: Host[]; baseHeaders: Headers; - userAgent: string; + userAgent: UserAgent; timeouts: Timeouts; - requester?: Requester; + requester: Requester; }) { this.hosts = hosts; this.hostsCache = new MemoryCache(); @@ -134,7 +134,7 @@ export class Transporter { : {}; const queryParameters = { - 'x-algolia-agent': this.userAgent, + 'x-algolia-agent': this.userAgent.value, ...dataQueryParameters, ...requestOptions.queryParameters, }; diff --git a/clients/algoliasearch-client-javascript/client-common/src/createAuth.ts b/clients/algoliasearch-client-javascript/client-common/src/createAuth.ts new file mode 100644 index 0000000000..80bc5e1991 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-common/src/createAuth.ts @@ -0,0 +1,25 @@ +import type { AuthMode } from './types'; + +export function createAuth( + appId: string, + apiKey: string, + authMode: AuthMode = 'WithinHeaders' +): { + readonly headers: () => Readonly>; + readonly queryParameters: () => Readonly>; +} { + const credentials = { + 'x-algolia-api-key': apiKey, + 'x-algolia-application-id': appId, + }; + + return { + headers(): Readonly> { + return authMode === 'WithinHeaders' ? credentials : {}; + }, + + queryParameters(): Readonly> { + return authMode === 'WithinQueryParameters' ? credentials : {}; + }, + }; +} diff --git a/clients/algoliasearch-client-javascript/client-common/src/createUserAgent.ts b/clients/algoliasearch-client-javascript/client-common/src/createUserAgent.ts new file mode 100644 index 0000000000..915a9c63ef --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-common/src/createUserAgent.ts @@ -0,0 +1,20 @@ +import type { UserAgentOptions, UserAgent } from './types'; + +export function createUserAgent(version: string): UserAgent { + const userAgent = { + value: `Algolia for JavaScript (${version})`, + add(options: UserAgentOptions): UserAgent { + const addedUserAgent = `; ${options.segment}${ + options.version !== undefined ? ` (${options.version})` : '' + }`; + + if (userAgent.value.indexOf(addedUserAgent) === -1) { + userAgent.value = `${userAgent.value}${addedUserAgent}`; + } + + return userAgent; + }, + }; + + return userAgent; +} diff --git a/clients/algoliasearch-client-javascript/client-common/src/getUserAgent.ts b/clients/algoliasearch-client-javascript/client-common/src/getUserAgent.ts new file mode 100644 index 0000000000..1f91ebb1b8 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-common/src/getUserAgent.ts @@ -0,0 +1,23 @@ +import { createUserAgent } from './createUserAgent'; +import type { UserAgentOptions, UserAgent } from './types'; + +export type GetUserAgent = { + userAgents: UserAgentOptions[]; + client: string; + version: string; +}; + +export function getUserAgent({ + userAgents, + client, + version, +}: GetUserAgent): UserAgent { + const defaultUserAgent = createUserAgent(version).add({ + segment: client, + version, + }); + + userAgents.forEach((userAgent) => defaultUserAgent.add(userAgent)); + + return defaultUserAgent; +} diff --git a/clients/algoliasearch-client-javascript/client-common/src/requester/EchoRequester.ts b/clients/algoliasearch-client-javascript/client-common/src/requester/EchoRequester.ts index f773d0f637..491a9d69de 100644 --- a/clients/algoliasearch-client-javascript/client-common/src/requester/EchoRequester.ts +++ b/clients/algoliasearch-client-javascript/client-common/src/requester/EchoRequester.ts @@ -1,3 +1,5 @@ +import { URL } from 'url'; + import type { EndRequest, Request, Response, EchoResponse } from '../types'; import { Requester } from './Requester'; diff --git a/clients/algoliasearch-client-javascript/client-common/src/requester/index.ts b/clients/algoliasearch-client-javascript/client-common/src/requester/index.ts index c50d4513eb..cf4a31f791 100644 --- a/clients/algoliasearch-client-javascript/client-common/src/requester/index.ts +++ b/clients/algoliasearch-client-javascript/client-common/src/requester/index.ts @@ -1,3 +1,2 @@ export * from './EchoRequester'; -export * from './HttpRequester'; export * from './Requester'; diff --git a/clients/algoliasearch-client-javascript/client-common/src/types.ts b/clients/algoliasearch-client-javascript/client-common/src/types.ts index 20136fe367..850a06e921 100644 --- a/clients/algoliasearch-client-javascript/client-common/src/types.ts +++ b/clients/algoliasearch-client-javascript/client-common/src/types.ts @@ -71,3 +71,39 @@ export type Timeouts = { 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/client-insights/api.ts b/clients/algoliasearch-client-javascript/client-insights/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/client-insights/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/client-insights/browser.ts b/clients/algoliasearch-client-javascript/client-insights/browser.ts new file mode 100644 index 0000000000..4023d1dc1c --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-insights/browser.ts @@ -0,0 +1,38 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createInsightsApi } from './src/insightsApi'; +import type { InsightsApi, Region } from './src/insightsApi'; + +export * from './src/insightsApi'; +export * from '@algolia/client-common'; + +export function insightsApi( + appId: string, + apiKey: string, + region?: Region, + options?: { requester?: Requester; hosts?: Host[] } +): InsightsApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createInsightsApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-insights/node.ts b/clients/algoliasearch-client-javascript/client-insights/node.ts new file mode 100644 index 0000000000..057956b781 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-insights/node.ts @@ -0,0 +1,37 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createInsightsApi } from './src/insightsApi'; +import type { InsightsApi, Region } from './src/insightsApi'; + +export * from './src/insightsApi'; +export * from '@algolia/client-common'; + +export function insightsApi( + appId: string, + apiKey: string, + region?: Region, + options?: { requester?: Requester; hosts?: Host[] } +): InsightsApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createInsightsApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-insights/package.json b/clients/algoliasearch-client-javascript/client-insights/package.json index bd7e8c3166..66dd23408b 100644 --- a/clients/algoliasearch-client-javascript/client-insights/package.json +++ b/clients/algoliasearch-client-javascript/client-insights/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/client-insights/src/apis.ts b/clients/algoliasearch-client-javascript/client-insights/src/apis.ts deleted file mode 100644 index c77ef8ef28..0000000000 --- a/clients/algoliasearch-client-javascript/client-insights/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { InsightsApi } from './insightsApi'; - -export * from './insightsApi'; -export * from '@algolia/client-common'; - -export const APIS = [InsightsApi]; diff --git a/clients/algoliasearch-client-javascript/client-insights/src/insightsApi.ts b/clients/algoliasearch-client-javascript/client-insights/src/insightsApi.ts index e9a5fcc1ff..d47ac5a4d5 100644 --- a/clients/algoliasearch-client-javascript/client-insights/src/insightsApi.ts +++ b/clients/algoliasearch-client-javascript/client-insights/src/insightsApi.ts @@ -1,10 +1,9 @@ -import { Transporter } from '@algolia/client-common'; +import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { InsightEvents } from '../model/insightEvents'; @@ -12,98 +11,38 @@ import type { PushEventsResponse } from '../model/pushEventsResponse'; export const version = '5.0.0'; -export class InsightsApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; +export type Region = 'de' | 'us'; - private transporter: Transporter; +function getDefaultHosts(region?: Region): Host[] { + const regionHost = region ? `.${region}.` : '.'; - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - region?: 'de' | 'us', - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } - - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(region), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', - }, - userAgent: 'Algolia for Javascript (5.0.0)', - timeouts: { - connect: 2, - read: 5, - write: 30, - }, - requester: options?.requester, - }); - } - - getDefaultHosts(region?: 'de' | 'us'): Host[] { - const regionHost = region ? `.${region}.` : '.'; - - return [ - { - url: `insights${regionHost}algolia.io`, - accept: 'readWrite', - protocol: 'https', - }, - ]; - } - - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } - - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } + return [ + { + url: `insights${regionHost}algolia.io`, + accept: 'readWrite', + protocol: 'https', + }, + ]; +} - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createInsightsApi = ( + options: CreateClientOptions & { region?: Region } +) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.region), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'Insights', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * This command pushes an array of events. @@ -111,7 +50,9 @@ export class InsightsApi { * @summary Pushes an array of events. * @param insightEvents - The insightEvents object. */ - pushEvents(insightEvents: InsightEvents): Promise { + function pushEvents( + insightEvents: InsightEvents + ): Promise { const path = '/1/events'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -134,11 +75,16 @@ export class InsightsApi { data: insightEvents, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { pushEvents }; +}; + +export type InsightsApi = ReturnType; diff --git a/clients/algoliasearch-client-javascript/client-insights/tsconfig.json b/clients/algoliasearch-client-javascript/client-insights/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/client-insights/tsconfig.json +++ b/clients/algoliasearch-client-javascript/client-insights/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/client-personalization/api.ts b/clients/algoliasearch-client-javascript/client-personalization/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/client-personalization/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/client-personalization/browser.ts b/clients/algoliasearch-client-javascript/client-personalization/browser.ts new file mode 100644 index 0000000000..b3ffccff69 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-personalization/browser.ts @@ -0,0 +1,42 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createPersonalizationApi } from './src/personalizationApi'; +import type { PersonalizationApi, Region } from './src/personalizationApi'; + +export * from './src/personalizationApi'; +export * from '@algolia/client-common'; + +export function personalizationApi( + appId: string, + apiKey: string, + region: Region, + options?: { requester?: Requester; hosts?: Host[] } +): PersonalizationApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + if (!region) { + throw new Error('`region` is missing.'); + } + + return createPersonalizationApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-personalization/node.ts b/clients/algoliasearch-client-javascript/client-personalization/node.ts new file mode 100644 index 0000000000..2cb84dcd7a --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-personalization/node.ts @@ -0,0 +1,41 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createPersonalizationApi } from './src/personalizationApi'; +import type { PersonalizationApi, Region } from './src/personalizationApi'; + +export * from './src/personalizationApi'; +export * from '@algolia/client-common'; + +export function personalizationApi( + appId: string, + apiKey: string, + region: Region, + options?: { requester?: Requester; hosts?: Host[] } +): PersonalizationApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + if (!region) { + throw new Error('`region` is missing.'); + } + + return createPersonalizationApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-personalization/package.json b/clients/algoliasearch-client-javascript/client-personalization/package.json index e0a18ed044..462e58175b 100644 --- a/clients/algoliasearch-client-javascript/client-personalization/package.json +++ b/clients/algoliasearch-client-javascript/client-personalization/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/client-personalization/src/apis.ts b/clients/algoliasearch-client-javascript/client-personalization/src/apis.ts deleted file mode 100644 index e4883c1626..0000000000 --- a/clients/algoliasearch-client-javascript/client-personalization/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { PersonalizationApi } from './personalizationApi'; - -export * from './personalizationApi'; -export * from '@algolia/client-common'; - -export const APIS = [PersonalizationApi]; diff --git a/clients/algoliasearch-client-javascript/client-personalization/src/personalizationApi.ts b/clients/algoliasearch-client-javascript/client-personalization/src/personalizationApi.ts index 4f9b848db1..b347427ed8 100644 --- a/clients/algoliasearch-client-javascript/client-personalization/src/personalizationApi.ts +++ b/clients/algoliasearch-client-javascript/client-personalization/src/personalizationApi.ts @@ -1,10 +1,9 @@ -import { Transporter } from '@algolia/client-common'; +import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { DeleteUserProfileResponse } from '../model/deleteUserProfileResponse'; @@ -14,100 +13,36 @@ import type { SetPersonalizationStrategyResponse } from '../model/setPersonaliza export const version = '5.0.0'; -export class PersonalizationApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; - - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - region: 'eu' | 'us', - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } +export type Region = 'eu' | 'us'; - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } - - if (!region) { - throw new Error('`region` is missing.'); - } - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(region), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', - }, - userAgent: 'Algolia for Javascript (5.0.0)', - timeouts: { - connect: 2, - read: 5, - write: 30, - }, - requester: options?.requester, - }); - } - - getDefaultHosts(region: 'eu' | 'us'): Host[] { - return [ - { - url: `personalization.${region}.algolia.com`, - accept: 'readWrite', - protocol: 'https', - }, - ]; - } - - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } - - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } +function getDefaultHosts(region: Region): Host[] { + return [ + { + url: `personalization.${region}.algolia.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]; +} - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createPersonalizationApi = ( + options: CreateClientOptions & { region: Region } +) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.region), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'Personalization', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * Returns, as part of the response, a date until which the data can safely be considered as deleted for the given user. This means that if you send events for the given user before this date, they will be ignored. Any data received after the deletedUntil date will start building a new user profile. It might take a couple hours before for the deletion request to be fully processed. @@ -116,7 +51,7 @@ export class PersonalizationApi { * @param deleteUserProfile - The deleteUserProfile object. * @param deleteUserProfile.userToken - UserToken representing the user for which to fetch the Personalization profile. */ - deleteUserProfile({ + function deleteUserProfile({ userToken, }: DeleteUserProfileProps): Promise { const path = '/1/profiles/{userToken}'.replace( @@ -137,19 +72,21 @@ export class PersonalizationApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * The strategy contains information on the events and facets that impact user profiles and personalized search results. * * @summary Get the current personalization strategy. */ - getPersonalizationStrategy(): Promise { + function getPersonalizationStrategy(): Promise { const path = '/1/strategies/personalization'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -159,13 +96,15 @@ export class PersonalizationApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * The profile is structured by facet name used in the strategy. Each facet value is mapped to its score. Each score represents the user affinity for a specific facet value given the userToken past events and the Personalization strategy defined. Scores are bounded to 20. The last processed event timestamp is provided using the ISO 8601 format for debugging purposes. * @@ -173,7 +112,7 @@ export class PersonalizationApi { * @param getUserTokenProfile - The getUserTokenProfile object. * @param getUserTokenProfile.userToken - UserToken representing the user for which to fetch the Personalization profile. */ - getUserTokenProfile({ + function getUserTokenProfile({ userToken, }: GetUserTokenProfileProps): Promise { const path = '/1/profiles/personalization/{userToken}'.replace( @@ -194,20 +133,22 @@ export class PersonalizationApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * A strategy defines the events and facets that impact user profiles and personalized search results. * * @summary Set a new personalization strategy. * @param personalizationStrategyParams - The personalizationStrategyParams object. */ - setPersonalizationStrategy( + function setPersonalizationStrategy( personalizationStrategyParams: PersonalizationStrategyParams ): Promise { const path = '/1/strategies/personalization'; @@ -242,14 +183,24 @@ export class PersonalizationApi { data: personalizationStrategyParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { + deleteUserProfile, + getPersonalizationStrategy, + getUserTokenProfile, + setPersonalizationStrategy, + }; +}; + +export type PersonalizationApi = ReturnType; export type DeleteUserProfileProps = { /** diff --git a/clients/algoliasearch-client-javascript/client-personalization/tsconfig.json b/clients/algoliasearch-client-javascript/client-personalization/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/client-personalization/tsconfig.json +++ b/clients/algoliasearch-client-javascript/client-personalization/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/client-query-suggestions/api.ts b/clients/algoliasearch-client-javascript/client-query-suggestions/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/client-query-suggestions/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/client-query-suggestions/browser.ts b/clients/algoliasearch-client-javascript/client-query-suggestions/browser.ts new file mode 100644 index 0000000000..da7cd014a0 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-query-suggestions/browser.ts @@ -0,0 +1,42 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createQuerySuggestionsApi } from './src/querySuggestionsApi'; +import type { QuerySuggestionsApi, Region } from './src/querySuggestionsApi'; + +export * from './src/querySuggestionsApi'; +export * from '@algolia/client-common'; + +export function querySuggestionsApi( + appId: string, + apiKey: string, + region: Region, + options?: { requester?: Requester; hosts?: Host[] } +): QuerySuggestionsApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + if (!region) { + throw new Error('`region` is missing.'); + } + + return createQuerySuggestionsApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-query-suggestions/node.ts b/clients/algoliasearch-client-javascript/client-query-suggestions/node.ts new file mode 100644 index 0000000000..074fbcfb1f --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-query-suggestions/node.ts @@ -0,0 +1,41 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createQuerySuggestionsApi } from './src/querySuggestionsApi'; +import type { QuerySuggestionsApi, Region } from './src/querySuggestionsApi'; + +export * from './src/querySuggestionsApi'; +export * from '@algolia/client-common'; + +export function querySuggestionsApi( + appId: string, + apiKey: string, + region: Region, + options?: { requester?: Requester; hosts?: Host[] } +): QuerySuggestionsApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + if (!region) { + throw new Error('`region` is missing.'); + } + + return createQuerySuggestionsApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-query-suggestions/package.json b/clients/algoliasearch-client-javascript/client-query-suggestions/package.json index 422db8a534..e7e9255ab8 100644 --- a/clients/algoliasearch-client-javascript/client-query-suggestions/package.json +++ b/clients/algoliasearch-client-javascript/client-query-suggestions/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/client-query-suggestions/src/apis.ts b/clients/algoliasearch-client-javascript/client-query-suggestions/src/apis.ts deleted file mode 100644 index cff36ebfb2..0000000000 --- a/clients/algoliasearch-client-javascript/client-query-suggestions/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { QuerySuggestionsApi } from './querySuggestionsApi'; - -export * from './querySuggestionsApi'; -export * from '@algolia/client-common'; - -export const APIS = [QuerySuggestionsApi]; diff --git a/clients/algoliasearch-client-javascript/client-query-suggestions/src/querySuggestionsApi.ts b/clients/algoliasearch-client-javascript/client-query-suggestions/src/querySuggestionsApi.ts index 00ac8685de..c105b43fc4 100644 --- a/clients/algoliasearch-client-javascript/client-query-suggestions/src/querySuggestionsApi.ts +++ b/clients/algoliasearch-client-javascript/client-query-suggestions/src/querySuggestionsApi.ts @@ -1,10 +1,9 @@ -import { Transporter } from '@algolia/client-common'; +import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { LogFile } from '../model/logFile'; @@ -16,100 +15,36 @@ import type { SucessResponse } from '../model/sucessResponse'; export const version = '5.0.0'; -export class QuerySuggestionsApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; - - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - region: 'eu' | 'us', - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } - - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } - - if (!region) { - throw new Error('`region` is missing.'); - } - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(region), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', - }, - userAgent: 'Algolia for Javascript (5.0.0)', - timeouts: { - connect: 2, - read: 5, - write: 30, - }, - requester: options?.requester, - }); - } - - getDefaultHosts(region: 'eu' | 'us'): Host[] { - return [ - { - url: `query-suggestions.${region}.algolia.com`, - accept: 'readWrite', - protocol: 'https', - }, - ]; - } +export type Region = 'eu' | 'us'; - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } - - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } +function getDefaultHosts(region: Region): Host[] { + return [ + { + url: `query-suggestions.${region}.algolia.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]; +} - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createQuerySuggestionsApi = ( + options: CreateClientOptions & { region: Region } +) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.region), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'QuerySuggestions', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * Create a configuration of a Query Suggestions index. There\'s a limit of 100 configurations per application. @@ -117,7 +52,7 @@ export class QuerySuggestionsApi { * @summary Create a configuration of a Query Suggestions index. * @param querySuggestionsIndexWithIndexParam - The querySuggestionsIndexWithIndexParam object. */ - createConfig( + function createConfig( querySuggestionsIndexWithIndexParam: QuerySuggestionsIndexWithIndexParam ): Promise { const path = '/1/configs'; @@ -136,13 +71,15 @@ export class QuerySuggestionsApi { data: querySuggestionsIndexWithIndexParam, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete a configuration of a Query Suggestion\'s index. By deleting a configuraton, you stop all updates to the underlying query suggestion index. Note that when doing this, the underlying index does not change - existing suggestions remain untouched. * @@ -150,7 +87,9 @@ export class QuerySuggestionsApi { * @param deleteConfig - The deleteConfig object. * @param deleteConfig.indexName - The index in which to perform the request. */ - deleteConfig({ indexName }: DeleteConfigProps): Promise { + function deleteConfig({ + indexName, + }: DeleteConfigProps): Promise { const path = '/1/configs/{indexName}'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -169,19 +108,21 @@ export class QuerySuggestionsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get all the configurations of Query Suggestions. For each index, you get a block of JSON with a list of its configuration settings. * * @summary Get all the configurations of Query Suggestions. */ - getAllConfigs(): Promise { + function getAllConfigs(): Promise { const path = '/1/configs'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -191,13 +132,15 @@ export class QuerySuggestionsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get the configuration of a single Query Suggestions index. * @@ -205,7 +148,9 @@ export class QuerySuggestionsApi { * @param getConfig - The getConfig object. * @param getConfig.indexName - The index in which to perform the request. */ - getConfig({ indexName }: GetConfigProps): Promise { + function getConfig({ + indexName, + }: GetConfigProps): Promise { const path = '/1/configs/{indexName}'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -224,13 +169,15 @@ export class QuerySuggestionsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get the status of a Query Suggestion\'s index. The status includes whether the Query Suggestions index is currently in the process of being built, and the last build time. * @@ -238,7 +185,9 @@ export class QuerySuggestionsApi { * @param getConfigStatus - The getConfigStatus object. * @param getConfigStatus.indexName - The index in which to perform the request. */ - getConfigStatus({ indexName }: GetConfigStatusProps): Promise { + function getConfigStatus({ + indexName, + }: GetConfigStatusProps): Promise { const path = '/1/configs/{indexName}/status'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -257,13 +206,15 @@ export class QuerySuggestionsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get the log file of the last build of a single Query Suggestion index. * @@ -271,7 +222,7 @@ export class QuerySuggestionsApi { * @param getLogFile - The getLogFile object. * @param getLogFile.indexName - The index in which to perform the request. */ - getLogFile({ indexName }: GetLogFileProps): Promise { + function getLogFile({ indexName }: GetLogFileProps): Promise { const path = '/1/logs/{indexName}'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -290,13 +241,15 @@ export class QuerySuggestionsApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Update the configuration of a Query Suggestions index. * @@ -305,7 +258,7 @@ export class QuerySuggestionsApi { * @param updateConfig.indexName - The index in which to perform the request. * @param updateConfig.querySuggestionsIndexParam - The querySuggestionsIndexParam object. */ - updateConfig({ + function updateConfig({ indexName, querySuggestionsIndexParam, }: UpdateConfigProps): Promise { @@ -340,14 +293,27 @@ export class QuerySuggestionsApi { data: querySuggestionsIndexParam, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { + createConfig, + deleteConfig, + getAllConfigs, + getConfig, + getConfigStatus, + getLogFile, + updateConfig, + }; +}; + +export type QuerySuggestionsApi = ReturnType; export type DeleteConfigProps = { /** diff --git a/clients/algoliasearch-client-javascript/client-query-suggestions/tsconfig.json b/clients/algoliasearch-client-javascript/client-query-suggestions/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/client-query-suggestions/tsconfig.json +++ b/clients/algoliasearch-client-javascript/client-query-suggestions/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/client-search/api.ts b/clients/algoliasearch-client-javascript/client-search/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/client-search/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/client-search/browser.ts b/clients/algoliasearch-client-javascript/client-search/browser.ts new file mode 100644 index 0000000000..72669d1ab7 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/browser.ts @@ -0,0 +1,37 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createSearchApi } from './src/searchApi'; +import type { SearchApi } from './src/searchApi'; + +export * from './src/searchApi'; +export * from '@algolia/client-common'; + +export function searchApi( + appId: string, + apiKey: string, + options?: { requester?: Requester; hosts?: Host[] } +): SearchApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createSearchApi({ + appId, + apiKey, + + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-search/node.ts b/clients/algoliasearch-client-javascript/client-search/node.ts new file mode 100644 index 0000000000..23d2b07da5 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-search/node.ts @@ -0,0 +1,36 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createSearchApi } from './src/searchApi'; +import type { SearchApi } from './src/searchApi'; + +export * from './src/searchApi'; +export * from '@algolia/client-common'; + +export function searchApi( + appId: string, + apiKey: string, + options?: { requester?: Requester; hosts?: Host[] } +): SearchApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createSearchApi({ + appId, + apiKey, + + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-search/package.json b/clients/algoliasearch-client-javascript/client-search/package.json index c83575b9d6..3ae2ecd6da 100644 --- a/clients/algoliasearch-client-javascript/client-search/package.json +++ b/clients/algoliasearch-client-javascript/client-search/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/client-search/src/apis.ts b/clients/algoliasearch-client-javascript/client-search/src/apis.ts deleted file mode 100644 index b9b43ae707..0000000000 --- a/clients/algoliasearch-client-javascript/client-search/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { SearchApi } from './searchApi'; - -export * from './searchApi'; -export * from '@algolia/client-common'; - -export const APIS = [SearchApi]; diff --git a/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts b/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts index 59b3e91ea9..22e5da4b11 100644 --- a/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts +++ b/clients/algoliasearch-client-javascript/client-search/src/searchApi.ts @@ -1,10 +1,14 @@ -import { shuffle, Transporter } from '@algolia/client-common'; +import { + shuffle, + Transporter, + createAuth, + getUserAgent, +} from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { AddApiKeyResponse } from '../model/addApiKeyResponse'; @@ -66,112 +70,57 @@ import type { UserId } from '../model/userId'; export const version = '5.0.0'; -export class SearchApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; - - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } - - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(appId), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', +function getDefaultHosts(appId: string): Host[] { + return ( + [ + { + url: `${appId}-dsn.algolia.net`, + accept: 'read', + protocol: 'https', }, - userAgent: 'Algolia for Javascript (5.0.0)', - timeouts: { - connect: 2, - read: 5, - write: 30, + { + url: `${appId}.algolia.net`, + accept: 'write', + protocol: 'https', }, - requester: options?.requester, - }); - } - - getDefaultHosts(appId: string): Host[] { - return ( - [ - { url: `${appId}-dsn.algolia.net`, accept: 'read', protocol: 'https' }, - { url: `${appId}.algolia.net`, accept: 'write', protocol: 'https' }, - ] as Host[] - ).concat( - shuffle([ - { - url: `${appId}-1.algolianet.com`, - accept: 'readWrite', - protocol: 'https', - }, - { - url: `${appId}-2.algolianet.com`, - accept: 'readWrite', - protocol: 'https', - }, - { - url: `${appId}-3.algolianet.com`, - accept: 'readWrite', - protocol: 'https', - }, - ]) - ); - } - - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } - - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } + ] as Host[] + ).concat( + shuffle([ + { + url: `${appId}-1.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + { + url: `${appId}-2.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + { + url: `${appId}-3.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]) + ); +} - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createSearchApi = (options: CreateClientOptions) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.appId), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'Search', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * Add a new API Key with specific permissions/restrictions. @@ -179,7 +128,7 @@ export class SearchApi { * @summary Create a new API key. * @param apiKey - The apiKey object. */ - addApiKey(apiKey: ApiKey): Promise { + function addApiKey(apiKey: ApiKey): Promise { const path = '/1/keys'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -202,13 +151,15 @@ export class SearchApi { data: apiKey, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Add or replace an object with a given object ID. If the object does not exist, it will be created. If it already exists, it will be replaced. * @@ -218,7 +169,7 @@ export class SearchApi { * @param addOrUpdateObject.objectID - Unique identifier of an object. * @param addOrUpdateObject.body - The Algolia object. */ - addOrUpdateObject({ + function addOrUpdateObject({ indexName, objectID, body, @@ -253,20 +204,22 @@ export class SearchApi { data: body, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Add a single source to the list of allowed sources. * * @summary Add a single source. * @param source - The source to add. */ - appendSource(source: Source): Promise { + function appendSource(source: Source): Promise { const path = '/1/security/sources/append'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -283,13 +236,15 @@ export class SearchApi { data: source, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Assign or Move a userID to a cluster. The time it takes to migrate (move) a user is proportional to the amount of data linked to the userID. Upon success, the response is 200 OK. A successful response indicates that the operation has been taken into account, and the userID is directly usable. * @@ -298,7 +253,7 @@ export class SearchApi { * @param assignUserId.xAlgoliaUserID - UserID to assign. * @param assignUserId.assignUserIdParams - The assignUserIdParams object. */ - assignUserId({ + function assignUserId({ xAlgoliaUserID, assignUserIdParams, }: AssignUserIdProps): Promise { @@ -334,13 +289,15 @@ export class SearchApi { data: assignUserIdParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Performs multiple write operations in a single API call. * @@ -349,7 +306,10 @@ export class SearchApi { * @param batch.indexName - The index in which to perform the request. * @param batch.batchWriteParams - The batchWriteParams object. */ - batch({ indexName, batchWriteParams }: BatchProps): Promise { + function batch({ + indexName, + batchWriteParams, + }: BatchProps): Promise { const path = '/1/indexes/{indexName}/batch'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -375,13 +335,15 @@ export class SearchApi { data: batchWriteParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Assign multiple userIDs to a cluster. Upon success, the response is 200 OK. A successful response indicates that the operation has been taken into account, and the userIDs are directly usable. * @@ -390,7 +352,7 @@ export class SearchApi { * @param batchAssignUserIds.xAlgoliaUserID - UserID to assign. * @param batchAssignUserIds.batchAssignUserIdsParams - The batchAssignUserIdsParams object. */ - batchAssignUserIds({ + function batchAssignUserIds({ xAlgoliaUserID, batchAssignUserIdsParams, }: BatchAssignUserIdsProps): Promise { @@ -431,13 +393,15 @@ export class SearchApi { data: batchAssignUserIdsParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Send a batch of dictionary entries. * @@ -446,7 +410,7 @@ export class SearchApi { * @param batchDictionaryEntries.dictionaryName - The dictionary to search in. * @param batchDictionaryEntries.batchDictionaryEntries - The batchDictionaryEntries object. */ - batchDictionaryEntries({ + function batchDictionaryEntries({ dictionaryName, batchDictionaryEntries, }: BatchDictionaryEntriesProps): Promise { @@ -481,13 +445,15 @@ export class SearchApi { data: batchDictionaryEntries, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Create or update a batch of Rules. * @@ -498,7 +464,7 @@ export class SearchApi { * @param batchRules.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. * @param batchRules.clearExistingRules - When true, existing Rules are cleared before adding this batch. When false, existing Rules are kept. */ - batchRules({ + function batchRules({ indexName, rule, forwardToReplicas, @@ -537,13 +503,15 @@ export class SearchApi { data: rule, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * This method allows you to retrieve all index content. It can retrieve up to 1,000 records per call and supports full text search and filters. For performance reasons, some features are not supported, including `distinct`, sorting by `typos`, `words` or `geo distance`. When there is more content to be browsed, the response contains a cursor field. This cursor has to be passed to the subsequent call to browse in order to get the next page of results. When the end of the index has been reached, the cursor field is absent from the response. * @@ -552,7 +520,10 @@ export class SearchApi { * @param browse.indexName - The index in which to perform the request. * @param browse.browseRequest - The browseRequest object. */ - browse({ indexName, browseRequest }: BrowseProps): Promise { + function browse({ + indexName, + browseRequest, + }: BrowseProps): Promise { const path = '/1/indexes/{indexName}/browse'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -572,13 +543,15 @@ export class SearchApi { data: browseRequest, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Remove all synonyms from an index. * @@ -587,7 +560,7 @@ export class SearchApi { * @param clearAllSynonyms.indexName - The index in which to perform the request. * @param clearAllSynonyms.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. */ - clearAllSynonyms({ + function clearAllSynonyms({ indexName, forwardToReplicas, }: ClearAllSynonymsProps): Promise { @@ -613,13 +586,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete an index\'s content, but leave settings and index-specific API keys untouched. * @@ -627,7 +602,9 @@ export class SearchApi { * @param clearObjects - The clearObjects object. * @param clearObjects.indexName - The index in which to perform the request. */ - clearObjects({ indexName }: ClearObjectsProps): Promise { + function clearObjects({ + indexName, + }: ClearObjectsProps): Promise { const path = '/1/indexes/{indexName}/clear'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -646,13 +623,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete all Rules in the index. * @@ -661,7 +640,7 @@ export class SearchApi { * @param clearRules.indexName - The index in which to perform the request. * @param clearRules.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. */ - clearRules({ + function clearRules({ indexName, forwardToReplicas, }: ClearRulesProps): Promise { @@ -687,13 +666,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete an existing API Key. * @@ -701,7 +682,9 @@ export class SearchApi { * @param deleteApiKey - The deleteApiKey object. * @param deleteApiKey.key - API Key string. */ - deleteApiKey({ key }: DeleteApiKeyProps): Promise { + function deleteApiKey({ + key, + }: DeleteApiKeyProps): Promise { const path = '/1/keys/{key}'.replace( '{key}', encodeURIComponent(String(key)) @@ -720,13 +703,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Remove all objects matching a filter (including geo filters). This method enables you to delete one or more objects based on filters (numeric, facet, tag or geo queries). It doesn\'t accept empty filters or a query. * @@ -735,7 +720,7 @@ export class SearchApi { * @param deleteBy.indexName - The index in which to perform the request. * @param deleteBy.searchParams - The searchParams object. */ - deleteBy({ + function deleteBy({ indexName, searchParams, }: DeleteByProps): Promise { @@ -764,13 +749,15 @@ export class SearchApi { data: searchParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete an existing index. * @@ -778,7 +765,9 @@ export class SearchApi { * @param deleteIndex - The deleteIndex object. * @param deleteIndex.indexName - The index in which to perform the request. */ - deleteIndex({ indexName }: DeleteIndexProps): Promise { + function deleteIndex({ + indexName, + }: DeleteIndexProps): Promise { const path = '/1/indexes/{indexName}'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -797,13 +786,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete an existing object. * @@ -812,7 +803,7 @@ export class SearchApi { * @param deleteObject.indexName - The index in which to perform the request. * @param deleteObject.objectID - Unique identifier of an object. */ - deleteObject({ + function deleteObject({ indexName, objectID, }: DeleteObjectProps): Promise { @@ -839,13 +830,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete the Rule with the specified objectID. * @@ -855,7 +848,7 @@ export class SearchApi { * @param deleteRule.objectID - Unique identifier of an object. * @param deleteRule.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. */ - deleteRule({ + function deleteRule({ indexName, objectID, forwardToReplicas, @@ -887,13 +880,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Remove a single source from the list of allowed sources. * @@ -901,7 +896,9 @@ export class SearchApi { * @param deleteSource - The deleteSource object. * @param deleteSource.source - The IP range of the source. */ - deleteSource({ source }: DeleteSourceProps): Promise { + function deleteSource({ + source, + }: DeleteSourceProps): Promise { const path = '/1/security/sources/{source}'.replace( '{source}', encodeURIComponent(String(source)) @@ -920,13 +917,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Delete a single synonyms set, identified by the given objectID. * @@ -936,7 +935,7 @@ export class SearchApi { * @param deleteSynonym.objectID - Unique identifier of an object. * @param deleteSynonym.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. */ - deleteSynonym({ + function deleteSynonym({ indexName, objectID, forwardToReplicas, @@ -968,13 +967,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get the permissions of an API key. * @@ -982,7 +983,7 @@ export class SearchApi { * @param getApiKey - The getApiKey object. * @param getApiKey.key - API Key string. */ - getApiKey({ key }: GetApiKeyProps): Promise { + function getApiKey({ key }: GetApiKeyProps): Promise { const path = '/1/keys/{key}'.replace( '{key}', encodeURIComponent(String(key)) @@ -999,19 +1000,21 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * List dictionaries supported per language. * * @summary List dictionaries supported per language. */ - getDictionaryLanguages(): Promise<{ [key: string]: Languages }> { + function getDictionaryLanguages(): Promise<{ [key: string]: Languages }> { const path = '/1/dictionaries/*/languages'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1021,19 +1024,21 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Retrieve dictionaries settings. * * @summary Retrieve dictionaries settings. The API stores languages whose standard entries are disabled. Fetch settings does not return false values. */ - getDictionarySettings(): Promise { + function getDictionarySettings(): Promise { const path = '/1/dictionaries/*/settings'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1043,13 +1048,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Return the lastest log entries. * @@ -1060,7 +1067,7 @@ export class SearchApi { * @param getLogs.indexName - Index for which log entries should be retrieved. When omitted, log entries are retrieved across all indices. * @param getLogs.type - Type of log entries to retrieve. When omitted, all log entries are retrieved. */ - getLogs({ + function getLogs({ offset, length, indexName, @@ -1091,13 +1098,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Retrieve one object from the index. * @@ -1107,7 +1116,7 @@ export class SearchApi { * @param getObject.objectID - Unique identifier of an object. * @param getObject.attributesToRetrieve - List of attributes to retrieve. If not specified, all retrievable attributes are returned. */ - getObject({ + function getObject({ indexName, objectID, attributesToRetrieve, @@ -1139,20 +1148,24 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Retrieve one or more objects, potentially from different indices, in a single API call. * * @summary Retrieve one or more objects. * @param getObjectsParams - The getObjectsParams object. */ - getObjects(getObjectsParams: GetObjectsParams): Promise { + function getObjects( + getObjectsParams: GetObjectsParams + ): Promise { const path = '/1/indexes/*/objects'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1169,13 +1182,15 @@ export class SearchApi { data: getObjectsParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Retrieve the Rule with the specified objectID. * @@ -1184,7 +1199,7 @@ export class SearchApi { * @param getRule.indexName - The index in which to perform the request. * @param getRule.objectID - Unique identifier of an object. */ - getRule({ indexName, objectID }: GetRuleProps): Promise { + function getRule({ indexName, objectID }: GetRuleProps): Promise { const path = '/1/indexes/{indexName}/rules/{objectID}' .replace('{indexName}', encodeURIComponent(String(indexName))) .replace('{objectID}', encodeURIComponent(String(objectID))); @@ -1208,13 +1223,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Retrieve settings of a given indexName. * @@ -1222,7 +1239,9 @@ export class SearchApi { * @param getSettings - The getSettings object. * @param getSettings.indexName - The index in which to perform the request. */ - getSettings({ indexName }: GetSettingsProps): Promise { + function getSettings({ + indexName, + }: GetSettingsProps): Promise { const path = '/1/indexes/{indexName}/settings'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -1241,19 +1260,21 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * List all allowed sources. * * @summary List all allowed sources. */ - getSources(): Promise { + function getSources(): Promise { const path = '/1/security/sources'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1263,13 +1284,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Fetch a synonym object identified by its objectID. * @@ -1278,7 +1301,10 @@ export class SearchApi { * @param getSynonym.indexName - The index in which to perform the request. * @param getSynonym.objectID - Unique identifier of an object. */ - getSynonym({ indexName, objectID }: GetSynonymProps): Promise { + function getSynonym({ + indexName, + objectID, + }: GetSynonymProps): Promise { const path = '/1/indexes/{indexName}/synonyms/{objectID}' .replace('{indexName}', encodeURIComponent(String(indexName))) .replace('{objectID}', encodeURIComponent(String(objectID))); @@ -1302,13 +1328,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Check the current status of a given task. * @@ -1317,7 +1345,10 @@ export class SearchApi { * @param getTask.indexName - The index in which to perform the request. * @param getTask.taskID - Unique identifier of an task. Numeric value (up to 64bits). */ - getTask({ indexName, taskID }: GetTaskProps): Promise { + function getTask({ + indexName, + taskID, + }: GetTaskProps): Promise { const path = '/1/indexes/{indexName}/task/{taskID}' .replace('{indexName}', encodeURIComponent(String(indexName))) .replace('{taskID}', encodeURIComponent(String(taskID))); @@ -1339,19 +1370,21 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get the top 10 userIDs with the highest number of records per cluster. The data returned will usually be a few seconds behind real time, because userID usage may take up to a few seconds to propagate to the different clusters. Upon success, the response is 200 OK and contains the following array of userIDs and clusters. * * @summary Get top userID. */ - getTopUserIds(): Promise { + function getTopUserIds(): Promise { const path = '/1/clusters/mapping/top'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1361,13 +1394,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Returns the userID data stored in the mapping. The data returned will usually be a few seconds behind real time, because userID usage may take up to a few seconds to propagate to the different clusters. Upon success, the response is 200 OK and contains the following userID data. * @@ -1375,7 +1410,7 @@ export class SearchApi { * @param getUserId - The getUserId object. * @param getUserId.userID - UserID to assign. */ - getUserId({ userID }: GetUserIdProps): Promise { + function getUserId({ userID }: GetUserIdProps): Promise { const path = '/1/clusters/mapping/{userID}'.replace( '{userID}', encodeURIComponent(String(userID)) @@ -1394,13 +1429,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get the status of your clusters\' migrations or user creations. Creating a large batch of users or migrating your multi-cluster may take quite some time. This method lets you retrieve the status of the migration, so you can know when it\'s done. Upon success, the response is 200 OK. A successful response indicates that the operation has been taken into account, and the userIDs are directly usable. * @@ -1408,7 +1445,7 @@ export class SearchApi { * @param hasPendingMappings - The hasPendingMappings object. * @param hasPendingMappings.getClusters - Whether to get clusters or not. */ - hasPendingMappings({ + function hasPendingMappings({ getClusters, }: HasPendingMappingsProps): Promise { const path = '/1/clusters/mapping/pending'; @@ -1424,19 +1461,21 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * List API keys, along with their associated rights. * * @summary Get the full list of API Keys. */ - listApiKeys(): Promise { + function listApiKeys(): Promise { const path = '/1/keys'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1446,19 +1485,21 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * List the clusters available in a multi-clusters setup for a single appID. Upon success, the response is 200 OK and contains the following clusters. * * @summary List clusters. */ - listClusters(): Promise { + function listClusters(): Promise { const path = '/1/clusters'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1468,13 +1509,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * List existing indexes from an application. * @@ -1482,7 +1525,9 @@ export class SearchApi { * @param listIndices - The listIndices object. * @param listIndices.page - Requested page (zero-based). When specified, will retrieve a specific page; the page size is implicitly set to 100. When null, will retrieve all indices (no pagination). */ - listIndices({ page }: ListIndicesProps): Promise { + function listIndices({ + page, + }: ListIndicesProps): Promise { const path = '/1/indexes'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1496,13 +1541,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * List the userIDs assigned to a multi-clusters appID. The data returned will usually be a few seconds behind real time, because userID usage may take up to a few seconds to propagate to the different clusters. Upon success, the response is 200 OK and contains the following userIDs data. * @@ -1511,7 +1558,7 @@ export class SearchApi { * @param listUserIds.page - Requested page (zero-based). When specified, will retrieve a specific page; the page size is implicitly set to 100. When null, will retrieve all indices (no pagination). * @param listUserIds.hitsPerPage - Maximum number of objects to retrieve. */ - listUserIds({ + function listUserIds({ page, hitsPerPage, }: ListUserIdsProps): Promise { @@ -1532,20 +1579,24 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Perform multiple write operations, potentially targeting multiple indices, in a single API call. * * @summary Perform multiple write operations. * @param batchParams - The batchParams object. */ - multipleBatch(batchParams: BatchParams): Promise { + function multipleBatch( + batchParams: BatchParams + ): Promise { const path = '/1/indexes/*/batch'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -1562,20 +1613,22 @@ export class SearchApi { data: batchParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get search results for the given requests. * * @summary Get search results for the given requests. * @param multipleQueriesParams - The multipleQueriesParams object. */ - multipleQueries( + function multipleQueries( multipleQueriesParams: MultipleQueriesParams ): Promise { const path = '/1/indexes/*/queries'; @@ -1600,13 +1653,15 @@ export class SearchApi { data: multipleQueriesParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Peforms a copy or a move operation on a index. * @@ -1615,7 +1670,7 @@ export class SearchApi { * @param operationIndex.indexName - The index in which to perform the request. * @param operationIndex.operationIndexParams - The operationIndexParams object. */ - operationIndex({ + function operationIndex({ indexName, operationIndexParams, }: OperationIndexProps): Promise { @@ -1655,13 +1710,15 @@ export class SearchApi { data: operationIndexParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Update one or more attributes of an existing object. This method lets you update only a part of an existing object, either by adding new attributes or updating existing ones. You can partially update several objects in a single method call. If the index targeted by this operation doesn\'t exist yet, it\'s automatically created. * @@ -1672,7 +1729,7 @@ export class SearchApi { * @param partialUpdateObject.stringBuiltInOperation - List of attributes to update. * @param partialUpdateObject.createIfNotExists - Creates the record if it does not exist yet. */ - partialUpdateObject({ + function partialUpdateObject({ indexName, objectID, stringBuiltInOperation, @@ -1712,13 +1769,15 @@ export class SearchApi { data: stringBuiltInOperation, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Remove a userID and its associated data from the multi-clusters. Upon success, the response is 200 OK and a task is created to remove the userID data and mapping. * @@ -1726,7 +1785,9 @@ export class SearchApi { * @param removeUserId - The removeUserId object. * @param removeUserId.userID - UserID to assign. */ - removeUserId({ userID }: RemoveUserIdProps): Promise { + function removeUserId({ + userID, + }: RemoveUserIdProps): Promise { const path = '/1/clusters/mapping/{userID}'.replace( '{userID}', encodeURIComponent(String(userID)) @@ -1745,13 +1806,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Replace all allowed sources. * @@ -1759,7 +1822,7 @@ export class SearchApi { * @param replaceSources - The replaceSources object. * @param replaceSources.source - The sources to allow. */ - replaceSources({ + function replaceSources({ source, }: ReplaceSourcesProps): Promise { const path = '/1/security/sources'; @@ -1778,13 +1841,15 @@ export class SearchApi { data: source, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Restore a deleted API key, along with its associated rights. * @@ -1792,7 +1857,9 @@ export class SearchApi { * @param restoreApiKey - The restoreApiKey object. * @param restoreApiKey.key - API Key string. */ - restoreApiKey({ key }: RestoreApiKeyProps): Promise { + function restoreApiKey({ + key, + }: RestoreApiKeyProps): Promise { const path = '/1/keys/{key}/restore'.replace( '{key}', encodeURIComponent(String(key)) @@ -1811,13 +1878,15 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Add an object to the index, automatically assigning it an object ID. * @@ -1826,7 +1895,7 @@ export class SearchApi { * @param saveObject.indexName - The index in which to perform the request. * @param saveObject.body - The Algolia record. */ - saveObject({ + function saveObject({ indexName, body, }: SaveObjectProps): Promise { @@ -1855,13 +1924,15 @@ export class SearchApi { data: body, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Create or update the Rule with the specified objectID. * @@ -1872,7 +1943,7 @@ export class SearchApi { * @param saveRule.rule - The rule object. * @param saveRule.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. */ - saveRule({ + function saveRule({ indexName, objectID, rule, @@ -1921,13 +1992,15 @@ export class SearchApi { data: rule, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Create a new synonym object or update the existing synonym object with the given object ID. * @@ -1938,7 +2011,7 @@ export class SearchApi { * @param saveSynonym.synonymHit - The synonymHit object. * @param saveSynonym.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. */ - saveSynonym({ + function saveSynonym({ indexName, objectID, synonymHit, @@ -1984,13 +2057,15 @@ export class SearchApi { data: synonymHit, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Create/update multiple synonym objects at once, potentially replacing the entire list of synonyms if replaceExistingSynonyms is true. * @@ -2001,7 +2076,7 @@ export class SearchApi { * @param saveSynonyms.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. * @param saveSynonyms.replaceExistingSynonyms - Replace all synonyms of the index with the ones sent with this request. */ - saveSynonyms({ + function saveSynonyms({ indexName, synonymHit, forwardToReplicas, @@ -2041,13 +2116,15 @@ export class SearchApi { data: synonymHit, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Get search results. * @@ -2056,7 +2133,10 @@ export class SearchApi { * @param search.indexName - The index in which to perform the request. * @param search.searchParams - The searchParams object. */ - search({ indexName, searchParams }: SearchProps): Promise { + function search({ + indexName, + searchParams, + }: SearchProps): Promise { const path = '/1/indexes/{indexName}/query'.replace( '{indexName}', encodeURIComponent(String(indexName)) @@ -2082,13 +2162,15 @@ export class SearchApi { data: searchParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Search the dictionary entries. * @@ -2097,7 +2179,7 @@ export class SearchApi { * @param searchDictionaryEntries.dictionaryName - The dictionary to search in. * @param searchDictionaryEntries.searchDictionaryEntries - The searchDictionaryEntries object. */ - searchDictionaryEntries({ + function searchDictionaryEntries({ dictionaryName, searchDictionaryEntries, }: SearchDictionaryEntriesProps): Promise { @@ -2132,13 +2214,15 @@ export class SearchApi { data: searchDictionaryEntries, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Search for values of a given facet, optionally restricting the returned values to those contained in objects matching other search criteria. * @@ -2148,7 +2232,7 @@ export class SearchApi { * @param searchForFacetValues.facetName - The facet name. * @param searchForFacetValues.searchForFacetValuesRequest - The searchForFacetValuesRequest object. */ - searchForFacetValues({ + function searchForFacetValues({ indexName, facetName, searchForFacetValuesRequest, @@ -2177,13 +2261,15 @@ export class SearchApi { data: searchForFacetValuesRequest, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Search for rules matching various criteria. * @@ -2192,7 +2278,7 @@ export class SearchApi { * @param searchRules.indexName - The index in which to perform the request. * @param searchRules.searchRulesParams - The searchRulesParams object. */ - searchRules({ + function searchRules({ indexName, searchRulesParams, }: SearchRulesProps): Promise { @@ -2221,13 +2307,15 @@ export class SearchApi { data: searchRulesParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Search or browse all synonyms, optionally filtering them by type. * @@ -2239,7 +2327,7 @@ export class SearchApi { * @param searchSynonyms.page - Requested page (zero-based). When specified, will retrieve a specific page; the page size is implicitly set to 100. When null, will retrieve all indices (no pagination). * @param searchSynonyms.hitsPerPage - Maximum number of objects to retrieve. */ - searchSynonyms({ + function searchSynonyms({ indexName, query, type, @@ -2280,20 +2368,22 @@ export class SearchApi { path, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Search for userIDs. The data returned will usually be a few seconds behind real time, because userID usage may take up to a few seconds propagate to the different clusters. To keep updates moving quickly, the index of userIDs isn\'t built synchronously with the mapping. Instead, the index is built once every 12h, at the same time as the update of userID usage. For example, when you perform a modification like adding or moving a userID, the search will report an outdated value until the next rebuild of the mapping, which takes place every 12h. Upon success, the response is 200 OK and contains the following userIDs data. * * @summary Search userID. * @param searchUserIdsParams - The searchUserIdsParams object. */ - searchUserIds( + function searchUserIds( searchUserIdsParams: SearchUserIdsParams ): Promise { const path = '/1/clusters/mapping/search'; @@ -2318,20 +2408,22 @@ export class SearchApi { data: searchUserIdsParams, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Set dictionary settings. * * @summary Set dictionary settings. * @param dictionarySettingsRequest - The dictionarySettingsRequest object. */ - setDictionarySettings( + function setDictionarySettings( dictionarySettingsRequest: DictionarySettingsRequest ): Promise { const path = '/1/dictionaries/*/settings'; @@ -2356,13 +2448,15 @@ export class SearchApi { data: dictionarySettingsRequest, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Update settings of a given indexName. Only specified settings are overridden; unspecified settings are left unchanged. Specifying null for a setting resets it to its default value. * @@ -2372,7 +2466,7 @@ export class SearchApi { * @param setSettings.indexSettings - The indexSettings object. * @param setSettings.forwardToReplicas - When true, changes are also propagated to replicas of the given indexName. */ - setSettings({ + function setSettings({ indexName, indexSettings, forwardToReplicas, @@ -2406,13 +2500,15 @@ export class SearchApi { data: indexSettings, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } + /** * Replace every permission of an existing API key. * @@ -2421,7 +2517,7 @@ export class SearchApi { * @param updateApiKey.key - API Key string. * @param updateApiKey.apiKey - The apiKey object. */ - updateApiKey({ + function updateApiKey({ key, apiKey, }: UpdateApiKeyProps): Promise { @@ -2456,14 +2552,77 @@ export class SearchApi { data: apiKey, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { + addApiKey, + addOrUpdateObject, + appendSource, + assignUserId, + batch, + batchAssignUserIds, + batchDictionaryEntries, + batchRules, + browse, + clearAllSynonyms, + clearObjects, + clearRules, + deleteApiKey, + deleteBy, + deleteIndex, + deleteObject, + deleteRule, + deleteSource, + deleteSynonym, + getApiKey, + getDictionaryLanguages, + getDictionarySettings, + getLogs, + getObject, + getObjects, + getRule, + getSettings, + getSources, + getSynonym, + getTask, + getTopUserIds, + getUserId, + hasPendingMappings, + listApiKeys, + listClusters, + listIndices, + listUserIds, + multipleBatch, + multipleQueries, + operationIndex, + partialUpdateObject, + removeUserId, + replaceSources, + restoreApiKey, + saveObject, + saveRule, + saveSynonym, + saveSynonyms, + search, + searchDictionaryEntries, + searchForFacetValues, + searchRules, + searchSynonyms, + searchUserIds, + setDictionarySettings, + setSettings, + updateApiKey, + }; +}; + +export type SearchApi = ReturnType; export type AddOrUpdateObjectProps = { /** diff --git a/clients/algoliasearch-client-javascript/client-search/tsconfig.json b/clients/algoliasearch-client-javascript/client-search/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/client-search/tsconfig.json +++ b/clients/algoliasearch-client-javascript/client-search/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/client-sources/api.ts b/clients/algoliasearch-client-javascript/client-sources/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/client-sources/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/client-sources/browser.ts b/clients/algoliasearch-client-javascript/client-sources/browser.ts new file mode 100644 index 0000000000..73066ccbc3 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-sources/browser.ts @@ -0,0 +1,42 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createSourcesApi } from './src/sourcesApi'; +import type { SourcesApi, Region } from './src/sourcesApi'; + +export * from './src/sourcesApi'; +export * from '@algolia/client-common'; + +export function sourcesApi( + appId: string, + apiKey: string, + region: Region, + options?: { requester?: Requester; hosts?: Host[] } +): SourcesApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + if (!region) { + throw new Error('`region` is missing.'); + } + + return createSourcesApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-sources/node.ts b/clients/algoliasearch-client-javascript/client-sources/node.ts new file mode 100644 index 0000000000..9a6efef352 --- /dev/null +++ b/clients/algoliasearch-client-javascript/client-sources/node.ts @@ -0,0 +1,41 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createSourcesApi } from './src/sourcesApi'; +import type { SourcesApi, Region } from './src/sourcesApi'; + +export * from './src/sourcesApi'; +export * from '@algolia/client-common'; + +export function sourcesApi( + appId: string, + apiKey: string, + region: Region, + options?: { requester?: Requester; hosts?: Host[] } +): SourcesApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + if (!region) { + throw new Error('`region` is missing.'); + } + + return createSourcesApi({ + appId, + apiKey, + region, + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/client-sources/package.json b/clients/algoliasearch-client-javascript/client-sources/package.json index 9c2e02cd31..da4c21fa45 100644 --- a/clients/algoliasearch-client-javascript/client-sources/package.json +++ b/clients/algoliasearch-client-javascript/client-sources/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/client-sources/src/apis.ts b/clients/algoliasearch-client-javascript/client-sources/src/apis.ts deleted file mode 100644 index 7c654bbce7..0000000000 --- a/clients/algoliasearch-client-javascript/client-sources/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { SourcesApi } from './sourcesApi'; - -export * from './sourcesApi'; -export * from '@algolia/client-common'; - -export const APIS = [SourcesApi]; diff --git a/clients/algoliasearch-client-javascript/client-sources/src/sourcesApi.ts b/clients/algoliasearch-client-javascript/client-sources/src/sourcesApi.ts index 42516da5c6..5ac7ce908e 100644 --- a/clients/algoliasearch-client-javascript/client-sources/src/sourcesApi.ts +++ b/clients/algoliasearch-client-javascript/client-sources/src/sourcesApi.ts @@ -1,10 +1,9 @@ -import { Transporter } from '@algolia/client-common'; +import { Transporter, createAuth, getUserAgent } from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { PostIngestUrlResponse } from '../model/postIngestUrlResponse'; @@ -12,100 +11,36 @@ import type { PostURLJob } from '../model/postURLJob'; export const version = '0.0.1'; -export class SourcesApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; +export type Region = 'de' | 'us'; - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - region: 'de' | 'us', - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } - - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } - - if (!region) { - throw new Error('`region` is missing.'); - } - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(region), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', - }, - userAgent: 'Algolia for Javascript (0.0.1)', - timeouts: { - connect: 2, - read: 5, - write: 30, - }, - requester: options?.requester, - }); - } - - getDefaultHosts(region: 'de' | 'us'): Host[] { - return [ - { - url: `data.${region}.algolia.com`, - accept: 'readWrite', - protocol: 'https', - }, - ]; - } - - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } +function getDefaultHosts(region: Region): Host[] { + return [ + { + url: `data.${region}.algolia.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]; +} - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } - - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createSourcesApi = ( + options: CreateClientOptions & { region: Region } +) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.region), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'Sources', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * Add an ingestion job that will fetch data from an URL. @@ -113,7 +48,9 @@ export class SourcesApi { * @summary Create a new ingestion job via URL. * @param postURLJob - The postURLJob object. */ - postIngestUrl(postURLJob: PostURLJob): Promise { + function postIngestUrl( + postURLJob: PostURLJob + ): Promise { const path = '/1/ingest/url'; const headers: Headers = { Accept: 'application/json' }; const queryParameters: Record = {}; @@ -141,11 +78,16 @@ export class SourcesApi { data: postURLJob, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { postIngestUrl }; +}; + +export type SourcesApi = ReturnType; diff --git a/clients/algoliasearch-client-javascript/client-sources/tsconfig.json b/clients/algoliasearch-client-javascript/client-sources/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/client-sources/tsconfig.json +++ b/clients/algoliasearch-client-javascript/client-sources/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/recommend/api.ts b/clients/algoliasearch-client-javascript/recommend/api.ts deleted file mode 100644 index c4759f623a..0000000000 --- a/clients/algoliasearch-client-javascript/recommend/api.ts +++ /dev/null @@ -1,2 +0,0 @@ -// This is the entrypoint for the package -export * from './src/apis'; diff --git a/clients/algoliasearch-client-javascript/recommend/browser.ts b/clients/algoliasearch-client-javascript/recommend/browser.ts new file mode 100644 index 0000000000..dce3291aa6 --- /dev/null +++ b/clients/algoliasearch-client-javascript/recommend/browser.ts @@ -0,0 +1,37 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { createRecommendApi } from './src/recommendApi'; +import type { RecommendApi } from './src/recommendApi'; + +export * from './src/recommendApi'; +export * from '@algolia/client-common'; + +export function recommendApi( + appId: string, + apiKey: string, + options?: { requester?: Requester; hosts?: Host[] } +): RecommendApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createRecommendApi({ + appId, + apiKey, + + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/recommend/node.ts b/clients/algoliasearch-client-javascript/recommend/node.ts new file mode 100644 index 0000000000..247fbac0d5 --- /dev/null +++ b/clients/algoliasearch-client-javascript/recommend/node.ts @@ -0,0 +1,36 @@ +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { createRecommendApi } from './src/recommendApi'; +import type { RecommendApi } from './src/recommendApi'; + +export * from './src/recommendApi'; +export * from '@algolia/client-common'; + +export function recommendApi( + appId: string, + apiKey: string, + options?: { requester?: Requester; hosts?: Host[] } +): RecommendApi { + if (!appId) { + throw new Error('`appId` is missing.'); + } + + if (!apiKey) { + throw new Error('`apiKey` is missing.'); + } + + return createRecommendApi({ + appId, + apiKey, + + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/clients/algoliasearch-client-javascript/recommend/package.json b/clients/algoliasearch-client-javascript/recommend/package.json index 4389a1b441..bd21bcbff4 100644 --- a/clients/algoliasearch-client-javascript/recommend/package.json +++ b/clients/algoliasearch-client-javascript/recommend/package.json @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/clients/algoliasearch-client-javascript/recommend/src/apis.ts b/clients/algoliasearch-client-javascript/recommend/src/apis.ts deleted file mode 100644 index 8705167102..0000000000 --- a/clients/algoliasearch-client-javascript/recommend/src/apis.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RecommendApi } from './recommendApi'; - -export * from './recommendApi'; -export * from '@algolia/client-common'; - -export const APIS = [RecommendApi]; diff --git a/clients/algoliasearch-client-javascript/recommend/src/recommendApi.ts b/clients/algoliasearch-client-javascript/recommend/src/recommendApi.ts index 5a680f6242..8812c59837 100644 --- a/clients/algoliasearch-client-javascript/recommend/src/recommendApi.ts +++ b/clients/algoliasearch-client-javascript/recommend/src/recommendApi.ts @@ -1,10 +1,14 @@ -import { shuffle, Transporter } from '@algolia/client-common'; +import { + shuffle, + Transporter, + createAuth, + getUserAgent, +} from '@algolia/client-common'; import type { + CreateClientOptions, Headers, - Requester, Host, Request, - RequestOptions, } from '@algolia/client-common'; import type { GetRecommendations } from '../model/getRecommendations'; @@ -12,112 +16,57 @@ import type { GetRecommendationsResponse } from '../model/getRecommendationsResp export const version = '5.0.0'; -export class RecommendApi { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; - - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - options?: { requester?: Requester; hosts?: Host[] } - ) { - if (!appId) { - throw new Error('`appId` is missing.'); - } - - if (!apiKey) { - throw new Error('`apiKey` is missing.'); - } - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts(appId), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded', +function getDefaultHosts(appId: string): Host[] { + return ( + [ + { + url: `${appId}-dsn.algolia.net`, + accept: 'read', + protocol: 'https', }, - userAgent: 'Algolia for Javascript (5.0.0)', - timeouts: { - connect: 2, - read: 5, - write: 30, + { + url: `${appId}.algolia.net`, + accept: 'write', + protocol: 'https', }, - requester: options?.requester, - }); - } - - getDefaultHosts(appId: string): Host[] { - return ( - [ - { url: `${appId}-dsn.algolia.net`, accept: 'read', protocol: 'https' }, - { url: `${appId}.algolia.net`, accept: 'write', protocol: 'https' }, - ] as Host[] - ).concat( - shuffle([ - { - url: `${appId}-1.algolianet.com`, - accept: 'readWrite', - protocol: 'https', - }, - { - url: `${appId}-2.algolianet.com`, - accept: 'readWrite', - protocol: 'https', - }, - { - url: `${appId}-3.algolianet.com`, - accept: 'readWrite', - protocol: 'https', - }, - ]) - ); - } - - setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } + ] as Host[] + ).concat( + shuffle([ + { + url: `${appId}-1.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + { + url: `${appId}-2.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + { + url: `${appId}-3.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]) + ); +} - setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } - - setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const createRecommendApi = (options: CreateClientOptions) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts(options.appId), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: 'Recommend', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); /** * Returns recommendations for a specific model and objectID. @@ -125,7 +74,7 @@ export class RecommendApi { * @summary Returns recommendations for a specific model and objectID. * @param getRecommendations - The getRecommendations object. */ - getRecommendations( + function getRecommendations( getRecommendations: GetRecommendations ): Promise { const path = '/1/indexes/*/recommendations'; @@ -150,11 +99,16 @@ export class RecommendApi { data: getRecommendations, }; - const requestOptions: RequestOptions = { - headers, + return transporter.request(request, { queryParameters, - }; - - return this.sendRequest(request, requestOptions); + headers: { + ...headers, + ...auth.headers(), + }, + }); } -} + + return { getRecommendations }; +}; + +export type RecommendApi = ReturnType; diff --git a/clients/algoliasearch-client-javascript/recommend/tsconfig.json b/clients/algoliasearch-client-javascript/recommend/tsconfig.json index 2f72c93ccb..2613b3ebad 100644 --- a/clients/algoliasearch-client-javascript/recommend/tsconfig.json +++ b/clients/algoliasearch-client-javascript/recommend/tsconfig.json @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["src", "model", "api.ts"], + "include": ["src", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/clients/algoliasearch-client-javascript/requester-browser-xhr/index.ts b/clients/algoliasearch-client-javascript/requester-browser-xhr/index.ts new file mode 100644 index 0000000000..8b46f7f1ce --- /dev/null +++ b/clients/algoliasearch-client-javascript/requester-browser-xhr/index.ts @@ -0,0 +1 @@ +export * from './src/XhrRequester'; diff --git a/clients/algoliasearch-client-javascript/requester-browser-xhr/package.json b/clients/algoliasearch-client-javascript/requester-browser-xhr/package.json new file mode 100644 index 0000000000..d6dbcacb71 --- /dev/null +++ b/clients/algoliasearch-client-javascript/requester-browser-xhr/package.json @@ -0,0 +1,26 @@ +{ + "name": "@algolia/requester-browser-xhr", + "version": "5.0.0", + "description": "Promise-based request library for browser using xhr.", + "repository": "algolia/algoliasearch-client-javascript", + "author": "Algolia", + "private": true, + "license": "MIT", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "rm -rf dist/" + }, + "engines": { + "node": "^14.0.0", + "yarn": "^3.0.0" + }, + "dependencies": { + "@algolia/client-common": "5.0.0" + }, + "devDependencies": { + "@types/node": "16.11.11", + "typescript": "4.5.4" + } +} diff --git a/clients/algoliasearch-client-javascript/requester-browser-xhr/src/XhrRequester.ts b/clients/algoliasearch-client-javascript/requester-browser-xhr/src/XhrRequester.ts new file mode 100644 index 0000000000..c3c6e7d073 --- /dev/null +++ b/clients/algoliasearch-client-javascript/requester-browser-xhr/src/XhrRequester.ts @@ -0,0 +1,78 @@ +import { Requester } from '@algolia/client-common'; +import type { EndRequest, Response } from '@algolia/client-common'; + +export class XhrRequester extends Requester { + send(request: EndRequest): Promise { + return new Promise((resolve) => { + const baseRequester = new XMLHttpRequest(); + baseRequester.open(request.method, request.url, true); + + Object.keys(request.headers).forEach((key) => + baseRequester.setRequestHeader(key, request.headers[key]) + ); + + const createTimeout = ( + timeout: number, + content: string + ): NodeJS.Timeout => { + return setTimeout(() => { + baseRequester.abort(); + + resolve({ + status: 0, + content, + isTimedOut: true, + }); + }, timeout * 1000); + }; + + const connectTimeout = createTimeout( + request.connectTimeout, + 'Connection timeout' + ); + + let responseTimeout: NodeJS.Timeout | undefined; + + baseRequester.onreadystatechange = (): void => { + if ( + baseRequester.readyState > baseRequester.OPENED && + responseTimeout === undefined + ) { + clearTimeout(connectTimeout); + + responseTimeout = createTimeout( + request.responseTimeout, + 'Socket timeout' + ); + } + }; + + baseRequester.onerror = (): void => { + // istanbul ignore next + if (baseRequester.status === 0) { + clearTimeout(connectTimeout); + clearTimeout(responseTimeout as NodeJS.Timeout); + + resolve({ + content: baseRequester.responseText || 'Network request failed', + status: baseRequester.status, + isTimedOut: false, + }); + } + }; + + baseRequester.onload = (): void => { + clearTimeout(connectTimeout); + clearTimeout(responseTimeout as NodeJS.Timeout); + + resolve({ + content: baseRequester.responseText, + status: baseRequester.status, + isTimedOut: false, + }); + }; + + baseRequester.send(request.data); + }); + } +} diff --git a/clients/algoliasearch-client-javascript/requester-browser-xhr/tsconfig.json b/clients/algoliasearch-client-javascript/requester-browser-xhr/tsconfig.json new file mode 100644 index 0000000000..b32907408a --- /dev/null +++ b/clients/algoliasearch-client-javascript/requester-browser-xhr/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitAny": false, + "suppressImplicitAnyIndexErrors": true, + "target": "ES6", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "strict": true, + "moduleResolution": "node", + "removeComments": true, + "sourceMap": true, + "noLib": false, + "declaration": true, + "lib": ["dom", "es6", "es5", "dom.iterable", "scripthost"], + "outDir": "dist", + "typeRoots": ["node_modules/@types"], + "types": ["node"] + }, + "include": ["src", "index.ts"], + "exclude": ["dist", "node_modules"] +} diff --git a/clients/algoliasearch-client-javascript/requester-node-http/index.ts b/clients/algoliasearch-client-javascript/requester-node-http/index.ts new file mode 100644 index 0000000000..c2c9989d95 --- /dev/null +++ b/clients/algoliasearch-client-javascript/requester-node-http/index.ts @@ -0,0 +1 @@ +export * from './src/HttpRequester'; diff --git a/clients/algoliasearch-client-javascript/requester-node-http/package.json b/clients/algoliasearch-client-javascript/requester-node-http/package.json new file mode 100644 index 0000000000..4147deb5c9 --- /dev/null +++ b/clients/algoliasearch-client-javascript/requester-node-http/package.json @@ -0,0 +1,26 @@ +{ + "name": "@algolia/requester-node-http", + "version": "5.0.0", + "description": "Promise-based request library for node using the native http module.", + "repository": "algolia/algoliasearch-client-javascript", + "author": "Algolia", + "private": true, + "license": "MIT", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "rm -rf dist/" + }, + "engines": { + "node": "^14.0.0", + "yarn": "^3.0.0" + }, + "dependencies": { + "@algolia/client-common": "5.0.0" + }, + "devDependencies": { + "@types/node": "16.11.11", + "typescript": "4.5.4" + } +} diff --git a/clients/algoliasearch-client-javascript/client-common/src/requester/HttpRequester.ts b/clients/algoliasearch-client-javascript/requester-node-http/src/HttpRequester.ts similarity index 94% rename from clients/algoliasearch-client-javascript/client-common/src/requester/HttpRequester.ts rename to clients/algoliasearch-client-javascript/requester-node-http/src/HttpRequester.ts index 3697d290fb..1e9b2cb2b5 100644 --- a/clients/algoliasearch-client-javascript/client-common/src/requester/HttpRequester.ts +++ b/clients/algoliasearch-client-javascript/requester-node-http/src/HttpRequester.ts @@ -1,9 +1,9 @@ import http from 'http'; import https from 'https'; +import { URL } from 'url'; -import type { EndRequest, Response } from '../types'; - -import { Requester } from './Requester'; +import { Requester } from '@algolia/client-common'; +import type { EndRequest, Response } from '@algolia/client-common'; // Global agents allow us to reuse the TCP protocol with multiple clients const agentOptions = { keepAlive: true }; diff --git a/clients/algoliasearch-client-javascript/requester-node-http/tsconfig.json b/clients/algoliasearch-client-javascript/requester-node-http/tsconfig.json new file mode 100644 index 0000000000..b32907408a --- /dev/null +++ b/clients/algoliasearch-client-javascript/requester-node-http/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitAny": false, + "suppressImplicitAnyIndexErrors": true, + "target": "ES6", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "strict": true, + "moduleResolution": "node", + "removeComments": true, + "sourceMap": true, + "noLib": false, + "declaration": true, + "lib": ["dom", "es6", "es5", "dom.iterable", "scripthost"], + "outDir": "dist", + "typeRoots": ["node_modules/@types"], + "types": ["node"] + }, + "include": ["src", "index.ts"], + "exclude": ["dist", "node_modules"] +} diff --git a/openapitools.json b/openapitools.json index 71d0fddc28..42aa40aaa4 100644 --- a/openapitools.json +++ b/openapitools.json @@ -18,6 +18,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-search", + "apiName": "search", + "capitalizedApiName": "Search", "packageVersion": "5.0.0", "packageName": "@algolia/client-search" } @@ -37,6 +39,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/recommend", + "apiName": "recommend", + "capitalizedApiName": "Recommend", "packageVersion": "5.0.0", "packageName": "@algolia/recommend" } @@ -55,6 +59,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-personalization", + "apiName": "personalization", + "capitalizedApiName": "Personalization", "packageVersion": "5.0.0", "packageName": "@algolia/client-personalization", "hasRegionalHost": true, @@ -77,6 +83,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-analytics", + "apiName": "analytics", + "capitalizedApiName": "Analytics", "packageVersion": "5.0.0", "packageName": "@algolia/client-analytics", "fallbackToAliasHost": true, @@ -100,6 +108,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-insights", + "apiName": "insights", + "capitalizedApiName": "Insights", "packageVersion": "5.0.0", "packageName": "@algolia/client-insights", "fallbackToAliasHost": true, @@ -123,6 +133,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-abtesting", + "apiName": "abtesting", + "capitalizedApiName": "Abtesting", "packageVersion": "5.0.0", "packageName": "@algolia/client-abtesting", "hasRegionalHost": true, @@ -146,6 +158,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-query-suggestions", + "apiName": "querySuggestions", + "capitalizedApiName": "QuerySuggestions", "packageVersion": "5.0.0", "packageName": "@algolia/client-query-suggestions", "hasRegionalHost": true, @@ -168,6 +182,8 @@ "modelPropertyNaming": "original", "supportsES6": true, "npmName": "@algolia/client-sources", + "apiName": "sources", + "capitalizedApiName": "Sources", "packageVersion": "0.0.1", "packageName": "@algolia/client-sources", "hasRegionalHost": true, diff --git a/playground/javascript/abtesting.ts b/playground/javascript/abtesting.ts index 0b32ebda0d..9f9c6c13f4 100644 --- a/playground/javascript/abtesting.ts +++ b/playground/javascript/abtesting.ts @@ -1,4 +1,4 @@ -import { AbtestingApi, ApiError } from '@algolia/client-abtesting'; +import { abtestingApi, ApiError } from '@algolia/client-abtesting'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); @@ -8,7 +8,7 @@ const apiKey = process.env.ALGOLIA_ANALYTICS_KEY || '**** ANALYTICS_API_KEY *****'; // Init client with appId and apiKey -const client = new AbtestingApi(appId, apiKey, 'de'); +const client = abtestingApi(appId, apiKey, 'de'); async function testABTesting() { try { diff --git a/playground/javascript/analytics.ts b/playground/javascript/analytics.ts index c97cf08f36..f799c5daf5 100644 --- a/playground/javascript/analytics.ts +++ b/playground/javascript/analytics.ts @@ -1,4 +1,4 @@ -import { AnalyticsApi, ApiError } from '@algolia/client-analytics'; +import { analyticsApi, ApiError } from '@algolia/client-analytics'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); @@ -10,7 +10,7 @@ const apiKey = const analyticsIndex = process.env.ANALYTICS_INDEX || 'test_index'; // Init client with appId and apiKey -const client = new AnalyticsApi(appId, apiKey, 'de'); +const client = analyticsApi(appId, apiKey, 'de'); async function testAnalytics() { try { diff --git a/playground/javascript/personalization.ts b/playground/javascript/personalization.ts index 08c433f50b..2adde22066 100644 --- a/playground/javascript/personalization.ts +++ b/playground/javascript/personalization.ts @@ -1,4 +1,4 @@ -import { PersonalizationApi, ApiError } from '@algolia/client-personalization'; +import { personalizationApi, ApiError } from '@algolia/client-personalization'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); @@ -8,7 +8,7 @@ const apiKey = process.env.ALGOLIA_RECOMMENDATION_KEY || '**** RECOMMENDATION_API_KEY *****'; // Init client with appId and apiKey -const client = new PersonalizationApi(appId, apiKey, 'eu'); +const client = personalizationApi(appId, apiKey, 'eu'); async function testPersonalization() { try { diff --git a/playground/javascript/query-suggestions.ts b/playground/javascript/query-suggestions.ts index d81c2d9995..921133f07e 100644 --- a/playground/javascript/query-suggestions.ts +++ b/playground/javascript/query-suggestions.ts @@ -1,5 +1,5 @@ import { - QuerySuggestionsApi, + querySuggestionsApi, ApiError, } from '@algolia/client-query-suggestions'; import dotenv from 'dotenv'; @@ -12,7 +12,7 @@ const apiKey = '**** QUERY_SUGGESTIONS_KEY *****'; // Init client with appId and apiKey -const client = new QuerySuggestionsApi(appId, apiKey, 'us'); +const client = querySuggestionsApi(appId, apiKey, 'us'); async function testABTesting() { try { diff --git a/playground/javascript/recommend.ts b/playground/javascript/recommend.ts index 8eafeb0cc4..1023b76763 100644 --- a/playground/javascript/recommend.ts +++ b/playground/javascript/recommend.ts @@ -1,4 +1,4 @@ -import { RecommendApi, ApiError } from '@algolia/recommend'; +import { recommendApi, ApiError } from '@algolia/recommend'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); @@ -10,7 +10,7 @@ const searchIndex = process.env.SEARCH_INDEX || 'test_index'; const searchQuery = process.env.SEARCH_QUERY || 'test_query'; // Init client with appId and apiKey -const client = new RecommendApi(appId, apiKey); +const client = recommendApi(appId, apiKey); async function testRecommend() { try { diff --git a/playground/javascript/search.ts b/playground/javascript/search.ts index 36990d431b..d77131440f 100644 --- a/playground/javascript/search.ts +++ b/playground/javascript/search.ts @@ -1,4 +1,4 @@ -import { SearchApi, ApiError } from '@algolia/client-search'; +import { searchApi, ApiError } from '@algolia/client-search'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); @@ -10,7 +10,7 @@ const searchIndex = process.env.SEARCH_INDEX || 'test_index'; const searchQuery = process.env.SEARCH_QUERY || 'test_query'; // Init client with appId and apiKey -const client = new SearchApi(appId, apiKey); +const client = searchApi(appId, apiKey); async function testSearch() { try { diff --git a/playground/javascript/sources.ts b/playground/javascript/sources.ts index 978fc948b0..4852cf8f74 100644 --- a/playground/javascript/sources.ts +++ b/playground/javascript/sources.ts @@ -1,4 +1,4 @@ -import { SourcesApi, ApiError } from '@algolia/client-sources'; +import { sourcesApi, ApiError } from '@algolia/client-sources'; import dotenv from 'dotenv'; dotenv.config({ path: '../.env' }); @@ -7,16 +7,16 @@ const appId = process.env.ALGOLIA_APPLICATION_ID || '**** APP_ID *****'; const apiKey = process.env.ALGOLIA_ADMIN_KEY || '**** ALGOLIA_ADMIN_KEY *****'; // Init client with appId and apiKey -const client = new SourcesApi(appId, apiKey); +const client = sourcesApi(appId, apiKey, 'us'); async function testSource() { try { const res = await client.postIngestUrl({ type: 'csv', input: { - url: '' + url: '', // url: 'https://docs.google.com/spreadsheets/d/e/2PACX-1vR7HII972uvH_5IOVCH8HS6348FJP575hs-v1f8EtrUYEFzuapc5QYrZIktNQJMUiF-9ACN_ddodkCk/pub?output=csv' - } + }, }); console.log(`[OK]`, res); diff --git a/playground/javascript/tsconfig.json b/playground/javascript/tsconfig.json index 89cca43a96..cf2579dd53 100644 --- a/playground/javascript/tsconfig.json +++ b/playground/javascript/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../base.tsconfig.json", + "extends": "../../base.tsconfig.json", "compilerOptions": { "outDir": "dist" }, diff --git a/scripts/post-gen/global.sh b/scripts/post-gen/global.sh index fb6002bcac..8d9ebb0a86 100755 --- a/scripts/post-gen/global.sh +++ b/scripts/post-gen/global.sh @@ -15,11 +15,19 @@ if [[ ! $DOCKER ]]; then exit 1 fi -build_js_common() { +build_js_common_requesters() { echo "> Building @algolia/client-common..." yarn workspace @algolia/client-common build + echo "> Building @algolia/requester-node-http..." + + yarn workspace @algolia/requester-node-http build + + echo "> Building @algolia/requester-browser-xhr..." + + yarn workspace @algolia/requester-browser-xhr build + echo "" } @@ -46,5 +54,5 @@ format_specs() { format_specs if [[ $LANGUAGE == 'javascript' || $LANGUAGE == 'all' ]]; then - build_js_common + build_js_common_requesters fi diff --git a/scripts/post-gen/javascript.sh b/scripts/post-gen/javascript.sh new file mode 100755 index 0000000000..92f7e66dad --- /dev/null +++ b/scripts/post-gen/javascript.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Break on non-zero code +set -e + +FOLDER=$1 + +# Generator does not allow new files, so we use existing ones to generate +# our `node` and `browser` build files. + +mv $FOLDER/api.ts $FOLDER/node.ts +mv $FOLDER/src/apis.ts $FOLDER/browser.ts diff --git a/templates/javascript/api-all.mustache b/templates/javascript/api-all.mustache index 17954c9dfc..4a76ba035f 100644 --- a/templates/javascript/api-all.mustache +++ b/templates/javascript/api-all.mustache @@ -1,14 +1,53 @@ -{{#apiInfo}} -{{#apis}} -{{#operations}} -export * from './{{ classFilename }}'; -import { {{ classname }} } from './{{ classFilename }}'; -{{/operations}} -{{#withInterfaces}} -export * from './{{ classFilename }}Interface' -{{/withInterfaces}} -{{/apis}} +{{! This file will be renamed to `browser.ts` after generating the client }} + +import type { Host, Requester } from '@algolia/client-common'; +import { XhrRequester } from '@algolia/requester-browser-xhr'; + +import { create{{capitalizedApiName}}Api, version } from './src/{{apiName}}Api'; +import type { {{capitalizedApiName}}Api } from './src/{{apiName}}Api'; + +{{#hasRegionalHost}} +import type { Region } from './src/{{apiName}}Api'; +{{/hasRegionalHost}} + + +export * from './src/{{apiName}}Api'; export * from '@algolia/client-common'; -export const APIS = [{{#apis}}{{#operations}}{{ classname }}{{/operations}}{{^-last}}, {{/-last}}{{/apis}}]; -{{/apiInfo}} +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export function {{apiName}}Api( + appId: string, + apiKey: string,{{#hasRegionalHost}}region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}: Region,{{/hasRegionalHost}} + options?: { requester?: Requester; hosts?: Host[] } +): {{capitalizedApiName}}Api { + if (!appId) { + throw new Error("`appId` is missing."); + } + + if (!apiKey) { + throw new Error("`apiKey` is missing."); + } + + {{#hasRegionalHost}} + {{^fallbackToAliasHost}} + if (!region) { + throw new Error("`region` is missing."); + } + {{/fallbackToAliasHost}} + {{/hasRegionalHost}} + + return create{{capitalizedApiName}}Api({ + appId, + apiKey, + {{#hasRegionalHost}}region,{{/hasRegionalHost}} + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new XhrRequester(), + userAgents: [{ segment: 'Browser' }], + authMode: 'WithinQueryParameters', + ...options, + }); +} diff --git a/templates/javascript/api-single.mustache b/templates/javascript/api-single.mustache index 3d4d1bb9b5..bbc39b6307 100644 --- a/templates/javascript/api-single.mustache +++ b/templates/javascript/api-single.mustache @@ -1,5 +1,5 @@ -import { shuffle, Transporter } from '@algolia/client-common'; -import type { Headers, Requester, Host, Request, RequestOptions } from '@algolia/client-common'; +import { shuffle, Transporter, createAuth, getUserAgent } from '@algolia/client-common'; +import type { CreateClientOptions, Headers, Host, Request } from '@algolia/client-common'; {{#imports}} import { {{classname}} } from '{{filename}}'; @@ -14,124 +14,71 @@ export const version = '{{packageVersion}}'; */ {{/description}} -export class {{classname}} { - protected authentications = { - apiKey: 'Algolia-API-Key', - appId: 'Algolia-Application-Id', - }; +{{#hasRegionalHost}} +export type Region = {{#isDeHost}}'de'{{/isDeHost}}{{#isEuHost}}'eu'{{/isEuHost}} | 'us'; +{{/hasRegionalHost}} - private transporter: Transporter; - - private applyAuthenticationHeaders( - requestOptions: RequestOptions - ): RequestOptions { - if (requestOptions?.headers) { - return { - ...requestOptions, - headers: { - ...requestOptions.headers, - 'X-Algolia-API-Key': this.authentications.apiKey, - 'X-Algolia-Application-Id': this.authentications.appId, - }, - }; - } - - return requestOptions; - } - - private sendRequest( - request: Request, - requestOptions: RequestOptions - ): Promise { - return this.transporter.request( - request, - this.applyAuthenticationHeaders(requestOptions) - ); - } - - constructor( - appId: string, - apiKey: string, - {{#hasRegionalHost}} - region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}: {{#isDeHost}}'de'{{/isDeHost}}{{#isEuHost}}'eu'{{/isEuHost}} | 'us', - {{/hasRegionalHost}} - options?: {requester?: Requester, hosts?: Host[]} - ) { - if (!appId) { - throw new Error("`appId` is missing."); - } - - if (!apiKey) { - throw new Error("`apiKey` is missing."); - } - - {{#hasRegionalHost}} - {{^fallbackToAliasHost}} - if (!region) { - throw new Error("`region` is missing."); - } - {{/fallbackToAliasHost}} - {{/hasRegionalHost}} - - this.setAuthentication({ appId, apiKey }); - - this.transporter = new Transporter({ - hosts: options?.hosts ?? this.getDefaultHosts( - {{^hasRegionalHost}}appId{{/hasRegionalHost}} - {{#hasRegionalHost}}region{{/hasRegionalHost}} - ), - baseHeaders: { - 'content-type': 'application/x-www-form-urlencoded' +{{^hasRegionalHost}} +function getDefaultHosts(appId: string): Host[] { + return ( + [ + { + url: `${appId}-dsn.algolia.net`, + accept: 'read', + protocol: 'https', }, - userAgent: 'Algolia for Javascript ({{packageVersion}})', - timeouts: { - connect: 2, - read: 5, - write: 30, + { + url: `${appId}.algolia.net`, + accept: 'write', + protocol: 'https', }, - requester: options?.requester, - }); - } - - {{^hasRegionalHost}} - public getDefaultHosts(appId: string): Host[] { - return ( - [ - { url: `${appId}-dsn.algolia.net`, accept: 'read', protocol: 'https' }, - { url: `${appId}.algolia.net`, accept: 'write', protocol: 'https' }, - ] as Host[] - ).concat( - shuffle([ - { url: `${appId}-1.algolianet.com`, accept: 'readWrite', protocol: 'https' }, - { url: `${appId}-2.algolianet.com`, accept: 'readWrite', protocol: 'https' }, - { url: `${appId}-3.algolianet.com`, accept: 'readWrite', protocol: 'https' }, - ]) - ); - } - {{/hasRegionalHost}} - - {{#hasRegionalHost}} - public getDefaultHosts(region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}: {{#isDeHost}}'de'{{/isDeHost}}{{#isEuHost}}'eu'{{/isEuHost}} | 'us'): Host[] { - {{#fallbackToAliasHost}}const regionHost = region ? `.${region}.` : '.';{{/fallbackToAliasHost}} - - return [{ url: `{{{host}}}{{#fallbackToAliasHost}}${regionHost}{{/fallbackToAliasHost}}{{^fallbackToAliasHost}}.${region}.{{/fallbackToAliasHost}}algolia.{{#topLevelDomain}}{{.}}{{/topLevelDomain}}{{^topLevelDomain}}com{{/topLevelDomain}}`, accept: 'readWrite', protocol: 'https' }]; - } - {{/hasRegionalHost}} + ] as Host[] + ).concat( + shuffle([ + { + url: `${appId}-1.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + { + url: `${appId}-2.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + { + url: `${appId}-3.algolianet.com`, + accept: 'readWrite', + protocol: 'https', + }, + ]) + ); +} +{{/hasRegionalHost}} - public setRequest(requester: Requester): void { - this.transporter.setRequester(requester); - } +{{#hasRegionalHost}} +function getDefaultHosts(region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}: Region): Host[] { + {{#fallbackToAliasHost}}const regionHost = region ? `.${region}.` : '.';{{/fallbackToAliasHost}} - public setHosts(hosts: Host[]): void { - this.transporter.setHosts(hosts); - } + return [{ url: `{{{host}}}{{#fallbackToAliasHost}}${regionHost}{{/fallbackToAliasHost}}{{^fallbackToAliasHost}}.${region}.{{/fallbackToAliasHost}}algolia.{{#topLevelDomain}}{{.}}{{/topLevelDomain}}{{^topLevelDomain}}com{{/topLevelDomain}}`, accept: 'readWrite', protocol: 'https' }]; +} +{{/hasRegionalHost}} - public setAuthentication({ appId, apiKey }): void { - this.authentications = { - apiKey, - appId, - }; - } +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export const create{{capitalizedApiName}}Api = (options: CreateClientOptions{{#hasRegionalHost}} & {region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}: Region }{{/hasRegionalHost}}) => { + const auth = createAuth(options.appId, options.apiKey, options.authMode); + const transporter = new Transporter({ + hosts: options?.hosts ?? getDefaultHosts({{^hasRegionalHost}}options.appId{{/hasRegionalHost}}{{#hasRegionalHost}}options.region{{/hasRegionalHost}}), + baseHeaders: { + 'content-type': 'application/x-www-form-urlencoded', + }, + userAgent: getUserAgent({ + userAgents: options.userAgents, + client: '{{{capitalizedApiName}}}', + version, + }), + timeouts: options.timeouts, + requester: options.requester, + }); {{#operation}} /** @@ -179,7 +126,7 @@ export class {{classname}} { {{/bodyParams.0}} {{/allParams.0}} */ - public {{nickname}}( + function {{nickname}}( {{#allParams.0}} {{^bodyParams.0}} { @@ -267,16 +214,22 @@ export class {{classname}} { {{/bodyParam}} }; - const requestOptions: RequestOptions = { - headers, - queryParameters - }; - - return this.sendRequest(request, requestOptions); + return transporter.request(request, { + queryParameters, + headers: { + ...headers, + ...auth.headers(), + }, + }); } + {{/operation}} + + return { {{#operation}}{{nickname}},{{/operation}} }; } +export type {{capitalizedApiName}}Api = ReturnType; + {{#operation}} {{#allParams.0}} {{^bodyParams.0}} diff --git a/templates/javascript/api.mustache b/templates/javascript/api.mustache index 19d153c096..c2529416b2 100644 --- a/templates/javascript/api.mustache +++ b/templates/javascript/api.mustache @@ -1,2 +1,51 @@ -// This is the entrypoint for the package -export * from './{{apiPackage}}/apis'; +{{! This file will be renamed to `node.ts` after generating the client }} + +import type { Host, Requester } from '@algolia/client-common'; +import { HttpRequester } from '@algolia/requester-node-http'; + +import { create{{capitalizedApiName}}Api, version } from './src/{{apiName}}Api'; +import type { {{capitalizedApiName}}Api } from './src/{{apiName}}Api'; + +{{#hasRegionalHost}} +import type { Region } from './src/{{apiName}}Api'; +{{/hasRegionalHost}} + + +export * from './src/{{apiName}}Api'; +export * from '@algolia/client-common'; + +export function {{apiName}}Api( + appId: string, + apiKey: string,{{#hasRegionalHost}}region{{#fallbackToAliasHost}}?{{/fallbackToAliasHost}}: Region,{{/hasRegionalHost}} + options?: { requester?: Requester; hosts?: Host[] } +): {{capitalizedApiName}}Api { + if (!appId) { + throw new Error("`appId` is missing."); + } + + if (!apiKey) { + throw new Error("`apiKey` is missing."); + } + + {{#hasRegionalHost}} + {{^fallbackToAliasHost}} + if (!region) { + throw new Error("`region` is missing."); + } + {{/fallbackToAliasHost}} + {{/hasRegionalHost}} + + return create{{capitalizedApiName}}Api({ + appId, + apiKey, + {{#hasRegionalHost}}region,{{/hasRegionalHost}} + timeouts: { + connect: 1, + read: 2, + write: 30, + }, + requester: options?.requester ?? new HttpRequester(), + userAgents: [{ segment: 'Node.js', version: process.versions.node }], + ...options, + }); +} diff --git a/templates/javascript/package.mustache b/templates/javascript/package.mustache index 3ddc7606d4..f5058586fc 100644 --- a/templates/javascript/package.mustache +++ b/templates/javascript/package.mustache @@ -6,18 +6,25 @@ "author": "Algolia", "private": true, "license": "MIT", - "main": "dist/api.js", - "types": "dist/api.d.ts", + "main": "./dist/node.js", + "types": "./dist/node.d.ts", + "jsdelivr": "./dist/browser.js", + "unpkg": "./dist/browser.js", + "browser": { + "./index.js": "./dist/browser.js" + }, "scripts": { "build": "tsc", "clean": "rm -rf dist/" }, "engines": { - "node": "^16.0.0", + "node": "^14.0.0", "yarn": "^3.0.0" }, "dependencies": { - "@algolia/client-common": "5.0.0" + "@algolia/client-common": "5.0.0", + "@algolia/requester-browser-xhr": "5.0.0", + "@algolia/requester-node-http": "5.0.0" }, "devDependencies": { "@types/node": "16.11.11", diff --git a/templates/javascript/tsconfig.mustache b/templates/javascript/tsconfig.mustache index 1b77056931..a8f0297e53 100644 --- a/templates/javascript/tsconfig.mustache +++ b/templates/javascript/tsconfig.mustache @@ -17,6 +17,6 @@ "typeRoots": ["node_modules/@types"], "types": ["node"] }, - "include": ["{{apiPackage}}", "model", "api.ts"], + "include": ["{{apiPackage}}", "model", "node.ts", "browser.ts"], "exclude": ["dist", "node_modules"] } diff --git a/tests/CTS/client/templates/javascript/createClient.mustache b/tests/CTS/client/templates/javascript/createClient.mustache index bcb79ba239..a158339f78 100644 --- a/tests/CTS/client/templates/javascript/createClient.mustache +++ b/tests/CTS/client/templates/javascript/createClient.mustache @@ -1,8 +1,3 @@ -new {{client}}( - '{{parameters.appId}}', - '{{parameters.apiKey}}', - {{#hasRegionalHost}}'{{parameters.region}}',{{/hasRegionalHost}} - { - requester: new EchoRequester() - } -) \ No newline at end of file +{{client}}( + '{{parameters.appId}}','{{parameters.apiKey}}',{{#hasRegionalHost}}'{{parameters.region}}',{{/hasRegionalHost}}{requester: new EchoRequester()} +) diff --git a/tests/CTS/client/templates/javascript/suite.mustache b/tests/CTS/client/templates/javascript/suite.mustache index d863e23a70..3385dc6a41 100644 --- a/tests/CTS/client/templates/javascript/suite.mustache +++ b/tests/CTS/client/templates/javascript/suite.mustache @@ -2,13 +2,15 @@ /* eslint-disable require-await */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ // @ts-nocheck -import { {{client}}, EchoRequester } from '{{{import}}}'; +import { {{client}} } from '{{{import}}}'; +import { EchoRequester } from '@algolia/client-common'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'Algolia-API-Key'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'Algolia-Application-Id'; -function createClient(): {{client}} { - return new {{client}}(appId, apiKey, {{#hasRegionalHost}}'us', {{/hasRegionalHost}}{ requester: new EchoRequester() }); +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +function createClient() { + return {{client}}(appId, apiKey, {{#hasRegionalHost}}'us', {{/hasRegionalHost}}{ requester: new EchoRequester() }); } {{#blocks}} diff --git a/tests/CTS/methods/requests/templates/javascript/requests.mustache b/tests/CTS/methods/requests/templates/javascript/requests.mustache index bb139f9358..4299cdb6e0 100644 --- a/tests/CTS/methods/requests/templates/javascript/requests.mustache +++ b/tests/CTS/methods/requests/templates/javascript/requests.mustache @@ -1,10 +1,11 @@ -import { {{client}}, EchoRequester } from '{{{import}}}'; -import type { EchoResponse } from '{{{import}}}'; +import { {{client}} } from '{{{import}}}'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new {{client}}(appId, apiKey, {{#hasRegionalHost}}'us', {{/hasRegionalHost}}{ requester: new EchoRequester() }); +const client = {{client}}(appId, apiKey, {{#hasRegionalHost}}'us', {{/hasRegionalHost}}{ requester: new EchoRequester() }); {{#blocks}} describe('{{operationId}}', () => { diff --git a/tests/output/javascript/package.json b/tests/output/javascript/package.json index 3a90d10f8a..49c41351b3 100644 --- a/tests/output/javascript/package.json +++ b/tests/output/javascript/package.json @@ -8,6 +8,7 @@ "dependencies": { "@algolia/client-abtesting": "5.0.0", "@algolia/client-analytics": "5.0.0", + "@algolia/client-common": "5.0.0", "@algolia/client-insights": "5.0.0", "@algolia/client-personalization": "5.0.0", "@algolia/client-query-suggestions": "5.0.0", diff --git a/tests/output/javascript/tests/client/analytics.test.ts b/tests/output/javascript/tests/client/analytics.test.ts index bb53b0a94f..4795f14453 100644 --- a/tests/output/javascript/tests/client/analytics.test.ts +++ b/tests/output/javascript/tests/client/analytics.test.ts @@ -1,13 +1,13 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ // @ts-nocheck -import { AnalyticsApi, EchoRequester } from '@algolia/client-analytics'; +import { analyticsApi } from '@algolia/client-analytics'; +import { EchoRequester } from '@algolia/client-common'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'Algolia-API-Key'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'Algolia-Application-Id'; -function createClient(): AnalyticsApi { - return new AnalyticsApi(appId, apiKey, 'us', { - requester: new EchoRequester(), - }); +function createClient() { + return analyticsApi(appId, apiKey, 'us', { requester: new EchoRequester() }); } describe('basic', () => { @@ -16,9 +16,10 @@ describe('basic', () => { await expect( new Promise((resolve, reject) => { - const $client = new AnalyticsApi('my-app-id', 'my-api-key', '', { + const $client = analyticsApi('my-app-id', 'my-api-key', '', { requester: new EchoRequester(), }); + actual = $client; if (actual instanceof Promise) { diff --git a/tests/output/javascript/tests/client/search.test.ts b/tests/output/javascript/tests/client/search.test.ts index 6001f04cbf..7cf803766f 100644 --- a/tests/output/javascript/tests/client/search.test.ts +++ b/tests/output/javascript/tests/client/search.test.ts @@ -1,11 +1,13 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ // @ts-nocheck -import { SearchApi, EchoRequester } from '@algolia/client-search'; +import { EchoRequester } from '@algolia/client-common'; +import { searchApi } from '@algolia/client-search'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'Algolia-API-Key'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'Algolia-Application-Id'; -function createClient(): SearchApi { - return new SearchApi(appId, apiKey, { requester: new EchoRequester() }); +function createClient() { + return searchApi(appId, apiKey, { requester: new EchoRequester() }); } describe('parameters', () => { @@ -13,14 +15,8 @@ describe('parameters', () => { let actual; await expect( new Promise((resolve, reject) => { - const $client = new SearchApi( - '', - '', - - { - requester: new EchoRequester(), - } - ); + const $client = searchApi('', '', { requester: new EchoRequester() }); + actual = $client; if (actual instanceof Promise) { @@ -33,14 +29,10 @@ describe('parameters', () => { await expect( new Promise((resolve, reject) => { - const $client = new SearchApi( - '', - 'my-api-key', - - { - requester: new EchoRequester(), - } - ); + const $client = searchApi('', 'my-api-key', { + requester: new EchoRequester(), + }); + actual = $client; if (actual instanceof Promise) { @@ -53,14 +45,10 @@ describe('parameters', () => { await expect( new Promise((resolve, reject) => { - const $client = new SearchApi( - 'my-app-id', - '', - - { - requester: new EchoRequester(), - } - ); + const $client = searchApi('my-app-id', '', { + requester: new EchoRequester(), + }); + actual = $client; if (actual instanceof Promise) { diff --git a/tests/output/javascript/tests/methods/requests/abtesting.test.ts b/tests/output/javascript/tests/methods/requests/abtesting.test.ts index 8bdbde5eef..ddccb4fa44 100644 --- a/tests/output/javascript/tests/methods/requests/abtesting.test.ts +++ b/tests/output/javascript/tests/methods/requests/abtesting.test.ts @@ -1,10 +1,11 @@ -import { AbtestingApi, EchoRequester } from '@algolia/client-abtesting'; -import type { EchoResponse } from '@algolia/client-abtesting'; +import { abtestingApi } from '@algolia/client-abtesting'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new AbtestingApi(appId, apiKey, 'us', { +const client = abtestingApi(appId, apiKey, 'us', { requester: new EchoRequester(), }); diff --git a/tests/output/javascript/tests/methods/requests/analytics.test.ts b/tests/output/javascript/tests/methods/requests/analytics.test.ts index a7ba9d0aeb..05357f3ee4 100644 --- a/tests/output/javascript/tests/methods/requests/analytics.test.ts +++ b/tests/output/javascript/tests/methods/requests/analytics.test.ts @@ -1,10 +1,11 @@ -import { AnalyticsApi, EchoRequester } from '@algolia/client-analytics'; -import type { EchoResponse } from '@algolia/client-analytics'; +import { analyticsApi } from '@algolia/client-analytics'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new AnalyticsApi(appId, apiKey, 'us', { +const client = analyticsApi(appId, apiKey, 'us', { requester: new EchoRequester(), }); diff --git a/tests/output/javascript/tests/methods/requests/insights.test.ts b/tests/output/javascript/tests/methods/requests/insights.test.ts index 23a49b40f2..c44fcce9c7 100644 --- a/tests/output/javascript/tests/methods/requests/insights.test.ts +++ b/tests/output/javascript/tests/methods/requests/insights.test.ts @@ -1,10 +1,11 @@ -import { InsightsApi, EchoRequester } from '@algolia/client-insights'; -import type { EchoResponse } from '@algolia/client-insights'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; +import { insightsApi } from '@algolia/client-insights'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new InsightsApi(appId, apiKey, 'us', { +const client = insightsApi(appId, apiKey, 'us', { requester: new EchoRequester(), }); diff --git a/tests/output/javascript/tests/methods/requests/personalization.test.ts b/tests/output/javascript/tests/methods/requests/personalization.test.ts index d735e23d6a..a23a709444 100644 --- a/tests/output/javascript/tests/methods/requests/personalization.test.ts +++ b/tests/output/javascript/tests/methods/requests/personalization.test.ts @@ -1,13 +1,11 @@ -import { - PersonalizationApi, - EchoRequester, -} from '@algolia/client-personalization'; -import type { EchoResponse } from '@algolia/client-personalization'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; +import { personalizationApi } from '@algolia/client-personalization'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new PersonalizationApi(appId, apiKey, 'us', { +const client = personalizationApi(appId, apiKey, 'us', { requester: new EchoRequester(), }); diff --git a/tests/output/javascript/tests/methods/requests/query-suggestions.test.ts b/tests/output/javascript/tests/methods/requests/query-suggestions.test.ts index e8dcdf3275..33067fcbdf 100644 --- a/tests/output/javascript/tests/methods/requests/query-suggestions.test.ts +++ b/tests/output/javascript/tests/methods/requests/query-suggestions.test.ts @@ -1,13 +1,11 @@ -import { - QuerySuggestionsApi, - EchoRequester, -} from '@algolia/client-query-suggestions'; -import type { EchoResponse } from '@algolia/client-query-suggestions'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; +import { querySuggestionsApi } from '@algolia/client-query-suggestions'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new QuerySuggestionsApi(appId, apiKey, 'us', { +const client = querySuggestionsApi(appId, apiKey, 'us', { requester: new EchoRequester(), }); diff --git a/tests/output/javascript/tests/methods/requests/recommend.test.ts b/tests/output/javascript/tests/methods/requests/recommend.test.ts index f3ef59a022..57ca8bfe3c 100644 --- a/tests/output/javascript/tests/methods/requests/recommend.test.ts +++ b/tests/output/javascript/tests/methods/requests/recommend.test.ts @@ -1,12 +1,11 @@ -import { RecommendApi, EchoRequester } from '@algolia/recommend'; -import type { EchoResponse } from '@algolia/recommend'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; +import { recommendApi } from '@algolia/recommend'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new RecommendApi(appId, apiKey, { - requester: new EchoRequester(), -}); +const client = recommendApi(appId, apiKey, { requester: new EchoRequester() }); describe('getRecommendations', () => { test('get recommendations with minimal parameters', async () => { diff --git a/tests/output/javascript/tests/methods/requests/search.test.ts b/tests/output/javascript/tests/methods/requests/search.test.ts index 128f50211d..f8e8121ac2 100644 --- a/tests/output/javascript/tests/methods/requests/search.test.ts +++ b/tests/output/javascript/tests/methods/requests/search.test.ts @@ -1,10 +1,11 @@ -import { SearchApi, EchoRequester } from '@algolia/client-search'; -import type { EchoResponse } from '@algolia/client-search'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; +import { searchApi } from '@algolia/client-search'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new SearchApi(appId, apiKey, { requester: new EchoRequester() }); +const client = searchApi(appId, apiKey, { requester: new EchoRequester() }); describe('addApiKey', () => { test('addApiKey', async () => { diff --git a/tests/output/javascript/tests/methods/requests/sources.test.ts b/tests/output/javascript/tests/methods/requests/sources.test.ts index d7663d4b2c..6a80113218 100644 --- a/tests/output/javascript/tests/methods/requests/sources.test.ts +++ b/tests/output/javascript/tests/methods/requests/sources.test.ts @@ -1,10 +1,11 @@ -import { SourcesApi, EchoRequester } from '@algolia/client-sources'; -import type { EchoResponse } from '@algolia/client-sources'; +import { EchoRequester } from '@algolia/client-common'; +import type { EchoResponse } from '@algolia/client-common'; +import { sourcesApi } from '@algolia/client-sources'; const appId = process.env.ALGOLIA_APPLICATION_ID || 'test_app_id'; const apiKey = process.env.ALGOLIA_SEARCH_KEY || 'test_api_key'; -const client = new SourcesApi(appId, apiKey, 'us', { +const client = sourcesApi(appId, apiKey, 'us', { requester: new EchoRequester(), }); diff --git a/tests/src/client/generate.ts b/tests/src/client/generate.ts index 744811868b..9469c0ebcc 100644 --- a/tests/src/client/generate.ts +++ b/tests/src/client/generate.ts @@ -90,7 +90,7 @@ export async function generateTests( template, { import: packageNames[language][client], - client: createClientName(client), + client: createClientName(client, language), blocks: modifyForMustache(testsBlocks), hasRegionalHost: openapitools['generator-cli'].generators[ `${language}-${client}` diff --git a/tests/src/methods/requests/generate.ts b/tests/src/methods/requests/generate.ts index 916e091499..4d14c9f4f7 100644 --- a/tests/src/methods/requests/generate.ts +++ b/tests/src/methods/requests/generate.ts @@ -35,7 +35,7 @@ export async function generateTests( template, { import: packageNames[language][client], - client: createClientName(client), + client: createClientName(client, language), blocks: cts, hasRegionalHost: openapitools['generator-cli'].generators[ `${language}-${client}` diff --git a/tests/src/utils.test.ts b/tests/src/utils.test.ts index 84ea587de0..de0f60ea20 100644 --- a/tests/src/utils.test.ts +++ b/tests/src/utils.test.ts @@ -25,10 +25,22 @@ describe('utils', () => { }); describe('createClientName', () => { - it('capitalize every part', () => { - expect(createClientName('search')).toEqual('SearchApi'); - expect(createClientName('search-client')).toEqual('SearchClientApi'); - expect(createClientName('search-cli!nt-complex')).toEqual( + it('does not capitalize every part for JavaScript', () => { + expect(createClientName('search', 'javascript')).toEqual('searchApi'); + expect(createClientName('search-client', 'javascript')).toEqual( + 'searchClientApi' + ); + expect(createClientName('search-cli!nt-complex', 'javascript')).toEqual( + 'searchCli!ntComplexApi' + ); + }); + + it('capitalize every part for other languages', () => { + expect(createClientName('search', 'java')).toEqual('SearchApi'); + expect(createClientName('search-client', 'java')).toEqual( + 'SearchClientApi' + ); + expect(createClientName('search-cli!nt-complex', 'java')).toEqual( 'SearchCli!ntComplexApi' ); }); diff --git a/tests/src/utils.ts b/tests/src/utils.ts index 761bef3f6a..a6fd563a2d 100644 --- a/tests/src/utils.ts +++ b/tests/src/utils.ts @@ -49,11 +49,19 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } -export function createClientName(client: string): string { - return `${client +export function createClientName(client: string, language: string): string { + const clientName = client .split('-') - .map((part) => capitalize(part)) - .join('')}Api`; + .map((part, i) => { + if (language === 'javascript' && i === 0) { + return part; + } + + return capitalize(part); + }) + .join(''); + + return `${clientName}Api`; } export function removeObjectName(obj: any): any { diff --git a/yarn.lock b/yarn.lock index 536a72b75b..be1d639bb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -37,6 +37,8 @@ __metadata: resolution: "@algolia/client-abtesting@workspace:clients/algoliasearch-client-javascript/client-abtesting" dependencies: "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 "@types/node": 16.11.11 typescript: 4.5.4 languageName: unknown @@ -47,6 +49,8 @@ __metadata: resolution: "@algolia/client-analytics@workspace:clients/algoliasearch-client-javascript/client-analytics" dependencies: "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 "@types/node": 16.11.11 typescript: 4.5.4 languageName: unknown @@ -66,6 +70,8 @@ __metadata: resolution: "@algolia/client-insights@workspace:clients/algoliasearch-client-javascript/client-insights" dependencies: "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 "@types/node": 16.11.11 typescript: 4.5.4 languageName: unknown @@ -76,6 +82,8 @@ __metadata: resolution: "@algolia/client-personalization@workspace:clients/algoliasearch-client-javascript/client-personalization" dependencies: "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 "@types/node": 16.11.11 typescript: 4.5.4 languageName: unknown @@ -86,6 +94,8 @@ __metadata: resolution: "@algolia/client-query-suggestions@workspace:clients/algoliasearch-client-javascript/client-query-suggestions" dependencies: "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 "@types/node": 16.11.11 typescript: 4.5.4 languageName: unknown @@ -96,6 +106,8 @@ __metadata: resolution: "@algolia/client-search@workspace:clients/algoliasearch-client-javascript/client-search" dependencies: "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 "@types/node": 16.11.11 typescript: 4.5.4 languageName: unknown @@ -106,6 +118,8 @@ __metadata: resolution: "@algolia/client-sources@workspace:clients/algoliasearch-client-javascript/client-sources" dependencies: "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 "@types/node": 16.11.11 typescript: 4.5.4 languageName: unknown @@ -114,6 +128,28 @@ __metadata: "@algolia/recommend@5.0.0, @algolia/recommend@workspace:clients/algoliasearch-client-javascript/recommend": version: 0.0.0-use.local resolution: "@algolia/recommend@workspace:clients/algoliasearch-client-javascript/recommend" + dependencies: + "@algolia/client-common": 5.0.0 + "@algolia/requester-browser-xhr": 5.0.0 + "@algolia/requester-node-http": 5.0.0 + "@types/node": 16.11.11 + typescript: 4.5.4 + languageName: unknown + linkType: soft + +"@algolia/requester-browser-xhr@5.0.0, @algolia/requester-browser-xhr@workspace:clients/algoliasearch-client-javascript/requester-browser-xhr": + version: 0.0.0-use.local + resolution: "@algolia/requester-browser-xhr@workspace:clients/algoliasearch-client-javascript/requester-browser-xhr" + dependencies: + "@algolia/client-common": 5.0.0 + "@types/node": 16.11.11 + typescript: 4.5.4 + languageName: unknown + linkType: soft + +"@algolia/requester-node-http@5.0.0, @algolia/requester-node-http@workspace:clients/algoliasearch-client-javascript/requester-node-http": + version: 0.0.0-use.local + resolution: "@algolia/requester-node-http@workspace:clients/algoliasearch-client-javascript/requester-node-http" dependencies: "@algolia/client-common": 5.0.0 "@types/node": 16.11.11 @@ -3814,6 +3850,7 @@ __metadata: dependencies: "@algolia/client-abtesting": 5.0.0 "@algolia/client-analytics": 5.0.0 + "@algolia/client-common": 5.0.0 "@algolia/client-insights": 5.0.0 "@algolia/client-personalization": 5.0.0 "@algolia/client-query-suggestions": 5.0.0