{"version":3,"sources":["../src/cache.ts","../src/api.ts","../src/request_builder.ts","../src/query_builder.ts","../src/client.ts","../src/utils.ts","../src/index.ts"],"names":["Cache","ttl","method","url","params","key","cached","value","API","apiKey","endpoint","path","options","__spreadValues","body","cacheParams","__spreadProps","cachedQueryResult","response","err","result","_a","_b","_c","errorMessage","fetchError","__async","error","TermsAggregation","facetConfiguration","StatsAggregation","RequestBuilder","facetsConfiguration","facetFilters","filter","sort","requests","facetName","acc","facetNames","initialRequest","aggs","aggregation","filters","facetFilter","transformResponse","results","facetConfigurations","combinedAggregations","facets","buckets","bucket","min","max","avg","sum","count","userSpecifiedAggs","aggregationKey","QueryBuilder","apiClient","baseParams","rest","__objRest","field","parameter","query","request","data","Client","applicationName","apiOptions","Highlight","hit","highlightValue","throwParamRequiredError","param","SearchApplicationClient","client"],"mappings":"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","sourcesContent":["const ONE_HOUR = 1000 * 60 * 60\nexport class Cache {\n  private cache: Record<string, any> = {}\n\n  constructor(private readonly ttl: number = ONE_HOUR) {}\n\n  private createKeyByRequestParams(method, url, params: Record<string, any>) {\n    return method + url + JSON.stringify(params)\n  }\n\n  getByRequestParams(method, url, params: Record<string, any>) {\n    const key = this.createKeyByRequestParams(method, url, params)\n\n    return this.get(key)\n  }\n\n  get(key: string) {\n    const cached = this.cache[key]\n\n    if (!cached) return null\n\n    if (cached.expiration < Date.now()) {\n      delete this.cache[key]\n\n      return null\n    }\n\n    return cached.value\n  }\n\n  set(key: string, value: any) {\n    this.cache[key] = {\n      value,\n      expiration: Date.now() + this.ttl,\n    }\n  }\n\n  setByRequestParams(\n    method: 'POST' | 'GET',\n    url: string,\n    params: Record<string, any>,\n    value: any\n  ) {\n    const key = this.createKeyByRequestParams(method, url, params)\n    this.set(key, value)\n  }\n}\n","import { Cache } from './cache'\nimport { RequestParams, ResponseParams } from './types'\nimport { ErrorResponseBase } from '@elastic/elasticsearch/lib/api/types'\n\ninterface NetworkError extends Error {\n  isNetworkError: boolean\n}\ninterface FetchError extends Error {\n  isFetchError: boolean\n  data: ErrorResponseBase\n}\n\nexport interface Options {\n  cacheExpiration?: number\n  cache?: boolean\n  headers?: HeadersInit\n}\n\nexport class API {\n  private readonly options: Options\n  private readonly cacheService\n  constructor(\n    private readonly apiKey: string,\n    private readonly endpoint: string,\n    private readonly path: string,\n    options: Options = {\n      cache: true,\n      headers: {},\n    }\n  ) {\n    this.cacheService = new Cache(options.cacheExpiration)\n    this.options = { cache: true, ...options }\n  }\n\n  private request<R extends ResponseParams = ResponseParams>(\n    method: 'POST' | 'GET',\n    url: string,\n    body?: { params: RequestParams }\n  ): Promise<R> {\n    const cacheParams = {\n      ...body,\n      apiKey: this.apiKey,\n      endpoint: this.endpoint,\n    }\n    const cachedQueryResult =\n      this.options.cache &&\n      this.cacheService.getByRequestParams(method, url, cacheParams)\n\n    if (cachedQueryResult) {\n      return Promise.resolve(cachedQueryResult)\n    }\n\n    return fetch(url, {\n      method,\n      headers: {\n        ...this.options.headers,\n        'Content-Type': 'application/json',\n        Authorization: `Apikey ${this.apiKey}`,\n      },\n      body: body ? JSON.stringify(body) : undefined,\n    })\n      .then(\n        (response) => response.json(),\n        (err) => {\n          err.isNetworkError = true\n\n          throw err\n        }\n      )\n      .then((result) => {\n        if (result.error) {\n          const errorMessage =\n            (result as ErrorResponseBase)?.error?.reason ||\n            (result as ErrorResponseBase)?.error?.caused_by?.reason\n          const fetchError = new Error(errorMessage) as FetchError\n          fetchError.isFetchError = true\n          fetchError.data = result\n\n          throw fetchError\n        }\n\n        if (this.options.cache) {\n          this.cacheService.setByRequestParams(method, url, cacheParams, result)\n        }\n\n        return result\n      })\n      .catch(this.handleError)\n  }\n\n  async post<R extends ResponseParams = ResponseParams>(body: {\n    params: RequestParams\n  }) {\n    return await this.request<R>('POST', `${this.endpoint}${this.path}`, body)\n  }\n\n  private handleError(error: Error): void {\n    if ((error as NetworkError).isNetworkError) {\n      error.name = '[Network Error]'\n    } else if (\n      (error as FetchError).isFetchError &&\n      (error as FetchError).data.status === 500 &&\n      ((error as FetchError).data.error?.caused_by?.type.includes(\n        'format_exception'\n      ) ||\n        (error as FetchError).data.error.type === 'json_parse_exception')\n    ) {\n      error.name = '[Parameter or type is invalid]'\n    } else if (\n      (error as FetchError).isFetchError &&\n      (error as FetchError).data.status === 401\n    ) {\n      error.name = '[Authorization Error]'\n    } else if (\n      (error as FetchError).isFetchError &&\n      (error as FetchError).data.status === 404\n    ) {\n      error.name = '[Not Found Error]'\n      error.message = `${(error as FetchError).data.error.type}: ${\n        error.message\n      }`\n    }\n\n    console.error(error)\n  }\n}\n","import {\n  Aggregations,\n  FacetFilters,\n  Params,\n  Query,\n  RequestParams,\n  SortFields,\n} from './types'\n\ninterface BaseFacetConfiguration {\n  type: 'terms' | 'stats'\n  field: string\n  disjunctive?: boolean\n}\n\ninterface TermsFacetConfiguration extends BaseFacetConfiguration {\n  type: 'terms'\n  size: number\n}\n\ninterface StatsFacetConfiguration extends BaseFacetConfiguration {\n  type: 'stats'\n}\n\nexport type FacetConfiguration =\n  | TermsFacetConfiguration\n  | StatsFacetConfiguration\n\ninterface FacetsConfiguration {\n  [facetName: string]: FacetConfiguration\n}\n\nconst TermsAggregation = (\n  facetConfiguration: TermsFacetConfiguration\n): Pick<Aggregations, 'terms'> => ({\n  terms: {\n    field: facetConfiguration.field,\n    size: facetConfiguration.size,\n  },\n})\n\nconst StatsAggregation = (\n  facetConfiguration: StatsFacetConfiguration\n): Pick<Aggregations, 'stats'> => ({\n  stats: {\n    field: facetConfiguration.field,\n  },\n})\n\nexport class RequestBuilder {\n  constructor(\n    private readonly facetsConfiguration: FacetsConfiguration,\n    private readonly facetFilters: FacetFilters,\n    private readonly filter: Query,\n    private readonly sort: SortFields,\n    private readonly params: Params\n  ) {}\n\n  build(): RequestParams[] {\n    const facetRequests = Object.keys(this.facetsConfiguration).reduce<\n      string[][]\n    >(\n      (requests, facetName) => {\n        const facetConfiguration = this.facetsConfiguration[facetName]\n        if (\n          facetConfiguration.disjunctive &&\n          this.facetFilters[facetName]?.length > 0\n        ) {\n          requests.push([facetName])\n          return requests\n        }\n        requests[0].push(facetName)\n        return requests\n      },\n      [[]]\n    )\n\n    return facetRequests.reduce<RequestParams[]>((acc, facetNames, i) => {\n      const initialRequest = i === 0\n\n      const aggs = facetNames.reduce<Record<string, Aggregations>>(\n        (acc, facetName) => {\n          const facetConfiguration = this.facetsConfiguration[facetName]\n\n          const aggregation =\n            facetConfiguration.type === 'terms'\n              ? TermsAggregation(facetConfiguration)\n              : StatsAggregation(facetConfiguration)\n\n          return {\n            ...acc,\n            [`${facetName}_facet`]: aggregation,\n          }\n        },\n        {}\n      )\n\n      const filters = Object.keys(this.facetsConfiguration).reduce(\n        (acc, facetName) => {\n          const facetConfiguration = this.facetsConfiguration[facetName]\n          const facetFilter = this.facetFilters[facetName] || []\n\n          if (facetFilter.length === 0) return acc\n          if (facetConfiguration.disjunctive && !initialRequest) return acc\n\n          return [\n            ...acc,\n            {\n              [facetConfiguration.type === 'terms' ? 'terms' : 'range']: {\n                [facetConfiguration.field]: facetFilter,\n              },\n            },\n          ]\n        },\n        []\n      )\n\n      acc.push({\n        _es_aggs: aggs,\n        _es_filters: {\n          bool: {\n            must: [...(this.filter ? [this.filter] : []), ...filters],\n          },\n        },\n        ...(this.sort ? { _es_sort_fields: this.sort } : {}),\n        ...this.params,\n        ...(initialRequest ? {} : { size: 0, from: 0 }),\n      })\n      return acc\n    }, [])\n  }\n}\n","import { API } from './api'\nimport { FacetConfiguration, RequestBuilder } from './request_builder'\nimport type {\n  FilterFieldValue,\n  Params,\n  Query,\n  SortFields,\n  ResponseParams,\n  ResponseTermsAggregation,\n  ResponseStatsAggregation,\n  ResponseFacets,\n} from './types'\n\nconst transformResponse = <T extends ResponseParams = ResponseParams>(\n  results: T[],\n  facetConfigurations: Record<string, FacetConfiguration>\n): T & { facets?: ResponseFacets[] } => {\n  const combinedAggregations = results.reduce((acc, result) => {\n    return {\n      ...acc,\n      ...result.aggregations,\n    }\n  }, {})\n\n  const facets = Object.keys(combinedAggregations).reduce<ResponseFacets[]>(\n    (facets, facetName) => {\n      const key = facetName.replace('_facet', '')\n      const facetConfiguration = facetConfigurations[key]\n      if (!facetConfiguration) return facets\n\n      const aggregation = combinedAggregations[facetName]\n      if (facetConfiguration.type === 'terms') {\n        const { buckets } = aggregation as ResponseTermsAggregation\n\n        return [\n          ...facets,\n          {\n            name: key,\n            entries: (Array.isArray(buckets)\n              ? buckets\n              : Object.values(buckets)\n            ).map((bucket) => {\n              return {\n                value: bucket.key,\n                count: bucket.doc_count,\n              }\n            }),\n          },\n        ]\n      } else if (facetConfiguration.type === 'stats') {\n        const { min, max, avg, sum, count } =\n          aggregation as ResponseStatsAggregation\n\n        return [\n          ...facets,\n          {\n            name: key,\n            stats: {\n              min,\n              max,\n              avg,\n              sum,\n              count,\n            },\n          },\n        ]\n      }\n    },\n    []\n  )\n\n  const userSpecifiedAggs = Object.keys(results[0]?.aggregations || {}).reduce(\n    (acc, aggregationKey) => {\n      if (!facetConfigurations[aggregationKey.replace('_facet', '')]) {\n        return {\n          ...acc,\n          [aggregationKey]: results[0].aggregations[aggregationKey],\n        }\n      }\n      return acc\n    },\n    {}\n  )\n\n  return {\n    ...results[0],\n    aggregations: userSpecifiedAggs,\n    facets,\n  }\n}\n\nexport class QueryBuilder {\n  readonly facets: Record<string, FacetConfiguration> = {}\n  facetFilters: Record<string, FilterFieldValue[]> = {}\n  sort: SortFields\n  filter: Query\n  params: Params = {}\n\n  constructor(\n    private readonly apiClient: API,\n    baseParams: {\n      facets?: Record<string, FacetConfiguration>\n    } & Params = {}\n  ) {\n    const { facets, ...rest } = baseParams\n    this.facets = facets || {}\n    this.params = rest\n  }\n\n  /**\n   * @public\n   * @param {string} field\n   * @param {string | Array.string | Object} value\n   * @returns {QueryBuilder}\n   */\n  addFacetFilter(field: string, value: FilterFieldValue): this {\n    const facetInfo = this.facets?.[field]\n\n    if (!facetInfo) {\n      throw new Error(`Facet ${field} wasn't passed in configuration params`)\n    }\n\n    this.facetFilters[field] = [\n      ...(this.facetFilters[field] || []),\n      Array.isArray(value) ? value : [value],\n    ].flat()\n\n    return this\n  }\n\n  /**\n   * @public\n   * @param {string} parameter\n   * @param {*} value\n   * @returns {QueryBuilder}\n   */\n  addParameter(parameter: keyof Params, value: Params[keyof Params]): this {\n    this.params[parameter] = value\n\n    return this\n  }\n\n  /**\n   * @public\n   * @param {string} query\n   * @returns {QueryBuilder}\n   */\n  query(query: string): this {\n    return this.addParameter('query', query)\n  }\n\n  /**\n   * @async\n   * @public - returns search results\n   * @returns {Promise.<Array.<Object>>}\n   */\n  async search<Result = unknown>() {\n    const requests = new RequestBuilder(\n      this.facets,\n      this.facetFilters,\n      this.filter,\n      this.sort,\n      this.params\n    ).build()\n\n    const results = (\n      await Promise.all(\n        requests.map((request) =>\n          this.apiClient.post<ResponseParams<Result>>({ params: request })\n        )\n      )\n    ).filter((data) => !!data)\n\n    return transformResponse<ResponseParams<Result>>(results, this.facets)\n  }\n\n  /**\n   * @public\n   * @param {Object} value\n   * @returns {QueryBuilder}\n   */\n  setFilter(value: Query): this {\n    this.filter = value\n    return this\n  }\n\n  /**\n   * @public\n   * @param {number} value\n   * @returns {QueryBuilder}\n   */\n  setFrom(value: Params['from']): this {\n    return this.addParameter('from', value)\n  }\n\n  /**\n   * @public\n   * @param {number} value\n   * @returns {QueryBuilder}\n   */\n  setPageSize(value: Params['size']): this {\n    return this.addParameter('size', value)\n  }\n\n  /**\n   * @public\n   * @param {Array.<Object<string, 'desc' | 'asc'>|'_score'>} sort\n   * @returns {QueryBuilder}\n   */\n  setSort(sort: SortFields): this {\n    this.sort = sort\n\n    return this\n  }\n}\n","import { API, Options } from './api'\nimport { QueryBuilder } from './query_builder'\n\nexport class Client {\n  private readonly apiClient: API\n  private readonly baseParams: Record<string, any>\n\n  constructor({\n    applicationName,\n    endpoint,\n    apiKey,\n    baseParams,\n    apiOptions,\n  }: {\n    applicationName: string\n    endpoint: string\n    apiKey: string\n    baseParams?: Record<string, any>\n    apiOptions?: Options\n  }) {\n    this.baseParams = baseParams || {}\n    this.apiClient = new API(\n      apiKey,\n      endpoint,\n      `/_application/search_application/${applicationName}/_search`,\n      apiOptions\n    )\n  }\n\n  /**\n   * @public\n   * @returns {QueryBuilder} - returns QueryBuilder instance\n   */\n  initQuery() {\n    return new QueryBuilder(this.apiClient, this.baseParams)\n  }\n}\n","import { ResponseParams } from './types'\n\nexport const Highlight = (\n  hit: ResponseParams['hits']['hits'][0],\n  field: string\n) => {\n  const highlightValue = hit.highlight?.[field]\n\n  return highlightValue?.length\n    ? highlightValue.join('...')\n    : hit['_source'][field]\n}\n","import { Options } from './api'\nimport { Client } from './client'\nimport { QueryBuilder } from './query_builder'\n\nconst throwParamRequiredError = (param: string) => {\n  throw new Error(`${param} is required`)\n}\n\n/**\n * @function SearchApplicationClient\n * @param {string} applicationName\n * @param {string} endpoint\n * @param {string} apiKey\n * @param {Object} params\n * @param {Object} apiOptions\n * @returns {function(): QueryBuilder}\n */\nexport default function SearchApplicationClient(\n  applicationName: string,\n  endpoint: string,\n  apiKey: string,\n  params?: Record<string, any>,\n  apiOptions?: Options\n): () => QueryBuilder {\n  if (!applicationName) throwParamRequiredError('applicationName')\n  if (!endpoint) throwParamRequiredError('endpoint')\n  if (!apiKey) throwParamRequiredError('apiKey')\n\n  const client = new Client({\n    applicationName,\n    endpoint,\n    apiKey,\n    baseParams: params,\n    apiOptions,\n  })\n\n  return () => client.initQuery()\n}\n\nexport * from './utils'\n"]}