UNPKG

@bitrix24/b24jssdk

Version:

Bitrix24 REST API JavaScript SDK

236 lines (232 loc) 8.48 kB
/** * @package @bitrix24/b24jssdk * @version 2.2.0 * @copyright (c) 2026 Bitrix24 * @license MIT * @see https://github.com/bitrix24/b24jssdk * @see https://bitrix24.github.io/b24jssdk/ */ 'use strict'; const parseErrorPayload = require('./parse-error-payload.cjs'); const type = require('../../tools/type.cjs'); const text = require('../../tools/text.cjs'); const result = require('../result.cjs'); const ajaxError = require('./ajax-error.cjs'); const b24 = require('../../types/b24.cjs'); const sdkError = require('../sdk-error.cjs'); var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); class AjaxResult extends result.Result { static { __name(this, "AjaxResult"); } _status; _query; _data; constructor(options) { super(); this._data = options.answer ? Object.freeze(options.answer) : void 0; this._query = Object.freeze(structuredClone(options.query)); this._status = options.status; if (options.error) { this.addError(options.error, "base-error"); } else { this.#processErrors(); } } get isSuccess() { return this.#getIsSuccess(); } /** * @todo test this predicate */ #getIsSuccess() { return this._errors.size === 0; } getData() { if (!this.isSuccess) { return void 0; } const payload = this._data; return Object.freeze({ result: payload.result, time: payload.time }); } /** * If the response contains error data, we'll restore it to an error. * * The parsing lives in {@link parseErrorPayload}, shared with * `AbstractHttp._convertAxiosErrorToAjaxError()`. It used to be written out * here as well, and the two copies had drifted into agreeing on everything * except that neither read `validation[].field` (#423). */ #processErrors() { const parsed = parseErrorPayload.parseErrorPayload(this._data, "JSSDK_RESPONSE_ERROR", "Some error in response"); if (parsed === void 0) { return; } this.addError(this.#createAjaxError({ code: parsed.code, description: parsed.description, status: this._status, validation: parsed.validation }), "base-error"); } #createAjaxError(errorData) { return new ajaxError.AjaxError({ code: errorData.code, description: errorData.description, status: errorData.status, validation: errorData.validation, requestInfo: { method: this._query.method, params: this._query.params, requestId: this._query.requestId } }); } /** * Alias for {@link AjaxResult.isMore}. * * `restApi:v2` only — see {@link AjaxResult.isMore} for what this returns on * a `restApi:v3` response. */ hasMore() { return this.isMore(); } /** * Whether the `restApi:v2` envelope carries a `next` offset — i.e. the portal * has more rows for this query. * * **`restApi:v2` only.** `restApi:v3` returns no `next` field, so this returns * `false` on a v3 response — which is not the same statement as "there are no * more rows". Do not branch on it for v3; there is nothing to read. * * This is a reader for a protocol field, not a deprecated API: it stays for as * long as `restApi:v2` does, and so does its counterpart * {@link AjaxResult.getNext} — the two together are the manual `restApi:v2` * paging loop, and neither is going away. For new code prefer the list * helpers, which hide the offset bookkeeping and work under both protocol * versions: * - `restApi:v2`: `b24.actions.v2.callList.make` or `b24.actions.v2.fetchList.make` * - `restApi:v3`: `b24.actions.v3.callList.make` or `b24.actions.v3.fetchList.make` */ isMore() { if (!this.isSuccess) { return false; } const payload = this._data; const nextValue = "next" in payload ? payload.next : void 0; return type.Type.isNumber(nextValue); } /** * The row count the `restApi:v2` envelope reports in its `total` field. * * **`restApi:v2` only.** `restApi:v3` returns no `total`, so this returns `0` * on a v3 response — which is not the same statement as "no rows matched". * Do not read it for v3; use * `b24.actions.v3.aggregate.make` with `count` / `countDistinct` instead, * bearing in mind that action is `@experimental` and unverified against a live * portal. * * This is a reader for a protocol field, not a deprecated API. It is the only * way to obtain a count under `restApi:v2` — the list helpers iterate without * exposing `total`, {@link SuccessPayload} deliberately omits it, and the * `aggregate` action exists for `restApi:v3` only. It therefore stays for as * long as `restApi:v2` does, and is not part of the `3.0.0` removal set. * * That is a decision with a trigger, not an open-ended promise. Revisit it * when either holds: `b24.actions.v3.aggregate` is verified against a live * portal and loses its `@experimental` tag across the common modules (a v3 * count then exists, and `getTotal()` has a replacement for the first time), * or Bitrix24 announces a `restApi:v2` sunset date (the field it reads goes * away regardless). Until one of those happens there is nothing to migrate * callers to, which is the whole reason it is still here. * * Note this trigger is specific to the readers. {@link AjaxResult.getNext} and * {@link AjaxResult.fetchNext} already have a working replacement, so nothing * about `aggregate` maturing changes anything for them — a `restApi:v2` sunset * is their only exit condition. */ getTotal() { if (!this.isSuccess) { return 0; } const payload = this._data; const totalValue = "total" in payload ? payload.total : void 0; return text.Text.toInteger(totalValue); } getStatus() { return this._status; } getQuery() { return this._query; } /** * Alias for {@link AjaxResult.getNext}, returning `null` where that returns * `false`. * * **`restApi:v2` only** — see {@link AjaxResult.getNext}, including the throw * on a `restApi:v3` client, which this inherits. */ async fetchNext(http) { const data = await this.getNext(http); if (data === false) { return null; } return data; } /** * Re-runs this result's own query with `params.start` set to the `next` offset * the `restApi:v2` envelope reported, and resolves to the following page. * Returns `false` when this result is unsuccessful or has no `next`. * * `restApi:v2` only, and permanently so. Unlike the readers above, this one * acts on the envelope, and `restApi:v3` has no `next` to act on — so it * throws rather than silently returning `false`, which would be * indistinguishable from "last page". That throw is not a transitional * measure; it is the honest answer for a protocol that does not have this * operation. * * For new code prefer `b24.actions.v{2,3}.callList.make` (collect everything) * or `b24.actions.v{2,3}.fetchList.make` (async generator, one page per * iteration — the same page-by-page control this gives, without the manual * offset bookkeeping, and it works under both protocol versions). This method * is kept because it works under `restApi:v2` and deleting it would break * running code for no gain, not because it is the better tool. * * @throws {SdkError} `JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3` when called against a `restApi:v3` HTTP client. */ async getNext(http) { if (http.apiVersion === b24.ApiVersion.v3) { throw new sdkError.SdkError({ code: "JSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3", description: `restApi:v3 not support method getNext`, status: 500 }); } if (!this.isSuccess || !this.isMore()) { return false; } const nextPageQuery = this.#buildNextPageQuery(); return http.call( nextPageQuery.method, nextPageQuery.params ); } #buildNextPageQuery() { const payload = this._data; const nextValue = "next" in payload ? payload.next : void 0; return { ...this._query, params: { ...this._query.params, start: text.Text.toInteger(nextValue) } }; } // Immutable API setData() { throw new ReferenceError("AjaxResult does not allow data modification"); } } exports.AjaxResult = AjaxResult; //# sourceMappingURL=ajax-result.cjs.map