{"version":3,"file":"fetch-list.mjs","sources":["../../../../../src/core/actions/v3/fetch-list.ts"],"sourcesContent":["import type { ActionOptions } from '../abstract-action'\nimport type { TypeCallParams } from '../../../types/http'\nimport { AbstractAction } from '../abstract-action'\nimport { SdkError } from '../../sdk-error'\nimport { keysetPaginate, KeysetPaginationError } from './_keyset-paginate'\n\nexport type ActionFetchListV3 = ActionOptions & {\n  method: string\n  params?: Omit<TypeCallParams, 'pagination' | 'order'>\n  idKey?: string\n  cursorIdKey?: string\n  customKeyForResult: string\n  requestId?: string\n  limit?: number\n}\n\n/**\n * Calls a REST API list method and returns an async generator for efficient large data retrieval. `restApi:v3`\n *\n * @todo add docs\n */\nexport class FetchListV3 extends AbstractAction {\n  /**\n   * Calls a REST API list method and returns an async generator for efficient large data retrieval.\n   * Implements the fast algorithm for iterating over large datasets without loading all data into memory at once.\n   *\n   * @template T - The type of items in the returned arrays (default is `unknown`).\n   *\n   * @param {ActionFetchListV3} 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, 'pagination' | 'order'>` - Request parameters, excluding the `pagination` 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'. Set it to match the id field the method returns.\n   *     - `cursorIdKey?: string` - The field name used in the REQUEST for `order` and the\n   *         `[field, '>', n]` page filter. Defaults to `idKey`. Set it only when the sortable /\n   *         filterable field name differs from the response field name (e.g. an uppercase request\n   *         field but a lowercase response id): 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   *    - `limit?: number` - How many records to retrieve at a time. Default is `50`. Maximum is `1000`.\n   *\n   * @returns {AsyncGenerator<T[]>} An async generator that yields chunks of data as arrays of type `T`.\n   *     Each iteration returns the next page/batch of results until all data is fetched.\n   *\n   * @example\n   * import { Text } from '@bitrix24/b24jssdk'\n   *\n   * interface MainEventLogItem { id: number, userId: number }\n   * const sixMonthAgo = new Date()\n   * sixMonthAgo.setMonth((new Date()).getMonth() - 6)\n   * sixMonthAgo.setHours(0, 0, 0)\n   * const generator = b24.actions.v3.fetchList.make<MainEventLogItem>({\n   *   method: 'main.eventlog.list',\n   *   params: {\n   *     filter: [\n   *      ['timestampX', '>=', Text.toB24Format(sixMonthAgo)] // created at least 6 months ago\n   *     ],\n   *     select: ['id', 'userId']\n   *   },\n   *   idKey: 'id',\n   *   customKeyForResult: 'items',\n   *   requestId: 'eventlog-123',\n   *   limit: 60\n   * })\n   *\n   * for await (const chunk of generator) {\n   *   // Process chunk (e.g., save to database, analyze, etc.)\n   *   console.log(`Processing ${chunk.length} items`)\n   * }\n   */\n  public override async* make<T = unknown>(options: ActionFetchListV3): AsyncGenerator<T[]> {\n    const batchSize = options?.limit ?? 50\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('fetchList.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 { order: _ignoredOrder, ...restParams } = params as TypeCallParams\n    const requestParams: TypeCallParams = {\n      ...restParams,\n      order: { [cursorIdKey]: 'ASC' },\n      filter: [...(params['filter'] || [])],\n      pagination: { page: 0, limit: batchSize }\n    }\n\n    try {\n      yield* keysetPaginate<T>(this._b24, this._logger, {\n        method: options.method,\n        requestId: options.requestId,\n        customKeyForResult,\n        initialCursor: 0,\n        // Emulated keyset: append the `[cursorIdKey, '>', cursor]` page filter.\n        buildParams: cursor => ({ ...requestParams, filter: [...requestParams.filter, [cursorIdKey, '>', cursor]] }),\n        // Advance by the numeric id read from the last item via `idKey`. A\n        // non-numeric value (almost always an `idKey` that doesn't match the\n        // response field — e.g. sorting by `ID` while the response carries a\n        // lowercase `id`) stops the walk instead of silently truncating.\n        readNextCursor: (lastItem) => {\n          const value = Number.parseInt(lastItem[idKey], 10)\n          return Number.isFinite(value) ? value : null\n        },\n        noCursorWarning: `fetchList.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        errorLabel: 'fetchListMethod'\n      })\n    } catch (error) {\n      if (error instanceof KeysetPaginationError) {\n        throw new SdkError({\n          code: 'JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V3',\n          description: `API Error: ${error.messages.join('; ')}`,\n          status: 500\n        })\n      }\n      throw error\n    }\n  }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAqBO,MAAM,oBAAoB,cAAA,CAAe;AAAA,EArBhD;AAqBgD,IAAA,MAAA,CAAA,IAAA,EAAA,aAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqD9C,OAAuB,KAAkB,OAAA,EAAiD;AACxF,IAAA,MAAM,SAAA,GAAY,SAAS,KAAA,IAAS,EAAA;AAEpC,IAAA,MAAM,KAAA,GAAQ,SAAS,KAAA,IAAS,IAAA;AAChC,IAAA,MAAM,WAAA,GAAc,SAAS,WAAA,IAAe,KAAA;AAC5C,IAAA,MAAM,kBAAA,GAAqB,SAAS,kBAAA,IAAsB,IAAA;AAC1D,IAAA,MAAM,MAAA,GAAS,OAAA,EAAS,MAAA,IAAU,EAAC;AAGnC,IAAA,IAAI,OAAA,IAAW,MAAA,IAAU,MAAA,CAAO,OAAO,CAAA,EAAG;AACxC,MAAA,IAAA,CAAK,OAAA,CAAQ,QAAQ,sKAAsK,CAAA;AAAA,IAC7L;AAEA,IAAA,MAAM,EAAE,KAAA,EAAO,aAAA,EAAe,GAAG,YAAW,GAAI,MAAA;AAChD,IAAA,MAAM,aAAA,GAAgC;AAAA,MACpC,GAAG,UAAA;AAAA,MACH,KAAA,EAAO,EAAE,CAAC,WAAW,GAAG,KAAA,EAAM;AAAA,MAC9B,QAAQ,CAAC,GAAI,OAAO,QAAQ,CAAA,IAAK,EAAG,CAAA;AAAA,MACpC,UAAA,EAAY,EAAE,IAAA,EAAM,CAAA,EAAG,OAAO,SAAA;AAAU,KAC1C;AAEA,IAAA,IAAI;AACF,MAAA,OAAO,cAAA,CAAkB,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,OAAA,EAAS;AAAA,QAChD,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB,WAAW,OAAA,CAAQ,SAAA;AAAA,QACnB,kBAAA;AAAA,QACA,aAAA,EAAe,CAAA;AAAA;AAAA,QAEf,6BAAa,MAAA,CAAA,CAAA,MAAA,MAAW,EAAE,GAAG,aAAA,EAAe,QAAQ,CAAC,GAAG,aAAA,CAAc,MAAA,EAAQ,CAAC,WAAA,EAAa,GAAA,EAAK,MAAM,CAAC,GAAE,CAAA,EAA7F,aAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKb,cAAA,0BAAiB,QAAA,KAAa;AAC5B,UAAA,MAAM,QAAQ,MAAA,CAAO,QAAA,CAAS,QAAA,CAAS,KAAK,GAAG,EAAE,CAAA;AACjD,UAAA,OAAO,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,GAAI,KAAA,GAAQ,IAAA;AAAA,QAC1C,CAAA,EAHgB,gBAAA,CAAA;AAAA,QAIhB,eAAA,EAAiB,+GAA0G,KAAK,CAAA,gKAAA,CAAA;AAAA,QAChI,UAAA,EAAY;AAAA,OACb,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,iBAAiB,qBAAA,EAAuB;AAC1C,QAAA,MAAM,IAAI,QAAA,CAAS;AAAA,UACjB,IAAA,EAAM,yCAAA;AAAA,UACN,aAAa,CAAA,WAAA,EAAc,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,UACpD,MAAA,EAAQ;AAAA,SACT,CAAA;AAAA,MACH;AACA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AACF;;;;"}