{"version":3,"file":"aseansc-admin-sea-http.mjs","sources":["../../../../libs/sea-http/src/lib/config/asc-http.config.ts","../../../../libs/sea-http/src/lib/config/asc-http.provider.ts","../../../../libs/sea-http/src/lib/types/api.types.ts","../../../../libs/sea-http/src/lib/interceptors/loading.token.ts","../../../../libs/sea-http/src/lib/services/asc-api.service.ts","../../../../libs/sea-http/src/lib/services/asc-loading.service.ts","../../../../libs/sea-http/src/lib/services/asc-auth-storage.service.ts","../../../../libs/sea-http/src/lib/services/asc-local-storage-auth.service.ts","../../../../libs/sea-http/src/lib/services/asc-cookie-auth.service.ts","../../../../libs/sea-http/src/lib/services/asc-session-storage-auth.service.ts","../../../../libs/sea-http/src/lib/services/asc-sse.service.ts","../../../../libs/sea-http/src/lib/services/asc-websocket.service.ts","../../../../libs/sea-http/src/lib/interceptors/asc-auth.interceptor.ts","../../../../libs/sea-http/src/lib/interceptors/asc-error.interceptor.ts","../../../../libs/sea-http/src/lib/interceptors/asc-loading.interceptor.ts","../../../../libs/sea-http/src/index.ts","../../../../libs/sea-http/src/aseansc-admin-sea-http.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { AscApiError } from '../types/api.types';\n\nexport interface AscHttpConfig {\n  /** Base URL mặc định, vd: https://api.aseansc.com.vn/api */\n  baseUrl: string;\n  /**\n   * Named endpoints — dùng khi app có nhiều URL khác nhau.\n   * Truyền key vào tham số `endpoint` của post()/login().\n   * @example\n   *   endpoints: { auth: 'https://auth.aseansc.com.vn/api' }\n   *   this.api.post({ authenType: 'doSomething', data, endpoint: 'auth' })\n   */\n  endpoints?: Record<string, string>;\n  /** API key cố định gắn vào mọi request */\n  apiKey: string;\n  /** Tên service, vd: 'sea-meetings' */\n  api: string;\n  /** Mặc định: 'ASEANSC' */\n  channel?: string;\n  /** Mặc định: 'ASEANSC' */\n  subChannel?: string;\n  /** Mặc định: 'WEB' */\n  context?: string;\n  /** Mặc định: '1' */\n  priority?: string;\n}\n\n/** Config token — provide qua provideAscHttp() */\nexport const ASC_HTTP_CONFIG = new InjectionToken<AscHttpConfig>('ASC_HTTP_CONFIG');\n\n/**\n * Hàm trả về userID của user đang đăng nhập.\n * App cần provide:\n *   { provide: ASC_HTTP_USER_ID_FN, useFactory: (auth: AuthService) => () => auth.userId(), deps: [AuthService] }\n */\nexport const ASC_HTTP_USER_ID_FN = new InjectionToken<() => string>(\n  'ASC_HTTP_USER_ID_FN',\n  { factory: () => () => '' },\n);\n\n/**\n * Error handler tập trung cho cả HTTP error lẫn AscApiError.\n * App có thể provide để tích hợp toast, logging, v.v.\n *\n * @example\n * {\n *   provide: ASC_HTTP_ERROR_HANDLER,\n *   useFactory: (toast: AscToastService) =>\n *     (err) => toast.error(err instanceof AscApiError ? err.message : 'Lỗi kết nối server'),\n *   deps: [AscToastService],\n * }\n */\nexport const ASC_HTTP_ERROR_HANDLER = new InjectionToken<\n  (error: HttpErrorResponse | AscApiError) => void\n>(\n  'ASC_HTTP_ERROR_HANDLER',\n  { factory: () => (err) => console.error('[AscHttp]', err) },\n);\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { ASC_HTTP_CONFIG, AscHttpConfig } from './asc-http.config';\n\n/**\n * provideAscHttp — đăng ký config cho AscApiService và AscLoadingService.\n *\n * Đặt trong providers của app.config.ts.\n * Các interceptor cần thêm thủ công vào withInterceptors() để\n * tránh xung đột khi app đã có provideHttpClient() riêng.\n *\n * @example\n * // app.config.ts\n * import { provideHttpClient, withInterceptors } from '@angular/common/http';\n * import {\n *   provideAscHttp,\n *   ascAuthInterceptor,\n *   ascErrorInterceptor,\n *   ascLoadingInterceptor,\n * } from '@aseansc-admin/http';\n *\n * export const appConfig: ApplicationConfig = {\n *   providers: [\n *     provideHttpClient(\n *       withInterceptors([ascAuthInterceptor, ascErrorInterceptor, ascLoadingInterceptor]),\n *     ),\n *     provideAscHttp({\n *       baseUrl:  'https://api.aseansc.com.vn/api',\n *       apiKey:   'qmklfoni1ezxlf2ckpygpfx248',\n *       api:      'sea-meetings',\n *     }),\n *\n *     // Tuỳ chọn: cấu hình userID từ auth service\n *     {\n *       provide:    ASC_HTTP_USER_ID_FN,\n *       useFactory: (auth: AuthService) => () => auth.currentUser()?.userId ?? '',\n *       deps:       [AuthService],\n *     },\n *\n *     // Tuỳ chọn: hiển thị toast khi có lỗi\n *     {\n *       provide:    ASC_HTTP_ERROR_HANDLER,\n *       useFactory: (toast: AscToastService) =>\n *         (err) => toast.error(err instanceof AscApiError ? err.message : 'Lỗi kết nối server'),\n *       deps:       [AscToastService],\n *     },\n *   ],\n * };\n */\nexport function provideAscHttp(config: AscHttpConfig): EnvironmentProviders {\n  return makeEnvironmentProviders([\n    { provide: ASC_HTTP_CONFIG, useValue: config },\n  ]);\n}\n","// ─── Request ──────────────────────────────────────────────────────────────────\n\nexport interface AscApiRequestHeader {\n  reqType:    'REQUEST';\n  api:        string;\n  apiKey:     string;\n  priority:   string;\n  channel:    string;\n  subChannel: string;\n  context:    string;\n  userID:     string;\n  synasyn:    string;\n}\n\nexport interface AscApiRequest<T = unknown> {\n  header: AscApiRequestHeader;\n  body: {\n    authenType: string;\n    data:       T;\n  };\n}\n\n// ─── Response ─────────────────────────────────────────────────────────────────\n\nexport interface AscApiResponseHeader {\n  reqType:    'RESPONSE';\n  api:        string;\n  apiKey:     string;\n  channel:    string;\n  subChannel: string;\n  location:   string;\n  context:    string;\n  duration:   number;\n  priority:   number;\n  userID:     string;\n  synasyn:    string;\n}\n\n/**\n * Một số BE (vd bos-api) không nhét message lỗi vào `body.data` mà trả riêng\n * ở field `error` ngang hàng với `body`/`header` — `body.data` lúc đó thường\n * không tồn tại. Field bên trong không cố định (tuỳ BE: `desc`, `messageVn`...)\n * nên chỉ khai unknown, để `AscApiError` tự dò field message quen thuộc.\n */\nexport interface AscApiResponseError {\n  code?: string;\n  [key: string]: unknown;\n}\n\nexport interface AscApiResponse<T = unknown> {\n  header: AscApiResponseHeader;\n  body: {\n    status: string;\n    data?:  T;\n  };\n  /** Chỉ có khi status lỗi, tuỳ BE — xem AscApiResponseError */\n  error?: AscApiResponseError;\n}\n\n// ─── Error ────────────────────────────────────────────────────────────────────\n\n/**\n * Các field thường gặp mà BE dùng để chứa message lỗi — trong `body.data` lẫn\n * trong `response.error` (BE dạng bos-api). Ưu tiên field tiếng Việt trước\n * (`messageVn`) vì locale mặc định của app là vi-VN.\n */\nconst AscApiErrorMessageKeys = [\n  'messageVn', 'message', 'msg', 'errorMessage', 'desc', 'description', 'messageEn',\n] as const;\n\nexport class AscApiError extends Error {\n  constructor(\n    public readonly status:     string,\n    public readonly authenType: string,\n    public readonly data:       unknown = null,\n  ) {\n    super(AscApiError._extractMessage(data) ?? `[${authenType}] API responded with status: ${status}`);\n    this.name = 'AscApiError';\n  }\n\n  /**\n   * BE không thống nhất tên field chứa message lỗi trong `data` (tuỳ endpoint:\n   * `message`, `msg`, `errorMessage`...), nên thử lần lượt các field phổ biến.\n   * Không tìm thấy → giữ nguyên message debug cũ (`[authenType] ... status`).\n   */\n  private static _extractMessage(data: unknown): string | null {\n    if (!data || typeof data !== 'object') return null;\n    const record = data as Record<string, unknown>;\n    for (const key of AscApiErrorMessageKeys) {\n      const value = record[key];\n      if (typeof value === 'string' && value.trim() !== '') return value;\n    }\n    return null;\n  }\n}\n\n// ─── Type guard ───────────────────────────────────────────────────────────────\n\nexport function isAscApiRequest(body: unknown): body is AscApiRequest {\n  return (\n    !!body &&\n    typeof body === 'object' &&\n    'header' in body &&\n    'body' in body &&\n    typeof (body as AscApiRequest).header?.api === 'string'\n  );\n}\n\n// ─── Service options ──────────────────────────────────────────────────────────\n\nexport interface AscPostOptions<TBody = unknown> {\n  /** Tên action/operation, vd: 'getAllMeetingAsean' */\n  authenType: string;\n  /** Payload gửi vào body.data */\n  data: TBody;\n  /** Key của named endpoint trong AscHttpConfig.endpoints */\n  endpoint?: string;\n  /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */\n  skipLoading?: boolean;\n}\n\nexport interface AscLoginOptions extends LoginRequestData {\n  /** Key của named endpoint trong AscHttpConfig.endpoints */\n  endpoint?: string;\n}\n\n// ─── Blob (envelope + binary response, vd: download file) ─────────────────\n\nexport interface AscPostBlobOptions<TBody = unknown> {\n  /** Tên action/operation, vd: 'downloadApplication' */\n  authenType: string;\n  /** Payload gửi vào body.data */\n  data: TBody;\n  /** Key của named endpoint trong AscHttpConfig.endpoints */\n  endpoint?: string;\n  /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */\n  skipLoading?: boolean;\n}\n\n// ─── FormData (envelope + file upload) ─────────────────────────────────────\n\nexport interface AscFormDataFile {\n  /** Tên field multipart cho file này, vd: 'avatar', 'attachment' */\n  field: string;\n  /**\n   * `null` → gửi field rỗng ('') xuống BE — theo quy ước BE, field multipart\n   * rỗng nghĩa là xoá file đó khỏi record. Không truyền field này trong `files`\n   * nếu muốn giữ nguyên file cũ (không đụng tới).\n   */\n  file: File | null;\n}\n\nexport interface AscPostFormDataOptions<TBody = unknown> {\n  /** Tên action/operation, vd: 'uploadAvatar' */\n  authenType: string;\n  /**\n   * Payload nghiệp vụ gửi kèm — được đóng gói cùng envelope header thành 1\n   * field multipart tên 'request' (JSON.stringify).\n   */\n  data: TBody;\n  /** File đính kèm — mỗi phần tử tạo 1 field multipart riêng theo `field` */\n  files: AscFormDataFile[];\n  /** Key của named endpoint trong AscHttpConfig.endpoints */\n  endpoint?: string;\n  /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */\n  skipLoading?: boolean;\n}\n\n// ─── REST (non-envelope) ────────────────────────────────────────────────────\n//\n// Dùng cho endpoint BE trả thẳng chuẩn HTTP (không bọc envelope { header, body }).\n// Đi qua cùng interceptor chain (auth token, error handler, loading) như post()/\n// login() — chỉ khác là không build/unwrap envelope.\n\nexport type AscHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\nexport interface AscRestOptions<TBody = unknown> {\n  /** Mặc định: 'GET' */\n  method?: AscHttpMethod;\n  /** Path nối vào baseUrl/endpoint, vd: '/users/123'. Có thể để trống nếu baseUrl/endpoint đã là URL đầy đủ. */\n  path?: string;\n  /** Request body — dùng cho POST/PUT/PATCH/DELETE */\n  body?: TBody;\n  /** Query params — áp dụng cho mọi method */\n  params?: Record<string, string | number | boolean | undefined | null>;\n  /** Header bổ sung — không ghi đè Authorization (do ascAuthInterceptor set) */\n  headers?: Record<string, string>;\n  /** Key của named endpoint trong AscHttpConfig.endpoints */\n  endpoint?: string;\n  /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */\n  skipLoading?: boolean;\n}\n\n// ─── Login ────────────────────────────────────────────────────────────────────\n\nexport interface LoginRequestData {\n  username:   string;\n  password:   string;\n  authenType: 'getLogin';\n  type:       'INHOUSE' | 'EXTERNAL';\n}\n\n/**\n * Shape tối thiểu mà AscAuthStorageService/ascAuthInterceptor cần để lưu và\n * đọc token. Response login thực tế do consuming app tự định nghĩa (extend\n * `AscAuthUser`) và truyền vào qua generic khi gọi `login()`/`getUser()` —\n * sea-http không hardcode các field còn lại (email, permissionList, ...).\n */\nexport interface AscAuthUser {\n  token: string;\n  [key: string]: unknown;\n}\n","import { HttpContextToken } from '@angular/common/http';\n\n/**\n * Set SKIP_LOADING = true trên HttpContext của một request để bỏ qua global loading indicator.\n *\n * @example\n *   this.api.post({ authenType: 'silentRefresh', data: {}, skipLoading: true })\n *\n * Hoặc dùng trực tiếp với HttpClient:\n *   this.http.post(url, body, { context: new HttpContext().set(SKIP_LOADING, true) })\n */\nexport const SKIP_LOADING = new HttpContextToken<boolean>(() => false);\n","import { inject, Injectable } from '@angular/core';\nimport { HttpClient, HttpContext, HttpParams, HttpResponse } from '@angular/common/http';\nimport { map, Observable, catchError, throwError } from 'rxjs';\nimport { SKIP_LOADING } from '../interceptors/loading.token';\nimport { ASC_HTTP_CONFIG, ASC_HTTP_ERROR_HANDLER, ASC_HTTP_USER_ID_FN } from '../config/asc-http.config';\nimport {\n  AscApiRequest,\n  AscApiResponse,\n  AscApiError,\n  AscPostOptions,\n  AscLoginOptions,\n  AscPostFormDataOptions,\n  AscPostBlobOptions,\n  AscRestOptions,\n  AscAuthUser,\n} from '../types/api.types';\n\n/**\n * AscApiService — gọi API qua 4 flow, cùng đi qua 1 interceptor chain (auth,\n * error handler, loading):\n *\n * - post() / login()   — envelope { header, body } — cho BE cũ theo chuẩn envelope.\n *   Tự build header, unwrap body.data, throw AscApiError nếu body.status !== 'OK'.\n * - postFormData()      — envelope + file upload (multipart/form-data). Cùng\n *   unwrap/throw AscApiError như post(), nhưng tự lấy userID trực tiếp thay vì\n *   qua interceptor (FormData không mutate được như JSON body).\n * - postBlob()           — envelope, nhận response dạng binary (Blob) — dùng cho\n *   download file. Tự build envelope giống post(), trả nguyên HttpResponse<Blob>\n *   (không unwrap, không throw AscApiError vì response không phải JSON).\n * - postFormDataBlob()   — kết hợp postFormData() + postBlob(): multipart file\n *   upload (dựng request như postFormData()) nhưng nhận response dạng binary\n *   (Blob) không unwrap/không throw (như postBlob()) — dùng cho endpoint vừa\n *   upload file vừa trả response không đồng nhất kiểu (rỗng/Blob/JSON lỗi).\n * - request()           — chuẩn HTTP thuần (GET/POST/PUT/PATCH/DELETE) — cho BE\n *   trả thẳng REST, không bọc envelope. Lỗi luôn là HttpErrorResponse.\n *\n * userID được inject vào envelope header bởi ascAuthInterceptor cho post()/\n * login()/postBlob() (mutate JSON body); postFormData()/postFormDataBlob() tự\n * lấy trực tiếp qua ASC_HTTP_USER_ID_FN. Bearer token được inject cho cả 5 flow.\n *\n * @example\n *   private api = inject(AscApiService);\n *\n *   // Envelope\n *   getMeetings(pagination: Pagination): Observable<MeetingListData> {\n *     return this.api.post<MeetingListData, MyBody>({\n *       authenType: 'getAllMeetingAsean',\n *       data: { pagination: { pageNumber: 0, pageSize: 25 }, search: '' },\n *     });\n *   }\n *\n *   // Envelope + file upload\n *   uploadAvatar(userId: string, file: File): Observable<UploadResult> {\n *     return this.api.postFormData<UploadResult>({\n *       authenType: 'uploadAvatar',\n *       data: { userId },\n *       files: [{ field: 'avatar', file }],\n *     });\n *   }\n *\n *   // REST thuần\n *   getUser(id: string): Observable<User> {\n *     return this.api.request<User>({ path: `/users/${id}` });\n *   }\n */\n@Injectable({ providedIn: 'root' })\nexport class AscApiService {\n  private readonly http         = inject(HttpClient);\n  private readonly config       = inject(ASC_HTTP_CONFIG);\n  private readonly errorHandler = inject(ASC_HTTP_ERROR_HANDLER);\n  private readonly getUserId    = inject(ASC_HTTP_USER_ID_FN);\n\n  /**\n   * Gọi API POST với envelope chuẩn.\n   * @returns Observable<TResponse> — trực tiếp là body.data từ response\n   */\n  post<TResponse, TBody = unknown>({ authenType, data, endpoint, skipLoading }: AscPostOptions<TBody>): Observable<TResponse> {\n    const payload: AscApiRequest<TBody> = {\n      header: this._buildHeader(),\n      body:   { authenType, data },\n    };\n    const context = skipLoading ? new HttpContext().set(SKIP_LOADING, true) : undefined;\n    return this._send<TResponse>(payload, authenType, endpoint, context);\n  }\n\n  /**\n   * Gọi API login — dùng envelope riêng với `command` thay vì `authenType`.\n   * `TResponse` do consuming app tự định nghĩa (extend `AscAuthUser`) — sea-http\n   * chỉ cần biết field `token` để phục vụ AscAuthStorageService/interceptor.\n   */\n  login<TResponse extends AscAuthUser = AscAuthUser>({ endpoint, ...data }: AscLoginOptions): Observable<TResponse> {\n    const payload = {\n      header: this._buildHeader(),\n      body:   { command: 'GET_ENQUIRY', data },\n    };\n\n    return this._send<TResponse>(payload, 'GET_ENQUIRY', endpoint);\n  }\n\n  /**\n   * Gọi API POST envelope kèm file upload (multipart/form-data).\n   *\n   * KHÔNG dùng chung cơ chế userID với post()/login(): ascAuthInterceptor chỉ\n   * inject userID vào envelope bằng cách mutate JSON body — với FormData thì\n   * interceptor không \"nhìn\" được vào bên trong (isAscApiRequest trả về false),\n   * nên userID sẽ luôn rỗng nếu để mặc định. Vì vậy header ở đây tự lấy userID\n   * thật ngay lúc build qua ASC_HTTP_USER_ID_FN, không phụ thuộc interceptor.\n   * Bearer token vẫn được interceptor tự inject bình thường (không phân biệt\n   * body type).\n   *\n   * Envelope { header, body: { authenType, data } } được đóng gói làm 1 field\n   * multipart tên 'request' (JSON.stringify); mỗi file trong `files` được append\n   * riêng theo `field` tương ứng. Unwrap response / throw AscApiError giống\n   * hệt post() (dùng chung _send()).\n   *\n   * `file: null` → gửi field rỗng ('') thay vì Blob — theo quy ước BE, field\n   * multipart rỗng nghĩa là xoá file đó khỏi record hiện có. Không đưa field\n   * vào `files` nếu muốn giữ nguyên (không đụng tới file cũ).\n   *\n   * @example\n   *   this.api.postFormData<UploadResult>({\n   *     authenType: 'uploadAvatar',\n   *     data: { userId: '123' },\n   *     files: [{ field: 'avatar', file: selectedFile }],\n   *   });\n   *\n   *   // Xoá avatar hiện có, giữ nguyên các file khác\n   *   this.api.postFormData<UploadResult>({\n   *     authenType: 'updateProfile',\n   *     data: { userId: '123' },\n   *     files: [{ field: 'avatar', file: null }],\n   *   });\n   */\n  postFormData<TResponse, TBody = unknown>(\n    { authenType, data, files, endpoint, skipLoading }: AscPostFormDataOptions<TBody>\n  ): Observable<TResponse> {\n    const header = this._buildHeader();\n    header.userID = this.getUserId();\n\n    const formData = new FormData();\n    formData.append('request', JSON.stringify({ header, body: { authenType, data } }));\n    for (const { field, file } of files) {\n      if (file === null) {\n        formData.append(field, '');\n      } else {\n        formData.append(field, file, file.name);\n      }\n    }\n\n    const context = skipLoading ? new HttpContext().set(SKIP_LOADING, true) : undefined;\n    return this._send<TResponse>(formData, authenType, endpoint, context);\n  }\n\n  /**\n   * Gọi API POST với envelope chuẩn, nhận response dạng binary (Blob) — dùng cho\n   * download file. Tự build envelope { header, body } giống hệt post(), nên\n   * consuming app không cần tự ghi đè/định nghĩa lại envelope.\n   *\n   * Trả về nguyên `HttpResponse<Blob>` (không unwrap) — app tự đọc `body` (Blob)\n   * và header (vd: `Content-Disposition` để lấy filename) theo nhu cầu riêng.\n   * Không throw AscApiError vì response không phải JSON envelope — lỗi HTTP\n   * (4xx/5xx) vẫn đi qua ascErrorInterceptor như bình thường.\n   *\n   * @example\n   *   downloadPassportFile(transactionId: string): Observable<HttpResponse<Blob>> {\n   *     return this.api.postBlob({\n   *       authenType: 'downloadApplication',\n   *       data: { transactionId },\n   *     });\n   *   }\n   */\n  postBlob<TBody = unknown>({ authenType, data, endpoint, skipLoading }: AscPostBlobOptions<TBody>): Observable<HttpResponse<Blob>> {\n    const payload: AscApiRequest<TBody> = {\n      header: this._buildHeader(),\n      body:   { authenType, data },\n    };\n    const context = skipLoading ? new HttpContext().set(SKIP_LOADING, true) : undefined;\n\n    return this.http.post(this._urlFor(endpoint), payload, {\n      responseType: 'blob',\n      observe:      'response',\n      ...(context ? { context } : {}),\n    });\n  }\n\n  /**\n   * Gọi API POST envelope kèm file upload (multipart/form-data), nhận response dạng\n   * binary (Blob) — dùng cho endpoint vừa upload file vừa có thể trả về response\n   * KHÔNG đồng nhất kiểu (rỗng / Blob nhị phân / JSON envelope lỗi), nên không thể\n   * dùng postFormData() (luôn parse JSON, tự throw AscApiError) lẫn postBlob()\n   * (không hỗ trợ upload file).\n   *\n   * Cách dựng request giống hệt postFormData(): multipart FormData, tự build\n   * envelope header + inject userID trực tiếp qua ASC_HTTP_USER_ID_FN (FormData\n   * không mutate được qua ascAuthInterceptor). Cách nhận response giống hệt\n   * postBlob(): `responseType: 'blob', observe: 'response'`, KHÔNG unwrap, KHÔNG\n   * tự throw AscApiError — trả nguyên `HttpResponse<Blob>` để app tự đọc `body`\n   * (Blob) và phân loại nội dung theo nhu cầu riêng (vd: `size === 0` → thành\n   * công; `await blob.text()` parse được JSON có `status: 'FAIL'` → lỗi nghiệp\n   * vụ; parse JSON thất bại → file lỗi thật, cho tải về nguyên Blob).\n   *\n   * @example\n   *   validateFile(logType: BookTypeEnum, file: File): Observable<HttpResponse<Blob>> {\n   *     return this.api.postFormDataBlob({\n   *       authenType: 'uploadLogbook',\n   *       data: { logbookCode: logType },\n   *       files: [{ field: 'files', file }],\n   *     });\n   *   }\n   */\n  postFormDataBlob<TBody = unknown>(\n    { authenType, data, files, endpoint, skipLoading }: AscPostFormDataOptions<TBody>\n  ): Observable<HttpResponse<Blob>> {\n    const header = this._buildHeader();\n    header.userID = this.getUserId();\n\n    const formData = new FormData();\n    formData.append('request', JSON.stringify({ header, body: { authenType, data } }));\n    for (const { field, file } of files) {\n      if (file === null) {\n        formData.append(field, '');\n      } else {\n        formData.append(field, file, file.name);\n      }\n    }\n\n    const context = skipLoading ? new HttpContext().set(SKIP_LOADING, true) : undefined;\n    return this.http.post(this._urlFor(endpoint), formData, {\n      responseType: 'blob',\n      observe:      'response',\n      ...(context ? { context } : {}),\n    });\n  }\n\n  /**\n   * Gọi endpoint chuẩn HTTP (không bọc envelope) — dùng cho BE trả thẳng REST.\n   * Vẫn đi qua cùng interceptor chain với post()/login(): Bearer token tự inject\n   * bởi ascAuthInterceptor, lỗi HTTP tự xử lý bởi ascErrorInterceptor + ASC_HTTP_ERROR_HANDLER,\n   * loading indicator tự đếm bởi ascLoadingInterceptor.\n   *\n   * Không throw AscApiError (đó là lỗi nghiệp vụ riêng của envelope) — lỗi ở đây\n   * luôn là HttpErrorResponse chuẩn, phát sinh khi response không phải 2xx.\n   *\n   * @example\n   *   this.api.request<User>({ path: '/users/123' })\n   *   this.api.request<User, CreateUserDto>({ method: 'POST', path: '/users', body: dto })\n   *   this.api.request<User[]>({ path: '/users', params: { status: 'active' } })\n   */\n  request<TResponse, TBody = unknown>(opts: AscRestOptions<TBody>): Observable<TResponse> {\n    const { method = 'GET', path, body, params, headers, endpoint, skipLoading } = opts;\n    const url = this._urlFor(endpoint, path);\n    const context = skipLoading ? new HttpContext().set(SKIP_LOADING, true) : undefined;\n\n    return this.http.request<TResponse>(method, url, {\n      body,\n      params:  this._toHttpParams(params),\n      headers,\n      context,\n    });\n  }\n\n  private _urlFor(endpoint?: string, path?: string): string {\n    const base = !endpoint ? this.config.baseUrl : (this.config.endpoints?.[endpoint] ?? this.config.baseUrl);\n    if (!path) return base;\n    return `${base.replace(/\\/$/, '')}/${path.replace(/^\\//, '')}`;\n  }\n\n  private _toHttpParams(params?: AscRestOptions['params']): HttpParams | undefined {\n    if (!params) return undefined;\n    let httpParams = new HttpParams();\n    for (const [key, value] of Object.entries(params)) {\n      if (value === undefined || value === null) continue;\n      httpParams = httpParams.set(key, String(value));\n    }\n    return httpParams;\n  }\n\n  private _buildHeader() {\n    return {\n      reqType:    'REQUEST' as const,\n      api:        this.config.api,\n      apiKey:     this.config.apiKey,\n      priority:   this.config.priority   ?? '1',\n      channel:    this.config.channel    ?? 'ASEANSC',\n      subChannel: this.config.subChannel ?? 'ASEANSC',\n      context:    this.config.context    ?? 'WEB',\n      userID:     '',   // ascAuthInterceptor sẽ inject giá trị thực\n      synasyn:    'true',\n    };\n  }\n\n  private _send<TResponse>(payload: object, operation: string, endpoint?: string, context?: HttpContext): Observable<TResponse> {\n    return this.http\n      .post<AscApiResponse<TResponse>>(this._urlFor(endpoint), payload, context ? { context } : {})\n      .pipe(\n        map(res => {\n          if (res.body.status !== 'OK') {\n            // Một số BE (vd bos-api) không trả body.data khi lỗi, nội dung lỗi\n            // nằm ở field `error` riêng (ngang hàng body) — xem AscApiResponseError.\n            const err = new AscApiError(res.body.status, operation, res.body.data ?? res.error ?? null);\n            this.errorHandler(err);\n            throw err;\n          }\n          return res.body.data as TResponse;\n        }),\n        catchError(err => throwError(() => err)),\n      );\n  }\n}\n","import { computed, Injectable, signal } from '@angular/core';\n\n/**\n * AscLoadingService — đếm số HTTP request đang chạy.\n * Dùng kèm với ascLoadingInterceptor.\n *\n * @example\n *   private loading = inject(AscLoadingService);\n *\n *   // Template\n *   @if (loading.isLoading()) { <p-progressbar mode=\"indeterminate\" /> }\n */\n@Injectable({ providedIn: 'root' })\nexport class AscLoadingService {\n  private readonly _count = signal(0);\n\n  /** true khi có ít nhất 1 request đang chạy */\n  readonly isLoading = computed(() => this._count() > 0);\n\n  /** Số request đang pending */\n  readonly pendingCount = this._count.asReadonly();\n\n  /** @internal — gọi bởi ascLoadingInterceptor */\n  increment(): void {\n    this._count.update(n => n + 1);\n  }\n\n  /** @internal — gọi bởi ascLoadingInterceptor */\n  decrement(): void {\n    this._count.update(n => Math.max(0, n - 1));\n  }\n}\n","import { Injectable } from '@angular/core';\nimport { AscAuthUser } from '../types/api.types';\n\n/**\n * Abstract contract cho auth storage.\n *\n * App provide một trong các implementation sau:\n *   { provide: AscAuthStorageService, useExisting: AscLocalStorageAuthService }\n *   { provide: AscAuthStorageService, useExisting: AscCookieAuthService }\n *   { provide: AscAuthStorageService, useExisting: AscSessionStorageAuthService }\n */\n@Injectable()\nexport abstract class AscAuthStorageService {\n  abstract save(data: AscAuthUser): void;\n  abstract getToken(): string | null;\n  abstract getUser<T extends AscAuthUser = AscAuthUser>(): T | null;\n  abstract clear(): void;\n}\n","import { inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { AscAuthUser } from '../types/api.types';\nimport { AscAuthStorageService } from './asc-auth-storage.service';\n\nconst TOKEN_KEY = 'asc_token';\nconst USER_KEY  = 'asc_user';\n\n@Injectable({ providedIn: 'root' })\nexport class AscLocalStorageAuthService extends AscAuthStorageService {\n  private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n  save(data: AscAuthUser): void {\n    if (!this.isBrowser) return;\n    localStorage.setItem(TOKEN_KEY, data.token);\n    localStorage.setItem(USER_KEY, JSON.stringify(data));\n  }\n\n  getToken(): string | null {\n    return this.isBrowser ? localStorage.getItem(TOKEN_KEY) : null;\n  }\n\n  getUser<T extends AscAuthUser = AscAuthUser>(): T | null {\n    if (!this.isBrowser) return null;\n    const raw = localStorage.getItem(USER_KEY);\n    try { return raw ? (JSON.parse(raw) as T) : null; }\n    catch { return null; }\n  }\n\n  clear(): void {\n    if (!this.isBrowser) return;\n    localStorage.removeItem(TOKEN_KEY);\n    localStorage.removeItem(USER_KEY);\n  }\n}\n","import { inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { DOCUMENT } from '@angular/common';\nimport { AscAuthUser } from '../types/api.types';\nimport { AscAuthStorageService } from './asc-auth-storage.service';\n\nconst TOKEN_KEY = 'asc_token';\nconst USER_KEY  = 'asc_user';\n\n/**\n * Lưu session bằng cookie. Mỗi cookie bị giới hạn ~4KB — nếu permissionList\n * quá lớn, hãy dùng AscLocalStorageAuthService thay thế.\n */\n@Injectable({ providedIn: 'root' })\nexport class AscCookieAuthService extends AscAuthStorageService {\n  private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n  private readonly doc       = inject(DOCUMENT);\n\n  save(data: AscAuthUser, expireDays = 1): void {\n    if (!this.isBrowser) return;\n    this._set(TOKEN_KEY, data.token, expireDays);\n    this._set(USER_KEY, JSON.stringify(data), expireDays);\n  }\n\n  getToken(): string | null {\n    return this.isBrowser ? this._get(TOKEN_KEY) : null;\n  }\n\n  getUser<T extends AscAuthUser = AscAuthUser>(): T | null {\n    if (!this.isBrowser) return null;\n    const raw = this._get(USER_KEY);\n    try { return raw ? (JSON.parse(raw) as T) : null; }\n    catch { return null; }\n  }\n\n  clear(): void {\n    if (!this.isBrowser) return;\n    this._delete(TOKEN_KEY);\n    this._delete(USER_KEY);\n  }\n\n  private _set(name: string, value: string, expireDays: number): void {\n    const exp = new Date();\n    exp.setDate(exp.getDate() + expireDays);\n    this.doc.cookie =\n      `${name}=${encodeURIComponent(value)};expires=${exp.toUTCString()};path=/;SameSite=Strict`;\n  }\n\n  private _get(name: string): string | null {\n    const match = this.doc.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));\n    return match ? decodeURIComponent(match[1]) : null;\n  }\n\n  private _delete(name: string): void {\n    this.doc.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;SameSite=Strict`;\n  }\n}\n","import { inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { AscAuthUser } from '../types/api.types';\nimport { AscAuthStorageService } from './asc-auth-storage.service';\n\nconst TOKEN_KEY = 'asc_token';\nconst USER_KEY  = 'asc_user';\n\n/**\n * Lưu session bằng sessionStorage — mất khi đóng tab/trình duyệt.\n * Phù hợp khi không muốn token tồn tại xuyên phiên làm việc.\n */\n@Injectable({ providedIn: 'root' })\nexport class AscSessionStorageAuthService extends AscAuthStorageService {\n  private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n  save(data: AscAuthUser): void {\n    if (!this.isBrowser) return;\n    sessionStorage.setItem(TOKEN_KEY, data.token);\n    sessionStorage.setItem(USER_KEY, JSON.stringify(data));\n  }\n\n  getToken(): string | null {\n    return this.isBrowser ? sessionStorage.getItem(TOKEN_KEY) : null;\n  }\n\n  getUser<T extends AscAuthUser = AscAuthUser>(): T | null {\n    if (!this.isBrowser) return null;\n    const raw = sessionStorage.getItem(USER_KEY);\n    try { return raw ? (JSON.parse(raw) as T) : null; }\n    catch { return null; }\n  }\n\n  clear(): void {\n    if (!this.isBrowser) return;\n    sessionStorage.removeItem(TOKEN_KEY);\n    sessionStorage.removeItem(USER_KEY);\n  }\n}\n","/**\n * @file asc-sse.service.ts\n *\n * AscSseService — Server-Sent Events wrapper.\n *\n * EventSource không hỗ trợ custom HTTP header, nên token JWT được\n * truyền qua URL query param (mặc định: ?token=<jwt>).\n *\n * @example\n *   private sse = inject(AscSseService);\n *\n *   // Unnamed events (server gửi: \"data: {...}\\n\\n\")\n *   this.sse.connect<NotificationDto>('/notifications/stream')\n *     .pipe(takeUntilDestroyed())\n *     .subscribe(event => console.log(event.data));\n *\n *   // Named events (server gửi: \"event: meeting-update\\ndata: {...}\\n\\n\")\n *   this.sse.on<MeetingUpdate>('/notifications/stream', 'meeting-update')\n *     .pipe(takeUntilDestroyed())\n *     .subscribe(data => this.update(data));\n */\nimport { inject, Injectable, NgZone, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser }                        from '@angular/common';\nimport { Observable }                               from 'rxjs';\nimport { filter, map }                              from 'rxjs/operators';\nimport { ASC_HTTP_CONFIG }                          from '../config/asc-http.config';\nimport { AscLocalStorageAuthService }               from './asc-local-storage-auth.service';\nimport { AscCookieAuthService }                     from './asc-cookie-auth.service';\nimport { AscSessionStorageAuthService }             from './asc-session-storage-auth.service';\nimport type { AscSseEvent, AscSseOptions }          from '../types/sse.types';\n\n@Injectable({ providedIn: 'root' })\nexport class AscSseService {\n  private readonly config      = inject(ASC_HTTP_CONFIG);\n  private readonly lsAuth      = inject(AscLocalStorageAuthService);\n  private readonly cookieAuth  = inject(AscCookieAuthService);\n  private readonly sessionAuth = inject(AscSessionStorageAuthService);\n  private readonly zone        = inject(NgZone);\n  private readonly isBrowser   = isPlatformBrowser(inject(PLATFORM_ID));\n\n  /**\n   * Kết nối SSE và nhận tất cả unnamed events (type = 'message').\n   * Unsubscribe để đóng kết nối.\n   */\n  connect<T = unknown>(path: string, options: AscSseOptions = {}): Observable<AscSseEvent<T>> {\n    return new Observable<AscSseEvent<T>>(subscriber => {\n      if (!this.isBrowser) {\n        subscriber.complete();\n        return;\n      }\n\n      const url             = this._buildUrl(path, options);\n      const shouldReconnect = options.reconnect      ?? true;\n      const reconnectDelay  = options.reconnectDelay ?? 3000;\n      let es: EventSource | null = null;\n      let closed = false;\n      let timer:  ReturnType<typeof setTimeout> | null = null;\n\n      const open = () => {\n        if (closed) return;\n\n        es = new EventSource(url, { withCredentials: options.withCredentials ?? false });\n\n        es.onmessage = (event: MessageEvent) => {\n          this.zone.run(() => {\n            subscriber.next({\n              type: 'message',\n              data: this._parse<T>(event.data),\n              id:   event.lastEventId || undefined,\n            });\n          });\n        };\n\n        es.onerror = () => {\n          es!.close();\n          if (closed) return;\n          if (shouldReconnect) {\n            timer = setTimeout(open, reconnectDelay);\n          } else {\n            this.zone.run(() => subscriber.error(new Error('SSE connection error')));\n          }\n        };\n      };\n\n      open();\n\n      return () => {\n        closed = true;\n        if (timer) clearTimeout(timer);\n        es?.close();\n      };\n    });\n  }\n\n  /**\n   * Lắng nghe một named event type cụ thể.\n   * Server phải gửi: \"event: <eventType>\\ndata: {...}\\n\\n\"\n   */\n  on<T = unknown>(path: string, eventType: string, options: AscSseOptions = {}): Observable<T> {\n    return new Observable<T>(subscriber => {\n      if (!this.isBrowser) {\n        subscriber.complete();\n        return;\n      }\n\n      const url             = this._buildUrl(path, options);\n      const shouldReconnect = options.reconnect      ?? true;\n      const reconnectDelay  = options.reconnectDelay ?? 3000;\n      let es: EventSource | null = null;\n      let closed = false;\n      let timer:  ReturnType<typeof setTimeout> | null = null;\n\n      const handler = (event: MessageEvent) => {\n        this.zone.run(() => subscriber.next(this._parse<T>(event.data)));\n      };\n\n      const open = () => {\n        if (closed) return;\n\n        es = new EventSource(url, { withCredentials: options.withCredentials ?? false });\n\n        es.addEventListener(eventType, handler as EventListener);\n\n        es.onerror = () => {\n          es!.removeEventListener(eventType, handler as EventListener);\n          es!.close();\n          if (closed) return;\n          if (shouldReconnect) {\n            timer = setTimeout(open, reconnectDelay);\n          } else {\n            this.zone.run(() => subscriber.error(new Error('SSE connection error')));\n          }\n        };\n      };\n\n      open();\n\n      return () => {\n        closed = true;\n        if (timer) clearTimeout(timer);\n        es?.removeEventListener(eventType, handler as EventListener);\n        es?.close();\n      };\n    });\n  }\n\n  // ── Private helpers ───────────────────────────────────────────────────────\n\n  private _buildUrl(path: string, options: AscSseOptions): string {\n    const base   = path.startsWith('http') ? path : `${this.config.baseUrl}${path}`;\n    const params = new URLSearchParams(options.params ?? {});\n    const token  = this.lsAuth.getToken() ?? this.cookieAuth.getToken() ?? this.sessionAuth.getToken();\n\n    if (token) {\n      params.set(options.tokenParam ?? 'token', token);\n    }\n\n    const qs = params.toString();\n    return qs ? `${base}?${qs}` : base;\n  }\n\n  private _parse<T>(raw: string): T {\n    try   { return JSON.parse(raw) as T; }\n    catch { return raw as unknown as T; }\n  }\n}\n","/**\n * @file asc-websocket.service.ts\n *\n * AscWebSocketService — WebSocket wrapper với envelope protocol.\n *\n * Outgoing / Incoming messages dùng cùng cấu trúc:\n *   { header: { api, apiKey, userID, ... }, body: { authenType, data } }\n *\n * Token JWT được truyền qua URL query param khi kết nối.\n * Tự động reconnect khi mất kết nối (configurable).\n *\n * @example\n *   private ws = inject(AscWebSocketService);\n *\n *   ngOnInit() {\n *     this.conn = this.ws.connect('/ws/meetings');\n *\n *     // Subscribe trạng thái kết nối\n *     this.conn.status$.pipe(takeUntilDestroyed()).subscribe(s => console.log(s));\n *\n *     // Nhận event theo authenType\n *     this.conn.on<MeetingEvent>('meetingUpdate')\n *       .pipe(takeUntilDestroyed())\n *       .subscribe(data => this.handleUpdate(data));\n *\n *     // Gửi message\n *     this.conn.send('subscribeMeeting', { meetingId: '123' });\n *   }\n *\n *   ngOnDestroy() {\n *     this.conn.close();\n *   }\n */\nimport { inject, Injectable, NgZone, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser }    from '@angular/common';\nimport { webSocket, WebSocketSubject } from 'rxjs/webSocket';\nimport {\n  Observable,\n  Subject,\n  BehaviorSubject,\n  EMPTY,\n  timer,\n} from 'rxjs';\nimport {\n  filter,\n  map,\n  retry,\n  share,\n  takeUntil,\n} from 'rxjs/operators';\nimport { ASC_HTTP_CONFIG, ASC_HTTP_USER_ID_FN }   from '../config/asc-http.config';\nimport { AscLocalStorageAuthService }              from './asc-local-storage-auth.service';\nimport { AscCookieAuthService }                    from './asc-cookie-auth.service';\nimport { AscSessionStorageAuthService }            from './asc-session-storage-auth.service';\nimport type { AscWsOptions, AscWsMessage, AscWsStatus } from '../types/websocket.types';\nimport type { AscHttpConfig }                      from '../config/asc-http.config';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Connection handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class AscWsConnection {\n  private readonly socket$:  WebSocketSubject<AscWsMessage>;\n  private readonly destroy$ = new Subject<void>();\n  private readonly _status$ = new BehaviorSubject<AscWsStatus>('connecting');\n\n  /** Stream trạng thái kết nối */\n  readonly status$: Observable<AscWsStatus> = this._status$.asObservable();\n\n  /** Stream tất cả messages nhận được */\n  readonly messages$: Observable<AscWsMessage>;\n\n  constructor(\n    wsUrl:         string,\n    private config: AscHttpConfig,\n    private userIdFn: () => string,\n    private options: AscWsOptions,\n    private zone:   NgZone,\n  ) {\n    this.socket$ = webSocket<AscWsMessage>({\n      url: wsUrl,\n      openObserver: {\n        next: () => this.zone.run(() => this._status$.next('connected')),\n      },\n      closingObserver: {\n        next: () => this.zone.run(() => {\n          if (!this.destroy$.closed) this._status$.next('disconnected');\n        }),\n      },\n    });\n\n    const reconnect    = options.reconnect      ?? true;\n    const maxRetries   = options.maxRetries      ?? 5;\n    const retryDelay   = options.reconnectDelay  ?? 3000;\n\n    const base$ = this.socket$.pipe(takeUntil(this.destroy$));\n\n    this.messages$ = (\n      reconnect\n        ? base$.pipe(\n            retry({\n              count: maxRetries,\n              delay: (err, attempt) => {\n                this.zone.run(() => this._status$.next('connecting'));\n                return timer(retryDelay * attempt);\n              },\n            }),\n          )\n        : base$\n    ).pipe(share());\n  }\n\n  /**\n   * Lọc messages theo authenType và trả về data đã type.\n   */\n  on<T = unknown>(authenType: string): Observable<T> {\n    return this.messages$.pipe(\n      filter(msg => msg.body.authenType === authenType),\n      map(msg => msg.body.data as T),\n    );\n  }\n\n  /**\n   * Gửi message với envelope chuẩn.\n   */\n  send<T = unknown>(authenType: string, data: T): void {\n    this.socket$.next({\n      header: {\n        api:        this.config.api,\n        apiKey:     this.config.apiKey,\n        userID:     this.userIdFn(),\n        channel:    this.config.channel    ?? 'ASEANSC',\n        subChannel: this.config.subChannel ?? 'ASEANSC',\n      },\n      body: { authenType, data },\n    });\n  }\n\n  /** Đóng kết nối và giải phóng tài nguyên */\n  close(): void {\n    this._status$.next('disconnected');\n    this.destroy$.next();\n    this.destroy$.complete();\n    this.socket$.complete();\n  }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Service\n// ─────────────────────────────────────────────────────────────────────────────\n\n@Injectable({ providedIn: 'root' })\nexport class AscWebSocketService {\n  private readonly config      = inject(ASC_HTTP_CONFIG);\n  private readonly getUserId   = inject(ASC_HTTP_USER_ID_FN);\n  private readonly lsAuth      = inject(AscLocalStorageAuthService);\n  private readonly cookieAuth  = inject(AscCookieAuthService);\n  private readonly sessionAuth = inject(AscSessionStorageAuthService);\n  private readonly zone        = inject(NgZone);\n  private readonly isBrowser   = isPlatformBrowser(inject(PLATFORM_ID));\n\n  /**\n   * Mở kết nối WebSocket đến path.\n   * Gọi conn.close() trong ngOnDestroy để tránh memory leak.\n   *\n   * @param path  Path tương đối (vd: '/ws/meetings') hoặc URL đầy đủ wss://\n   * @param options  Cấu hình reconnect, token param, v.v.\n   */\n  connect(path: string, options: AscWsOptions = {}): AscWsConnection {\n    if (!this.isBrowser) {\n      return this._noop();\n    }\n\n    const wsUrl = this._buildWsUrl(path, options);\n    return new AscWsConnection(wsUrl, this.config, this.getUserId, options, this.zone);\n  }\n\n  // ── Private helpers ───────────────────────────────────────────────────────\n\n  private _buildWsUrl(path: string, options: AscWsOptions): string {\n    const raw  = path.startsWith('ws://') || path.startsWith('wss://')\n      ? path\n      : path.startsWith('http')\n        ? path.replace(/^https?/, m => m === 'https' ? 'wss' : 'ws')\n        : `${this.config.baseUrl.replace(/^https?/, m => m === 'https' ? 'wss' : 'ws')}${path}`;\n\n    if (options.tokenParam === false) return raw;\n\n    const token = this.lsAuth.getToken() ?? this.cookieAuth.getToken() ?? this.sessionAuth.getToken();\n    if (!token) return raw;\n\n    const sep   = raw.includes('?') ? '&' : '?';\n    const param = typeof options.tokenParam === 'string' ? options.tokenParam : 'token';\n    return `${raw}${sep}${param}=${encodeURIComponent(token)}`;\n  }\n\n  /** Trả về connection rỗng cho môi trường SSR */\n  private _noop(): AscWsConnection {\n    const noop = {\n      status$:   EMPTY as Observable<AscWsStatus>,\n      messages$: EMPTY as Observable<AscWsMessage>,\n      on:        () => EMPTY,\n      send:      () => undefined,\n      close:     () => undefined,\n    } as unknown as AscWsConnection;\n    return noop;\n  }\n}\n","import { inject } from '@angular/core';\nimport { HttpInterceptorFn } from '@angular/common/http';\nimport { ASC_HTTP_USER_ID_FN } from '../config/asc-http.config';\nimport { isAscApiRequest } from '../types/api.types';\nimport { AscLocalStorageAuthService } from '../services/asc-local-storage-auth.service';\nimport { AscCookieAuthService } from '../services/asc-cookie-auth.service';\nimport { AscSessionStorageAuthService } from '../services/asc-session-storage-auth.service';\n\n/**\n * ascAuthInterceptor — inject userID vào envelope header và Bearer token vào\n * HTTP Authorization header cho mọi AscApiRequest.\n *\n * Token được lấy từ localStorage trước, nếu không có thì thử cookie, cuối\n * cùng thử sessionStorage.\n * Không gắn token cho các request auth (login) — nhận biết qua body.body.command.\n *\n * @example\n * // app.config.ts\n * {\n *   provide: ASC_HTTP_USER_ID_FN,\n *   useFactory: (auth: AuthService) => () => auth.currentUser()?.userId ?? '',\n *   deps: [AuthService],\n * }\n */\nexport const ascAuthInterceptor: HttpInterceptorFn = (req, next) => {\n  const getUserId    = inject(ASC_HTTP_USER_ID_FN);\n  const lsAuth       = inject(AscLocalStorageAuthService);\n  const cookieAuth   = inject(AscCookieAuthService);\n  const sessionAuth  = inject(AscSessionStorageAuthService);\n\n  const body = req.body as Record<string, unknown> | null;\n  const isAuthRequest =\n    !!body &&\n    typeof body['body'] === 'object' &&\n    body['body'] !== null &&\n    'command' in (body['body'] as object);\n\n  let modified = req;\n\n  // Gắn Bearer token vào HTTP header, bỏ qua request login/auth\n  if (!isAuthRequest) {\n    const token = lsAuth.getToken() ?? cookieAuth.getToken() ?? sessionAuth.getToken();\n    if (token) {\n      modified = modified.clone({\n        setHeaders: { Authorization: `Bearer ${token}` },\n      });\n    }\n  }\n\n  // Gắn userID vào envelope header\n  if (modified.body && isAscApiRequest(modified.body)) {\n    modified = modified.clone({\n      body: {\n        ...modified.body,\n        header: {\n          ...modified.body.header,\n          userID: getUserId(),\n        },\n      },\n    });\n  }\n\n  return next(modified);\n};\n","import { inject } from '@angular/core';\nimport { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http';\nimport { Router } from '@angular/router';\nimport { catchError, retry, throwError, timer } from 'rxjs';\nimport { ASC_HTTP_ERROR_HANDLER } from '../config/asc-http.config';\nimport { AscLocalStorageAuthService } from '../services/asc-local-storage-auth.service';\nimport { AscCookieAuthService } from '../services/asc-cookie-auth.service';\nimport { AscSessionStorageAuthService } from '../services/asc-session-storage-auth.service';\n\nconst RETRY_COUNT = 3;\nconst RETRY_DELAY = 1000; // ms\n\n/**\n * ascErrorInterceptor — xử lý HTTP error tập trung, dùng chung cho cả envelope\n * (AscApiService.post()/login()) lẫn REST thuần (AscApiService.request()) — vì\n * interceptor chỉ dựa vào HttpErrorResponse.status, không đọc envelope.\n *\n * - 500 Server error     → retry tối đa 3 lần (delay 1s, 2s, 3s) trước khi báo lỗi\n * - 401 Unauthorized     → xoá session (localStorage + cookie + sessionStorage), redirect về /login (KHÔNG gọi error handler)\n * - 403 Forbidden        → redirect về /login (KHÔNG gọi error handler)\n * - 0   Network error    → gọi error handler\n * - Mọi status khác      → gọi error handler (404, 4xx, 5xx...)\n */\nexport const ascErrorInterceptor: HttpInterceptorFn = (req, next) => {\n  const router       = inject(Router);\n  const errorHandler = inject(ASC_HTTP_ERROR_HANDLER);\n  const lsAuth       = inject(AscLocalStorageAuthService);\n  const cookieAuth   = inject(AscCookieAuthService);\n  const sessionAuth  = inject(AscSessionStorageAuthService);\n\n  return next(req).pipe(\n    retry({\n      count: RETRY_COUNT,\n      delay: (error, attempt) => {\n        if (error instanceof HttpErrorResponse && error.status === 500) {\n          return timer(RETRY_DELAY * attempt);\n        }\n        // Không retry các lỗi khác\n        throw error;\n      },\n    }),\n    catchError((error: HttpErrorResponse) => {\n      if (!(error instanceof HttpErrorResponse)) {\n        return throwError(() => error);\n      }\n\n      switch (true) {\n        case error.status === 401:\n          lsAuth.clear();\n          cookieAuth.clear();\n          sessionAuth.clear();\n          router.navigate(['/login']);\n          break;\n        case error.status === 403:\n          router.navigate(['/login']);\n          break;\n\n        case error.status === 0:\n          errorHandler(\n            new HttpErrorResponse({\n              error:      error.error,\n              status:     0,\n              statusText: 'Network Error — Không kết nối được server',\n              url:        req.url,\n            }),\n          );\n          break;\n\n        default:\n          errorHandler(error);\n          break;\n      }\n\n      return throwError(() => error);\n    }),\n  );\n};\n","import { inject } from '@angular/core';\nimport { HttpInterceptorFn } from '@angular/common/http';\nimport { finalize } from 'rxjs';\nimport { AscLoadingService } from '../services/asc-loading.service';\nimport { SKIP_LOADING } from './loading.token';\n\n/**\n * ascLoadingInterceptor — tự động tăng/giảm bộ đếm loading khi có request.\n *\n * Mặc định BẬT cho mọi request. Để tắt cho request cụ thể, dùng skipLoading\n * trong AscApiService.post() hoặc set SKIP_LOADING context token thủ công.\n *\n * @example\n *   // Qua AscApiService:\n *   this.api.post({ authenType: 'poll', data: {}, skipLoading: true })\n *\n *   // Hiển thị UI loading (trong app.component.html):\n *   <asc-loading-bar [visible]=\"loading.isLoading()\" />\n */\nexport const ascLoadingInterceptor: HttpInterceptorFn = (req, next) => {\n  if (req.context.get(SKIP_LOADING)) return next(req);\n\n  const loading = inject(AscLoadingService);\n  loading.increment();\n  return next(req).pipe(\n    finalize(() => loading.decrement()),\n  );\n};\n","// ─── Bootstrap ───────────────────────────────────────────────────────────────\nexport { provideAscHttp } from './lib/config/asc-http.provider';\n\n// ─── Config tokens ────────────────────────────────────────────────────────────\nexport {\n  ASC_HTTP_CONFIG,\n  ASC_HTTP_USER_ID_FN,\n  ASC_HTTP_ERROR_HANDLER,\n} from './lib/config/asc-http.config';\nexport type { AscHttpConfig } from './lib/config/asc-http.config';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\nexport type {\n  AscApiRequest,\n  AscApiRequestHeader,\n  AscApiResponse,\n  AscApiResponseHeader,\n  AscPostOptions,\n  AscLoginOptions,\n  AscPostFormDataOptions,\n  AscPostBlobOptions,\n  AscFormDataFile,\n  AscHttpMethod,\n  AscRestOptions,\n  LoginRequestData,\n  AscAuthUser,\n} from './lib/types/api.types';\nexport { AscApiError, isAscApiRequest } from './lib/types/api.types';\n\n// ─── Services ─────────────────────────────────────────────────────────────────\nexport { AscApiService }              from './lib/services/asc-api.service';\nexport { AscLoadingService }          from './lib/services/asc-loading.service';\nexport { AscAuthStorageService }      from './lib/services/asc-auth-storage.service';\nexport { AscLocalStorageAuthService } from './lib/services/asc-local-storage-auth.service';\nexport { AscCookieAuthService }       from './lib/services/asc-cookie-auth.service';\nexport { AscSessionStorageAuthService } from './lib/services/asc-session-storage-auth.service';\nexport { AscSseService }              from './lib/services/asc-sse.service';\nexport { AscWebSocketService, AscWsConnection } from './lib/services/asc-websocket.service';\n\n// ─── SSE / WebSocket types ───────────────────────────────────────────────────\nexport type { AscSseOptions, AscSseEvent }                       from './lib/types/sse.types';\nexport type { AscWsOptions, AscWsMessage, AscWsHeader, AscWsStatus } from './lib/types/websocket.types';\n\n// ─── Interceptors ─────────────────────────────────────────────────────────────\nexport { ascAuthInterceptor }    from './lib/interceptors/asc-auth.interceptor';\nexport { ascErrorInterceptor }   from './lib/interceptors/asc-error.interceptor';\nexport { ascLoadingInterceptor } from './lib/interceptors/asc-loading.interceptor';\nexport { SKIP_LOADING }          from './lib/interceptors/loading.token';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["TOKEN_KEY","USER_KEY","map","retry"],"mappings":"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"}