import * as i0 from '@angular/core'; import { InjectionToken, EnvironmentProviders, NgZone } from '@angular/core'; import { HttpErrorResponse, HttpResponse, HttpInterceptorFn, HttpContextToken } from '@angular/common/http'; import { Observable } from 'rxjs'; interface AscApiRequestHeader { reqType: 'REQUEST'; api: string; apiKey: string; priority: string; channel: string; subChannel: string; context: string; userID: string; synasyn: string; } interface AscApiRequest { header: AscApiRequestHeader; body: { authenType: string; data: T; }; } interface AscApiResponseHeader { reqType: 'RESPONSE'; api: string; apiKey: string; channel: string; subChannel: string; location: string; context: string; duration: number; priority: number; userID: string; synasyn: string; } /** * Một số BE (vd bos-api) không nhét message lỗi vào `body.data` mà trả riêng * ở field `error` ngang hàng với `body`/`header` — `body.data` lúc đó thường * không tồn tại. Field bên trong không cố định (tuỳ BE: `desc`, `messageVn`...) * nên chỉ khai unknown, để `AscApiError` tự dò field message quen thuộc. */ interface AscApiResponseError { code?: string; [key: string]: unknown; } interface AscApiResponse { header: AscApiResponseHeader; body: { status: string; data?: T; }; /** Chỉ có khi status lỗi, tuỳ BE — xem AscApiResponseError */ error?: AscApiResponseError; } declare class AscApiError extends Error { readonly status: string; readonly authenType: string; readonly data: unknown; constructor(status: string, authenType: string, data?: unknown); /** * BE không thống nhất tên field chứa message lỗi trong `data` (tuỳ endpoint: * `message`, `msg`, `errorMessage`...), nên thử lần lượt các field phổ biến. * Không tìm thấy → giữ nguyên message debug cũ (`[authenType] ... status`). */ private static _extractMessage; } declare function isAscApiRequest(body: unknown): body is AscApiRequest; interface AscPostOptions { /** Tên action/operation, vd: 'getAllMeetingAsean' */ authenType: string; /** Payload gửi vào body.data */ data: TBody; /** Key của named endpoint trong AscHttpConfig.endpoints */ endpoint?: string; /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */ skipLoading?: boolean; } interface AscLoginOptions extends LoginRequestData { /** Key của named endpoint trong AscHttpConfig.endpoints */ endpoint?: string; } interface AscPostBlobOptions { /** Tên action/operation, vd: 'downloadApplication' */ authenType: string; /** Payload gửi vào body.data */ data: TBody; /** Key của named endpoint trong AscHttpConfig.endpoints */ endpoint?: string; /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */ skipLoading?: boolean; } interface AscFormDataFile { /** Tên field multipart cho file này, vd: 'avatar', 'attachment' */ field: string; /** * `null` → gửi field rỗng ('') xuống BE — theo quy ước BE, field multipart * rỗng nghĩa là xoá file đó khỏi record. Không truyền field này trong `files` * nếu muốn giữ nguyên file cũ (không đụng tới). */ file: File | null; } interface AscPostFormDataOptions { /** Tên action/operation, vd: 'uploadAvatar' */ authenType: string; /** * Payload nghiệp vụ gửi kèm — được đóng gói cùng envelope header thành 1 * field multipart tên 'request' (JSON.stringify). */ data: TBody; /** File đính kèm — mỗi phần tử tạo 1 field multipart riêng theo `field` */ files: AscFormDataFile[]; /** Key của named endpoint trong AscHttpConfig.endpoints */ endpoint?: string; /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */ skipLoading?: boolean; } type AscHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; interface AscRestOptions { /** Mặc định: 'GET' */ method?: AscHttpMethod; /** Path nối vào baseUrl/endpoint, vd: '/users/123'. Có thể để trống nếu baseUrl/endpoint đã là URL đầy đủ. */ path?: string; /** Request body — dùng cho POST/PUT/PATCH/DELETE */ body?: TBody; /** Query params — áp dụng cho mọi method */ params?: Record; /** Header bổ sung — không ghi đè Authorization (do ascAuthInterceptor set) */ headers?: Record; /** Key của named endpoint trong AscHttpConfig.endpoints */ endpoint?: string; /** Bỏ qua global loading indicator cho request này. Mặc định: false (loading bật) */ skipLoading?: boolean; } interface LoginRequestData { username: string; password: string; authenType: 'getLogin'; type: 'INHOUSE' | 'EXTERNAL'; } /** * Shape tối thiểu mà AscAuthStorageService/ascAuthInterceptor cần để lưu và * đọc token. Response login thực tế do consuming app tự định nghĩa (extend * `AscAuthUser`) và truyền vào qua generic khi gọi `login()`/`getUser()` — * sea-http không hardcode các field còn lại (email, permissionList, ...). */ interface AscAuthUser { token: string; [key: string]: unknown; } interface AscHttpConfig { /** Base URL mặc định, vd: https://api.aseansc.com.vn/api */ baseUrl: string; /** * Named endpoints — dùng khi app có nhiều URL khác nhau. * Truyền key vào tham số `endpoint` của post()/login(). * @example * endpoints: { auth: 'https://auth.aseansc.com.vn/api' } * this.api.post({ authenType: 'doSomething', data, endpoint: 'auth' }) */ endpoints?: Record; /** API key cố định gắn vào mọi request */ apiKey: string; /** Tên service, vd: 'sea-meetings' */ api: string; /** Mặc định: 'ASEANSC' */ channel?: string; /** Mặc định: 'ASEANSC' */ subChannel?: string; /** Mặc định: 'WEB' */ context?: string; /** Mặc định: '1' */ priority?: string; } /** Config token — provide qua provideAscHttp() */ declare const ASC_HTTP_CONFIG: InjectionToken; /** * Hàm trả về userID của user đang đăng nhập. * App cần provide: * { provide: ASC_HTTP_USER_ID_FN, useFactory: (auth: AuthService) => () => auth.userId(), deps: [AuthService] } */ declare const ASC_HTTP_USER_ID_FN: InjectionToken<() => string>; /** * Error handler tập trung cho cả HTTP error lẫn AscApiError. * App có thể provide để tích hợp toast, logging, v.v. * * @example * { * provide: ASC_HTTP_ERROR_HANDLER, * useFactory: (toast: AscToastService) => * (err) => toast.error(err instanceof AscApiError ? err.message : 'Lỗi kết nối server'), * deps: [AscToastService], * } */ declare const ASC_HTTP_ERROR_HANDLER: InjectionToken<(error: HttpErrorResponse | AscApiError) => void>; /** * provideAscHttp — đăng ký config cho AscApiService và AscLoadingService. * * Đặt trong providers của app.config.ts. * Các interceptor cần thêm thủ công vào withInterceptors() để * tránh xung đột khi app đã có provideHttpClient() riêng. * * @example * // app.config.ts * import { provideHttpClient, withInterceptors } from '@angular/common/http'; * import { * provideAscHttp, * ascAuthInterceptor, * ascErrorInterceptor, * ascLoadingInterceptor, * } from '@aseansc-admin/http'; * * export const appConfig: ApplicationConfig = { * providers: [ * provideHttpClient( * withInterceptors([ascAuthInterceptor, ascErrorInterceptor, ascLoadingInterceptor]), * ), * provideAscHttp({ * baseUrl: 'https://api.aseansc.com.vn/api', * apiKey: 'qmklfoni1ezxlf2ckpygpfx248', * api: 'sea-meetings', * }), * * // Tuỳ chọn: cấu hình userID từ auth service * { * provide: ASC_HTTP_USER_ID_FN, * useFactory: (auth: AuthService) => () => auth.currentUser()?.userId ?? '', * deps: [AuthService], * }, * * // Tuỳ chọn: hiển thị toast khi có lỗi * { * provide: ASC_HTTP_ERROR_HANDLER, * useFactory: (toast: AscToastService) => * (err) => toast.error(err instanceof AscApiError ? err.message : 'Lỗi kết nối server'), * deps: [AscToastService], * }, * ], * }; */ declare function provideAscHttp(config: AscHttpConfig): EnvironmentProviders; /** * AscApiService — gọi API qua 4 flow, cùng đi qua 1 interceptor chain (auth, * error handler, loading): * * - post() / login() — envelope { header, body } — cho BE cũ theo chuẩn envelope. * Tự build header, unwrap body.data, throw AscApiError nếu body.status !== 'OK'. * - postFormData() — envelope + file upload (multipart/form-data). Cùng * unwrap/throw AscApiError như post(), nhưng tự lấy userID trực tiếp thay vì * qua interceptor (FormData không mutate được như JSON body). * - postBlob() — envelope, nhận response dạng binary (Blob) — dùng cho * download file. Tự build envelope giống post(), trả nguyên HttpResponse * (không unwrap, không throw AscApiError vì response không phải JSON). * - postFormDataBlob() — kết hợp postFormData() + postBlob(): multipart file * upload (dựng request như postFormData()) nhưng nhận response dạng binary * (Blob) không unwrap/không throw (như postBlob()) — dùng cho endpoint vừa * upload file vừa trả response không đồng nhất kiểu (rỗng/Blob/JSON lỗi). * - request() — chuẩn HTTP thuần (GET/POST/PUT/PATCH/DELETE) — cho BE * trả thẳng REST, không bọc envelope. Lỗi luôn là HttpErrorResponse. * * userID được inject vào envelope header bởi ascAuthInterceptor cho post()/ * login()/postBlob() (mutate JSON body); postFormData()/postFormDataBlob() tự * lấy trực tiếp qua ASC_HTTP_USER_ID_FN. Bearer token được inject cho cả 5 flow. * * @example * private api = inject(AscApiService); * * // Envelope * getMeetings(pagination: Pagination): Observable { * return this.api.post({ * authenType: 'getAllMeetingAsean', * data: { pagination: { pageNumber: 0, pageSize: 25 }, search: '' }, * }); * } * * // Envelope + file upload * uploadAvatar(userId: string, file: File): Observable { * return this.api.postFormData({ * authenType: 'uploadAvatar', * data: { userId }, * files: [{ field: 'avatar', file }], * }); * } * * // REST thuần * getUser(id: string): Observable { * return this.api.request({ path: `/users/${id}` }); * } */ declare class AscApiService { private readonly http; private readonly config; private readonly errorHandler; private readonly getUserId; /** * Gọi API POST với envelope chuẩn. * @returns Observable — trực tiếp là body.data từ response */ post({ authenType, data, endpoint, skipLoading }: AscPostOptions): Observable; /** * Gọi API login — dùng envelope riêng với `command` thay vì `authenType`. * `TResponse` do consuming app tự định nghĩa (extend `AscAuthUser`) — sea-http * chỉ cần biết field `token` để phục vụ AscAuthStorageService/interceptor. */ login({ endpoint, ...data }: AscLoginOptions): Observable; /** * Gọi API POST envelope kèm file upload (multipart/form-data). * * KHÔNG dùng chung cơ chế userID với post()/login(): ascAuthInterceptor chỉ * inject userID vào envelope bằng cách mutate JSON body — với FormData thì * interceptor không "nhìn" được vào bên trong (isAscApiRequest trả về false), * nên userID sẽ luôn rỗng nếu để mặc định. Vì vậy header ở đây tự lấy userID * thật ngay lúc build qua ASC_HTTP_USER_ID_FN, không phụ thuộc interceptor. * Bearer token vẫn được interceptor tự inject bình thường (không phân biệt * body type). * * Envelope { header, body: { authenType, data } } được đóng gói làm 1 field * multipart tên 'request' (JSON.stringify); mỗi file trong `files` được append * riêng theo `field` tương ứng. Unwrap response / throw AscApiError giống * hệt post() (dùng chung _send()). * * `file: null` → gửi field rỗng ('') thay vì Blob — theo quy ước BE, field * multipart rỗng nghĩa là xoá file đó khỏi record hiện có. Không đưa field * vào `files` nếu muốn giữ nguyên (không đụng tới file cũ). * * @example * this.api.postFormData({ * authenType: 'uploadAvatar', * data: { userId: '123' }, * files: [{ field: 'avatar', file: selectedFile }], * }); * * // Xoá avatar hiện có, giữ nguyên các file khác * this.api.postFormData({ * authenType: 'updateProfile', * data: { userId: '123' }, * files: [{ field: 'avatar', file: null }], * }); */ postFormData({ authenType, data, files, endpoint, skipLoading }: AscPostFormDataOptions): Observable; /** * Gọi API POST với envelope chuẩn, nhận response dạng binary (Blob) — dùng cho * download file. Tự build envelope { header, body } giống hệt post(), nên * consuming app không cần tự ghi đè/định nghĩa lại envelope. * * Trả về nguyên `HttpResponse` (không unwrap) — app tự đọc `body` (Blob) * và header (vd: `Content-Disposition` để lấy filename) theo nhu cầu riêng. * Không throw AscApiError vì response không phải JSON envelope — lỗi HTTP * (4xx/5xx) vẫn đi qua ascErrorInterceptor như bình thường. * * @example * downloadPassportFile(transactionId: string): Observable> { * return this.api.postBlob({ * authenType: 'downloadApplication', * data: { transactionId }, * }); * } */ postBlob({ authenType, data, endpoint, skipLoading }: AscPostBlobOptions): Observable>; /** * Gọi API POST envelope kèm file upload (multipart/form-data), nhận response dạng * binary (Blob) — dùng cho endpoint vừa upload file vừa có thể trả về response * KHÔNG đồng nhất kiểu (rỗng / Blob nhị phân / JSON envelope lỗi), nên không thể * dùng postFormData() (luôn parse JSON, tự throw AscApiError) lẫn postBlob() * (không hỗ trợ upload file). * * Cách dựng request giống hệt postFormData(): multipart FormData, tự build * envelope header + inject userID trực tiếp qua ASC_HTTP_USER_ID_FN (FormData * không mutate được qua ascAuthInterceptor). Cách nhận response giống hệt * postBlob(): `responseType: 'blob', observe: 'response'`, KHÔNG unwrap, KHÔNG * tự throw AscApiError — trả nguyên `HttpResponse` để app tự đọc `body` * (Blob) và phân loại nội dung theo nhu cầu riêng (vd: `size === 0` → thành * công; `await blob.text()` parse được JSON có `status: 'FAIL'` → lỗi nghiệp * vụ; parse JSON thất bại → file lỗi thật, cho tải về nguyên Blob). * * @example * validateFile(logType: BookTypeEnum, file: File): Observable> { * return this.api.postFormDataBlob({ * authenType: 'uploadLogbook', * data: { logbookCode: logType }, * files: [{ field: 'files', file }], * }); * } */ postFormDataBlob({ authenType, data, files, endpoint, skipLoading }: AscPostFormDataOptions): Observable>; /** * Gọi endpoint chuẩn HTTP (không bọc envelope) — dùng cho BE trả thẳng REST. * Vẫn đi qua cùng interceptor chain với post()/login(): Bearer token tự inject * bởi ascAuthInterceptor, lỗi HTTP tự xử lý bởi ascErrorInterceptor + ASC_HTTP_ERROR_HANDLER, * loading indicator tự đếm bởi ascLoadingInterceptor. * * Không throw AscApiError (đó là lỗi nghiệp vụ riêng của envelope) — lỗi ở đây * luôn là HttpErrorResponse chuẩn, phát sinh khi response không phải 2xx. * * @example * this.api.request({ path: '/users/123' }) * this.api.request({ method: 'POST', path: '/users', body: dto }) * this.api.request({ path: '/users', params: { status: 'active' } }) */ request(opts: AscRestOptions): Observable; private _urlFor; private _toHttpParams; private _buildHeader; private _send; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } /** * AscLoadingService — đếm số HTTP request đang chạy. * Dùng kèm với ascLoadingInterceptor. * * @example * private loading = inject(AscLoadingService); * * // Template * @if (loading.isLoading()) { } */ declare class AscLoadingService { private readonly _count; /** true khi có ít nhất 1 request đang chạy */ readonly isLoading: i0.Signal; /** Số request đang pending */ readonly pendingCount: i0.Signal; /** @internal — gọi bởi ascLoadingInterceptor */ increment(): void; /** @internal — gọi bởi ascLoadingInterceptor */ decrement(): void; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } /** * Abstract contract cho auth storage. * * App provide một trong các implementation sau: * { provide: AscAuthStorageService, useExisting: AscLocalStorageAuthService } * { provide: AscAuthStorageService, useExisting: AscCookieAuthService } * { provide: AscAuthStorageService, useExisting: AscSessionStorageAuthService } */ declare abstract class AscAuthStorageService { abstract save(data: AscAuthUser): void; abstract getToken(): string | null; abstract getUser(): T | null; abstract clear(): void; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } declare class AscLocalStorageAuthService extends AscAuthStorageService { private readonly isBrowser; save(data: AscAuthUser): void; getToken(): string | null; getUser(): T | null; clear(): void; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } /** * Lưu session bằng cookie. Mỗi cookie bị giới hạn ~4KB — nếu permissionList * quá lớn, hãy dùng AscLocalStorageAuthService thay thế. */ declare class AscCookieAuthService extends AscAuthStorageService { private readonly isBrowser; private readonly doc; save(data: AscAuthUser, expireDays?: number): void; getToken(): string | null; getUser(): T | null; clear(): void; private _set; private _get; private _delete; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } /** * Lưu session bằng sessionStorage — mất khi đóng tab/trình duyệt. * Phù hợp khi không muốn token tồn tại xuyên phiên làm việc. */ declare class AscSessionStorageAuthService extends AscAuthStorageService { private readonly isBrowser; save(data: AscAuthUser): void; getToken(): string | null; getUser(): T | null; clear(): void; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } interface AscSseOptions { /** Query params thêm vào URL */ params?: Record; /** * Tên query param chứa JWT token. * EventSource không hỗ trợ custom header nên token phải đi qua URL. * Mặc định: 'token' */ tokenParam?: string; /** withCredentials cho cookie. Mặc định: false */ withCredentials?: boolean; /** Tự động kết nối lại khi mất kết nối. Mặc định: true */ reconnect?: boolean; /** Delay giữa các lần reconnect (ms). Mặc định: 3000 */ reconnectDelay?: number; } interface AscSseEvent { /** Tên event type từ server, mặc định là 'message' */ type: string; /** Payload đã parse JSON */ data: T; /** Event ID từ server nếu có */ id?: string; } declare class AscSseService { private readonly config; private readonly lsAuth; private readonly cookieAuth; private readonly sessionAuth; private readonly zone; private readonly isBrowser; /** * Kết nối SSE và nhận tất cả unnamed events (type = 'message'). * Unsubscribe để đóng kết nối. */ connect(path: string, options?: AscSseOptions): Observable>; /** * Lắng nghe một named event type cụ thể. * Server phải gửi: "event: \ndata: {...}\n\n" */ on(path: string, eventType: string, options?: AscSseOptions): Observable; private _buildUrl; private _parse; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } interface AscWsOptions { /** * Tên query param chứa JWT token khi kết nối. * Mặc định: 'token'. Đặt false để không gửi token. */ tokenParam?: string | false; /** Tự động reconnect khi bị ngắt. Mặc định: true */ reconnect?: boolean; /** Số lần retry tối đa. Mặc định: 5 */ maxRetries?: number; /** Delay giữa các lần retry (ms). Mặc định: 3000 */ reconnectDelay?: number; } interface AscWsHeader { api: string; apiKey: string; userID: string; channel: string; subChannel: string; } interface AscWsMessage { header: AscWsHeader; body: { authenType: string; data: T; }; } type AscWsStatus = 'connecting' | 'connected' | 'disconnected' | 'error'; /** * @file asc-websocket.service.ts * * AscWebSocketService — WebSocket wrapper với envelope protocol. * * Outgoing / Incoming messages dùng cùng cấu trúc: * { header: { api, apiKey, userID, ... }, body: { authenType, data } } * * Token JWT được truyền qua URL query param khi kết nối. * Tự động reconnect khi mất kết nối (configurable). * * @example * private ws = inject(AscWebSocketService); * * ngOnInit() { * this.conn = this.ws.connect('/ws/meetings'); * * // Subscribe trạng thái kết nối * this.conn.status$.pipe(takeUntilDestroyed()).subscribe(s => console.log(s)); * * // Nhận event theo authenType * this.conn.on('meetingUpdate') * .pipe(takeUntilDestroyed()) * .subscribe(data => this.handleUpdate(data)); * * // Gửi message * this.conn.send('subscribeMeeting', { meetingId: '123' }); * } * * ngOnDestroy() { * this.conn.close(); * } */ declare class AscWsConnection { private config; private userIdFn; private options; private zone; private readonly socket$; private readonly destroy$; private readonly _status$; /** Stream trạng thái kết nối */ readonly status$: Observable; /** Stream tất cả messages nhận được */ readonly messages$: Observable; constructor(wsUrl: string, config: AscHttpConfig, userIdFn: () => string, options: AscWsOptions, zone: NgZone); /** * Lọc messages theo authenType và trả về data đã type. */ on(authenType: string): Observable; /** * Gửi message với envelope chuẩn. */ send(authenType: string, data: T): void; /** Đóng kết nối và giải phóng tài nguyên */ close(): void; } declare class AscWebSocketService { private readonly config; private readonly getUserId; private readonly lsAuth; private readonly cookieAuth; private readonly sessionAuth; private readonly zone; private readonly isBrowser; /** * Mở kết nối WebSocket đến path. * Gọi conn.close() trong ngOnDestroy để tránh memory leak. * * @param path Path tương đối (vd: '/ws/meetings') hoặc URL đầy đủ wss:// * @param options Cấu hình reconnect, token param, v.v. */ connect(path: string, options?: AscWsOptions): AscWsConnection; private _buildWsUrl; /** Trả về connection rỗng cho môi trường SSR */ private _noop; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; } /** * ascAuthInterceptor — inject userID vào envelope header và Bearer token vào * HTTP Authorization header cho mọi AscApiRequest. * * Token được lấy từ localStorage trước, nếu không có thì thử cookie, cuối * cùng thử sessionStorage. * Không gắn token cho các request auth (login) — nhận biết qua body.body.command. * * @example * // app.config.ts * { * provide: ASC_HTTP_USER_ID_FN, * useFactory: (auth: AuthService) => () => auth.currentUser()?.userId ?? '', * deps: [AuthService], * } */ declare const ascAuthInterceptor: HttpInterceptorFn; /** * ascErrorInterceptor — xử lý HTTP error tập trung, dùng chung cho cả envelope * (AscApiService.post()/login()) lẫn REST thuần (AscApiService.request()) — vì * interceptor chỉ dựa vào HttpErrorResponse.status, không đọc envelope. * * - 500 Server error → retry tối đa 3 lần (delay 1s, 2s, 3s) trước khi báo lỗi * - 401 Unauthorized → xoá session (localStorage + cookie + sessionStorage), redirect về /login (KHÔNG gọi error handler) * - 403 Forbidden → redirect về /login (KHÔNG gọi error handler) * - 0 Network error → gọi error handler * - Mọi status khác → gọi error handler (404, 4xx, 5xx...) */ declare const ascErrorInterceptor: HttpInterceptorFn; /** * ascLoadingInterceptor — tự động tăng/giảm bộ đếm loading khi có request. * * Mặc định BẬT cho mọi request. Để tắt cho request cụ thể, dùng skipLoading * trong AscApiService.post() hoặc set SKIP_LOADING context token thủ công. * * @example * // Qua AscApiService: * this.api.post({ authenType: 'poll', data: {}, skipLoading: true }) * * // Hiển thị UI loading (trong app.component.html): * */ declare const ascLoadingInterceptor: HttpInterceptorFn; /** * Set SKIP_LOADING = true trên HttpContext của một request để bỏ qua global loading indicator. * * @example * this.api.post({ authenType: 'silentRefresh', data: {}, skipLoading: true }) * * Hoặc dùng trực tiếp với HttpClient: * this.http.post(url, body, { context: new HttpContext().set(SKIP_LOADING, true) }) */ declare const SKIP_LOADING: HttpContextToken; export { ASC_HTTP_CONFIG, ASC_HTTP_ERROR_HANDLER, ASC_HTTP_USER_ID_FN, AscApiError, AscApiService, AscAuthStorageService, AscCookieAuthService, AscLoadingService, AscLocalStorageAuthService, AscSessionStorageAuthService, AscSseService, AscWebSocketService, AscWsConnection, SKIP_LOADING, ascAuthInterceptor, ascErrorInterceptor, ascLoadingInterceptor, isAscApiRequest, provideAscHttp }; export type { AscApiRequest, AscApiRequestHeader, AscApiResponse, AscApiResponseHeader, AscAuthUser, AscFormDataFile, AscHttpConfig, AscHttpMethod, AscLoginOptions, AscPostBlobOptions, AscPostFormDataOptions, AscPostOptions, AscRestOptions, AscSseEvent, AscSseOptions, AscWsHeader, AscWsMessage, AscWsOptions, AscWsStatus, LoginRequestData };