Cross-cutting interceptors
Three Angular HttpInterceptorFn covering requests the atomic client never sees — the ui-language body field, audit metadata, and 401 recovery on the HttpClient channel.
The @sinequa/atomic client covers its own requests directly — the interface language, audit metadata and
401 recovery are all built into it. These three interceptors give the same coverage to requests that never go
through the client at all: @sinequa/agent, @sinequa/assistant, or your own code built on Angular's
HttpClient.
Two channels, never the same request
A request either goes through the atomic client (which handles it directly) or through HttpClient (which
these interceptors cover) — never both. Registering the client's own handling and these interceptors is
therefore correct, not a duplicate.
Minimal example
import { ApplicationConfig } from "@angular/core";
import { provideHttpClient, withInterceptors } from "@angular/common/http";
import { auditInterceptorFn, bodyInterceptorFn, errorInterceptorFn } from "@sinequa/atomic-angular";
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withInterceptors([bodyInterceptorFn, errorInterceptorFn, auditInterceptorFn])),
],
};How it works
bodyInterceptorFn — the interface language
Adds the current interface language to the request body as ui-language, read fresh from TranslocoService
on every request rather than captured once — the language changes while the application runs (the user
menus and the user-profile form call setActiveLang), and a request must carry the one in force when it is
sent. FormData bodies get the field appended directly; a plain object body is cloned with the field added.
GET/HEAD requests pass through untouched — they carry no body with the fetch backend.
errorInterceptorFn — 401 recovery
Same recovery as the client's own recoverFromUnauthorized hook (see Bootstrap the
application), on the HttpClient channel: on a 401, call signIn(), and retry the
original request once — only if signIn() reports the user is authenticated. A 403 is propagated as a
permanent auth failure, never retried. When a 401 still reaches the caller — signIn() could not authenticate, or
the retry was rejected again — the interceptor tells provideSessionExpiry(), which raises its
"session expired" toast for this channel too.
auditInterceptorFn — audit metadata
Adds Sinequa's audit metadata to a request body, for any request whose URL contains api/v1 and whose body is
JSON-serializable (skipped for HttpParams bodies). The @sinequa/atomic API functions already add this to
their own requests; this covers the ones built directly on HttpClient.
Pitfalls
What's next
Document language
Keep the page's lang attribute on the language the interface is displayed in, so screen readers pronounce it correctly.
Cross-cutting pipes
Six template pipes with no search-specific meaning of their own — legacy filter display, a translated system string, locale-aware dates, file sizes, and search-term highlighting.