{"version":3,"file":"BaseApiClient.cjs","names":[],"sources":["../../src/core/BaseApiClient.ts"],"sourcesContent":["import type { ApiClient, HttpMethod } from './ApiClient'\n\nexport interface ValidationError {\n  path: string\n  message: string\n  code: string\n}\n\nexport class ApiError extends Error {\n  public readonly errorClass?: string | undefined\n  public readonly status?: number | undefined\n  public readonly validationErrors: ValidationError[] | null\n\n  constructor(\n    message: string,\n    errorClass?: string,\n    status?: number,\n    validationErrors: ValidationError[] | null = null,\n  ) {\n    super(message)\n    this.name = 'ApiError'\n    this.errorClass = errorClass\n    this.status = status\n    this.validationErrors = validationErrors\n  }\n}\n\nexport class BaseApiClient implements ApiClient {\n  protected readonly baseUrl: string\n  protected accessToken: string | null = null\n\n  constructor(baseUrl: string, accessToken?: string) {\n    this.baseUrl = baseUrl.replace(/\\/$/, '')\n    this.accessToken = accessToken || null\n  }\n\n  setAccessToken(accessToken: string): this {\n    this.accessToken = accessToken\n    return this\n  }\n\n  async request<TResponse = unknown, TBody = unknown>(\n    method: HttpMethod,\n    endpoint: string,\n    body?: TBody,\n    headers?: Record<string, string>,\n  ): Promise<TResponse> {\n    const url = `${this.baseUrl}/${endpoint.replace(/^\\//, '')}`\n\n    const response = await fetch(url, {\n      method,\n      headers: {\n        'Content-Type': 'application/json',\n        ...(this.accessToken && { Authorization: `Bearer ${this.accessToken}` }),\n        ...headers,\n      },\n      ...(body !== undefined && { body: JSON.stringify(body) }),\n    })\n\n    return this.handleResponse<TResponse>(response)\n  }\n\n  protected async handleResponse<TResponse>(response: Response): Promise<TResponse> {\n    if (!response.ok) {\n      const contentType = response.headers.get('Content-Type')\n      const isJson = contentType?.includes('application/json') ?? false\n\n      let errorMessage = `HTTP Error ${response.status}: ${response.statusText}`\n      let errorClass: string | undefined\n      let validationErrors: ValidationError[] | null = null\n\n      if (isJson) {\n        try {\n          const errorText = await response.text()\n          if (errorText) {\n            const errorData = JSON.parse(errorText)\n            errorMessage = errorData.message || errorData.error || errorMessage\n            errorClass = errorData.error\n            validationErrors = errorData.validationErrors ?? null\n          }\n        } catch {\n          // If JSON parsing fails, use the default error message\n        }\n      }\n\n      throw new ApiError(errorMessage, errorClass, response.status, validationErrors)\n    }\n\n    // 204 No Content never has a body; short-circuit before reading the stream.\n    if (response.status === 204) {\n      return undefined as unknown as TResponse\n    }\n\n    // Read body as text once and treat an empty body as \"no content\" regardless of\n    // Content-Type. Servers sometimes return 200 with Content-Type: application/json\n    // and an empty body (e.g. POST endpoints whose framework keeps the default JSON\n    // content-type even when nothing is written). `response.json()` would throw\n    // \"Unexpected end of input\" in that case.\n    const text = await response.text()\n    if (!text) {\n      return undefined as unknown as TResponse\n    }\n\n    const contentType = response.headers.get('Content-Type')\n    const isJson = contentType?.includes('application/json') ?? false\n\n    if (isJson) {\n      return JSON.parse(text) as TResponse\n    }\n\n    try {\n      return JSON.parse(text) as TResponse\n    } catch {\n      return text as unknown as TResponse\n    }\n  }\n\n  get<TResponse = unknown>(endpoint: string, headers?: Record<string, string>): Promise<TResponse> {\n    return this.request<TResponse>('GET', endpoint, undefined, headers)\n  }\n\n  post<TResponse = unknown, TBody = unknown>(\n    endpoint: string,\n    body?: TBody,\n    headers?: Record<string, string>,\n  ): Promise<TResponse> {\n    return this.request<TResponse, TBody>('POST', endpoint, body, headers)\n  }\n\n  put<TResponse = unknown, TBody = unknown>(\n    endpoint: string,\n    body?: TBody,\n    headers?: Record<string, string>,\n  ): Promise<TResponse> {\n    return this.request<TResponse, TBody>('PUT', endpoint, body, headers)\n  }\n\n  patch<TResponse = unknown, TBody = unknown>(\n    endpoint: string,\n    body?: TBody,\n    headers?: Record<string, string>,\n  ): Promise<TResponse> {\n    return this.request<TResponse, TBody>('PATCH', endpoint, body, headers)\n  }\n\n  delete<TResponse = unknown>(\n    endpoint: string,\n    headers?: Record<string, string>,\n  ): Promise<TResponse> {\n    return this.request<TResponse>('DELETE', endpoint, undefined, headers)\n  }\n}\n"],"mappings":";;;AAQA,IAAa,WAAb,cAA8B,MAAM;CAClC,AAAgB;CAChB,AAAgB;CAChB,AAAgB;CAEhB,YACE,SACA,YACA,QACA,mBAA6C,MAC7C;AACA,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,aAAa;AAClB,OAAK,SAAS;AACd,OAAK,mBAAmB;;;AAI5B,IAAa,gBAAb,MAAgD;CAC9C,AAAmB;CACnB,AAAU,cAA6B;CAEvC,YAAY,SAAiB,aAAsB;AACjD,OAAK,UAAU,QAAQ,QAAQ,OAAO,GAAG;AACzC,OAAK,cAAc,eAAe;;CAGpC,eAAe,aAA2B;AACxC,OAAK,cAAc;AACnB,SAAO;;CAGT,MAAM,QACJ,QACA,UACA,MACA,SACoB;EACpB,MAAM,MAAM,GAAG,KAAK,QAAQ,GAAG,SAAS,QAAQ,OAAO,GAAG;EAE1D,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC;GACA,SAAS;IACP,gBAAgB;IAChB,GAAI,KAAK,eAAe,EAAE,eAAe,UAAU,KAAK,eAAe;IACvE,GAAG;IACJ;GACD,GAAI,SAAS,UAAa,EAAE,MAAM,KAAK,UAAU,KAAK,EAAE;GACzD,CAAC;AAEF,SAAO,KAAK,eAA0B,SAAS;;CAGjD,MAAgB,eAA0B,UAAwC;AAChF,MAAI,CAAC,SAAS,IAAI;GAEhB,MAAM,SADc,SAAS,QAAQ,IAAI,eAAe,EAC5B,SAAS,mBAAmB,IAAI;GAE5D,IAAI,eAAe,cAAc,SAAS,OAAO,IAAI,SAAS;GAC9D,IAAI;GACJ,IAAI,mBAA6C;AAEjD,OAAI,OACF,KAAI;IACF,MAAM,YAAY,MAAM,SAAS,MAAM;AACvC,QAAI,WAAW;KACb,MAAM,YAAY,KAAK,MAAM,UAAU;AACvC,oBAAe,UAAU,WAAW,UAAU,SAAS;AACvD,kBAAa,UAAU;AACvB,wBAAmB,UAAU,oBAAoB;;WAE7C;AAKV,SAAM,IAAI,SAAS,cAAc,YAAY,SAAS,QAAQ,iBAAiB;;AAIjF,MAAI,SAAS,WAAW,IACtB;EAQF,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,MAAI,CAAC,KACH;AAMF,MAHoB,SAAS,QAAQ,IAAI,eAAe,EAC5B,SAAS,mBAAmB,IAAI,MAG1D,QAAO,KAAK,MAAM,KAAK;AAGzB,MAAI;AACF,UAAO,KAAK,MAAM,KAAK;UACjB;AACN,UAAO;;;CAIX,IAAyB,UAAkB,SAAsD;AAC/F,SAAO,KAAK,QAAmB,OAAO,UAAU,QAAW,QAAQ;;CAGrE,KACE,UACA,MACA,SACoB;AACpB,SAAO,KAAK,QAA0B,QAAQ,UAAU,MAAM,QAAQ;;CAGxE,IACE,UACA,MACA,SACoB;AACpB,SAAO,KAAK,QAA0B,OAAO,UAAU,MAAM,QAAQ;;CAGvE,MACE,UACA,MACA,SACoB;AACpB,SAAO,KAAK,QAA0B,SAAS,UAAU,MAAM,QAAQ;;CAGzE,OACE,UACA,SACoB;AACpB,SAAO,KAAK,QAAmB,UAAU,UAAU,QAAW,QAAQ"}