@ulabase/kit-ng 0.13.1 → 0.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -231,8 +231,9 @@ full reasoning.
231
231
  The fastest path to a working app:
232
232
 
233
233
  1. Create a service on [Ulabase](https://ulabase.com)
234
- 2. Fork [`ulabase/starter-ng`](https://github.com/ulabase/starter-ng)
235
- 3. Set `apiBaseUrl` in `environment.ts`
236
- 4. `ng serve`
234
+ 2. Clone [`ulabase/starter-ng`](https://github.com/ulabase/starter-ng) and run `npm install`
235
+ 3. `npx ulabase login`, then `npx ulabase setup --srv <srvId>`: it configures the service and writes
236
+ its URL into `src/environments/environment.dev.ts`
237
+ 4. `npm start`
237
238
 
238
239
  You get login, signup, email verification, invitations, password reset, and multi-team switching — all wired up.
@@ -36,8 +36,8 @@ var RhAuthService = class RhAuthService {
36
36
  login(email, password, mode = "bearer") {
37
37
  return from(kit.login(this.config, email, password, mode)).pipe(tap((u) => this._user.set(u)), switchMap((u) => from(kit.getTeams(this.config)).pipe(catchError(() => of([])), tap((ts) => this._teams.set(ts)), map(() => u))));
38
38
  }
39
- logout() {
40
- return from(kit.logout(this.config)).pipe(tap(() => {
39
+ logout(mode = "bearer") {
40
+ return from(kit.logout(this.config, mode)).pipe(tap(() => {
41
41
  this._user.set(null);
42
42
  this._teams.set([]);
43
43
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"ulabase-kit-ng.mjs","names":[],"sources":["../../src/tokens.ts","../../src/auth.service.ts","../../src/payments.service.ts","../../src/cart.service.ts","../../src/auth.guard.ts","../../src/auth.interceptor.ts","../../src/http-transport.ts","../../src/provide-rh-auth.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { HttpContextToken } from '@angular/common/http';\nimport type { AuthConfig } from '@ulabase/kit';\n\nexport const RH_AUTH_CONFIG = new InjectionToken<AuthConfig>('RH_AUTH_CONFIG');\n\n\n/**\n * Marks a request as originating from the kit rather than from application\n * code. Set by `httpClientTransport`, read by `rhAuthInterceptor`.\n *\n * The kit owns the meaning of a 401 on its own endpoints, and that meaning is\n * not always \"the session is dead\": `PATCH /auth/change-password` answers 401\n * when the *current password* is wrong, and `GET /token` when the credentials\n * are. Letting the interceptor clear the session on those would sign a user\n * out for mistyping their old password.\n */\nexport const RH_KIT_REQUEST = new HttpContextToken<boolean>(() => false);\n","import { Injectable, computed, inject, signal } from '@angular/core';\nimport { Observable, catchError, from, map, of, switchMap, tap, throwError } from 'rxjs';\nimport type { UserInfo, TeamMembership, TeamMember, PendingInvitation, AuthConfig, LoginMode } from '@ulabase/kit';\nimport * as kit from '@ulabase/kit';\nimport { RH_AUTH_CONFIG } from './tokens.js';\n\n@Injectable({ providedIn: 'root' })\nexport class RhAuthService {\n private readonly config: AuthConfig = inject(RH_AUTH_CONFIG);\n\n private readonly _user = signal<UserInfo | null>(null);\n private readonly _teams = signal<TeamMembership[]>([]);\n\n readonly user = this._user.asReadonly();\n readonly teams = this._teams.asReadonly();\n readonly isAuthenticated = computed(() => this._user() !== null);\n readonly hasMultipleTeams = computed(() => this._teams().length > 1);\n\n /**\n * Check the current session state.\n *\n * Reads the token from localStorage — if present and not expired,\n * returns user info from the server. Otherwise returns null.\n */\n checkSession(): Observable<UserInfo | null> {\n // If no valid token in localStorage, we're logged out — no HTTP call needed\n if (!kit.getToken()) {\n this._user.set(null);\n this._teams.set([]);\n return of(null);\n }\n\n return from(kit.checkSession(this.config)).pipe(\n tap(u => {\n this._user.set(u);\n if (!u) {\n this._teams.set([]);\n }\n }),\n switchMap(u =>\n u === null\n ? of([])\n : from(kit.getTeams(this.config)).pipe(catchError(() => of([])))\n ),\n tap(ts => this._teams.set(ts)),\n map(() => this._user())\n );\n }\n\n register(payload: {\n email: string;\n password: string;\n teamName: string;\n firstName: string;\n lastName: string;\n [key: string]: unknown;\n }): Observable<void> {\n return from(kit.register(this.config, payload));\n }\n\n verify(email: string, token: string, delivery: 'cookie' | 'fragment' = 'fragment'): Observable<string> {\n return from(kit.verify(this.config, email, token, delivery));\n }\n\n login(email: string, password: string, mode: LoginMode = 'bearer'): Observable<UserInfo> {\n return from(kit.login(this.config, email, password, mode)).pipe(\n tap(u => this._user.set(u)),\n switchMap(u =>\n from(kit.getTeams(this.config)).pipe(\n catchError(() => of([])),\n tap(ts => this._teams.set(ts)),\n map(() => u)\n )\n )\n );\n }\n\n logout(): Observable<void> {\n return from(kit.logout(this.config)).pipe(\n tap(() => {\n this._user.set(null);\n this._teams.set([]);\n })\n );\n }\n\n invite(email: string, role: 'owner' | 'member'): Observable<void> {\n return from(kit.invite(this.config, email, role));\n }\n\n getInvitation(email: string, token: string) {\n return from(kit.getInvitation(this.config, email, token));\n }\n\n activate(payload: { email: string; token: string; password: string }, mode: LoginMode = 'bearer'): Observable<void> {\n return from(kit.activate(this.config, payload, mode)).pipe(map(() => undefined));\n }\n\n acceptInvite(token: string): Observable<void> {\n return from(kit.acceptInvite(this.config, token)).pipe(\n switchMap(() =>\n from(kit.getTeams(this.config)).pipe(\n catchError(() => of([])),\n tap(ts => this._teams.set(ts))\n )\n ),\n map(() => undefined)\n );\n }\n\n resendInvite(email: string): Observable<void> {\n return from(kit.resendInvite(this.config, email));\n }\n\n listInvitations(): Observable<PendingInvitation[]> {\n return from(kit.listInvitations(this.config));\n }\n\n loadTeams(): Observable<TeamMembership[]> {\n return from(kit.getTeams(this.config)).pipe(\n tap(ts => this._teams.set(ts))\n );\n }\n\n switchTeam(teamId: { $oid: string }, mode: LoginMode = 'bearer'): Observable<void> {\n return from(kit.switchTeam(this.config, teamId, mode)).pipe(\n switchMap(() => this.checkSession()),\n map(() => undefined)\n );\n }\n\n clearSession(): void {\n kit.clearToken();\n kit.cancelRefresh();\n this._user.set(null);\n this._teams.set([]);\n }\n\n forgotPassword(email: string): Observable<void> {\n return from(kit.forgotPassword(this.config, email));\n }\n\n resetPassword(payload: { email: string; token: string; password: string }, mode: LoginMode = 'bearer'): Observable<void> {\n return from(kit.resetPassword(this.config, payload, mode)).pipe(map(() => undefined));\n }\n\n // ── Team members ─────────────────────────────────────────────────────────\n\n listTeamMembers(): Observable<TeamMember[]> {\n return from(kit.listTeamMembers(this.config));\n }\n\n removeMember(email: string): Observable<void> {\n return from(kit.removeMember(this.config, email));\n }\n\n updateMemberRole(email: string, role: 'owner' | 'member'): Observable<void> {\n return from(kit.updateMemberRole(this.config, email, role));\n }\n\n // ── Team lifecycle ───────────────────────────────────────────────────────\n\n createTeam(teamName: string): Observable<TeamMembership> {\n return from(kit.createTeam(this.config, teamName));\n }\n\n updateTeam(updates: { name?: string; description?: string }): Observable<void> {\n return from(kit.updateTeam(this.config, updates));\n }\n\n deleteTeam(): Observable<void> {\n return from(kit.deleteTeam(this.config));\n }\n\n // ── Profile & password ──────────────────────────────────────────────────\n\n updateProfile(updates: { firstName?: string; lastName?: string }): Observable<void> {\n return from(kit.updateProfile(this.config, updates)).pipe(\n switchMap(() => this.checkSession()),\n map(() => undefined)\n );\n }\n\n changePassword(currentPassword: string, newPassword: string): Observable<void> {\n return from(kit.changePassword(this.config, currentPassword, newPassword));\n }\n\n updateUser(email: string, updates: Record<string, unknown>): Observable<void> {\n return from(kit.updateUser(this.config, email, updates));\n }\n\n // ── Consents ────────────────────────────────────────────────────────────\n\n /**\n * Record the signed-in user's acceptance of the application's consents,\n * renew the token so the guard sees it, and update the `user` signal.\n */\n acceptConsents(body?: Record<string, unknown>, mode: LoginMode = 'bearer'): Observable<UserInfo> {\n // The user document may be missing precisely because the rule is blocking\n // `/users/me` — the case this call exists to get out of. The token still\n // says who they are.\n const userId = this._user()?._id ?? (kit.getTokenClaims()?.['sub'] as string | undefined);\n if (!userId) {\n return throwError(() => ({ status: 0, message: 'acceptConsents requires a signed-in user' }));\n }\n return from(kit.acceptConsents(this.config, userId, body, mode)).pipe(\n tap(u => this._user.set(u))\n );\n }\n\n /** Force a new token, carrying the user document as it is now. */\n renewToken(mode: LoginMode = 'bearer'): Observable<string | null> {\n return from(kit.renewToken(this.config, mode));\n }\n\n /**\n * An authenticated `fetch` against the service, returned as an Observable.\n *\n * The Angular counterpart of React's `auth.api()` — the bearer token is\n * attached automatically, and the request goes through the Angular\n * interceptor chain (when `httpClientTransport` is configured).\n *\n * ```ts\n * this.auth.api('/demo').pipe(\n * switchMap(res => res.json()),\n * ).subscribe(data => console.log(data));\n * ```\n *\n * For a POST:\n * ```ts\n * this.auth.api('/demo', {\n * method: 'POST',\n * body: JSON.stringify({ name: 'hello' }),\n * }).pipe(switchMap(res => res.json()));\n * ```\n *\n * Rejects with an `ApiError` (`{ status, message }`) on any non-2xx response.\n */\n api(path: string, init?: RequestInit): Observable<Response> {\n return from(kit.apiFetch(this.config, path, init));\n }\n}\n","import { Injectable, computed, effect, inject, signal, untracked } from '@angular/core';\nimport { Observable, catchError, from, of, tap } from 'rxjs';\nimport type {\n AuthConfig,\n CatalogItem,\n GrantLicenseResult,\n Licenses,\n Order,\n Plan,\n Subscription,\n WaitOptions,\n CatalogQuery,\n} from '@ulabase/kit';\nimport * as kit from '@ulabase/kit';\nimport { RH_AUTH_CONFIG } from './tokens.js';\nimport { RhAuthService } from './auth.service.js';\n\n/**\n * Subscription, billing and order management.\n *\n * Separated from {@link RhAuthService} because payments are not authentication.\n * Reads the current user from {@link RhAuthService} to derive\n * `canManageBilling`, but owns its own subscription state.\n *\n * Subscription is loaded automatically when the user signs in and reloaded\n * when they switch team (via an `effect` watching {@link teamKey}). No manual\n * wiring needed.\n *\n * Only active when `config.payments` is `true` — otherwise every method\n * is a no-op and no `/stripe/*` call is ever made.\n */\n@Injectable({ providedIn: 'root' })\nexport class RhPaymentsService {\n private readonly config: AuthConfig = inject(RH_AUTH_CONFIG);\n private readonly auth = inject(RhAuthService);\n\n private readonly _subscription = signal<Subscription | null>(null);\n\n readonly subscription = this._subscription.asReadonly();\n readonly plan = computed(() => this._subscription()?.plan ?? null);\n readonly isSubscribed = computed(() => this._subscription()?.active ?? false);\n readonly canManageBilling = computed(\n () => this.auth.user()?.team?.role === (this.config.ownershipRole ?? 'owner')\n );\n readonly seatsAvailable = computed(() => this._subscription()?.seats?.available ?? null);\n\n /**\n * The team the subscription belongs to: `null` when signed out, `''` for a\n * signed-in user with no team.\n *\n * The effect below tracks this rather than `auth.user()` itself. Both\n * `updateProfile` and `acceptConsents` re-run `checkSession`, which replaces\n * the user with a freshly parsed document — tracking that object's identity\n * would reload the subscription on every profile edit and consent\n * acceptance, which the adapter contract rules out. A subscription changes\n * with the team, not with the profile.\n */\n private readonly teamKey = computed(() => {\n const user = this.auth.user();\n return user ? (user.team?._id?.$oid ?? '') : null;\n });\n\n private get paymentsEnabled(): boolean {\n return this.config.payments === true;\n }\n\n constructor() {\n if (this.paymentsEnabled) {\n effect(() => {\n const teamKey = this.teamKey();\n untracked(() => {\n if (teamKey === null) {\n this._subscription.set(null);\n } else {\n this.loadSubscription().subscribe();\n }\n });\n });\n }\n }\n\n /** Reload the team's subscription. No-op when `config.payments` is not `true`. */\n loadSubscription(): Observable<Subscription | null> {\n if (!this.paymentsEnabled) return of(null);\n return from(kit.getSubscription(this.config)).pipe(\n tap(sub => this._subscription.set(sub)),\n catchError(() => {\n this._subscription.set(null);\n return of(null);\n })\n );\n }\n\n /** The service's subscription plan catalog. No session required. */\n getPlans(): Observable<{ default_plan: string; plans: Plan[] }> {\n return from(kit.getPlans(this.config));\n }\n\n /**\n * Start a Stripe Checkout session.\n *\n * **Rejects with `status: 409`** when the team already has an active\n * subscription — send them to {@link openBillingPortal} instead.\n */\n createCheckoutSession(plan: string, interval: 'month' | 'year'): Observable<{ url: string }> {\n return from(kit.createCheckoutSession(this.config, plan, interval));\n }\n\n /** Open the Stripe Customer Portal for self-service plan changes. */\n openBillingPortal(): Observable<{ url: string }> {\n return from(kit.openBillingPortal(this.config));\n }\n\n /** The team's seat licences. Requires `canManageBilling`. */\n getLicenses(): Observable<Licenses> {\n return from(kit.getLicenses(this.config));\n }\n\n /**\n * Grant a seat licence. Returns `'granted'` or `'already-licensed'`.\n * Rejects with `status: 409` when no seat is available.\n */\n grantLicense(userId: string): Observable<GrantLicenseResult> {\n return from(kit.grantLicense(this.config, userId));\n }\n\n /** Revoke a seat licence. */\n revokeLicense(userId: string): Observable<void> {\n return from(kit.revokeLicense(this.config, userId));\n }\n\n /** Read the product catalog. */\n getCatalog(opts?: CatalogQuery): Observable<CatalogItem[]> {\n return from(kit.getCatalog(this.config, opts));\n }\n\n /**\n * Create an order and start Checkout.\n *\n * @param email Required for guest checkout.\n */\n createOrder(\n items: { productId: string; quantity: number }[],\n email?: string,\n collection?: string\n ): Observable<{ _id: { $oid: string }; checkout_url: string; secret: string }> {\n return from(kit.createOrder(this.config, items, email, collection));\n }\n\n /** Read an order back. */\n getOrder(id: string, secret?: string, collection?: string): Observable<Order> {\n return from(kit.getOrder(this.config, id, secret, collection));\n }\n\n /**\n * Poll until the subscription satisfies `predicate`.\n *\n * Use on the Checkout success page — the redirect back from Stripe races\n * the webhook, so a bare `getSubscription` can still show the old plan.\n *\n * **Timing out is not a payment failure.** Rejects with\n * `WaitTimeoutError` when the webhook hasn't arrived yet.\n */\n waitForSubscription(\n predicate: (subscription: Subscription) => boolean,\n opts?: WaitOptions\n ): Observable<Subscription> {\n return from(\n kit.waitForSubscription(this.config, predicate, opts).then(sub => {\n this._subscription.set(sub);\n return sub;\n })\n );\n }\n\n /**\n * Poll until the order leaves `'pending_payment'`.\n *\n * Same race as {@link waitForSubscription} — use on the order success page.\n *\n * **Timing out is not a payment failure.** Rejects with\n * `WaitTimeoutError` when the webhook hasn't arrived yet.\n */\n waitForOrder(\n id: string,\n secret?: string,\n opts?: WaitOptions & { collection?: string }\n ): Observable<Order> {\n return from(kit.waitForOrder(this.config, id, secret, opts));\n }\n}\n","import { Injectable, InjectionToken, computed, inject, signal } from '@angular/core';\nimport {\n addToCart,\n cartTotals,\n loadCart,\n removeFromCart,\n saveCart,\n setCartQuantity,\n toOrderItems,\n DEFAULT_CART_STORAGE_KEY,\n type CartItem,\n type CartLine,\n} from '@ulabase/kit';\n/**\n * Where {@link RhCartService} keeps the cart in `localStorage`. Defaults to `'rh-cart'`.\n *\n * Worth providing when two of your apps share an origin, which is one deployment decision away\n * from happening by accident.\n *\n * Declared here rather than in `tokens.ts`: that file is the authentication surface, and a cart\n * needs no session. Importing the kit into it to reach one constant also dragged the kit's module\n * into every spec that touches `RH_AUTH_CONFIG`, where it is auto-mocked — which shifted module\n * initialisation enough to make two unrelated guard tests fail, in CI only.\n */\nexport const RH_CART_STORAGE_KEY = new InjectionToken<string>('RH_CART_STORAGE_KEY', {\n providedIn: 'root',\n factory: () => DEFAULT_CART_STORAGE_KEY,\n});\n\n/**\n * The shopping cart.\n *\n * Independent of {@link import('./auth.service.js').RhAuthService | RhAuthService}\n * and of `RH_AUTH_CONFIG`: a cart belongs to the browser, not to a session, and\n * a shop that makes people sign in before they can put something in a basket\n * loses most of them there. It becomes an order — which does need a config —\n * when {@link RhCartService.orderItems} is handed to `createOrder`.\n *\n * On the server, `localStorage` does not exist and the cart reads as empty.\n * That is correct for a rendered page — a request carries no basket — but it\n * does mean a server-rendered cart count starts at zero and fills in once the\n * browser takes over.\n */\n@Injectable({ providedIn: 'root' })\nexport class RhCartService {\n private readonly storageKey = inject(RH_CART_STORAGE_KEY);\n\n // Declared after `storageKey` so the field is there: initializers run in order.\n private readonly _lines = signal<CartLine[]>(loadCart(this.storageKey));\n\n /** The lines, in the order they were added. */\n readonly lines = this._lines.asReadonly();\n\n private readonly totals = computed(() => cartTotals(this._lines()));\n\n /** Units, not lines: two of one thing counts two. */\n readonly totalItems = computed(() => this.totals().totalItems);\n /** Display only. Minor units, meaningful when every line shares a currency. */\n readonly subtotal = computed(() => this.totals().subtotal);\n /** The first line's currency, or `'eur'` when empty. */\n readonly currency = computed(() => this.totals().currency);\n /** The cart as `createOrder` wants it. */\n readonly orderItems = computed(() => toOrderItems(this._lines()));\n\n /** Adds an item, or increases the line already holding it. */\n add(item: CartItem, quantity = 1): void {\n this.apply(current => addToCart(current, item, quantity));\n }\n\n /** Sets a line's quantity. Zero removes it. */\n setQuantity(productId: string, quantity: number): void {\n this.apply(current => setCartQuantity(current, productId, quantity));\n }\n\n remove(productId: string): void {\n this.apply(current => removeFromCart(current, productId));\n }\n\n clear(): void {\n this.apply(() => []);\n }\n\n /**\n * State and storage move together, in the operation that changed them.\n *\n * Deliberately not an `effect` reacting to the signal: an effect runs after\n * the fact and can be skipped or reordered, and the failure that produces is\n * a line coming back from storage after somebody removed it.\n */\n private apply(next: (current: CartLine[]) => CartLine[]): void {\n const updated = next(this._lines());\n saveCart(updated, this.storageKey);\n this._lines.set(updated);\n }\n}\n","import { inject } from '@angular/core';\nimport { Router, type CanActivateFn } from '@angular/router';\nimport { map, tap } from 'rxjs';\nimport { RhAuthService } from './auth.service.js';\n\nexport const authGuard: CanActivateFn = () => {\n const auth = inject(RhAuthService);\n const router = inject(Router);\n\n if (auth.isAuthenticated()) return true;\n\n return auth.checkSession().pipe(\n map(user => user !== null),\n tap(ok => { if (!ok) router.navigate(['/auth/login']); })\n );\n};\n\nexport const publicGuard: CanActivateFn = () => {\n const auth = inject(RhAuthService);\n const router = inject(Router);\n\n if (!auth.isAuthenticated()) return true;\n\n return auth.checkSession().pipe(\n map(user => user === null),\n tap(isPublic => { if (!isPublic) router.navigate(['/']); })\n );\n};\n","import { inject } from '@angular/core';\nimport {\n HttpRequest,\n HttpHandlerFn,\n HttpInterceptorFn,\n HttpErrorResponse,\n} from '@angular/common/http';\nimport { Observable, catchError, from, switchMap, throwError } from 'rxjs';\nimport { RhAuthService } from './auth.service.js';\nimport { RH_AUTH_CONFIG, RH_KIT_REQUEST } from './tokens.js';\nimport { clearToken, cancelRefresh, getToken } from '@ulabase/kit';\nimport type { AuthConfig } from '@ulabase/kit';\n\n/** The token source is pluggable and may be async — keep the sync path sync. */\nfunction readToken(config: AuthConfig): string | null | Promise<string | null> {\n return config.getToken ? config.getToken() : getToken();\n}\n\nfunction isPromise<T>(v: T | Promise<T>): v is Promise<T> {\n return typeof (v as Promise<T>)?.then === 'function';\n}\n\n/**\n * Authenticates the application's own `HttpClient` requests, and clears the\n * session when the service rejects one with a 401.\n *\n * The kit's own calls go out through `fetch` and never reach an Angular\n * interceptor, so without this an app querying its own collections had to\n * attach the bearer token by hand at every call site.\n *\n * **Only requests to `apiBaseUrl` are touched.** The token is a credential:\n * attaching it to every outgoing request would hand it to any third-party host\n * the app happens to call. Requests elsewhere pass through untouched — they\n * still get the 401 handling, which is about the session and not the target.\n *\n * An `Authorization` header already on the request is left alone, so a call\n * that needs different credentials can say so.\n */\nexport const rhAuthInterceptor: HttpInterceptorFn = (\n req: HttpRequest<unknown>,\n next: HttpHandlerFn\n) => {\n const auth = inject(RhAuthService);\n const config = inject(RH_AUTH_CONFIG);\n\n // A 401 on the kit's own endpoints does not always mean the session is dead\n // — change-password and token answer 401 for wrong *supplied* credentials —\n // and the kit already handles those. Clearing here would sign a user out for\n // mistyping their old password.\n const ownsIts401s = req.context.get(RH_KIT_REQUEST);\n\n const onError = (source: Observable<unknown>) =>\n source.pipe(\n catchError((err: unknown) => {\n if (!ownsIts401s && err instanceof HttpErrorResponse && err.status === 401) {\n clearToken();\n cancelRefresh();\n auth.clearSession();\n }\n return throwError(() => err);\n })\n );\n\n if (!req.url.startsWith(config.apiBaseUrl)) {\n return next(req).pipe(onError) as ReturnType<HttpHandlerFn>;\n }\n\n const withCredentials = (token: string | null) =>\n next(\n req.clone({\n setHeaders: {\n ...(token && !req.headers.has('Authorization')\n ? { Authorization: `Bearer ${token}` }\n : {}),\n // Suppress RESTHeart's WWW-Authenticate challenge on a 401 —\n // without it the browser shows its native Basic Auth popup.\n ...(req.headers.has('No-Auth-Challenge') ? {} : { 'No-Auth-Challenge': 'true' }),\n },\n // Matches the kit's own `credentials: 'include'`, so a cookie-mode\n // session authenticates these requests too.\n withCredentials: true,\n })\n ).pipe(onError) as ReturnType<HttpHandlerFn>;\n\n const token = readToken(config);\n return isPromise(token)\n ? (from(token).pipe(switchMap(withCredentials)) as ReturnType<HttpHandlerFn>)\n : withCredentials(token);\n};\n","import {\n HttpClient,\n HttpContext,\n HttpErrorResponse,\n HttpHeaders,\n HttpResponse,\n} from '@angular/common/http';\nimport { firstValueFrom } from 'rxjs';\nimport type { AuthConfig } from '@ulabase/kit';\nimport { RH_KIT_REQUEST } from './tokens.js';\n\n/** Statuses the Fetch spec forbids a body on — `new Response(body, …)` throws. */\nconst NULL_BODY_STATUS = new Set([101, 103, 204, 205, 304]);\n\nfunction toHttpHeaders(source: HeadersInit | undefined): HttpHeaders {\n let headers = new HttpHeaders();\n new Headers(source).forEach((value, name) => {\n headers = headers.set(name, value);\n });\n return headers;\n}\n\nfunction toHeaders(source: HttpHeaders): Headers {\n const headers = new Headers();\n for (const name of source.keys()) {\n for (const value of source.getAll(name) ?? []) {\n headers.append(name, value);\n }\n }\n return headers;\n}\n\nfunction toResponse(body: string | null, status: number, statusText: string, headers: HttpHeaders): Response {\n return new Response(NULL_BODY_STATUS.has(status) ? null : body, {\n status,\n statusText,\n headers: toHeaders(headers),\n });\n}\n\n/**\n * A {@link AuthConfig.transport} backed by Angular's `HttpClient`, so the kit's\n * own calls go through the interceptor chain like everything else the\n * application sends.\n *\n * Without it the kit speaks `fetch` directly and an interceptor never sees a\n * login, a session check or a token renewal — which makes any cross-cutting\n * concern written as an interceptor quietly partial.\n *\n * Two mismatches with `fetch` are reconciled here:\n *\n * - **`HttpClient` throws on a non-2xx response.** `fetch` resolves and lets\n * the caller read the status, which is what the core does to build its\n * `ApiError`. So an `HttpErrorResponse` carrying a real response is turned\n * back into a resolved `Response`.\n * - **`status === 0` is not a response**, it is a network or CORS failure with\n * nothing behind it. `new Response` would reject the status anyway, so the\n * original error is rethrown and surfaces as a rejected promise, exactly as\n * a failed `fetch` would.\n *\n * The body is read as text and left unparsed: the core calls `.json()` itself,\n * and on an error response it needs the raw body to pull out the message.\n */\nexport function httpClientTransport(http: HttpClient) {\n return (url: string, init?: RequestInit): Promise<Response> => {\n const request = firstValueFrom(\n http.request(init?.method ?? 'GET', url, {\n body: init?.body ?? null,\n headers: toHttpHeaders(init?.headers as HeadersInit | undefined),\n observe: 'response',\n responseType: 'text',\n // The kit handles 401s on its own endpoints; see RH_KIT_REQUEST.\n context: new HttpContext().set(RH_KIT_REQUEST, true),\n // Mirrors the core's `credentials: 'include'` — cookie-mode sessions\n // authenticate on the cookie alone.\n withCredentials: true,\n })\n );\n\n return request.then(\n (res: HttpResponse<string>) => toResponse(res.body, res.status, res.statusText, res.headers),\n (err: unknown) => {\n if (err instanceof HttpErrorResponse && err.status !== 0) {\n const body = typeof err.error === 'string' ? err.error : JSON.stringify(err.error ?? null);\n return toResponse(body, err.status, err.statusText, err.headers);\n }\n throw err;\n }\n );\n };\n}\n","import { EnvironmentProviders, inject, makeEnvironmentProviders } from '@angular/core';\nimport { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';\nimport type { AuthConfig } from '@ulabase/kit';\nimport { RH_AUTH_CONFIG } from './tokens.js';\nimport { rhAuthInterceptor } from './auth.interceptor.js';\nimport { httpClientTransport } from './http-transport.js';\n\nexport function provideRhAuth(config: AuthConfig): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideHttpClient(withInterceptors([rhAuthInterceptor])),\n {\n provide: RH_AUTH_CONFIG,\n // A factory, not a value, so the kit's own calls can be routed through\n // `HttpClient` — which does not exist yet when the caller builds the\n // config. An explicit `transport` is left alone, so an application can\n // still supply its own.\n useFactory: (): AuthConfig => ({\n ...config,\n transport: config.transport ?? httpClientTransport(inject(HttpClient)),\n }),\n },\n ]);\n}\n"],"mappings":";;;;;;;;AAIA,MAAa,iBAAiB,IAAI,eAA2B,gBAAgB;AAa7E,MAAa,iBAAiB,IAAI,uBAAgC,KAAK;ACVvE,IAAa,gBAAb,MAAa,cAAa;CACP,SAAqB,OAAO,cAAc;CAE1C,QAAQ,OAAwB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACrC,SAAS,OAAyB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAE7C,OAAO,KAAK,MAAM,WAAU;CAC5B,QAAQ,KAAK,OAAO,WAAU;CAC9B,kBAAkB,eAAe,KAAK,MAAK,MAAO,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,kBAAA,CAAA,+BAAA,CAAA,CAAA;CACvD,mBAAmB,eAAe,KAAK,OAAM,CAAE,CAAC,SAAS,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAQpE,eAAY;EAEV,IAAI,CAAC,IAAI,SAAQ,GAAI;GACnB,KAAK,MAAM,IAAI,IAAI;GACnB,KAAK,OAAO,IAAI,CAAA,CAAE;GAClB,OAAO,GAAG,IAAI;EAChB;EAEA,OAAO,KAAK,IAAI,aAAa,KAAK,MAAM,CAAC,CAAC,CAAC,KACzC,KAAI,MAAI;GACN,KAAK,MAAM,IAAI,CAAC;GAChB,IAAI,CAAC,GACH,KAAK,OAAO,IAAI,CAAA,CAAE;EAEtB,CAAC,GACD,WAAU,MACR,MAAM,OACF,GAAG,CAAA,CAAE,IACL,KAAK,IAAI,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,iBAAiB,GAAG,CAAA,CAAE,CAAC,CAAC,CAAC,GAEpE,KAAI,OAAM,KAAK,OAAO,IAAI,EAAE,CAAC,GAC7B,UAAU,KAAK,MAAK,CAAE,CAAC;CAE3B;CAEA,SAAS,SAOR;EACC,OAAO,KAAK,IAAI,SAAS,KAAK,QAAQ,OAAO,CAAC;CAChD;CAEA,OAAO,OAAe,OAAe,WAAkC,YAAU;EAC/E,OAAO,KAAK,IAAI,OAAO,KAAK,QAAQ,OAAO,OAAO,QAAQ,CAAC;CAC7D;CAEA,MAAM,OAAe,UAAkB,OAAkB,UAAQ;EAC/D,OAAO,KAAK,IAAI,MAAM,KAAK,QAAQ,OAAO,UAAU,IAAI,CAAC,CAAC,CAAC,KACzD,KAAI,MAAK,KAAK,MAAM,IAAI,CAAC,CAAC,GAC1B,WAAU,MACR,KAAK,IAAI,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAC9B,iBAAiB,GAAG,CAAA,CAAE,CAAC,GACvB,KAAI,OAAM,KAAK,OAAO,IAAI,EAAE,CAAC,GAC7B,UAAU,CAAC,CAAC,CACb,CACF;CAEL;CAEA,SAAM;EACJ,OAAO,KAAK,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,KACnC,UAAS;GACP,KAAK,MAAM,IAAI,IAAI;GACnB,KAAK,OAAO,IAAI,CAAA,CAAE;EACpB,CAAC,CAAC;CAEN;CAEA,OAAO,OAAe,MAAwB;EAC5C,OAAO,KAAK,IAAI,OAAO,KAAK,QAAQ,OAAO,IAAI,CAAC;CAClD;CAEA,cAAc,OAAe,OAAa;EACxC,OAAO,KAAK,IAAI,cAAc,KAAK,QAAQ,OAAO,KAAK,CAAC;CAC1D;CAEA,SAAS,SAA6D,OAAkB,UAAQ;EAC9F,OAAO,KAAK,IAAI,SAAS,KAAK,QAAQ,SAAS,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,MAAS,CAAC;CACjF;CAEA,aAAa,OAAa;EACxB,OAAO,KAAK,IAAI,aAAa,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,KAChD,gBACE,KAAK,IAAI,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAC9B,iBAAiB,GAAG,CAAA,CAAE,CAAC,GACvB,KAAI,OAAM,KAAK,OAAO,IAAI,EAAE,CAAC,CAAC,CAC/B,GAEH,UAAU,MAAS,CAAC;CAExB;CAEA,aAAa,OAAa;EACxB,OAAO,KAAK,IAAI,aAAa,KAAK,QAAQ,KAAK,CAAC;CAClD;CAEA,kBAAe;EACb,OAAO,KAAK,IAAI,gBAAgB,KAAK,MAAM,CAAC;CAC9C;CAEA,YAAS;EACP,OAAO,KAAK,IAAI,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KACrC,KAAI,OAAM,KAAK,OAAO,IAAI,EAAE,CAAC,CAAC;CAElC;CAEA,WAAW,QAA0B,OAAkB,UAAQ;EAC7D,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,QAAQ,IAAI,CAAC,CAAC,CAAC,KACrD,gBAAgB,KAAK,aAAY,CAAE,GACnC,UAAU,MAAS,CAAC;CAExB;CAEA,eAAY;EACV,IAAI,WAAU;EACd,IAAI,cAAa;EACjB,KAAK,MAAM,IAAI,IAAI;EACnB,KAAK,OAAO,IAAI,CAAA,CAAE;CACpB;CAEA,eAAe,OAAa;EAC1B,OAAO,KAAK,IAAI,eAAe,KAAK,QAAQ,KAAK,CAAC;CACpD;CAEA,cAAc,SAA6D,OAAkB,UAAQ;EACnG,OAAO,KAAK,IAAI,cAAc,KAAK,QAAQ,SAAS,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,MAAS,CAAC;CACtF;CAIA,kBAAe;EACb,OAAO,KAAK,IAAI,gBAAgB,KAAK,MAAM,CAAC;CAC9C;CAEA,aAAa,OAAa;EACxB,OAAO,KAAK,IAAI,aAAa,KAAK,QAAQ,KAAK,CAAC;CAClD;CAEA,iBAAiB,OAAe,MAAwB;EACtD,OAAO,KAAK,IAAI,iBAAiB,KAAK,QAAQ,OAAO,IAAI,CAAC;CAC5D;CAIA,WAAW,UAAgB;EACzB,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,QAAQ,CAAC;CACnD;CAEA,WAAW,SAAgD;EACzD,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,OAAO,CAAC;CAClD;CAEA,aAAU;EACR,OAAO,KAAK,IAAI,WAAW,KAAK,MAAM,CAAC;CACzC;CAIA,cAAc,SAAkD;EAC9D,OAAO,KAAK,IAAI,cAAc,KAAK,QAAQ,OAAO,CAAC,CAAC,CAAC,KACnD,gBAAgB,KAAK,aAAY,CAAE,GACnC,UAAU,MAAS,CAAC;CAExB;CAEA,eAAe,iBAAyB,aAAmB;EACzD,OAAO,KAAK,IAAI,eAAe,KAAK,QAAQ,iBAAiB,WAAW,CAAC;CAC3E;CAEA,WAAW,OAAe,SAAgC;EACxD,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,OAAO,OAAO,CAAC;CACzD;CAQA,eAAe,MAAgC,OAAkB,UAAQ;EAIvE,MAAM,SAAS,KAAK,MAAK,CAAE,EAAE,OAAQ,IAAI,eAAc,CAAE,GAAG;EAC5D,IAAI,CAAC,QACH,OAAO,kBAAkB;GAAE,QAAQ;GAAG,SAAS;EAA0C,EAAG;EAE9F,OAAO,KAAK,IAAI,eAAe,KAAK,QAAQ,QAAQ,MAAM,IAAI,CAAC,CAAC,CAAC,KAC/D,KAAI,MAAK,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC;CAE/B;CAGA,WAAW,OAAkB,UAAQ;EACnC,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,IAAI,CAAC;CAC/C;CAyBA,IAAI,MAAc,MAAkB;EAClC,OAAO,KAAK,IAAI,SAAS,KAAK,QAAQ,MAAM,IAAI,CAAC;CACnD;CAzOW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAb,OAAA,QAAA,GAAA,sBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,YADA;CAAM,CAAA;;AACnB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAa,YAAA,CAAA;EADzB,MAAA;EAAW,MAAA,CAAA,EAAE,YAAY,OAAM,CAAE;;;AC0BlC,IAAa,oBAAb,MAAa,kBAAiB;CACX,SAAqB,OAAO,cAAc;CAC1C,OAAO,OAAO,aAAa;CAE3B,gBAAgB,OAA4B,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAEzD,eAAe,KAAK,cAAc,WAAU;CAC5C,OAAO,eAAe,KAAK,cAAa,CAAE,EAAE,QAAQ,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACzD,eAAe,eAAe,KAAK,cAAa,CAAE,EAAE,UAAU,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CACpE,mBAAmB,eACpB,KAAK,KAAK,KAAI,CAAE,EAAE,MAAM,UAAU,KAAK,OAAO,iBAAiB,UACtE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CACQ,iBAAiB,eAAe,KAAK,cAAa,CAAE,EAAE,OAAO,aAAa,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAavE,UAAU,eAAc;EACvC,MAAM,OAAO,KAAK,KAAK,KAAI;EAC3B,OAAO,OAAQ,KAAK,MAAM,KAAK,QAAQ,KAAM;CAC/C,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAEF,IAAY,kBAAe;EACzB,OAAO,KAAK,OAAO,aAAa;CAClC;CAEA,cAAA;EACE,IAAI,KAAK,iBACP,aAAY;GACV,MAAM,UAAU,KAAK,QAAO;GAC5B,gBAAe;IACb,IAAI,YAAY,MACd,KAAK,cAAc,IAAI,IAAI;SAE3B,KAAK,iBAAgB,CAAE,CAAC,UAAS;GAErC,CAAC;EACH,CAAC;CAEL;CAGA,mBAAgB;EACd,IAAI,CAAC,KAAK,iBAAiB,OAAO,GAAG,IAAI;EACzC,OAAO,KAAK,IAAI,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,KAC5C,KAAI,QAAO,KAAK,cAAc,IAAI,GAAG,CAAC,GACtC,iBAAgB;GACd,KAAK,cAAc,IAAI,IAAI;GAC3B,OAAO,GAAG,IAAI;EAChB,CAAC,CAAC;CAEN;CAGA,WAAQ;EACN,OAAO,KAAK,IAAI,SAAS,KAAK,MAAM,CAAC;CACvC;CAQA,sBAAsB,MAAc,UAA0B;EAC5D,OAAO,KAAK,IAAI,sBAAsB,KAAK,QAAQ,MAAM,QAAQ,CAAC;CACpE;CAGA,oBAAiB;EACf,OAAO,KAAK,IAAI,kBAAkB,KAAK,MAAM,CAAC;CAChD;CAGA,cAAW;EACT,OAAO,KAAK,IAAI,YAAY,KAAK,MAAM,CAAC;CAC1C;CAMA,aAAa,QAAc;EACzB,OAAO,KAAK,IAAI,aAAa,KAAK,QAAQ,MAAM,CAAC;CACnD;CAGA,cAAc,QAAc;EAC1B,OAAO,KAAK,IAAI,cAAc,KAAK,QAAQ,MAAM,CAAC;CACpD;CAGA,WAAW,MAAmB;EAC5B,OAAO,KAAK,IAAI,WAAW,KAAK,QAAQ,IAAI,CAAC;CAC/C;CAOA,YACE,OACA,OACA,YAAmB;EAEnB,OAAO,KAAK,IAAI,YAAY,KAAK,QAAQ,OAAO,OAAO,UAAU,CAAC;CACpE;CAGA,SAAS,IAAY,QAAiB,YAAmB;EACvD,OAAO,KAAK,IAAI,SAAS,KAAK,QAAQ,IAAI,QAAQ,UAAU,CAAC;CAC/D;CAWA,oBACE,WACA,MAAkB;EAElB,OAAO,KACL,IAAI,oBAAoB,KAAK,QAAQ,WAAW,IAAI,CAAC,CAAC,MAAK,QAAM;GAC/D,KAAK,cAAc,IAAI,GAAG;GAC1B,OAAO;EACT,CAAC,CAAC;CAEN;CAUA,aACE,IACA,QACA,MAA4C;EAE5C,OAAO,KAAK,IAAI,aAAa,KAAK,QAAQ,IAAI,QAAQ,IAAI,CAAC;CAC7D;CA7JW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAiB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAjB,OAAA,QAAA,GAAA,sBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAiB,YADJ;CAAM,CAAA;;AACnB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAD7B,MAAA;EAAW,MAAA,CAAA,EAAE,YAAY,OAAM,CAAE;;;;ACPlC,MAAa,sBAAsB,IAAI,eAAuB,uBAAuB;CACnF,YAAY;CACZ,eAAe;AAChB,CAAA;AAiBD,IAAa,gBAAb,MAAa,cAAa;CACP,aAAa,OAAO,mBAAmB;CAGvC,SAAS,OAAmB,SAAS,KAAK,UAAU,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAG9D,QAAQ,KAAK,OAAO,WAAU;CAEtB,SAAS,eAAe,WAAW,KAAK,OAAM,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAG1D,aAAa,eAAe,KAAK,OAAM,CAAE,CAAC,YAAW,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAErD,WAAW,eAAe,KAAK,OAAM,CAAE,CAAC,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEjD,WAAW,eAAe,KAAK,OAAM,CAAE,CAAC,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEjD,aAAa,eAAe,aAAa,KAAK,OAAM,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAGjE,IAAI,MAAgB,WAAW,GAAC;EAC9B,KAAK,OAAM,YAAW,UAAU,SAAS,MAAM,QAAQ,CAAC;CAC1D;CAGA,YAAY,WAAmB,UAAgB;EAC7C,KAAK,OAAM,YAAW,gBAAgB,SAAS,WAAW,QAAQ,CAAC;CACrE;CAEA,OAAO,WAAiB;EACtB,KAAK,OAAM,YAAW,eAAe,SAAS,SAAS,CAAC;CAC1D;CAEA,QAAK;EACH,KAAK,YAAY,CAAA,CAAE;CACrB;CASQ,MAAM,MAAyC;EACrD,MAAM,UAAU,KAAK,KAAK,OAAM,CAAE;EAClC,SAAS,SAAS,KAAK,UAAU;EACjC,KAAK,OAAO,IAAI,OAAO;CACzB;CAjDW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAb,OAAA,QAAA,GAAA,sBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAa,YADA;CAAM,CAAA;;AACnB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAa,YAAA,CAAA;EADzB,MAAA;EAAW,MAAA,CAAA,EAAE,YAAY,OAAM,CAAE;;;ACtClC,MAAa,kBAAgC;CAC3C,MAAM,OAAO,OAAO,aAAa;CACjC,MAAM,SAAS,OAAO,MAAM;CAE5B,IAAI,KAAK,gBAAe,GAAI,OAAO;CAEnC,OAAO,KAAK,aAAY,CAAE,CAAC,KACzB,KAAI,SAAQ,SAAS,IAAI,GACzB,KAAI,OAAK;EAAG,IAAI,CAAC,IAAI,OAAO,SAAS,CAAC,aAAa,CAAC;CAAG,CAAC,CAAC;AAE7D;AAEA,MAAa,oBAAkC;CAC7C,MAAM,OAAO,OAAO,aAAa;CACjC,MAAM,SAAS,OAAO,MAAM;CAE5B,IAAI,CAAC,KAAK,gBAAe,GAAI,OAAO;CAEpC,OAAO,KAAK,aAAY,CAAE,CAAC,KACzB,KAAI,SAAQ,SAAS,IAAI,GACzB,KAAI,aAAW;EAAG,IAAI,CAAC,UAAU,OAAO,SAAS,CAAC,GAAG,CAAC;CAAG,CAAC,CAAC;AAE/D;ACbA,SAAS,UAAU,QAAkB;CACnC,OAAO,OAAO,WAAW,OAAO,SAAQ,IAAK,SAAQ;AACvD;AAEA,SAAS,UAAa,GAAiB;CACrC,OAAO,OAAQ,GAAkB,SAAS;AAC5C;AAkBA,MAAa,qBACX,KACA,SACE;CACF,MAAM,OAAO,OAAO,aAAa;CACjC,MAAM,SAAS,OAAO,cAAc;CAMpC,MAAM,cAAc,IAAI,QAAQ,IAAI,cAAc;CAElD,MAAM,WAAW,WACf,OAAO,KACL,YAAY,QAAgB;EAC1B,IAAI,CAAC,eAAe,eAAe,qBAAqB,IAAI,WAAW,KAAK;GAC1E,WAAU;GACV,cAAa;GACb,KAAK,aAAY;EACnB;EACA,OAAO,iBAAiB,GAAG;CAC7B,CAAC,CAAC;CAGN,IAAI,CAAC,IAAI,IAAI,WAAW,OAAO,UAAU,GACvC,OAAO,KAAK,GAAG,CAAC,CAAC,KAAK,OAAO;CAG/B,MAAM,mBAAmB,UACvB,KACE,IAAI,MAAM;EACR,YAAY;GACV,GAAI,SAAS,CAAC,IAAI,QAAQ,IAAI,eAAe,IACzC,EAAE,eAAe,UAAU,QAAO,IAClC,CAAA;GAGJ,GAAI,IAAI,QAAQ,IAAI,mBAAmB,IAAI,CAAA,IAAK,EAAE,qBAAqB,OAAM;EAC9E;EAGD,iBAAiB;CAClB,CAAA,CAAC,CACH,CAAC,KAAK,OAAO;CAEhB,MAAM,QAAQ,UAAU,MAAM;CAC9B,OAAO,UAAU,KAAK,IACjB,KAAK,KAAK,CAAC,CAAC,KAAK,UAAU,eAAe,CAAC,IAC5C,gBAAgB,KAAK;AAC3B;AC5EA,MAAM,mCAAmB,IAAI,IAAI;CAAC;CAAK;CAAK;CAAK;CAAK;AAAG,CAAC;AAE1D,SAAS,cAAc,QAA+B;CACpD,IAAI,UAAU,IAAI,YAAW;CAC7B,IAAI,QAAQ,MAAM,CAAC,CAAC,SAAS,OAAO,SAAQ;EAC1C,UAAU,QAAQ,IAAI,MAAM,KAAK;CACnC,CAAC;CACD,OAAO;AACT;AAEA,SAAS,UAAU,QAAmB;CACpC,MAAM,UAAU,IAAI,QAAO;CAC3B,KAAK,MAAM,QAAQ,OAAO,KAAI,GAC5B,KAAK,MAAM,SAAS,OAAO,OAAO,IAAI,KAAK,CAAA,GACzC,QAAQ,OAAO,MAAM,KAAK;CAG9B,OAAO;AACT;AAEA,SAAS,WAAW,MAAqB,QAAgB,YAAoB,SAAoB;CAC/F,OAAO,IAAI,SAAS,iBAAiB,IAAI,MAAM,IAAI,OAAO,MAAM;EAC9D;EACA;EACA,SAAS,UAAU,OAAO;CAC3B,CAAA;AACH;AAyBA,SAAgB,oBAAoB,MAAgB;CAClD,QAAQ,KAAa,SAAyC;EAe5D,OAdgB,eACd,KAAK,QAAQ,MAAM,UAAU,OAAO,KAAK;GACvC,MAAM,MAAM,QAAQ;GACpB,SAAS,cAAc,MAAM,OAAkC;GAC/D,SAAS;GACT,cAAc;GAEd,SAAS,IAAI,YAAW,CAAE,CAAC,IAAI,gBAAgB,IAAI;GAGnD,iBAAiB;EAClB,CAAA,CAGI,CAAA,CAAQ,MACZ,QAA8B,WAAW,IAAI,MAAM,IAAI,QAAQ,IAAI,YAAY,IAAI,OAAO,IAC1F,QAAgB;GACf,IAAI,eAAe,qBAAqB,IAAI,WAAW,GAErD,OAAO,WADM,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ,KAAK,UAAU,IAAI,SAAS,IAAI,GACjE,IAAI,QAAQ,IAAI,YAAY,IAAI,OAAO;GAEjE,MAAM;EACR,CAAC;CAEL;AACF;ACnFA,SAAgB,cAAc,QAAkB;CAC9C,OAAO,yBAAyB,CAC9B,kBAAkB,iBAAiB,CAAC,iBAAiB,CAAC,CAAC,GACvD;EACE,SAAS;EAKT,mBAA+B;GAC7B,GAAG;GACH,WAAW,OAAO,aAAa,oBAAoB,OAAO,UAAU,CAAC;EACtE;CACF,CACF,CAAA;AACH"}
1
+ {"version":3,"file":"ulabase-kit-ng.mjs","names":[],"sources":["../../src/tokens.ts","../../src/auth.service.ts","../../src/payments.service.ts","../../src/cart.service.ts","../../src/auth.guard.ts","../../src/auth.interceptor.ts","../../src/http-transport.ts","../../src/provide-rh-auth.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { HttpContextToken } from '@angular/common/http';\nimport type { AuthConfig } from '@ulabase/kit';\n\nexport const RH_AUTH_CONFIG = new InjectionToken<AuthConfig>('RH_AUTH_CONFIG');\n\n\n/**\n * Marks a request as originating from the kit rather than from application\n * code. Set by `httpClientTransport`, read by `rhAuthInterceptor`.\n *\n * The kit owns the meaning of a 401 on its own endpoints, and that meaning is\n * not always \"the session is dead\": `PATCH /auth/change-password` answers 401\n * when the *current password* is wrong, and `GET /token` when the credentials\n * are. Letting the interceptor clear the session on those would sign a user\n * out for mistyping their old password.\n */\nexport const RH_KIT_REQUEST = new HttpContextToken<boolean>(() => false);\n","import { Injectable, computed, inject, signal } from '@angular/core';\nimport { Observable, catchError, from, map, of, switchMap, tap, throwError } from 'rxjs';\nimport type { UserInfo, TeamMembership, TeamMember, PendingInvitation, AuthConfig, LoginMode } from '@ulabase/kit';\nimport * as kit from '@ulabase/kit';\nimport { RH_AUTH_CONFIG } from './tokens.js';\n\n@Injectable({ providedIn: 'root' })\nexport class RhAuthService {\n private readonly config: AuthConfig = inject(RH_AUTH_CONFIG);\n\n private readonly _user = signal<UserInfo | null>(null);\n private readonly _teams = signal<TeamMembership[]>([]);\n\n readonly user = this._user.asReadonly();\n readonly teams = this._teams.asReadonly();\n readonly isAuthenticated = computed(() => this._user() !== null);\n readonly hasMultipleTeams = computed(() => this._teams().length > 1);\n\n /**\n * Check the current session state.\n *\n * Reads the token from localStorage — if present and not expired,\n * returns user info from the server. Otherwise returns null.\n */\n checkSession(): Observable<UserInfo | null> {\n // If no valid token in localStorage, we're logged out — no HTTP call needed\n if (!kit.getToken()) {\n this._user.set(null);\n this._teams.set([]);\n return of(null);\n }\n\n return from(kit.checkSession(this.config)).pipe(\n tap(u => {\n this._user.set(u);\n if (!u) {\n this._teams.set([]);\n }\n }),\n switchMap(u =>\n u === null\n ? of([])\n : from(kit.getTeams(this.config)).pipe(catchError(() => of([])))\n ),\n tap(ts => this._teams.set(ts)),\n map(() => this._user())\n );\n }\n\n register(payload: {\n email: string;\n password: string;\n teamName: string;\n firstName: string;\n lastName: string;\n [key: string]: unknown;\n }): Observable<void> {\n return from(kit.register(this.config, payload));\n }\n\n verify(email: string, token: string, delivery: 'cookie' | 'fragment' = 'fragment'): Observable<string> {\n return from(kit.verify(this.config, email, token, delivery));\n }\n\n login(email: string, password: string, mode: LoginMode = 'bearer'): Observable<UserInfo> {\n return from(kit.login(this.config, email, password, mode)).pipe(\n tap(u => this._user.set(u)),\n switchMap(u =>\n from(kit.getTeams(this.config)).pipe(\n catchError(() => of([])),\n tap(ts => this._teams.set(ts)),\n map(() => u)\n )\n )\n );\n }\n\n logout(mode: LoginMode = 'bearer'): Observable<void> {\n return from(kit.logout(this.config, mode)).pipe(\n tap(() => {\n this._user.set(null);\n this._teams.set([]);\n })\n );\n }\n\n invite(email: string, role: 'owner' | 'member'): Observable<void> {\n return from(kit.invite(this.config, email, role));\n }\n\n getInvitation(email: string, token: string) {\n return from(kit.getInvitation(this.config, email, token));\n }\n\n activate(payload: { email: string; token: string; password: string }, mode: LoginMode = 'bearer'): Observable<void> {\n return from(kit.activate(this.config, payload, mode)).pipe(map(() => undefined));\n }\n\n acceptInvite(token: string): Observable<void> {\n return from(kit.acceptInvite(this.config, token)).pipe(\n switchMap(() =>\n from(kit.getTeams(this.config)).pipe(\n catchError(() => of([])),\n tap(ts => this._teams.set(ts))\n )\n ),\n map(() => undefined)\n );\n }\n\n resendInvite(email: string): Observable<void> {\n return from(kit.resendInvite(this.config, email));\n }\n\n listInvitations(): Observable<PendingInvitation[]> {\n return from(kit.listInvitations(this.config));\n }\n\n loadTeams(): Observable<TeamMembership[]> {\n return from(kit.getTeams(this.config)).pipe(\n tap(ts => this._teams.set(ts))\n );\n }\n\n switchTeam(teamId: { $oid: string }, mode: LoginMode = 'bearer'): Observable<void> {\n return from(kit.switchTeam(this.config, teamId, mode)).pipe(\n switchMap(() => this.checkSession()),\n map(() => undefined)\n );\n }\n\n clearSession(): void {\n kit.clearToken();\n kit.cancelRefresh();\n this._user.set(null);\n this._teams.set([]);\n }\n\n forgotPassword(email: string): Observable<void> {\n return from(kit.forgotPassword(this.config, email));\n }\n\n resetPassword(payload: { email: string; token: string; password: string }, mode: LoginMode = 'bearer'): Observable<void> {\n return from(kit.resetPassword(this.config, payload, mode)).pipe(map(() => undefined));\n }\n\n // ── Team members ─────────────────────────────────────────────────────────\n\n listTeamMembers(): Observable<TeamMember[]> {\n return from(kit.listTeamMembers(this.config));\n }\n\n removeMember(email: string): Observable<void> {\n return from(kit.removeMember(this.config, email));\n }\n\n updateMemberRole(email: string, role: 'owner' | 'member'): Observable<void> {\n return from(kit.updateMemberRole(this.config, email, role));\n }\n\n // ── Team lifecycle ───────────────────────────────────────────────────────\n\n createTeam(teamName: string): Observable<TeamMembership> {\n return from(kit.createTeam(this.config, teamName));\n }\n\n updateTeam(updates: { name?: string; description?: string }): Observable<void> {\n return from(kit.updateTeam(this.config, updates));\n }\n\n deleteTeam(): Observable<void> {\n return from(kit.deleteTeam(this.config));\n }\n\n // ── Profile & password ──────────────────────────────────────────────────\n\n updateProfile(updates: { firstName?: string; lastName?: string }): Observable<void> {\n return from(kit.updateProfile(this.config, updates)).pipe(\n switchMap(() => this.checkSession()),\n map(() => undefined)\n );\n }\n\n changePassword(currentPassword: string, newPassword: string): Observable<void> {\n return from(kit.changePassword(this.config, currentPassword, newPassword));\n }\n\n updateUser(email: string, updates: Record<string, unknown>): Observable<void> {\n return from(kit.updateUser(this.config, email, updates));\n }\n\n // ── Consents ────────────────────────────────────────────────────────────\n\n /**\n * Record the signed-in user's acceptance of the application's consents,\n * renew the token so the guard sees it, and update the `user` signal.\n */\n acceptConsents(body?: Record<string, unknown>, mode: LoginMode = 'bearer'): Observable<UserInfo> {\n // The user document may be missing precisely because the rule is blocking\n // `/users/me` — the case this call exists to get out of. The token still\n // says who they are.\n const userId = this._user()?._id ?? (kit.getTokenClaims()?.['sub'] as string | undefined);\n if (!userId) {\n return throwError(() => ({ status: 0, message: 'acceptConsents requires a signed-in user' }));\n }\n return from(kit.acceptConsents(this.config, userId, body, mode)).pipe(\n tap(u => this._user.set(u))\n );\n }\n\n /** Force a new token, carrying the user document as it is now. */\n renewToken(mode: LoginMode = 'bearer'): Observable<string | null> {\n return from(kit.renewToken(this.config, mode));\n }\n\n /**\n * An authenticated `fetch` against the service, returned as an Observable.\n *\n * The Angular counterpart of React's `auth.api()` — the bearer token is\n * attached automatically, and the request goes through the Angular\n * interceptor chain (when `httpClientTransport` is configured).\n *\n * ```ts\n * this.auth.api('/demo').pipe(\n * switchMap(res => res.json()),\n * ).subscribe(data => console.log(data));\n * ```\n *\n * For a POST:\n * ```ts\n * this.auth.api('/demo', {\n * method: 'POST',\n * body: JSON.stringify({ name: 'hello' }),\n * }).pipe(switchMap(res => res.json()));\n * ```\n *\n * Rejects with an `ApiError` (`{ status, message }`) on any non-2xx response.\n */\n api(path: string, init?: RequestInit): Observable<Response> {\n return from(kit.apiFetch(this.config, path, init));\n }\n}\n","import { Injectable, computed, effect, inject, signal, untracked } from '@angular/core';\nimport { Observable, catchError, from, of, tap } from 'rxjs';\nimport type {\n AuthConfig,\n CatalogItem,\n GrantLicenseResult,\n Licenses,\n Order,\n Plan,\n Subscription,\n WaitOptions,\n CatalogQuery,\n} from '@ulabase/kit';\nimport * as kit from '@ulabase/kit';\nimport { RH_AUTH_CONFIG } from './tokens.js';\nimport { RhAuthService } from './auth.service.js';\n\n/**\n * Subscription, billing and order management.\n *\n * Separated from {@link RhAuthService} because payments are not authentication.\n * Reads the current user from {@link RhAuthService} to derive\n * `canManageBilling`, but owns its own subscription state.\n *\n * Subscription is loaded automatically when the user signs in and reloaded\n * when they switch team (via an `effect` watching {@link teamKey}). No manual\n * wiring needed.\n *\n * Only active when `config.payments` is `true` — otherwise every method\n * is a no-op and no `/stripe/*` call is ever made.\n */\n@Injectable({ providedIn: 'root' })\nexport class RhPaymentsService {\n private readonly config: AuthConfig = inject(RH_AUTH_CONFIG);\n private readonly auth = inject(RhAuthService);\n\n private readonly _subscription = signal<Subscription | null>(null);\n\n readonly subscription = this._subscription.asReadonly();\n readonly plan = computed(() => this._subscription()?.plan ?? null);\n readonly isSubscribed = computed(() => this._subscription()?.active ?? false);\n readonly canManageBilling = computed(\n () => this.auth.user()?.team?.role === (this.config.ownershipRole ?? 'owner')\n );\n readonly seatsAvailable = computed(() => this._subscription()?.seats?.available ?? null);\n\n /**\n * The team the subscription belongs to: `null` when signed out, `''` for a\n * signed-in user with no team.\n *\n * The effect below tracks this rather than `auth.user()` itself. Both\n * `updateProfile` and `acceptConsents` re-run `checkSession`, which replaces\n * the user with a freshly parsed document — tracking that object's identity\n * would reload the subscription on every profile edit and consent\n * acceptance, which the adapter contract rules out. A subscription changes\n * with the team, not with the profile.\n */\n private readonly teamKey = computed(() => {\n const user = this.auth.user();\n return user ? (user.team?._id?.$oid ?? '') : null;\n });\n\n private get paymentsEnabled(): boolean {\n return this.config.payments === true;\n }\n\n constructor() {\n if (this.paymentsEnabled) {\n effect(() => {\n const teamKey = this.teamKey();\n untracked(() => {\n if (teamKey === null) {\n this._subscription.set(null);\n } else {\n this.loadSubscription().subscribe();\n }\n });\n });\n }\n }\n\n /** Reload the team's subscription. No-op when `config.payments` is not `true`. */\n loadSubscription(): Observable<Subscription | null> {\n if (!this.paymentsEnabled) return of(null);\n return from(kit.getSubscription(this.config)).pipe(\n tap(sub => this._subscription.set(sub)),\n catchError(() => {\n this._subscription.set(null);\n return of(null);\n })\n );\n }\n\n /** The service's subscription plan catalog. No session required. */\n getPlans(): Observable<{ default_plan: string; plans: Plan[] }> {\n return from(kit.getPlans(this.config));\n }\n\n /**\n * Start a Stripe Checkout session.\n *\n * **Rejects with `status: 409`** when the team already has an active\n * subscription — send them to {@link openBillingPortal} instead.\n */\n createCheckoutSession(plan: string, interval: 'month' | 'year'): Observable<{ url: string }> {\n return from(kit.createCheckoutSession(this.config, plan, interval));\n }\n\n /** Open the Stripe Customer Portal for self-service plan changes. */\n openBillingPortal(): Observable<{ url: string }> {\n return from(kit.openBillingPortal(this.config));\n }\n\n /** The team's seat licences. Requires `canManageBilling`. */\n getLicenses(): Observable<Licenses> {\n return from(kit.getLicenses(this.config));\n }\n\n /**\n * Grant a seat licence. Returns `'granted'` or `'already-licensed'`.\n * Rejects with `status: 409` when no seat is available.\n */\n grantLicense(userId: string): Observable<GrantLicenseResult> {\n return from(kit.grantLicense(this.config, userId));\n }\n\n /** Revoke a seat licence. */\n revokeLicense(userId: string): Observable<void> {\n return from(kit.revokeLicense(this.config, userId));\n }\n\n /** Read the product catalog. */\n getCatalog(opts?: CatalogQuery): Observable<CatalogItem[]> {\n return from(kit.getCatalog(this.config, opts));\n }\n\n /**\n * Create an order and start Checkout.\n *\n * @param email Required for guest checkout.\n */\n createOrder(\n items: { productId: string; quantity: number }[],\n email?: string,\n collection?: string\n ): Observable<{ _id: { $oid: string }; checkout_url: string; secret: string }> {\n return from(kit.createOrder(this.config, items, email, collection));\n }\n\n /** Read an order back. */\n getOrder(id: string, secret?: string, collection?: string): Observable<Order> {\n return from(kit.getOrder(this.config, id, secret, collection));\n }\n\n /**\n * Poll until the subscription satisfies `predicate`.\n *\n * Use on the Checkout success page — the redirect back from Stripe races\n * the webhook, so a bare `getSubscription` can still show the old plan.\n *\n * **Timing out is not a payment failure.** Rejects with\n * `WaitTimeoutError` when the webhook hasn't arrived yet.\n */\n waitForSubscription(\n predicate: (subscription: Subscription) => boolean,\n opts?: WaitOptions\n ): Observable<Subscription> {\n return from(\n kit.waitForSubscription(this.config, predicate, opts).then(sub => {\n this._subscription.set(sub);\n return sub;\n })\n );\n }\n\n /**\n * Poll until the order leaves `'pending_payment'`.\n *\n * Same race as {@link waitForSubscription} — use on the order success page.\n *\n * **Timing out is not a payment failure.** Rejects with\n * `WaitTimeoutError` when the webhook hasn't arrived yet.\n */\n waitForOrder(\n id: string,\n secret?: string,\n opts?: WaitOptions & { collection?: string }\n ): Observable<Order> {\n return from(kit.waitForOrder(this.config, id, secret, opts));\n }\n}\n","import { Injectable, InjectionToken, computed, inject, signal } from '@angular/core';\nimport {\n addToCart,\n cartTotals,\n loadCart,\n removeFromCart,\n saveCart,\n setCartQuantity,\n toOrderItems,\n DEFAULT_CART_STORAGE_KEY,\n type CartItem,\n type CartLine,\n} from '@ulabase/kit';\n/**\n * Where {@link RhCartService} keeps the cart in `localStorage`. Defaults to `'rh-cart'`.\n *\n * Worth providing when two of your apps share an origin, which is one deployment decision away\n * from happening by accident.\n *\n * Declared here rather than in `tokens.ts`: that file is the authentication surface, and a cart\n * needs no session. Importing the kit into it to reach one constant also dragged the kit's module\n * into every spec that touches `RH_AUTH_CONFIG`, where it is auto-mocked — which shifted module\n * initialisation enough to make two unrelated guard tests fail, in CI only.\n */\nexport const RH_CART_STORAGE_KEY = new InjectionToken<string>('RH_CART_STORAGE_KEY', {\n providedIn: 'root',\n factory: () => DEFAULT_CART_STORAGE_KEY,\n});\n\n/**\n * The shopping cart.\n *\n * Independent of {@link import('./auth.service.js').RhAuthService | RhAuthService}\n * and of `RH_AUTH_CONFIG`: a cart belongs to the browser, not to a session, and\n * a shop that makes people sign in before they can put something in a basket\n * loses most of them there. It becomes an order — which does need a config —\n * when {@link RhCartService.orderItems} is handed to `createOrder`.\n *\n * On the server, `localStorage` does not exist and the cart reads as empty.\n * That is correct for a rendered page — a request carries no basket — but it\n * does mean a server-rendered cart count starts at zero and fills in once the\n * browser takes over.\n */\n@Injectable({ providedIn: 'root' })\nexport class RhCartService {\n private readonly storageKey = inject(RH_CART_STORAGE_KEY);\n\n // Declared after `storageKey` so the field is there: initializers run in order.\n private readonly _lines = signal<CartLine[]>(loadCart(this.storageKey));\n\n /** The lines, in the order they were added. */\n readonly lines = this._lines.asReadonly();\n\n private readonly totals = computed(() => cartTotals(this._lines()));\n\n /** Units, not lines: two of one thing counts two. */\n readonly totalItems = computed(() => this.totals().totalItems);\n /** Display only. Minor units, meaningful when every line shares a currency. */\n readonly subtotal = computed(() => this.totals().subtotal);\n /** The first line's currency, or `'eur'` when empty. */\n readonly currency = computed(() => this.totals().currency);\n /** The cart as `createOrder` wants it. */\n readonly orderItems = computed(() => toOrderItems(this._lines()));\n\n /** Adds an item, or increases the line already holding it. */\n add(item: CartItem, quantity = 1): void {\n this.apply(current => addToCart(current, item, quantity));\n }\n\n /** Sets a line's quantity. Zero removes it. */\n setQuantity(productId: string, quantity: number): void {\n this.apply(current => setCartQuantity(current, productId, quantity));\n }\n\n remove(productId: string): void {\n this.apply(current => removeFromCart(current, productId));\n }\n\n clear(): void {\n this.apply(() => []);\n }\n\n /**\n * State and storage move together, in the operation that changed them.\n *\n * Deliberately not an `effect` reacting to the signal: an effect runs after\n * the fact and can be skipped or reordered, and the failure that produces is\n * a line coming back from storage after somebody removed it.\n */\n private apply(next: (current: CartLine[]) => CartLine[]): void {\n const updated = next(this._lines());\n saveCart(updated, this.storageKey);\n this._lines.set(updated);\n }\n}\n","import { inject } from '@angular/core';\nimport { Router, type CanActivateFn } from '@angular/router';\nimport { map, tap } from 'rxjs';\nimport { RhAuthService } from './auth.service.js';\n\nexport const authGuard: CanActivateFn = () => {\n const auth = inject(RhAuthService);\n const router = inject(Router);\n\n if (auth.isAuthenticated()) return true;\n\n return auth.checkSession().pipe(\n map(user => user !== null),\n tap(ok => { if (!ok) router.navigate(['/auth/login']); })\n );\n};\n\nexport const publicGuard: CanActivateFn = () => {\n const auth = inject(RhAuthService);\n const router = inject(Router);\n\n if (!auth.isAuthenticated()) return true;\n\n return auth.checkSession().pipe(\n map(user => user === null),\n tap(isPublic => { if (!isPublic) router.navigate(['/']); })\n );\n};\n","import { inject } from '@angular/core';\nimport {\n HttpRequest,\n HttpHandlerFn,\n HttpInterceptorFn,\n HttpErrorResponse,\n} from '@angular/common/http';\nimport { Observable, catchError, from, switchMap, throwError } from 'rxjs';\nimport { RhAuthService } from './auth.service.js';\nimport { RH_AUTH_CONFIG, RH_KIT_REQUEST } from './tokens.js';\nimport { clearToken, cancelRefresh, getToken } from '@ulabase/kit';\nimport type { AuthConfig } from '@ulabase/kit';\n\n/** The token source is pluggable and may be async — keep the sync path sync. */\nfunction readToken(config: AuthConfig): string | null | Promise<string | null> {\n return config.getToken ? config.getToken() : getToken();\n}\n\nfunction isPromise<T>(v: T | Promise<T>): v is Promise<T> {\n return typeof (v as Promise<T>)?.then === 'function';\n}\n\n/**\n * Authenticates the application's own `HttpClient` requests, and clears the\n * session when the service rejects one with a 401.\n *\n * The kit's own calls go out through `fetch` and never reach an Angular\n * interceptor, so without this an app querying its own collections had to\n * attach the bearer token by hand at every call site.\n *\n * **Only requests to `apiBaseUrl` are touched.** The token is a credential:\n * attaching it to every outgoing request would hand it to any third-party host\n * the app happens to call. Requests elsewhere pass through untouched — they\n * still get the 401 handling, which is about the session and not the target.\n *\n * An `Authorization` header already on the request is left alone, so a call\n * that needs different credentials can say so.\n */\nexport const rhAuthInterceptor: HttpInterceptorFn = (\n req: HttpRequest<unknown>,\n next: HttpHandlerFn\n) => {\n const auth = inject(RhAuthService);\n const config = inject(RH_AUTH_CONFIG);\n\n // A 401 on the kit's own endpoints does not always mean the session is dead\n // — change-password and token answer 401 for wrong *supplied* credentials —\n // and the kit already handles those. Clearing here would sign a user out for\n // mistyping their old password.\n const ownsIts401s = req.context.get(RH_KIT_REQUEST);\n\n const onError = (source: Observable<unknown>) =>\n source.pipe(\n catchError((err: unknown) => {\n if (!ownsIts401s && err instanceof HttpErrorResponse && err.status === 401) {\n clearToken();\n cancelRefresh();\n auth.clearSession();\n }\n return throwError(() => err);\n })\n );\n\n if (!req.url.startsWith(config.apiBaseUrl)) {\n return next(req).pipe(onError) as ReturnType<HttpHandlerFn>;\n }\n\n const withCredentials = (token: string | null) =>\n next(\n req.clone({\n setHeaders: {\n ...(token && !req.headers.has('Authorization')\n ? { Authorization: `Bearer ${token}` }\n : {}),\n // Suppress RESTHeart's WWW-Authenticate challenge on a 401 —\n // without it the browser shows its native Basic Auth popup.\n ...(req.headers.has('No-Auth-Challenge') ? {} : { 'No-Auth-Challenge': 'true' }),\n },\n // Matches the kit's own `credentials: 'include'`, so a cookie-mode\n // session authenticates these requests too.\n withCredentials: true,\n })\n ).pipe(onError) as ReturnType<HttpHandlerFn>;\n\n const token = readToken(config);\n return isPromise(token)\n ? (from(token).pipe(switchMap(withCredentials)) as ReturnType<HttpHandlerFn>)\n : withCredentials(token);\n};\n","import {\n HttpClient,\n HttpContext,\n HttpErrorResponse,\n HttpHeaders,\n HttpResponse,\n} from '@angular/common/http';\nimport { firstValueFrom } from 'rxjs';\nimport type { AuthConfig } from '@ulabase/kit';\nimport { RH_KIT_REQUEST } from './tokens.js';\n\n/** Statuses the Fetch spec forbids a body on — `new Response(body, …)` throws. */\nconst NULL_BODY_STATUS = new Set([101, 103, 204, 205, 304]);\n\nfunction toHttpHeaders(source: HeadersInit | undefined): HttpHeaders {\n let headers = new HttpHeaders();\n new Headers(source).forEach((value, name) => {\n headers = headers.set(name, value);\n });\n return headers;\n}\n\nfunction toHeaders(source: HttpHeaders): Headers {\n const headers = new Headers();\n for (const name of source.keys()) {\n for (const value of source.getAll(name) ?? []) {\n headers.append(name, value);\n }\n }\n return headers;\n}\n\nfunction toResponse(body: string | null, status: number, statusText: string, headers: HttpHeaders): Response {\n return new Response(NULL_BODY_STATUS.has(status) ? null : body, {\n status,\n statusText,\n headers: toHeaders(headers),\n });\n}\n\n/**\n * A {@link AuthConfig.transport} backed by Angular's `HttpClient`, so the kit's\n * own calls go through the interceptor chain like everything else the\n * application sends.\n *\n * Without it the kit speaks `fetch` directly and an interceptor never sees a\n * login, a session check or a token renewal — which makes any cross-cutting\n * concern written as an interceptor quietly partial.\n *\n * Two mismatches with `fetch` are reconciled here:\n *\n * - **`HttpClient` throws on a non-2xx response.** `fetch` resolves and lets\n * the caller read the status, which is what the core does to build its\n * `ApiError`. So an `HttpErrorResponse` carrying a real response is turned\n * back into a resolved `Response`.\n * - **`status === 0` is not a response**, it is a network or CORS failure with\n * nothing behind it. `new Response` would reject the status anyway, so the\n * original error is rethrown and surfaces as a rejected promise, exactly as\n * a failed `fetch` would.\n *\n * The body is read as text and left unparsed: the core calls `.json()` itself,\n * and on an error response it needs the raw body to pull out the message.\n */\nexport function httpClientTransport(http: HttpClient) {\n return (url: string, init?: RequestInit): Promise<Response> => {\n const request = firstValueFrom(\n http.request(init?.method ?? 'GET', url, {\n body: init?.body ?? null,\n headers: toHttpHeaders(init?.headers as HeadersInit | undefined),\n observe: 'response',\n responseType: 'text',\n // The kit handles 401s on its own endpoints; see RH_KIT_REQUEST.\n context: new HttpContext().set(RH_KIT_REQUEST, true),\n // Mirrors the core's `credentials: 'include'` — cookie-mode sessions\n // authenticate on the cookie alone.\n withCredentials: true,\n })\n );\n\n return request.then(\n (res: HttpResponse<string>) => toResponse(res.body, res.status, res.statusText, res.headers),\n (err: unknown) => {\n if (err instanceof HttpErrorResponse && err.status !== 0) {\n const body = typeof err.error === 'string' ? err.error : JSON.stringify(err.error ?? null);\n return toResponse(body, err.status, err.statusText, err.headers);\n }\n throw err;\n }\n );\n };\n}\n","import { EnvironmentProviders, inject, makeEnvironmentProviders } from '@angular/core';\nimport { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';\nimport type { AuthConfig } from '@ulabase/kit';\nimport { RH_AUTH_CONFIG } from './tokens.js';\nimport { rhAuthInterceptor } from './auth.interceptor.js';\nimport { httpClientTransport } from './http-transport.js';\n\nexport function provideRhAuth(config: AuthConfig): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideHttpClient(withInterceptors([rhAuthInterceptor])),\n {\n provide: RH_AUTH_CONFIG,\n // A factory, not a value, so the kit's own calls can be routed through\n // `HttpClient` — which does not exist yet when the caller builds the\n // config. An explicit `transport` is left alone, so an application can\n // still supply its own.\n useFactory: (): AuthConfig => ({\n ...config,\n transport: config.transport ?? httpClientTransport(inject(HttpClient)),\n }),\n },\n ]);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulabase/kit-ng",
3
- "version": "0.13.1",
3
+ "version": "0.13.3",
4
4
  "description": "Angular services, route guards, and HTTP interceptor for Ulabase authentication and payments — wraps @ulabase/kit.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,7 +15,7 @@
15
15
  "rxjs": ">=7"
16
16
  },
17
17
  "dependencies": {
18
- "@ulabase/kit": "0.13.1",
18
+ "@ulabase/kit": "0.13.3",
19
19
  "tslib": "^2.3.0"
20
20
  },
21
21
  "module": "fesm2022/ulabase-kit-ng.mjs",
@@ -31,7 +31,7 @@ export declare class RhAuthService {
31
31
  }): Observable<void>;
32
32
  verify(email: string, token: string, delivery?: 'cookie' | 'fragment'): Observable<string>;
33
33
  login(email: string, password: string, mode?: LoginMode): Observable<UserInfo>;
34
- logout(): Observable<void>;
34
+ logout(mode?: LoginMode): Observable<void>;
35
35
  invite(email: string, role: 'owner' | 'member'): Observable<void>;
36
36
  getInvitation(email: string, token: string): Observable<kit.Invitation>;
37
37
  activate(payload: {