{"version":3,"file":"parse-error-payload.cjs","sources":["../../../../src/core/http/parse-error-payload.ts"],"sourcesContent":["import type { TypeDescriptionError, TypeDescriptionErrorV3 } from '../../types/auth'\n\n/**\n * One entry of the `restApi:v3` `validation` array, as the SDK exposes it.\n *\n * `field` and `message` are both optional because the portal's own type says so\n * — `TypeDescriptionErrorV3` declares them optional and permits extra keys. A\n * caller matching on `field` has to handle it being absent; that is the portal's\n * shape, not a hedge.\n */\nexport type ValidationDetail = {\n  readonly field?: string\n  readonly message?: string\n  readonly [key: string]: unknown\n}\n\n/** What a REST error body yields, whichever protocol version produced it. */\nexport type ParsedErrorPayload = {\n  readonly code: string\n  readonly description: string\n  /**\n   * The `restApi:v3` `validation` array, verbatim and **unredacted** — this is\n   * the raw read. `AjaxError` runs each entry through `redactSensitiveParams`\n   * when it stores them, which is the copy a caller sees.\n   *\n   * Absent for `restApi:v2`, which has no equivalent, and absent when v3 did not\n   * send one.\n   */\n  readonly validation?: readonly ValidationDetail[]\n}\n\n/**\n * Separates the messages folded into {@link ParsedErrorPayload.description}.\n *\n * Two validation rows used to be concatenated with nothing between them —\n * `Field A must not be empty.Field B is invalid.` — with no way to tell where\n * one ended (#423).\n */\nconst MESSAGE_SEPARATOR = ' '\n\n/**\n * Reads a Bitrix24 REST error body into the parts the SDK reports.\n *\n * This existed twice — in `AjaxResult.#processErrors()` and in\n * `AbstractHttp._convertAxiosErrorToAjaxError()` — each carrying a\n * `@todo make single function` pointing at the other. Which copy ran depended on\n * whether the error code was soft or hard, something a caller does not control,\n * so the two had to agree and nothing made them. They did not: neither read\n * `validation[].field`, and a fix applied to one would have left the other\n * lossy (#423).\n *\n * Returns `undefined` when the body carries no error the SDK recognises, so a\n * caller can tell \"no error here\" from \"an error with an empty description\".\n *\n * @param body the parsed response body — `unknown` because it arrives from\n *   `axios` on one path and from a stored response on the other, and neither is\n *   trustworthy enough to assert a type on.\n * @param fallbackCode used when the body names no code, e.g. an axios error\n *   whose own code is the only one available.\n * @param fallbackDescription likewise for the message.\n */\nexport function parseErrorPayload(\n  body: unknown,\n  fallbackCode: string,\n  fallbackDescription: string\n): ParsedErrorPayload | undefined {\n  if (!body || typeof body !== 'object' || !('error' in body)) {\n    return undefined\n  }\n\n  const responseData = body as TypeDescriptionError | TypeDescriptionErrorV3\n\n  // restApi:v3 — `error` is an object carrying `code`, and optionally the\n  // `validation` array this function exists to stop losing.\n  if (\n    responseData.error\n    && typeof responseData.error === 'object'\n    && 'code' in responseData.error\n  ) {\n    const error = responseData.error\n    let description = String(error.message ?? '').trimEnd()\n\n    if (error.validation && error.validation.length > 0) {\n      const messages = error.validation\n        // `||`, not `??`: a row whose `message` is present but empty says\n        // nothing, so it falls back to the row itself rather than contributing\n        // an empty fragment and a stray separator.\n        .map(row => row?.message || JSON.stringify(row))\n        .filter(message => message !== undefined && message !== '')\n\n      if (messages.length > 0) {\n        if (description.length > 0) {\n          if (!description.endsWith('.')) {\n            description += '.'\n          }\n          description += MESSAGE_SEPARATOR\n        }\n        description += messages.join(MESSAGE_SEPARATOR)\n      }\n    }\n\n    return {\n      code: error.code,\n      description,\n      // Kept verbatim rather than reshaped: `field` is what the caller came for,\n      // and the portal is free to add keys the SDK has not seen. The copy is\n      // what detaches it from the response body; the freeze stops a caller\n      // reordering or extending the array. Both are **shallow** — the `readonly`\n      // on each entry's fields is a type-level claim only, and nothing stops a\n      // caller writing to `validation[0].field` at runtime.\n      ...(error.validation ? { validation: Object.freeze([...error.validation]) } : {})\n    }\n  }\n\n  // restApi:v2 — `error` is the code itself, with the text alongside it.\n  if (responseData.error && typeof responseData.error === 'string') {\n    return {\n      code: responseData.error !== '0' ? responseData.error : fallbackCode,\n      description: (responseData as TypeDescriptionError)?.error_description ?? fallbackDescription\n    }\n  }\n\n  return undefined\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAsCA,MAAM,iBAAA,GAAoB,GAAA;AAuBnB,SAAS,iBAAA,CACd,IAAA,EACA,YAAA,EACA,mBAAA,EACgC;AAChC,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,SAAS,QAAA,IAAY,EAAE,WAAW,IAAA,CAAA,EAAO;AAC3D,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,IAAA;AAIrB,EAAA,IACE,YAAA,CAAa,SACV,OAAO,YAAA,CAAa,UAAU,QAAA,IAC9B,MAAA,IAAU,aAAa,KAAA,EAC1B;AACA,IAAA,MAAM,QAAQ,YAAA,CAAa,KAAA;AAC3B,IAAA,IAAI,cAAc,MAAA,CAAO,KAAA,CAAM,OAAA,IAAW,EAAE,EAAE,OAAA,EAAQ;AAEtD,IAAA,IAAI,KAAA,CAAM,UAAA,IAAc,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA,EAAG;AACnD,MAAA,MAAM,WAAW,KAAA,CAAM,UAAA,CAIpB,GAAA,CAAI,CAAA,GAAA,KAAO,KAAK,OAAA,IAAW,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA,CAC9C,MAAA,CAAO,aAAW,OAAA,KAAY,MAAA,IAAa,YAAY,EAAE,CAAA;AAE5D,MAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,QAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,UAAA,IAAI,CAAC,WAAA,CAAY,QAAA,CAAS,GAAG,CAAA,EAAG;AAC9B,YAAA,WAAA,IAAe,GAAA;AAAA,UACjB;AACA,UAAA,WAAA,IAAe,iBAAA;AAAA,QACjB;AACA,QAAA,WAAA,IAAe,QAAA,CAAS,KAAK,iBAAiB,CAAA;AAAA,MAChD;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,WAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,GAAI,KAAA,CAAM,UAAA,GAAa,EAAE,YAAY,MAAA,CAAO,MAAA,CAAO,CAAC,GAAG,KAAA,CAAM,UAAU,CAAC,CAAA,KAAM;AAAC,KACjF;AAAA,EACF;AAGA,EAAA,IAAI,YAAA,CAAa,KAAA,IAAS,OAAO,YAAA,CAAa,UAAU,QAAA,EAAU;AAChE,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,YAAA,CAAa,KAAA,KAAU,GAAA,GAAM,aAAa,KAAA,GAAQ,YAAA;AAAA,MACxD,WAAA,EAAc,cAAuC,iBAAA,IAAqB;AAAA,KAC5E;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AA9DgB,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;;;;"}