1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276 |
- import { createAuth, AuthMode, shuffle, addMethods, createWaitablePromise, createRetryablePromise, encode } from '@algolia/client-common';
- import { createTransporter, CallEnum, createMappedRequestOptions, serializeQueryParameters } from '@algolia/transporter';
- import { MethodEnum } from '@algolia/requester-common';
- import { createHmac } from 'crypto';
- function createBrowsablePromise(options) {
- const browse = (data) => {
- return options.request(data).then(response => {
- /**
- * First we send to the developer the
- * batch retrieved from the API.
- */
- if (options.batch !== undefined) {
- options.batch(response.hits);
- }
- /**
- * Then, we ask to the browse concrete implementation
- * if we should stop browsing. As example, the `browseObjects`
- * method will stop if the cursor is not present on the response.
- */
- if (options.shouldStop(response)) {
- return undefined;
- }
- /**
- * Finally, if the response contains a cursor, we browse to the next
- * batch using that same cursor. Otherwise, we just use the traditional
- * browsing using the page element.
- */
- if (response.cursor) {
- return browse({
- cursor: response.cursor,
- });
- }
- return browse({
- page: (data.page || 0) + 1,
- });
- });
- };
- return browse({});
- }
- const createSearchClient = options => {
- const appId = options.appId;
- const auth = createAuth(options.authMode !== undefined ? options.authMode : AuthMode.WithinHeaders, appId, options.apiKey);
- const transporter = createTransporter({
- hosts: [
- { url: `${appId}-dsn.algolia.net`, accept: CallEnum.Read },
- { url: `${appId}.algolia.net`, accept: CallEnum.Write },
- ].concat(shuffle([
- { url: `${appId}-1.algolianet.com` },
- { url: `${appId}-2.algolianet.com` },
- { url: `${appId}-3.algolianet.com` },
- ])),
- ...options,
- headers: {
- ...auth.headers(),
- ...{ 'content-type': 'application/x-www-form-urlencoded' },
- ...options.headers,
- },
- queryParameters: {
- ...auth.queryParameters(),
- ...options.queryParameters,
- },
- });
- const base = {
- transporter,
- appId,
- addAlgoliaAgent(segment, version) {
- transporter.userAgent.add({ segment, version });
- },
- clearCache() {
- return Promise.all([
- transporter.requestsCache.clear(),
- transporter.responsesCache.clear(),
- ]).then(() => undefined);
- },
- };
- return addMethods(base, options.methods);
- };
- function createMissingObjectIDError() {
- return {
- name: 'MissingObjectIDError',
- message: 'All objects must have an unique objectID ' +
- '(like a primary key) to be valid. ' +
- 'Algolia is also able to generate objectIDs ' +
- "automatically but *it's not recommended*. " +
- "To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option.",
- };
- }
- function createObjectNotFoundError() {
- return {
- name: 'ObjectNotFoundError',
- message: 'Object not found.',
- };
- }
- function createValidUntilNotFoundError() {
- return {
- name: 'ValidUntilNotFoundError',
- message: 'ValidUntil not found in given secured api key.',
- };
- }
- const addApiKey = (base) => {
- return (acl, requestOptions) => {
- const { queryParameters, ...options } = requestOptions || {};
- const data = {
- acl,
- ...(queryParameters !== undefined ? { queryParameters } : {}),
- };
- const wait = (response, waitRequestOptions) => {
- return createRetryablePromise(retry => {
- return getApiKey(base)(response.key, waitRequestOptions).catch((apiError) => {
- if (apiError.status !== 404) {
- throw apiError;
- }
- return retry();
- });
- });
- };
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: '1/keys',
- data,
- }, options), wait);
- };
- };
- const assignUserID = (base) => {
- return (userID, clusterName, requestOptions) => {
- const mappedRequestOptions = createMappedRequestOptions(requestOptions);
- // eslint-disable-next-line functional/immutable-data
- mappedRequestOptions.queryParameters['X-Algolia-User-ID'] = userID;
- return base.transporter.write({
- method: MethodEnum.Post,
- path: '1/clusters/mapping',
- data: { cluster: clusterName },
- }, mappedRequestOptions);
- };
- };
- const assignUserIDs = (base) => {
- return (userIDs, clusterName, requestOptions) => {
- return base.transporter.write({
- method: MethodEnum.Post,
- path: '1/clusters/mapping/batch',
- data: {
- users: userIDs,
- cluster: clusterName,
- },
- }, requestOptions);
- };
- };
- const clearDictionaryEntries = (base) => {
- return (dictionary, requestOptions) => {
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('/1/dictionaries/%s/batch', dictionary),
- data: {
- clearExistingDictionaryEntries: true,
- requests: { action: 'addEntry', body: [] },
- },
- }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const copyIndex = (base) => {
- return (from, to, requestOptions) => {
- const wait = (response, waitRequestOptions) => {
- return initIndex(base)(from, {
- methods: { waitTask },
- }).waitTask(response.taskID, waitRequestOptions);
- };
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/operation', from),
- data: {
- operation: 'copy',
- destination: to,
- },
- }, requestOptions), wait);
- };
- };
- const copyRules = (base) => {
- return (from, to, requestOptions) => {
- return copyIndex(base)(from, to, {
- ...requestOptions,
- scope: [ScopeEnum.Rules],
- });
- };
- };
- const copySettings = (base) => {
- return (from, to, requestOptions) => {
- return copyIndex(base)(from, to, {
- ...requestOptions,
- scope: [ScopeEnum.Settings],
- });
- };
- };
- const copySynonyms = (base) => {
- return (from, to, requestOptions) => {
- return copyIndex(base)(from, to, {
- ...requestOptions,
- scope: [ScopeEnum.Synonyms],
- });
- };
- };
- const customRequest = (base) => {
- return (request, requestOptions) => {
- if (request.method === MethodEnum.Get) {
- return base.transporter.read(request, requestOptions);
- }
- return base.transporter.write(request, requestOptions);
- };
- };
- const deleteApiKey = (base) => {
- return (apiKey, requestOptions) => {
- const wait = (_, waitRequestOptions) => {
- return createRetryablePromise(retry => {
- return getApiKey(base)(apiKey, waitRequestOptions)
- .then(retry)
- .catch((apiError) => {
- if (apiError.status !== 404) {
- throw apiError;
- }
- });
- });
- };
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Delete,
- path: encode('1/keys/%s', apiKey),
- }, requestOptions), wait);
- };
- };
- const deleteDictionaryEntries = (base) => {
- return (dictionary, objectIDs, requestOptions) => {
- const requests = objectIDs.map(objectID => ({
- action: 'deleteEntry',
- body: { objectID },
- }));
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('/1/dictionaries/%s/batch', dictionary),
- data: { clearExistingDictionaryEntries: false, requests },
- }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const generateSecuredApiKey = () => {
- return (parentApiKey, restrictions) => {
- const queryParameters = serializeQueryParameters(restrictions);
- const securedKey = createHmac('sha256', parentApiKey)
- .update(queryParameters)
- .digest('hex');
- return Buffer.from(securedKey + queryParameters).toString('base64');
- };
- };
- const getApiKey = (base) => {
- return (apiKey, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode('1/keys/%s', apiKey),
- }, requestOptions);
- };
- };
- const getAppTask = (base) => {
- return (taskID, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode('1/task/%s', taskID.toString()),
- }, requestOptions);
- };
- };
- const getDictionarySettings = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '/1/dictionaries/*/settings',
- }, requestOptions);
- };
- };
- const getLogs = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '1/logs',
- }, requestOptions);
- };
- };
- const getSecuredApiKeyRemainingValidity = () => {
- return (securedApiKey) => {
- const decodedString = Buffer.from(securedApiKey, 'base64').toString('ascii');
- const regex = /validUntil=(\d+)/;
- const match = decodedString.match(regex);
- if (match === null) {
- throw createValidUntilNotFoundError();
- }
- return parseInt(match[1], 10) - Math.round(new Date().getTime() / 1000);
- };
- };
- const getTopUserIDs = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '1/clusters/mapping/top',
- }, requestOptions);
- };
- };
- const getUserID = (base) => {
- return (userID, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode('1/clusters/mapping/%s', userID),
- }, requestOptions);
- };
- };
- const hasPendingMappings = (base) => {
- return (requestOptions) => {
- const { retrieveMappings, ...options } = requestOptions || {};
- if (retrieveMappings === true) {
- // eslint-disable-next-line functional/immutable-data
- options.getClusters = true;
- }
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '1/clusters/mapping/pending',
- }, options);
- };
- };
- const initIndex = (base) => {
- return (indexName, options = {}) => {
- const searchIndex = {
- transporter: base.transporter,
- appId: base.appId,
- indexName,
- };
- return addMethods(searchIndex, options.methods);
- };
- };
- const listApiKeys = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '1/keys',
- }, requestOptions);
- };
- };
- const listClusters = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '1/clusters',
- }, requestOptions);
- };
- };
- const listIndices = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '1/indexes',
- }, requestOptions);
- };
- };
- const listUserIDs = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: '1/clusters/mapping',
- }, requestOptions);
- };
- };
- const moveIndex = (base) => {
- return (from, to, requestOptions) => {
- const wait = (response, waitRequestOptions) => {
- return initIndex(base)(from, {
- methods: { waitTask },
- }).waitTask(response.taskID, waitRequestOptions);
- };
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/operation', from),
- data: {
- operation: 'move',
- destination: to,
- },
- }, requestOptions), wait);
- };
- };
- const multipleBatch = (base) => {
- return (requests, requestOptions) => {
- const wait = (response, waitRequestOptions) => {
- return Promise.all(Object.keys(response.taskID).map(indexName => {
- return initIndex(base)(indexName, {
- methods: { waitTask },
- }).waitTask(response.taskID[indexName], waitRequestOptions);
- }));
- };
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: '1/indexes/*/batch',
- data: {
- requests,
- },
- }, requestOptions), wait);
- };
- };
- const multipleGetObjects = (base) => {
- return (requests, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: '1/indexes/*/objects',
- data: {
- requests,
- },
- }, requestOptions);
- };
- };
- const multipleQueries = (base) => {
- return (queries, requestOptions) => {
- const requests = queries.map(query => {
- return {
- ...query,
- params: serializeQueryParameters(query.params || {}),
- };
- });
- return base.transporter.read({
- method: MethodEnum.Post,
- path: '1/indexes/*/queries',
- data: {
- requests,
- },
- cacheable: true,
- }, requestOptions);
- };
- };
- const multipleSearchForFacetValues = (base) => {
- return (queries, requestOptions) => {
- return Promise.all(queries.map(query => {
- const { facetName, facetQuery, ...params } = query.params;
- return initIndex(base)(query.indexName, {
- methods: { searchForFacetValues },
- }).searchForFacetValues(facetName, facetQuery, {
- ...requestOptions,
- ...params,
- });
- }));
- };
- };
- const removeUserID = (base) => {
- return (userID, requestOptions) => {
- const mappedRequestOptions = createMappedRequestOptions(requestOptions);
- // eslint-disable-next-line functional/immutable-data
- mappedRequestOptions.queryParameters['X-Algolia-User-ID'] = userID;
- return base.transporter.write({
- method: MethodEnum.Delete,
- path: '1/clusters/mapping',
- }, mappedRequestOptions);
- };
- };
- const replaceDictionaryEntries = (base) => {
- return (dictionary, entries, requestOptions) => {
- const requests = entries.map(entry => ({
- action: 'addEntry',
- body: entry,
- }));
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('/1/dictionaries/%s/batch', dictionary),
- data: { clearExistingDictionaryEntries: true, requests },
- }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const restoreApiKey = (base) => {
- return (apiKey, requestOptions) => {
- const wait = (_, waitRequestOptions) => {
- return createRetryablePromise(retry => {
- return getApiKey(base)(apiKey, waitRequestOptions).catch((apiError) => {
- if (apiError.status !== 404) {
- throw apiError;
- }
- return retry();
- });
- });
- };
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/keys/%s/restore', apiKey),
- }, requestOptions), wait);
- };
- };
- const saveDictionaryEntries = (base) => {
- return (dictionary, entries, requestOptions) => {
- const requests = entries.map(entry => ({
- action: 'addEntry',
- body: entry,
- }));
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('/1/dictionaries/%s/batch', dictionary),
- data: { clearExistingDictionaryEntries: false, requests },
- }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const searchDictionaryEntries = (base) => {
- return (dictionary, query, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: encode('/1/dictionaries/%s/search', dictionary),
- data: {
- query,
- },
- cacheable: true,
- }, requestOptions);
- };
- };
- const searchUserIDs = (base) => {
- return (query, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: '1/clusters/mapping/search',
- data: {
- query,
- },
- }, requestOptions);
- };
- };
- const setDictionarySettings = (base) => {
- return (settings, requestOptions) => {
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Put,
- path: '/1/dictionaries/*/settings',
- data: settings,
- }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const updateApiKey = (base) => {
- return (apiKey, requestOptions) => {
- const updatedFields = Object.assign({}, requestOptions);
- const { queryParameters, ...options } = requestOptions || {};
- const data = queryParameters ? { queryParameters } : {};
- const apiKeyFields = [
- 'acl',
- 'indexes',
- 'referers',
- 'restrictSources',
- 'queryParameters',
- 'description',
- 'maxQueriesPerIPPerHour',
- 'maxHitsPerQuery',
- ];
- const hasChanged = (getApiKeyResponse) => {
- return Object.keys(updatedFields)
- .filter((updatedField) => apiKeyFields.indexOf(updatedField) !== -1)
- .every(updatedField => {
- return getApiKeyResponse[updatedField] === updatedFields[updatedField];
- });
- };
- const wait = (_, waitRequestOptions) => createRetryablePromise(retry => {
- return getApiKey(base)(apiKey, waitRequestOptions).then(getApiKeyResponse => {
- return hasChanged(getApiKeyResponse) ? Promise.resolve() : retry();
- });
- });
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Put,
- path: encode('1/keys/%s', apiKey),
- data,
- }, options), wait);
- };
- };
- const waitAppTask = (base) => {
- return (taskID, requestOptions) => {
- return createRetryablePromise(retry => {
- return getAppTask(base)(taskID, requestOptions).then(response => {
- return response.status !== 'published' ? retry() : undefined;
- });
- });
- };
- };
- const batch = (base) => {
- return (requests, requestOptions) => {
- const wait = (response, waitRequestOptions) => {
- return waitTask(base)(response.taskID, waitRequestOptions);
- };
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/batch', base.indexName),
- data: {
- requests,
- },
- }, requestOptions), wait);
- };
- };
- const browseObjects = (base) => {
- return (requestOptions) => {
- return createBrowsablePromise({
- shouldStop: response => response.cursor === undefined,
- ...requestOptions,
- request: (data) => base.transporter.read({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/browse', base.indexName),
- data,
- }, requestOptions),
- });
- };
- };
- const browseRules = (base) => {
- return (requestOptions) => {
- const options = {
- hitsPerPage: 1000,
- ...requestOptions,
- };
- return createBrowsablePromise({
- shouldStop: response => response.hits.length < options.hitsPerPage,
- ...options,
- request(data) {
- return searchRules(base)('', { ...options, ...data }).then((response) => {
- return {
- ...response,
- hits: response.hits.map(rule => {
- // eslint-disable-next-line functional/immutable-data,no-param-reassign
- delete rule._highlightResult;
- return rule;
- }),
- };
- });
- },
- });
- };
- };
- const browseSynonyms = (base) => {
- return (requestOptions) => {
- const options = {
- hitsPerPage: 1000,
- ...requestOptions,
- };
- return createBrowsablePromise({
- shouldStop: response => response.hits.length < options.hitsPerPage,
- ...options,
- request(data) {
- return searchSynonyms(base)('', { ...options, ...data }).then((response) => {
- return {
- ...response,
- hits: response.hits.map(synonym => {
- // eslint-disable-next-line functional/immutable-data,no-param-reassign
- delete synonym._highlightResult;
- return synonym;
- }),
- };
- });
- },
- });
- };
- };
- const chunkedBatch = (base) => {
- return (bodies, action, requestOptions) => {
- const { batchSize, ...options } = requestOptions || {};
- const response = {
- taskIDs: [],
- objectIDs: [],
- };
- const forEachBatch = (lastIndex = 0) => {
- // eslint-disable-next-line functional/prefer-readonly-type
- const bodiesChunk = [];
- // eslint-disable-next-line functional/no-let
- let index;
- /* eslint-disable-next-line functional/no-loop-statement */
- for (index = lastIndex; index < bodies.length; index++) {
- // eslint-disable-next-line functional/immutable-data
- bodiesChunk.push(bodies[index]);
- if (bodiesChunk.length === (batchSize || 1000)) {
- break;
- }
- }
- if (bodiesChunk.length === 0) {
- return Promise.resolve(response);
- }
- return batch(base)(bodiesChunk.map(body => {
- return {
- action,
- body,
- };
- }), options).then(res => {
- response.objectIDs = response.objectIDs.concat(res.objectIDs); // eslint-disable-line functional/immutable-data
- response.taskIDs.push(res.taskID); // eslint-disable-line functional/immutable-data
- index++;
- return forEachBatch(index);
- });
- };
- return createWaitablePromise(forEachBatch(), (chunkedBatchResponse, waitRequestOptions) => {
- return Promise.all(chunkedBatchResponse.taskIDs.map(taskID => {
- return waitTask(base)(taskID, waitRequestOptions);
- }));
- });
- };
- };
- const clearObjects = (base) => {
- return (requestOptions) => {
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/clear', base.indexName),
- }, requestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const clearRules = (base) => {
- return (requestOptions) => {
- const { forwardToReplicas, ...options } = requestOptions || {};
- const mappedRequestOptions = createMappedRequestOptions(options);
- if (forwardToReplicas) {
- mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
- }
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/rules/clear', base.indexName),
- }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const clearSynonyms = (base) => {
- return (requestOptions) => {
- const { forwardToReplicas, ...options } = requestOptions || {};
- const mappedRequestOptions = createMappedRequestOptions(options);
- if (forwardToReplicas) {
- mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
- }
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/synonyms/clear', base.indexName),
- }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const deleteBy = (base) => {
- return (filters, requestOptions) => {
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/deleteByQuery', base.indexName),
- data: filters,
- }, requestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const deleteIndex = (base) => {
- return (requestOptions) => {
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Delete,
- path: encode('1/indexes/%s', base.indexName),
- }, requestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const deleteObject = (base) => {
- return (objectID, requestOptions) => {
- return createWaitablePromise(deleteObjects(base)([objectID], requestOptions).then(response => {
- return { taskID: response.taskIDs[0] };
- }), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const deleteObjects = (base) => {
- return (objectIDs, requestOptions) => {
- const objects = objectIDs.map(objectID => {
- return { objectID };
- });
- return chunkedBatch(base)(objects, BatchActionEnum.DeleteObject, requestOptions);
- };
- };
- const deleteRule = (base) => {
- return (objectID, requestOptions) => {
- const { forwardToReplicas, ...options } = requestOptions || {};
- const mappedRequestOptions = createMappedRequestOptions(options);
- if (forwardToReplicas) {
- mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
- }
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Delete,
- path: encode('1/indexes/%s/rules/%s', base.indexName, objectID),
- }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const deleteSynonym = (base) => {
- return (objectID, requestOptions) => {
- const { forwardToReplicas, ...options } = requestOptions || {};
- const mappedRequestOptions = createMappedRequestOptions(options);
- if (forwardToReplicas) {
- mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
- }
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Delete,
- path: encode('1/indexes/%s/synonyms/%s', base.indexName, objectID),
- }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const exists = (base) => {
- return (requestOptions) => {
- return getSettings(base)(requestOptions)
- .then(() => true)
- .catch(error => {
- if (error.status !== 404) {
- throw error;
- }
- return false;
- });
- };
- };
- const findAnswers = (base) => {
- return (query, queryLanguages, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: encode('1/answers/%s/prediction', base.indexName),
- data: {
- query,
- queryLanguages,
- },
- cacheable: true,
- }, requestOptions);
- };
- };
- const findObject = (base) => {
- return (callback, requestOptions) => {
- const { query, paginate, ...options } = requestOptions || {};
- // eslint-disable-next-line functional/no-let
- let page = 0;
- const forEachPage = () => {
- return search(base)(query || '', { ...options, page }).then(result => {
- // eslint-disable-next-line functional/no-loop-statement
- for (const [position, hit] of Object.entries(result.hits)) {
- // eslint-disable-next-line promise/no-callback-in-promise
- if (callback(hit)) {
- return {
- object: hit,
- position: parseInt(position, 10),
- page,
- };
- }
- }
- page++;
- // paginate if option was set and has next page
- if (paginate === false || page >= result.nbPages) {
- throw createObjectNotFoundError();
- }
- return forEachPage();
- });
- };
- return forEachPage();
- };
- };
- const getObject = (base) => {
- return (objectID, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode('1/indexes/%s/%s', base.indexName, objectID),
- }, requestOptions);
- };
- };
- const getObjectPosition = () => {
- return (searchResponse, objectID) => {
- // eslint-disable-next-line functional/no-loop-statement
- for (const [position, hit] of Object.entries(searchResponse.hits)) {
- if (hit.objectID === objectID) {
- return parseInt(position, 10);
- }
- }
- return -1;
- };
- };
- const getObjects = (base) => {
- return (objectIDs, requestOptions) => {
- const { attributesToRetrieve, ...options } = requestOptions || {};
- const requests = objectIDs.map(objectID => {
- return {
- indexName: base.indexName,
- objectID,
- ...(attributesToRetrieve ? { attributesToRetrieve } : {}),
- };
- });
- return base.transporter.read({
- method: MethodEnum.Post,
- path: '1/indexes/*/objects',
- data: {
- requests,
- },
- }, options);
- };
- };
- const getRule = (base) => {
- return (objectID, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode('1/indexes/%s/rules/%s', base.indexName, objectID),
- }, requestOptions);
- };
- };
- const getSettings = (base) => {
- return (requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode('1/indexes/%s/settings', base.indexName),
- data: {
- getVersion: 2,
- },
- }, requestOptions);
- };
- };
- const getSynonym = (base) => {
- return (objectID, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode(`1/indexes/%s/synonyms/%s`, base.indexName, objectID),
- }, requestOptions);
- };
- };
- const getTask = (base) => {
- return (taskID, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Get,
- path: encode('1/indexes/%s/task/%s', base.indexName, taskID.toString()),
- }, requestOptions);
- };
- };
- const partialUpdateObject = (base) => {
- return (object, requestOptions) => {
- return createWaitablePromise(partialUpdateObjects(base)([object], requestOptions).then(response => {
- return {
- objectID: response.objectIDs[0],
- taskID: response.taskIDs[0],
- };
- }), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const partialUpdateObjects = (base) => {
- return (objects, requestOptions) => {
- const { createIfNotExists, ...options } = requestOptions || {};
- const action = createIfNotExists
- ? BatchActionEnum.PartialUpdateObject
- : BatchActionEnum.PartialUpdateObjectNoCreate;
- return chunkedBatch(base)(objects, action, options);
- };
- };
- const replaceAllObjects = (base) => {
- return (objects, requestOptions) => {
- const { safe, autoGenerateObjectIDIfNotExist, batchSize, ...options } = requestOptions || {};
- const operation = (from, to, type, operationRequestOptions) => {
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/operation', from),
- data: {
- operation: type,
- destination: to,
- },
- }, operationRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- const randomSuffix = Math.random()
- .toString(36)
- .substring(7);
- const temporaryIndexName = `${base.indexName}_tmp_${randomSuffix}`;
- const saveObjectsInTemporary = saveObjects({
- appId: base.appId,
- transporter: base.transporter,
- indexName: temporaryIndexName,
- });
- // @ts-ignore
- // eslint-disable-next-line prefer-const, functional/no-let, functional/prefer-readonly-type
- let responses = [];
- const copyWaitablePromise = operation(base.indexName, temporaryIndexName, 'copy', {
- ...options,
- scope: ['settings', 'synonyms', 'rules'],
- });
- // eslint-disable-next-line functional/immutable-data
- responses.push(copyWaitablePromise);
- const result = (safe
- ? copyWaitablePromise.wait(options)
- : copyWaitablePromise)
- .then(() => {
- const saveObjectsWaitablePromise = saveObjectsInTemporary(objects, {
- ...options,
- autoGenerateObjectIDIfNotExist,
- batchSize,
- });
- // eslint-disable-next-line functional/immutable-data
- responses.push(saveObjectsWaitablePromise);
- return safe ? saveObjectsWaitablePromise.wait(options) : saveObjectsWaitablePromise;
- })
- .then(() => {
- const moveWaitablePromise = operation(temporaryIndexName, base.indexName, 'move', options);
- // eslint-disable-next-line functional/immutable-data
- responses.push(moveWaitablePromise);
- return safe ? moveWaitablePromise.wait(options) : moveWaitablePromise;
- })
- .then(() => Promise.all(responses))
- .then(([copyResponse, saveObjectsResponse, moveResponse]) => {
- return {
- objectIDs: saveObjectsResponse.objectIDs,
- taskIDs: [copyResponse.taskID, ...saveObjectsResponse.taskIDs, moveResponse.taskID],
- };
- });
- return createWaitablePromise(result, (_, waitRequestOptions) => {
- return Promise.all(responses.map(response => response.wait(waitRequestOptions)));
- });
- };
- };
- const replaceAllRules = (base) => {
- return (rules, requestOptions) => {
- return saveRules(base)(rules, {
- ...requestOptions,
- clearExistingRules: true,
- });
- };
- };
- const replaceAllSynonyms = (base) => {
- return (synonyms, requestOptions) => {
- return saveSynonyms(base)(synonyms, {
- ...requestOptions,
- clearExistingSynonyms: true,
- });
- };
- };
- const saveObject = (base) => {
- return (object, requestOptions) => {
- return createWaitablePromise(saveObjects(base)([object], requestOptions).then(response => {
- return {
- objectID: response.objectIDs[0],
- taskID: response.taskIDs[0],
- };
- }), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const saveObjects = (base) => {
- return (objects, requestOptions) => {
- const { autoGenerateObjectIDIfNotExist, ...options } = requestOptions || {};
- const action = autoGenerateObjectIDIfNotExist
- ? BatchActionEnum.AddObject
- : BatchActionEnum.UpdateObject;
- if (action === BatchActionEnum.UpdateObject) {
- // eslint-disable-next-line functional/no-loop-statement
- for (const object of objects) {
- if (object.objectID === undefined) {
- return createWaitablePromise(Promise.reject(createMissingObjectIDError()));
- }
- }
- }
- return chunkedBatch(base)(objects, action, options);
- };
- };
- const saveRule = (base) => {
- return (rule, requestOptions) => {
- return saveRules(base)([rule], requestOptions);
- };
- };
- const saveRules = (base) => {
- return (rules, requestOptions) => {
- const { forwardToReplicas, clearExistingRules, ...options } = requestOptions || {};
- const mappedRequestOptions = createMappedRequestOptions(options);
- if (forwardToReplicas) {
- mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
- }
- if (clearExistingRules) {
- mappedRequestOptions.queryParameters.clearExistingRules = 1; // eslint-disable-line functional/immutable-data
- }
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/rules/batch', base.indexName),
- data: rules,
- }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const saveSynonym = (base) => {
- return (synonym, requestOptions) => {
- return saveSynonyms(base)([synonym], requestOptions);
- };
- };
- const saveSynonyms = (base) => {
- return (synonyms, requestOptions) => {
- const { forwardToReplicas, clearExistingSynonyms, replaceExistingSynonyms, ...options } = requestOptions || {};
- const mappedRequestOptions = createMappedRequestOptions(options);
- if (forwardToReplicas) {
- mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
- }
- if (replaceExistingSynonyms || clearExistingSynonyms) {
- mappedRequestOptions.queryParameters.replaceExistingSynonyms = 1; // eslint-disable-line functional/immutable-data
- }
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/synonyms/batch', base.indexName),
- data: synonyms,
- }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const search = (base) => {
- return (query, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/query', base.indexName),
- data: {
- query,
- },
- cacheable: true,
- }, requestOptions);
- };
- };
- const searchForFacetValues = (base) => {
- return (facetName, facetQuery, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/facets/%s/query', base.indexName, facetName),
- data: {
- facetQuery,
- },
- cacheable: true,
- }, requestOptions);
- };
- };
- const searchRules = (base) => {
- return (query, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/rules/search', base.indexName),
- data: {
- query,
- },
- }, requestOptions);
- };
- };
- const searchSynonyms = (base) => {
- return (query, requestOptions) => {
- return base.transporter.read({
- method: MethodEnum.Post,
- path: encode('1/indexes/%s/synonyms/search', base.indexName),
- data: {
- query,
- },
- }, requestOptions);
- };
- };
- const setSettings = (base) => {
- return (settings, requestOptions) => {
- const { forwardToReplicas, ...options } = requestOptions || {};
- const mappedRequestOptions = createMappedRequestOptions(options);
- if (forwardToReplicas) {
- mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
- }
- return createWaitablePromise(base.transporter.write({
- method: MethodEnum.Put,
- path: encode('1/indexes/%s/settings', base.indexName),
- data: settings,
- }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
- };
- };
- const waitTask = (base) => {
- return (taskID, requestOptions) => {
- return createRetryablePromise(retry => {
- return getTask(base)(taskID, requestOptions).then(response => {
- return response.status !== 'published' ? retry() : undefined;
- });
- });
- };
- };
- const ApiKeyACLEnum = {
- AddObject: 'addObject',
- Analytics: 'analytics',
- Browser: 'browse',
- DeleteIndex: 'deleteIndex',
- DeleteObject: 'deleteObject',
- EditSettings: 'editSettings',
- ListIndexes: 'listIndexes',
- Logs: 'logs',
- Personalization: 'personalization',
- Recommendation: 'recommendation',
- Search: 'search',
- SeeUnretrievableAttributes: 'seeUnretrievableAttributes',
- Settings: 'settings',
- Usage: 'usage',
- };
- const BatchActionEnum = {
- AddObject: 'addObject',
- UpdateObject: 'updateObject',
- PartialUpdateObject: 'partialUpdateObject',
- PartialUpdateObjectNoCreate: 'partialUpdateObjectNoCreate',
- DeleteObject: 'deleteObject',
- DeleteIndex: 'delete',
- ClearIndex: 'clear',
- };
- const ScopeEnum = {
- Settings: 'settings',
- Synonyms: 'synonyms',
- Rules: 'rules',
- };
- const StrategyEnum = {
- None: 'none',
- StopIfEnoughMatches: 'stopIfEnoughMatches',
- };
- const SynonymEnum = {
- Synonym: 'synonym',
- OneWaySynonym: 'oneWaySynonym',
- AltCorrection1: 'altCorrection1',
- AltCorrection2: 'altCorrection2',
- Placeholder: 'placeholder',
- };
- export { ApiKeyACLEnum, BatchActionEnum, ScopeEnum, StrategyEnum, SynonymEnum, addApiKey, assignUserID, assignUserIDs, batch, browseObjects, browseRules, browseSynonyms, chunkedBatch, clearDictionaryEntries, clearObjects, clearRules, clearSynonyms, copyIndex, copyRules, copySettings, copySynonyms, createBrowsablePromise, createMissingObjectIDError, createObjectNotFoundError, createSearchClient, createValidUntilNotFoundError, customRequest, deleteApiKey, deleteBy, deleteDictionaryEntries, deleteIndex, deleteObject, deleteObjects, deleteRule, deleteSynonym, exists, findAnswers, findObject, generateSecuredApiKey, getApiKey, getAppTask, getDictionarySettings, getLogs, getObject, getObjectPosition, getObjects, getRule, getSecuredApiKeyRemainingValidity, getSettings, getSynonym, getTask, getTopUserIDs, getUserID, hasPendingMappings, initIndex, listApiKeys, listClusters, listIndices, listUserIDs, moveIndex, multipleBatch, multipleGetObjects, multipleQueries, multipleSearchForFacetValues, partialUpdateObject, partialUpdateObjects, removeUserID, replaceAllObjects, replaceAllRules, replaceAllSynonyms, replaceDictionaryEntries, restoreApiKey, saveDictionaryEntries, saveObject, saveObjects, saveRule, saveRules, saveSynonym, saveSynonyms, search, searchDictionaryEntries, searchForFacetValues, searchRules, searchSynonyms, searchUserIDs, setDictionarySettings, setSettings, updateApiKey, waitAppTask, waitTask };
|