# Проект на Vue > Руководство по установке Bitrix24 JS SDK в приложениях Vue. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект Vue ### Установка пакета Bitrix24 JS SDK ```bash [pnpm] pnpm add @bitrix24/b24jssdk ``` ```bash [yarn] yarn add @bitrix24/b24jssdk ``` ```bash [npm] npm install @bitrix24/b24jssdk ``` ```bash [bun] bun add @bitrix24/b24jssdk ``` ### Импорт Импортируйте библиотеку в проект: ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' ``` ### Инициализация Для работы с Bitrix24 из приложения, встроенного в интерфейс Bitrix24, используйте объект `B24Frame`. Он инициализируется на стороне клиента через `initializeB24Frame()`. ```vue [SomePage.vue] ``` > \[!CAUTION] > > Объект `B24Hook` предназначен **исключительно для использования на сервере**. > > - Вебхук содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24Hook`. ```ts import { B24Hook } from '@bitrix24/b24jssdk' // 1. Получите URL вебхука в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Вебхуки // - Создайте новый вебхук с необходимыми правами // - Скопируйте URL в формате: https://your-domain.bitrix24.com/rest/1/your-token/ // 2. Инициализируйте B24Hook const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 3. Используйте методы API ``` > \[!CAUTION] > > Объект `B24OAuth` предназначен **исключительно для использования на сервере**. > > - B24OAuth содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24OAuth`. ```ts import { B24OAuth } from '@bitrix24/b24jssdk' // 1. Зарегистрируйте приложение в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Приложения // - Создайте новое приложение // - Получите Client ID и Client Secret // 2. Инициализируйте B24OAuth — передайте данные токена и OAuth-учётные данные отдельно. // Полную форму B24OAuthParams см. на /docs/working-with-the-rest-api/oauth/. import { EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( { applicationToken: 'current_application_token', userId: 1, memberId: 'portal_member_id', accessToken: 'current_access_token', refreshToken: 'refresh_token', expires: 1745997853, // unix timestamp, секунды expiresIn: 3600, scope: 'crm,user_brief', domain: 'your-domain.bitrix24.com', clientEndpoint: 'https://your-domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, { clientId: 'your_client_id', clientSecret: 'your_client_secret' } ) // 3. Используйте методы API // B24OAuth автоматически обновляет токены при их истечении ``` --- # Проект на Nuxt > Руководство по установке Bitrix24 JS SDK в приложениях Nuxt. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект Nuxt Для доступа к **Bitrix24 JS SDK** в проекте **Nuxt** используйте модуль `@bitrix24/b24jssdk-nuxt`. > \[!NOTE] > > Требуется **Nuxt 4**. Перед началом убедитесь, что обновились до Nuxt 4. ### Установка пакета Bitrix24 JS SDK ```bash [pnpm] pnpm add @bitrix24/b24jssdk-nuxt ``` ```bash [yarn] yarn add @bitrix24/b24jssdk-nuxt ``` ```bash [npm] npm install @bitrix24/b24jssdk-nuxt ``` ```bash [bun] bun add @bitrix24/b24jssdk-nuxt ``` ### Добавьте модуль Bitrix24 JS SDK в ваш `nuxt.config.ts` // @check-ignore: defineNuxtConfig is a Nuxt auto-import, not available in SDK typecheck context ```ts [nuxt.config.ts] export default defineNuxtConfig({ modules: ['@bitrix24/b24jssdk-nuxt'] }) ``` ### Импорт Импортируйте библиотеку в проект: ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' ``` ### Инициализация Для работы с Bitrix24 из приложения, встроенного в интерфейс Bitrix24, используйте объект `B24Frame`. Он инициализируется на стороне клиента через `initializeB24Frame()`. ```vue [SomePage.vue] ``` > \[!CAUTION] > > Объект `B24Hook` предназначен **исключительно для использования на сервере**. > > - Вебхук содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24Hook`. ```ts import { B24Hook } from '@bitrix24/b24jssdk' // 1. Получите URL вебхука в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Вебхуки // - Создайте новый вебхук с необходимыми правами // - Скопируйте URL в формате: https://your-domain.bitrix24.com/rest/1/your-token/ // 2. Инициализируйте B24Hook const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 3. Используйте методы API ``` > \[!CAUTION] > > Объект `B24OAuth` предназначен **исключительно для использования на сервере**. > > - B24OAuth содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24OAuth`. ```ts import { B24OAuth } from '@bitrix24/b24jssdk' // 1. Зарегистрируйте приложение в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Приложения // - Создайте новое приложение // - Получите Client ID и Client Secret // 2. Инициализируйте B24OAuth — передайте данные токена и OAuth-учётные данные отдельно. // Полную форму B24OAuthParams см. на /docs/working-with-the-rest-api/oauth/. import { EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( { applicationToken: 'current_application_token', userId: 1, memberId: 'portal_member_id', accessToken: 'current_access_token', refreshToken: 'refresh_token', expires: 1745997853, // unix timestamp, секунды expiresIn: 3600, scope: 'crm,user_brief', domain: 'your-domain.bitrix24.com', clientEndpoint: 'https://your-domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, { clientId: 'your_client_id', clientSecret: 'your_client_secret' } ) // 3. Используйте методы API // B24OAuth автоматически обновляет токены при их истечении ``` --- # Проект на React > Руководство по установке Bitrix24 JS SDK в приложениях React. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект React ### Установка пакета Bitrix24 JS SDK ```bash [pnpm] pnpm add @bitrix24/b24jssdk ``` ```bash [yarn] yarn add @bitrix24/b24jssdk ``` ```bash [npm] npm install @bitrix24/b24jssdk ``` ```bash [bun] bun add @bitrix24/b24jssdk ``` ### Импорт Импортируйте библиотеку в проект: ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' ``` ### Инициализация Для работы с Bitrix24 из приложения, встроенного в интерфейс Bitrix24, используйте объект `B24Frame`. Он инициализируется на стороне клиента через `initializeB24Frame()`. ```tsx [App.tsx] import type { B24Frame, ISODate } from '@bitrix24/b24jssdk'; import type { DateTime } from 'luxon'; import { useEffect, useRef } from 'react'; import { initializeB24Frame, LoggerFactory, EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk'; const devMode = typeof import.meta !== 'undefined' && (import.meta.env?.DEV ?? false); const $logger = LoggerFactory.createForBrowser('MyApp', devMode); type CompanyResponse = { id: number; title: string; createdTime: ISODate }; type Company = Omit & { createdTime: DateTime }; async function loadCompanyList(b24: B24Frame): Promise { const result: Company[] = []; const response = await b24.actions.v2.call.make<{ items: CompanyResponse[] }>({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.company, order: { id: 'DESC' }, select: ['id', 'title', 'createdTime'], }, }); if (!response.isSuccess) { throw new Error(`API Error: ${response.getErrorMessages().join('; ')}`); } const responseData = response.getData()!.result as { items: CompanyResponse[] }; responseData.items.forEach((entity) => { result.push({ id: entity.id, title: entity.title, createdTime: Text.toDateTime(entity.createdTime), }); }); return result; } function App() { const b24Ref = useRef(null); useEffect(() => { let isMounted = true; async function init() { try { const b24 = await initializeB24Frame(); if (!isMounted) { b24.destroy(); return; } b24Ref.current = b24; const companies = await loadCompanyList(b24); $logger.notice('Companies loaded successfully', { companies }); } catch (error) { $logger.error('Some problems', { error }); } } init(); return () => { isMounted = false; b24Ref.current?.destroy(); }; }, []); return (

B24 JS SDK - React Demo

See the result in the developer console

Note: This app must be opened inside Bitrix24 as a frame application.

); } export default App; ``` Ключевые особенности React: - **Используйте React-хуки:** инициализируйте B24Frame в useEffect с функцией очистки - **Используйте Refs:** храните экземпляр B24Frame в ref, чтобы он сохранялся между рендерами - **Очистка:** всегда вызывайте destroy() при размонтировании компонента, чтобы избежать утечек памяти - **Окружение:** помните, что B24Frame работает только внутри iframe Bitrix24 > \[!CAUTION] > > Объект `B24Hook` предназначен **исключительно для использования на сервере**. > > - Вебхук содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24Hook`. ```ts import { B24Hook } from '@bitrix24/b24jssdk' // 1. Получите URL вебхука в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Вебхуки // - Создайте новый вебхук с необходимыми правами // - Скопируйте URL в формате: https://your-domain.bitrix24.com/rest/1/your-token/ // 2. Инициализируйте B24Hook const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 3. Используйте методы API ``` > \[!CAUTION] > > Объект `B24OAuth` предназначен **исключительно для использования на сервере**. > > - B24OAuth содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24OAuth`. ```ts import { B24OAuth } from '@bitrix24/b24jssdk' // 1. Зарегистрируйте приложение в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Приложения // - Создайте новое приложение // - Получите Client ID и Client Secret // 2. Инициализируйте B24OAuth — передайте данные токена и OAuth-учётные данные отдельно. // Полную форму B24OAuthParams см. на /docs/working-with-the-rest-api/oauth/. import { EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( { applicationToken: 'current_application_token', userId: 1, memberId: 'portal_member_id', accessToken: 'current_access_token', refreshToken: 'refresh_token', expires: 1745997853, // unix timestamp, секунды expiresIn: 3600, scope: 'crm,user_brief', domain: 'your-domain.bitrix24.com', clientEndpoint: 'https://your-domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, { clientId: 'your_client_id', clientSecret: 'your_client_secret' } ) // 3. Используйте методы API // B24OAuth автоматически обновляет токены при их истечении ``` --- # Проект на Node.js > Руководство по установке Bitrix24 JS SDK в приложениях Node.js. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект Node.js > \[!NOTE] > > **`ESM` — рекомендуемый формат модулей.** `CommonJS` тоже поддерживается — вы можете `require('@bitrix24/b24jssdk')` из CommonJS-проекта (он резолвится в полноценную CJS-сборку с внешними зависимостями — см. note ниже; TypeScript-файлы, запускаемые напрямую через `ts-node` / `tsx`, тоже работают). Для использования через ` ``` При необходимости скачайте UMD-версию библиотеки с [unpkg.com](https://unpkg.com/browse/@bitrix24/b24jssdk@latest/dist/){rel=""nofollow""} и добавьте её в проект. Затем подключите её в HTML-файл: ```html ``` > \[!NOTE] > > Бандл `UMD` **инлайнит** свои зависимости (`axios`, `luxon`, `qs-esm`), чтобы работать из одного ` ``` #rest-api-ver3 ```html Bitrix24 JS SDK Demo

Company Loader Example

Check developer console for results

``` --- # Начало работы > Краткое руководство по работе с SDK для REST API Bitrix24 > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Обзор SDK для работы с REST API Bitrix24 предоставляет единый интерфейс для взаимодействия с API Bitrix24 из JavaScript/TypeScript-приложений. Эта страница поможет вам быстро начать работу с библиотекой. ## Выбор подходящего класса Выберите класс в зависимости от сценария использования: | Сценарий | Класс | Описание | | --- | --- | --- | | Приложение, встроенное в интерфейс Bitrix24 | `B24Frame` | Автоматически доступен в iframe, использует токен текущего пользователя | | Автономное серверное приложение с вебхуком | `B24Hook` | Использует постоянный токен вебхука для серверных приложений | | Автономное серверное приложение с OAuth | `B24OAuth` | Использует OAuth 2.0 с возможностью обновления токена | ### Для клиентских приложений (B24Frame) Если вы разрабатываете приложение, которое будет работать внутри интерфейса Bitrix24: // @check-ignore: declares own $b24 with B24Frame type without import ```ts // В приложении, встроенном в Bitrix24 let $b24: undefined | B24Frame async function getCurrentUser() { if (!$b24) { return } try { const response = await $b24.actions.v2.call.make({ method: 'user.current', requestId: 'get-current-user' }) if (response.isSuccess) { const user = response.getData() console.log('Current user:', user) return user } else { console.error('Error:', response.getErrorMessages()) } } catch (error) { console.error('Unexpected error:', error) } } // Пример получения списка контактов async function getContacts() { if (!$b24) { return } const response = await $b24.actions.v2.callList.make({ method: 'crm.contact.list', params: { filter: { '>ID': 0 }, select: ['ID', 'NAME', 'LAST_NAME', 'EMAIL'] }, idKey: 'ID', requestId: 'get-all-contacts' }) if (response.isSuccess) { return response.getData() } return [] } async function init() { $b24 = await initializeB24Frame() } await init() ``` ### Для серверных приложений с вебхуком (B24Hook) Для серверных приложений с постоянным доступом через вебхук: ```ts import { B24Hook } from '@bitrix24/b24jssdk' // 1. Получите URL вебхука в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Вебхуки // - Создайте новый вебхук с необходимыми правами // - Скопируйте URL в формате: https://your-domain.bitrix24.com/rest/1/your-token/ // 2. Инициализируйте B24Hook const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 3. Используйте методы API async function getCompany(companyId: number) { const response = await $b24.actions.v2.call.make({ method: 'crm.company.get', params: { id: companyId }, requestId: `get-company-${companyId}` }) if (response.isSuccess) { return response.getData() } else { throw new Error(`Error getting company: ${response.getErrorMessages().join(', ')}`) } } // Пример массового создания сделок async function createMultipleDeals(dealsData: Array<{title: string, opportunity: number}>) { const calls = dealsData.map((deal, index): [string, Record] => [ 'crm.deal.add', { fields: { TITLE: deal.title, OPPORTUNITY: deal.opportunity, CATEGORY_ID: 0 } } ]) const response = await $b24.actions.v2.batchByChunk.make({ calls, options: { requestId: 'bulk-create-deals' } }) return response } ``` ### Для серверных приложений с OAuth (B24OAuth) Для серверных приложений с аутентификацией через OAuth 2.0: ```ts import { B24OAuth } from '@bitrix24/b24jssdk' // 1. Зарегистрируйте приложение в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Приложения // - Создайте новое приложение // - Получите Client ID и Client Secret // 2. Инициализируйте B24OAuth — передайте данные токена и OAuth-учётные данные отдельно. // Полную форму B24OAuthParams см. на странице справочника OAuth. import { EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( { applicationToken: 'current_application_token', userId: 1, memberId: 'portal_member_id', accessToken: 'current_access_token', refreshToken: 'refresh_token', expires: 1745997853, // unix timestamp, секунды expiresIn: 3600, scope: 'crm,user_brief', domain: 'your-domain.bitrix24.com', clientEndpoint: 'https://your-domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, { clientId: 'your_client_id', clientSecret: 'your_client_secret' } ) // 3. Используйте методы API async function getTasks() { const response = await $b24.actions.v2.call.make({ method: 'tasks.task.list', params: { filter: { '>ID': 0 }, select: ['ID', 'TITLE', 'STATUS'] }, requestId: 'get-all-tasks' }) return response } // B24OAuth автоматически обновляет токены при их истечении ``` ## Первые шаги с API ### Простой тест подключения // @check-ignore: partial snippet — B24Hook used without import ```typescript // Проверка доступности API async function testConnection() { // Для B24Hook или B24OAuth const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 1. Проверьте доступность const isHealthy = await $b24.tools.healthCheck.make({ requestId: 'health-check' }) if (!isHealthy) { console.error('API unavailable. Check the webhook and connection.') return } // 2. Измерьте скорость const pingTime = await $b24.tools.ping.make({ requestId: 'ping-test' }) console.log(`API available, response time: ${pingTime}ms`) // 3. Получите данные текущего пользователя const userResponse = await $b24.actions.v2.call.make({ method: 'user.current', requestId: 'get-current-user' }) if (userResponse.isSuccess) { console.log('Current user:', userResponse.getData()) } return true } ``` ### Базовые операции с CRM ```ts // Создание контакта async function createContact(name: string, lastName: string, email: string) { const response = await $b24.actions.v2.call.make({ method: 'crm.contact.add', params: { fields: { NAME: name, LAST_NAME: lastName, EMAIL: [{ VALUE: email, VALUE_TYPE: 'WORK' }] } }, requestId: 'create-contact' }) return response } // Получение списка контактов async function getAllContacts() { const generator = $b24.actions.v2.fetchList.make({ method: 'crm.contact.list', params: { select: ['ID', 'NAME', 'LAST_NAME', 'EMAIL'], order: { ID: 'ASC' } }, idKey: 'ID', requestId: 'fetch-all-contacts' }) const allContacts = [] for await (const chunk of generator) { allContacts.push(...chunk) console.log(`Loaded ${chunk.length} contacts, total: ${allContacts.length}`) } return allContacts } ``` ### Примеры использования основных методов // @check-ignore: partial snippet — processChunk not declared and top-level return ```ts // 1. Одиночный вызов (Call) const singleItem = await $b24.actions.v2.call.make({ method: 'crm.company.get', params: { id: 123 }, requestId: 'single-call' }) // 2. Получение всего списка (CallList) const allItems = await $b24.actions.v2.callList.make({ method: 'crm.company.list', params: { filter: { '>ID': 0 }, select: ['ID', 'TITLE'] }, idKey: 'ID', requestId: 'get-all-companies' }) // 3. Потоковая обработка (FetchList) const generator = $b24.actions.v2.fetchList.make({ method: 'crm.deal.list', params: { select: ['ID', 'TITLE', 'OPPORTUNITY'] }, idKey: 'ID', requestId: 'stream-deals' }) for await (const chunk of generator) { // Обрабатываем пачками по 50 элементов processChunk(chunk) } // 4. Пакетная обработка (Batch) const batchResult = await $b24.actions.v2.batch.make({ calls: [ ['crm.company.get', { id: 1 }], ['crm.company.get', { id: 2 }], ['crm.company.get', { id: 3 }] ], options: { requestId: 'batch-get-companies' } }) // 5. Массовая пакетная обработка (BatchByChunk) const commands = Array.from({ length: 150 }, (_, i): [string, Record] => [ 'crm.contact.add', { fields: { NAME: `Contact ${i + 1}` } } ]) const bulkResult = await $b24.actions.v2.batchByChunk.make({ calls: commands, options: { requestId: 'bulk-create-contacts' } }) ``` ## Советы для начинающих ### 1. Всегда используйте requestId ```ts // Хорошо await $b24.actions.v2.call.make({ method: 'crm.contact.get', params: { id: 123 }, requestId: `contact-${123}-${Date.now()}` }) // Плохо (без requestId будет сложно отладить) await $b24.actions.v2.call.make({ method: 'crm.contact.get', params: { id: 123 } }) ``` ### 2. Проверяйте результаты операций // @check-ignore: top-level return in error-handling illustration ```ts const response = await $b24.actions.v2.call.make({ method: 'some.method', params: { /* ... */ }, requestId: 'my-request' }) // Всегда проверяйте isSuccess if (!response.isSuccess) { console.error('Error:', response.getErrorMessages()) // Обработка ошибки return } // Только после успешной проверки работаем с данными const data = response.getData()! ``` ### 3. Выбирайте правильный метод для работы со списками | Объём данных | Метод | Почему | | --- | --- | --- | | < 1000 записей | `CallList` | Удобно использовать, все данные сразу | | > 1000 записей | `FetchList` | Эффективен по памяти, потоковая обработка | | Выборочные данные | `Call` + `Batch` | Только нужные записи, контроль над запросами | ## Нужна помощь? - [Открыть issue в GitHub](https://github.com/bitrix24/b24jssdk/issues){rel=""nofollow""} - [Посмотреть существующие вопросы](https://github.com/bitrix24/b24jssdk/issues?q=is%3Aissue){rel=""nofollow""} - [Официальная документация](https://apidocs.bitrix24.ru/){rel=""nofollow""} --- **Совет**: Начните с простых запросов (например, `user.current`), чтобы убедиться, что соединение работает корректно, прежде чем переходить к сложным операциям с CRM или задачами. --- # Проект на Vue > Руководство по установке Bitrix24 JS SDK в приложениях Vue. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект Vue ### Установка пакета Bitrix24 JS SDK ```bash [pnpm] pnpm add @bitrix24/b24jssdk ``` ```bash [yarn] yarn add @bitrix24/b24jssdk ``` ```bash [npm] npm install @bitrix24/b24jssdk ``` ```bash [bun] bun add @bitrix24/b24jssdk ``` ### Импорт Импортируйте библиотеку в проект: ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' ``` ### Инициализация Для работы с Bitrix24 из приложения, встроенного в интерфейс Bitrix24, используйте объект `B24Frame`. Он инициализируется на стороне клиента через `initializeB24Frame()`. ```vue [SomePage.vue] ``` > \[!CAUTION] > > Объект `B24Hook` предназначен **исключительно для использования на сервере**. > > - Вебхук содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24Hook`. ```ts import { B24Hook } from '@bitrix24/b24jssdk' // 1. Получите URL вебхука в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Вебхуки // - Создайте новый вебхук с необходимыми правами // - Скопируйте URL в формате: https://your-domain.bitrix24.com/rest/1/your-token/ // 2. Инициализируйте B24Hook const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 3. Используйте методы API ``` > \[!CAUTION] > > Объект `B24OAuth` предназначен **исключительно для использования на сервере**. > > - B24OAuth содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24OAuth`. ```ts import { B24OAuth } from '@bitrix24/b24jssdk' // 1. Зарегистрируйте приложение в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Приложения // - Создайте новое приложение // - Получите Client ID и Client Secret // 2. Инициализируйте B24OAuth — передайте данные токена и OAuth-учётные данные отдельно. // Полную форму B24OAuthParams см. на /docs/working-with-the-rest-api/oauth/. import { EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( { applicationToken: 'current_application_token', userId: 1, memberId: 'portal_member_id', accessToken: 'current_access_token', refreshToken: 'refresh_token', expires: 1745997853, // unix timestamp, секунды expiresIn: 3600, scope: 'crm,user_brief', domain: 'your-domain.bitrix24.com', clientEndpoint: 'https://your-domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, { clientId: 'your_client_id', clientSecret: 'your_client_secret' } ) // 3. Используйте методы API // B24OAuth автоматически обновляет токены при их истечении ``` --- # Проект на Nuxt > Руководство по установке Bitrix24 JS SDK в приложениях Nuxt. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект Nuxt Для доступа к **Bitrix24 JS SDK** в проекте **Nuxt** используйте модуль `@bitrix24/b24jssdk-nuxt`. > \[!NOTE] > > Требуется **Nuxt 4**. Перед началом убедитесь, что обновились до Nuxt 4. ### Установка пакета Bitrix24 JS SDK ```bash [pnpm] pnpm add @bitrix24/b24jssdk-nuxt ``` ```bash [yarn] yarn add @bitrix24/b24jssdk-nuxt ``` ```bash [npm] npm install @bitrix24/b24jssdk-nuxt ``` ```bash [bun] bun add @bitrix24/b24jssdk-nuxt ``` ### Добавьте модуль Bitrix24 JS SDK в ваш `nuxt.config.ts` // @check-ignore: defineNuxtConfig is a Nuxt auto-import, not available in SDK typecheck context ```ts [nuxt.config.ts] export default defineNuxtConfig({ modules: ['@bitrix24/b24jssdk-nuxt'] }) ``` ### Импорт Импортируйте библиотеку в проект: ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' ``` ### Инициализация Для работы с Bitrix24 из приложения, встроенного в интерфейс Bitrix24, используйте объект `B24Frame`. Он инициализируется на стороне клиента через `initializeB24Frame()`. ```vue [SomePage.vue] ``` > \[!CAUTION] > > Объект `B24Hook` предназначен **исключительно для использования на сервере**. > > - Вебхук содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24Hook`. ```ts import { B24Hook } from '@bitrix24/b24jssdk' // 1. Получите URL вебхука в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Вебхуки // - Создайте новый вебхук с необходимыми правами // - Скопируйте URL в формате: https://your-domain.bitrix24.com/rest/1/your-token/ // 2. Инициализируйте B24Hook const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 3. Используйте методы API ``` > \[!CAUTION] > > Объект `B24OAuth` предназначен **исключительно для использования на сервере**. > > - B24OAuth содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24OAuth`. ```ts import { B24OAuth } from '@bitrix24/b24jssdk' // 1. Зарегистрируйте приложение в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Приложения // - Создайте новое приложение // - Получите Client ID и Client Secret // 2. Инициализируйте B24OAuth — передайте данные токена и OAuth-учётные данные отдельно. // Полную форму B24OAuthParams см. на /docs/working-with-the-rest-api/oauth/. import { EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( { applicationToken: 'current_application_token', userId: 1, memberId: 'portal_member_id', accessToken: 'current_access_token', refreshToken: 'refresh_token', expires: 1745997853, // unix timestamp, секунды expiresIn: 3600, scope: 'crm,user_brief', domain: 'your-domain.bitrix24.com', clientEndpoint: 'https://your-domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, { clientId: 'your_client_id', clientSecret: 'your_client_secret' } ) // 3. Используйте методы API // B24OAuth автоматически обновляет токены при их истечении ``` --- # Проект на React > Руководство по установке Bitrix24 JS SDK в приложениях React. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект React ### Установка пакета Bitrix24 JS SDK ```bash [pnpm] pnpm add @bitrix24/b24jssdk ``` ```bash [yarn] yarn add @bitrix24/b24jssdk ``` ```bash [npm] npm install @bitrix24/b24jssdk ``` ```bash [bun] bun add @bitrix24/b24jssdk ``` ### Импорт Импортируйте библиотеку в проект: ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' ``` ### Инициализация Для работы с Bitrix24 из приложения, встроенного в интерфейс Bitrix24, используйте объект `B24Frame`. Он инициализируется на стороне клиента через `initializeB24Frame()`. ```tsx [App.tsx] import type { B24Frame, ISODate } from '@bitrix24/b24jssdk'; import type { DateTime } from 'luxon'; import { useEffect, useRef } from 'react'; import { initializeB24Frame, LoggerFactory, EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk'; const devMode = typeof import.meta !== 'undefined' && (import.meta.env?.DEV ?? false); const $logger = LoggerFactory.createForBrowser('MyApp', devMode); type CompanyResponse = { id: number; title: string; createdTime: ISODate }; type Company = Omit & { createdTime: DateTime }; async function loadCompanyList(b24: B24Frame): Promise { const result: Company[] = []; const response = await b24.actions.v2.call.make<{ items: CompanyResponse[] }>({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.company, order: { id: 'DESC' }, select: ['id', 'title', 'createdTime'], }, }); if (!response.isSuccess) { throw new Error(`API Error: ${response.getErrorMessages().join('; ')}`); } const responseData = response.getData()!.result as { items: CompanyResponse[] }; responseData.items.forEach((entity) => { result.push({ id: entity.id, title: entity.title, createdTime: Text.toDateTime(entity.createdTime), }); }); return result; } function App() { const b24Ref = useRef(null); useEffect(() => { let isMounted = true; async function init() { try { const b24 = await initializeB24Frame(); if (!isMounted) { b24.destroy(); return; } b24Ref.current = b24; const companies = await loadCompanyList(b24); $logger.notice('Companies loaded successfully', { companies }); } catch (error) { $logger.error('Some problems', { error }); } } init(); return () => { isMounted = false; b24Ref.current?.destroy(); }; }, []); return (

B24 JS SDK - React Demo

See the result in the developer console

Note: This app must be opened inside Bitrix24 as a frame application.

); } export default App; ``` Ключевые особенности React: - **Используйте React-хуки:** инициализируйте B24Frame в useEffect с функцией очистки - **Используйте Refs:** храните экземпляр B24Frame в ref, чтобы он сохранялся между рендерами - **Очистка:** всегда вызывайте destroy() при размонтировании компонента, чтобы избежать утечек памяти - **Окружение:** помните, что B24Frame работает только внутри iframe Bitrix24 > \[!CAUTION] > > Объект `B24Hook` предназначен **исключительно для использования на сервере**. > > - Вебхук содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24Hook`. ```ts import { B24Hook } from '@bitrix24/b24jssdk' // 1. Получите URL вебхука в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Вебхуки // - Создайте новый вебхук с необходимыми правами // - Скопируйте URL в формате: https://your-domain.bitrix24.com/rest/1/your-token/ // 2. Инициализируйте B24Hook const $b24 = B24Hook.fromWebhookUrl('https://your-domain.bitrix24.com/rest/1/your-token/') // 3. Используйте методы API ``` > \[!CAUTION] > > Объект `B24OAuth` предназначен **исключительно для использования на сервере**. > > - B24OAuth содержит секретный ключ доступа, который **НЕЛЬЗЯ** использовать в клиентском коде (браузер, мобильное приложение). > - Для клиентской стороны используйте [`B24Frame`] Для работы с Bitrix24 из автономного серверного приложения используйте объект `B24OAuth`. ```ts import { B24OAuth } from '@bitrix24/b24jssdk' // 1. Зарегистрируйте приложение в Bitrix24: // - Перейдите в Bitrix24 // - Настройки → Разработчикам → Приложения // - Создайте новое приложение // - Получите Client ID и Client Secret // 2. Инициализируйте B24OAuth — передайте данные токена и OAuth-учётные данные отдельно. // Полную форму B24OAuthParams см. на /docs/working-with-the-rest-api/oauth/. import { EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( { applicationToken: 'current_application_token', userId: 1, memberId: 'portal_member_id', accessToken: 'current_access_token', refreshToken: 'refresh_token', expires: 1745997853, // unix timestamp, секунды expiresIn: 3600, scope: 'crm,user_brief', domain: 'your-domain.bitrix24.com', clientEndpoint: 'https://your-domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, { clientId: 'your_client_id', clientSecret: 'your_client_secret' } ) // 3. Используйте методы API // B24OAuth автоматически обновляет токены при их истечении ``` --- # Проект на Node.js > Руководство по установке Bitrix24 JS SDK в приложениях Node.js. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Установка в проект Node.js > \[!NOTE] > > **`ESM` — рекомендуемый формат модулей.** `CommonJS` тоже поддерживается — вы можете `require('@bitrix24/b24jssdk')` из CommonJS-проекта (он резолвится в полноценную CJS-сборку с внешними зависимостями — см. note ниже; TypeScript-файлы, запускаемые напрямую через `ts-node` / `tsx`, тоже работают). Для использования через ` ``` При необходимости скачайте UMD-версию библиотеки с [unpkg.com](https://unpkg.com/browse/@bitrix24/b24jssdk@latest/dist/){rel=""nofollow""} и добавьте её в проект. Затем подключите её в HTML-файл: ```html ``` > \[!NOTE] > > Бандл `UMD` **инлайнит** свои зависимости (`axios`, `luxon`, `qs-esm`), чтобы работать из одного ` ``` #rest-api-ver3 ```html Bitrix24 JS SDK Demo

Company Loader Example

Check developer console for results

``` --- # Миграция на v1 > Подробное руководство по миграции приложения с Bitrix24 JS SDK v0 на Bitrix24 JS SDK v1. Это руководство содержит пошаговые инструкции по миграции приложения на Bitrix24 JS SDK v1. > \[!NOTE] > > Мы старались сохранить совместимость, но если возникнут проблемы, [сообщите нам](https://github.com/bitrix24/b24jssdk/issues){rel=""nofollow""}. После обновления до Bitrix24 JS SDK v1 обратите внимание на следующие важные изменения: ## Изменения ### PlacementManager.title Для согласованности с документацией и устранения путаницы свойство `PlacementManager.title` переименовано в `PlacementManager.placement`. ```diff - if (b24Frame.placement.title === 'DEFAULT') { + if (b24Frame.placement.placement === 'DEFAULT') { // some code } ``` ### TypeB24.getTargetOriginWithPath > Получает адрес аккаунта Bitrix24 с путём Функция теперь возвращает пути для `restApi:v2` и `restApi:v3`. ```diff + import { ApiVersion } from '@bitrix24/b24jssdk' - b24.getTargetOriginWithPath() + b24.getTargetOriginWithPath().get(ApiVersion.v2) + b24.getTargetOriginWithPath().get(ApiVersion.v3) ``` ### TypeB24.getHttpClient > Возвращает HTTP-клиент для выполнения запроса. Функция теперь возвращает HTTP-клиент для `restApi:v2` и `restApi:v3`. ```diff + import { ApiVersion } from '@bitrix24/b24jssdk' - b24.getHttpClient() + b24.getHttpClient(ApiVersion.v2) + b24.getHttpClient(ApiVersion.v3) ``` ### Error Все ошибки теперь наследуются от `SdkError`. Учитывайте это. ```diff + import { SdkError } from '@bitrix24/b24jssdk' try { // ... } catch (error) { - if (error instanceof Error) { + if (error instanceof SdkError) { // ... } } ``` ## Удалено ### Неиспользуемые методы TypeHttp Методы регистрации запросов: - `TypeHttp.setLogTag()` - `TypeHttp.clearLogTag()` Теперь для этих целей нужно использовать параметр `requestId`. ### Неиспользуемые методы Http Метод вывода системных сообщений `Http.getSystemLogger()` Теперь используется принудительный вывод через [`LoggerFactory.forcedLog()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md) ### Restriction Manager Класс `RestrictionManager` удалён. Вместо него используется система [`Limiters`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md). ```diff - import { RestrictionManagerParamsForEnterprise } from '@bitrix24/b24jssdk' + import { ParamsFactory } from '@bitrix24/b24jssdk' - $b24.getHttpClient().setRestrictionManagerParams( RestrictionManagerParamsForEnterprise ) + $b24.setRestrictionManagerParams( ParamsFactory.getEnterprise() ) // or + const b24 = B24Hook.fromWebhookUrl(hookPath, { restrictionParams: ParamsFactory.getEnterprise() }) - $b24.getHttpClient().setRestrictionManagerParams( { sleep: 600, speed: 0.01, amount: 30 * 5 } ) + $b24.setRestrictionManagerParams( { rateLimit: { burstLimit: 250, drainRate: 5 } } ) ``` ## Устарело ### AbstractB24.batchSize > Максимальная длина пакетного ответа. Эта константа устарела и будет удалена в версии `3.0.0`. ```diff - if (size < AbstractB24.batchSize) { + if (size < 50) { // some code ... } ``` ### TypeB24.callMethod > Вызывает метод REST API Bitrix24. Этот метод устарел и будет удалён в версии `3.0.0`. Для `restApi:v2` следует использовать метод [`b24.actions.v2.call.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md). ```diff - await b24.callMethod('some.method', { filter: { '>id': 123 } }, 100) + await b24.actions.v2.call.make({ + method: 'some.method', + params: { + filter: { '>id': 123 }, + start: 100 + }, + requestId: 'unique-request-id' + }) ``` Для `restApi:v3` следует использовать метод [`b24.actions.v3.call.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver3.md). ```diff - await b24.callMethod('some.method', { filter: { '>id': 123 } }, 100) + await b24.actions.v3.call.make({ + method: 'some.method', + params: { + filter: [['id', '>', 123 ]], + pagination: { limit: 50, page: 2 } + }, + requestId: 'unique-request-id' + }) ``` ### TypeB24.callListMethod > Вызывает list-метод REST API Bitrix24 для получения всех данных. Этот метод устарел и будет удалён в версии `3.0.0`. Для `restApi:v2` следует использовать метод [`b24.actions.v2.callList.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md). ```diff - await b24.callListMethod('some.method', { filter: { '>id': 123 } }, null, 'items') + await b24.actions.v2.callList.make({ + method: 'some.method', + params: { filter: { '>id': 123 } }, + idKey: 'id', + customKeyForResult: 'items', + requestId: 'unique-request-id' + }) ``` Для `restApi:v3` следует использовать метод [`b24.actions.v3.callList.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver3.md). ```diff - await b24.callListMethod('some.method', { filter: { '>id': 123 } }, null, 'items') + await b24.actions.v3.callList.make({ + method: 'some.method', + params: { filter: [['id', '>', 123 ]] }, + idKey: 'id', + customKeyForResult: 'items', + requestId: 'unique-request-id', + limit: 60 + }) ``` ### TypeB24.fetchListMethod > Вызывает list-метод REST API Bitrix24 и возвращает асинхронный генератор. Этот метод устарел и будет удалён в версии `3.0.0`. Для `restApi:v2` следует использовать метод [`b24.actions.v2.fetchList.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md). ```diff - b24.fetchListMethod('some.method', { filter: { '>id': 123 } }, 'id', 'items') + b24.actions.v2.fetchList.make({ + method: 'some.method', + params: { filter: { '>id': 123 } }, + idKey: 'id', + customKeyForResult: 'items', + requestId: 'unique-request-id' + }) ``` Для `restApi:v3` следует использовать метод [`b24.actions.v3.fetchList.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md). ```diff - b24.fetchListMethod('some.method', { filter: { '>id': 123 } }, 'id', 'items') + b24.actions.v3.fetchList.make({ + method: 'some.method', + params: { filter: [['id', '>', 123 ]] }, + idKey: 'id', + customKeyForResult: 'items', + requestId: 'unique-request-id', + limit: 60 + }) ``` ### TypeB24.callBatch > Выполняет пакетный запрос к REST API Bitrix24. Этот метод устарел и будет удалён в версии `3.0.0`. Для `restApi:v2` следует использовать метод [`b24.actions.v2.batch.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md). ```diff - await b24.callBatch([['some.method.1', { filter: { '>id': 123 } }], ['some.method.2', { filter: { 'id': 123 } }], + ['some.method.2', { filter: { 'id': 123 } }], ['some.method.2', { filter: { '', 123 ]] }], + ['some.method.2', { filter: [['id', '<', 456 ]] }], + ], + options: { + isHaltOnError: true, + returnAjaxResult: true, + requestId: 'unique-request-id' + } + }) ``` ### TypeB24.callBatchByChunk > Выполняет пакетный запрос к REST API Bitrix24 с автоматическим разбиением на чанки для любого числа команд. Этот метод устарел и будет удалён в версии `3.0.0`. Для `restApi:v2` следует использовать метод [`b24.actions.v2.batchByChunk.make(options)`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-by-chunk-rest-api-ver2.md). ```diff - await b24.callBatchByChunk([['some.method.1', { filter: { '>id': 123 } }], ['some.method.2', { filter: { 'id': 123 } }], + ['some.method.2', { filter: { 'id': 123 } }], ['some.method.2', { filter: { '', 123 ]] }], + ['some.method.2', { filter: [['id', '<', 456 ]] }], + ], + options: { + isHaltOnError: true, + requestId: 'unique-request-id' + } + }) ``` ### LoggerBrowser > Используется для логирования данных Этот класс устарел и будет удалён в версии `3.0.0`. Теперь используется более [универсальная система логирования](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md), отчасти похожая на [`Monolog (PHP)`](https://github.com/Seldaek/monolog){rel=""nofollow""}. ```diff - import { LoggerBrowser } from '@bitrix24/b24jssdk' + import { LoggerFactory } from '@bitrix24/b24jssdk' - const $logger = LoggerBrowser.build('MyApp', import.meta.env?.DEV === true) + const $logger = LoggerFactory.createForBrowser('MyApp', import.meta.env?.DEV === true) const dataList = { key1: value1, key2: value2 } - $logger.info('response', dataList) + $logger.info('response', { someInfo: dataList }) ``` --- # Миграция на v3 (удаление legacy REST-поверхности) > Как уйти с устаревшей REST-поверхности, которая удаляется в Bitrix24 JS SDK 3.0.0. Это руководство перечисляет всё, что помечено **`@deprecated` в `2.0.0`** и **удаляется в `3.0.0`**, с канонической заменой для каждого символа. > \[!WARNING] > > Символы ниже всё ещё поставляются в `2.0.0` — они продолжают работать, но при каждом вызове выводят рантайм-предупреждение об устаревании. В `3.0.0` они **удалены**. Мигрируйте до перехода на `3.0.0`. > \[!NOTE] > > Пошаговые `diff`-примеры для каждого метода — в [руководстве v0 → v1](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/migration/v1.md) в разделе «Deprecated». Эта страница — сжатый чеклист удалений. ## Что удаляется в 3.0.0 ### Legacy REST-шорткаты на `AbstractB24` Эти шорткаты экземпляра игнорируют разделение `restApi:v2` / `restApi:v3` и заменяются явной поверхностью действий: | Удалено | Замена | | --- | --- | | `b24.callMethod(method, params, start)` | `b24.actions.v{2,3}.call.make(options)` | | `b24.callListMethod(method, params, progress, customKeyForResult)` | `b24.actions.v{2,3}.callList.make(options)` [1](https://bitrix-tools.github.io/b24jssdk/#user-content-fn-idkey){#user-content-fnref-idkey ariaDescribedBy=""footnote-label"" dataFootnoteRef=""} | | `b24.fetchListMethod(method, params, idKey, customKeyForResult)` | `b24.actions.v{2,3}.fetchList.make(options)` [1](https://bitrix-tools.github.io/b24jssdk/#user-content-fn-idkey){#user-content-fnref-idkey-2 ariaDescribedBy=""footnote-label"" dataFootnoteRef=""} | | `b24.callBatch(calls, isHaltOnError, returnAjaxResult)` | `b24.actions.v{2,3}.batch.make(options)` | | `b24.callBatchByChunk(calls, isHaltOnError)` | `b24.actions.v{2,3}.batchByChunk.make(options)` | ```diff - await b24.callMethod('crm.deal.list', { filter: { '>id': 123 } }, 100) + await b24.actions.v2.call.make({ + method: 'crm.deal.list', + params: { filter: { '>id': 123 }, start: 100 }, + requestId: 'unique-request-id' + }) ``` ### `AbstractB24.batchSize` > Максимальная длина ответа батча. Статическая константа удалена. Впишите значение `50` вручную, если полагались на неё. ```diff - if (size < AbstractB24.batchSize) { + if (size < 50) { // some code ... } ``` ### Хелперы пагинации `AjaxResult` Они завязаны на поля конверта `restApi:v2` `next` / `total`, которые `restApi:v3` не возвращает: | Удалено | Замена | | --- | --- | | `result.isMore()` | используйте хелперы списков — они полностью скрывают пагинацию | | `result.hasMore()` | используйте хелперы списков | | `result.getNext(http)` | используйте хелперы списков | | `result.fetchNext(http)` | используйте хелперы списков | | `result.getTotal()` | `restApi:v2`: используйте хелперы списков; в `restApi:v3` пока нет счётчика элементов (планируется действие `aggregate`) | Замените ручную пагинацию на [`callList.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) (собрать всё) или [`fetchList.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) (асинхронный генератор): ```diff - // ручная пагинация на устаревшей поверхности - const res = await b24.callMethod('crm.deal.list', {}) - let list = res.getData().result - while (res.isMore()) { res = await res.getNext(http); list.push(...res.getData().result) } + // хелпер списка итерирует за вас — `chunk` это очередной массив элементов + for await (const chunk of b24.actions.v2.fetchList.make({ method: 'crm.deal.list' })) { + // обрабатываем chunk + } ``` ### `LoggerBrowser` и `LoggerType` Заменены универсальной системой [`Logger` / `LoggerFactory`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md). Enum `LoggerType` удалён без замены — `LoggerFactory` управляет уровнями сам, поэтому просто уберите импорт: ```diff - import { LoggerBrowser, LoggerType } from '@bitrix24/b24jssdk' + import { LoggerFactory } from '@bitrix24/b24jssdk' - const $logger = LoggerBrowser.build('MyApp', import.meta.env?.DEV === true) + const $logger = LoggerFactory.createForBrowser('MyApp', import.meta.env?.DEV === true) - $logger.info('response', dataList) + $logger.info('response', { someInfo: dataList }) ``` ## Как найти все места вызова Устаревшие символы выводят предупреждение `JSSDK_CORE_DEPRECATED_METHOD` в рантайме, а `LoggerBrowser` логирует `@deprecated: use Logger`. Быстрая статическая проверка: ```bash grep -rnE 'callMethod|callListMethod|fetchListMethod|callBatch|callBatchByChunk|\.isMore\(|\.hasMore\(|\.getNext\(|\.fetchNext\(|\.getTotal\(|LoggerBrowser|LoggerType' src ``` ```powershell Get-ChildItem -Recurse src -Include *.ts,*.js | Select-String -Pattern 'callMethod|callListMethod|fetchListMethod|callBatch|callBatchByChunk|\.isMore\(|\.hasMore\(|\.getNext\(|\.fetchNext\(|\.getTotal\(|LoggerBrowser|LoggerType' ``` Как только это ничего не вернёт — вы готовы к `3.0.0`. ## Footnotes 1. Передавайте правильный `idKey` — `'ID'` для классических list-методов, `'id'` для `crm.item.*` / `restApi:v3`. Пропуск может привести к молча пустому результату. [↩](https://bitrix-tools.github.io/b24jssdk/#user-content-fnref-idkey){.data-footnote-backref ariaLabel="Back to reference 1" dataFootnoteBackref=""} [↩2](https://bitrix-tools.github.io/b24jssdk/#user-content-fnref-idkey-2){.data-footnote-backref ariaLabel="Back to reference 1-2" dataFootnoteBackref=""} --- # AI-навыки (Skills) > Узкоспециализированные skill-файлы для AI-агентов разработчика, работающих с @bitrix24/b24jssdk. ## Обзор AI-агенты для разработки (Claude Code, Cursor, GitHub Copilot) могут загружать узкоспециализированные skill-файлы из директории `skills/` вместо чтения всего репозитория. Каждый skill покрывает одну тему — берите только то, что нужно для текущей задачи. ## Доступные skill'ы | Skill | Когда использовать | | --- | --- | | `b24jssdk-core` | Первый skill для загрузки — выбор точки входа (B24Hook / B24Frame / B24OAuth), запуск/завершение, классификация ошибок, настройка hardErrorCodes / softErrorCodes / retryOnNetworkError | | `b24jssdk-rest` | actions.v{2,3}.\*.make() — call / batch / callList / fetchList / callTail / fetchTail / batchByChunk; форма AjaxResult; v2/v3-роутинг (без v3-allowlist) | | `b24jssdk-filtering` | Фильтры v2 (ключи с префиксом) vs v3 (массивы триплетов); операторы; даты через Text.toB24Format; правило обрезки order в callList | | `b24jssdk-frame-ui` | Менеджеры только для iframe: slider / dialog (selectUser/Users/CRM/Access) / parent / placement (с setValue) / options / auth | | `b24jssdk-helpers` | useB24Helper, B24HelperManager, Pull-клиент, форматирование валюты, опции приложения/пользователя | | `b24jssdk-recipes` | 12 готовых end-to-end TypeScript мини-приложений, типизация проверяется в CI через pnpm run skills\:typecheck | | `b24jssdk-vibecode` | Когда комбинировать SDK с HTTP API VibeCode | ## Использование Каждый skill — это обычный Markdown-файл по пути `skills//SKILL.md`, следующий открытому стандарту [Agent Skills](https://agentskills.io){rel=""nofollow""}, поэтому его может использовать любой агент, умеющий читать файлы. Есть два пути добраться до skill'ов: **загрузить inline** для быстрой сессии или **установить** их в свой проект, чтобы они были всегда доступны. ### Загрузка inline (этот репозиторий) Если ваша рабочая директория — чекаут этого репозитория, ссылайтесь на skill по пути: ```text @skills/b24jssdk-core/SKILL.md ``` Ссылайтесь на сам файл `SKILL.md`, а не на директорию `skills/b24jssdk-core` — ссылка на директорию лишь перечислит файлы папки, но не подтянет содержимое skill'а. Путь резолвится относительно текущей директории, поэтому это работает только когда рабочая директория — сам `b24jssdk`. Чтобы использовать skill'ы из своего приложения, установите их одним из способов ниже. ### Claude Code — установка в проект Скопируйте директории skill'ов в `.claude/skills/` вашего проекта. Раскладка уже совпадает с ожидаемой Claude Code `.claude/skills//SKILL.md`, конвертация не нужна: ```bash mkdir -p .claude/skills cp -R path/to/b24jssdk/skills/b24jssdk-* .claude/skills/ ``` Закоммитьте `.claude/skills/` в систему контроля версий, чтобы поделиться skill'ами со всеми участниками проекта. Claude загружает skill, когда он релевантен, или его можно вызвать напрямую через `/b24jssdk-core`. ### Claude Code — личная установка Чтобы те же skill'ы были доступны во **всех** ваших проектах, скопируйте их в личную папку skill'ов: ```bash mkdir -p ~/.claude/skills cp -R path/to/b24jssdk/skills/b24jssdk-* ~/.claude/skills/ ``` Личные skill'ы (`~/.claude/skills//SKILL.md`) доступны в каждом проекте без коммита чего-либо. ### Claude Code — плагин / маркетплейс Пока недоступно. В этом репозитории сейчас **нет `.claude-plugin/marketplace.json`**, поэтому `/plugin marketplace add bitrix24/b24jssdk` сегодня не работает. Пока манифест маркетплейса не вышел, используйте установку в проект или личную выше. ### Cursor / Windsurf / GitHub Copilot — сначала вендорьте файлы У этих инструментов нет папки личных skill'ов, поэтому сначала вендорьте skill-файлы в свой проект, а затем укажите на них инструмент: ```bash # склонируйте весь репозиторий… git clone https://github.com/bitrix24/b24jssdk # …или подтяните только skills через sparse checkout git clone --depth 1 --filter=blob:none --sparse https://github.com/bitrix24/b24jssdk cd b24jssdk && git sparse-checkout set skills # …или добавьте как сабмодуль внутрь своего проекта git submodule add https://github.com/bitrix24/b24jssdk vendor/b24jssdk ``` Затем ссылайтесь на `skills//SKILL.md`: в **Cursor / Windsurf** перетащите его в чат или используйте `@`-ссылки на файлы (или `@docs`); в **GitHub Copilot** прикрепите как workspace-документ или вставьте путь в чат. ### Загрузка с опубликованного URL (без клонирования) Директория `skills/` также отдаётся с docs-сайта по пути `/.well-known/skills/`, поэтому skill можно получить, не клонируя репозиторий: ```bash curl -O https://bitrix24.github.io/b24jssdk/.well-known/skills/b24jssdk-core/SKILL.md ``` Каждый skill — по пути `/.well-known/skills/b24jssdk-/SKILL.md`. Ответы кэшируются на 24 часа. Удобно для быстрого вендоринга (положить файл в `.claude/skills//` или прикрепить в другом инструменте) или для тулинга, обнаруживающего skill'ы по HTTP. ## Порядок загрузки Всегда начинайте с `b24jssdk-core` — он покрывает выбор точки входа и жизненный цикл SDK, что предполагают все остальные skill'ы. Затем добавляйте темо-специфичные skill'ы в зависимости от задачи: 1. `b24jssdk-core` (всегда первый) 2. `b24jssdk-rest` — если делаете REST-вызовы 3. `b24jssdk-filtering` — если строите фильтры или list-запросы 4. `b24jssdk-frame-ui` — если работаете внутри iframe-приложения 5. `b24jssdk-helpers` — если используете helper-утилиты или Pull 6. `b24jssdk-recipes` — для готовых end-to-end примеров Не загружайте все skill'ы сразу — описания спроектированы для выборочного использования, чтобы контекст оставался сфокусированным. ## Дополнительно См. [AGENTS.md](https://github.com/bitrix24/b24jssdk/blob/main/AGENTS.md){rel=""nofollow""} — полная документация для контрибьюторов и агентов, включая команды, тестирование и ключевые конвенции. --- # LLMs.txt > Как сделать, чтобы AI-инструменты вроде Cursor, Windsurf, GitHub Copilot, ChatGPT и Claude понимали методы, инструменты и лучшие практики Bitrix24 JS SDK. ## Что такое LLMs.txt? LLMs.txt — это формат структурированной документации, разработанный специально для больших языковых моделей (LLM). Bitrix24 JS SDK предоставляет LLMs.txt-файлы с исчерпывающей информацией о библиотеке, чтобы AI-инструментам было проще понимать и помогать в разработке с Bitrix24 JS SDK. Эти файлы оптимизированы для потребления AI и содержат структурированную информацию о компонентах, API, паттернах использования и лучших практиках. ## Доступные маршруты Мы предоставляем LLMs.txt-маршруты, чтобы AI-инструменты могли обращаться к документации: - **`/llms.txt`** — содержит структурированный обзор всех компонентов и ссылки на их документацию (\~5К токенов) - **`/llms-full.txt`** — предоставляет исчерпывающую документацию, включая детали реализации, примеры, тематизацию, composables и руководство по миграции (\~1М+ токенов) ## Выбор подходящего файла > \[!NOTE] > > **Большинству пользователей следует начать с `/llms.txt`** — он содержит всю необходимую информацию и работает со стандартными контекстными окнами LLM. > > Используйте `/llms-full.txt` только если вам нужны исчерпывающие примеры реализации, а ваш AI-инструмент поддерживает большие контексты (200К+ токенов). ## Важные замечания по использованию > \[!WARNING] > > **Символ @ нужно вводить вручную** — при использовании Cursor или Windsurf символ `@` необходимо набирать руками в интерфейсе чата. Копирование-вставка ломает распознавание этого символа как контекстной ссылки. ## Использование с AI-инструментами ### Cursor Bitrix24 JS SDK предоставляет специализированные LLMs.txt-файлы, на которые можно ссылаться в Cursor для улучшения AI-помощи в разработке компонентов. #### Как использовать: 1. **Прямая ссылка**: упоминайте URL'ы LLMs.txt при формулировке вопросов 2. Добавьте эти URL'ы в контекст проекта через `@docs` [Подробнее о Cursor Web and Docs Search](https://docs.cursor.com/en/context/@-symbols/@-docs){rel=""nofollow""} ### Windsurf Windsurf может напрямую обращаться к LLMs.txt-файлам Bitrix24 JS SDK для понимания использования компонентов и лучших практик. #### Использование LLMs.txt с Windsurf: - Используйте `@docs` для ссылки на конкретные URL'ы LLMs.txt - Создавайте постоянные правила, ссылающиеся на эти URL'ы, в вашем workspace [Подробнее о Windsurf Web and Docs Search](https://docs.windsurf.com/windsurf/cascade/web-search){rel=""nofollow""} ### Другие AI-инструменты Любой AI-инструмент с поддержкой LLMs.txt может использовать эти маршруты для лучшего понимания Bitrix24 JS SDK. #### Примеры для ChatGPT, Claude и других LLM: - «Используя документацию Bitrix24 JS SDK из {rel=""nofollow""}» - «Следуйте полному руководству Bitrix24 JS SDK из {rel=""nofollow""}» --- # CallV2.make > Метод для вызовов REST API Bitrix24 версии 2. > \[!CAUTION] > > **Bitrix24 постепенно переходит на REST API версии 3**. > > - Где у метода есть форма v3, предпочитайте явную поверхность `actions.v3.*` — см. [доступные методы v3](https://apidocs.bitrix24.ru/api-reference/rest-v3/index.html){rel=""nofollow""}. ## Обзор Используйте `CallV2.make()` для вызова методов REST API версии 2. Метод возвращает `Promise` с объектом `AjaxResult`, содержащим данные ответа, статус и методы обработки ошибок. ```ts // Базовое использование import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk' const response = await $b24.actions.v2.call.make({ method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 123 }, requestId: 'unique-request-id' }) ``` ## Сигнатура метода ```ts-type make( options: ActionCallV2 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`method`** | `string` | Да | Имя метода REST API (например, `crm.item.get`, `tasks.task.get`). | | **`params`** | `TypeCallParams` | Нет | Объект с параметрами для передачи в метод REST API. | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект [`AjaxResult`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-result.ts){rel=""nofollow""}. Этот объект предоставляет: - `.getData(): SuccessPayload | undefined` — возвращает success-конверт `{ result: T, time: PayloadTime }` или `undefined`, если запрос провалился. Сначала проверьте `.isSuccess`. - `.isSuccess: boolean` — флаг успешного выполнения запроса. - `.getErrorMessages(): string[]` — массив сообщений об ошибках. ## Ключевые понятия ## Обработка ошибок Всегда проверяйте результат через `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const response = await $b24.actions.v2.call.make({ method: 'some.method', params: { /* some_params */ }, requestId: 'unique-request-id' }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData()?.result ``` ## Примеры ### Получение компании из CRM ```ts [call-rest-api-ver2.ts] import { B24Hook, EnumCrmEntityTypeId, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk' type Company = { id: number title: string [key: string]: any } const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:getCrmItem', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function getCrmItem(entityTypeId: number, itemId: number, requestId: string): Promise { const response = await $b24.actions.v2.call.make<{ item: Company }>({ method: 'crm.item.get', params: { entityTypeId: entityTypeId, id: itemId }, requestId }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } return (response.getData()!.result as { item: Company }).item } // Usage const itemId = 528 const requestId = `crm-item-${itemId}` try { const entity = await getCrmItem(EnumCrmEntityTypeId.company, itemId, requestId) $logger.info(`Entity [${entity?.id}]`, { entity }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ## Долгие запросы Тяжёлые неидемпотентные методы вроде `crm.documentgenerator.document.add` регулярно превышают аxios-таймаут 30 секунд по умолчанию. При таймауте SDK по умолчанию делает повторные запросы, что может создать **дубликаты сущностей** на стороне сервера (см. [issue #24](https://github.com/bitrix24/b24jssdk/issues/24){rel=""nofollow""}). Для любого метода, создающего или сохраняющего состояние, увеличьте axios-таймаут и отключите повторные запросы при транспортных ошибках: ```ts import { ApiVersion, ParamsFactory } from '@bitrix24/b24jssdk' // const $b24 = ... $b24.getHttpClient(ApiVersion.v2).ajaxClient.defaults.timeout = 120_000 await $b24.setRestrictionManagerParams({ ...ParamsFactory.getDefault(), retryOnNetworkError: false }) await $b24.actions.v2.call.make({ method: 'crm.documentgenerator.document.add', params: {/*…*/} }) ``` См. [Limiters — долгие запросы и неидемпотентные вызовы](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md#long-running-requests--non-idempotent-calls) для полного объяснения и альтернативных конфигураций. ## Альтернативы и рекомендации - **Для работы со списками:**вместо ручного управления пагинацией используйте: - [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) — автоматически получает все страницы и возвращает единый результат. - [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) — возвращает асинхронный генератор для поэтапной обработки больших списков. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). --- # CallV3.make > Метод для вызовов REST API Bitrix24 версии 3. ## Обзор Используйте `CallV3.make()` для вызова методов REST API версии 3. Метод возвращает `Promise` с объектом `AjaxResult`, содержащим данные ответа, статус и методы обработки ошибок. ```ts // Базовое использование const response = await $b24.actions.v3.call.make({ method: 'tasks.task.get', params: { id: 123 }, requestId: 'unique-request-id' }) ``` ## Сигнатура метода ```ts-type make( options: ActionCallV3 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`method`** | `string` | Да | Имя метода REST API (например, `tasks.task.get`, `tasks.task.add`). | | **`params`** | `TypeCallParams` | Нет | Объект с параметрами для передачи в метод REST API. | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект [`AjaxResult`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-result.ts){rel=""nofollow""}. Этот объект предоставляет: - `.getData(): SuccessPayload | undefined` — возвращает success-конверт `{ result: T, time: PayloadTime }` или `undefined`, если запрос провалился. Сначала проверьте `.isSuccess`. - `.isSuccess: boolean` — флаг успешного выполнения запроса. - `.getErrorMessages(): string[]` — массив сообщений об ошибках. ## Обработка ошибок SDK не держит клиентский список v3-методов: `CallV3.make()` отправляет любой переданный метод на v3-endpoint, и решает сервер. Если метод не является v3-методом, сервер отвечает `METHODNOTFOUNDEXCEPTION` как **soft-ошибкой** (`response.isSuccess === false`, сообщение в `getErrorMessages()`) — предварительного выброса на стороне SDK нет. Используйте `CallV2.make()` для legacy-методов или проверьте [`apidocs.bitrix24.ru`](https://apidocs.bitrix24.ru/api-reference/rest-v3/index.html){rel=""nofollow""} (либо собственный `rest.documentation.openapi` портала), что существует в v3. Для успешных запросов всегда проверяйте `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const response = await $b24.actions.v3.call.make({ method: 'some.method', params: { /* some_params */ }, requestId: 'unique-request-id' }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData()?.result ``` ## Примеры ### Получение задачи ```ts [call-rest-api-ver3.ts] import { B24Hook, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk' type Task = { id: number title: string autocompleteSubTasks: boolean } const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:taskGet', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function getTask(itemId: number, requestId: string): Promise { const response = await $b24.actions.v3.call.make<{ item: Task }>({ method: 'tasks.task.get', params: { id: itemId, select: ['id', 'title', 'autocompleteSubTasks'] }, requestId }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } return (response.getData()!.result as { item: Task }).item } // Usage const itemId = 2 const requestId = `task-${itemId}` try { const entity = await getTask(itemId, requestId) $logger.info(`Entity [${entity.id}]`, { entity }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ## Долгие запросы Неидемпотентные методы, создающие или сохраняющие состояние — например `tasks.task.add` — могут превысить axios-таймаут 30 секунд по умолчанию на нагруженном портале. При таймауте SDK по умолчанию делает повторные запросы, что может создать **дубликаты сущностей** на стороне сервера (см. [issue #24](https://github.com/bitrix24/b24jssdk/issues/24){rel=""nofollow""}). Для любого метода, создающего или сохраняющего состояние, увеличьте axios-таймаут и отключите повторные запросы при транспортных ошибках: ```ts import { ApiVersion, ParamsFactory } from '@bitrix24/b24jssdk' // const $b24 = ... $b24.getHttpClient(ApiVersion.v3).ajaxClient.defaults.timeout = 120_000 await $b24.setRestrictionManagerParams({ ...ParamsFactory.getDefault(), retryOnNetworkError: false }) await $b24.actions.v3.call.make({ method: 'tasks.task.add', params: {/*…*/} }) ``` См. [Limiters — долгие запросы и неидемпотентные вызовы](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md#long-running-requests--non-idempotent-calls) для полного объяснения и альтернативных конфигураций. ## Альтернативы и рекомендации - **Для работы со списками:**вместо ручного управления пагинацией используйте: - [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver3.md) — автоматически получает все страницы и возвращает единый результат. - [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md) — возвращает асинхронный генератор для поэтапной обработки больших списков. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver3.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). --- # CallListV2.make > Метод для быстрого получения всех данных из list-методов REST API Bitrix24 версии 2. > \[!CAUTION] > > **Bitrix24 постепенно переходит на REST API версии 3**. > > - При вызове методов, [доступных в REST API v3](https://apidocs.bitrix24.ru/api-reference/rest-v3/index.html){rel=""nofollow""}, метод автоматически выводит предупреждение. ## Обзор Когда нужно получить все записи из list-методов REST API версии 2 с максимальной эффективностью и вы готовы хранить полный набор данных в памяти, используйте `CallListV2.make()`. Метод автоматически обрабатывает пагинацию и возвращает все данные в едином массиве. > \[!NOTE] > > Для импорта, экспорта, обработки всех элементов и генерации отчётов рекомендуем использовать [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) — он возвращает асинхронный генератор для поэтапной обработки больших списков. ```ts // Базовое использование import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk' const response = await $b24.actions.v2.callList.make({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.deal, filter: { '>opportunity': 10000 } }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id' }) ``` ### Когда использовать CallListV2.make() 1. **Малые и средние объёмы данных**: когда общее число записей не превышает нескольких тысяч. 2. **Простая обработка**: когда нужен простой доступ ко всем данным сразу. 3. **Агрегация данных**: когда нужно выполнить операции над всем набором данных (суммирование, группировка и т.д.). ## Сигнатура метода ```ts-type make( options: ActionCallListV2 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`method`** | `string` | Да | Имя метода REST API, возвращающего список данных (например, `crm.contact.list`, `tasks.task.list`). | | **`params`** | `Omit` | Нет | Параметры запроса без параметров `start` и `order`. Параметр `start` зарезервирован, так как метод получает все данные одним вызовом. Параметр `order` зарезервирован, так как курсорной пагинации нужна строгая сортировка по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию — см. [Ограничения](https://bitrix-tools.github.io/b24jssdk/#limitations). Для сужения выборки используйте `filter` и `select`. | | **`idKey`** | `string` | Нет | Имя поля id **так, как оно приходит в каждом элементе ответа**; его значение управляет курсором. По умолчанию: `'ID'` (верхний регистр). Для методов, возвращающих id в нижнем/camelCase (например, `tasks.task.list` возвращает `id`), задайте `'id'`. | | **`cursorIdKey`** | `string` | Нет | Имя поля, используемое в **запросе** для `order` и постраничного фильтра `>`. По умолчанию равно `idKey`. Задавайте, только когда имя сортируемого / фильтруемого поля отличается от поля в ответе — например, `tasks.task.list` сортирует и фильтрует по `ID`, но возвращает `id`: передайте `idKey: 'id', cursorIdKey: 'ID'`. | | **`customKeyForResult`** | `string` | Нет | Ключ, по которому в ответе REST API будет выбран массив данных. Например: `items` для списка элементов CRM. | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект [`Result`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/result.ts){rel=""nofollow""}, содержащий массив всех полученных элементов. Этот объект предоставляет: - `.getData(): T[]` — возвращает массив всех полученных элементов. - `.isSuccess: boolean` — флаг успешного выполнения всех запросов. - `.getErrorMessages(): string[]` — массив сообщений об ошибках. ## Ключевые понятия ### Автоматическое предупреждение При вызове методов, которые **доступны в REST API версии 3**, система автоматически выводит предупреждение: ```json "The method {method_name} is available in restApi:v3. It's worth migrating to the new API." ``` Это указывает на то, что стоит рассмотреть миграцию на более новую версию REST API. ### Оптимизация производительности Метод реализует [рекомендованный Bitrix24 алгоритм](https://apidocs.bitrix24.ru/settings/performance/huge-data.html){rel=""nofollow""} для эффективной работы с большими объёмами данных: 1. `start: -1`: отключает подсчёт общего числа записей, значительно ускоряет выполнение запроса. 2. **Фильтрация по возрастающему id**: каждый следующий запрос использует фильтр `>cursorIdKey` с id последнего полученного элемента (читается через `idKey`). 3. **Автоматическое определение конца данных**: запросы останавливаются при получении пустого массива или если число элементов меньше размера страницы (`50`). ### Структура ответа REST API v2 В REST API версии 2 разные методы могут возвращать данные в разных структурах: - **Прямой массив**: `{ result: [...] }` - **Сгруппированный массив**: `{ result: { items: [...] } }` Параметр `customKeyForResult` позволяет указать ключ, по которому расположены данные в ответе. ### Ограничения - **Размер страницы**: фиксированное ограничение Bitrix24 REST API версии 2 — `50` записей на запрос. - **Сортировка фиксирована**: метод всегда сортирует по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию, потому что курсорная пагинация опирается на фильтр `>cursorIdKey` для прохождения по набору. Пользовательское значение `order` нарушило бы этот инвариант, поэтому сигнатура типа исключает `order`, а любое значение, переданное в runtime, отбрасывается с записью `warning` в лог. Для сужения выборки используйте `filter`. - **Только для list-методов**: предназначен только для методов, возвращающих массивы данных. ## Обработка ошибок Всегда проверяйте результат через `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const response = await $b24.actions.v2.callList.make({ method: 'some.method', params: { /* some_params */ }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id' }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData() ``` ## Примеры ### Получение всех компаний с фильтрацией ```ts [AllCrmItems.ts] import { B24Hook, EnumCrmEntityTypeId, LoggerFactory, Text, SdkError, AjaxError } from '@bitrix24/b24jssdk' type Company = { id: number title: string } const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:AllCrmItems', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function getCrmItemList(requestId: string): Promise { const sixMonthAgo = new Date() sixMonthAgo.setMonth((new Date()).getMonth() - 6) sixMonthAgo.setHours(0, 0, 0) const response = await $b24.actions.v2.callList.make({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.company, filter: { // фильтрация по названию '=%title': 'Prime%', '>=createdTime': Text.toB24Format(sixMonthAgo) // созданы как минимум 6 месяцев назад }, select: ['id', 'title'] }, idKey: 'id', customKeyForResult: 'items', requestId }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } return response.getData() ?? [] } // Использование const requestId = 'some-crm-item-list' try { const list = await getCrmItemList(requestId) $logger.info(`List [${list?.length}]`, { requestId, list }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ### Получение всех записей `tasks.task.list` (поле запроса ≠ поле ответа) `tasks.task.list` сортирует и фильтрует по `ID` (верхний регистр), но возвращает каждую задачу с `id` в нижнем регистре. Задайте `idKey` на поле **ответа**, а `cursorIdKey` — на поле **запроса**: ```ts [AllTasks.ts] type TaskListItem = { id: string, title: string } const response = await $b24.actions.v2.callList.make({ method: 'tasks.task.list', params: { filter: { RESPONSIBLE_ID: 1 }, // поля фильтра задач в верхнем регистре select: ['ID', 'TITLE'] // выбираем в верхнем регистре, но в ответе id / title в нижнем }, idKey: 'id', // читаем task.id из ответа cursorIdKey: 'ID', // order + постраничный фильтр ">ID" в запросе customKeyForResult: 'tasks' }) console.log(`Loaded ${response.getData()?.length ?? 0} tasks`) ``` Без `cursorIdKey` значение `idKey: 'ID'` по умолчанию невозможно прочитать из ответа в нижнем регистре, поэтому пагинация остановится после первых 50 задач — и SDK залогирует `warning`, указывающий сюда. ## Альтернативы и рекомендации - **Для работы со списками:**вместо ручного управления пагинацией используйте: - [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) — возвращает асинхронный генератор для поэтапной обработки больших списков. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). - **См. также:** [Фильтрация](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/filtering.md) — построение `filter` (и почему `order` отбрасывается). --- # CallListV3.make > Метод для быстрого получения всех данных из list-методов REST API Bitrix24 версии 3. > \[!NOTE] > > Важно отметить, что REST API версии 3 позволяет получать до 1000 элементов за один запрос через параметр пагинации `parameter: { limit: 1000, page: 1 }`. ## Обзор Когда нужно получить все записи из list-методов REST API версии 3 с максимальной эффективностью и вы готовы хранить полный набор данных в памяти, используйте `CallListV3.make()`. Метод автоматически обрабатывает пагинацию и возвращает все данные в едином массиве. > \[!NOTE] > > Для импорта, экспорта, обработки всех элементов и генерации отчётов рекомендуем использовать [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md) — он возвращает асинхронный генератор для поэтапной обработки больших списков. ```ts // Базовое использование const response = await $b24.actions.v3.callList.make({ method: 'main.eventlog.list', params: { filter: [ ['userId', '=', 1] ], select: ['id', 'userId'] }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id', limit: 600 }) ``` ### Когда использовать CallListV3.make() 1. **Малые и средние объёмы данных**: когда общее число записей не превышает нескольких тысяч. 2. **Простая обработка**: когда нужен простой доступ ко всем данным сразу. ## Сигнатура метода ```ts-type make( options: ActionCallListV3 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`method`** | `string` | Да | Имя метода REST API, возвращающего список данных (например, `crm.contact.list`, `tasks.task.list`). | | **`params`** | `Omit` | Нет | Параметры запроса без `pagination` и `order`. Параметр `pagination` зарезервирован, так как метод получает все данные одним вызовом. Параметр `order` зарезервирован, так как курсорной пагинации нужна строгая сортировка по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию — см. [Ограничения](https://bitrix-tools.github.io/b24jssdk/#limitations). Для сужения выборки используйте `filter` и `select`. | | **`idKey`** | `string` | Нет | Имя поля id **так, как оно приходит в каждом элементе ответа**; его значение управляет курсором. По умолчанию: `'id'`. Задайте под то поле id, которое возвращает метод. | | **`cursorIdKey`** | `string` | Нет | Имя поля, используемое в **запросе** для `order` и постраничного фильтра `[field, '>', n]`. По умолчанию равно `idKey`. Задавайте, только когда имя сортируемого / фильтруемого поля отличается от поля в ответе (например, поле запроса в верхнем регистре, а id в ответе в нижнем): передайте `idKey: 'id', cursorIdKey: 'ID'`. | | **`customKeyForResult`** | `string` | Да | Ключ, по которому в ответе REST API будет выбран массив данных. Например: `items` для списка элементов CRM. | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | | **`limit`** | `number` | Нет | Сколько записей получать за раз. По умолчанию `50`. Максимум `1000`. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект [`Result`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/result.ts){rel=""nofollow""}, содержащий массив всех полученных элементов. Этот объект предоставляет: - `.getData(): T[]` — возвращает массив всех полученных элементов. - `.isSuccess: boolean` — флаг успешного выполнения всех запросов. - `.getErrorMessages(): string[]` — массив сообщений об ошибках. ## Ключевые понятия ### Оптимизация производительности Метод реализует [рекомендованный Bitrix24 алгоритм](https://apidocs.bitrix24.ru/settings/performance/huge-data.html){rel=""nofollow""} для эффективной работы с большими объёмами данных: 1. **Фильтрация по возрастающему id**: каждый следующий запрос использует фильтр `[cursorIdKey, '>', id]` с id последнего полученного элемента (читается через `idKey`). 2. **Автоматическое определение конца данных**: запросы останавливаются при получении пустого массива или когда страница короче самой большой из виденных. Это привязывает остановку к размеру страницы, который реально возвращает сервер, а не к запрошенному `options.limit`, поэтому метод, молча ограничивающий страницу ниже `limit` (например, `tasks.task.list`, зафиксирован на 50), всё равно проходит все записи, а не останавливается после первой урезанной страницы. ### Структура ответа REST API v3 > \[!NOTE] > > Параметр `customKeyForResult` сохранён для обратной совместимости. В будущем после анализа реального использования будет принято решение о его необходимости. В REST API версии 3 разные методы возвращают данные в одинаковых структурах: - **Сгруппированный массив**: `{ result: { items: [...] } }` Параметр `customKeyForResult` позволяет указать ключ, по которому расположены данные в ответе. > \[!NOTE] > > Некоторые v3 list-методы (например, `note.*`) также возвращают в конверте ответа поле `nextCursor` рядом с `items` — `{ result: { nextCursor, items: [...] } }`. Читать или передавать его **не** нужно: `CallListV3.make()` листает собственным курсором по `idKey` (внедрённый фильтр `[idField, '>', n]`) и проходит все страницы независимо от `nextCursor`. Поле информационное; SDK его игнорирует. ### Ограничения - **Размер страницы**: ограничение Bitrix24 REST API версии 3 — максимум `1000` записей на запрос. - **Сортировка фиксирована**: метод всегда сортирует по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию, потому что курсорная пагинация опирается на фильтры `[cursorIdKey, '>', nextId]` для прохождения по набору. Пользовательское значение `order` нарушило бы этот инвариант, поэтому сигнатура типа исключает `order`, а любое значение, переданное в runtime, отбрасывается с записью `warning` в лог. Для сужения выборки используйте `filter`. - **Только для list-методов**: предназначен только для методов, возвращающих массивы данных. ## Обработка ошибок Всегда проверяйте результат через `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const response = await $b24.actions.v3.callList.make({ method: 'some.method', params: { /* some_params */ }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id', limit: 600 }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData() ``` ## Примеры ### Получение всех элементов журнала событий с фильтрацией ```ts [AllMainEventLogItems.ts] import { B24Hook, LoggerFactory, Text, SdkError, AjaxError } from '@bitrix24/b24jssdk' type MainEventLogItem = { id: number userId: number } const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:AllMainEventLogItems', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function getMainEventLogItemList(requestId: string): Promise { const sixMonthAgo = new Date() sixMonthAgo.setMonth((new Date()).getMonth() - 6) sixMonthAgo.setHours(0, 0, 0) const response = await $b24.actions.v3.callList.make({ method: 'main.eventlog.list', params: { filter: [ ['timestampX', '>=', Text.toB24Format(sixMonthAgo)] // созданы как минимум 6 месяцев назад ], select: ['id', 'userId'] }, idKey: 'id', customKeyForResult: 'items', requestId, limit: 60 }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } return response.getData() ?? [] } // Использование const requestId = 'some-main-event-log-item-list' try { const list = await getMainEventLogItemList(requestId) $logger.info(`List [${list?.length}]`, { requestId, list }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ### Когда поля id в запросе и ответе различаются Некоторые методы сортируют / фильтруют по одному имени поля, но возвращают другое (например, `ID` в верхнем регистре в запросе против `id` в нижнем в payload). Задайте `idKey` на поле **ответа**, а `cursorIdKey` — на поле **запроса**: ```ts const response = await $b24.actions.v3.callList.make({ method: 'some.list', params: { select: ['ID', 'TITLE'] }, idKey: 'id', // читаем id из каждого возвращённого элемента cursorIdKey: 'ID', // order + постраничный фильтр ["ID", ">", n] в запросе customKeyForResult: 'items' }) ``` Если `idKey` не удаётся прочитать из полной страницы, SDK логирует `warning` и прекращает пагинацию, вместо того чтобы молча обрезать данные. ## Альтернативы и рекомендации - **Для работы со списками:**вместо ручного управления пагинацией используйте: - [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md) — возвращает асинхронный генератор для поэтапной обработки больших списков. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver3.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). - **См. также:** [Фильтрация](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/filtering.md) — построение `filter` (и почему `order` отбрасывается). --- # FetchListV2.make > Возвращает AsyncGenerator, позволяющий обрабатывать данные из list-методов REST API Bitrix24 версии 2 по мере поступления, не загружая весь массив в память сразу. Особенно полезно при работе с очень большими объёмами данных. > \[!CAUTION] > > **Bitrix24 постепенно переходит на REST API версии 3**. > > - При вызове методов, [доступных в REST API v3](https://apidocs.bitrix24.ru/api-reference/rest-v3/index.html){rel=""nofollow""}, метод автоматически выводит предупреждение. ## Обзор Когда нужно обработать большие объёмы данных из list-методов REST API версии 2 по частям (чанками), используйте `FetchListV2.make()`. Метод реализует быстрый алгоритм итерации по большим наборам данных без загрузки всех данных в память сразу. Каждая итерация возвращает следующую страницу/пакет результатов, пока не получены все данные. ```ts // Базовое использование import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk' const generator = $b24.actions.v2.fetchList.make({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.deal, filter: { '>opportunity': 10000 } }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id' }) for await (const chunk of generator) { // Обработка чанка (например, сохранение в БД, анализ и т.д.) console.log(`Processing ${chunk.length} items`) } ``` ### Когда использовать FetchListV2.make() 1. **Очень большие объёмы данных**: когда число записей в тысячах или десятках тысяч. 2. **Потоковая обработка**: когда данные нужно обрабатывать по мере поступления. 3. **Длительные операции**: когда обработка каждой записи требует значительного времени. ## Сигнатура метода ```ts-type make( options: ActionFetchListV2 ): AsyncGenerator ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`method`** | `string` | Да | Имя метода REST API, возвращающего список данных (например, `crm.contact.list`, `tasks.task.list`). | | **`params`** | `Omit` | Нет | Параметры запроса без параметров `start` и `order`. Параметр `start` зарезервирован, так как метод получает все данные одним вызовом. Параметр `order` зарезервирован, так как курсорной пагинации нужна строгая сортировка по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию — см. [Ограничения](https://bitrix-tools.github.io/b24jssdk/#limitations). Для сужения выборки используйте `filter` и `select`. | | **`idKey`** | `string` | Нет | Имя поля id **так, как оно приходит в каждом элементе ответа**; его значение управляет курсором. По умолчанию: `'ID'` (верхний регистр). Для методов, возвращающих id в нижнем/camelCase (например, `tasks.task.list` возвращает `id`), задайте `'id'`. | | **`cursorIdKey`** | `string` | Нет | Имя поля, используемое в **запросе** для `order` и постраничного фильтра `>`. По умолчанию равно `idKey`. Задавайте, только когда имя сортируемого / фильтруемого поля отличается от поля в ответе — например, `tasks.task.list` сортирует и фильтрует по `ID`, но возвращает `id`: передайте `idKey: 'id', cursorIdKey: 'ID'`. | | **`customKeyForResult`** | `string` | Нет | Ключ, по которому в ответе REST API будет выбран массив данных. Например: `items` для списка элементов CRM. | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `AsyncGenerator` — асинхронный генератор, возвращающий чанки данных в виде массивов типа `T`. Каждая итерация генератора возвращает: - Массив элементов (чанк) до `50` записей. - Генератор завершается, когда все данные получены. ## Ключевые понятия ### Автоматическое предупреждение При вызове методов, которые **доступны в REST API версии 3**, система автоматически выводит предупреждение: ```json "The method {method_name} is available in restApi:v3. It's worth migrating to the new API." ``` Это указывает на то, что стоит рассмотреть миграцию на более новую версию REST API. ### AsyncGenerator vs Promise В отличие от `CallListV2.make()`, который возвращает `Promise` со всеми данными сразу, `FetchListV2.make()` возвращает асинхронный генератор: | Аспект | `CallListV2.make()` | `FetchListV2.make()` | | --- | --- | --- | | **Возвращаемое значение** | `Promise>` | `AsyncGenerator` | | **Память** | Загружает все данные в память | Обрабатывает данные по частям | | **Использование** | `await response.getData()` | `for await (const chunk of generator)` | | **Подходит для** | Малые и средние объёмы данных | Очень большие объёмы данных | ### Оптимизация производительности Метод реализует [рекомендованный Bitrix24 алгоритм](https://apidocs.bitrix24.ru/settings/performance/huge-data.html){rel=""nofollow""} для эффективной работы с большими объёмами данных: 1. `start: -1`: отключает подсчёт общего числа записей, значительно ускоряет выполнение запроса. 2. **Фильтрация по возрастающему id**: каждый следующий запрос использует фильтр `>cursorIdKey` с id последнего полученного элемента (читается через `idKey`). 3. **Потоковая обработка**: данные обрабатываются по мере поступления, экономя память. 4. **Автоматическое определение конца данных**: запросы останавливаются при получении пустого массива или если число элементов меньше размера страницы (`50`). ### Структура ответа REST API v2 В REST API версии 2 разные методы могут возвращать данные в разных структурах: - **Прямой массив**: `{ result: [...] }` - **Сгруппированный массив**: `{ result: { items: [...] } }` Параметр `customKeyForResult` позволяет указать ключ, по которому расположены данные в ответе. ### Ограничения - **Размер страницы**: фиксированное ограничение Bitrix24 REST API версии 2 — `50` записей на запрос. - **Сортировка фиксирована**: метод всегда сортирует по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию, потому что курсорная пагинация опирается на фильтр `>cursorIdKey` для прохождения по набору. Пользовательское значение `order` нарушило бы этот инвариант, поэтому сигнатура типа исключает `order`, а любое значение, переданное в runtime, отбрасывается с записью `warning` в лог. Для сужения выборки используйте `filter`. - **Только для list-методов**: предназначен только для методов, возвращающих массивы данных. ## Обработка ошибок Поскольку метод возвращает асинхронный генератор, ошибки обрабатываются иначе, чем в `CallListV2.make()`: ```ts import { SdkError } from '@bitrix24/b24jssdk' try { const generator = $b24.actions.v2.fetchList.make({ method: 'some.method', params: { /* some_params */ }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id' }) for await (const chunk of generator) { // Обработка чанка (например, сохранение в БД, анализ и т.д.) console.log(`Processing ${chunk.length} items`) } } catch (error) { // Обработка ошибки if ( error instanceof SdkError && error.code === 'JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V2' ) { console.error(`${error.message}`, { code: error.code }) } else { console.error('Some error', error) } } ``` ## Примеры ### Поэтапная обработка большого числа компаний ```ts [ProcessCrmItems.ts] import { B24Hook, EnumCrmEntityTypeId, LoggerFactory, Text, SdkError, AjaxError } from '@bitrix24/b24jssdk' type Company = { id: number title: string } const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:ProcessCrmItems', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function processCrmItemList(): Promise { let batchNumber = 0 let totalItems = 0 const sixMonthAgo = new Date() sixMonthAgo.setMonth((new Date()).getMonth() - 6) sixMonthAgo.setHours(0, 0, 0) const requestId = 'some-crm-item-list' try { const generator = $b24.actions.v2.fetchList.make({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.company, filter: { // фильтрация по названию '=%title': 'Prime%', '>=createdTime': Text.toB24Format(sixMonthAgo) // созданы как минимум 6 месяцев назад }, select: ['id', 'title'] }, idKey: 'id', customKeyForResult: 'items', requestId }) for await (const chunk of generator) { batchNumber++ totalItems += chunk.length $logger.info(`Processing batch #${batchNumber}`, { batchSize: chunk.length, totalSoFar: totalItems }) // Пример: сохранение в базу данных await saveToDatabase(chunk) // Пример: отправка в очередь сообщений await sendToMessageQueue(chunk) } $logger.notice(`Processed ${totalItems} elements in ${batchNumber} batches`) } catch (error) { if (error instanceof SdkError) { $logger.error(`Processing error: ${error.message}`, { code: error.code, batchNumber, totalItems }) } else { $logger.error('Unknown error', { error, batchNumber, totalItems }) } throw error } } // Вспомогательные функции // Реализация сохранения в базу данных async function saveToDatabase(items: Company[]): Promise { await new Promise(resolve => setTimeout(resolve, 100)) // Simulation } // Реализация отправки в очередь сообщений async function sendToMessageQueue(items: Company[]): Promise { await new Promise(resolve => setTimeout(resolve, 50)) // Simulation } // Использование try { await processCrmItemList() } catch (error) { $logger.critical('A problem occurred', { error }) } ``` ### Пагинация `tasks.task.list` (поле запроса ≠ поле ответа) `tasks.task.list` сортирует и фильтрует по `ID` (верхний регистр), но возвращает каждую задачу с `id` в нижнем регистре. Задайте `idKey` на поле **ответа**, а `cursorIdKey` — на поле **запроса**: курсор тогда читает последний `id` со страницы и запрашивает следующий с `>ID`: ```ts [ProcessAllTasks.ts] type TaskListItem = { id: string, title: string } const generator = $b24.actions.v2.fetchList.make({ method: 'tasks.task.list', params: { filter: { RESPONSIBLE_ID: 1 }, // поля фильтра задач в верхнем регистре select: ['ID', 'TITLE'] // выбираем в верхнем регистре, но в ответе id / title в нижнем }, idKey: 'id', // читаем task.id из ответа cursorIdKey: 'ID', // order + постраничный фильтр ">ID" в запросе customKeyForResult: 'tasks' }) let total = 0 for await (const chunk of generator) { total += chunk.length } console.log(`Processed ${total} tasks`) ``` Без `cursorIdKey` значение `idKey: 'ID'` по умолчанию невозможно прочитать из ответа в нижнем регистре, поэтому пагинация остановится после первых 50 задач — и SDK залогирует `warning`, указывающий сюда. ## Альтернативы и рекомендации - **Размер чанка**: Bitrix24 REST API версии 2 всегда возвращает до 50 записей на запрос. - **Оптимальная параллельность**: при обработке данных из генератора рекомендуется ограниченная параллельность (3–5 одновременных операций). - **Обработка ошибок**: всегда обрабатывайте ошибки внутри цикла `for await...of`, чтобы предотвратить прерывание всего процесса. - **Мониторинг прогресса**: внедряйте логирование прогресса для длительных операций. - **Для последовательных запросов**: используйте [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md) для одиночных вызовов. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). - **См. также:** [Фильтрация](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/filtering.md) — построение `filter` (и почему `order` отбрасывается). --- # FetchListV3.make > Возвращает AsyncGenerator, позволяющий обрабатывать данные из list-методов REST API Bitrix24 версии 3 по мере поступления, не загружая весь массив в память сразу. Особенно полезно при работе с очень большими объёмами данных. ## Обзор Когда нужно обработать большие объёмы данных из list-методов REST API версии 3 по частям (чанками), используйте `FetchListV3.make()`. Метод реализует быстрый алгоритм итерации по большим наборам данных без загрузки всех данных в память сразу. Каждая итерация возвращает следующую страницу/пакет результатов, пока не получены все данные. ```ts // Базовое использование const generator = $b24.actions.v3.fetchList.make({ method: 'main.eventlog.list', params: { filter: [ ['userId', '=', 1] ], select: ['id', 'userId'] }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id', limit: 600 }) for await (const chunk of generator) { // Обработка чанка (например, сохранение в БД, анализ и т.д.) console.log(`Processing ${chunk.length} items`) } ``` ### Когда использовать FetchListV3.make() 1. **Очень большие объёмы данных**: когда число записей в тысячах или десятках тысяч. 2. **Потоковая обработка**: когда данные нужно обрабатывать по мере поступления. 3. **Длительные операции**: когда обработка каждой записи требует значительного времени. ## Сигнатура метода ```ts-type make( options: ActionFetchListV3 ): AsyncGenerator ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`method`** | `string` | Да | Имя метода REST API, возвращающего список данных (например, `crm.contact.list`, `tasks.task.list`). | | **`params`** | `Omit` | Нет | Параметры запроса без `pagination` и `order`. Параметр `pagination` зарезервирован, так как метод получает все данные одним вызовом. Параметр `order` зарезервирован, так как курсорной пагинации нужна строгая сортировка по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию — см. [Ограничения](https://bitrix-tools.github.io/b24jssdk/#limitations). Для сужения выборки используйте `filter` и `select`. | | **`idKey`** | `string` | Нет | Имя поля id **так, как оно приходит в каждом элементе ответа**; его значение управляет курсором. По умолчанию: `'id'`. Задайте под то поле id, которое возвращает метод. | | **`cursorIdKey`** | `string` | Нет | Имя поля, используемое в **запросе** для `order` и постраничного фильтра `[field, '>', n]`. По умолчанию равно `idKey`. Задавайте, только когда имя сортируемого / фильтруемого поля отличается от поля в ответе (например, поле запроса в верхнем регистре, а id в ответе в нижнем): передайте `idKey: 'id', cursorIdKey: 'ID'`. | | **`customKeyForResult`** | `string` | Да | Ключ, по которому в ответе REST API будет выбран массив данных. Например: `items` для списка элементов CRM. | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | | **`limit`** | `number` | Нет | Сколько записей получать за раз. По умолчанию `50`. Максимум `1000`. | ### Возвращаемое значение `AsyncGenerator` — асинхронный генератор, возвращающий чанки данных в виде массивов типа `T`. Каждая итерация генератора возвращает: - Массив элементов (чанк) до `options.limit` записей. - Генератор завершается, когда все данные получены. ## Ключевые понятия ### AsyncGenerator vs Promise В отличие от `CallListV3.make()`, который возвращает `Promise` со всеми данными сразу, `FetchListV3.make()` возвращает асинхронный генератор: | Аспект | `CallListV3.make()` | `FetchListV3.make()` | | --- | --- | --- | | **Возвращаемое значение** | `Promise>` | `AsyncGenerator` | | **Память** | Загружает все данные в память | Обрабатывает данные по частям | | **Использование** | `await response.getData()` | `for await (const chunk of generator)` | | **Подходит для** | Малые и средние объёмы данных | Очень большие объёмы данных | ### Оптимизация производительности Метод реализует [рекомендованный Bitrix24 алгоритм](https://apidocs.bitrix24.ru/settings/performance/huge-data.html){rel=""nofollow""} для эффективной работы с большими объёмами данных: 1. **Фильтрация по возрастающему id**: каждый следующий запрос использует фильтр `[cursorIdKey, '>', id]` с id последнего полученного элемента (читается через `idKey`). 2. **Потоковая обработка**: данные обрабатываются по мере поступления, экономя память. 3. **Автоматическое определение конца данных**: запросы останавливаются при получении пустого массива или когда страница короче самой большой из виденных. Это привязывает остановку к размеру страницы, который реально возвращает сервер, а не к запрошенному `options.limit`, поэтому метод, молча ограничивающий страницу ниже `limit` (например, `tasks.task.list`, зафиксирован на 50), всё равно проходит все записи, а не останавливается после первой урезанной страницы. ### Структура ответа REST API v3 > \[!NOTE] > > Параметр `customKeyForResult` сохранён для обратной совместимости. В будущем после анализа реального использования будет принято решение о его необходимости. В REST API версии 3 разные методы возвращают данные в одинаковых структурах: - **Сгруппированный массив**: `{ result: { items: [...] } }` Параметр `customKeyForResult` позволяет указать ключ, по которому расположены данные в ответе. > \[!NOTE] > > Некоторые v3 list-методы (например, `note.*`) также возвращают в конверте ответа поле `nextCursor` рядом с `items` — `{ result: { nextCursor, items: [...] } }`. Читать или передавать его **не** нужно: `FetchListV3.make()` листает собственным курсором по `idKey` (внедрённый фильтр `[idField, '>', n]`) и проходит все страницы независимо от `nextCursor`. Поле информационное; SDK его игнорирует. ### Ограничения - **Размер страницы**: ограничение Bitrix24 REST API версии 3 — максимум `1000` записей на запрос. - **Сортировка фиксирована**: метод всегда сортирует по `cursorIdKey` (по умолчанию равен `idKey`) по возрастанию, потому что курсорная пагинация опирается на фильтры `[cursorIdKey, '>', nextId]` для прохождения по набору. Пользовательское значение `order` нарушило бы этот инвариант, поэтому сигнатура типа исключает `order`, а любое значение, переданное в runtime, отбрасывается с записью `warning` в лог. Для сужения выборки используйте `filter`. - **Только для list-методов**: предназначен только для методов, возвращающих массивы данных. ## Обработка ошибок Поскольку метод возвращает асинхронный генератор, ошибки обрабатываются иначе, чем в `CallListV3.make()`: ```ts import { SdkError } from '@bitrix24/b24jssdk' try { const generator = $b24.actions.v3.fetchList.make({ method: 'some.method', params: { /* some_params */ }, idKey: 'id', customKeyForResult: 'items', requestId: 'unique-request-id', limit: 600 }) for await (const chunk of generator) { // Обработка чанка (например, сохранение в БД, анализ и т.д.) console.log(`Processing ${chunk.length} items`) } } catch (error) { // Обработка ошибки if ( error instanceof SdkError && error.code === 'JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V3' ) { console.error(`${error.message}`, { code: error.code }) } else { console.error('Some error', error) } } ``` ## Примеры ### Поэтапная обработка большого числа элементов журнала событий ```ts [ProcessMainEventLogItems.ts] import { B24Hook, LoggerFactory, Text, SdkError, AjaxError } from '@bitrix24/b24jssdk' type MainEventLogItem = { id: number userId: number } const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:ProcessMainEventLogItems', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function processMainEventLogItem(): Promise { let batchNumber = 0 let totalItems = 0 const sixMonthAgo = new Date() sixMonthAgo.setMonth((new Date()).getMonth() - 6) sixMonthAgo.setHours(0, 0, 0) const requestId = 'some-main-event-log-item-list' try { const generator = $b24.actions.v3.fetchList.make({ method: 'main.eventlog.list', params: { filter: [ ['timestampX', '>=', Text.toB24Format(sixMonthAgo)] // созданы как минимум 6 месяцев назад ], select: ['id', 'userId'] }, idKey: 'id', customKeyForResult: 'items', requestId, limit: 60 }) for await (const chunk of generator) { batchNumber++ totalItems += chunk.length $logger.info(`Processing batch #${batchNumber}`, { batchSize: chunk.length, totalSoFar: totalItems }) // Пример: сохранение в базу данных await saveToDatabase(chunk) // Пример: отправка в очередь сообщений await sendToMessageQueue(chunk) } $logger.notice(`Processed ${totalItems} elements in ${batchNumber} batches`) } catch (error) { if (error instanceof SdkError) { $logger.error(`Processing error: ${error.message}`, { code: error.code, batchNumber, totalItems }) } else { $logger.error('Unknown error', { error, batchNumber, totalItems }) } throw error } } // Вспомогательные функции // Реализация сохранения в базу данных async function saveToDatabase(items: MainEventLogItem[]): Promise { await new Promise(resolve => setTimeout(resolve, 100)) // Simulation } // Реализация отправки в очередь сообщений async function sendToMessageQueue(items: MainEventLogItem[]): Promise { await new Promise(resolve => setTimeout(resolve, 50)) // Simulation } // Использование try { await processMainEventLogItem() } catch (error) { $logger.critical('A problem occurred', { error }) } ``` ### Когда поля id в запросе и ответе различаются Некоторые методы сортируют / фильтруют по одному имени поля, но возвращают другое (например, `ID` в верхнем регистре в запросе против `id` в нижнем в payload). Задайте `idKey` на поле **ответа**, а `cursorIdKey` — на поле **запроса**: ```ts const generator = $b24.actions.v3.fetchList.make({ method: 'some.list', params: { select: ['ID', 'TITLE'] }, idKey: 'id', // читаем id из каждого возвращённого элемента cursorIdKey: 'ID', // order + постраничный фильтр ["ID", ">", n] в запросе customKeyForResult: 'items' }) for await (const chunk of generator) { console.log(`Got ${chunk.length} records`) } ``` Если `idKey` не удаётся прочитать из полной страницы, SDK логирует `warning` и прекращает пагинацию, вместо того чтобы молча обрезать данные. ## Альтернативы и рекомендации - **Размер чанка**: каждый чанк вмещает до `options.limit` записей (по умолчанию `50`, макс `1000`). Большие чанки — меньше HTTP-запросов, но больше нагрузки на память на каждой итерации. - **Оптимальная параллельность**: при обработке данных из генератора рекомендуется ограниченная параллельность (3–5 одновременных операций). - **Обработка ошибок**: всегда обрабатывайте ошибки внутри цикла `for await...of`, чтобы предотвратить прерывание всего процесса. - **Мониторинг прогресса**: внедряйте логирование прогресса для длительных операций. - **Для последовательных запросов**: используйте [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver3.md) для одиночных вызовов. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver3.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). - **См. также:** [Фильтрация](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/filtering.md) — построение `filter` (и почему `order` отбрасывается). --- # Класс B24Hook > Серверная точка входа для работы с REST API Bitrix24 через входящий вебхук (постоянный токен). > \[!CAUTION] > > Объект `B24Hook` предназначен **исключительно для использования на сервере**. > > - URL вебхука содержит секретный ключ доступа. **Он никогда не должен попадать в клиентский код (браузер, мобильное приложение)**. > - Для клиентской стороны используйте [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame.md). > - HTTP-клиент по умолчанию создаётся с включённым предупреждением о клиентской стороне — см. [`offClientSideWarning`](https://bitrix-tools.github.io/b24jssdk/#offclientsidewarning). ## Обзор `B24Hook` — это класс SDK для работы с REST API Bitrix24 через входящий вебхук. Вебхук — это URL, который уже содержит идентификатор пользователя и секретный токен, поэтому запросы аутентифицируются без OAuth-рукопожатия. Класс наследуется от `AbstractB24` и реализует [`TypeB24`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/b24.ts){rel=""nofollow""}, поэтому полный набор REST-методов (`actions.v2.*`, `actions.v3.*`, `tools.*`) доступен сразу после создания экземпляра — шаг `await b24.init()` не требуется. ## Создание экземпляра B24Hook Создать экземпляр `B24Hook` можно двумя способами. ### Из полного URL вебхука Рекомендуемый способ, когда URL вебхука хранится в одной переменной окружения. ```ts import { B24Hook } from '@bitrix24/b24jssdk' const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/k32t88gf3azpmwv3/') ``` #### Сигнатура метода ```ts-type static fromWebhookUrl( url: string, options?: { restrictionParams?: Partial } ): B24Hook ``` #### Параметры | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | `url` | `string` | Да | Полный URL вебхука. Поддерживаются оба формата URL: `/rest//` (REST v2) и `/rest/api//` (REST v3). | | `options.restrictionParams` | `Partial` | Нет | Переопределение конфигурации rate limit / operating limit / адаптивной задержки, заданной по умолчанию. См. [Лимитеры](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md). | Статическая фабрика валидирует URL: требуется HTTPS, путь должен соответствовать одному из поддерживаемых форматов, а идентификатор пользователя должен быть числовым. Всё остальное синхронно выбрасывает исключение. ### Из параметров Используйте этот конструктор, когда части вебхука хранятся раздельно (например: URL портала в одной переменной окружения, токен — в менеджере секретов). ```ts import { B24Hook } from '@bitrix24/b24jssdk' const $b24 = new B24Hook({ b24Url: 'https://your_domain.bitrix24.com', userId: 1, secret: 'k32t88gf3azpmwv3' }) ``` #### Сигнатура конструктора ```ts-type constructor( b24HookParams: B24HookParams, options?: { restrictionParams?: Partial } ) ``` #### Поля `B24HookParams` | Поле | Тип | Описание | | --- | --- | --- | | `b24Url` | `string` | URL портала Bitrix24 (`https://your_domain.bitrix24.com`). | | `userId` | `number` | Идентификатор пользователя, которому принадлежит вебхук. | | `secret` | `string` | Секретный токен вебхука. | ## Быстрый пример ```ts import { B24Hook, EnumCrmEntityTypeId, LoggerFactory } from '@bitrix24/b24jssdk' const $logger = LoggerFactory.createForBrowser('node:hook', process.env.NODE_ENV === 'development') if (!process.env.B24_HOOK) { throw new Error('B24_HOOK env variable is required') } const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK) const response = await $b24.actions.v2.call.make<{ id: number, title: string }>({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.company, select: ['id', 'title'] }, requestId: 'companies-list' }) if (!response.isSuccess) { $logger.error('REST error', { messages: response.getErrorMessages() }) process.exit(1) } $logger.info('Companies', response.getData()?.result) ``` ## Геттеры ### `auth` ```ts-type get auth(): AuthActions ``` Возвращает экземпляр [`AuthHookManager`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/hook/auth.ts){rel=""nofollow""}, который реализует [`AuthActions`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/auth.ts){rel=""nofollow""}: - `getAuthData()` — возвращает синтетический `AuthData`, собранный из секрета вебхука. `expires` всегда равен `0` (токены вебхуков не истекают). - `refreshAuth()` — для совместимости с `B24OAuth`; возвращает те же данные без сетевого запроса. - `getUniq(prefix: string)` — возвращает `_`, используется Pull-клиентом и другими хелперами. - `isAdmin` — всегда `true` (предполагается, что вебхуки создаются администраторами). ### `isInit` ```ts-type get isInit(): boolean ``` Всегда `true` сразу после создания экземпляра — вызов `init()` для `B24Hook` не требуется. ### `actions` / `tools` Та же структура, что и у каждого класса `TypeB24`. См.: - [`CallV2.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md) / [`CallV3.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver3.md) - [`CallListV2.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) / [`CallListV3.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver3.md) - [`FetchListV2.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) / [`FetchListV3.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md) - [`BatchV2.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md) / [`BatchV3.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver3.md) - [`BatchByChunkV2.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-by-chunk-rest-api-ver2.md) / [`BatchByChunkV3.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-by-chunk-rest-api-ver3.md) - [`tools.healthCheck.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-health-check.md), [`tools.ping.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-ping.md) ## Методы ### `getTargetOrigin` ```ts-type getTargetOrigin(): string ``` Возвращает origin портала (`https://your_domain.bitrix24.com`). ### `getTargetOriginWithPath` ```ts-type getTargetOriginWithPath(): Map ``` Возвращает REST-endpoint для каждой версии: - `ApiVersion.v2` → `https://your_domain.bitrix24.com/rest//` - `ApiVersion.v3` → `https://your_domain.bitrix24.com/rest/api//` ### `offClientSideWarning` ```ts-type offClientSideWarning(): void ``` Отключает runtime-предупреждение, которое оба HTTP-клиента выводят при обнаружении `B24Hook` в браузерном окружении. Используйте только если вы намеренно проксируете вебхук через серверную обёртку, которая удаляет секрет до любого запроса из браузера. ### `getHttpClient` / `setHttpClient` ```ts-type getHttpClient(version: ApiVersion): TypeHttp setHttpClient(version: ApiVersion, client: TypeHttp): void ``` Прямой доступ к нижележащим HTTP-транспортам (по одному на каждую версию REST API). См. [справочник Http](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-http.md). ### `setRestrictionManagerParams` ```ts-type setRestrictionManagerParams(params: RestrictionParams): Promise ``` Заменяет конфигурацию rate limit / operating limit / адаптивной задержки сразу на клиентах v2 и v3. См. [Лимитеры](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md). ### `getLogger` / `setLogger` ```ts-type getLogger(): LoggerInterface setLogger(logger: LoggerInterface): void ``` Получает или заменяет логгер, используемый SDK и передаваемый в HTTP-клиенты. См. [Логгер](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md). ### `destroy` ```ts-type destroy(): void ``` Освобождает внутренние ссылки. Вызывайте перед завершением процесса или при удалении долгоживущего экземпляра. ```ts function shutdown() { $b24.destroy() } ``` ## Хранение секрета вебхука // @check-ignore: partial snippet — illustrates env vs inline URL pattern ```ts // ✅ Серверная переменная окружения const $b24ok = B24Hook.fromWebhookUrl(process.env.BITRIX24_WEBHOOK_URL!) // ❌ Никогда не вставляйте URL в клиентский код и не коммитьте его в Git const $b24bad = B24Hook.fromWebhookUrl( 'https://company.bitrix24.com/rest/1/abcdef123456/' ) ``` ## FAQ **Q: Где взять URL вебхука?** Bitrix24 → Настройки → Разработчикам → Вебхуки → Входящий вебхук. См. [официальную документацию](https://apidocs.bitrix24.ru/local-integrations/local-webhooks.html#vhodyashij-vebhuk){rel=""nofollow""}. **Q: Может ли один экземпляр B24Hook обслуживать весь сервер?** Да. Создайте экземпляр один раз при запуске и переиспользуйте его между запросами — HTTP-клиенты переиспользуют общий экземпляр axios и состояние лимитера. **Q: Почему fromWebhookUrl выбрасывает „Webhook requires HTTPS protocol“?** Фабрика намеренно отклоняет `http://`-URL. Секреты вебхуков должны передаваться по TLS. **Q: Что означает „Access denied“?** У пользователя вебхука нет прав на вызванный REST-метод, либо сам вебхук был отозван. Пересоздайте вебхук с необходимыми scope. --- # BatchV2.make > Метод для выполнения пакетных запросов к REST API Bitrix24 версии 2. Позволяет выполнить до 50 команд в одном API-вызове. ## Обзор Используйте `BatchV2.make()` для выполнения до 50 команд REST API в одном запросе. Это особенно полезно, когда нужно получить или обновить большие объёмы данных, минимизируя сетевые запросы и соблюдая ограничения REST API. ```ts // Базовое использование import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk' const response = await $b24.actions.v2.batch.make({ calls: [ ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: 1 }], ['crm.item.get', { entityTypeId: EnumCrmEntityTypeId.contact, id: 2 }] ], options: { isHaltOnError: true, returnAjaxResult: true, requestId: 'unique-request-id' } }) ``` ## Сигнатура метода ```ts-type make( options: ActionBatchV2 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`calls`** | `BatchCommandsArrayUniversal | BatchCommandsObjectUniversal | BatchNamedCommandsUniversal` | Да | Команды для выполнения в батче. Поддерживает несколько [форматов](https://bitrix-tools.github.io/b24jssdk/#command-formats-optionscalls). | | **`options`** | `IB24BatchOptions` | Нет | [Дополнительные опции](https://bitrix-tools.github.io/b24jssdk/#batch-request-options-optionsoptions) для выполнения пакетного запроса. | ### Форматы команд (`options.calls`) #### 1. Массив кортежей (`BatchCommandsArrayUniversal`) // @check-ignore: partial snippet — calls array literal, not a valid statement ```ts calls: [ ['method1', params1], ['method2', params2], // ... ] ``` #### 2. Массив объектов (`BatchCommandsObjectUniversal`) // @check-ignore: partial snippet — object array literal, not a valid statement ```ts calls: [ { method: 'method1', params: params1 }, { method: 'method2', params: params2 }, // ... ] ``` #### 3. Объект с именованными командами (`BatchNamedCommandsUniversal`) ```ts-type calls: { command1: { method: 'method1', params: params1 }, command2: ['method2', params2], // ... } ``` ### Опции пакетного запроса (`options.options`) | Опция | Тип | По умолчанию | Описание | | --- | --- | --- | --- | | **`isHaltOnError`** | `boolean` | `true` | Останавливать ли выполнение при первой ошибке. | | **`returnAjaxResult`** | `boolean` | `false` | Возвращать ли объект `AjaxResult` вместо данных. | | **`requestId`** | `string` | — | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект `CallBatchResult`. Структура результата зависит от формата входных данных: - **Для массива команд**: массив результатов в том же порядке. - **Для именованных команд**: объект с ключами, соответствующими именам команд. ## Данные элемента результата Каждый `result` отдельной команды возвращается ровно так, как его отдал REST API, включая `null`, когда вызываемый метод действительно не возвращает данных (например, `im.chat.get`, вызванный с `ENTITY_TYPE`, не соответствующим никакому чату). // @check-ignore: partial snippet — uses union result type and undeclared variables ```ts const response = await $b24.actions.v2.batch.make<{ ID: number } | null>({ calls: { chatGet: { method: 'im.chat.get', params: { ENTITY_TYPE: 'UNKNOWN', ENTITY_ID: 'UNKNOWN' } } }, options: { returnAjaxResult: true, requestId: 'chat-get' } }) const chatGet = response.getData().chatGet if (chatGet.getData()?.result === null) { // метод вернул null — ни один чат не совпал } else { console.log(chatGet.getData()?.result.ID) } ``` > \[!NOTE] > > До v1.1.1 результат `null` приводился к `{}`, что ломало nullable-type-guards на > стороне вызова (см. [issue #23](https://github.com/bitrix24/b24jssdk/issues/23){rel=""nofollow""}). > При типизации generic для методов, которые могут вернуть `null`, объявляйте его как > `T | null`. ## Обработка ошибок Всегда проверяйте результат через `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const response = await $b24.actions.v2.batch.make({ calls: [ { method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 1 } }, { method: 'crm.item.get', params: { entityTypeId: EnumCrmEntityTypeId.contact, id: 2 } } ], options: { isHaltOnError: true, returnAjaxResult: true, requestId: 'unique-request-id' } }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData() ``` Проверка `isSuccess` покрывает **два** разных вида сбоя: - **Ошибки отдельных команд** — конверт батча успешен, но отдельные команды упали. Проверяйте каждый `AjaxResult` в `getData()` или используйте `getErrorsByKey()`, чтобы узнать, какая команда упала. - **Ошибки уровня конверта (soft)** — весь батч падает до того, как вернётся хоть один результат команды, например при серверном коде валидации (`BITRIX_REST_V3_EXCEPTION_VALIDATION_*`). Тогда внешний `Result` — `isSuccess === false`, ошибка(и) в `getErrorMessages()` / `getErrors()`, а `getData().result` пуст. Одна проверка `if (!response.isSuccess)` обрабатывает оба случая. ## Примеры ### Получение нескольких компаний из CRM ```ts [batch-rest-api-ver2.ts] import type { AjaxResult, Result, BatchCommandsArrayUniversal } from '@bitrix24/b24jssdk' import { B24Hook, EnumCrmEntityTypeId, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk' type Company = { id: number title: string [key: string]: any } const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:batchCrmItems', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function getMultipleItems(itemIds: number[], requestId: string): Promise { if (itemIds.length < 1 || itemIds.length > 50) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `The number of elements must be between 1 and 50`, status: 404 }) } const batchCalls: BatchCommandsArrayUniversal = itemIds.map(id => [ 'crm.item.get', { entityTypeId: EnumCrmEntityTypeId.company, id } ]) const response = await $b24.actions.v2.batch.make<{ item: Company }>({ calls: batchCalls, options: { isHaltOnError: true, returnAjaxResult: true, requestId } }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } const resultData = (response as Result[]>).getData()! const results: Company[] = [] resultData.forEach((resultRow, _index) => { if (resultRow.isSuccess) { results.push((resultRow.getData()!.result as { item: Company }).item) } }) return results } // Usage const requestId = 'batch/crm.item.get' try { const itemIds = [2, 4] const items = await getMultipleItems(itemIds, requestId) $logger.info(`Retrieved ${items.length} items`, { expected: itemIds.length, retrieved: items.length, items: items.map(c => ({ id: c.id, title: c.title })) }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ### Инициализация хранилища данных Этот код автоматизирует создание и инициализацию хранилищ данных в Bitrix24 через REST API. Он проверяет существование указанных хранилищ и, если их нет, создаёт их вместе с указанными свойствами, используя пакетные запросы для эффективности. ```ts [batch-rest-api-ver2-data-storage.ts] import type { BatchNamedCommandsUniversal } from '@bitrix24/b24jssdk' import { B24Hook, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk' type DataStorageParams = { ENTITY: string NAME: string ACCESS: Record } type PropertyParams = { PROPERTY: string NAME: string TYPE: 'S' | 'N' | 'F' } type DataStorage = { isInit: boolean dataStorage: DataStorageParams props: PropertyParams[] } const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:batchDataStorage', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function initDataStorageList(dataStorageMap: Map, requestId: string): Promise { // get current list const response = await $b24.actions.v2.call.make<{ ENTITY: string, NAME: string }[]>({ method: 'entity.get', params: {}, requestId: `${requestId}/init:getCurrentList` }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } const currentDataStorageList = response.getData()!.result as { ENTITY: string, NAME: string }[] for (const dataStorage of dataStorageMap.values()) { const isInit = currentDataStorageList.some(row => row.ENTITY === dataStorage.dataStorage.ENTITY) if (isInit) { dataStorage.isInit = true } else { await initDataStorage(dataStorage, requestId) dataStorage.isInit = true } } } async function initDataStorage(dataStorage: DataStorage, requestId: string): Promise { const callBatch: BatchNamedCommandsUniversal = { AddEntity: { method: 'entity.add', params: dataStorage.dataStorage } } for (const property of dataStorage.props) { callBatch[`prop${property.PROPERTY}`] = { method: 'entity.item.property.add', params: { ...property, ENTITY: dataStorage.dataStorage.ENTITY } } } const response = await $b24.actions.v2.batch.make({ calls: callBatch, options: { isHaltOnError: true, returnAjaxResult: false, requestId: `${requestId}/init:${dataStorage.dataStorage.ENTITY}` } }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } } // Usage const requestId = 'batch/DataStorage' try { const dataStorageMap: Map = new Map([ ['DataStorage1', { isInit: false, dataStorage: { ENTITY: 'DS1', NAME: 'Data Storage 1', ACCESS: { U1: 'X', AU: 'R' } }, props: [ { PROPERTY: 'PropertyN', NAME: 'Property N', TYPE: 'N' } ] }], ['DataStorage2', { isInit: false, dataStorage: { ENTITY: 'DS2', NAME: 'Data Storage 2', ACCESS: { U1: 'X', AU: 'R' } }, props: [ { PROPERTY: 'PropertyS', NAME: 'Property S', TYPE: 'S' } ] }], ['DataStorage3', { isInit: false, dataStorage: { ENTITY: 'DS3', NAME: 'Data Storage 3', ACCESS: { U1: 'X', AU: 'R' } }, props: [ { PROPERTY: 'PropertyF', NAME: 'Property F', TYPE: 'F' } ] }] ]) await initDataStorageList(dataStorageMap, requestId) $logger.info(`dataStorageList`, { items: [...dataStorageMap.values()].map(c => ({ entity: c.dataStorage.ENTITY, isInit: c.isInit, title: c.dataStorage.NAME, props: c.props })) }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ### Удаление хранилища данных Этот код удаляет несколько хранилищ данных в системе Bitrix24 через REST API. Он последовательно отправляет delete-запросы для каждого хранилища данных, указанного в dataStorageMap, используя метод entity.delete. ```ts [batch-rest-api-ver2-data-storage-delete.ts] import { B24Hook, LoggerFactory, SdkError, AjaxError } from '@bitrix24/b24jssdk' type DataStorageParams = { ENTITY: string NAME: string } type DataStorage = { dataStorage: DataStorageParams } const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:batchDataStorageDelete', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function removeDataStorageList(dataStorageMap: Map, requestId: string): Promise { for (const dataStorage of dataStorageMap.values()) { const response = await $b24.actions.v2.call.make({ method: 'entity.delete', params: { ENTITY: dataStorage.dataStorage.ENTITY }, requestId: `${requestId}/init:getCurrentList` }) if (!response.isSuccess) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `Problem ${response.getErrorMessages().join('; ')}`, status: 404 }) } } } // Usage const requestId = 'batch/DataStorageRemove' try { const dataStorageMap: Map = new Map([ ['DataStorage1', { dataStorage: { ENTITY: 'DS1', NAME: 'Data Storage 1' } }], ['DataStorage2', { dataStorage: { ENTITY: 'DS2', NAME: 'Data Storage 2' } }], ['DataStorage3', { dataStorage: { ENTITY: 'DS3', NAME: 'Data Storage 3' } }] ]) await removeDataStorageList(dataStorageMap, requestId) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ## Альтернативы и рекомендации - **Для последовательных запросов**: используйте [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md) для одиночных вызовов. - **Для работы со списками**: используйте [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) для получения больших объёмов данных. - **Для поэтапной обработки**: используйте [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) для обработки данных по мере поступления. - **Для запуска большего числа команд (более 50)**: используйте [`BatchByChunk`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-by-chunk-rest-api-ver2.md), который автоматически разбивает команды на чанки по 50. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). --- # BatchV3.make > Метод для выполнения пакетных запросов к REST API Bitrix24 версии 3. Позволяет выполнить до 50 команд в одном API-вызове. ## Обзор Используйте `BatchV3.make()` для выполнения до 50 команд REST API в одном запросе. Это особенно полезно, когда нужно получить или обновить большие объёмы данных, минимизируя сетевые запросы и соблюдая ограничения REST API. ```ts // Базовое использование import { EnumCrmEntityTypeId } from '@bitrix24/b24jssdk' const response = await $b24.actions.v3.batch.make({ calls: [ ['tasks.task.get', { id: 1 }], ['tasks.task.get', { id: 2 }] ], options: { isHaltOnError: true, returnAjaxResult: true, requestId: 'unique-request-id' } }) ``` ## Сигнатура метода ```ts-type make( options: ActionBatchV3 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`calls`** | `BatchCommandsArrayUniversal | BatchCommandsObjectUniversal | BatchNamedCommandsUniversal` | Да | Команды для выполнения в батче. Поддерживает несколько [форматов](https://bitrix-tools.github.io/b24jssdk/#command-formats-optionscalls). | | **`options`** | `IB24BatchOptions` | Нет | [Дополнительные опции](https://bitrix-tools.github.io/b24jssdk/#batch-request-options-optionsoptions) для выполнения пакетного запроса. | ### Форматы команд (`options.calls`) #### 1. Массив кортежей (`BatchCommandsArrayUniversal`) // @check-ignore: partial snippet — calls array literal, not a valid statement ```ts calls: [ ['method1', params1], ['method2', params2], // ... ] ``` #### 2. Массив объектов (`BatchCommandsObjectUniversal`) // @check-ignore: partial snippet — object array literal, not a valid statement ```ts calls: [ { method: 'method1', params: params1 }, { method: 'method2', params: params2 }, // ... ] ``` #### 3. Объект с именованными командами (`BatchNamedCommandsUniversal`) ```ts-type calls: { command1: { method: 'method1', params: params1 }, command2: ['method2', params2], // ... } ``` ### Опции пакетного запроса (`options.options`) | Опция | Тип | По умолчанию | Описание | | --- | --- | --- | --- | | **`isHaltOnError`** | `boolean` | `true` | Останавливать ли выполнение при первой ошибке. | | **`returnAjaxResult`** | `boolean` | `false` | Возвращать ли объект `AjaxResult` вместо данных. | | **`requestId`** | `string` | — | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект `CallBatchResult`. Структура результата зависит от формата входных данных: - **Для массива команд**: массив результатов в том же порядке. - **Для именованных команд**: объект с ключами, соответствующими именам команд. ## Данные элемента результата Каждый `result` отдельной команды возвращается ровно так, как его отдал REST API, включая `null`, когда вызываемый метод действительно не возвращает данных. При типизации generic для методов, которые могут вернуть `null`, объявляйте его как `T | null`. > \[!NOTE] > > До v1.1.1 результат `null` приводился к `{}`, что ломало nullable-type-guards на > стороне вызова (см. [issue #23](https://github.com/bitrix24/b24jssdk/issues/23){rel=""nofollow""}). ## Ограничения Батч `restApi:v3` — **всё или ничего**: - Ошибки отдельных команд не возвращаются. Если любая команда в батче упадёт, весь батч провалится, и `response.getErrorMessages()` верхнего уровня будет содержать ошибку(и); `getData()` вернёт пустую map. - `time` на каждом `AjaxResult` — это время уровня батча, не отдельной команды. Ограничитель частоты **не** относит длительность батча к отдельным методам. - Если в успешном v3-ответе отсутствует запись результата для какой-то команды (что указывает на некорректный ответ API), SDK бросает `JSSDK_INTERACTION_BATCH_STRATEGY_V3_EMPTY_COMMAND_RESPONSE`. ## Передача данных между командами (`$ref` / `$refArray`) Батч v3 может подать вывод одной команды во `params` последующей. Дайте команде-источнику алиас `as`, затем сошлитесь на него маркером `$ref` (одно значение) или `$refArray` (поле, собранное по `items[]` источника). **Подстановку выполняет сервер** — SDK лишь пробрасывает маркер. Используйте хелпер `BatchRefV3` для сборки маркеров (он валидирует путь на стороне клиента): ```ts import { BatchRefV3 as R } from '@bitrix24/b24jssdk' const response = await $b24.actions.v3.batch.make({ calls: [ { method: 'tasks.task.list', as: 'tasks', params: { select: ['id'] } }, { method: 'tasks.task.list', // сервер разворачивает это в `['id', 'in', []]` params: { select: ['id', 'title'], filter: [['id', 'in', R.refArray('tasks.id')]] } } ] }) ``` - `R.ref('alias.path.to.field')` → `{ $ref: '…' }` — одно значение. В контекст попадают только `item` (get) и `items` (list/tail); `add` → id / `update` → bool — нет. - `R.refArray('alias.field')` → `{ $refArray: '…' }` — собирает `field` по `items[]` алиаса. Путь должен содержать точку. - Некорректный путь или неразрешённая ссылка проваливают батч с `BITRIX_REST_V3_EXCEPTION_INVALIDSELECTEXCEPTION`. - **Только v3.** Эти маркеры не подставляются в v2-батче (`actions.v2.batch.make`) — там они становятся литеральными значениями фильтра и молча дают неверный/пустой результат. ## Обработка ошибок SDK больше не проверяет методы батча по клиентскому списку v3: каждая команда отправляется на v3-batch-endpoint, и сервер валидирует каждую. Команда, называющая не-v3-метод, возвращается как серверная ошибка для этой команды (и, по семантике v3-батча, ошибка прерывает батч). Используйте [`BatchV2.make()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md), если батч содержит legacy-методы, или разделите смешанные батчи по версиям API. Для успешных запросов всегда проверяйте `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const response = await $b24.actions.v3.batch.make({ calls: [ { method: 'tasks.task.get', params: { id: 1 } }, { method: 'tasks.task.get', params: { id: 2 } } ], options: { isHaltOnError: true, returnAjaxResult: true, requestId: 'unique-request-id' } }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData() ``` ## Примеры ### Получение нескольких задач // @check-ignore: full example — processResult callback and BatchCommands tuple inference not in scope ```ts [BatchTasks.ts] import type { AjaxResult, Result } from '@bitrix24/b24jssdk' import { AjaxError, B24Hook, LoggerFactory, SdkError } from '@bitrix24/b24jssdk' type TaskItem = { id: number title: string } const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:batchTasks', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function getMultipleItems(itemIds: number[], requestId: string): Promise { if (itemIds.length < 1 || itemIds.length > 50) { throw new SdkError({ code: 'MY_APP_GET_PROBLEM', description: `The number of elements must be between 1 and 50`, status: 404 }) } const calls = itemIds.map(id => [ 'tasks.task.get', { id, select: ['id', 'title'] } ]) const response = await $b24.actions.v3.batch.make<{ item: TaskItem }>({ calls, options: { isHaltOnError: true, returnAjaxResult: true, requestId } }) if (!response.isSuccess) { throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`) } const resultData = (response as Result[]>).getData() ?? [] const results: TaskItem[] = [] resultData.forEach((resultRow) => { if (resultRow.isSuccess) { const item = resultRow.getData()?.result.item if (item) { results.push(item) } } }) return results } // Использование const requestId = 'batch/tasks.task.get' try { const itemIds = [1, 2, 3] const items = await getMultipleItems(itemIds, requestId) $logger.info(`Retrieved ${items.length} items`, { expected: itemIds.length, retrieved: items.length, items: items.map(c => ({ id: c.id, title: c.title })) }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ## Альтернативы и рекомендации - **Для последовательных запросов**: используйте [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver3.md) для одиночных вызовов. - **Для работы со списками**: используйте [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver3.md) для получения больших объёмов данных. - **Для поэтапной обработки**: используйте [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md) для обработки данных по мере поступления. - **Для запуска большего числа команд (более 50)**: используйте [`BatchByChunk`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-by-chunk-rest-api-ver3.md), который автоматически разбивает команды на чанки по 50. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). --- # Класс B24Frame > Предназначен для управления приложениями Bitrix24, работающими внутри placement-iframe. Наследуется от AbstractB24 и предоставляет менеджеры для аутентификации, обмена сообщениями с родительским окном, слайдеров, диалогов, placement и опций. > \[!NOTE] > > Не вызывайте `new B24Frame(...)` напрямую — используйте [`initializeB24Frame()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame-initialize-b24-frame.md), которая устраняет дублирование параллельных инициализаций, разбирает payload из `window.name` от Bitrix24 и сама выполняет `await` для `init()`. `B24Frame` наследуется от `AbstractB24` и реализует [`TypeB24`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/b24.ts){rel=""nofollow""}. Поверх общего набора REST-методов (`actions.v2.*`, `actions.v3.*`, `tools.*`) он предоставляет менеджеры, которые общаются с родительским окном через `postMessage`: `auth`, `parent`, `slider`, `dialog`, `placement`, `options`. ## Конструктор ```ts-type constructor( queryParams: B24FrameQueryParams, options?: { restrictionParams?: Partial } ) ``` [`B24FrameQueryParams`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/auth.ts){rel=""nofollow""} описывает предоставляемые Bitrix24 идентификаторы, разобранные из `window.name`: | Поле | Тип | Описание | | --- | --- | --- | | `DOMAIN` | `string` | Домен портала Bitrix24. | | `PROTOCOL` | `boolean` | Флаг протокола соединения. | | `LANG` | `string` | Язык интерфейса Bitrix24. | | `APP_SID` | `string` | Идентификатор сессии приложения. | В отличие от `B24Hook` и `B24OAuth`, `B24Frame` требует `await b24.init()` перед любым REST-вызовом — `init()` выполняет рукопожатие `getInitData` с родительским окном. `initializeB24Frame()` делает это за вас. ## Геттеры ### `isInit` ```ts-type get isInit(): boolean ``` `true` после завершения рукопожатия с родительским окном. До этого обращение к `auth`, `actions`, `tools` или любому менеджеру фрейма выбрасывает `'B24 not initialized'`. ### `isFirstRun` ```ts-type get isFirstRun(): boolean ``` `true` при самом первом запуске приложения (Bitrix24 устанавливает `FIRST_RUN`). При `isFirstRun = true` SDK автоматически отправляет `setInstall: true` родительскому окну. ### `isInstallMode` ```ts-type get isInstallMode(): boolean ``` `true` пока приложение находится в процессе установки (флаг `INSTALL` от родителя). Требуется для [`installFinish`](https://bitrix-tools.github.io/b24jssdk/#installfinish). ### `auth` ```ts-type get auth(): AuthManager ``` [Менеджер авторизации](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame-auth.md). Предоставляет `getAuthData`, `refreshAuth`, `getUniq`, `isAdmin`, а также автообновление при ответах 401. ### `parent` ```ts-type get parent(): ParentManager ``` [Менеджер родительского окна](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame-parent.md). Отправка сообщений в окружающую страницу Bitrix24 и чтение её метаданных. ### `slider` ```ts-type get slider(): SliderManager ``` [Менеджер слайдеров](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame-slider.md). Открытие и закрытие слайдеров Bitrix24. ### `placement` ```ts-type get placement(): PlacementManager ``` [Менеджер placement](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame-placement.md). Просмотр и обновление контекста placement. ### `options` ```ts-type get options(): OptionsManager ``` [Менеджер опций](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame-options.md). Чтение опций приложения и пользователя, синхронизированных из родительского окна. ### `dialog` ```ts-type get dialog(): DialogManager ``` [Менеджер диалогов](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame-dialog.md). Запрос к Bitrix24 на отображение нативных диалогов подтверждения / сообщений / выбора файлов. ## Методы ### `init` ```ts-type init(): Promise ``` Выполняет рукопожатие с родительским окном (`getInitData`), настраивает состояние менеджеров и создаёт оба HTTP-клиента REST API. На практике идемпотентен — `initializeB24Frame()` устраняет дублирование параллельных вызовов. ### `destroy` ```ts-type destroy(): void ``` Отписывается от событий `postMessage`. Всегда вызывайте перед размонтированием хост-компонента, чтобы избежать утечек. ### `installFinish` ```ts-type installFinish(): Promise ``` Отправляет `setInstallFinish` родителю. Выбрасывает `Error('Application was previously installed. You cannot call installFinish')` при вызове вне режима установки — защищайтесь проверкой `isInstallMode`. ### `getAppSid` ```ts-type getAppSid(): string ``` Идентификатор сессии приложения относительно родительского окна (повторяет `APP_SID`). ### `getLang` ```ts-type getLang(): B24LangList ``` Enum языка интерфейса Bitrix24. См. [LangList](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/language/list.ts){rel=""nofollow""}. ### `getTargetOrigin` / `getTargetOriginWithPath` ```ts-type getTargetOrigin(): string getTargetOriginWithPath(): Map ``` Origin портала и REST-endpoint-ы для каждой версии (предоставляются родителем). ### Унаследовано от `AbstractB24` `getHttpClient`, `setHttpClient`, `setRestrictionManagerParams`, `getLogger`, `setLogger`, `actions`, `tools`. См.: - [Лимитеры](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md) - [Логгер](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md) ## Использование ```ts import { initializeB24Frame, LoggerFactory, EnumCrmEntityTypeId, Text, type B24Frame, type ISODate } from '@bitrix24/b24jssdk' const $logger = LoggerFactory.createForBrowser('MyApp', import.meta.env?.DEV === true) let $b24: undefined | B24Frame async function loadCompanies() { if (!$b24) return const response = await $b24.actions.v2.callList.make<{ id: number, title: string, createdTime: ISODate }>({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.company, select: ['id', 'title', 'createdTime'] }, idKey: 'id', requestId: 'companies-list' }) if (!response.isSuccess) { $logger.error('REST error', { messages: response.getErrorMessages() }) return } return response.getData()!.map((item) => ({ id: Number(item.id), title: item.title, createdTime: Text.toDateTime(item.createdTime) })) } async function bootstrap() { try { $b24 = await initializeB24Frame() const companies = await loadCompanies() $logger.notice('companies', { companies }) } catch (error) { $logger.error('init failed', { error }) } } bootstrap() ``` > \[!NOTE] > > Страница должна работать как [приложение Bitrix24](https://apidocs.bitrix24.ru/api-reference/app-installation/local-apps/index.html){rel=""nofollow""} (внутри placement-iframe). Вне этого контекста рукопожатие с родительским окном никогда не завершится. --- # Инициализация B24Frame > Функция предназначена для инициализации B24Frame > \[!WARNING] > > Мы всё ещё дорабатываем эту страницу. Некоторых данных здесь может не хватать — скоро дополним. ```ts-type initializeB24Frame(): Promise ``` Функция `initializeB24Frame` предназначена для инициализации объекта [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame.md), который используется для работы с приложениями Bitrix24. Она управляет процессом инициализации и обрабатывает возможные ошибки соединения. > \[!NOTE] > > Поддерживает повторные вызовы до завершения инициализации, используя очередь callback-ов. **Возвращаемое значение** - **`Promise`**: возвращает promise, который при успешной инициализации разрешается объектом [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame.md). ## Использование ```ts import { initializeB24Frame } from '@bitrix24/b24jssdk' ``` --- # Класс AuthManager > Предназначен для управления аутентификацией в приложениях Bitrix24. Обрабатывает данные аутентификации, полученные от родительского окна, и предоставляет методы для их обновления и получения. ```ts // ... ///// $b24 = await initializeB24Frame() if ($b24.auth.isAdmin) { // ... //// } ``` ## Геттеры ### isAdmin ```ts-type get isAdmin(): boolean ``` Возвращает `true`, если у текущего пользователя есть права администратора, иначе `false`. ## Методы > \[!NOTE] > See: https\://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/auth.ts > > Реализует интерфейс `AuthActions`. ### getAuthData ```ts-type getAuthData(): false | AuthData ``` Возвращает данные аутентификации [`AuthData`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/auth.ts){rel=""nofollow""}, если они не истекли. Если истекли — возвращает `false`. ### refreshAuth ```ts-type async refreshAuth(): Promise ``` Обновляет данные аутентификации через родительское окно и возвращает обновлённые данные [`AuthData`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/auth.ts){rel=""nofollow""}. ### getUniq ```ts-type getUniq(prefix: string): string ``` Возвращает уникальную строку, состоящую из заданного префикса и `AuthData.memberId`. > Используется в `B24PullClientManager` --- # Класс DialogManager > Оборачивает системные диалоги BX24 (выбор пользователя, выбор прав доступа, выбор CRM-сущности), чтобы их можно было открывать изнутри iframe приложения Bitrix24. `DialogManager` доступен через [`$b24.dialog`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame.md#dialog) на экземпляре `B24Frame` и доступен только когда ваше приложение отрисовано внутри iframe Bitrix24 (он использует `postMessage` для общения с родительским окном). Он повторяет legacy-хелперы [`BX24.selectUser`](https://apidocs.bitrix24.ru/sdk/bx24-js-sdk/system-dialogues/bx24-select-user.html){rel=""nofollow""}, [`BX24.selectUsers`](https://apidocs.bitrix24.ru/sdk/bx24-js-sdk/system-dialogues/bx24-select-users.html){rel=""nofollow""}, [`BX24.selectAccess`](https://apidocs.bitrix24.ru/sdk/bx24-js-sdk/system-dialogues/bx24-select-access.html){rel=""nofollow""} и [`BX24.selectCRM`](https://apidocs.bitrix24.ru/sdk/bx24-js-sdk/system-dialogues/bx24-select-crm.html){rel=""nofollow""}, но возвращает строго типизированные `Promise` вместо приёма callback-ов. ## Методы ### selectUser ```ts-type async selectUser(): Promise ``` Отображает стандартный диалог выбора одного сотрудника компании. Promise разрешается объектом [`SelectedUser`](https://bitrix-tools.github.io/b24jssdk/#selecteduser) или `null`, если пользователь закрыл диалог, не сделав выбор. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// const makeSelectUser = async() => { const selectedUser = await $b24.dialog.selectUser() if (!selectedUser) { return } $logger.info(selectedUser) } ``` ### selectUsers ```ts-type async selectUsers(): Promise ``` Отображает стандартный диалог выбора нескольких сотрудников компании. Promise разрешается массивом объектов [`SelectedUser`](https://bitrix-tools.github.io/b24jssdk/#selecteduser). Массив пуст, если пользователь подтвердил диалог, никого не выбрав. ```ts import { SelectedUser } from '@bitrix24/b24jssdk' // ... ///// $b24 = await initializeB24Frame() // ... ///// const makeSelectUsers = async() => { const selectedUsers = await $b24.dialog.selectUsers() const list = selectedUsers.map((row: SelectedUser): string => { return [`[id: ${row.id}]`, row.name].join(' ') }) $logger.info(selectedUsers, list) } ``` ### selectAccess ```ts-type async selectAccess(blockedAccessPermissions?: string[]): Promise ``` Отображает стандартный диалог выбора прав доступа (отделы, группы, отдельные пользователи и предопределённые коды прав, такие как `AU` или `CR`). | Параметр | Тип | Описание | | --- | --- | --- | | `blockedAccessPermissions` | `string[]` | Необязательный список кодов прав, которые нужно отключить в диалоге. По умолчанию `[]`. Полезно, когда некоторые права уже выданы в другом месте. | Promise разрешается массивом записей [`SelectedAccess`](https://bitrix-tools.github.io/b24jssdk/#selectedaccess). ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// const makeSelectAccess = async() => { const selected = await $b24.dialog.selectAccess(['AU']) $logger.info( selected.map(row => `${row.id} → ${row.name}`) ) } ``` ### selectCRM ```ts-type async selectCRM(params?: SelectCRMParams): Promise ``` Отображает стандартный диалог выбора CRM-сущностей (лиды, контакты, компании, сделки, предложения). | Параметр | Тип | Описание | | --- | --- | --- | | `params.entityType` | `SelectCRMParamsEntityType[]` | Какие типы сущностей показывать вкладками в окне выбора. Допустимые значения: `lead`, `contact`, `company`, `deal`, `quote`. | | `params.multiple` | `boolean` | Разрешить множественный выбор. По умолчанию `false`. | | `params.value` | `SelectCRMParamsValue` | Необязательная карта идентификаторов сущностей, которые нужно отметить как изначально выбранные. Применяется **только когда `multiple` равно `true`** — режим одиночного выбора её игнорирует. | Promise разрешается объектом [`SelectedCRM`](https://bitrix-tools.github.io/b24jssdk/#selectedcrm), свойства которого (`lead`, `contact`, `company`, `deal`, `quote`) — настоящие JavaScript-массивы [`SelectedCRMEntity`](https://bitrix-tools.github.io/b24jssdk/#selectedcrmentity). Корзины для типов сущностей, которые пользователь не выбрал (или не запрашивал), остаются `undefined`, а не пустым массивом. > \[!NOTE] > > Начиная с v1.0.7, `selectCRM` всегда возвращает настоящие массивы. Более ранние версии передавали payload родительского окна как есть, поэтому каждая корзина фактически была `Record` (например, `{ 0: {...}, 1: {...} }`) — вызов `.length` или `.map()` на ней возвращал `undefined`. Код, написанный по документированным типам, продолжает работать; единственное поведенческое различие в том, что теперь runtime-форма совпадает с типами. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// const makeSelectCRM = async() => { const selected = await $b24.dialog.selectCRM({ entityType: ['contact', 'company'], multiple: true, value: { contact: [42], company: [7] } }) selected.contact?.forEach((row) => { $logger.info(`[${row.id}] ${row.title} — ${row.url}`) }) selected.company?.forEach((row) => { $logger.info(`[${row.id}] ${row.title}`) }) } ``` > \[!NOTE] > > Режим одиночного выбора (`multiple: false`) всё равно разрешается той же формой `SelectedCRM` — корзины просто содержат не более одного элемента. Чтобы получить этот элемент, используйте `selected.contact?.[0]`. ## Типы данных ### SelectedUser Представляет одного сотрудника компании, выбранного через `selectUser` / `selectUsers`. Флаги `sub` и `sup` описывают иерархические отношения с текущим пользователем. | Поле | Тип | Описание | | --- | --- | --- | | `id` | `NumberString` | Идентификатор пользователя — строка с числовым значением (например, `"42"`). | | `name` | `string` | Отформатированное отображаемое имя. | | `photo` | `string` | URL аватара пользователя. | | `position` | `string` | Должность пользователя. | | `url` | `string` | URL профиля пользователя внутри портала. | | `sub` | `boolean` | `true`, если выбранный пользователь — подчинённый текущего пользователя. | | `sup` | `boolean` | `true`, если выбранный пользователь — руководитель текущего пользователя. | ### SelectedAccess Представляет одну запись, возвращаемую `selectAccess`. | Поле | Тип | Описание | | --- | --- | --- | | `id` | `string` | Код права (см. таблицу ниже). | | `name` | `string` | Человекочитаемое имя права, локализованное под язык портала. | Поле `id` использует грамматику кодов прав Bitrix24: | Шаблон | Значение | | --- | --- | | `AU` | Все авторизованные пользователи портала. | | `CR` | Текущий пользователь. | | `U${number}` | Конкретный пользователь по ID. | | `IU${number}` | Сотрудник по ID (с учётом экстранета). | | `D${number}` | Все сотрудники отдела. | | `DR${number}` | Все сотрудники отдела, включая подотделы. | | `G${number}` | Группа пользователей (например, `G2` — все посетители). | | `SG${number}` | Соцсеть / рабочая группа. | ### SelectCRMParamsEntityType ```ts type SelectCRMParamsEntityType = 'lead' | 'contact' | 'company' | 'deal' | 'quote' ``` Набор видов CRM-сущностей, которые понимает `selectCRM`. Передаётся как `params.entityType` и используется в качестве ключей `SelectCRMParamsValue` и `SelectedCRM`. ### SelectCRMParamsValue Карта идентификаторов сущностей для предварительного выбора при `multiple: true`. Читаются только запрошенные типы сущностей; лишние ключи игнорируются. | Поле | Тип | Описание | | --- | --- | --- | | `lead` | `number[]` | ID лидов, которые нужно отметить как уже выбранные. | | `contact` | `number[]` | ID контактов, которые нужно отметить как уже выбранные. | | `company` | `number[]` | ID компаний, которые нужно отметить как уже выбранные. | | `deal` | `number[]` | ID сделок, которые нужно отметить как уже выбранные. | | `quote` | `number[]` | ID предложений, которые нужно отметить как уже выбранные. | ### SelectedCRMEntity Представляет одну строку внутри корзины `SelectedCRM`. | Поле | Тип | Описание | | --- | --- | --- | | `id` | `string` | Идентификатор сущности с префиксом — см. таблицу в [`SelectedCRM`](https://bitrix-tools.github.io/b24jssdk/#selectedcrm). | | `type` | `SelectCRMParamsEntityType` | Вид сущности (`lead` / `contact` / `company` / `deal` / `quote`). | | `place` | `string` | Метка placement в UI, используемая Bitrix24 (нужна редко; информационная). | | `title` | `string` | Отображаемый заголовок сущности (например, название компании, заголовок сделки, полное имя контакта). | | `desc` | `string` | Краткое описание, показываемое рядом с заголовком в окне выбора. | | `url` | `string` | URL для открытия сущности внутри портала. | ### SelectedCRM Результат `selectCRM`. Каждое свойство — это либо массив [`SelectedCRMEntity`](https://bitrix-tools.github.io/b24jssdk/#selectedcrmentity), уточнённый литеральным шаблоном `id`, либо `undefined`, если пользователь не выбрал ничего этого типа. | Поле | Тип | Описание | | --- | --- | --- | | `lead` | `(SelectedCRMEntity & { id: ``L_${number}`` })[]` | Выбранные лиды. Каждый `id` выглядит как `L_42`. | | `contact` | `(SelectedCRMEntity & { id: ``C_${number}``, image: string })[]` | Выбранные контакты. Дополнительное поле `image` содержит URL аватара контакта. | | `company` | `(SelectedCRMEntity & { id: ``CO_${number}``, image: string })[]` | Выбранные компании. Дополнительное поле `image` содержит URL логотипа компании. | | `deal` | `(SelectedCRMEntity & { id: ``D_${number}`` })[]` | Выбранные сделки. Каждый `id` выглядит как `D_17`. | | `quote` | `(SelectedCRMEntity & { id: ``Q_${number}`` })[]` | Выбранные предложения. Каждый `id` выглядит как `Q_3`. | --- # Класс OptionsManager > Используется для управления настройками приложения и пользователя в приложении Bitrix24. Позволяет инициализировать данные, получать и устанавливать опции через сообщения родительскому окну. ## Методы ### appGet ```ts-type appGet(option: string): any ``` Получает значение опции приложения. Возвращает значение опции или выбрасывает ошибку, если опция не задана. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// const value: any = $b24.options.appGet('test') ``` ### appSet ```ts-type async appSet(option: string, value: any): Promise ``` Устанавливает значение опции приложения. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// await $b24.options.appSet('test', 123) ``` ### userGet ```ts-type userGet(option: string): any ``` Получает значение пользовательской опции. Возвращает значение опции или выбрасывает ошибку, если опция не задана. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// const value: any = $b24.options.userGet('test') ``` ### userSet ```ts-type async userSet(option: string, value: any): Promise ``` Устанавливает значение пользовательской опции. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// await $b24.options.userSet('test', 123) ``` --- # Класс ParentManager > Предоставляет методы для управления родительским окном приложения в Bitrix24, включая изменение размера окна, управление прокруткой, инициацию звонков и открытие мессенджера. > \[!WARNING] > > Мы всё ещё дорабатываем эту страницу. Некоторых данных здесь может не хватать — скоро дополним. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// await $b24.parent.fitWindow() ``` ## Методы ### closeApplication ```ts-type async closeApplication(): Promise ``` Закрывает слайдер приложения. ### fitWindow ```ts-type async fitWindow(): Promise ``` Устанавливает размер фрейма приложения в соответствии с размером его содержимого. ### resizeWindow ```ts-type async resizeWindow(width: number, height: number): Promise ``` Изменяет размер фрейма приложения до указанных ширины и высоты. ### resizeWindowAuto ```ts-type async resizeWindowAuto( appNode: null | HTMLElement = null, minHeight: number = 0, minWidth: number = 0 ): Promise ``` Автоматически изменяет размер `document.body` фрейма приложения в соответствии с размером его содержимого. | Параметр | Тип | Описание | | --- | --- | --- | | `appNode` | `null|HTMLElement` | Узел приложения для расчёта высоты. | | `minHeight` | `number` | Минимальная высота. | | `minWidth` | `number` | Минимальная ширина. | ### getScrollSize ```ts-type getScrollSize(): { scrollWidth: number, scrollHeight: number } ``` Возвращает внутренние размеры фрейма приложения. ### scrollParentWindow ```ts-type async scrollParentWindow(scroll: number): Promise ``` Прокручивает родительское окно до указанной позиции. ### reloadWindow ```ts-type async reloadWindow(): Promise ``` Перезагружает страницу приложения. ### setTitle ```ts-type async setTitle(title: string): Promise ``` Устанавливает заголовок страницы. ### imCallTo ```ts-type async imCallTo(userId: number, isVideo: boolean = true): Promise ``` Инициирует звонок через внутреннюю связь. | Параметр | Тип | Описание | | --- | --- | --- | | `userId` | `number` | Идентификатор пользователя. | | `isVideo` | `boolean` | `true` — видеозвонок, `false` — аудиозвонок. | ### imPhoneTo ```ts-type async imPhoneTo(phone: string): Promise ``` Совершает звонок на указанный номер телефона. | Параметр | Тип | Описание | | --- | --- | --- | | `phone` | `string` | Номер телефона. | ### imOpenMessenger ```ts-type async imOpenMessenger(dialogId: number|'chat${number}'|'sg${number}'|'imol|${number}'|undefined): Promise ``` Открывает окно мессенджера. | Параметр | Тип | Описание | | --- | --- | --- | | `dialogId` | `number|chat${number}|sg${number}|imol|${number}|undefined` | Идентификатор диалога. | ### imOpenHistory ```ts-type async imOpenHistory(dialogId: number|'chat${number}'|'imol|${number}'): Promise ``` Открывает окно истории сообщений. | Параметр | Тип | Описание | | --- | --- | --- | | `dialogId` | `number|chat${number}|imol|${number}` | Идентификатор диалога. | ## Примеры ### Пробный звонок ```ts [frame-parent-call.ts] import type { B24Frame } from '@bitrix24/b24jssdk' import { Text, LoggerFactory, Logger, ConsoleV2Handler, LogLevel } from '@bitrix24/b24jssdk' const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:B24FrameParentCall', devMode) const $b24 = useB24().get() as B24Frame const loggerForDebugB24 = Logger.create('b24') const handlerForDebugB24 = new ConsoleV2Handler(LogLevel.DEBUG, { useStyles: true }) loggerForDebugB24.pushHandler(handlerForDebugB24) $b24.setLogger(loggerForDebugB24) const response = await $b24.parent.message.send( 'setTitle', { title: 'Text for insertion', requestId: Text.getUuidRfc4122(), isSafely: true, safelyTime: 1500 } ) $logger.debug('parent response', { response }) ``` --- # Класс PlacementManager > Используется для управления placement виджетов в приложении Bitrix24. > \[!WARNING] > > Мы всё ещё дорабатываем эту страницу. Некоторых данных здесь может не хватать — скоро дополним. [Подробнее](https://apidocs.bitrix24.ru/api-reference/widgets/ui-interaction/index.html){rel=""nofollow""} ## Геттеры ### title ```ts-type get title(): string ``` Псевдоним [`placement`](https://bitrix-tools.github.io/b24jssdk/#placement). Возвращает заголовок placement (`'DEFAULT'`, если заголовок не был предоставлен родительским окном). ### `placement` ```ts-type get placement(): string ``` Возвращает заголовок placement. По умолчанию возвращает `'DEFAULT'`, если заголовок не задан. ### isDefault ```ts-type get isDefault(): boolean ``` Возвращает `true`, если заголовок placement равен `'DEFAULT'`. ### options ```ts-type get options(): any ``` Возвращает объект опций placement. Объект заморожен для предотвращения изменений. ### isSliderMode ```ts-type get isSliderMode(): boolean ``` Возвращает `true`, если виджет работает в режиме слайдера (опция `IFRAME` равна `'Y'`). ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// if ($b24.placement.isSliderMode) { $b24.parent.setTitle('SliderMode') } ``` ## Методы ### getInterface ```ts-type async getInterface(): Promise ``` Получение информации о JS-интерфейсе текущего места встраивания: список возможных команд и событий. ```ts // ... ///// $b24 = await initializeB24Frame() // ... ///// const value: any = await $b24.placement.getInterface() ``` ### bindEvent ```ts-type async bindEvent(eventName: string): Promise ``` Настройка обработчика события для интерфейса. ### call ```ts-type async call(command: 'setValue', parameters: { value: string }): Promise async call(command: string, parameters?: Record): Promise ``` Вызывает зарегистрированную команду интерфейса. ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' // ... ///// const logger = LoggerFactory.createForBrowser('Demo', true) $b24 = await initializeB24Frame() // ... ///// $b24.placement.call('reloadData') .then((respose: any) => { logger.info('reload call') }) ``` > \[!WARNING] > > Команда `setValue` особенная: родительское окно вызывает `JSON.parse(value)` > на полученном payload, поэтому `value` **обязан** быть JSON-сериализованной строкой. Передача > обычной строки или объекта напрямую приведёт к ошибке (`SyntaxError` из > `JSON.parse` или тихому повреждению до `"[object Object]"`). > > Предпочитайте хелпер [`setValue`](https://bitrix-tools.github.io/b24jssdk/#setvalue), который сериализует за вас. Если вы используете > `call('setValue', ...)` напрямую, SDK выбросит `TypeError`, когда `value` > не является строкой. > > ```ts > // ✗ выбрасывает TypeError — value не является строкой > await $b24.placement.call('setValue', { value: 'test' }) > > // ✓ работает — value является JSON-строкой > await $b24.placement.call('setValue', { value: JSON.stringify('test') }) > await $b24.placement.call('setValue', { value: JSON.stringify({ id: 1 }) }) > ``` ### setValue ```ts-type async setValue(value: unknown): Promise ``` Удобная обёртка над `placement.call('setValue', ...)`, которая выполняет `JSON.stringify` над значением за вас. Принимает любое JSON-сериализуемое значение (строку, число, булево, объект, массив). ```ts $b24 = await initializeB24Frame() // ... ///// await $b24.placement.setValue('test') await $b24.placement.setValue({ id: 1, title: 'demo' }) ``` ### callCustomBind ```ts-type async callCustomBind( command: string, parameters: null | string | Record, callBack: (...args: any[]) => void ): Promise ``` Вызывает команду интерфейса и регистрирует callback, который получает последующие события от команды. Используйте это для команд, которые порождают непрерывные события (например, обновления прогресса), вместо однократного разрешения. `parameters` принимает три формы: - `null` — без payload. - `string` — отправляется как `singleOption`. - `Record` — раскрывается в payload сообщения. ```ts $b24 = await initializeB24Frame() // ... ///// $b24.placement.callCustomBind('subscribe', { topic: 'crm:deal' }, (event) => { console.log('event', event) }) ``` --- # Класс SliderManager > Предоставляет методы для работы со слайдерами в приложении Bitrix24. Позволяет открывать и закрывать слайдеры, а также управлять их содержимым. > \[!WARNING] > > Мы всё ещё дорабатываем эту страницу. Некоторых данных здесь может не хватать — скоро дополним. ## Методы ### openSliderAppPage ```ts-type async openSliderAppPage(params: any = {}}: Promise ``` Метод `openSliderAppPage` позволяет открыть текущее приложение в новом слайдере, передав произвольные параметры. Как это работает: - **Передача данных:** вы вызываете метод и передаёте объект с параметрами (например, place, action или id). - **Обработка в приложении:** на стороне приложения удобнее всего перехватывать эти параметры через middleware. Это позволяет решить, какой маршрут показать пользователю до отрисовки страницы. - **Бесшовная навигация:** пользователь видит новый слайдер с нужным содержимым, а логика перенаправления скрыта внутри приложения. ```ts [frame-slider-app-page-open.ts] import type { B24Frame } from '@bitrix24/b24jssdk' import { LoggerFactory } from '@bitrix24/b24jssdk' const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:B24FrameSliderOpenPath', devMode) const $b24 = useB24().get() as B24Frame async function openAppPage() { const response = await $b24.slider.openSliderAppPage( { // The 'place' parameter will be available in placement // It should be processed in middleware to redirect to the desired route. place: 'app.place', bx24_width: 650, bx24_title: 'Page title in the browser' } ) $logger.debug('response', { response }) } await openAppPage() ``` ### closeSliderAppPage ```ts-type async closeSliderAppPage(): Promise ``` Закрывает слайдер с приложением. ```ts [frame-slider-app-page-close.ts] import type { B24Frame } from '@bitrix24/b24jssdk' const $b24 = useB24().get() as B24Frame async function closePage() { return $b24.slider.closeSliderAppPage() } closePage() ``` ### openPath ```ts-type async openPath(url: URL, width: number = 1640): Promise ``` Открывает указанный путь внутри портала в слайдере. Обрабатывает ошибки, связанные с использованием мобильных устройств, и может открыть URL в новой вкладке, если слайдер не поддерживается. Возвращает [`StatusClose`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/slider.ts){rel=""nofollow""} | Параметр | Тип | Описание | | --- | --- | --- | | `url` | `URL` | Открываемый URL. | | `width` | `number` | Ширина слайдера, число в диапазоне от `1640` до `900`. | Этот пример демонстрирует вызов слайдера Bitrix24 и обработку результата его закрытия. Ключевые моменты: - **Обработка завершения:** после закрытия слайдера SDK возвращает статус. Это позволяет запускать последующие операции, например повторную инициализацию данных приложения. > \[!WARNING] > > В некоторых случаях Bitrix24 открывает интерфейс не в слайдере, а в новой вкладке браузера. > > - **Ограничение:** обнаружить закрытие отдельной вкладки стандартными средствами JS практически невозможно. > - **Решение:** параметр `isOpenAtNewWindow` в ответе jsSdk позволяет определить, была ли открыта вкладка вместо слайдера, и правильно настроить логику приложения. ```ts [frame-slider-open-path.ts] import type { B24Frame } from '@bitrix24/b24jssdk' import { LoggerFactory } from '@bitrix24/b24jssdk' const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:B24FrameSliderOpenPath', devMode) const $b24 = useB24().get() as B24Frame async function makeOpenSliderEditCurrency(currencyCode: string) { // Open the slider with the specified width const url = $b24.slider.getUrl(`/crm/configs/currency/edit/${currencyCode}/`) const response = await $b24.slider.openPath( $b24.slider.getUrl(`/crm/configs/currency/edit/${currencyCode}/`), 950 ) $logger.debug('response', { url, response }) // Check that it was a slider (not a new tab) and it was closed if (!response.isOpenAtNewWindow && response.isClose) { $logger.notice(`The slider is closed. Reinitializing the application...`) // Data update logic } } await makeOpenSliderEditCurrency('USD') ``` ### getUrl ```ts-type getUrl(path: string = '/'): URL ``` Возвращает `URL` относительно доменного имени и пути. ```ts $b24 = await initializeB24Frame() // ... const url = $b24.slider.getUrl('/settings/configs/userfield_list.php') ``` ### getTargetOrigin ```ts-type getTargetOrigin(): string ``` Возвращает адрес Bitrix24 (например, `https://your_domain.bitrix24.com`). --- # BatchByChunkV2.make > Метод для выполнения пакетных запросов с автоматическим разбиением на чанки для любого числа команд. Автоматически делит большие наборы команд на батчи по 50 и выполняет их последовательно. Используйте только массивы кортежей или массивы объектов. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Обзор Используйте `BatchByChunkV2.make()` для выполнения большого числа запросов REST API с автоматическим пакетированием. Метод возвращает `Promise` с объектом `Result`, содержащим объединённые результаты всех успешных команд. Это особенно полезно для: - Массового создания или обновления записей - Экспорта больших объёмов данных через пакетные запросы - Выполнения сложных операций, требующих множества разных API-вызовов // @check-ignore: full example — BatchCommands Array.from tuple inference and fields not in TypeCallParams ```ts // Базовое использование import { B24Hook, EnumCrmEntityTypeId } from '@bitrix24/b24jssdk' // Создаём 150 сделок (будут разделены на 3 чанка по 50 сделок каждый) const commands = Array.from({ length: 150 }, (_, i) => [ 'crm.item.add', { entityTypeId: EnumCrmEntityTypeId.deal, fields: { title: `Deal ${i + 1}` } } ]) const response = await $b24.actions.v2.batchByChunk.make({ calls: commands, options: { isHaltOnError: true, requestId: 'unique-request-id' } }) ``` ## Сигнатура метода ```ts-type make( options: ActionBatchByChunkV2 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`calls`** | `BatchCommandsArrayUniversal | BatchCommandsObjectUniversal` | Да | Команды для выполнения в батче. Поддерживает несколько [форматов](https://bitrix-tools.github.io/b24jssdk/#command-formats-optionscalls). **Именованные команды не поддерживаются**. | | **`options`** | `Omit` | Нет | [Дополнительные опции](https://bitrix-tools.github.io/b24jssdk/#batch-request-options-optionsoptions) для выполнения пакетного запроса. | ### Форматы команд (`options.calls`) #### 1. Массив кортежей (`BatchCommandsArrayUniversal`) // @check-ignore: partial snippet — calls array literal, not a valid statement ```ts calls: [ ['method1', params1], ['method2', params2], // ... ] ``` #### 2. Массив объектов (`BatchCommandsObjectUniversal`) // @check-ignore: partial snippet — object array literal, not a valid statement ```ts calls: [ { method: 'method1', params: params1 }, { method: 'method2', params: params2 }, // ... ] ``` ### Опции пакетного запроса (`options.options`) | Опция | Тип | По умолчанию | Описание | | --- | --- | --- | --- | | **`isHaltOnError`** | `boolean` | `true` | Останавливать ли выполнение при первой ошибке в чанке. | | **`requestId`** | `string` | — | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект `Result`. Важные особенности: - **Только успешные результаты**: в массив попадают только успешно выполненные команды. - **Объединённый массив**: результаты из всех чанков объединяются в единый массив. - **Порядок сохраняется**: результаты сохраняются в том же порядке, что и исходные команды. ## Обработка ошибок Метод разбивает все команды на чанки и начинает выполнять их по очереди через [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md). Если при вызове `Batch` возникает ошибка, она сохраняется в `Result`, и цикл продолжает выполняться. Параметр `isHaltOnError` влияет на поведение метода callBatch: При `isHaltOnError = false` команды выполняются, даже если некоторые завершились с ошибкой. При `isHaltOnError = true` (по умолчанию) выполнение пакета прекращается, если в какой-либо команде возникает ошибка. Всегда проверяйте результат через `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const calls = Array.from({ length: 150 }, (_, i) => [ 'crm.item.add', { entityTypeId: EnumCrmEntityTypeId.deal, fields: { title: `Deal ${i + 1}` } } ]) const response = await $b24.actions.v2.batchByChunk.make({ calls, options: { isHaltOnError: true, requestId: 'unique-request-id' } }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData() ``` ## Примеры ### Массовое создание сделок CRM // @check-ignore: full example — BatchCommands Array.from tuple inference and fields not in TypeCallParams ```ts [BatchByChunkCrmItems.ts] import { AjaxError, B24Hook, EnumCrmEntityTypeId, LoggerFactory } from '@bitrix24/b24jssdk' type Deal = { id: number title: string stageId: string opportunity: number } const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:batchByChunkCrmItems', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function addMultipleItems(needAdd: number, requestId: string): Promise { const calls = Array.from({ length: needAdd }, (_, i) => [ 'crm.item.add', { entityTypeId: EnumCrmEntityTypeId.deal, fields: { title: `Automatic deal #${i + 1}`, stageId: 'NEW', opportunity: Math.floor(Math.random() * 10000) + 1000 } } ]) const response = await $b24.actions.v2.batchByChunk.make<{ item: Deal }>({ calls, options: { isHaltOnError: true, requestId } }) if (!response.isSuccess) { throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`) } const resultData = response.getData() ?? [] const results: number[] = resultData.map(chunkRow => chunkRow.item.id) return results } // Использование const requestId = 'batch/crm.item.add' try { const needAdd = 120 const items = await addMultipleItems(needAdd, requestId) $logger.info(`Retrieved ${items.length} items`, { expected: needAdd, retrieved: items.length, items }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ## Альтернативы и рекомендации - **Для последовательных запросов**: используйте [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md) для одиночных вызовов. - **Для работы со списками**: используйте [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) для получения больших объёмов данных. - **Для поэтапной обработки**: используйте [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) для обработки данных по мере поступления. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). --- # BatchByChunkV3.make > Метод для выполнения пакетных запросов к REST API Bitrix24 версии 3 с автоматическим разбиением на чанки для любого числа команд. Автоматически делит большие наборы команд на батчи по 50 и выполняет их последовательно. Используйте только массивы кортежей или массивы объектов. > \[!WARNING] > > Эта страница ещё обновляется. Некоторые данные могут отсутствовать — мы их вскоре дополним. ## Обзор Используйте `BatchByChunkV3.make()` для выполнения большого числа запросов REST API с автоматическим пакетированием. Метод возвращает `Promise` с объектом `Result`, содержащим объединённые результаты всех успешных команд. Это особенно полезно для: - Массового создания или обновления записей - Экспорта больших объёмов данных через пакетные запросы - Выполнения сложных операций, требующих множества разных API-вызовов // @check-ignore: full example — BatchCommands Array.from tuple inference and fields not in TypeCallParams ```ts // Базовое использование import { B24Hook, EnumCrmEntityTypeId } from '@bitrix24/b24jssdk' // Создаём 150 задач (будут разделены на 3 чанка по 50 задач каждый) const commands = Array.from({ length: 150 }, (_, i) => [ 'tasks.task.get', { id: i + 1, select: ['id', 'title'] } ]) const response = await $b24.actions.v3.batchByChunk.make({ calls: commands, options: { isHaltOnError: true, requestId: 'unique-request-id' } }) ``` ## Сигнатура метода ```ts-type make( options: ActionBatchByChunkV3 ): Promise> ``` ### Параметры Объект `options` содержит следующие свойства: | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`calls`** | `BatchCommandsArrayUniversal | BatchCommandsObjectUniversal` | Да | Команды для выполнения в батче. Поддерживает несколько [форматов](https://bitrix-tools.github.io/b24jssdk/#command-formats-optionscalls). **Именованные команды не поддерживаются**. | | **`options`** | `Omit` | Нет | [Дополнительные опции](https://bitrix-tools.github.io/b24jssdk/#batch-request-options-optionsoptions) для выполнения пакетного запроса. | ### Форматы команд (`options.calls`) #### 1. Массив кортежей (`BatchCommandsArrayUniversal`) // @check-ignore: partial snippet — calls array literal, not a valid statement ```ts calls: [ ['method1', params1], ['method2', params2], // ... ] ``` #### 2. Массив объектов (`BatchCommandsObjectUniversal`) // @check-ignore: partial snippet — object array literal, not a valid statement ```ts calls: [ { method: 'method1', params: params1 }, { method: 'method2', params: params2 }, // ... ] ``` ### Опции пакетного запроса (`options.options`) | Опция | Тип | По умолчанию | Описание | | --- | --- | --- | --- | | **`isHaltOnError`** | `boolean` | `true` | Останавливать ли выполнение при первой ошибке в чанке. | | **`requestId`** | `string` | — | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise>` — promise, разрешающийся в объект `Result`. Важные особенности: - **Только успешные результаты**: в массив попадают только успешно выполненные команды. - **Объединённый массив**: результаты из всех чанков объединяются в единый массив. - **Порядок сохраняется**: результаты сохраняются в том же порядке, что и исходные команды. ## Обработка ошибок Метод разбивает все команды на чанки и начинает выполнять их по очереди через [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver3.md). Если при вызове `Batch` возникает ошибка, она сохраняется в `Result`, и цикл продолжает выполняться. Параметр `isHaltOnError` влияет на поведение метода callBatch: При `isHaltOnError = false` команды выполняются, даже если некоторые завершились с ошибкой. При `isHaltOnError = true` (по умолчанию) выполнение пакета прекращается, если в какой-либо команде возникает ошибка. Всегда проверяйте результат через `isSuccess` и обрабатывайте ошибки: // @check-ignore: top-level return in error-handling illustration ```ts const calls = Array.from({ length: 150 }, (_, i) => [ 'tasks.task.get', { id: i + 1 } ]) const response = await $b24.actions.v3.batchByChunk.make({ calls, options: { isHaltOnError: true, requestId: 'unique-request-id' } }) if (!response.isSuccess) { // Обработка ошибки console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) return } // Работа с успешным результатом const data = response.getData() ``` ## Примеры ### Массовое создание задач // @check-ignore: full example — BatchCommands Array.from tuple inference and fields not in TypeCallParams ```ts [BatchByChunkTask.ts] import { AjaxError, B24Hook, LoggerFactory } from '@bitrix24/b24jssdk' type TaskItem = { id: number title: string } const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:batchByChunkTask', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function addMultipleItems(needAdd: number, requestId: string): Promise { const calls = Array.from({ length: needAdd }, (_, i) => [ 'tasks.task.add', { fields: { title: `Automatic task #${i + 1}`, creatorId: 1, responsibleId: 1 } } ]) const response = await $b24.actions.v3.batchByChunk.make<{ item: TaskItem }>({ calls, options: { isHaltOnError: true, requestId } }) if (!response.isSuccess) { throw new Error(`Problem: ${response.getErrorMessages().join('; ')}`) } const resultData = response.getData() ?? [] const results: number[] = resultData.map(chunkRow => chunkRow.item.id) return results } // Использование const requestId = 'batch/tasks.task.add' try { const needAdd = 120 const items = await addMultipleItems(needAdd, requestId) $logger.info(`Retrieved ${items.length} items`, { expected: needAdd, retrieved: items.length, items }) } catch (error) { if (error instanceof AjaxError) { $logger.critical(error.message, { requestId, code: error.code }) } else { $logger.alert('Problem', { requestId, error }) } } ``` ## Альтернативы и рекомендации - **Для последовательных запросов**: используйте [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver3.md) для одиночных вызовов. - **Для работы со списками**: используйте [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver3.md) для получения больших объёмов данных. - **Для поэтапной обработки**: используйте [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md) для обработки данных по мере поступления. - **Для пакетных операций:** используйте [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver3.md) для выполнения до 50 команд в одном запросе. - **На стороне клиента (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). --- # Класс B24OAuth > Серверная точка входа для работы с REST API Bitrix24 по access token OAuth 2.0 (с автоматическим обновлением). > \[!CAUTION] > > Объект `B24OAuth` предназначен **исключительно для использования на сервере**. > > - `clientSecret`, access token и refresh token никогда не должны попадать в код браузера. > - Предупреждение о клиентской стороне по умолчанию включено на обоих HTTP-клиентах; см. [`offClientSideWarning`](https://bitrix-tools.github.io/b24jssdk/#offclientsidewarning). > - Для клиентских сценариев используйте [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/frame.md). ## Обзор `B24OAuth` — это точка входа SDK для [локальных приложений OAuth 2.0](https://apidocs.bitrix24.ru/settings/oauth/index.html){rel=""nofollow""}. Он принимает существующую пару токенов (выданную Bitrix24 при установке), использует access token для REST-вызовов и обновляет пару через `oauth.bitrix.info`, когда access token истекает. Класс наследуется от `AbstractB24` и реализует [`TypeB24`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/b24.ts){rel=""nofollow""}, поэтому полный набор REST-методов (`actions.v2.*`, `actions.v3.*`, `tools.*`) доступен сразу после создания экземпляра — шаг `await b24.init()` не требуется. ## Создание экземпляра B24OAuth ```ts import { B24OAuth, EnumAppStatus } from '@bitrix24/b24jssdk' const $b24 = new B24OAuth( // 1) Данные токена, полученные от Bitrix24 (payload события, OAuth-рукопожатие и т.д.) { applicationToken: '', userId: 1, memberId: '', accessToken: '', refreshToken: '', expires: 1745997853, // unix-таймстамп, секунды expiresIn: 3600, // секунды scope: 'crm,catalog,user_brief', domain: 'your_domain.bitrix24.com', clientEndpoint: 'https://your_domain.bitrix24.com/rest/', serverEndpoint: 'https://oauth.bitrix.info/rest/', status: EnumAppStatus.Free }, // 2) Учётные данные приложения, выданные в Bitrix24 → Разработчикам → Приложения { clientId: 'local.xxxxxx.xxxxxx', clientSecret: '' } ) const response = await $b24.actions.v2.call.make({ method: 'tasks.task.list', params: { select: ['ID', 'TITLE', 'STATUS'] }, requestId: 'tasks-list' }) ``` ### Сигнатура конструктора ```ts-type constructor( authOptions: B24OAuthParams, oAuthSecret: B24OAuthSecret, options?: { restrictionParams?: Partial } ) ``` ### Поля `B24OAuthParams` | Поле | Тип | Описание | | --- | --- | --- | | `applicationToken` | `string` | Application token, выданный при установке. | | `userId` | `number` | Идентификатор пользователя, которому принадлежит токен. | | `memberId` | `string` | member id портала. | | `accessToken` | `string` | Текущий access token. | | `refreshToken` | `string` | Refresh token, используемый `refreshAuth`. | | `expires` | `number` | Срок действия access token (unix-таймстамп, **секунды**). | | `expiresIn` | `number` | Время жизни токена, секунды. | | `scope` | `string` | Список scope через запятую (например, `crm,catalog,user_brief`). | | `domain` | `string` | Домен портала (`xxx.bitrix24.com`). | | `clientEndpoint` | `string` | Корень REST портала, например `https://xxx.bitrix24.com/rest/`. | | `serverEndpoint` | `string` | OAuth-сервер, обычно `https://oauth.bitrix.info/rest/`. | | `status` | `TypeEnumAppStatus` | Одно из `EnumAppStatus.Free / Demo / Trial / Paid / Local / Subscription`. | ### Поля `B24OAuthSecret` | Поле | Тип | Описание | | --- | --- | --- | | `clientId` | `string` | OAuth `client_id` вашего приложения. | | `clientSecret` | `string` | OAuth `client_secret` вашего приложения. | ## Процесс обновления токена `B24OAuth` обновляет access token автоматически, когда: - REST-вызов возвращает `expired_token`, **или** - вызывается `getAuthData()` и `expires <= Date.now()`. Путь обновления по умолчанию вызывает `GET /oauth/token/` на `serverEndpoint` (обычно `https://oauth.bitrix.info/rest/`) с `grant_type=refresh_token`, переданными `refreshToken`, `clientId` и `clientSecret`. При успехе менеджер обновляет `accessToken`, `refreshToken`, `expires`, `expiresIn`, `clientEndpoint`, `serverEndpoint`, `scope` и `status`. Если запрос обновления завершается неудачей, SDK выбрасывает [`RefreshTokenError`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/oauth/refresh-token-error.ts){rel=""nofollow""} (подкласс `SdkError`), несущий `code`, `description` и HTTP-`status`. ### Сохранение обновлённых токенов Зарегистрируйте callback, чтобы ваше приложение могло сохранить новую пару токенов (БД, менеджер секретов и т.д.): // @check-ignore: B24OAuth-specific method, ambient $b24 is typed as B24Frame ```ts $b24.setCallbackRefreshAuth(async ({ authData, b24OAuthParams }) => { await tokenStore.save({ accessToken: b24OAuthParams.accessToken, refreshToken: b24OAuthParams.refreshToken, expires: b24OAuthParams.expires, expiresIn: b24OAuthParams.expiresIn, memberId: authData.member_id }) }) ``` Удаляется через `$b24.removeCallbackRefreshAuth()`. ### Кастомная логика обновления Если ваше приложение получает refresh-токены из отдельного сервиса (например, централизованного брокера токенов), передайте функцию `CustomRefreshAuth`. SDK вызовет её вместо обращения к `oauth.bitrix.info`: // @check-ignore: B24OAuth-specific method, ambient $b24 is typed as B24Frame ```ts import type { HandlerRefreshAuth } from '@bitrix24/b24jssdk' $b24.setCustomRefreshAuth(async (): Promise => { const fresh = await tokenBroker.fetch() return { access_token: fresh.accessToken, refresh_token: fresh.refreshToken, expires: fresh.expires, expires_in: fresh.expiresIn, client_endpoint: fresh.clientEndpoint, server_endpoint: fresh.serverEndpoint, member_id: fresh.memberId, scope: fresh.scope, status: fresh.status, domain: fresh.domain } }) ``` Удаляется через `$b24.removeCustomRefreshAuth()`. ## Методы ### `initIsAdmin` ```ts-type initIsAdmin(requestId?: string): Promise ``` Один раз вызывает REST-метод `profile` и кэширует, есть ли у аутентифицированного пользователя права администратора. Требуется перед чтением [`auth.isAdmin`](https://bitrix-tools.github.io/b24jssdk/#getter-auth) — геттер выбрасывает `Error('isAdmin not init. You need call B24OAuth::initIsAdmin().')` при слишком раннем вызове. // @check-ignore: B24OAuth-specific method, ambient $b24 is typed as B24Frame ```ts await $b24.initIsAdmin('boot:isAdmin') if ($b24.auth.isAdmin) { // ... } ``` ### `setCallbackRefreshAuth` / `removeCallbackRefreshAuth` ```ts-type setCallbackRefreshAuth(cb: CallbackRefreshAuth): void removeCallbackRefreshAuth(): void ``` Регистрирует / снимает callback, выполняемый после каждого успешного обновления. См. [Сохранение обновлённых токенов](https://bitrix-tools.github.io/b24jssdk/#persisting-refreshed-tokens). ### `setCustomRefreshAuth` / `removeCustomRefreshAuth` ```ts-type setCustomRefreshAuth(cb: CustomRefreshAuth): void removeCustomRefreshAuth(): void ``` Регистрирует / снимает кастомную реализацию обновления. См. [Кастомная логика обновления](https://bitrix-tools.github.io/b24jssdk/#custom-refresh-logic). ### `offClientSideWarning` ```ts-type offClientSideWarning(): void ``` Отключает runtime-предупреждение, возникающее при обнаружении `B24OAuth` в браузерном окружении. Используйте только когда вы проксируете OAuth-токены через серверную обёртку. ### `getTargetOrigin` / `getTargetOriginWithPath` ```ts-type getTargetOrigin(): string getTargetOriginWithPath(): Map ``` Возвращают origin портала (например, `https://xxx.bitrix24.com`) и REST-endpoint-ы для каждой версии, выведенные из `clientEndpoint`. ### `getHttpClient` / `setHttpClient` / `setRestrictionManagerParams` / `getLogger` / `setLogger` / `destroy` Унаследованы от `AbstractB24` — та же структура, что и у `B24Hook` и `B24Frame`. См.: - [Лимитеры](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md) — `setRestrictionManagerParams`. - [Логгер](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md) — `getLogger` / `setLogger`. ## Геттеры ### `auth` Возвращает экземпляр [`AuthOAuthManager`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/oauth/auth.ts){rel=""nofollow""}, который реализует [`AuthActions`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/auth.ts){rel=""nofollow""}: - `getAuthData()` — возвращает текущий `AuthData` или `false`, если access token истёк (следующий REST-вызов вызовет автоматическое обновление). - `refreshAuth()` — ручное обновление; выбрасывает `RefreshTokenError` при неудаче. - `getUniq(prefix: string)` — возвращает `_`. - `isAdmin` — требует предварительного вызова `initIsAdmin()`. ### `isInit` ```ts-type get isInit(): boolean ``` Всегда `true` сразу после создания экземпляра. ## Обработка ошибок // @check-ignore: top-level return in error-handling illustration ```ts import { B24OAuth, RefreshTokenError } from '@bitrix24/b24jssdk' try { const response = await $b24.actions.v3.call.make({ method: 'tasks.task.get', params: { id: 1, select: ['id', 'title'] }, requestId: 'task-get-1' }) if (!response.isSuccess) { // Обработка ошибок уровня REST console.error(response.getErrorMessages()) } } catch (error) { if (error instanceof RefreshTokenError) { // Refresh token мёртв — переавторизуйте приложение console.error('OAuth refresh failed:', error.message) return } throw error } ``` ## FAQ **Q: Где взять начальную пару токенов?** Bitrix24 отправляет их при установке вашего локального приложения и повторно на событиях [`ONAPPINSTALL` / `ONAPPUPDATE`](https://apidocs.bitrix24.ru/api-reference/events/index.html){rel=""nofollow""}. Сохраняйте их и передавайте в `B24OAuth` при каждом старте сервера. **Q: Почему \`expires\` в секундах, а не в миллисекундах?** Bitrix24 возвращает Unix-таймстампы в секундах. SDK конвертирует внутри; вы должны передавать секунды в `B24OAuthParams.expires`. **Q: Можно ли использовать один экземпляр B24OAuth между запросами?** Да — и нужно. Совместное использование сохраняет состояние лимитера и access token в памяти согласованными. Сохраняйте обновлённую пару токенов через `setCallbackRefreshAuth`, чтобы после перезапуска использовались последние токены. **Q: А как насчёт методов только для чтения, которым не нужны права администратора?** Вы можете пропустить `initIsAdmin()`, если ваш код никогда не читает `auth.isAdmin`. Сами REST-вызовы от него не зависят. --- # Выбор подходящего метода > Руководство по выбору между Call, CallList, FetchList, Batch и BatchByChunk в REST API v2 и v3. ## Обзор SDK предоставляет пять примитивов для работы с REST API Bitrix24, все доступны через `b24.actions.v{2,3}..make(options)`. Они выглядят похоже, но имеют очень разные характеристики стоимости. Выбор неподходящего — самая частая причина медленных приложений и тикетов «почему мой дашборд забивает очередь?». Эта страница поможет принять решение за 30 секунд. Выбор определяется тремя осями: 1. **Один вызов или много?** Один REST-метод или несколько сразу. 2. **Ограничено или нет?** Известно ли заранее, что результатов ≤ 50, или их может быть 50 000? 3. **Всё сразу или потоком?** Нужны все записи в памяти для агрегации или обрабатывать по мере поступления? > \[!CAUTION] > > Шорткаты на уровне экземпляра в `AbstractB24` (`b24.callMethod()`, `b24.callBatch()`, `b24.callListMethod()`, `b24.fetchListMethod()`, `b24.callBatchByChunk()`) помечены `@deprecated` и будут удалены в v2.0.0. Они выводят runtime-предупреждение при каждом вызове и игнорируют разделение API по версиям. Всегда вызывайте действие явно: `b24.actions.v2.call.make({…})` / `b24.actions.v3.batch.make({…})` и т.д. См. [руководство по миграции v0 → v1](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/migration/v1.md) для пошаговых замен. ## Матрица решений | Ваша ситуация | Используйте | | --- | --- | | Один метод, одна запись (`crm.deal.get`, `tasks.task.get`) | [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md) | | Один list-метод, ≤ нескольких тысяч записей, нужен весь массив в памяти | [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) | | Один list-метод, десятки тысяч записей, обработка чанками (CSV-экспорт, ETL) | [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) | | Несколько **разных** методов, которые нужно отправить в одном round-trip (загрузка плитки дашборда) | [`Batch`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md) | | Много вызовов одной формы (массовые create / update / delete > 50 элементов) | [`BatchByChunk`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-by-chunk-rest-api-ver2.md) | Затем выберите версию API: предпочтительно **v3** для любых методов, [доступных в v3](https://apidocs.bitrix24.ru/api-reference/rest-v3/index.html){rel=""nofollow""} (лучшая фильтрация, большие страницы, оптимизация на сервере), и **v2** для всего остального. v2-версия `Call.make()` в SDK выводит предупреждение, когда вы вызываете v3-доступный метод в v2 — это сигнал к миграции. ## Компромиссы по методам ### `Call.make()` **Используйте, когда** нужна ровно одна запись или одна серверная операция (`update`, `add`, `delete`). **Избегайте, когда** обнаруживаете, что оборачиваете его в `for`-цикл с `await` — это сигнал переключиться на `Batch` или `BatchByChunk`. Цикл из N вызовов `Call.make()` — это N round-trip'ов; `Batch` сворачивает до 50 в один. `BatchByChunk` сворачивает любое число в `ceil(N / 50)` round-trip'ов. ### `CallList.make()` **Используйте, когда** результирующий набор достаточно мал, чтобы держать в памяти, и вы будете делать с ним что-то сквозное (сортировка, группировка, агрегация, дедупликация, передача в библиотеку графиков). **Избегайте, когда** нужен лишь небольшой срез — передайте `select` и `filter`, чтобы сузить результат, вместо того чтобы получать всё. Метод всегда забирает все страницы, соответствующие вашему фильтру; «дай мне топ-10» без фильтра — расточительство. ### `FetchList.make()` **Используйте, когда** результат неограничен (или может быть), и вы можете обрабатывать записи по мере поступления: стримить их в CSV, отправлять в очередь, писать в базу, передавать через WebSocket. **Избегайте, когда** нужна агрегация по всем записям, требующая полного набора в памяти — `CallList` проще. Генератор отдаёт чанки по `50` (v2) или `options.limit` до `1000` (v3); ваш downstream-код должен обработать каждый чанк до следующего запроса, поэтому тяжёлая синхронная работа между чанками замедляет общий проход. ### `Batch.make()` **Используйте, когда** одно действие пользователя зависит от данных нескольких разных методов. Типичный пример — плитка дашборда, которой нужны профиль пользователя, число открытых сделок и закреплённые задачи — три разных метода, один round-trip. **Избегайте, когда** один и тот же метод повторяется 50+ раз. Именно для этого нужен `BatchByChunk`, а `Batch` отклонит всё, что больше 50 команд. Также избегайте, когда нужны именованные ключи результата *и* > 50 вызовов — `BatchByChunk` намеренно принимает только массив кортежей / массив объектов (именованные команды ломаются на границах чанков). ### `BatchByChunk.make()` **Используйте, когда** у вас произвольное число команд одной формы — массовые миграции, массовые `create` / `update` / `delete`, экспорт per-id-деталей для тысяч связанных записей. **Избегайте, когда** у вас всего несколько вызовов — `Batch` проще и даёт именованные результаты. Также избегайте, когда нужно транзакционное поведение — `BatchByChunk` **не** атомарен. Если чанк 7 из 30 упал, чанки 1-6 уже применены; чанки 8-30 могут выполниться или нет в зависимости от `isHaltOnError`. ## Лимиты — кратко | Метод | Макс. вызовов | Макс. страница | Возвращает | Бросает на первой ошибке? | | --- | --- | --- | --- | --- | | `Call.make()` | 1 | н/д | `AjaxResult` | Нет (проверяйте `isSuccess`) | | `CallList.make()` | неограничено (с пагинацией) | 50 (v2) / 1000 (v3) | `Result` | Нет | | `FetchList.make()` | неограничено (потоково) | 50 (v2) / 1000 (v3) | `AsyncGenerator` | Да — `SdkError` | | `Batch.make()` | 50 | н/д | `CallBatchResult` | Настраивается через `isHaltOnError` | | `BatchByChunk.make()` | неограничено (чанками × 50) | н/д | `Result` | Настраивается через `isHaltOnError` | ## Частые антипаттерны - **`b24.callMethod()` / `b24.callBatch()` / `b24.callListMethod()` / `b24.fetchListMethod()` / `b24.callBatchByChunk()`.** Устаревшие шорткаты в `AbstractB24`. Они ещё работают, но выводят предупреждение при каждом вызове и будут удалены в v2.0.0. Мигрируйте на соответствующий `b24.actions.v{2,3}..make({…})` — см. [руководство по миграции v0 → v1](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/migration/v1.md) для пошагового соответствия. - **`for (const id of ids) await b24.actions.v2.call.make(...)`.** N ID = N round-trip'ов. Используйте `actions.v2.batch.make`, если `ids.length ≤ 50`, иначе `actions.v2.batchByChunk.make`. - **`actions.v2.callList.make → actions.v2.callList.make → actions.v2.callList.make` для связанных сущностей.** Это причина большинства медленных дашбордов. Получите родительский список один раз (`actions.v2.callList.make` или `actions.v2.fetchList.make`), затем загрузите связанные записи через один `actions.v2.batch.make` на каждый чанк из 50 ID. - **Свой `order` в `actions.v{2,3}.callList.make` / `actions.v{2,3}.fetchList.make`.** Курсорной пагинации нужен `order: { idKey: 'ASC' }`. Любой пользовательский `order` отбрасывается с runtime-предупреждением (см. [Ограничения](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md#limitations)). Вместо этого используйте `filter`, чтобы сузить срез. - **`actions.v{2,3}.batch.make` с именованными командами на > 50 элементах.** Либо разбейте вручную на несколько вызовов `batch.make`, либо переключитесь на `actions.v{2,3}.batchByChunk.make` и используйте упорядоченные результаты. - **Смешивание методов v2 и v3 в одном вызове `actions.v3.batch.make`.** `BatchV3` предварительно валидирует список вызовов и бросает `SdkError` с кодом `JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3`, если какой-то метод не поддерживается в v3. Разделите батч по версиям API или используйте `actions.v2.batch.make`. ## См. также - [Рецепт: экспорт сделок в CSV](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/examples/dashboard-deals-csv.md) — `FetchList` для потокового экспорта. - [Рецепт: массовое обновление сделок](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/examples/bulk-update-deals.md) — `BatchByChunk` для массовой мутации. - [Коды ошибок и обработка](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/errors.md) — `SdkError`, `AjaxError`, коды на стороне REST. - [Система ограничений](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md) — выбор пресета `restrictionParams` для выбранного метода. --- # Фильтрация > Справочник по построению параметров фильтра в Bitrix24 REST API v2 (префиксные операторы) и v3 (массив троек), включая формат дат и правило отбрасывания order. ## Обзор В Bitrix24 **два диалекта фильтров**, и они не взаимозаменяемы — каждая версия API принимает только свой. - **v2** (`$b24.actions.v2.{call,callList,fetchList}.make`) использует **объект с префиксными ключами**: оператор — это префикс к имени поля. - **v3** (`$b24.actions.v3.{call,callList,fetchList}.make`) использует **массив троек**: `[field, operator, value]`. Передача фильтра в стиле v3 в v2-действие молча парсится неверно; передача фильтра в стиле v2 в v3-действие возвращает `UnknownFilterOperatorException`. ## v2 — префиксные операторы Оператор — это префикс к имени поля. Несколько ключей объединяются через `AND`. Два оператора на одном поле требуют двух отдельных ключей (например, диапазон). ```ts-type filter: { '>=opportunity': 50000, '<=opportunity': 200000, '!stageId': 'LOST', '=%title': 'A%' } ``` | Префикс | Значение | Пример | | --- | --- | --- | | (нет) | точное совпадение | `{ stageId: 'NEW' }` | | `>=` | больше либо равно | `{ '>=opportunity': 50000 }` | | `>` | больше | `{ '>id': 100 }` | | `<=` | меньше либо равно | `{ '<=opportunity': 200000 }` | | `<` | меньше | `{ '=', '2026-01-01T00:00:00+03:00'], ['responsibleId', 'in', [1, 2, 3]] ] ``` ### v3-операторы — всего 8 ```txt = != > >= < <= in between ``` > \[!NOTE] > > **Нет оператора `like` / `%` / подстроки** на уровне протокола v3. Поиск по > подстроке сейчас доступен только в v2 — используйте v2 с `%` или `=%`. Запрос v3 > `['title', 'like', 'A%']` падает с `UnknownFilterOperatorException`. - значение `between` должно быть массивом из 2 элементов: `[min, max]`. - значение `in` должно быть массивом. Двухаргументные формы — синтаксический сахар: ```ts-type ['id', 42] // то же, что ['id', '=', 42] ['stageId', ['A', 'B']] // то же, что ['stageId', 'in', ['A', 'B']] ``` Для всего, что сложнее плоского списка, предпочитайте типизированный билдер `FilterV3` — он валидирует операторы и форму `in` / `between` на стороне клиента. См. [скилл b24jssdk-filtering](https://github.com/bitrix24/b24jssdk/blob/main/skills/b24jssdk-filtering/SKILL.md){rel=""nofollow""}. ## Даты Используйте хелпер SDK `Text.toB24Format(date)` для **обоих** диалектов — он выдаёт формат Bitrix24 `yyyy-MM-dd'T'HH:mm:ssZZ` и принимает на вход `Date`, `DateTime` или `string`. ```ts import { Text } from '@bitrix24/b24jssdk' const sixMonthsAgo = new Date() sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6) // v2 const filterV2 = { '>=createdTime': Text.toB24Format(sixMonthsAgo) } // v3 const filterV3 = [['createdTime', '>=', Text.toB24Format(sixMonthsAgo)]] ``` > \[!NOTE] > > Всегда включайте смещение часового пояса в строки дат — порталы Bitrix24 > работают в часовом поясе, заданном на портале. `Text.toB24Format()` выводит > смещение за вас. ## Параметр `order` и list-действия `callList.make` и `fetchList.make` (и v2, и v3) **отбрасывают любой переданный `order`** и принудительно сортируют по id курсора (`{ [cursorIdKey]: 'ASC' }`), потому что листают набор данных keyset-курсором. Если передать `order`, SDK его отбрасывает и логирует `warning` — значение молча игнорируется для результирующего набора. Если нужен конкретный порядок сортировки, спуститесь до `call.make` и листайте вручную — но почти всегда вместо этого стоит **фильтровать точнее**. Подробности — [Ограничения CallList](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md#limitations). ## Бок о бок: один запрос в v2 и v3 Открытые сделки (`stageId` не в `WON` / `LOSE`) с суммой от 50 000 до 200 000, созданные за последние полгода: ```ts [v2] import { EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk' const sixMonthsAgo = new Date() sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6) const response = await $b24.actions.v2.callList.make({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.deal, filter: { '!stageId': ['WON', 'LOSE'], '>=opportunity': 50000, '<=opportunity': 200000, '>=createdTime': Text.toB24Format(sixMonthsAgo) }, select: ['id', 'title', 'stageId', 'opportunity'] }, idKey: 'id', customKeyForResult: 'items' }) ``` ```ts [v3] import { EnumCrmEntityTypeId, Text } from '@bitrix24/b24jssdk' const sixMonthsAgo = new Date() sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6) const response = await $b24.actions.v3.callList.make({ method: 'crm.item.list', params: { entityTypeId: EnumCrmEntityTypeId.deal, filter: [ // в v3 нет оператора «not in» — оберните `in` в NOT-группу (`negative: true`). // Хелпер `FilterV3.not(FilterV3.in(...))` строит ту же форму. { negative: true, conditions: [['stageId', 'in', ['WON', 'LOSE']]] }, ['opportunity', 'between', [50000, 200000]], ['createdTime', '>=', Text.toB24Format(sixMonthsAgo)] ], select: ['id', 'title', 'stageId', 'opportunity'] }, idKey: 'id', customKeyForResult: 'items' }) ``` ## См. также - [Выбор подходящего метода](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/choosing-the-right-method.md) — выбрать `Call` / `CallList` / `FetchList` / `Batch`. - [CallListV2](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) / [FetchListV2](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md) — list-действия, отбрасывающие `order`. - Скилл: [b24jssdk-filtering](https://github.com/bitrix24/b24jssdk/blob/main/skills/b24jssdk-filtering/SKILL.md){rel=""nofollow""} — полный справочник по контенту (билдер `FilterV3`, IN/between, мульти-воронка). --- # B24HelperManager > Агрегирующий менеджер, который загружает данные профиля, приложения, оплаты, лицензии, валют и опций одним батч-запросом REST, а также подключает Pull-клиент. ## Обзор `B24HelperManager` объединяет в один REST-вызов (`profile`, `app.info`, `crm.currency.base.get`, `crm.currency.list`, `app.option.get`, `user.option.get`) и предоставляет разобранный результат через специализированные суб-менеджеры. Он также владеет жизненным циклом [Pull-клиента](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/pull.md) — подключение, подписка, запуск, уничтожение. Обычно вы взаимодействуете с `B24HelperManager` косвенно — через composable [`useB24Helper`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-use-b24-helper.md). Прямое создание поддерживается, но требуется редко. ```ts import { useB24Helper, LoadDataType, initializeB24Frame } from '@bitrix24/b24jssdk' const { initB24Helper, getB24Helper } = useB24Helper() const $b24 = await initializeB24Frame() await initB24Helper($b24, [ LoadDataType.Profile, LoadDataType.App, LoadDataType.Currency, LoadDataType.AppOptions, LoadDataType.UserOptions ]) const helper = getB24Helper() console.log(helper.profileInfo.data, helper.appInfo.data) ``` ## Конструктор ```ts-type constructor(b24: TypeB24) ``` Принимает любой экземпляр `TypeB24` — `B24Frame`, `B24Hook` или `B24OAuth`. Хелпер **не** вызывает `init()` за вас; обёрнутый экземпляр должен быть уже инициализирован до запуска `loadData()`. ## Методы ### `loadData` ```ts-type loadData( dataTypes?: LoadDataType[], requestId?: string ): Promise ``` Получает запрошенные срезы данных через `actions.v2.batch.make({ isHaltOnError: true })`. После разрешения соответствующие геттеры (`profileInfo`, `appInfo` и т.д.) становятся доступны; до этого они выбрасывают `'B24HelperManager not initialized'`. `dataTypes` по умолчанию `[LoadDataType.App, LoadDataType.Profile]`. `requestId` по умолчанию `'helper-load-data'`. Переопределите его для трассируемости. #### Enum `LoadDataType` | Значение | Вызываемые REST-методы | Результирующий менеджер | | --- | --- | --- | | `App` | `app.info` | [`appInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-app-manager.md), [`paymentInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-payment-manager.md), [`licenseInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-license-manager.md) | | `Profile` | `profile` | [`profileInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-profile-manager.md) | | `Currency` | `crm.currency.base.get` + `crm.currency.list` | [`currency`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-currency-manager.md) | | `AppOptions` | `app.option.get` | [`appOptions`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-options-manager.md) | | `UserOptions` | `user.option.get` | [`userOptions`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-options-manager.md) | ### `getLogger` / `setLogger` ```ts-type getLogger(): LoggerInterface setLogger(logger: LoggerInterface): void ``` `setLogger` распространяет логгер во все разобранные суб-менеджеры. По умолчанию `LoggerFactory.createNullLogger()`. ### `destroy` ```ts-type destroy(): void ``` Разрушает Pull-клиент (отписка + отключение). Идемпотентен. ### Связка с Pull-клиентом ```ts-type usePullClient(prefix?: string, userId?: number): B24HelperManager subscribePullClient(callback: (message: TypePullMessage) => void, moduleId?: string): B24HelperManager startPullClient(): void getModuleIdPullClient(): string ``` Порядок важен: `usePullClient()` → `subscribePullClient()` (один или несколько раз) → `startPullClient()`. Полный процесс см. в [Pull-клиент](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/pull.md). `getModuleIdPullClient()` возвращает `moduleId`, последним переданный в `subscribePullClient`, предназначен для payload `pull.application.event.add`. ## Геттеры > \[!CAUTION] > > Все перечисленные ниже геттеры выбрасывают `'B24HelperManager not initialized'` до разрешения `loadData()`. Каждый отдельный геттер дополнительно выбрасывает исключение, если соответствующий `LoadDataType` не был запрошен. ### `isInit` ```ts-type get isInit(): boolean ``` `true` после успешного завершения `loadData()`. ### `profileInfo` / `appInfo` / `paymentInfo` / `licenseInfo` / `currency` / `appOptions` / `userOptions` Возвращают разобранный суб-менеджер. См.: - [ProfileManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-profile-manager.md) - [AppManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-app-manager.md) - [PaymentManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-payment-manager.md) - [LicenseManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-license-manager.md) - [CurrencyManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-currency-manager.md) - [OptionsManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-options-manager.md) ### `forB24Form` ```ts-type get forB24Form(): TypeB24Form ``` Возвращает плоский объект, подходящий для отправки в [форму обратной связи CRM](https://github.com/bitrix24/b24sdk-examples/blob/main/js/03-nuxt-frame/pages/feedback.client.vue){rel=""nofollow""} Bitrix24. Требует одновременно `LoadDataType.App` и `LoadDataType.Profile`. | Поле | Тип | Описание | | --- | --- | --- | | `app_code` | `string` | Код приложения в Bitrix24. | | `app_status` | `string` | Статус приложения (`F` / `D` / `T` / `P` / `L` / `S`). | | `payment_expired` | `BoolString` | `'Y'`, если платный/пробный период закончился, иначе `'N'`. | | `days` | `number` | Дней до / после окончания. | | `b24_plan` | `string` | Идентификатор облачного тарифа Bitrix24. | | `c_name` / `c_last_name` | `string` | Имя / фамилия из профиля. | | `hostname` | `string` | Адрес портала (например, `xxx.bitrix24.com`). | ### `hostName` ```ts-type get hostName(): string ``` Origin портала (`https://xxx.bitrix24.com`). Опирается на `b24.getTargetOrigin()`. ### `isSelfHosted` ```ts-type get isSelfHosted(): boolean ``` `true`, когда строка лицензии содержит `selfhosted`. Требует `LoadDataType.App`. ### `primaryKeyIncrementValue` ```ts-type get primaryKeyIncrementValue(): number ``` Возвращает шаг инкремента для полей типа ID: `1` на self-hosted, `2` в облаке. ### `b24SpecificUrl` ```ts-type get b24SpecificUrl(): Record ``` Возвращает URL-ы админ-зоны, различающиеся между облаком и self-hosted: | Ключ | Облако | Self-hosted | | --- | --- | --- | | `MainSettings` | `/settings/configs/` | `/configs/` | | `UfList` | `/settings/configs/userfield_list.php` | `/configs/userfield_list.php` | | `UfPage` | `/settings/configs/userfield.php` | `/configs/userfield.php` | --- # Composable useB24Helper > Основанный на замыкании composable, который владеет единственным экземпляром B24HelperManager и предоставляет хелперы жизненного цикла (init / destroy / связка с Pull-клиентом). ## Обзор `useB24Helper()` — это фабрика: каждый вызов возвращает новое замыкание с собственным слотом [`B24HelperManager`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md) и состоянием Pull-клиента. Оно устраняет дублирование инициализации между перерисовками и централизует уничтожение при размонтировании. ```ts import { useB24Helper, LoadDataType } from '@bitrix24/b24jssdk' const { initB24Helper, isInitB24Helper, destroyB24Helper, getB24Helper, usePullClient, useSubscribePullClient, startPullClient } = useB24Helper() ``` ## Возвращаемый API ### `initB24Helper` ```ts-type initB24Helper( $b24: TypeB24, dataTypes?: LoadDataType[], requestId?: string ): Promise ``` Создаёт `B24HelperManager` (один раз на замыкание) и вызывает `loadData(dataTypes, requestId)`. Последующие вызовы ничего не делают — они возвращают тот же менеджер без повторной загрузки. `dataTypes` по умолчанию `[LoadDataType.App, LoadDataType.Profile]`; `requestId` по умолчанию `'helper-load-data'`. ### `isInitB24Helper` ```ts-type isInitB24Helper(): boolean ``` Возвращает `true` после того, как `initB24Helper` разрешился хотя бы один раз. ### `destroyB24Helper` ```ts-type destroyB24Helper(): void ``` Вызывает `destroy()` на нижележащем менеджере (закрывая Pull-клиент) и сбрасывает флаги замыкания, чтобы новый вызов `initB24Helper` загрузил данные заново. ### `getB24Helper` ```ts-type getB24Helper(): B24HelperManager ``` Возвращает активный менеджер. Выбрасывает `'B24HelperManager is not initialized. You need to call initB24Helper first.'` при вызове до `initB24Helper`. ### Хелперы Pull-клиента ```ts-type usePullClient(): void useSubscribePullClient(callback: (message: TypePullMessage) => void, moduleId?: string): void startPullClient(): void ``` Тонкие обёртки над соответствующими методами `B24HelperManager`. Порядок: `usePullClient` → `useSubscribePullClient` (один или несколько) → `startPullClient`. Вызов `useSubscribePullClient` или `startPullClient` до `usePullClient` выбрасывает `'PullClient is not initialized. You need to call usePullClient first.'`. См. [Pull-клиент](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/pull.md). ## Enum `LoadDataType` ```ts-type enum LoadDataType { App = 'app', Profile = 'profile', Currency = 'currency', AppOptions = 'appOptions', UserOptions = 'userOptions' } ``` Каждое значение запускает один (или два для `Currency`) REST-метод внутри батча — см. таблицу на странице [B24HelperManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#loaddatatype-enum). ## Пример на Vue ```vue ``` --- # ProfileManager > Разобранный ответ REST-метода \`profile\`: id, имя, фамилия, пол, фото, часовой пояс, флаг администратора. `ProfileManager` оборачивает ответ REST-метода `profile`. Создаётся через [`B24HelperManager.loadData`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#loaddata), когда запрошен `LoadDataType.Profile`; доступен через [`B24HelperManager.profileInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#profileinfo--appinfo--paymentinfo--licenseinfo--currency--appoptions--useroptions). ## Использование ```ts import { useB24Helper, LoadDataType } from '@bitrix24/b24jssdk' const { initB24Helper, getB24Helper } = useB24Helper() await initB24Helper($b24, [LoadDataType.Profile]) const profile = getB24Helper().profileInfo.data console.log(profile.id, profile.name, profile.lastName, profile.isAdmin) ``` ## Геттер `data` ```ts-type get data(): TypeUser ``` Возвращает типизированный снимок профиля. Выбрасывает `'ProfileManager.data not initialized'`, если `loadData` ещё не был вызван. ### Поля `TypeUser` | Поле | Тип | Описание | | --- | --- | --- | | `id` | `null | number` | Идентификатор пользователя. | | `isAdmin` | `boolean` | `true`, если у пользователя есть права администратора на портале. | | `name` | `null | string` | Имя. | | `lastName` | `null | string` | Фамилия. | | `gender` | `'M' | 'F' | ''` | `'M' / 'F' / ''` (нет значения). | | `photo` | `null | string` | URL фото профиля. | | `TimeZone` | `null | string` | Часовой пояс IANA (например, `Europe/Moscow`). | | `TimeZoneOffset` | `null | number` | Смещение в секундах. | --- # AppManager > Разобранный ответ REST-метода \`app.info\`: id приложения, код, версия, статус, флаг установки. `AppManager` оборачивает ответ `app.info`. Создаётся через [`B24HelperManager.loadData`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#loaddata), когда запрошен `LoadDataType.App`; доступен через [`B24HelperManager.appInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#profileinfo--appinfo--paymentinfo--licenseinfo--currency--appoptions--useroptions). ## Использование ```ts import { useB24Helper, LoadDataType } from '@bitrix24/b24jssdk' const { initB24Helper, getB24Helper } = useB24Helper() await initB24Helper($b24, [LoadDataType.App]) const app = getB24Helper().appInfo console.log(app.data.code, app.data.version, app.statusCode) ``` ## Геттер `data` ```ts-type get data(): TypeApp ``` | Поле | Тип | Описание | | --- | --- | --- | | `id` | `number` | Идентификатор локального приложения на портале. | | `code` | `string` | Код приложения (`local.xxxxxx.xxxxxx`). | | `version` | `number` | Установленная версия. | | `status` | `TypeEnumAppStatus` | Одно из `'F' / 'D' / 'T' / 'P' / 'L' / 'S'`. | | `isInstalled` | `boolean` | Флаг установки от Bitrix24. | ## Геттер `statusCode` ```ts-type get statusCode(): string ``` Преобразует исходную букву `status` в человекочитаемую метку, используя таблицу `StatusDescriptions`: | Буква | `statusCode` | | --- | --- | | `F` | `Free` | | `D` | `Demo` | | `T` | `Trial` | | `P` | `Paid` | | `L` | `Local` | | `S` | `Subscription` | Возвращает `'Unknown status'` для неизвестных букв. --- # PaymentManager > Статус оплаты приложения Bitrix24 — извлекается из \`app.info\`. `PaymentManager` оборачивает связанные с оплатой поля `app.info` (`PAYMENT_EXPIRED`, `DAYS`). Создаётся, когда запрошен `LoadDataType.App`; доступен через [`B24HelperManager.paymentInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#profileinfo--appinfo--paymentinfo--licenseinfo--currency--appoptions--useroptions). ## Использование ```ts import { useB24Helper, LoadDataType } from '@bitrix24/b24jssdk' const { initB24Helper, getB24Helper } = useB24Helper() await initB24Helper($b24, [LoadDataType.App]) const payment = getB24Helper().paymentInfo.data if (payment.isExpired) { console.warn(`Paid period ended ${payment.days} day(s) ago`) } ``` ## Геттер `data` ```ts-type get data(): TypePayment ``` | Поле | Тип | Описание | | --- | --- | --- | | `isExpired` | `boolean` | `true`, когда платный период или пробный период закончился. | | `days` | `number` | Оставшиеся дни (когда `isExpired === false`) или дни с момента окончания (когда `isExpired === true`). | --- # LicenseManager > Информация о лицензии Bitrix24 из \`app.info\` — и автоматическая перенастройка менеджера ограничений под соответствующий тарифный план. `LicenseManager` оборачивает поля лицензии `app.info` (`LICENSE`, `LICENSE_TYPE`, `LICENSE_FAMILY`, `LICENSE_PREVIOUS`, `LANGUAGE_ID`). Создаётся, когда запрошен `LoadDataType.App`; доступен через [`B24HelperManager.licenseInfo`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#profileinfo--appinfo--paymentinfo--licenseinfo--currency--appoptions--useroptions). > \[!NOTE] > > При `initData` `LicenseManager` вызывает [`ParamsFactory.fromTariffPlan(license)`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/limiters/params-factory.ts){rel=""nofollow""} и применяет результат через `b24.setRestrictionManagerParams(...)`. Это подставляет enterprise-уровень rate limit, когда портал на enterprise-тарифе. См. [Лимитеры](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md). ## Использование ```ts import { useB24Helper, LoadDataType } from '@bitrix24/b24jssdk' const { initB24Helper, getB24Helper } = useB24Helper() await initB24Helper($b24, [LoadDataType.App]) const license = getB24Helper().licenseInfo.data console.log(license.license, license.isSelfHosted) ``` ## Геттер `data` ```ts-type get data(): TypeLicense ``` | Поле | Тип | Описание | | --- | --- | --- | | `languageId` | `null | string` | Код языка портала. | | `license` | `null | string` | Обозначение тарифа с префиксом региона (`ru_team`, `b24_enterprise`, …). | | `licenseType` | `null | string` | Обозначение тарифа без префикса региона. | | `licensePrevious` | `null | string` | Предыдущая лицензия (если применимо). | | `licenseFamily` | `null | string` | Семейство тарифа (`team`, `enterprise`, …). | | `isSelfHosted` | `boolean` | `true`, если `license` содержит `selfhosted`. | ## Метод `makeRestrictionManagerParams` ```ts-type makeRestrictionManagerParams(): Promise ``` Повторно применяет ограничения, выведенные из тарифа. Вызывается автоматически из `initData`; вызывать вручную нужно только если вы уже переопределили конфигурацию лимитера и хотите сбросить её к значениям тарифа по умолчанию. --- # CurrencyManager > Каталог валют, кэшируемый в памяти — базовая валюта, форматтеры для каждой валюты и форматтер числа в строку. `CurrencyManager` кэширует результат `crm.currency.base.get` + `crm.currency.list` (и последующий батч `crm.currency.get` для форматтеров по языкам). Создаётся, когда запрошен `LoadDataType.Currency`; доступен через [`B24HelperManager.currency`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#profileinfo--appinfo--paymentinfo--licenseinfo--currency--appoptions--useroptions). ## Использование ```ts import { useB24Helper, LoadDataType } from '@bitrix24/b24jssdk' const { initB24Helper, getB24Helper } = useB24Helper() await initB24Helper($b24, [LoadDataType.Currency]) const currency = getB24Helper().currency console.log(currency.baseCurrency) // 'USD' console.log(currency.currencyList) // ['USD', 'EUR', 'RUB', ...] console.log(currency.format(1234.5, 'USD', 'en')) // '$1,234.50' ``` ## Геттеры ### `baseCurrency` ```ts-type get baseCurrency(): string ``` Код базовой валюты портала (`USD`, `RUB`, …). ### `currencyList` ```ts-type get currencyList(): string[] ``` Массив доступных кодов валют. ### `data` ```ts-type get data(): { currencyBase: string, currencyList: Map } ``` Внутренний кэш. Тип значения `Currency` описан в [`b24-helper.ts`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/b24-helper.ts){rel=""nofollow""}. ## Методы ### `getCurrencyFullName` ```ts-type getCurrencyFullName(currencyCode: string, langCode?: string): string ``` Локализованное полное название (например, `Russian Ruble`). Выбрасывает `UnhandledMatchError` для неизвестного `currencyCode`. ### `getCurrencyLiteral` ```ts-type getCurrencyLiteral(currencyCode: string, langCode?: string): string ``` Символ/литерал валюты, извлечённый из строки формата (например, `$`, `₽`). ### `format` ```ts-type format(value: number, currencyCode: string, langCode: string): string ``` Возвращает значение, отформатированное по `formatString`, `decimals`, `decPoint`, `thousandsSep` для конкретного языка (с тем же отображением `THOUSANDS_VARIANT`, которое Bitrix24 использует на сервере). ### `setBaseCurrency` / `setCurrencyList` ```ts-type setBaseCurrency(currencyBase: string): void setCurrencyList(list: CurrencyInit[]): void ``` Ручные переопределения — в основном используются внутренне во время `initData`. --- # OptionsManager > Типизированный доступ к \`app.option.get\` / \`user.option.get\`, плюс save(), который батчит \`\*.option.set\` с необязательным Pull-уведомлением. `OptionsManager` создаётся дважды — один раз для `app.option.get` и один раз для `user.option.get`. Доступен через [`B24HelperManager.appOptions`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#profileinfo--appinfo--paymentinfo--licenseinfo--currency--appoptions--useroptions) и [`B24HelperManager.userOptions`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#profileinfo--appinfo--paymentinfo--licenseinfo--currency--appoptions--useroptions). Он хранит значения опций на сервере как сырые строки и конвертирует их при чтении. ## Использование ```ts import { useB24Helper, LoadDataType } from '@bitrix24/b24jssdk' const { initB24Helper, getB24Helper } = useB24Helper() await initB24Helper($b24, [LoadDataType.AppOptions, LoadDataType.UserOptions]) const helper = getB24Helper() // Чтение со значением по умолчанию const filters = helper.userOptions.getJsonObject('listFilters', {}) const itemsPerPage = helper.userOptions.getInteger('itemsPerPage', 20) // Сохранение await helper.appOptions.save( { theme: 'dark' }, { moduleId: 'main', command: 'optionsChanged', params: { theme: 'dark' } } ) ``` ## Типизированные геттеры | Метод | Возвращает | По умолчанию | Примечания | | --- | --- | --- | --- | | `getJsonArray(key, def?)` | `any[]` | `[]` | Парсит JSON, также принимает JSON-объекты (возвращает `Object.values`). | | `getJsonObject(key, def?)` | `object` | `{}` | Парсит JSON, при неудаче возвращает `def`. | | `getFloat(key, def?)` | `number` | `0.0` | Использует `Text.toNumber`. | | `getInteger(key, def?)` | `number` | `0` | Использует `Text.toInteger`. | | `getBoolYN(key, def?)` | `boolean` | `true` | `'Y'` → `true`, `'N'` → `false`. | | `getBoolNY(key, def?)` | `boolean` | `false` | То же преобразование, что и `getBoolYN`, но другое значение по умолчанию. | | `getString(key, def?)` | `string` | `''` | Вызывает `.toString()`. | | `getDate(key, def?)` | `null | DateTime` | `null` | Использует `Text.toDateTime` (Luxon). | ## Статические хелперы ```ts-type OptionsManager.getSupportTypes(): TypeOption[] OptionsManager.prepareArrayList(list: any): any[] ``` `TypeOption` перечисляет поддерживаемые формы значений (`NotSet / JsonArray / JsonObject / FloatVal / IntegerVal / BoolYN / StringVal`). ## Методы кэша ```ts-type get data(): Map reset(): void ``` `data` — это сырая карта ключ→строка. `reset()` очищает кэш в памяти, не затрагивая сервер. ## Сохранение ```ts-type save( options: Record, optionsPull?: { moduleId: string, command: string, params: any }, requestId?: string ): Promise ``` Выполняет один батч-вызов: 1. `app.option.set` для `appOptions` / `user.option.set` для `userOptions`, с переданным payload `options`. 2. Необязательно `pull.application.event.add`, чтобы другие клиенты были уведомлены об изменении. Оба вызова используют `isHaltOnError: true`. Возвращает оборачивающий [`Result`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-result.md). > \[!NOTE] > > `save()` **не** обновляет локальный кэш. Вызовите `getB24Helper().loadData([LoadDataType.AppOptions])` (или повторно запустите `initB24Helper`), если нужно, чтобы новое состояние было видно последующим чтениям `getX()`. ## Хелперы кодирования ```ts-type encode(value: any): string // обёртка над JSON.stringify decode(data: string, defaultValue: any): any // JSON.parse с логированием ошибки ``` Удобные обёртки над `JSON.stringify` / `JSON.parse`, которые логируют ошибки парсинга через логгер менеджера. --- # Коды ошибок и обработка > Справочник кодов SdkError и AjaxError, выбрасываемых SDK, плюс коды ошибок REST Bitrix24, которые через них проявляются. ## Обзор SDK выбрасывает ошибки через два связанных класса: - `SdkError` — выбрасывается самим кодом SDK (валидация, конфигурация, устаревшие пути, внутренние инварианты). Всегда несёт `code`, `status` (HTTP-подобный) и необязательный `originalError`. - `AjaxError extends SdkError` — выбрасывается, когда HTTP-вызов к Bitrix24 завершается неудачей. Добавляет `requestInfo` (`method`, `requestId`, параметры запроса), чтобы вы могли сопоставлять с логами на стороне портала. Начиная с v1.1.2 (#39), `requestInfo` **не** включает полный URL запроса, а поля с учётными данными внутри `params` редактируются — цель в том, чтобы секреты вебхуков не попадали в вывод `toJSON()` / `toString()`. Методы, которые не выбрасывают исключения — `Call`, `CallList`, `Batch`, `BatchByChunk` — сообщают о сбоях через `Result`/`AjaxResult`: проверяйте `.isSuccess` и читайте `.getErrorMessages()`. `FetchList`, напротив, **выбрасывает** исключение при сбое (генератор не может завершиться частично). ```ts import { SdkError, AjaxError } from '@bitrix24/b24jssdk' try { // …вызовы SDK } catch (error) { if (error instanceof AjaxError) { // сетевой / портальный сбой; error.code — это код Bitrix24 console.error(error.code, error.status, error.requestInfo?.method, error.requestInfo?.requestId) } else if (error instanceof SdkError) { // проблема на стороне SDK; error.code начинается с JSSDK_ console.error(error.code, error.status) } else { throw error } } ``` ## Коды SdkError, выбрасываемые SDK Коды — стабильные строки; сопоставляйте по ним, не парсите сообщения. | Код | Статус | Где выбрасывается | Что означает | | --- | --- | --- | --- | | `JSSDK_CORE_B24_NOT_INIT` | 500 | геттеры `AbstractB24` | Вы вызвали метод на экземпляре `B24`, конструктор которого не завершился. Для `B24Frame` дождитесь `initializeB24Frame()`; для `B24Hook` URL был некорректным. | | `JSSDK_CORE_B24_HTTP_V2_NOT_INIT` | 500 | `getHttpClient(ApiVersion.v2)` | HTTP-клиент v2 не был создан (обычно ошибка конфигурации). | | `JSSDK_CORE_B24_HTTP_V3_NOT_INIT` | 500 | `getHttpClient(ApiVersion.v3)` | То же, для v3. | | `JSSDK_CORE_B24_API_WRONG` | 500 | `getHttpClient` | Запрошена неизвестная `ApiVersion`. | | `JSSDK_CORE_DEPRECATED_METHOD` | — | только логгер | Не выбрасывается — выводится как `warning`-лог при вызове устаревших `callMethod` / `callBatch` / `callListMethod` / `fetchListMethod` / `callBatchByChunk`. Перейдите на `b24.actions.v2.*` / `v3.*`. | | `JSSDK_CORE_METHOD_AVAILABLE_IN_API_V3` | — | только логгер | Предупреждение, выводимое `CallV2.make()`, когда метод также существует в v3. Перейдите, когда сможете. | | `JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3` | 500 | `CallV3.make()`, `BatchV3.make()`, `AjaxResult.getNext()` | Вы попросили v3 выполнить метод, которого нет в поверхности v3. Используйте v2 или разбейте батч по версиям API. | | `JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V2` | 500 | генератор `FetchListV2.make()` | Нижележащий запрос страницы завершился неудачей; генератор останавливается. Оборачивайте `for await` в try/catch. | | `JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V3` | 500 | генератор `FetchListV3.make()` | То же, для v3. | | `JSSDK_VERSION_MANAGER_NOT_DETECT_FOR_METHOD` | — | `versionManager` | Внутренний — не удалось определить версию API метода. Обычно идёт в паре с одним из кодов выше. | | `JSSDK_BATCH_TOO_LARGE` | 400 | HTTP-клиент v2 | В один батч передано более 50 команд. Используйте `BatchByChunk`. | | `JSSDK_BATCH_EMPTY` | 400 | HTTP-клиент v2 | Пустой `calls`. | | `JSSDK_BATCH_SUB_ERROR` | 500 | обработка батча | Обёртка для сбоя вложенного вызова внутри батча. Проверьте результат конкретного вызова. | | `JSSDK_INTERACTION_BATCH_BUILD_STRATEGY_V3_EMPTY_COMMAND` | 400 | обработка батча v3 | Отдельная команда в v3-батче была пустой/некорректной. | | `JSSDK_INTERACTION_BATCH_BUILD_STRATEGY_V3_EMPTY_COMMANDS` | 400 | обработка батча v3 | Весь массив `commands` был пуст. | | `JSSDK_INTERACTION_BATCH_STRATEGY_V2_EMPTY_COMMANDS` | 400 | обработка батча v2 | То же, для v2. | | `JSSDK_INTERACTION_BATCH_STRATEGY_V2_EMPTY_COMMAND_RESPONSE` | 500 | обработка батча v2 | У команды в ответе не было тела — обычно на стороне портала. | | `JSSDK_INTERACTION_BATCH_EMPTY_PROCESSING_STRATEGY` | 500 | обработка батча | Внутренний — не удалось найти стратегию. | | `JSSDK_INTERACTION_BATCH_ROW_FAIL` | 500 | парсер строки батча | Не удалось разобрать одну строку батча. | | `JSSDK_INVALID_PARAMS` | 400 | HTTP-транспорт | Форма `params` была отклонена до отправки запроса. | | `JSSDK_PARAMS_TOO_LARGE` | 413 | HTTP-транспорт | Сериализованное тело запроса превысило лимит размера. Разбейте вызов. | | `JSSDK_CALL_ALL_ATTEMPTS_EXHAUSTED` | 500 | HTTP-транспорт | Повторы (по умолчанию 3, настраивается через `RestrictionParams.maxRetries`) исчерпаны до того, как вызов удался. | | `JSSDK_UNKNOWN_ERROR` | 500 | разное | Запасной вариант, когда не подходит более конкретный код. | | `JSSDK_INTERNAL_ERROR` | 500 | `SdkError.fromException` | Код по умолчанию при оборачивании неизвестного исключения. | | `JSSDK_INTERNAL_AJAX_ERROR` | 500 | `AjaxError.fromException` | Код по умолчанию при оборачивании неизвестной HTTP-ошибки. | | `JSSDK_CLIENT_SIDE_WARNING` | — | конструктор `B24Hook` | Предупреждение при создании `B24Hook` в браузере — вебхуки раскрывают секрет уровня портала и не должны попадать в клиентские бандлы. | ## Коды со стороны REST, возвращаемые как `AjaxError` Bitrix24 возвращает их в поле `error` HTTP-ответа. SDK переносит их в `AjaxError.code` как есть — сопоставляйте по строке. | Код | HTTP-статус | Значение | Типичное решение | | --- | --- | --- | --- | | `expired_token` | 401 | OAuth access token истёк. | SDK автообновляет для `B24Frame` и `B24OAuth`; для кастомных транспортов — обновите и повторите один раз. | | `invalid_token` | 401 | Токен некорректен или отозван. | Пользователь должен переавторизоваться (OAuth-флоу); URL вебхука неверен. | | `AUTHORIZE_ERROR` | 403 | Вызывающему не разрешено выполнять это действие. | Неверный scope у вебхука/приложения, или у пользователя нет права доступа (например, права CRM). | | `WRONG_AUTH_TYPE` | 403 | Тип токена не соответствует endpoint (например, вебхук использован там, где требуется OAuth). | Используйте правильный метод аутентификации для endpoint. | | `QUERY_LIMIT_EXCEEDED` | 503 | Достигнут rate limit (на секунду / на метод). | Уже обрабатывается встроенным `RateLimiter` — увеличивайте `restrictionParams.maxConcurrent` только если понимаете цену. | | `OVERLOAD_LIMIT` | 503 | Сброс нагрузки на уровне всего портала. | Сделайте паузу, повторите через несколько секунд. `AdaptiveDelayer` SDK уже это делает. | | `ERROR_METHOD_NOT_FOUND` | 400 | Неверное имя метода, или у приложения нет scope, чтобы его видеть. | Проверьте написание; сверьте `SCOPE` из `app.info` с требуемым scope метода. | | `INVALID_REQUEST` | 400 | Плохие параметры (отсутствует обязательное поле, неверный тип). | Проверьте `error.message` — описание Bitrix24 называет проблемное поле. | Это не исчерпывающий список — полный список по методам Bitrix24 публикует на [apidocs.bitrix24.ru](https://apidocs.bitrix24.ru/){rel=""nofollow""}. Всё, что здесь не перечислено, проходит как есть в `AjaxError.code`. ## Паттерны обработки ### Отличить баги SDK от сбоев на стороне портала `AjaxError` наследует `SdkError`, поэтому располагайте проверки `instanceof` от частного к общему: ::rest-api-version-only #rest-api-ver2 // @check-ignore: top-level try/catch with return, not valid at module scope ```ts import { AjaxError, SdkError } from '@bitrix24/b24jssdk' try { await $b24.actions.v2.call.make({ method: 'crm.deal.get', params: { id: 1 } }) } catch (error) { if (error instanceof AjaxError) { // Сторона портала: error.code — это код Bitrix24 (например, expired_token) if (error.code === 'expired_token') return refreshAndRetry() if (error.code === 'AUTHORIZE_ERROR') return showPermissionDenied() throw error } if (error instanceof SdkError) { // Сторона SDK: error.code начинается с JSSDK_ throw error // это ошибки программиста, показывайте их } throw error } ``` #rest-api-ver3 // @check-ignore: top-level try/catch with return, not valid at module scope ```ts import { AjaxError, SdkError } from '@bitrix24/b24jssdk' try { await $b24.actions.v3.call.make({ method: 'crm.deal.get', params: { id: 1 } }) } catch (error) { if (error instanceof AjaxError) { // Сторона портала: error.code — это код Bitrix24 (например, expired_token) if (error.code === 'expired_token') return refreshAndRetry() if (error.code === 'AUTHORIZE_ERROR') return showPermissionDenied() throw error } if (error instanceof SdkError) { // Сторона SDK: error.code начинается с JSSDK_ throw error // это ошибки программиста, показывайте их } throw error } ``` ### Используйте `isSuccess` для невыбрасывающих методов `Call`, `CallList`, `Batch`, `BatchByChunk` возвращают `Result` / `AjaxResult` вместо выброса исключения: ::rest-api-version-only #rest-api-ver2 // @check-ignore: top-level return in callList error-handling illustration ```ts const response = await $b24.actions.v2.callList.make({ /* … */ }) if (!response.isSuccess) { console.error(response.getErrorMessages().join('; ')) return } const items = response.getData() ``` #rest-api-ver3 // @check-ignore: top-level return in callList error-handling illustration ```ts const response = await $b24.actions.v3.callList.make({ /* … */ }) if (!response.isSuccess) { console.error(response.getErrorMessages().join('; ')) return } const items = response.getData() ``` Для батчей с `isHaltOnError: false` `isSuccess` становится false при **любом** сбое вложенного вызова, но `getData()` всё равно содержит успешные записи. Итерируйте и проверяйте `.isSuccess` по каждой строке, если нужно знать, какие вызовы прошли. ### Оборачивайте `for await` в try/catch для `FetchList` ::rest-api-version-only #rest-api-ver2 // @check-ignore: top-level for-await in fetchList error-handling illustration ```ts try { for await (const chunk of $b24.actions.v2.fetchList.make({ /* … */ })) { await persist(chunk) } } catch (error) { if ( error instanceof SdkError && error.code === 'JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V2' ) { // запрос страницы завершился неудачей; сохранённые до этого момента чанки всё ещё валидны return resumeFromLastSavedId() } throw error } ``` #rest-api-ver3 // @check-ignore: top-level for-await in fetchList error-handling illustration ```ts try { for await (const chunk of $b24.actions.v3.fetchList.make({ /* … */ })) { await persist(chunk) } } catch (error) { if ( error instanceof SdkError && error.code === 'JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V3' ) { // запрос страницы завершился неудачей; сохранённые до этого момента чанки всё ещё валидны return resumeFromLastSavedId() } throw error } ``` ### Решите, что повторять | Условие ошибки | Безопасно повторять? | | --- | --- | | `QUERY_LIMIT_EXCEEDED`, `OVERLOAD_LIMIT` | Да — встроенный лимитер уже это делает. | | `expired_token` (Frame/OAuth) | Да — уже автоматически. Для кастомных транспортов: обновите, повторите один раз. | | `invalid_token`, `AUTHORIZE_ERROR`, `WRONG_AUTH_TYPE` | Нет — нужно вмешательство человека (переавторизация, исправление scope). | | `ERROR_METHOD_NOT_FOUND`, `INVALID_REQUEST` | Нет — запрос некорректен; повтор даст ту же ошибку. | | Сеть / 5xx без конкретного кода | Да — но только через границу `JSSDK_CALL_ALL_ATTEMPTS_EXHAUSTED`; увеличьте `restrictionParams.maxRetries`, если нужно больше попыток. | ## См. также - [Выбор метода](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/choosing-the-right-method.md) — подбирает правильный примитив до того, как вам придётся читать эту страницу. - [Система ограничений](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md) — конфигурация rate limit, времени операций и адаптивной задержки. - [`AjaxResult`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-result.ts){rel=""nofollow""} — полная поверхность payload (`isSuccess`, `getData`, `getErrorMessages`). Пейджинговые хелперы только для v2 — `isMore`, `hasMore`, `getNext`, `fetchNext` и `getTotal` — устарели и намечены к удалению в 2.0.0; используйте вместо них [`b24.actions.v{2,3}.callList.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver2.md) или [`fetchList.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver2.md). `getNext()` продолжает выбрасывать `JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3` на клиентах v3. --- # Pull (Push & Pull) > Поток сообщений в реальном времени от Bitrix24 к вашему приложению — WebSocket как основной канал, long-polling как запасной. Только для фрейма. > \[!CAUTION] > > Pull-клиент предназначен для **фрейм-приложений** (`B24Frame`) — он опирается на авторизацию родительского окна, каналы и `member_id`. Он **не** работает через `B24Hook` или `B24OAuth` на сервере. ## Обзор Pull позволяет фронтенду вашего приложения получать события, которые бэкенд (или другой экземпляр фронтенда) порождает через REST-метод [`pull.application.event.add`](https://apidocs.bitrix24.ru/api-reference/interactivity/push-and-pull/pull-application-event-add.html){rel=""nofollow""}. SDK поставляет полноценный клиент (`B24PullClientManager`) с двумя коннекторами: - WebSocket как основной (`ConnectionType.WebSocket`) - Long-polling как запасной (`ConnectionType.LongPolling`) - Конверты сообщений в кодировке Protobuf (декодеры включены, без доп. зависимостей) Обычно вы управляете Pull через [`useB24Helper`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper-use-b24-helper.md) — `usePullClient` / `useSubscribePullClient` / `startPullClient` являются тонкими обёртками над соответствующими методами [`B24HelperManager`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md). ## Быстрый старт ```ts import { initializeB24Frame, useB24Helper, Text, LoggerFactory, type B24Frame, type TypePullMessage } from '@bitrix24/b24jssdk' const $logger = LoggerFactory.createForBrowser('MyApp', import.meta.env?.DEV === true) const { initB24Helper, getB24Helper, usePullClient, useSubscribePullClient, startPullClient, destroyB24Helper } = useB24Helper() let $b24: B24Frame async function init() { $b24 = await initializeB24Frame() await initB24Helper($b24) // 1. Поднимаем нижележащий B24PullClientManager (один на экземпляр хелпера) usePullClient() // 2. Подписка — можно вызывать несколько раз для нескольких moduleId useSubscribePullClient((message: TypePullMessage) => { $logger.info(`${Text.getDateForLog()} << pull`, { message }) }, 'main') // 3. Подключение (WebSocket → запасной long-polling) startPullClient() } async function emitPing(): Promise { await $b24.actions.v2.call.make({ method: 'pull.application.event.add', params: { COMMAND: 'ping', PARAMS: { tick: Text.getDateForLog() }, MODULE_ID: getB24Helper().getModuleIdPullClient() } }) } await init() setInterval(emitPing, 5000) ``` Когда хост-компонент размонтируется, вызовите `destroyB24Helper()` — это закрывает WebSocket и очищает все подписки. ## API через `B24HelperManager` Эти четыре метода — публичная поверхность Pull. См. [B24HelperManager](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/helper.md#pull-client-glue). ```ts-type usePullClient(prefix?: string, userId?: number): B24HelperManager subscribePullClient(callback: (message: TypePullMessage) => void, moduleId?: string): B24HelperManager startPullClient(): void getModuleIdPullClient(): string ``` - `usePullClient` создаёт `B24PullClientManager` один раз. `prefix` передаётся в `b24.auth.getUniq(prefix)` для вычисления `restApplication`. `userId` по умолчанию — id загруженного профиля. - `subscribePullClient` возвращает хелпер для цепочек; хендл отписки отслеживается внутри и освобождается при `destroy()`. - `startPullClient` запускает `PullClient.start()` и логирует сбой (не выбрасывая исключение), если соединение установить не удалось. - `getModuleIdPullClient` возвращает `moduleId`, последним переданный в `subscribePullClient`. Используйте его как параметр `MODULE_ID` метода `pull.application.event.add`. ## API напрямую через `B24PullClientManager` Если нужен более тонкий контроль, создайте клиент сами: // @check-ignore: partial snippet — B24PullClientManager SubscriptionType not exported publicly ```ts import { B24PullClientManager } from '@bitrix24/b24jssdk' const pull = new B24PullClientManager({ b24: $b24, restApplication: $b24.auth.getUniq('myApp'), userId: 1 }) const unsubscribe = pull.subscribe({ type: 'server', // 'server' | 'client' | 'online' moduleId: 'main', command: 'optionsChanged', callback: (params) => console.log(params) }) await pull.start() // Позже unsubscribe() pull.destroy() ``` `subscribe()` принимает либо полный объект `TypeSubscriptionOptions` (фильтр по `type` / `moduleId` / `command`), либо просто функцию `TypeSubscriptionCommandHandler` (ловит любую входящую команду). Возвращает callback отписки. ## Типы соединений Клиент выбирает коннектор автоматически: 1. WebSocket — предпочтителен, когда портал его предоставляет. 2. Long-polling — используется, когда WebSocket недоступен, заблокирован или соединение постоянно обрывается. `ConnectionType` (`Undefined / WebSocket / LongPolling`) и `PullStatus` (`Online / Offline / Connecting`) экспортируются из пакета — полезно, если хотите отразить состояние соединения в UI. ## Отправка сообщений Pull-клиент только **получает** сообщения. Чтобы отправить, вызывайте `pull.application.event.add` через REST: // @check-ignore: partial snippet — getB24Helper() not in scope ```ts await $b24.actions.v2.call.make({ method: 'pull.application.event.add', params: { COMMAND: 'optionsChanged', PARAMS: { theme: 'dark' }, MODULE_ID: getB24Helper().getModuleIdPullClient() } }) ``` Подписчики, добавленные через `useSubscribePullClient(cb, 'main')`, получат соответствующий `TypePullMessage`. --- # Logger > Логгер, вдохновлённый PHP Monolog, предоставляет структурированную систему логирования с поддержкой каналов, обработчиков, процессоров и форматтеров. Реализация следует принципам PSR-3 и паттерну цепочки ответственности. > \[!WARNING] > > Мы всё ещё дорабатываем эту страницу. Некоторых данных здесь может не хватать — скоро дополним. ## Уровни логирования Уровни логирования расположены по возрастанию серьёзности — от **детальной отладки** (0) до **критических сбоев** (7). Фильтрация работает по включающему принципу: когда задан определённый уровень, логируются сообщения этого уровня и всех более высоких. | Уровень | Значение | Когда использовать | Практический пример | | --- | --- | --- | --- | | **DEBUG** | 0 | Детальная отладочная информация для разработчиков :br**По умолчанию в development** | `Loaded 1523 records in 45ms` | | **INFO** | 1 | Информация о нормальной работе приложения :br Отслеживание бизнес-логики | `User #123 added item to cart` | | **NOTICE** | 2 | Важные, но некритичные события :br Успешные операции с последствиями | `System settings changed by administrator` | | **WARNING** | 3 | Потенциальные проблемы :br Приложение работает, но требует внимания | `Cache almost full (95%)` | | **ERROR** | 4 | Ошибки времени выполнения, требующие вмешательства :br Часть функциональности недоступна | `Failed to connect to database` | | **CRITICAL** | 5 | Критические сбои компонентов :br Требуют срочного вмешательства в рабочее время | `Payment gateway unavailable for more than 5 minutes` | | **ALERT** | 6 | Серьёзные проблемы, требующие немедленного решения | `Disk space exhausted at 99%` | | **EMERGENCY** | 7 | Система неработоспособна :br Наивысший уровень срочности | `Server farm completely unavailable` | ### Как работает фильтрация по уровням ```ts import { Logger, ConsoleHandler, LogLevel } from '@bitrix24/b24jssdk' // Пример 1: уровень ERROR const $logger = new Logger('app'); $logger.pushHandler(new ConsoleHandler(LogLevel.ERROR)); // Эти логи БУДУТ выведены: $logger.error('Loading error', {}); // ✓ уровень 4 >= 4 $logger.critical('Critical error'); // ✓ уровень 5 >= 4 $logger.alert('Alert'); // ✓ уровень 6 >= 4 $logger.emergency('Emergency'); // ✓ уровень 7 >= 4 // Эти логи НЕ будут выведены: $logger.debug('Debug'); // ✗ уровень 0 < 4 $logger.info('Info'); // ✗ уровень 1 < 4 $logger.warning('Warning'); // ✗ уровень 3 < 4 ``` ## Основные типы и интерфейсы **LogRecord** Структура записи лога: ```ts-type { channel: string, // Имя канала логгера level: LogLevel, // Числовой уровень levelName: LogLevelName, // Имя уровня (например, 'DEBUG') message: string, // Текст сообщения context: Record, // Контекстные данные extra: Record, // Дополнительные данные (добавляются процессорами) timestamp: Date // Временная метка } ``` **LoggerInterface** Основной интерфейс логгера: ```ts-type log(level: LogLevel, message: string, context?: Record): Promise debug(message: string, context?: Record): Promise info(message: string, context?: Record): Promise notice(message: string, context?: Record): Promise warning(message: string, context?: Record): Promise error(message: string, context?: Record): Promise critical(message: string, context?: Record): Promise alert(message: string, context?: Record): Promise emergency(message: string, context?: Record): Promise ``` **Handler** Обработчик лога: ```ts-type handle(record: LogRecord): Promise // Обработать запись isHandling(level: LogLevel): boolean // Проверить поддержку уровня shouldBubble(): boolean // Продолжать ли цепочку setFormatter(formatter: Formatter): void // Установить форматтер getFormatter(): Formatter | null // Получить форматтер ``` **Formatter** для преобразования LogRecord: ```ts-type format(record: LogRecord): any ``` **Processor** для модификации LogRecord: ```ts-type (record: LogRecord) => LogRecord ``` ## Основные классы **AbstractLogger** Абстрактный базовый класс, реализующий удобные методы (debug, info и т.д.). **Logger** Основная реализация логгера: ```ts-type constructor(channel: string) // Создать логгер с указанным каналом pushHandler(handler: Handler): this // Добавить обработчик popHandler(): Handler | null // Удалить последний обработчик setHandlers(handlers: Handler[]): this // Задать список обработчиков pushProcessor(processor: Processor): this // Добавить процессор log(level, message, context): Promise // Основной метод логирования ``` **NullLogger** Заглушка для случаев, когда логирование не требуется. Не выполняет операций. ## Фабрика логгеров **LoggerFactory** Статические методы для создания логгеров: ```ts-type createNullLogger(): LoggerInterface createForBrowser(channel: string, isDevMode: boolean = false): LoggerInterface createForBrowserDevelopment(channel: string, level: LogLevel = LogLevel.DEBUG): LoggerInterface createForBrowserProduction(channel: string, level: LogLevel = LogLevel.ERROR): LoggerInterface forcedLog(logger, action, message, context): Promise // Принудительное логирование ``` ## Процессоры Процессоры модифицируют записи лога перед обработкой: **Встроенные процессоры:** - `memoryUsageProcessor` — добавляет использование памяти - `pidProcessor` — добавляет ID процесса **Создание своего процессора:** ```ts import { Processor } from '@bitrix24/b24jssdk' const customProcessor: Processor = (record) => { record.extra.customField = 'value' return record } ``` ## Форматтеры **AbstractFormatter** Базовый класс форматтера с поддержкой форматирования дат. **LineFormatter** Форматирует логи в строку с поддержкой шаблонов: ```ts-type // По умолчанию: '[{channel}] {levelName}: {message} {context} {extra} {date}' new LineFormatter(formatString, dateFormat) ``` *Доступные плейсхолдеры:* - `{channel}` — имя канала - `{levelName}` — имя уровня - `{message}` — сообщение - `{context}` — контекст в JSON - `{extra}` — дополнительные данные в JSON - `{timestamp}` — unix-таймстамп - `{date}` — дата в заданном формате **JsonFormatter:** Форматирует логи в JSON-строку. **TelegramFormatter:** Форматирует запись лога для [отправки в Telegram](https://core.telegram.org/bots/api#html-style){rel=""nofollow""}. Поддерживает HTML-разметку с экранированными спецсимволами. ## Обработчики **AbstractHandler** Базовый класс обработчика с поддержкой уровня логирования и всплытия. **ConsoleHandler** Выводит логи в консоль браузера с поддержкой стилизации для разных уровней. **ConsoleV2Handler** Улучшенная версия ConsoleHandler с более читаемым выводом. **MemoryHandler** Хранит логи в памяти (полезно для тестирования и отладки): ```ts import { MemoryHandler, LogLevel } from '@bitrix24/b24jssdk' const handler = new MemoryHandler(LogLevel.DEBUG, { limit: 1000 }) const records = handler.getRecords() // Получить все записи handler.clear() // Очистить записи ``` **ConsolaAdapter** Адаптер для [Consola](https://github.com/unjs/consola){rel=""nofollow""}. **WinstonAdapter** Адаптер для [Winston](https://github.com/winstonjs/winston){rel=""nofollow""}. **StreamHandler** Обработчик потоков Node.js для записи логов в потоки. **TelegramHandler**[Отправляет логи](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger-telegram.md) в Telegram-чат. В браузере выводит предупреждение в консоль. На сервере отправляет сообщение через Telegram Bot API. ## Использование ### Базовый пример ```ts import { LoggerFactory } from '@bitrix24/b24jssdk' const devMode = !!(typeof import.meta !== 'undefined' && (import.meta.dev || import.meta.env?.DEV)) const $logger = LoggerFactory.createForBrowser('Example:getCrmItem', devMode) $logger.info('User logged in', { userId: 123 }) ``` ### Расширенная конфигурация ```ts import { Logger, ConsoleV2Handler, LineFormatter, LogLevel, memoryUsageProcessor, pidProcessor } from '@bitrix24/b24jssdk' const $logger = new Logger('app') const handler = new ConsoleV2Handler(LogLevel.DEBUG) handler.setFormatter(new LineFormatter('[{levelName}] {message}')) $logger .pushHandler(handler) .pushProcessor(memoryUsageProcessor) .pushProcessor(pidProcessor) $logger.warning('Low memory', { freeMemory: '10MB' }) ``` ### Создание своего обработчика // @check-ignore: AbstractHandler is not re-exported from the SDK main index ```ts import { AbstractHandler, LogRecord } from '@bitrix24/b24jssdk' class CustomHandler extends AbstractHandler { async handle(record: LogRecord): Promise { // Отправить на сервер, записать в файл и т.д. return true // Возвращает true, если запись обработана } } ``` ## Возможности 1. **Асинхронность**: все методы логирования возвращают Promise. 2. **Цепочка ответственности**: обработчики вызываются последовательно. 3. **Всплытие**: если обработчик возвращает `true` и `shouldBubble() === false`, цепочка прерывается. 4. **Каналы**: логи группируются по каналам для фильтрации. 5. **Контекст**: поддержка структурированных данных через параметр `context`. ## Рекомендации по использованию **Development** - Используйте `LoggerFactory.createForBrowserDevelopment` с уровнем `DEBUG` - Добавляйте процессоры для отладочной информации **Production** - Используйте `LoggerFactory.createForBrowserProduction` с уровнем `ERROR` или выше - Ограничивайте число обработчиков ради производительности - Рассмотрите создание своих обработчиков для отправки логов на сервер **Контекст** // @check-ignore: illustrative snippet — orderId, userId, error are not declared ```ts // Хорошо: $logger.error('Failed to process order', { orderId: 123, userId: 456, error: error.message }) // Плохо: $logger.error(`Failed to process order ${orderId} for user ${userId}: ${error.message}`) ``` --- # Обработчик Telegram > Отправка логов в Telegram ## Быстрый старт ### Установка и настройка Telegram-бота ```bash # Создайте бота через @BotFather # Получите token и chat_id ``` ### Использование на стороне сервера ```ts import { LogLevel, Logger, TelegramHandler } from '@bitrix24/b24jssdk' // Создаём логгер с обработчиком Telegram const $logger = new Logger('my-app') const telegramHandler = new TelegramHandler(LogLevel.ERROR, { botToken: 'YOUR_BOT_TOKEN', chatId: 'YOUR_CHAT_ID', parseMode: 'HTML', // или 'MarkdownV2' disableNotification: false, // Отправлять уведомления disableWebPagePreview: true // Отключить превью ссылок }); $logger.pushHandler(telegramHandler) // Теперь критические ошибки будут отправляться в Telegram $logger.error('Payment service unavailable', { service: 'stripe', error: 'Connection timeout', duration: '30s' }) ``` ### Использование на стороне клиента > \[!CAUTION] > > На стороне клиента не поддерживается из соображений безопасности. --- # Обнаружение v3-методов (OpenAPI) > Используйте rest.documentation.openapi, чтобы получить собственный машиночитаемый список всех доступных методов REST API v3 портала — источник истины, на который SDK опирается вместо захардкоженного allowlist. Особенно полезно для AI-агентов и кодогенерации. ## Обзор `rest.documentation.openapi` — это v3 REST-метод, который возвращает **собственный** [OpenAPI 3.0.0](https://spec.openapis.org/oas/v3.0.0){rel=""nofollow""}-документ портала — единое машиночитаемое описание каждого метода REST API v3, существующего **на конкретном портале**, с полями тела запроса (и примерами значений) и конвертом ответа для каждого. Это **источник истины** по доступности v3-методов. SDK намеренно **не** держит захардкоженный список v3-методов (прежний allowlist и отставал от сервера, и блокировал валидные методы); вместо этого `$b24.actions.v3.*` отправляет любой метод на сервер и даёт ему решать. Когда нужно узнать, *что там на самом деле* — какие методы, какие поля — вы спрашиваете сам портал этим вызовом. > \[!NOTE] > > Документ отражает **модули, установленные на этом портале**, и **scope, которыми > владеет ваш токен**, поэтому два портала могут вернуть разные наборы методов. > Всегда считайте его специфичным для портала, а не глобальным каталогом. ## Вызов через SDK Это обычный v3-вызов — без специального хелпера: ```ts const response = await $b24.actions.v3.call.make<{ openapi: string }>({ method: 'rest.documentation.openapi' }) if (!response.isSuccess) { console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) } else { const doc = response.getData()?.result console.log(`OpenAPI ${doc?.openapi}`) // напр. "3.0.0" } ``` ## Как выглядит документ Стандартный объект OpenAPI 3.0.0. Части, которые важны на практике: | Поле | Что содержит | | --- | --- | | `openapi` | строка версии спецификации, напр. `"3.0.0"` | | `info` | `{ title: "Bitrix24 REST V3 API", version }` | | `tags` | одна запись **на модуль** — `humanresources`, `mail`, `main`, `note`, `rest`, `tasks`, `timeman`, … | | `paths` | одна запись **на метод**, с ключом `/method.name` (напр. `/tasks.task.list`) | Каждый `paths['/method.name']` несёт операции `post` (и `get`) с массивом `tags` (модуль-владелец), JSON-схему `requestBody`, описывающую принимаемые параметры — часто с полем `example`, перечисляющим реальные имена полей, — и схему `responses` для конверта `{ result }`. ```ts // Форма (сокращённо) — поля, которые читаете на практике type OpenApiDoc = { openapi: string // напр. "3.0.0" info: { title: string, version: string } // title: "Bitrix24 REST V3 API" tags: Array<{ name: string, description: string }> // одна запись на модуль paths: Record } ``` ## Почему это важно для AI-агентов Документ — самый чистый способ для LLM или генератора кода работать с порталом **без догадок**: - **Обнаружение** — перечислить, какие именно v3-методы существуют, до генерации вызова, вместо галлюцинации имени метода, который вернёт `METHODNOTFOUNDEXCEPTION`. - **Правильные поля** — читать реальные имена `select` / параметров из схемы `requestBody` каждого метода (и её `example`) вместо их выдумывания. - **Типизация / кодогенерация** — скормить схему генератору, чтобы получить типизированные обёртки, или сузить `$b24.actions.v3.call.make()` правильным `T`. - **Учёт портала** — поскольку ответ на каждый портал свой, агент может подстроиться под реально присутствующие модули и scope, а не под общее предположение. > \[!TIP] > > Документ большой (часто **100 КБ+**) и **только в ответе** — он не меняется между > вызовами в рамках сессии. Запросите его **один раз**, закэшируйте и обращайтесь к > закэшированному объекту. Не запрашивайте его при каждом взаимодействии. ## Обработка ошибок `rest.documentation.openapi` — обычный v3-вызов, поэтому следует стандартному контракту `AjaxResult` — всегда проверяйте `isSuccess` перед чтением документа: ```ts const response = await $b24.actions.v3.call.make<{ openapi: string }>({ method: 'rest.documentation.openapi' }) if (!response.isSuccess) { // напр. у токена нет scope или портал недоступен console.error(new Error(`Error: ${response.getErrorMessages().join('; ')}`)) } else { const doc = response.getData()?.result console.log(`OpenAPI ${doc?.openapi}`) } ``` ## Примеры ### Перечислить все доступные методы ```ts const response = await $b24.actions.v3.call.make<{ paths: Record }>({ method: 'rest.documentation.openapi' }) const methods = Object.keys(response.getData()?.result?.paths ?? {}) .map(path => path.replace(/^\//, '')) // "/tasks.task.list" → "tasks.task.list" console.log(`${methods.length} v3 methods available`) ``` ### Методы, сгруппированные по модулю ```ts type OpenApiDoc = { paths: Record } const doc = (await $b24.actions.v3.call.make({ method: 'rest.documentation.openapi' })).getData()?.result const byModule = new Map() for (const [path, ops] of Object.entries(doc?.paths ?? {})) { const moduleName = ops.post?.tags?.[0] ?? 'unknown' const list = byModule.get(moduleName) ?? [] list.push(path.replace(/^\//, '')) byModule.set(moduleName, list) } console.log([...byModule.keys()]) // ['humanresources', 'mail', 'main', 'note', 'rest', 'tasks', 'timeman', …] ``` ### Проверить, существует ли конкретный метод ```ts const doc = (await $b24.actions.v3.call.make<{ paths: Record }>({ method: 'rest.documentation.openapi' })).getData()?.result const exists = Boolean(doc?.paths?.['/note.collection.list']) console.log(`note.collection.list on v3: ${exists}`) ``` ## Альтернативы и рекомендации - **Справочник apidocs**: публичный [справочник REST API v3](https://apidocs.bitrix24.ru/api-reference/rest-v3/index.html){rel=""nofollow""} документирует методы в человекочитаемой форме; `rest.documentation.openapi` — его *программный, специфичный для портала* аналог. - **Для вызова обнаруженного метода**: используйте [`Call`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver3.md), [`CallList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-list-rest-api-ver3.md) / [`FetchList`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md) или нативные [`CallTail` / `FetchTail`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md), когда метод публикует действие `tail`. - **Выбор v2 или v3**: см. [Выбор подходящего метода](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/choosing-the-right-method.md). --- # AjaxResult > Специализированный Result, возвращаемый каждым REST-хелпером. Предоставляет \`isMore() / getNext() / getTotal() / getStatus()\` для постраничных ответов и неизменяемые данные. `AjaxResult` наследуется от [`Result>`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-result.md) и является типом, которым разрешается каждый `actions.v{2,3}.call.make()`. По сравнению с обобщённым `Result`, он: - принимает сырой REST-ответ (`answer`), исходный запрос (`query`) и HTTP-статус и замораживает их — `setData()` выбрасывает исключение. - декодирует payload ошибок Bitrix24 в экземпляры [`AjaxError`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-error.ts){rel=""nofollow""}, хранящиеся под ключом `'base-error'`. - предоставляет хелперы пагинации (`isMore`, `getNext`, `fetchNext`, `getTotal`). - предоставляет HTTP-статус (`getStatus`) и исходный запрос (`getQuery`). ## Чтение данных ```ts-type getData(): undefined | SuccessPayload ``` Возвращает `undefined`, когда результат неуспешен. При успехе возвращает замороженный объект с `result`, `next`, `total`, `time` (только те поля, что присутствуют в исходном payload). Используйте `T` для типизации внутреннего `result`: ```ts const response = await $b24.actions.v2.call.make<{ id: number, title: string }[]>({ method: 'crm.item.list', params: { entityTypeId: 4, select: ['id', 'title'] }, requestId: 'list-companies' }) if (!response.isSuccess) { throw new Error(response.getErrorMessages().join('; ')) } const data = response.getData()! // { result: { id, title }[], next?: number, total?: number, time } ``` ## Пагинация > \[!CAUTION] > > `getNext` / `fetchNext` реализованы **только для REST API v2**. v3 выбрасывает `SdkError({ code: 'JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3' })` — используйте вместо этого [`actions.v3.fetchList.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/fetch-list-rest-api-ver3.md). ### `isMore` / `hasMore` ```ts-type isMore(): boolean hasMore(): boolean // псевдоним ``` `true`, когда успешный payload содержит числовой `next`. Всегда `false` для неуспешных результатов. ### `getNext` ```ts-type getNext(http: TypeHttp): Promise | false> ``` Повторно выполняет исходный метод с `params.start = next` и возвращает новый `AjaxResult`. Возвращает `false`, когда следующей страницы нет или текущий результат неуспешен. ### `fetchNext` ```ts-type fetchNext(http: TypeHttp): Promise | null> ``` То же, что `getNext`, но возвращает `null` вместо `false`. ### `getTotal` / `getStatus` / `getQuery` ```ts-type getTotal(): number getStatus(): number getQuery(): Readonly ``` `getTotal` возвращает `0` для неуспешных результатов. `AjaxQuery` содержит `{ method, params, requestId }`. ## Обработка ошибок Когда сырой ответ содержит поле `{ error: ... }`, `AjaxResult` преобразует его в [`AjaxError`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-error.ts){rel=""nofollow""} (подкласс `SdkError`) с ключом `'base-error'` в унаследованной карте `errors`. Обрабатываются формы ошибок и v2, и v3, включая массивы `validation[]` из v3. ```ts import { AjaxError } from '@bitrix24/b24jssdk' const response = await $b24.actions.v2.call.make({ method: 'profile', requestId: 'p' }) if (!response.isSuccess) { for (const error of response.getErrors()) { if (error instanceof AjaxError) { console.error(error.code, error.requestInfo?.method) } } } ``` ## `setData` отключён ```ts-type setData(): never ``` Всегда выбрасывает `ReferenceError('AjaxResult does not allow data modification')`. Используйте хелперы более высокого уровня (`callList`, `fetchList`, `batch`), когда нужно агрегировать. --- # Http (TypeHttp) > Низкоуровневый интерфейс транспорта, возвращаемый \`b24.getHttpClient(version)\`. Прямой доступ к axios-клиентам, параметрам ограничений, статистике и сбросу. > \[!NOTE] > > Обычно вы используете `actions.v2.*` / `actions.v3.*` и никогда не трогаете `TypeHttp` напрямую. Обращайтесь к нему, когда нужны сырые `call` / `batch`, тонкая настройка лимитера или runtime-статистика. `TypeHttp` — это контракт, реализуемый `HttpV2` и `HttpV3`. Каждый `B24Frame` / `B24Hook` / `B24OAuth` владеет одним экземпляром на каждую версию REST API. Доступ к ним: ```ts import { ApiVersion } from '@bitrix24/b24jssdk' const v2 = $b24.getHttpClient(ApiVersion.v2) const v3 = $b24.getHttpClient(ApiVersion.v3) ``` ## Свойства | Свойство | Тип | Описание | | --- | --- | --- | | `apiVersion` | `ApiVersion` | `ApiVersion.v2` или `ApiVersion.v3`. | | `ajaxClient` | `AxiosInstance` | Нижележащий экземпляр axios. Переиспользуйте его для не-REST-запросов к тому же origin. | ## Логгер ```ts-type setLogger(logger: LoggerInterface): void getLogger(): LoggerInterface ``` Позволяет подменить отладочный логгер в одном клиенте, не затрагивая остальной SDK. См. [Логгер](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md). ## Вызов REST ### `call` ```ts-type call( method: string, params: TypeCallParams, requestId?: string ): Promise> ``` Низкоуровневый вызов одного метода. Хелперы более высокого уровня (`actions.v2.call.make`, `callList`, `fetchList`) строятся поверх него. ### `batch` ```ts-type batch( calls: BatchCommandsArrayUniversal | BatchCommandsObjectUniversal | BatchNamedCommandsUniversal, options?: ICallBatchOptions ): Promise>> ``` Низкоуровневый батч-вызов. Принимаются три формы ввода: - Массив кортежей: `[ [method, params], [method, params] ]` - Массив объектов: `[ { method, params, as?, parallel? }, ... ]` - Именованная карта: `{ key1: { method, params }, key2: [method, params] }` В большинстве случаев вызывайте [`actions.v2.batch.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver2.md) / [`actions.v3.batch.make`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/batch-rest-api-ver3.md), которые берут на себя распаковку ответа и `returnAjaxResult`. ## Конфигурация лимитера ```ts-type setRestrictionManagerParams(params: RestrictionParams): Promise getRestrictionManagerParams(): RestrictionParams ``` Заменяет или читает конфигурацию rate limit / operating limit / адаптивной задержки на **этом** клиенте. Чтобы изменить v2 и v3 сразу, предпочитайте `b24.setRestrictionManagerParams(...)`. Форму параметров и пресеты (`ParamsFactory.getDefault()`, `getBatchProcessing()`, `getRealtime()`, `fromTariffPlan()`) см. в [Лимитеры](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md). ## Статистика ```ts-type getStats(): RestrictionManagerStats & { adaptiveDelayAvg: number errorCounts: Record totalRequests: number successfulRequests: number failedRequests: number totalDuration: number byMethod: Map lastErrors: { method: string, error: string, timestamp: number }[] } ``` Снимок состояния лимитера + счётчики по методам. Полезно для дашбордов. Полную разбивку см. в [Лимитеры → Мониторинг](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md#monitoring-and-statistics). ## Сброс ```ts-type reset(): Promise ``` Очищает состояние лимитера и статистику. Типичное применение — после реагирования на инцидент или в долгоживущих демонах, которым нужно чистое окно. ## Предупреждение о клиентской стороне ```ts-type setClientSideWarning(value: boolean, message: string): void ``` `B24Hook` и `B24OAuth` включают runtime-предупреждение при использовании в браузерном окружении (их секреты никогда не должны попадать на клиент). Переключайте его из родительского класса через `b24.offClientSideWarning()`; этот метод — нижележащий примитив. --- # B24LangList > Enum языков интерфейса облачного Bitrix24 плюс карта локалей BCP-47. `B24LangList` перечисляет коды языков, которые использует облачный Bitrix24 (`B24Frame.getLang()` возвращает один из них). `B24LocaleMap` сопоставляет каждой записи её локаль BCP-47 (`'en' → 'en-EN'`, `'br' → 'pt-BR'`, …) — удобно для `Intl.*` API. ## Использование ```ts import { B24LangList, B24LocaleMap } from '@bitrix24/b24jssdk' const lang = $b24.getLang() // B24LangList const locale = B24LocaleMap[lang] // 'en-EN' | 'ru-RU' | ... const fmt = new Intl.DateTimeFormat(locale, { dateStyle: 'long' }) console.log(fmt.format(new Date())) ``` ## Значения enum ```ts-type enum B24LangList { ru, id, ms, de, en, la, fr, in, it, pl, br, vn, tr, kz, ua, ar, th, sc, tc, ja } ``` > \[!NOTE] > > На инсталляциях Bitrix24.Box обычно доступны только 1–2 языка. Не считайте, что доступен весь enum; сначала проверяйте через `getLang()`. ## Карта локалей | `B24LangList` | Локаль | | --- | --- | | `ru` | `ru-RU` | | `id` | `id-ID` | | `ms` | `ms-MY` | | `de` | `de-DE` | | `en` | `en-EN` | | `la` | `es-ES` | | `fr` | `fr-FR` | | `in` | `hi-IN` | | `it` | `it-IT` | | `pl` | `pl-PL` | | `br` | `pt-BR` | | `vn` | `vi-VN` | | `tr` | `tr-TR` | | `kz` | `kk` | | `ua` | `uk-UA` | | `ar` | `ar-SA` | | `th` | `th-TH` | | `sc` | `zh-CN` | | `tc` | `zh-TW` | | `ja` | `ja-JP` | --- # RequestIdGenerator > Реализация \`IRequestIdGenerator\` по умолчанию. Генерирует request id в формате UUID v7 и предоставляет имена HTTP-заголовка / query-параметра, используемые SDK. `RequestIdGenerator` — это реализация `IRequestIdGenerator` по умолчанию, используемая HTTP-клиентами для того, чтобы: - генерировать уникальный id для каждого исходящего запроса через [`Text.getUuidRfc4122()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-text.md) (UUID v7), - определять, какой HTTP-заголовок его несёт (`X-Request-ID`), - определять, какие query-параметры несут его и метаданные SDK (`bx24_request_id`, `bx24_sdk_ver`, `bx24_sdk_type`). Переопределять это нужно только когда вы хотите серверную корреляцию с существующей схемой трассировки (например, пробросить request id из вышестоящего сервиса) — реализуйте `IRequestIdGenerator` и внедрите его через кастомную настройку `Http`. ## Константы по умолчанию | Константа | Значение | | --- | --- | | Поле заголовка | `X-Request-ID` | | Query-параметр | `bx24_request_id` | | Query-параметр (версия SDK) | `bx24_sdk_ver` | | Query-параметр (тип SDK) | `bx24_sdk_type` | Последние два постоянны в рамках сборки (заменяются на этапе компиляции через `unbuild`). ## API ```ts-type class RequestIdGenerator implements IRequestIdGenerator { getRequestId(): string // UUID v7 getHeaderFieldName(): string // 'X-Request-ID' getQueryStringParameterName(): string // 'bx24_request_id' getQueryStringSdkParameterName(): string // 'bx24_sdk_ver' getQueryStringSdkTypeParameterName(): string // 'bx24_sdk_type' } ``` ## Интерфейс `IRequestIdGenerator` ```ts-type interface IRequestIdGenerator { getRequestId(): string getHeaderFieldName(): string getQueryStringParameterName(): string getQueryStringSdkParameterName(): string } ``` Если вы предоставляете свою реализацию, убедитесь, что `getRequestId()` возвращает значение, **уникальное для каждого вызова** — лимитер и журнал запросов используют его как ключ. --- # Result > Обобщённый результат операции с флагом успеха, данными и картой ошибок. Аналог \\\Bitrix\\\Main\\\Result из Bitrix Framework. `Result` — это единый тип возврата SDK для хелперов высокого уровня (`callBatch`, `B24HelperManager.loadData`, `OptionsManager.save`, …). Класс реализует `IResult`; типизированные REST-хелперы (`call.make`, `callList.make`, …) возвращают его специализированный подкласс [`AjaxResult`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-ajax-result.md). ## Использование ```ts import { Result } from '@bitrix24/b24jssdk' function parseConfig(raw: string): Result<{ theme: string }> { try { const data = JSON.parse(raw) if (typeof data?.theme !== 'string') { return Result.fail<{ theme: string }>('theme is required', 'config:theme') } return Result.ok({ theme: data.theme }) } catch (error) { return Result.fail<{ theme: string }>(error as Error, 'config:json') } } function applyConfig() { const rawJson = '{"theme":"light"}' const result = parseConfig(rawJson) if (!result.isSuccess) { console.error(result.getErrorMessages()) return } const { theme } = result.getData()! console.log('theme:', theme) } applyConfig() ``` ## Конструктор ```ts-type new Result(data?: T) ``` `data` по умолчанию `null`. ## Статические фабрики ```ts-type Result.ok(data?: U): Result Result.fail(error: Error | string, key?: string): Result ``` ## Геттеры | Геттер | Тип | Описание | | --- | --- | --- | | `isSuccess` | `boolean` | `true`, когда карта ошибок пуста. | | `errors` | `Map` | Внутреннее хранилище ошибок (по соглашению — только для чтения). | ## Методы данных ```ts-type setData(data: T | null | undefined): Result getData(): T | null | undefined ``` `setData` поддерживает цепочки вызовов. Примечание: `AjaxResult` **отключает** `setData` и выбрасывает `ReferenceError` при вызове. ## Методы ошибок ```ts-type addError(error: Error | string, key?: string): Result addErrors(errors: (Error | string)[]): Result hasError(key: string): boolean getErrors(): IterableIterator getErrorMessages(): string[] getErrorsByKey(): Record getErrorMessagesByKey(): Record ``` Когда `key` опущен, `addError` генерирует UUID v7 через [`Text.getUuidRfc4122()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-text.md), чтобы дублирующиеся строки всё равно получали отдельные слоты. `getErrorsByKey()` / `getErrorMessagesByKey()` возвращают **снимок** `Record`, ключом которого служит этот идентификатор, поэтому можно понять, какой вызов упал — в отличие от `getErrors()` / `getErrorMessages()`, которые ключи теряют, и в отличие от живого геттера `errors` `Map`. Для батчей ключ говорит, какая команда упала: **object / named-command**-батч ключуется по метке команды, а **array-mode**-батч — по **числовой позиции** команды (`'0'`, `'1'`, … — начиная с v1.4.0 / [#255](https://github.com/bitrix24/b24jssdk/issues/255){rel=""nofollow""}; ранее это были случайные UUID). Soft-ошибка уровня конверта, не привязанная к одной команде, использует внутренний ключ `base-error`, а `addErrors()` (без явного ключа) по-прежнему использует сгенерированные UUID — для них предпочитайте `getErrors()` / `getErrorMessages()`. ```ts const res = await $b24.actions.v2.batch.make({ calls: { contact: { method: 'crm.item.get', params: { entityTypeId: 3, id: 1 } }, deal: { method: 'crm.item.get', params: { entityTypeId: 2, id: 999 } } }, options: { isHaltOnError: false } }) if (!res.isSuccess) { console.error(res.getErrorMessagesByKey()) // напр. { deal: 'Access denied' } } ``` ## `toString` ```ts-type toString(): string ``` Красиво печатает результат для логов: - успех → `Result(success): {}` - неудача → `Result(failure): {}\nErrors: ` Экземпляры `Error` внутри данных сериализуются как `{ name, message, stack }`. При неудаче сериализации возвращается `'[Unable to serialize data]'`. --- # Система ограничений > Система ограничений предоставляет комплексный механизм управления частотой запросов, временем выполнения операций и адаптивными задержками. ## Обзор Система состоит из нескольких компонентов, работающих вместе, чтобы предотвратить превышение лимитов API и обеспечить стабильную работу. ```ts-type ┌─────────────────────────────────────────────┐ │ RestrictionManager │ │ (Coordinator of all types of restrictions) │ └─────┬──────────────┬──────────────┬─────────┘ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌────────────┐ ┌─────────────┐ │ Rate │ │ Operating │ │ Adaptive │ │ Limiter │ │ Limiter │ │ Delayer │ └──────────┘ └────────────┘ └─────────────┘ ``` ### Интерфейсы и типы #### ILimiter (базовый интерфейс) ```ts-type interface ILimiter { getTitle(): string setConfig(config: any): Promise setLogger(logger: LoggerInterface): void getLogger(): LoggerInterface canProceed(requestId: string, method: string, params?: any): Promise waitIfNeeded(requestId: string, method: string, params?: any): Promise updateStats(requestId: string, method: string, data: any): Promise reset(): Promise getStats(): Record } ``` #### RestrictionParams ```ts-type interface RestrictionParams { rateLimit?: RateLimitConfig // Настройки rate limiting operatingLimit?: OperatingLimitConfig // Настройки лимита времени операций adaptiveConfig?: AdaptiveConfig // Настройки адаптивной задержки maxRetries?: number // Максимальное число повторов запроса (по умолчанию: 3). Кроме `batch`-запросов retryDelay?: number // Базовая задержка между повторами в мс (по умолчанию: 1000) retryOnNetworkError?: boolean // Повтор при `NETWORK_ERROR` / `REQUEST_TIMEOUT` (HTTP 408) (по умолчанию: true). // Установите `false` для неидемпотентных вызовов — см. «Неидемпотентные вызовы» ниже. hardErrorCodes?: string[] // Доп. коды для немедленного выброса (объединяются со встроенным hard-списком). softErrorCodes?: string[] // Доп. коды для возврата как AjaxResult с ошибкой (объединяются со встроенным soft-списком). } ``` ## Компоненты системы ### 1. RateLimiter (ограничение частоты) **Назначение**: реализует алгоритм «Leaky Bucket» для ограничения частоты запросов. #### RateLimiter — конфигурация ```ts-type interface RateLimitConfig { burstLimit: number // Ёмкость бакета (максимальное число одновременных запросов) drainRate: number // Скорость утечки (запросов в секунду) adaptiveEnabled: boolean // Включить адаптивное управление } ``` #### RateLimiter — принцип работы 1. **Токеновая система**: каждый запрос потребляет один токен 2. **Автоматическое пополнение**: токены пополняются со скоростью `drainRate` 3. **Адаптивное управление**: - При частых ошибках лимиты автоматически снижаются на 20% - При стабильной работе лимиты постепенно восстанавливаются - Минимальные значения: `drainRate = 0.5`, `burstLimit = 5` ### 2. OperatingLimiter (ограничение времени операций) **Назначение**: контролирует суммарное время выполнения операций в скользящем окне. #### OperatingLimiter — конфигурация ```ts-type interface OperatingLimitConfig { windowMs: number // Период времени в миллисекундах (по умолчанию: 600000 = 10 минут) limitMs: number // Максимальное время выполнения в миллисекундах (по умолчанию: 480000 = 480 секунд) heavyPercent: number // Порог для уведомлений о тяжёлых запросах (%) } ``` #### OperatingLimiter — принцип работы 1. **Скользящее окно**: отслеживает время выполнения за последние 10 минут 2. **Учёт по методам**: статистика ведётся отдельно для каждого метода 3. **Буфер безопасности**: в расчётах используется `limitMs - 5000` (буфер 5 секунд) 4. **Блокировка**: при достижении лимита блокирует выполнение до сброса статистики #### OperatingLimiter — особенности - Для batch-запросов анализирует все вложенные методы - Автоматическая очистка устаревших данных (> windowMs + 10 секунд) - Логирование тяжёлых запросов при превышении `heavyPercent` ### 3. AdaptiveDelayer (адаптивные задержки) **Назначение**: динамически рассчитывает задержки на основе опыта выполнения предыдущих запросов. #### AdaptiveDelayer — конфигурация ```ts-type interface AdaptiveConfig { enabled: boolean // Включить адаптивные задержки thresholdPercent: number // Порог активации (% от operating limit) coefficient: number // Множитель задержки (0.01 = 1% от оставшегося времени блокировки) maxDelay: number // Максимальная задержка в миллисекундах } ``` #### AdaptiveDelayer — алгоритм расчёта задержки ```html Если operating текущего метода > (limitMs × thresholdPercent / 100): Если operating_reset_at > текущее время: Задержка = (operating_reset_at - текущее время) × coefficient Иначе: Задержка = 7000 мс (значение по умолчанию) Итоговая задержка = min(рассчитанная, maxDelay) ``` #### AdaptiveDelayer — особенности - Для batch-запросов выбирает максимальную задержку среди всех методов - Не блокирует выполнение, только добавляет задержку - Использует статистику из OperatingLimiter ### 4. RestrictionManager (главный координатор) **Назначение**: управляет всеми типами ограничений и обработкой ошибок. #### Порядок применения ограничений 1. **Проверка Operating Limit**: проверяет лимит времени операций 2. **Адаптивная задержка**: при необходимости применяет адаптивную задержку 3. **Rate Limit**: проверяет и применяет ограничение частоты (цикл для параллельных запросов) #### Обработка ошибок ```ts-type // Определение типа ошибки #isRateLimitError(error): boolean // 503 или QUERY_LIMIT_EXCEEDED #isOperatingLimitError(error): boolean // 429 или OPERATION_TIME_LIMIT #isNonRetryableClientError(error): boolean // HTTP 4xx (кроме 429 / 408) #isNeedThrowError(error): boolean // Критические ошибки (повтор бессмыслен) ``` #### Стратегия повторов 1. **Для ошибок лимитов**: экспоненциальная задержка с учётом номера попытки 2. **Для клиентских ошибок (HTTP 4xx, кроме 429 / 408)**: без повторов — ответ `4xx` детерминирован, поэтому повтор не изменит исход. Ошибка выходит из цикла повторов на первой попытке; далее применяется обычная классификация hard/soft (выбрасывается как `AjaxError` или возвращается внутри `AjaxResult` для soft-кодов). `429` повторяется как rate/operating limit; `408` (таймаут запроса) остаётся временным. 3. **Для прочих ошибок**: базовый backoff с jitter (±10%) 4. **Критические ошибки**: без повторов ## Конфигурации по умолчанию ### Параметры по умолчанию для обычных тарифов (standard) ```ts-type { rateLimit: { burstLimit: 50, // 50 одновременных запросов drainRate: 2, // 2 запроса в секунду adaptiveEnabled: true }, operatingLimit: { windowMs: 600000, // 10 минут limitMs: 480000, // 480 секунд (8 минут) heavyPercent: 80 // Уведомление при 80% использования }, adaptiveConfig: { enabled: true, thresholdPercent: 80, // Активация при 80% лимита coefficient: 0.01, // 1% от оставшегося времени блокировки maxDelay: 7000 // Максимум 7 секунд задержки }, maxRetries: 3, retryDelay: 1000, retryOnNetworkError: true } ``` ### Параметры для тарифа Enterprise ```ts-type { ...standard, rateLimit: { burstLimit: 250, // 250 одновременных запросов drainRate: 5, // 5 запросов в секунду adaptiveEnabled: true } } ``` ### Параметры для массовой обработки данных ```ts-type { ...standard, rateLimit: { burstLimit: 30, drainRate: 1, adaptiveEnabled: true }, operatingLimit: { windowMs: 600_000, limitMs: 480_000, heavyPercent: 50 // Более высокий порог для уведомлений }, adaptiveConfig: { enabled: true, thresholdPercent: 50, // Больше порог coefficient: 0.015, // Больше пауза maxDelay: 10_000 // Макс 10 секунд }, maxRetries: 5 // Больше попыток } ``` ### Параметры реального времени ```ts-type { ...standard, adaptiveConfig: { enabled: false, // Выключено thresholdPercent: 100, coefficient: 0.001, maxDelay: 480_000 }, maxRetries: 1 } ``` ## Мониторинг и статистика ### Получение статистики ```ts import { ApiVersion } from '@bitrix24/b24jssdk' // const $b24 = ... const statsV2 = $b24.getHttpClient(ApiVersion.v2).getStats() const statsV3 = $b24.getHttpClient(ApiVersion.v3).getStats() ``` Структура статистики: ```ts-type { // Общая статистика retries: number, // Число попыток повтора consecutiveErrors: number, // Последовательные ошибки limitHits: number, // Попадания в лимит // Rate Limiter tokens: number, // Текущее число токенов burstLimit: number, // Текущий burst limit drainRate: number, // Текущий drain rate // Adaptive Delayer adaptiveDelays: number, // Число применённых задержек totalAdaptiveDelay: number, // Суммарное время задержек adaptiveDelayAvg: number, // Средняя задержка // Operating Limiter heavyRequestCount: number, // Число тяжёлых запросов operatingStats: { // Статистика по методам (в секундах) [method: string]: number }, // Ошибки по методам errorCounts: { [method: string]: number } } ``` ### Сброс статистики ```ts // Полный сброс всей статистики лимитера import { ApiVersion } from '@bitrix24/b24jssdk' // const $b24 = ... await $b24.getHttpClient(ApiVersion.v2).reset() await $b24.getHttpClient(ApiVersion.v3).reset() ``` ## Долгие запросы и неидемпотентные вызовы SDK поставляется с 30-секундным таймаутом axios и повторяет неудавшиеся запросы до `maxRetries` раз. Оба значения по умолчанию неверны для **долгих**, **неидемпотентных** REST-методов — канонический пример `crm.documentgenerator.document.add`, который может рендерить шаблон 10‒60 секунд и является исходным репортом из [issue #24](https://github.com/bitrix24/b24jssdk/issues/24){rel=""nofollow""}. ### Почему по умолчанию это ломается Когда сервер отвечает дольше таймаута axios, разворачивается такая последовательность: 1. Клиент открывает запрос, сервер начинает обработку. 2. Axios срабатывает по таймауту, SDK видит `REQUEST_TIMEOUT` (`code: ECONNABORTED`). 3. `REQUEST_TIMEOUT` трактуется как временная ошибка → SDK повторяет. 4. Сервер, не зная, что клиент сдался, завершает первый запрос и **сохраняет документ**. Затем принимает повтор и сохраняет **ещё один**. 5. После `maxRetries` попыток SDK выбрасывает исходную ошибку (её реальный код), и у вызывающего остаётся 2-3 дубликата в CRM. Тот же риск касается каждого неидемпотентного метода: `crm.deal.add`, `crm.contact.add`, `disk.folder.uploadfile`, `tasks.task.add`, любого кастомного REST- endpoint, создающего состояние. ### Рекомендуемая конфигурация Используйте этот паттерн для любого вызова, создающего сущность, независимо от ожидаемой длительности: ```ts import { ApiVersion, ParamsFactory } from '@bitrix24/b24jssdk' // const $b24 = ... // 1. Поднимите таймаут, чтобы клиент действительно ждал медленную операцию. const clientAxios = $b24.getHttpClient(ApiVersion.v2).ajaxClient clientAxios.defaults.timeout = 120_000 // по умолчанию 30_000 // 2. Отключите повторы на транспортных ошибках, чтобы клиентский таймаут никогда // не создавал дубликаты сущностей на сервере. await $b24.setRestrictionManagerParams({ ...ParamsFactory.getDefault(), retryOnNetworkError: false }) // Теперь безопасно для неидемпотентных вызовов. const result = await $b24.actions.v2.call.make({ method: 'crm.documentgenerator.document.add', params: { templateId: 42, entityTypeId: 2, entityId: 6014, values: {} } }) ``` > \[!NOTE] > > **Одного шага недостаточно.** > Длинный таймаут без `retryOnNetworkError: false` всё равно создаёт дубликаты > на нестабильной сети (сервер ответил, но ответ не дошёл). Флаг > без таймаута срабатывает слишком рано на запросах, которые завершились бы > за 35-40 секунд. ### Точечное применение — переопределение на вызов Если строгое поведение нужно только для конкретного участка кода, создайте отдельный `B24Hook` для этого вызова вместо мутации глобального: ```ts import { B24Hook, ParamsFactory } from '@bitrix24/b24jssdk' import { ApiVersion } from '@bitrix24/b24jssdk' const $b24Strict = B24Hook.fromWebhookUrl(hookUrl, { restrictionParams: { ...ParamsFactory.getDefault(), retryOnNetworkError: false } }) $b24Strict.getHttpClient(ApiVersion.v2).ajaxClient.defaults.timeout = 120_000 await $b24Strict.actions.v2.call.make({ method: 'crm.deal.add', params: {/*…*/} }) ``` ### Крайний случай — отключить все повторы Если вы не можете позволить ни одного повтора ни при каких обстоятельствах (например, биллинговая операция), задайте `maxRetries: 1`: ```ts import { ParamsFactory } from '@bitrix24/b24jssdk' await $b24.setRestrictionManagerParams({ ...ParamsFactory.getDefault(), maxRetries: 1 }) ``` Это затрагивает каждый класс ошибок, а не только транспортные, поэтому используйте осторожно. ## Настройка классификации ошибок SDK группирует коды ошибок REST на три категории: 1. **Hard-ошибки** — выбрасываются сразу как `AjaxError`. Без повтора. Используются для фатальных ситуаций (сбои авторизации, неверные аргументы, удалённые порталы). 2. **Soft-ошибки** — возвращаются внутри `AjaxResult` как payload ошибки, **не** выбрасываются. Используются для кодов, которые вызывающий код обычно проверяет в рамках обычного потока управления (например, `ENTITY_NOT_FOUND`, ошибки валидации v3). 3. **Всё остальное** — возможность повтора определяется HTTP-статусом. Клиентские ошибки (HTTP `4xx`, кроме `429` и `408`) **никогда не повторяются** — они детерминированы, поэтому SDK быстро завершается на первой попытке независимо от того, перечислен ли код ошибки. Временные состояния (`5xx`, `429`, `408`, сетевые ошибки) повторяются до `maxRetries` раз с backoff и jitter. Встроенные списки покрывают стандартную REST-поверхность Bitrix24. Если ваше приложение использует кастомные REST-endpoint-ы (например, из локального приложения или обработчика placement), которые возвращают свои коды ошибок со статусом не `4xx`, эти коды будут **повторяться по умолчанию** — что неверно для неидемпотентных бизнес-ошибок. Расширьте классификацию через `hardErrorCodes` и `softErrorCodes`: ```ts import { ParamsFactory } from '@bitrix24/b24jssdk' // const $b24 = ... await $b24.setRestrictionManagerParams({ ...ParamsFactory.getDefault(), // Эти будут выброшены сразу вместо повтора: hardErrorCodes: [ 'DOCUMENT_GENERATOR_ALREADY_IN_QUEUE', // бизнес-код: не повторять 'MY_APP_INVALID_PAYLOAD' // кастомный REST: нужна правка на стороне вызывающего ], // Эти будут возвращены в AjaxResult вместо выброса: softErrorCodes: [ 'MY_APP_VALIDATION_FAILED' // ожидается в рамках обычного потока ] }) ``` > \[!NOTE] > > **Объединение, не замена.** Коды, заданные пользователем, добавляются к встроенным > спискам. Вы можете только **добавлять** коды — встроенные (коды авторизации, > `INTERNAL_SERVER_ERROR`, коды валидации v3 и т.д.) остаются на месте. Это > предотвращает случайное отключение критичных защит, таких как обнаружение > `expired_token`. Встроенные списки доступны как статические поля для справки: ```ts import { RestrictionManager } from '@bitrix24/b24jssdk' console.log(RestrictionManager.BUILT_IN_HARD_ERROR_CODES) console.log(RestrictionManager.BUILT_IN_SOFT_ERROR_CODES) ``` ## Глобальная область `setRestrictionManagerParams` в пределах экземпляра `setRestrictionManagerParams()` мутирует **весь экземпляр `$b24`** — он перенастраивает единственный `RestrictionManager`, общий для каждого запроса, идущего через этот экземпляр. Это **не** переопределение на отдельный вызов. На сервере это грабли, когда один экземпляр `$b24` разделяется между параллельными запросами (типовой паттерн: синглтон уровня модуля, переиспользуемый многими HTTP-обработчиками). Изменение параметров для одного запроса меняет их для **всех запросов в полёте** на этом экземпляре. ```ts import { ParamsFactory } from '@bitrix24/b24jssdk' // ⚠️ АНТИ-ПАТТЕРН: общий $b24, параллельные обработчики // Запрос A — неидемпотентное создание, которое хочет ОТКЛЮЧИТЬ повторы: await $b24.setRestrictionManagerParams({ ...ParamsFactory.getDefault(), retryOnNetworkError: false }) await $b24.actions.v2.call.make({ method: 'crm.deal.add', params: { fields: { TITLE: 'Deal A' } } }) // Запрос B — выполняется параллельно на ТОМ ЖЕ $b24 — теперь ТОЖЕ видит // retryOnNetworkError: false, хотя никогда об этом не просил. А если // Запрос B первым вызовет setRestrictionManagerParams, создание из // Запроса A незаметно выполнится с параметрами B. Побеждает последний // записавший — глобально. ``` Поскольку мутация глобальна и нет изоляции на уровне запроса, два параллельных потока `createDeal` могут затирать друг у друга конфигурацию rate-limit / повторов. ### Безопасные паттерны 1. **Выделенный экземпляр `$b24` для неидемпотентных / нестандартных потоков.** Постройте отдельный экземпляр (или передайте `restrictionParams` при конструировании) для той ветки кода, которой нужно другое поведение, чтобы она никогда не разделяла состояние с общим пулом по умолчанию: ```ts import { B24Hook, ParamsFactory, ApiVersion } from '@bitrix24/b24jssdk' const $b24Strict = B24Hook.fromWebhookUrl(hookUrl, { restrictionParams: { ...ParamsFactory.getDefault(), retryOnNetworkError: false } }) $b24Strict.getHttpClient(ApiVersion.v2).ajaxClient.defaults.timeout = 120_000 await $b24Strict.actions.v2.call.make({ method: 'crm.deal.add', params: { fields: { TITLE: 'Deal A' } } }) ``` 2. **Задавайте параметры ограничений один раз при старте**, а не на каждый запрос. Считайте их конфигурацией экземпляра, а не переключателем на отдельный вызов. 3. **Идемпотентность на уровне приложения.** Для неидемпотентных созданий, которые должны пережить повтор независимо от конфигурации ограничений, добавьте собственную защиту идемпотентности (ключ дедупликации / уникальное бизнес-поле, проверяемое перед вставкой), чтобы дублирующий вызов был no-op, даже если повтор проскочит. ## Рекомендации по использованию Конфигурация для разных сценариев: ```ts import { ParamsFactory } from '@bitrix24/b24jssdk' // const $b24 = ... // Параметры по умолчанию $b24.setRestrictionManagerParams( ParamsFactory.getDefault() ) // Пакетная обработка $b24.setRestrictionManagerParams( ParamsFactory.getBatchProcessing() ) // Real-time $b24.setRestrictionManagerParams( ParamsFactory.getRealtime() ) // По тарифному плану $b24.setRestrictionManagerParams( ParamsFactory.fromTariffPlan('enterprise') ) // Динамическое изменение конфигурации $b24.setRestrictionManagerParams({ ...ParamsFactory.getDefault(), rateLimit: { burstLimit: 30, // Временное снижение при проблемах drainRate: 1, adaptiveEnabled: true } }) ``` --- # Логирование и редактирование учётных данных > Что SDK редактирует автоматически до того, как информация о запросе попадёт в логгер или AjaxError, что он не редактирует, и как подключить кастомный логгер через setLogger(...) без повторного появления утечек учётных данных. ## Обзор SDK редактирует фиксированный набор ключей с учётными данными до того, как данные запроса могут попасть в sink логгера или объект ошибки. Редактор ([`redact.ts`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/redact.ts){rel=""nofollow""}) — единый источник истины, общий для всего SDK. В **HTTP-слое** (начиная с v1.1.2) он вырезает эти ключи из любого payload запроса до того, как он может попасть в: - **контекст логгера** записей уровня info `post/send`, `post/response`, `post/catchError` (и более низкоуровневой debug-записи `http request starting` / `_logRequest`), - поле `requestInfo.params`, несомое [`AjaxError`](https://bitrix-tools.github.io/b24jssdk/#ajaxerror-tojson-tostring), которое потребители видят через `AjaxError.toString()` / `toJSON()`. Тот же редактор — плюс несколько исправлений безопасной проекции — также защищает поверхности с учётными данными **вне** HTTP-слоя: pull-клиент, канал frame `postMessage` и сообщения об ошибках хука. См. [Не-HTTP-поверхности](https://bitrix-tools.github.io/b24jssdk/#non-http-surfaces) ниже. Это значит, что пользователю, подключающему кастомный логгер через `B24Hook.setLogger(...)`, `B24Frame.setLogger(...)` или `B24OAuth.setLogger(...)`, **не** нужно добавлять собственное редактирование для стандартных ключей учётных данных, перечисленных ниже — SDK уже вырезает их на выходе. Кастомные поля, заданные вызывающим кодом, **не** покрываются. Всё, что вы кладёте в `params` под нестандартным ключом (например, `mySecretField`), попадает в логгер как есть. См. [Что SDK не редактирует](https://bitrix-tools.github.io/b24jssdk/#what-the-sdk-does-not-redact). ## Что SDK редактирует автоматически Единый источник истины — [`packages/jssdk/src/core/http/redact.ts`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/redact.ts){rel=""nofollow""}. ```ts // packages/jssdk/src/core/http/redact.ts export const SENSITIVE_PARAM_KEYS: readonly string[] = [ 'auth', 'password', 'token', 'secret', 'access_token', 'refresh_token', 'client_secret', 'application_token', 'sessid', 'key', 'signature' ] ``` Везде, где появляется любой из этих ключей — сопоставляемый **без учёта регистра**, так что `Auth` / `TOKEN` / `Access_Token` тоже попадают под правило — значение заменяется на `'***REDACTED***'` (экспортируемый `REDACTED_PLACEHOLDER`) до того, как payload сериализуется для логирования или сохраняется на объекте ошибки. Обход спускается на **два уровня** во вложенные объекты и массивы. Это покрывает форму батча `{ cmd: [{ method, params: { ...creds... } }, ...] }`, где учётные данные лежат в `cmd[i].params.`, плюс плоские одноуровневые формы вроде `{ data: { token } }`. Всё, что глубже, **не** обходится — держите секреты ближе к верху payload, если хотите, чтобы их поймали, или редактируйте на месте вызова. Редактор также сканирует **строковые значения** на предмет пар учётных данных в query-строке (`<ключ>=<значение>`) и маскирует значение на месте. Это покрывает сериализованную форму batch-команды `cmd[i] = 'method?auth=&…'`, где учётные данные — это текст, а не ключ объекта. Маскируется только пара `ключ=значение`, чей ключ — один из канонических, и требуется граница query (`?` / `&` / начало строки) — поэтому `=` в позиции значения не трогается. Запись `key` намеренно широкая: она маскирует любое свойство, буквально названное `key` (и любую query-пару `?key=…`), не только значения в форме API-ключа. В Bitrix24 REST `key` — это параметр с учётными данными, поэтому выбор консервативный — учтите, что не-секретное поле с именем `key` в ваших логах тоже покажется как `***REDACTED***`. Запись `signature` (добавлена в #43 для HMAC канала Pull) широкая так же: любое свойство с именем `signature` и любая query-пара `?signature=…` маскируются. В push/pull Bitrix24 `signature` — это HMAC канала, поэтому широта принята — не-секретное поле с именем `signature` тоже отрендерится как `***REDACTED***`. ### HTTP-места вызова, использующие редактор | Где | Канал лога | Уровень | Источник | | --- | --- | --- | --- | | `post/send` (отправляемый запрос) | контекст логгера `params` | `info` | [`abstract-http.ts:544`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/abstract-http.ts#L544){rel=""nofollow""} | | `post/response` (тело успешного ответа) | контекст логгера `result` | `info` | [`abstract-http.ts:561`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/abstract-http.ts#L561){rel=""nofollow""} | | `post/catchError` (ошибка axios) | контекст логгера `responseData` | `info` | [`abstract-http.ts:506`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/abstract-http.ts#L506){rel=""nofollow""} | | `http request starting` (`_logRequest`) | контекст логгера `params` | `debug` | [`abstract-http.ts:678`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/abstract-http.ts#L678){rel=""nofollow""} | | Конструктор `AjaxError` | `requestInfo.params` (видно через `toJSON()` / `toString()`) | — | [`ajax-error.ts:44`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-error.ts#L44){rel=""nofollow""} | Остальные места логирования в [`abstract-http.ts`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/abstract-http.ts){rel=""nofollow""} (`http request attempt`, `http request successful`, `http request failed`, `http refreshing auth token`, `http auth error detected`, логи ожидания повтора) несут только `requestId`, `method`, `api`, `attempt`, `duration` и code/message/status из `AjaxError` — ни одно из них не трогает `params` или URL вебхука, поэтому про редактирование можно не беспокоиться. Логируемые payload'ы также **ограничены по длине**: `params` в `post/send`, `result` в `post/response` и `responseData` в `post/catchError` каждый усекается до префикса в 100 символов + `...`, как только превышает 300 символов, так что большое тело (HTML-страница ошибки, крупный дамп валидации) не может затопить подключённый sink логгера. Ограничение применяется **после** редактирования, поэтому оно никогда не влияет на то, что маскируется — только на то, сколько записывается (#236). Редактирование **не зависит от уровня** — оно выполняется над данными до того, как они переданы логгеру, поэтому применяется независимо от того, фильтрует ли ваш обработчик на `DEBUG`, `INFO`, `ERROR` или чём-то ещё. ### Не-HTTP-поверхности Аудит #43 распространил ту же защиту на поверхности с учётными данными, которые живут вне HTTP-слоя. Они не проходят через `post/*`, поэтому защищаются на своих собственных местах вызова: | Поверхность | Что несло учётные данные | Как защищено | | --- | --- | --- | | **Pull** — `logMessage` (info-логи `onPull*Event`), warning об ошибке `broadcastMessages`, debug `attachCommandHandler` | заданные приложением `params` / `extra` могут держать ключ в форме учётных данных (например, `signature` канала) | прогоняются через `redactSensitiveParams` перед логированием | | **Pull** — error-логи JSON-RPC `unknown id` / `unknown rpc packet` / `unknown rpc command in batch` | непрозрачный кадр от сервера может нести `signature` | прогоняются через `redactSensitiveParams` | | **Pull** — console-лог `CHANNEL_EXPIRE` «new config for … channel set» | сериализовал объект `TypeChanel`, включающий его `signature` | выводит `[updated]` вместо объекта | | **Pull** — необработанный сырой сетевой кадр | сырые байты могли содержать встроенную `signature` | логирует только `byteLength` кадра, никогда его содержимое | | **Frame** — debug-лог «init data» из `B24Frame.init()` | данные `data` рукопожатия несут `AUTH_ID` / `REFRESH_ID` / `MEMBER_ID` и хранилища `*_OPTIONS` приложения | логирует фиксированную проекцию по allowlist (`PLACEMENT` / `LANG` / `INSTALL` / `IS_ADMIN` / `FIRST_RUN`) | | **Frame** — входящий `MessageManager._runCallback` | `event.data` несёт обновлённые `AUTH_ID` / `REFRESH_ID` | логирует только `id` и `origin` callback'а, никогда payload | | **Frame** — исходящий `MessageManager.send` | собранная строка `cmd` несёт сериализованные значения `setAppOption` / `setUserOption` | логирует только `command` + ключ callback'а, никогда строку `cmd` | | **Hook** — ошибки разбора / форматирования `B24Hook.fromWebhookUrl` | URL вебхука встраивает секрет в свой путь (`/rest///`) | выбрасываемые сообщения обобщённые и никогда не повторяют URL | Кэш конфигурации pull в `localStorage` (push `jwt` + подписи каналов) хранится только на время жизни клиента: `PullClient.destroy()` удаляет его при завершении, а устаревшая запись вытесняется при загрузке. Пока клиент активен, кэш остаётся **задокументированным, принятым** компромиссом при общем origin (он избегает похода за конфигурацией на каждый reconnect) — см. [#242](https://github.com/bitrix24/b24jssdk/issues/242){rel=""nofollow""}. ## URL вебхука больше не логируется Полный URL вебхука (`https:///rest///.json`) раньше попадал в info-лог `post/send`. Начиная с v1.1.2 логируется только голое имя REST-метода (например, `user.current`, `crm.item.add`); места `post/response` и `post/catchError` всегда были без URL и остаются такими. `AjaxQuery` (форма `requestInfo`, несомая `AjaxError`) больше вообще не типизирует поле `url` — см. [`ajax-result.ts:12-16`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-result.ts#L12-L16){rel=""nofollow""} — поэтому будущее изменение не сможет случайно вернуть утечку через рендеринг ошибки. Архивы логов из версий SDK `>= 1.1.0, < 1.1.2` с подключённым кастомным логгером могут содержать паттерн URL вебхука (`/rest/{userId}/{secret}/`) или паттерн auth-токена (`"auth":"..."`), которые больше не производятся с v1.1.2. Паттерны для проверки чистоты ваших sink'ов см. в [Аудит архивов логов](https://bitrix-tools.github.io/b24jssdk/#auditing-your-log-archives) ниже. ## AjaxError — `toJSON` / `toString` `AjaxError` принимает `requestInfo`, содержащий переданные вызывающим кодом `params`. Конструктор пропускает эти `params` через тот же редактор, поэтому ключи учётных данных выше никогда не сохраняются на объекте ошибки — ни в выводе `toJSON()`, ни в строковой форме, ни в любой строке лога, которая впоследствии включает ошибку. ```ts-type // Что вы получаете из AjaxError.toJSON().requestInfo.params, // независимо от того, что передал вызывающий код: { ID: 42, access_token: '***REDACTED***', auth: '***REDACTED***' } ``` ## Что SDK не редактирует SDK знает о канонических ключах, перечисленных выше, сопоставляемых **без учёта регистра** по точному имени ключа. Редактор **не** вырежет: - **Кастомные поля payload, которые вы придумали** — например, `mySecretField`, `apiKeyHeader`, `x_internal_token`, всё, чей ключ не входит в [`SENSITIVE_PARAM_KEYS`](https://bitrix-tools.github.io/b24jssdk/#what-the-sdk-redacts-automatically). - **Учётные данные, встроенные внутрь строковых значений, кроме канонических query-пар** — пара `<канонический-ключ>=<значение>` внутри строки (например, в batch `cmd[i]`) **маскируется**, но секрет не в форме `ключ=значение` — голый токен, вставленный в `description`, или ключ query в скобках/кодировке вроде `auth[application_token]=…` — нет. - **Данные глубже двух уровней** — всё за пределами глубины `cmd[i].params.` проходится мимо, а не внутрь. - **Кастомные заголовки запроса, которые вы задаёте на нижележащем axios-клиенте** — например, заголовок `Authorization: Bearer `, настроенный через ваш собственный axios-interceptor. Редактор трогает только `params`, а не заголовки, и заголовки в любом случае не входят в стандартный контекст логгера SDK — но они живут на `AxiosError.config.headers`, см. следующий пункт. > \[!WARNING] > > **Не логируйте `err.originalError` напрямую.** `AjaxError` (через свою > базу [`SdkError`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/sdk-error.ts#L15){rel=""nofollow""}) > предоставляет публичное поле `originalError`, которое при транспортных > сбоях держит **сырой** `AxiosError`. Этот `AxiosError.config.url` > содержит полный URL вебхука > (`/rest/{userId}/{secret}/method.json`), а `AxiosError.config.headers` > может содержать `Authorization`. Ни то, ни другое не редактируется SDK — их > никогда не было внутри `params`. Используйте `err.code`, `err.status`, `err.message` > или `err.requestInfo` (который **редактируется**) и никогда не превращайте > `err.originalError` целиком в строку в любой sink логгера. Вырезание перечисленного выше — **ответственность вызывающего кода**. Либо вообще не кладите секреты в нестандартные ключи / нестандартные каналы лога, либо редактируйте в обработчике / процессоре своего кастомного логгера. ## Рекомендуемый паттерн: подключение кастомного логгера Безопасный паттерн — оставить редактирование SDK на месте и прикрутить ваш кастомный sink сверху — никогда не заменяйте очистку на стороне SDK самописной ниже по потоку. // @check-ignore: full example — sendToRemoteAggregator is a placeholder, not declared ```ts import { B24Hook, Logger, ConsoleV2Handler, LogLevel } from '@bitrix24/b24jssdk' const b24 = new B24Hook({ /* … */ }) const $logger = new Logger('app') $logger.pushHandler(new ConsoleV2Handler(LogLevel.INFO)) // Необязательный процессор «на всякий случай»: редактирует любые *кастомные* ключи, о которых SDK // не знает. Стандартные ключи (auth / token / …) уже // очищены до того, как доходят сюда. $logger.pushProcessor((record) => { if (record.context?.params && typeof record.context.params === 'string') { record.context.params = record.context.params.replace( /"mySecretField":"[^"]*"/g, '"mySecretField":"***REDACTED***"' ) } return record }) b24.setLogger($logger) ``` Чего **избегать**: // @check-ignore: anti-pattern illustration — b24 and sendToRemoteAggregator are undeclared placeholders ```ts // НЕ ДЕЛАЙТЕ ТАК — повторная отдача контекста без проверки пробрасывает произвольные // данные от вызывающего кода в удалённый sink, а обход LoggerInterface // через `as any` скрывает факт, что обработчики должны реализовать все 8 // методов уровней логирования (log / debug / info / notice / warning / error / // critical / alert / emergency). Частичная реализация молча // отбросит записи на нереализованных уровнях. b24.setLogger({ async info(message, context) { await sendToRemoteAggregator({ msg: message, // `context.params` в `post/send` — это уже отредактированная *строка*, // но кастомная обёртка action может также вызвать этот `info` с // сырым объектом `params` (или с `error`, чей `originalError` // — неотредактированный `AxiosError`). Не пробрасывайте `context` // вслепую — выбирайте поля, которые вам действительно нужны. ctx: context }) } // ...остальные 7 методов опущены — приведение типа ниже и позволяет этому // компилироваться несмотря на неполный интерфейс; в реальном коде реализуйте // `LoggerInterface` полностью (или наследуйте `AbstractLogger`). } as any) ``` Три конкретных режима отказа, от которых нужно защищаться: 1. **Логирование исходного объекта запроса вами самими.** Если ваша обёртка захватывает `params` до вызова в SDK и логирует его, редактор SDK никогда не выполнится на этой копии. Всегда редактируйте и в своём собственном пути логирования. 2. **Обращение к `err.originalError` / `err.cause`.** `requestInfo.params` у `AjaxError` очищается, поэтому `String(err)` и `JSON.stringify(err)` сами по себе безопасны. Но если вы логируете `err.originalError`, вы можете смотреть на сырой `AxiosError`, чей `config.url` всё ещё держит полный URL вебхука. См. блок предупреждения в [Что SDK не редактирует](https://bitrix-tools.github.io/b24jssdk/#what-the-sdk-does-not-redact). 3. **Кастомные или глубоко вложенные секреты в `post/response`.** Канал `post/response` теперь прогоняет `response.data.result` через тот же редактор, поэтому канонические ключи учётных данных на глубине ≤ 2 маскируются. Но секрет под **кастомным** ключом или вложенный глубже двух уровней всё ещё доходит до вашего sink'а — те же ограничения, что и везде (см. [Что SDK не редактирует](https://bitrix-tools.github.io/b24jssdk/#what-the-sdk-does-not-redact)). ## Аудит архивов логов Просканируйте архивы логов, чтобы убедиться, что в них нет паттернов учётных данных — полезная рутинная проверка, особенно если ваша настройка отправляет логи в сторонний агрегатор или хранит их долго. **URL вебхука в логах запросов** — grep (Linux/macOS) / ripgrep / PowerShell: ```bash grep -rEi '/rest/[0-9]+/[a-zA-Z0-9]+/' /var/log/myapp/ rg -i '/rest/\d+/[a-zA-Z0-9]+/' /var/log/myapp/ ``` ```powershell Select-String -Path 'C:\logs\myapp\*.log' -Pattern '/rest/\d+/[a-zA-Z0-9]+/' ``` **Ключи учётных данных в сериализованных params** — grep (Linux/macOS) / ripgrep / PowerShell: ```bash grep -rE '"(auth|password|token|secret|access_token|refresh_token|client_secret|application_token|sessid)":\s*"[^"]+"' /var/log/myapp/ rg '"(auth|password|token|secret|access_token|refresh_token|client_secret|application_token|sessid)":\s*"[^"]+"' /var/log/myapp/ ``` ```powershell Select-String -Path 'C:\logs\myapp\*.log' -Pattern '"(auth|password|token|secret|access_token|refresh_token|client_secret|application_token|sessid)":\s*"[^"]+"' ``` Замените `/var/log/myapp/` (или `C:\logs\myapp\`) на ваши реальные пути логов. Типичные sink'и для проверки: захваты stdout (Docker logs, systemd journal, PM2), файлы, записанные через `StreamHandler`, и сторонние агрегаторы (Datadog, Logtail, Splunk, Papertrail и т.д.). Паттерн URL вебхука производился записями `post/send` в версиях SDK `>= 1.1.0, < 1.1.2`, когда был подключён кастомный логгер. Паттерны ключей учётных данных могли появляться в `post/send` для любой версии из этого диапазона, где соответствующий ключ присутствовал в params запроса. Оба подавлены SDK с v1.1.2. `client_secret`, `application_token` и `sessid` были добавлены в редактор в v1.3 — включите их (выше) при сканировании архивов с endpoint-ов, передающих эти параметры. Канонический список также покрывает `key`, опущенный в паттернах выше, потому что `"key":` слишком част, чтобы грепать без сильного шума — сканируйте его вручную, если ваша интеграция использует `key` как учётные данные. `signature` был добавлен в #43 для HMAC push/pull-канала. Архивы старых версий, где был подключён кастомный логгер с активным pull-клиентом, могут содержать `"signature":"…"` — сканируйте `"signature":\s*"[^"]+"`, если использовали pull-сервер, помня, что он (как и `key`) может быть шумным. Если любой из паттернов совпадает в ваших архивах, ротируйте затронутые учётные данные: удалите и пересоздайте вебхук, чтобы сгенерировать новый секрет, или отзовите и перевыпустите токен OAuth / Frame. ## Продвинутое: чтение исходников Для деталей сверх того, что здесь кратко изложено, канонические источники: - [`packages/jssdk/src/core/http/redact.ts`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/redact.ts){rel=""nofollow""} — список ключей, плейсхолдер и глубина обхода. - [`packages/jssdk/src/core/http/abstract-http.ts`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/abstract-http.ts){rel=""nofollow""} — каждое место вызова, прогоняющее данные через редактор. - [`packages/jssdk/src/core/http/ajax-error.ts`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-error.ts){rel=""nofollow""} — редактирование при конструировании ошибки и форма `requestInfo`. См. также [страницу Логгер](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/logger.md) о самом фреймворке логирования (каналы, обработчики, процессоры, форматтеры) и [страницу Ошибки](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/errors.md) о семантике `AjaxError`. --- # Browser > Дешёвый детектор user-agent / платформы / возможностей. Полезен для runtime-ветвлений во фронтенд-коде. ## Обзор `Browser` — это синглтон (`new BrowserManager()`), экспортируемый из `@bitrix24/b24jssdk`. Он объединяет дешёвые проверки user-agent / платформы / возможностей, на которые SDK опирается внутри, и предоставляет их коду приложения: - **Определение браузера** — Opera, Internet Explorer (с 6 по 11, плюс числовой `detectIEVersion`), Safari, Firefox, Chrome. - **Определение ОС / платформы** — macOS, Windows, Linux, Android (с `detectAndroidVersion`), iPad, iPhone и объединённый `isIOS`. - **Возможности** — `isMobile`, `isRetina`, `isTouchDevice`, `isDoctype` и `isLocalStorageSupported`. Все проверки выводятся из строки `UA` уровня модуля — приведённого к нижнему регистру `navigator.userAgent`, захваченного один раз во время импорта — или из браузерных глобальных объектов (`window`, `document`, `navigator`, `localStorage`). Из-за этого `Browser` имеет смысл только в браузерном контексте. ```ts import { Browser } from '@bitrix24/b24jssdk' if (Browser.isMobile()) { // ... } if (Browser.isLocalStorageSupported()) { // ... } ``` ## Сигнатура методов ### Определение браузера ```ts-type isOpera(): boolean // UA содержит 'opera' isIE(): boolean // устаревший 'attachEvent' в document и не Opera isIE6(): boolean // UA содержит 'msie 6' isIE7(): boolean // UA содержит 'msie 7' isIE8(): boolean // UA содержит 'msie 8' isIE9(): boolean // document.documentMode >= 9 isIE10(): boolean // document.documentMode >= 10 isIE11(): boolean // detectIEVersion() >= 11 detectIEVersion(): number // числовая версия IE, -1 если не IE isSafari(): boolean // UA содержит 'safari' и не 'chrome' isFirefox(): boolean // UA содержит 'firefox' isChrome(): boolean // UA содержит 'chrome' ``` ### Определение ОС / платформы ```ts-type isMac(): boolean // UA содержит 'macintosh' isWin(): boolean // UA содержит 'windows' isLinux(): boolean // UA содержит 'linux' и не Android isAndroid(): boolean // UA содержит 'android' detectAndroidVersion(): number // разобранная версия Android, 0 если не определена isIPad(): boolean // UA содержит 'ipad;' или Mac + touch isIPhone(): boolean // UA содержит 'iphone;' isIOS(): boolean // isIPad() || isIPhone() ``` ### Возможности ```ts-type isMobile(): boolean // UA iPhone / iPad / Android / 'mobile' / 'touch' isRetina(): boolean // window.devicePixelRatio >= 2 isTouchDevice(): boolean // 'ontouchstart' in window или maxTouchPoints > 0 isDoctype(target?: any): boolean // compatMode === 'CSS1Compat' (или запасной вариант) isLocalStorageSupported(): boolean // setItem/removeItem round-trip проходит успешно ``` ## Ключевые понятия > \[!NOTE] > > `Browser` читает `navigator.userAgent` в переменную `UA` уровня модуля **один раз**, во время импорта. Чтение обёрнуто в `try`/`catch`, поэтому импорт модуля в небраузерном окружении (например, Node/SSR) не выбрасывает исключение — `UA` просто откатывается к `'?'`, и каждая проверка на основе UA возвращает `false`. Методы, напрямую обращающиеся к `window`, `document` или `localStorage` (`isRetina`, `isTouchDevice`, `isDoctype`, `isLocalStorageSupported`, `isIE`/`isIE9`/`isIE10`), всё же предполагают наличие этих глобальных объектов, поэтому их вызов вне браузера может выбросить исключение. > \[!CAUTION] > > Это анализ user-agent (UA-sniffing), а не feature detection. Строки user agent можно подделать или обнулить, и браузеры всё чаще замораживают/урезают детали UA. Где возможно, предпочитайте feature detection (например, проверку именно того API, который вам нужен), и относитесь к `Browser` как к эвристике по принципу best-effort для косметических/UX-ветвлений, а не как к границе безопасности или корректности. - **`isIPad()` покрывает современный iPadOS.** Поскольку iPadOS сообщает о себе в строке UA как macOS, `isIPad()` также возвращает `true` для UA в стиле Mac, который при этом сообщает о поддержке touch (`isTouchDevice()`) — именно так он отличает iPad от настоящего десктопного Mac. - **`detectIEVersion()` возвращает `-1` для не-IE браузеров.** Он замыкается на `-1` для Opera, Safari, Firefox и Chrome до запуска специфичных для IE/Trident эвристик, поэтому его безопасно вызывать безусловно. - **`isDoctype(target?)` принимает любой document-подобный объект.** Передайте `document` из iframe (или подобный), чтобы проверить режим рендеринга *его*, а не верхнеуровневой страницы; при отсутствии `target` используется глобальный `document`. - **`isLocalStorageSupported()` — это реальная проба записи/удаления**, а не просто проверка `typeof localStorage` — она также ловит случаи, когда API существует, но выбрасывает исключение (режимы приватного просмотра, исчерпание квоты хранилища, отключение политикой). ## Обработка ошибок `Browser` рассчитан на браузерные runtime. Чтение user-agent уровня модуля и `isLocalStorageSupported()` обёрнуты в `try/catch`, но большинство проверок напрямую разыменовывают `document` / `window` / `navigator` (например, `isIE`, `isIE9`, `isRetina`, `isTouchDevice`, `detectIEVersion`, `detectAndroidVersion`) и выбрасывают `ReferenceError`, когда этих глобальных объектов нет. Оборачивайте любой вызов проверкой окружения (или вовсе избегайте `Browser`) в путях кода Node.js / SSR, которые могут выполниться до гидрации. ## Примеры Определение браузера: ```ts import { Browser } from '@bitrix24/b24jssdk' if (Browser.isChrome()) { // Поведение для Chrome } if (Browser.isIE()) { const version = Browser.detectIEVersion() console.log(`Running on Internet Explorer ${version}`) } ``` Ветвление по ОС / платформе: ```ts import { Browser } from '@bitrix24/b24jssdk' if (Browser.isIOS()) { // Общая ветка iPhone / iPad } if (Browser.isAndroid()) { const version = Browser.detectAndroidVersion() console.log(`Android version: ${version}`) } ``` Проверки возможностей: ```ts import { Browser } from '@bitrix24/b24jssdk' if (Browser.isMobile() && Browser.isTouchDevice()) { // Подстройка вёрстки / зон нажатия под touch } if (Browser.isRetina()) { // Отдавать ассеты высокого разрешения } ``` Защита доступа к `localStorage` и проверка режима рендеринга документа: ```ts import { Browser } from '@bitrix24/b24jssdk' function persist(key: string, value: string): void { if (!Browser.isLocalStorageSupported()) { return } localStorage.setItem(key, value) } if (!Browser.isDoctype(document)) { console.warn('Page is rendered in quirks mode') } ``` ## Альтернативы и рекомендации - **Где возможно, предпочитайте feature detection анализу UA.** Проверки `Browser` — это эвристики на основе `navigator.userAgent`, который можно подделать, заморозить или урезать в браузере. Например, предпочитайте прямую проверку `'ontouchstart' in window` (или `Browser.isTouchDevice()`, который делает ровно это) выводу о поддержке touch из проверок платформы. - **Используйте `isMobile()` / `isTouchDevice()` для решений по вёрстке, а не для блокировки функциональности.** Относитесь к ним как к UX-подсказкам (например, крупнее зоны нажатия, упрощённая навигация), а не как к способу полностью отключить функции — десктопный браузер на ноутбуке с поддержкой touch — это легитимная комбинация. - **Методы, связанные с IE (`isIE*`, `detectIEVersion`, `isIE11`), нацелены на давно снятые с поддержки браузеры.** Держите их только для веток legacy-совместимости; новому коду под современные браузеры они, как правило, не нужны. - **Проверки типов для значений (а не окружения) живут в [`Type`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-type.md).** `Browser` отвечает на вопрос «в чём я выполняюсь», тогда как `Type` — «какой формы это значение». --- # Text > Утилиты для текста и дат — UUID v4 / v7, кодирование / декодирование HTML-сущностей, преобразования типов, хелперы регистра, \`toDateTime\` / \`toB24Format\` на Luxon, форматирование чисел и конструктор query-строки. ## Обзор `Text` — это синглтон (`new TextManager()`), экспортируемый из `@bitrix24/b24jssdk`. Он объединяет небольшие хелперы для текста и дат, на которые SDK опирается внутри, и предоставляет их коду приложения: - **Идентификаторы** — случайные строки, локально генерируемый UUID v4 и упорядоченный по времени UUID v7 (request id по умолчанию у SDK). - **Кодирование HTML-сущностей** — `encode` / `decode` в стиле legacy Bitrix Framework. - **Преобразование типов** — приведение произвольных значений к числам, целым и булевым. - **Хелперы регистра** — `camelCase`, `PascalCase`, `kebab-case` и `capitalize`. - **Форматирование чисел** — группировка тысяч с фиксированным числом знаков после запятой. - **Хелперы дат** — парсинг на [Luxon](https://moment.github.io/luxon/){rel=""nofollow""} и формат `yyyy-MM-dd'T'HH:mm:ssZZ`, который Bitrix24 ожидает в REST-payload. - **Query-строки** — сборка строки `application/x-www-form-urlencoded` из обычного объекта. ```ts import { Text } from '@bitrix24/b24jssdk' console.log(Text.getUuidRfc4122()) // '019323ac-8ace-725b-a3dc-6a7c333da066' console.log(Text.getDateForLog()) // '2026-05-04 09:53:51' console.log(Text.numberFormat(1234.567, 2)) // '1,234.57' ``` ## Сигнатура методов ### Идентификаторы ```ts-type getRandom(length?: number): string // случайные [a-z0-9], длина по умолчанию 8 getUniqId(): string // UUID v4 (по возможности, локально) getUuidRfc4122(): string // UUID v7 (упорядоченный по времени) — request id по умолчанию у SDK ``` ### Кодирование сущностей ```ts-type encode(value: string): string // & < > ' " → entity-коды (без завершающей ;) decode(value: string): string // обратное к encode, также числовые сущности ``` ### Преобразование типов ```ts-type toNumber(value: any): number // 0 при неудаче парсинга toInteger(value: any): number // toNumber(parseInt(value, 10)) toBoolean(value: any, trueValues?: string[]): boolean // 'true'/'y'/'1'/1/true → true ``` ### Хелперы регистра ```ts-type toCamelCase(str: string): string toPascalCase(str: string): string // capitalize(toCamelCase(str)) toKebabCase(str: string): string capitalize(str: string): string ``` ### Форматирование чисел ```ts-type numberFormat( number: number, decimals?: number, // по умолчанию 0 decPoint?: string, // по умолчанию '.' thousandsSep?: string // по умолчанию ',' ): string ``` ### Хелперы дат (Luxon) ```ts-type toDateTime(dateString: string, template?: string, opts?: DateTimeOptions): DateTime toB24Format(date: string | Date | DateTime): string // yyyy-MM-dd'T'HH:mm:ssZZ getDateForLog(): string // 'yyyy-MM-dd HH:mm:ss' ``` ### Query-строка ```ts-type buildQueryString(params: any): string // application/x-www-form-urlencoded, без ведущего '?' ``` ## Ключевые понятия > \[!NOTE] > > `encode` / `decode` намеренно опускают завершающую `;` (например, `&` вместо `&`). Это соответствует поведению legacy Bitrix Framework. `decode` разворачивает такой вывод и также распознаёт числовые сущности (`&`, `<`, …). Поскольку токены не несут `;`, завершающая `;` во входе остаётся на месте (`&` → `&;`). > \[!CAUTION] > > `encode` — это **не** универсальный HTML-санитайзер. Он экранирует только `&`, `<`, `>`, `'` и `"` и не учитывает контекст — он не остановит выход за пределы атрибута, `javascript:`-URL или разметку вне этих пяти символов. Не используйте его как единственную защиту от XSS для недоверенного ввода, рендеримого как HTML. - **`getRandom` / `getUniqId` не криптографически стойкие.** Оба построены на `Math.random()` — используйте их для ключей cache-busting и одноразовых id, но никогда для токенов или секретов. - **Разделители `toCamelCase`.** `-`, `_` и пробелы трактуются как границы слов; полностью заглавный вход приводится к нижнему регистру (`'ABC'` → `'abc'`). - **`toKebabCase` разбивает по границам регистра.** `getUserId` → `get-user-id` и `XMLHttpRequest` → `xml-http-request`, поэтому `camelCase` и смешанные аббревиатуры обрабатываются. Один крайний случай: последовательность заглавных, сразу за которой идёт цифра, разбивается буква-за-буквой (`parseHTML5` → `parse-h-t-m-l-5`). - **`numberFormat` соответствует серверу.** Не-конечные значения становятся `0`, дробная часть округляется до `decimals` знаков, а разделитель тысяч вставляется каждые три цифры слева от десятичной точки. - **`toDateTime` возвращает `DateTime` даже для некорректного ввода.** Когда передан `template`, используется `DateTime.fromFormat`, иначе `DateTime.fromISO`. Проверяйте `result.isValid` перед использованием. - **`toB24Format` пропускает строки без изменений** (считаются уже отформатированными); JS-`Date` сначала нормализуется через Luxon. ## Обработка ошибок Хелперы `Text` не выбрасывают исключений для неожиданного ввода — они деградируют мягко: `toNumber` / `toInteger` возвращают `0`, `toBoolean` возвращает `false`, `buildQueryString(null)` возвращает `''`, а `encode` / `decode` возвращают не-строковые значения без изменений. `toDateTime` тоже никогда не выбрасывает — он возвращает `DateTime`, чей флаг `isValid` равен `false` для неразбираемого ввода, поэтому проверяйте `result.isValid` перед использованием значения. ## Примеры Идентификаторы и request id: ```ts import { Text } from '@bitrix24/b24jssdk' Text.getRandom() // 'a7f3k1z9' Text.getRandom(4) // 'p2x8' Text.getUniqId() // 'd2b8a1f0-3c4e-4a9b-8f7c-1e2d3a4b5c6d' (UUID v4) Text.getUuidRfc4122() // '019323ac-8ace-725b-a3dc-6a7c333da066' (UUID v7) ``` Кодирование и преобразование типов: ```ts import { Text } from '@bitrix24/b24jssdk' Text.encode('Tom & Jerry') // '<b>Tom & Jerry</b>' Text.decode('<b>Tom & Jerry</b>') // 'Tom & Jerry' Text.toNumber('12.5') // 12.5 Text.toInteger('42.9') // 42 Text.toBoolean('Y') // true Text.toBoolean('on', ['on']) // true ``` Хелперы регистра и форматирование чисел: ```ts import { Text } from '@bitrix24/b24jssdk' Text.toCamelCase('get_user_id') // 'getUserId' Text.toPascalCase('get_user_id') // 'GetUserId' Text.toKebabCase('getUserId') // 'get-user-id' Text.capitalize('hello') // 'Hello' Text.numberFormat(1234.567, 2) // '1,234.57' Text.numberFormat(1234.567, 2, ',', ' ') // '1 234,57' ``` Даты и query-строки: ```ts import { Text } from '@bitrix24/b24jssdk' // Форматирование даты для REST-payload Text.toB24Format(new Date()) // '2026-05-04T09:53:51+03:00' // Разбор ISO-строки или кастомного шаблона const dt = Text.toDateTime('04.05.2026', 'dd.MM.yyyy') if (dt.isValid) { console.log(dt.toISODate()) // '2026-05-04' } // Сборка query-строки (ведущий '?' не включается) Text.buildQueryString({ id: 7, tag: ['a', 'b'] }) // 'id=7&tag%5B0%5D=a&tag%5B1%5D=b' ``` ## Альтернативы и рекомендации - **Предпочитайте `getUuidRfc4122()` вместо `getUniqId()`.** Идентификатор v7 упорядочен по времени и совместим с RFC 4122 — поэтому SDK использует его как request id по умолчанию. Берите `getUniqId()` (UUID v4) только когда вам конкретно нужен случайный, несортируемый id, и ни то ни другое — когда нужна криптографическая случайность. - **Используйте `toB24Format` для каждой даты, которую отправляете в REST API.** Передача сырого `Date` или ISO-строки с неверным смещением — самая частая причина несовпадений фильтров; примеры фильтров по диапазону дат см. в [Фильтрации](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/filtering.md). - **Проверки типов в runtime живут в [`Type`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-type.md).** `Text` сфокусирован на преобразовании; используйте проверки `Type` (`isStringFilled`, `isArrayFilled`, …), когда сначала нужно ветвиться по форме значения. - **Форматирование валюты / IBAN с учётом локали живёт в [`useFormatter`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-use-formatters.md).** `numberFormat` — это лёгкий хелпер тысяч-и-десятичных; для валюты, процентов или IBAN используйте специализированные форматтеры. - **Для чего-либо богаче парсинга работайте с Luxon напрямую.** `toDateTime` — тонкая обёртка над `DateTime.fromISO` / `DateTime.fromFormat`; для арифметики, зон и длительностей импортируйте `DateTime` из `luxon` и оперируйте возвращённым значением. --- # Type > Runtime type guards — строки, числа, обычные объекты, массивы, DOM-узлы, Blob, FormData, формы JSON-RPC сообщений. ## Обзор `Type` — это синглтон (`new TypeManager()`), экспортируемый из `@bitrix24/b24jssdk`. Каждый метод (кроме `getTag` и `clone`) — это type guard TypeScript, поэтому вы можете использовать его в цепочках `if`, и компилятор сузит тип значения: ```ts import { Type } from '@bitrix24/b24jssdk' function process(value: unknown) { if (Type.isStringFilled(value)) { // value: string return value.trim() } if (Type.isPlainObject(value)) { // value: Record } } ``` Проверки сгруппированы по виду значения, которое они проверяют: - **Строки** — проверки на непустую строку. - **Числа / булевы** — число, целое, дробное, булево. - **Объекты / функции** — обычные объекты, функции, `Map` / `Set` / `WeakMap` / `WeakSet`, `RegExp`, прототипы, `null` / `undefined`. - **Массивы** — массивы, array-like значения, типизированные массивы, `ArrayBuffer`. - **DOM** — узлы, узлы-элементы, текстовые узлы. - **Файлы** — `Blob`, `File`, `FormData`. - **JSON-RPC** — формы сообщений request / response. - **Прочее** — `getTag` (сырой тег `[[Class]]`) и `clone` (глубокое клонирование). ## Сигнатура методов ### Строки | Метод | Предикат | | --- | --- | | `isString(value)` | `typeof value === 'string'` или `value instanceof String`. | | `isStringFilled(value)` | `isString(value) && value !== ''`. | ### Числа / булевы | Метод | Предикат | | --- | --- | | `isNumber(value)` | `typeof value === 'number'` и не `NaN`. | | `isInteger(value)` | `Number.isInteger(value)`. | | `isFloat(value)` | `isNumber && !isInteger`. | | `isBoolean(value)` | `value === true || value === false`. | ### Объекты / функции | Метод | Предикат | | --- | --- | | `isFunction(value)` | `typeof value === 'function'` (а также экземпляры `Function`). | | `isObject(value)` | `typeof === 'object' || 'function'` (и не `null`). | | `isObjectLike(value)` | только `typeof === 'object'` (также истинно для объектов, не равных `null`, включая массивы). | | `isPlainObject(value)` | Истина для объектов, чей `constructor` — `Object` (ложь для массивов, экземпляров классов, DOM-узлов). | | `isPrototype(value)` | Истина для объектов `prototype`. | | `isMap`, `isSet`, `isWeakMap`, `isWeakSet`, `isRegExp` | Проверки по тегу (`Object.prototype.toString.call(value)`). | | `isDate(value)` | `value instanceof Date`. | | `isNil(value)` | `value === null || value === undefined`. | | `isNull` / `isUndefined` | Очевидно из названия. | ### Массивы | Метод | Предикат | | --- | --- | | `isArray(value)` | `Array.isArray`. | | `isArrayFilled(value)` | `isArray && value.length > 0`. | | `isArrayLike(value)` | Имеет числовой `length` и не является функцией — также соответствует строкам. | | `isArrayBuffer(value)` | Проверка по тегу. | | `isTypedArray(value)` | Соответствует `Int8Array / Uint8Array / Uint8ClampedArray / Int16Array / Uint16Array / Int32Array / Uint32Array / Float32Array / Float64Array` (проверка по тегу). | ### DOM | Метод | Предикат | | --- | --- | | `isDomNode(value)` | Имеет `nodeType` и не является обычным объектом. | | `isElementNode(value)` | `nodeType === Node.ELEMENT_NODE`. | | `isTextNode(value)` | `nodeType === Node.TEXT_NODE`. | ### Файлы / Blob / FormData | Метод | Предикат | | --- | --- | | `isBlob(value)` | Имеет `size: number`, `type: string`, `slice: Function`. | | `isFile(value)` | `isBlob && name: string && (lastModified || lastModifiedDate)`. | | `isFormData(value)` | `instanceof FormData` (когда глобал доступен) или проверка по тегу. | ### JSON-RPC | Метод | Предикат | | --- | --- | | `isJsonRpcRequest(value)` | Имеет `jsonrpc` (непустой) и `method` (непустой). Тип возврата — `boolean`, а не type guard. | | `isJsonRpcResponse(value)` | Имеет `jsonrpc`, `id` и либо `result`, либо `error`. Тип возврата — `boolean`, а не type guard. | ### Прочее ```ts-type getTag(value: any): string // Object.prototype.toString.call(value) clone(obj: any, bCopyObj?: boolean): any // глубокое клонирование; bCopyObj по умолчанию true ``` ## Ключевые понятия - **`isJsonRpcRequest` / `isJsonRpcResponse` — это обычные предикаты `boolean`, а не type guards.** Каждый другой метод этого класса сужает через `value is X`; эти два намеренно (или нет) возвращают `boolean`, поэтому использование их в `if` не сужает тип `value`. - **`isObjectLike` сужает к переданному вызывающим кодом дженерику, а не к `object`.** Он лишь проверяет `typeof value === 'object' && value !== null`; переданный вами `T` не проверяется в runtime — массивы, `Map`, `Date` и DOM-узлы все проходят. `isPlainObject` — более строгая проверка, когда вам конкретно нужен объект в стиле `{}`. - **`isArrayLike` также соответствует строкам.** У строк есть числовой `length`, и они не функции, поэтому `Type.isArrayLike('abc')` — `true`. Используйте `isArray`, когда нужен настоящий массив. - **`isDomNode` требует реального DOM-глобала.** `isElementNode` / `isTextNode` разыменовывают глобальную константу `Node`, поэтому работают только в браузерном (или JSDOM) окружении — их вызов в чистом Node.js без DOM-шима выбрасывает `ReferenceError`. - **`clone` ничего не мутирует в источнике, но клонирует только распознаваемые им формы обычных данных.** Массивы и обычные объекты копируются ключ за ключом (рекурсивно, если `bCopyObj` не `false`), `Date` пересобирается через `new Date(obj)`, а DOM-узлы проходят через `Node.cloneNode(bCopyObj)`. Всё остальное с `typeof obj === 'object'` попадает в общую ветку и пересобирается через `new obj.constructor()`, поэтому кастомные классы с обязательными аргументами конструктора могут выбросить исключение. ## Обработка ошибок Методы-проверки никогда не выбрасывают исключений для проверяемого значения — не совпавшее, `null` или `undefined` значение просто даёт `false`. Исключения зависят от окружения: `isElementNode` / `isTextNode` разыменовывают глобальную константу `Node` и выбрасывают `ReferenceError` вне DOM-окружения, а `clone` может выбросить, когда откатывается к `new obj.constructor()` для класса, требующего аргументов конструктора. Оборачивайте такие вызовы при работе на сервере или при клонировании произвольных экземпляров классов. ## Примеры Сужение через проверки строк и объектов: ```ts import { Type } from '@bitrix24/b24jssdk' function describe(value: unknown): string { if (Type.isStringFilled(value)) { return `string: ${value.trim()}` } if (Type.isPlainObject(value)) { return `object with ${Object.keys(value).length} keys` } if (Type.isArrayFilled(value)) { return `array with ${value.length} items` } return 'unknown' } describe(' hi ') // 'string: hi' describe({ a: 1 }) // 'object with 1 keys' describe([1, 2, 3]) // 'array with 3 items' ``` Проверки по тегу и `getTag`: ```ts import { Type } from '@bitrix24/b24jssdk' Type.getTag([1, 2, 3]) // '[object Array]' Type.getTag(new Map()) // '[object Map]' Type.getTag(/abc/) // '[object RegExp]' Type.isMap(new Map()) // true Type.isSet(new Set()) // true Type.isRegExp(/abc/) // true ``` Формы JSON-RPC сообщений: ```ts import { Type } from '@bitrix24/b24jssdk' Type.isJsonRpcRequest({ jsonrpc: '2.0', method: 'ping', id: 1 }) // true Type.isJsonRpcRequest({ jsonrpc: '2.0' }) // false, нет `method` Type.isJsonRpcResponse({ jsonrpc: '2.0', id: 1, result: { ok: true } }) // true Type.isJsonRpcResponse({ jsonrpc: '2.0', id: 1 }) // false, нет `result`/`error` ``` Глубокое клонирование через `clone`: ```ts import { Type } from '@bitrix24/b24jssdk' const original = { a: 1, nested: { b: 2 } } const deep = Type.clone(original) deep.nested.b = 99 console.log(original.nested.b) // 2 — не тронуто, глубокое клонирование const shallow = Type.clone(original, false) shallow.nested.b = 42 console.log(original.nested.b) // 42 — та же вложенная ссылка, поверхностное клонирование ``` ## Альтернативы и рекомендации - **Предпочитайте методы-type-guards (`value is X`) ручным проверкам `typeof` / `instanceof`.** Они читаются так же, но ещё и сужают TypeScript-тип значения внутри ветки `if`, чего две возвращающие `boolean` проверки JSON-RPC не делают. - **Используйте `isPlainObject` вместо `isObject`, когда нужен объект-запись в стиле `{}`.** `isObject` также принимает функции, а `isObjectLike` принимает массивы, `Map`, `Date` и DOM-узлы — `isPlainObject` единственный из трёх исключает всё это. - **`isTypedArray` покрывает девять конкретных представлений типизированных массивов, но не `DataView`.** Он соответствует `Int8Array` … `Float64Array`, но возвращает `false` для `DataView`; используйте `ArrayBuffer.isView(value)`, когда хотите включить и `DataView`. - **Приведение и форматирование строк/чисел живут в [`Text`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-text.md).** `Type` только проверяет формы; используйте `Text.toNumber` / `Text.toInteger` / `Text.toBoolean`, когда нужно преобразовать значение, а не просто проверить его. - **`clone` — это универсальное глубокое клонирование, а не замена structured-clone.** Для значений, которыми вы управляете (обычные данные из REST API), его достаточно; для payload'ов `Map` / `Set` / `ArrayBuffer` или значений, требующих точной верности прототипа, предпочитайте `structuredClone` (где доступен) или специализированную библиотеку клонирования. --- # useFormatter > Composable, возвращающий общие экземпляры \`FormatterNumbers\` и \`FormatterIban\`, преднастроенные спецификациями стран. ## Обзор `useFormatter()` — это composable, экспортируемый из `@bitrix24/b24jssdk`. Он возвращает два общих форматтера-синглтона: - **`formatterNumber`** — экземпляр `FormatterNumbers`, обёртка над `Intl.NumberFormat` с учётом локали. - **`formatterIban`** — экземпляр `FormatterIban`, предзагруженный спецификациями стран IBAN: каждая страна из официального реестра IBAN, несколько неофициальных стран, следующих структуре IBAN, и французские региональные / административные территориальные единицы (GF, GP, MQ, RE, PF, TF, YT, NC, BL, MF, PM). Оба форматтера — синглтоны (`FormatterNumbers.getInstance()` / `FormatterIban.getInstance()`), поэтому каждый вызов `useFormatter()` возвращает одни и те же нижележащие экземпляры — состояние, заданное на одном (например, локаль по умолчанию), видно везде в приложении. `useFormatter()` перерегистрирует спецификации IBAN при каждом вызове, но поскольку `formatterIban` — синглтон, а `addSpecification` просто перезаписывает запись в map для кода страны, повторный вызов `useFormatter()` дёшев. ```ts import { useFormatter } from '@bitrix24/b24jssdk' const { formatterNumber, formatterIban } = useFormatter() console.log(formatterIban.printFormat('GB29NWBK60161331926819')) // 'GB29 NWBK 6016 1331 9268 19' console.log(formatterIban.isValid('DE89370400440532013000')) // true console.log(formatterNumber.format(1234.567)) // '1,234.57' ``` ## Сигнатура методов ### `useFormatter()` ```ts-type useFormatter(): { formatterNumber: FormatterNumbers formatterIban: FormatterIban } ``` ### `FormatterNumbers` ```ts-type setDefLocale(locale: string): void format(value: number, locale?: string): string ``` ### `FormatterIban` ```ts-type addSpecification(spec: IbanSpecification): void isValid(iban: string): boolean printFormat(iban: string, separator?: string): string // разделитель по умолчанию ' ' electronicFormat(iban: string): string // убирает не-буквенно-цифровые символы, переводит в верхний регистр toBBAN(iban: string, separator?: string): string // разделитель по умолчанию ' ' fromBBAN(countryCode: string, bban: string): string isValidBBAN(countryCode: string, bban: string): boolean ``` ## Ключевые понятия > \[!NOTE] > > `FormatterNumbers.format` выбирает локаль в таком порядке: явный аргумент `locale`, затем локаль, заданная через `setDefLocale`, затем `navigator.language` (только в браузере), затем откат к `'en'`. Целые числа форматируются с 0 знаками после запятой, нецелые — ровно с 2. Когда разрешённая локаль содержит `'ru'`, десятичная запятая, производимая `Intl.NumberFormat`, заменяется на точку. > \[!NOTE] > > `FormatterIban.isValid` и методы BBAN (`toBBAN`, `fromBBAN`, `isValidBBAN`) выбрасывают `Error('No country with code XX')`, если у кода страны IBAN/BBAN нет зарегистрированной `IbanSpecification`. Поскольку `useFormatter()` уже регистрирует каждую поддерживаемую страну, это случается только для действительно неподдерживаемых или некорректных кодов стран. - **`isValid` принимает слабо форматированный ввод.** Сначала он прогоняет IBAN через `electronicFormat`, поэтому пробелы и буквы в нижнем регистре нормализуются до проверки специфичных для страны длины, структуры и контрольной суммы ISO 7064 MOD 97-10. Не-строковый ввод возвращает `false` вместо выброса исключения. - **`printFormat` и `toBBAN` оба сначала нормализуют через `electronicFormat`**, поэтому принимают тот же слабо форматированный ввод, что и `isValid`. - **`addSpecification` перезаписывает по коду страны.** Повторный вызов для уже зарегистрированной страны (как делает `useFormatter()` при каждом вызове) просто заменяет существующую `IbanSpecification` — он не накопительный и не может выбросить исключение. - **`FormatterNumbers` и `FormatterIban` нельзя сконструировать напрямую.** Оба класса защищают свой конструктор, и только `getInstance()` может создать синглтон; всегда получайте их через `useFormatter()`. ## Обработка ошибок `useFormatter()` сам по себе никогда не выбрасывает исключений. `FormatterIban.isValid` возвращает `false` для некорректного или не-строкового ввода вместо выброса. Хелперы BBAN (`toBBAN`, `fromBBAN`, `isValidBBAN`) и путь проверки контрольной суммы выбрасывают `Error('No country with code XX')` только для кода страны без зарегистрированной `IbanSpecification` — чего `useFormatter()` никогда не производит, так как регистрирует каждую поддерживаемую страну при каждом вызове. `FormatterNumbers` делегирует `Intl.NumberFormat`, который выбрасывает `RangeError` для недопустимой локали или опции, но не для числового ввода. ## Примеры Валидация и форматирование IBAN: ```ts import { useFormatter } from '@bitrix24/b24jssdk' const { formatterIban } = useFormatter() formatterIban.isValid('DE89370400440532013000') // true formatterIban.isValid('GB29NWBK60161331926818') // false (неверная контрольная сумма) formatterIban.printFormat('GB29NWBK60161331926819') // 'GB29 NWBK 6016 1331 9268 19' formatterIban.printFormat('GB29NWBK60161331926819', '-') // 'GB29-NWBK-6016-1331-9268-19' // Принимает слабо форматированный ввод (пробелы, нижний регистр) formatterIban.electronicFormat('GB29 NWBK 6016 1331 9268 19') // 'GB29NWBK60161331926819' ``` Конвертация между IBAN и BBAN: ```ts import { useFormatter } from '@bitrix24/b24jssdk' const { formatterIban } = useFormatter() formatterIban.toBBAN('GB29NWBK60161331926819') // 'NWBK 601613 31926819' formatterIban.toBBAN('GB29NWBK60161331926819', '-') // 'NWBK-601613-31926819' formatterIban.isValidBBAN('GB', 'NWBK60161331926819') // true formatterIban.fromBBAN('GB', 'NWBK60161331926819') // 'GB29NWBK60161331926819' ``` Форматирование чисел с учётом локали: ```ts import { useFormatter } from '@bitrix24/b24jssdk' const { formatterNumber } = useFormatter() formatterNumber.format(1234) // '1,234' (целое, 'en' по умолчанию) formatterNumber.format(1234.567) // '1,234.57' (округлено до 2 знаков) formatterNumber.format(1234.5, 'de') // '1.234,50' formatterNumber.setDefLocale('ru') formatterNumber.format(1234.5) // '1 234.50' (ru-группировка, точка сохранена вместо запятой) ``` ## Альтернативы и рекомендации - **Используйте `formatterIban.isValid` для проверки пользовательского ввода перед вызовом `printFormat`/`toBBAN`.** Оба метода форматирования только нормализуют строку — они не проверяют контрольную сумму, поэтому некорректный IBAN всё равно можно «напечатать» или сконвертировать. - **Вызывайте `useFormatter()` один раз на модуль/компонент и деструктурируйте то, что нужно.** Поскольку оба форматтера — синглтоны, нет смысла кэшировать возвращаемый объект самому, кроме как ради избавления от boilerplate деструктуризации. - **Для обычного форматирования тысяч/десятичных без учёта локали предпочитайте [`Text.numberFormat`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-text.md).** `formatterNumber.format` учитывает локаль (через `Intl.NumberFormat`) и всегда округляет нецелые до ровно 2 знаков; `Text.numberFormat` позволяет явно выбрать число знаков и разделители, что соответствует серверному форматированию, используемому в остальных payload'ах Bitrix24 REST. - **`addSpecification` существует в основном для внутреннего использования.** `useFormatter()` уже регистрирует каждую поддерживаемую страну при каждом вызове; сама `IbanSpecification` не экспортируется из `@bitrix24/b24jssdk`, поэтому расширение списка стран из кода приложения сегодня не является поддерживаемым публичным сценарием. --- # IResult > Обобщённый интерфейс результата операции. Реализуется \`Result\\` и (транзитивно) \`AjaxResult\\`. `IResult` отражает паттерн «флаг успеха + данные + набор ошибок», используемый по всему SDK. Конкретные классы: - [`Result`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-result.md) — обобщённый. - [`AjaxResult`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-ajax-result.md) — REST-ориентированный (неизменяемый, постраничный, декодирует конверты ошибок Bitrix24). ## Форма ```ts-type interface IResult { readonly isSuccess: boolean readonly errors: Map setData(data: T | null | undefined): IResult getData(): T | null | undefined addError(error: Error | string, key?: string): IResult addErrors(errors: (Error | string)[]): IResult getErrors(): IterableIterator getErrorMessages(): string[] getErrorsByKey(): Record getErrorMessagesByKey(): Record hasError(key: string): boolean toString(): string } ``` `AjaxResult` сужает `setData` до `never` (неизменяемый ответ) и переопределяет `getData()`, чтобы возвращать [`SuccessPayload`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/payloads.ts){rel=""nofollow""} при `isSuccess`. ## Типичный паттерн использования ```ts import type { IResult } from '@bitrix24/b24jssdk' function consume(result: IResult) { if (!result.isSuccess) { for (const message of result.getErrorMessages()) { console.error(message) } return } const data = result.getData() // ... } ``` --- # TypeB24 > Публичный контракт, реализуемый каждым классом-точкой входа (B24Frame, B24Hook, B24OAuth). Единый источник истины для поверхности SDK. `TypeB24` — это унифицированный тип, реализуемый `B24Frame`, `B24Hook` и `B24OAuth`. Используйте его как тип параметра, когда вашему коду не важно, с каким транспортом он работает. ```ts import type { TypeB24 } from '@bitrix24/b24jssdk' async function listAdminTasks($b24: TypeB24): Promise { const response = await $b24.actions.v2.callList.make<{ id: number, title: string }>({ method: 'tasks.task.list', params: { filter: { '!=STATUS': '5' }, select: ['ID', 'TITLE'] }, idKey: 'id', // задачи возвращают id в нижнем регистре cursorIdKey: 'ID', // ...но сортировка / фильтр по ID в верхнем регистре customKeyForResult: 'tasks', requestId: 'admin-tasks' }) return response.isSuccess ? response.getData()! : [] } ``` ## Форма ```ts-type type TypeB24 = { readonly isInit: boolean init(): Promise destroy(): void getLogger(): LoggerInterface setLogger(logger: LoggerInterface): void get auth(): AuthActions get actions(): ActionsManager get tools(): ToolsManager setRestrictionManagerParams(params: RestrictionParams): Promise getTargetOrigin(): string getTargetOriginWithPath(): Map getHttpClient(version: ApiVersion): TypeHttp setHttpClient(version: ApiVersion, client: TypeHttp): void // @deprecated — используйте actions.v2.* / actions.v3.* вместо них. // Удалено в 3.0.0: callMethod(method: string, params?: object, start?: number): Promise callListMethod(method: string, params?: object, progress?: null | ((p: number) => void), customKeyForResult?: string | null): Promise fetchListMethod(method: string, params?: any, idKey?: string, customKeyForResult?: string | null): AsyncGenerator callBatch(calls: any[] | object, isHaltOnError?: boolean, returnAjaxResult?: boolean): Promise callBatchByChunk(calls: any[], isHaltOnError: boolean): Promise } ``` > \[!CAUTION] > > `callMethod` / `callListMethod` / `fetchListMethod` / `callBatch` / `callBatchByChunk` будут удалены в **3.0.0**. Перейдите на `actions.v{2,3}.{call,callList,fetchList,batch,batchByChunk}.make(options)`. ## Связанные типы - [`AuthActions`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/auth.ts){rel=""nofollow""} — возвращается `auth`. - [`ActionsManager`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/actions/manager.ts){rel=""nofollow""} — возвращается `actions`. Содержит `v2.*` и `v3.*`. - [`ToolsManager`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/tools/manager.ts){rel=""nofollow""} — возвращается `tools`. Содержит `healthCheck` и `ping`. - [`TypeHttp`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-http.md) — возвращается `getHttpClient(version)`. - [`RestrictionParams`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md) — аргумент `setRestrictionManagerParams`. - [`ApiVersion`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/types/b24.ts){rel=""nofollow""} — `'v2'` или `'v3'`. --- # Телеметрия > Query-параметры request id, версии SDK и типа SDK, добавляемые к каждому REST-вызову Bitrix24. SDK добавляет три телеметрических query-параметра к каждому исходящему REST-запросу. Их имена стабильны между версиями; их значения позволяют сопоставлять запросы SDK на стороне Bitrix24 и в вашей инфраструктуре (логи, трейсы, дашборды). | Параметр | Источник | Примечания | | --- | --- | --- | | `bx24_request_id` | `requestId`, который вы передаёте в `actions.v{2,3}.*.make({ requestId })`, или UUID v7, сгенерированный [`RequestIdGenerator`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-request-id-generator.md), если опущен. | Отправляется как query-параметр и как заголовок `X-Request-ID`. Все три телеметрических параметра **пропускаются для legacy-позиционных методов `task.*`** (`task.commentitem.*`, `task.checklistitem.*`, …) в **обоих** REST API v2 и v3 — эти методы читают query-строку позиционно, поэтому Bitrix24 отклоняет вызов (`WRONG_ARGUMENTS`), если параметры присутствуют. Современный `tasks.task.*` этим ограничением не затронут. | | `bx24_sdk_ver` | Константа времени сборки, заменяемая `unbuild`. Равна версии из `package.json` пакета. | Позволяет Bitrix24 различать проблемы по версии SDK. | | `bx24_sdk_type` | Константа времени сборки. Сейчас `b24-js-sdk`. | Отличает `b24jssdk` от других SDK (PHP, Python). | ## Имя заголовка То же значение `bx24_request_id` также помещается в заголовок `X-Request-ID` (`DEFAULT_REQUEST_ID_HEADER_FIELD_NAME` в [`RequestIdGenerator`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-request-id-generator.md)). Если ваш edge-слой логирует `X-Request-ID`, вы увидите один и тот же id в своих логах и в логах сервера Bitrix24. ## Кастомизация генератора Если нужно унаследовать вышестоящий id трассировки (например, пробросить `X-Request-ID` из вашего шлюза), реализуйте [`IRequestIdGenerator`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/core-request-id-generator.md) и внедрите его через кастомную настройку HTTP. Каждый вызов должен возвращать уникальное значение — лимитер и журнал запросов используют его как ключ. ## Всегда передавайте `requestId` Хотя SDK генерирует его за вас, **всегда задавайте `requestId` явно** в production-коде: ```ts await $b24.actions.v2.call.make({ method: 'crm.contact.get', params: { id: 123 }, requestId: `contact-${123}-${Date.now()}` }) ``` Причины: - Id появляется в выводе логгера SDK, упрощая корреляцию. - Id используется `RestrictionManager` для учёта повторных запросов / backoff. - Осмысленный id гораздо легче найти grep'ом в тикетах поддержки Bitrix24, чем UUID. --- # Коды ошибок > Каталог кодов ошибок, которые распознаёт SDK — разделённых на «hard» (выбрасываются) и «soft» (возвращаются как AjaxError внутри AjaxResult). SDK делит серверные коды ошибок на две корзины: - **Hard** — SDK выбрасывает `AjaxError` (или подкласс) **без** повтора. Вызывающий код обрабатывает rejection. - **Soft** — SDK упаковывает ошибку в возвращаемый `AjaxResult` как `AjaxError` и оставляет решение за вами. `response.isSuccess === false`. Всё остальное (сетевые ошибки, 5xx, коды rate limit) подчиняется стратегии повторов, описанной в [Лимитеры](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md). ## Hard-ошибки (выбрасываются) Эти коды распространяются через rejection промиса. Оборачивайте вызовы в `try / catch`, если нужно обрабатывать их централизованно. | Код | Значение | | --- | --- | | `ERR_BAD_REQUEST` | Некорректный запрос — обычно нужно исправить вызывающий код. | | `JSSDK_UNKNOWN_ERROR` | Внутренняя ошибка SDK неизвестной формы. | | `100` | Общий legacy-код 100. | | `INTERNAL_SERVER_ERROR` | Серверная 500. | | `ERROR_UNEXPECTED_ANSWER` | Bitrix24 вернул тело, которое SDK не смог разобрать. | | `PORTAL_DELETED` | Портал больше не существует. | | `ERROR_BATCH_METHOD_NOT_ALLOWED` | Батч содержит метод, недопустимый внутри батча. | | `ERROR_BATCH_LENGTH_EXCEEDED` | В батче более 50 команд. Используйте `batchByChunk`. | | `NO_AUTH_FOUND` | Отсутствуют учётные данные. | | `INVALID_REQUEST` | Bitrix24 отклонил форму запроса. | | `OVERLOAD_LIMIT` | Достигнут лимит перегрузки тарифа (отличается от rate limit). | | `expired_token` | OAuth access token истёк, а обновление не удалось. | | `ACCESS_DENIED` | Доступ запрещён для пользователя. | | `INVALID_CREDENTIALS` | Неверный секрет вебхука / учётные данные OAuth. | | `user_access_error` | Пользователь не может получить доступ к ресурсу. | | `insufficient_scope` | Scope OAuth-токена слишком узок для вызова. | | `ERROR_MANIFEST_IS_NOT_AVAILABLE` | Не удалось получить манифест приложения. | | `allowed_only_intranet_user` | Endpoint требует интранет-пользователя. | | `NOT_FOUND` | Ресурс не существует. | | `INVALID_ARG_VALUE` | Один из аргументов имеет значение, которое Bitrix24 отклонил. | | `PULL_DISABLED` | `PullClient.start()` — сервер Push & Pull отключён на портале. | | `PULL_DISPOSED` | `PullClient.start()` вызван после `destroy()` — создайте новый экземпляр. | ## Soft-ошибки (возвращаются в `AjaxResult`) Эти коды не выбрасываются — они появляются в `result.getErrors()` (и `getErrorMessages()`). Сначала проверяйте `isSuccess`. | Код | Значение | | --- | --- | | `ERROR_ENTITY_NOT_FOUND` | REST v2: строка сущности не существует. | | `BITRIX_REST_V3_EXCEPTION_ACCESSDENIEDEXCEPTION` | REST v3: доступ запрещён. | | `BITRIX_REST_V3_EXCEPTION_INVALIDJSONEXCEPTION` | REST v3: payload не является валидным JSON. | | `BITRIX_REST_V3_EXCEPTION_INVALIDFILTEREXCEPTION` | REST v3: некорректный фильтр. | | `BITRIX_REST_V3_EXCEPTION_INVALIDSELECTEXCEPTION` | REST v3: некорректный `select`. | | `BITRIX_REST_V3_EXCEPTION_ENTITYNOTFOUNDEXCEPTION` | REST v3: сущность не существует. | | `BITRIX_REST_V3_EXCEPTION_METHODNOTFOUNDEXCEPTION` | REST v3: метод не существует. | | `BITRIX_REST_V3_EXCEPTION_UNKNOWNDTOPROPERTYEXCEPTION` | REST v3: неизвестное свойство DTO. | | `BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION` | REST v3: валидация уровня запроса не прошла. `error.validation[]` несёт детали уровня полей. | | `BITRIX_REST_V3_EXCEPTION_VALIDATION_DTOVALIDATIONEXCEPTION` | REST v3: валидация уровня DTO не прошла. | ## Коды, запускающие повтор Их нет в каталоге выше — они определяются [`RestrictionManager`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/limiters.md) и запускают автоматические повторы с backoff: - HTTP 503 / `QUERY_LIMIT_EXCEEDED` — rate limit. - HTTP 429 / `OPERATION_TIME_LIMIT` — operating limit. - Любой другой временный код → экспоненциальный backoff с jitter. После `maxRetries` (по умолчанию `3`) SDK сдаётся и выдаёт исходную ошибку с её реальным кодом (например, `QUERY_LIMIT_EXCEEDED`) — выбрасывает для hard-кодов или возвращает в `AjaxResult` для soft-кодов. > \[!CAUTION] > > Сейчас `NETWORK_ERROR` и `REQUEST_TIMEOUT` **не** входят в hard-список, а значит неидемпотентные вызовы (например, `crm.documentgenerator.document.add`) могут быть повторены после серверного таймаута и создать дубликаты. Если столкнётесь с этим, рассмотрите оборачивание вызова в ручной ключ идемпотентности на вашей стороне. ## Работа с `AjaxError` Обе корзины проявляются как [`AjaxError`](https://github.com/bitrix24/b24jssdk/blob/main/packages/jssdk/src/core/http/ajax-error.ts){rel=""nofollow""} (подкласс `SdkError`). Полезные свойства: ```ts-type class AjaxError extends SdkError { readonly code: string readonly message: string readonly status: number readonly requestInfo?: { method?: string, params?: TypeCallParams, requestId?: string, url?: string } } ``` Паттерн для единообразной обработки: ```ts import { AjaxError } from '@bitrix24/b24jssdk' async function callWithUnifiedErrorHandling(method: string, params: Record, requestId: string) { try { const response = await $b24.actions.v3.call.make({ method, params, requestId }) if (!response.isSuccess) { for (const error of response.getErrors()) { if (error instanceof AjaxError) { // Soft-ошибка console.warn(error.code, error.requestInfo?.method) } } return null } return response.getData() } catch (error) { if (error instanceof AjaxError) { // Hard-ошибка console.error('SDK threw', error.code, error.status) } throw error } } ``` --- # HealthCheck.make() > Метод для проверки доступности REST API Bitrix24. Выполняет простой запрос к REST API для проверки работоспособности сервиса. ## Обзор Используйте `HealthCheck.make()` для проверки доступности REST API Bitrix24. Метод возвращает `Promise` с булевым значением, указывающим на доступность API. ```ts // Базовое использование const isHealthy = await $b24.tools.healthCheck.make() if (isHealthy) { console.log('Bitrix24 API is available') } else { console.error('Problems accessing Bitrix24 API') } ``` ## Сигнатура метода ```ts-type make( options?: { requestId?: string } ): Promise ``` ### Параметры | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise` — promise, который разрешается булевым значением: - **`true`** — REST API доступен и отвечает, вебхук настроен корректно. - **`false`** — REST API недоступен, произошла ошибка или отсутствуют необходимые права доступа. ## Обработка ошибок `HealthCheck.make()` никогда не выбрасывает исключений. Сетевые сбои, HTTP-ошибки, отсутствующие scope и таймауты — всё сводится к возврату `false`. Метод намеренно сделан «чёрным ящиком» — для информации об ошибке, с которой можно работать, вызывайте нижележащий метод напрямую через [`CallV2.make()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md) и проверяйте `AjaxResult` (`isSuccess`, `getErrorMessages()`). ## Примеры ### Проверка доступности ```ts [tools-health-check.ts] import { B24Hook, LoggerFactory } from '@bitrix24/b24jssdk' const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:healthCheck', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function checkRestApiHealth(): Promise { try { return await $b24.tools.healthCheck.make({ requestId: `unique-request-id` }) } catch (error) { $logger.error('Health check failed unexpectedly', { error }) return false } } // Usage try { const apiAvailable = await checkRestApiHealth() if (apiAvailable) { $logger.info('Bitrix24 API is available and responding') } else { $logger.error('Bitrix24 API is unavailable. Check:\n1. Correctness of webhook URL\n2. Bitrix24 availability from your network') } } catch (error) { $logger.error('Failed to perform health check', { error }) } ``` ## Альтернативы и рекомендации - **Для измерения скорости ответа**: используйте [`Ping`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-ping.md). - **Для проверки конкретных прав**: выполните тестовый запрос к нужному методу API. - **На клиентской стороне (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). --- # Ping.make() > Метод для измерения скорости ответа REST API Bitrix24. Выполняет тестовый запрос и возвращает время ответа в миллисекундах. ## Обзор Используйте `Ping.make()` для измерения времени ответа REST API Bitrix24. Метод возвращает `Promise` с числовым значением времени ответа в миллисекундах. ```ts // Базовое использование const responseTime = await $b24.tools.ping.make() if (responseTime >= 0) { console.log(`API response time: ${responseTime}ms`) } else { console.error('Failed to measure API response time') } ``` ## Сигнатура метода ```ts-type make( options?: { requestId?: string } ): Promise ``` ### Параметры | Параметр | Тип | Обязательный | Описание | | --- | --- | --- | --- | | **`requestId`** | `string` | Нет | Уникальный идентификатор запроса для отслеживания. Используется для дедупликации запросов и отладки. | ### Возвращаемое значение `Promise` — promise, который разрешается числовым значением: - **Положительное число** — время ответа в миллисекундах от отправки запроса до получения ответа. - **`-1`** — в случае ошибки или таймаута. ## Обработка ошибок `Ping.make()` никогда не выбрасывает исключений. Сетевые сбои, HTTP-ошибки, неверные учётные данные и таймауты — всё проглатывается внутри и возвращается как `-1`. Со стороны вызова нет способа различить виды сбоев — для этого используйте [`HealthCheck.make()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-health-check.md) или вызывайте нижележащий метод напрямую через [`CallV2.make()`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/call-rest-api-ver2.md) и проверяйте `AjaxResult`. ## Примеры ### Измерение времени ответа ```ts [tools-ping.ts] import { B24Hook, LoggerFactory } from '@bitrix24/b24jssdk' const devMode = typeof import.meta !== 'undefined' && (import.meta?.dev || globalThis._importMeta_.env?.DEV) const $logger = LoggerFactory.createForBrowser('Example:ping', devMode) const $b24 = B24Hook.fromWebhookUrl('https://your_domain.bitrix24.com/rest/1/webhook_code/') async function measureApiResponseTime(): Promise { try { return await $b24.tools.ping.make({ requestId: `unique-request-id` }) } catch (error) { $logger.error('Ping failed unexpectedly', { error }) return -1 } } // Usage try { const responseTime = await measureApiResponseTime() if (responseTime >= 0) { // Response time classification let status = 'optimal' if (responseTime > 1000) status = 'slow' if (responseTime > 3000) status = 'very_slow' if (responseTime > 10000) status = 'critical' $logger.info(`API response time: ${responseTime}ms (${status})`, { responseTime, status, threshold: 'Optimal < 1000ms' }) } else { $logger.error('Failed to measure API response time') } } catch (error) { $logger.error('Error measuring response time', { error }) } ``` ## Альтернативы и рекомендации - **Для проверки доступности**: используйте [`HealthCheck`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/working-with-the-rest-api/tools-health-check.md). - **Для измерения производительности операций**: выполняйте замеры времени для конкретных методов API. - **На клиентской стороне (браузер):** используйте встроенный объект [`B24Frame`](https://bitrix-tools.github.io/b24jssdk/b24jssdk/raw/docs/getting-started/installation/vue.md#init). ---