/** * HttpClient companion. Angular's HTTP layer ships a chainable * `HttpInterceptor` interface — the framework wires every interceptor * registered against the `HTTP_INTERCEPTORS` token into the request * pipeline. This module ships the SDK side of the interceptor as a * reporter factory, *not* a concrete interceptor class: * * `createBrowsonicHttpReporter(options?) → (req, err) => void` * * Consumers write the 5-line interceptor themselves so they own the * `rxjs` / `@angular/common/http` runtime imports — that keeps this * adapter peer-only on `@angular/*` and avoids forcing rxjs into a * graph that doesn't already have it. * * ```ts * // app/browsonic-http.interceptor.ts * import { Injectable } from '@angular/core'; * import { * HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, * } from '@angular/common/http'; * import { Observable, throwError } from 'rxjs'; * import { catchError } from 'rxjs/operators'; * import { createBrowsonicHttpReporter } from '@browsonic/angular'; * * @Injectable() * export class BrowsonicHttpInterceptor implements HttpInterceptor { * private readonly report = createBrowsonicHttpReporter(); * intercept(req: HttpRequest, next: HttpHandler): * Observable> { * return next.handle(req).pipe(catchError(err => { * this.report(req, err); * return throwError(() => err); * })); * } * } * * // app.config.ts (standalone) or AppModule providers: * { provide: HTTP_INTERCEPTORS, useClass: BrowsonicHttpInterceptor, multi: true } * ``` * * Why a reporter factory instead of a concrete class: * - Adapter stays free of `@angular/common/http` and `rxjs` runtime * deps. Same contract the rest of the package follows * (router instrumentation, error-handler). * - Consumers can wire the same reporter into a non-interceptor * surface — direct `fetch()` calls, GraphQL clients, custom * transports — without re-implementing the matching / status * logic. * * @copyright 2024-2026 Browsonic * @license Apache-2.0 */ import type { Browsonic } from '@browsonic/sdk'; /** * Subset of Angular's `HttpRequest` we read. The actual HttpRequest * has dozens of fields (headers, params, body, withCredentials, etc.); * none of those carry signal beyond what URL + method already do. */ export interface HttpRequestLike { url: string; method?: string; /** Optional `urlWithParams` — Angular populates this with the * serialised query string. Falls back to `url` when absent. */ urlWithParams?: string; } /** * Subset of Angular's `HttpErrorResponse` we read. The class is part * of `@angular/common/http` (peer-only here), so we structurally * duck-type the fields the dashboard needs. */ export interface HttpErrorResponseLike { status?: number; statusText?: string; url?: string | null; message?: string; /** Server-side error payload (parsed JSON in most setups). */ error?: unknown; /** `false` for any HttpErrorResponse — kept for type narrowing. */ ok?: false; /** `'HttpErrorResponse'` for the canonical class. Used as a * fallback discriminator when the consumer hands us a * re-thrown POJO. */ name?: string; } export interface CreateBrowsonicHttpReporterOptions { /** SDK instance. Falls back to `window.Browsonic.getBrowsonic()`. */ sdk?: Browsonic; /** * URLs to skip — match against the request URL exactly (string) * or via `regex.test(url)` (RegExp). The Browsonic ingest endpoint * itself should generally be on this list to avoid an infinite * report-on-failed-report loop. */ ignoreUrls?: (string | RegExp)[]; /** * HTTP status codes to skip — common values are `[401, 404]` for * apps that surface those at the UI layer and don't want them in * the dashboard. */ ignoreStatuses?: number[]; /** * Tag namespace prefix. Defaults to `'angular.http'`. Override * when a project hosts multiple Angular apps and wants distinct * dashboard buckets (e.g. `'admin.http'` / `'public.http'`). */ tagNamespace?: string; /** * Maximum response-body length (chars) to attach as * `httpResponseBody` metadata. Defaults to 1024. Set to `0` to * skip body capture entirely (e.g. APIs that echo PII in error * payloads). */ maxBodyLength?: number; } export type BrowsonicHttpReporter = (request: HttpRequestLike, error: unknown) => void; /** * Build a reporter callback that captures HttpClient failures to the * Browsonic SDK. The returned function takes the request + the * error caught by `catchError(...)` and: * * 1. Filters by `ignoreUrls` / `ignoreStatuses` (no-ops if matched). * 2. Tags the active scope with `.method` and `.status`. * 3. Attaches `httpUrl` + (truncated) `httpResponseBody` metadata. * 4. Coerces the error to an `Error` and forwards to `captureError`. * * Returns `void` — no rethrow. The interceptor's own `catchError` * branch is responsible for rethrowing so HttpClient sees the * failure unchanged. Decoupling rethrow from capture lets consumers * wire the reporter into surfaces that don't preserve errors (e.g. * fire-and-forget logging). */ export declare function createBrowsonicHttpReporter(options?: CreateBrowsonicHttpReporterOptions): BrowsonicHttpReporter; //# sourceMappingURL=http-interceptor.d.ts.map