{"version":3,"file":"call-list.mjs","sources":["../../../../../src/core/actions/v2/call-list.ts"],"sourcesContent":["import type { ActionOptions } from '../abstract-action'\nimport type { TypeCallParams } from '../../../types/http'\nimport type { AjaxResult } from '../../http/ajax-result'\nimport { AbstractAction } from '../abstract-action'\nimport { Result } from '../../result'\n\nexport type ActionCallListV2 = ActionOptions & {\n  method: string\n  params?: Omit<TypeCallParams, 'start' | 'order'>\n  idKey?: string\n  cursorIdKey?: string\n  customKeyForResult?: string\n  requestId?: string\n}\n\n/**\n * Fast data retrieval without counting the total number of records. `restApi:v2`\n *\n * @todo add docs\n */\nexport class CallListV2 extends AbstractAction {\n  /**\n   * Fast data retrieval without counting the total number of records.\n   *\n   * @template T - The type of the elements of the returned array (default is `unknown`).\n   *\n   * @param {ActionCallListV2} options - parameters for executing the request.\n   *     - `method: string` - The name of the REST API method that returns a list of data (for example: `crm.item.list`, `tasks.task.list`)\n   *     - `params?: Omit<TypeCallParams, 'start' | 'order'>` - Request parameters, excluding the `start` and `order` parameters,\n   *         since the method is designed to obtain all data in one call.\n   *         Note: Use `filter`, `order`, and `select` to control the selection.\n   *     - `idKey?: string` - The name of the id field as it appears in each RESPONSE item; its value\n   *         drives the cursor. Default is 'ID' (uppercase). For methods that return a lowercase /\n   *         camelCase id (for example `tasks.task.list` returns `id`), set `idKey: 'id'`.\n   *     - `cursorIdKey?: string` - The field name used in the REQUEST for `order` and the `>` page\n   *         filter. Defaults to `idKey`. Set it only when the sortable / filterable field name differs\n   *         from the response field name — e.g. `tasks.task.list` sorts and filters by `ID` (uppercase)\n   *         but returns `id` (lowercase): pass `idKey: 'id', cursorIdKey: 'ID'`.\n   *     - `customKeyForResult?: string` - A custom key indicating that the response REST API will be\n   *        grouped by this field.\n   *        Example: `items` to group a list of CRM items.\n   *    - `requestId?: string` - Unique request identifier for tracking. Used for query deduplication and debugging.\n   *\n   * @returns {Promise<Result<T[]>>} A promise that resolves to the result of an REST API call.\n   *\n   * @example\n   * import { EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk'\n   *\n   * interface CrmItem { id: number, title: string }\n   * const sixMonthAgo = new Date()\n   * sixMonthAgo.setMonth((new Date()).getMonth() - 6)\n   * sixMonthAgo.setHours(0, 0, 0)\n   * const response = await b24.actions.v2.callList.make<CrmItem>({\n   *   method: 'crm.item.list',\n   *   params: {\n   *     entityTypeId:  EnumCrmEntityTypeId.company,\n   *     filter: {\n   *       '=%title': 'A%',\n   *       '>=createdTime': Text.toB24Format(sixMonthAgo) // created at least 6 months ago\n   *     },\n   *     select: ['id', 'title']\n   *   },\n   *   idKey: 'id',\n   *   customKeyForResult: 'items',\n   *   requestId: 'list-123'\n   * })\n   * if (!response.isSuccess) {\n   *   throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`)\n   * }\n   * const list = response.getData()\n   * console.log(`Result: ${list?.length}`) // Number of items received\n   */\n  public override async make<T = unknown>(options: ActionCallListV2): Promise<Result<T[]>> {\n    const batchSize = 50\n    const result: Result<T[]> = new Result()\n\n    const idKey = options?.idKey ?? 'ID'\n    const cursorIdKey = options?.cursorIdKey ?? idKey\n    const customKeyForResult = options?.customKeyForResult ?? null\n    const params = options?.params ?? {}\n\n    // Warn and strip user-provided `order` — cursor pagination requires ordering by cursorIdKey only\n    if ('order' in params && params['order']) {\n      this._logger.warning('callList.make: user-provided `order` parameter is ignored because cursor-based pagination requires ordering by cursorIdKey. Use `filter` to narrow results instead.')\n    }\n\n    const moreIdKey = `>${cursorIdKey}`\n    const { order: _ignoredOrder, ...restParams } = params as TypeCallParams\n    const requestParams: TypeCallParams = {\n      ...restParams,\n      order: { [cursorIdKey]: 'ASC' },\n      filter: { ...(params['filter'] || {}), [moreIdKey]: 0 },\n      start: -1\n    }\n\n    let allItems: T[] = []\n    let isContinue = true\n\n    do {\n      const response: AjaxResult<T> = await this._b24.actions.v2.call.make<T>({\n        method: options.method,\n        params: requestParams,\n        requestId: options.requestId\n      })\n\n      if (!response.isSuccess) {\n        this._logger.error('callFastListMethod', {\n          method: options.method,\n          requestId: options.requestId,\n          messages: response.getErrorMessages()\n        })\n        for (const [index, error] of response.errors) {\n          result.addError(error, index)\n        }\n        isContinue = false\n        break\n      }\n      const responseData = response.getData()\n      if (!responseData) {\n        isContinue = false\n        break\n      }\n\n      let resultData: T[] = []\n      if (null === customKeyForResult) {\n        resultData = responseData.result as T[]\n      } else {\n        resultData = (responseData.result as any)[customKeyForResult] as T[]\n      }\n\n      if (resultData.length === 0) {\n        isContinue = false\n        break\n      }\n\n      allItems = [...allItems, ...resultData]\n\n      if (resultData.length < batchSize) {\n        isContinue = false\n        break\n      }\n\n      // Update the filter for the next iteration\n      const lastItem = resultData[resultData.length - 1] as Record<string, any>\n      const cursorValue = lastItem ? Number.parseInt(lastItem[idKey], 10) : Number.NaN\n      if (Number.isFinite(cursorValue)) {\n        requestParams.filter[moreIdKey] = cursorValue\n      } else {\n        // A full page came back, yet no usable numeric cursor id could be read from\n        // its items via `idKey` — almost always an `idKey` that doesn't match the\n        // response field (e.g. a request that sorts by `ID` while the response\n        // carries a lowercase `id`). Without a cursor we can't advance, so stop and\n        // tell the caller how to fix it instead of silently truncating.\n        this._logger.warning(`callList.make: pagination stops here — no numeric id could be read from the returned items via idKey \"${idKey}\". Make sure idKey matches the id field in the response; if the sortable field name differs from it, also set cursorIdKey (e.g. idKey: 'id', cursorIdKey: 'ID').`)\n        isContinue = false\n        break\n      }\n    } while (isContinue)\n\n    return result.setData(allItems)\n  }\n}\n"],"names":[],"mappings":"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"}