import { HttpInterceptorFn } from '@angular/common/http'; import { currentSubject } from './subject'; /** * Dev-only (WP-74): stamps every API request with `X-Subject`, the BSN * `StubIdentityProvider` (backend) resolves the caller's `ZorgverlenerCaller` from — * every owner-keyed store (`ApplicationStore`, `DocumentStore`, `BriefStore`) reads * off that resolved identity, so this is the seam that lets e2e specs log in as * distinct citizens and mutate independent rows instead of all colliding on * `DocumentStore.DemoOwner`. Scoped like `medewerker.interceptor.ts` (every * `/api/v1/*` request, not an allow-list like `roleInterceptor`) — the identity * middleware resolves a `CallerIdentity` for every request, not just some endpoints. * * **BSN source — a deliberate compromise, read before changing:** the "obvious" * source would be the authenticated `Session.bsn` held by each app's own * `SessionStore`, but `libs/shared` may not depend on an app-local `auth` context * (the import-direction rule), and the one sanctioned cross-context seam — * `SessionPort` (`@shared/application/session.port`) — deliberately exposes only * `{ naam }`: `SessionStore`'s G1 comment is explicit that the BSN (a GDPR * special-category identifier) is never persisted or otherwise handed outward, by * design. Extending that port (or injecting `SessionStore` itself) would undo that * boundary just to serve a dev/e2e convenience. So instead this reuses * `role.interceptor.ts`'s own trick (see `subject.ts`, mirroring `role.ts`'s * `currentRole()`): a `?subject=` seen in the URL is remembered in sessionStorage * for the tab, and every later request reuses it. `e2e/support/actors.ts`'s * `loginAs` sets it once per spec by navigating to `/login?subject=` before * filling in the login form. Outside e2e nothing ever sets `?subject=`, so no * header is sent and the backend falls back to `DocumentStore.DemoOwner` exactly as * before this WP. */ export const subjectInterceptor: HttpInterceptorFn = (req, next) => { const subject = currentSubject(); if (!subject || !req.url.includes('/api/v1/')) return next(req); return next(req.clone({ setHeaders: { 'X-Subject': subject } })); };