export { U as UiBootstrapConfig, a as UiBootstrapDiagnostic, b as UiBootstrapFailureReason, c as UiBootstrapFetcher, d as UiBootstrapLoader, e as UiBootstrapResource, f as UiBootstrapResources, g as UiBootstrapSnapshot, h as UiBootstrapValue, i as createUiBootstrapLoader } from '../uiBootstrap-Ci6K5j5t.js'; import { N as NajmTimeZone } from '../design-config-CdpHWwvE.js'; export { a as NAJM_CURRENCIES, b as NAJM_CURRENCY_OPTIONS, c as NAJM_DEFAULT_TIME_ZONE, d as NAJM_TIME_ZONES, e as NajmCurrency, f as defineNajmDesignConfig, p as parseNajmDesignConfig, s as stringifyNajmDesignConfig } from '../design-config-CdpHWwvE.js'; import { N as NajmMode } from '../design-types-CJYLgxmw.js'; export { a as NajmComponentThemeConfig, b as NajmDesignConfig, c as NajmLayoutConfig, d as NajmTypographyConfig } from '../design-types-CJYLgxmw.js'; /** * The part of an i18n definition this contract needs. * * Structural on purpose: `najm-i18n` is an *optional* peer of this package, and * a preference handler must not be the reason a consumer has to install it. A * `najm-i18n` definition satisfies this shape as it is. */ interface NajmPreferenceI18n { readonly supportedLanguages: readonly Language[]; readonly defaultLanguage: Language; normalizeLanguage(value: unknown): Language; } /** Cookie names, one per preference. */ interface NajmPreferenceCookieNames { language: string; theme: string; timeZone: string; } /** * Cookie attributes, applied to all three. * * `httpOnly` is the default because nothing in the browser reads these back — * the client provider holds the value it just set, and the server reads the * cookie. `secure` is left unset by default rather than `true`: these cookies * must survive `http://localhost`, and a deployment terminating TLS at the * edge sees no difference. Applications serving only HTTPS should set it. */ interface NajmPreferenceCookieOptions { httpOnly: boolean; maxAge: number; path: string; sameSite: "lax" | "strict" | "none"; secure?: boolean; domain?: string; } /** * Anything shaped like Next's cookie store. * * Structural rather than an import: this file must stay free of `next`, and a * test can pass `{ get: (name) => ... }` without building a request. */ interface NajmCookieReader { get(name: string): { value: string; } | undefined; } interface NajmPreferenceSnapshot { language: Language; theme: NajmMode; timeZone: TimeZone; } interface NajmPreferenceResolveOptions { /** * Used only when the language cookie is absent or holds an unsupported * value — a signed-in user's stored language, typically. Never overrides a * valid cookie: the cookie is what the user last chose in this browser. */ languageFallback?: unknown; /** * The raw `Accept-Language` request header. Used only after the language * cookie and `languageFallback`; quality weights and regional language tags * are matched against the application's supported languages. */ acceptLanguage?: string | null; } /** A route handler, ready to `export const POST = ...`. */ type NajmPreferenceHandler = (request: Request) => Promise; interface NajmPreferenceHandlers { /** Reads `{ language }`. */ language: NajmPreferenceHandler; /** Reads `{ theme }`. */ theme: NajmPreferenceHandler; /** Reads `{ timeZone }`. */ timeZone: NajmPreferenceHandler; } interface NajmPreferencesConfig { /** The application's catalog definition. The one required field. */ i18n: NajmPreferenceI18n; /** * Zones this application accepts. Defaults to the canonical list that * `TimeZoneInput` offers. * * Pass this *only* alongside a matching `items` on the input. Two lists that * disagree is the bug the shared default exists to prevent. */ timeZones?: readonly TimeZone[]; /** * Defaults to `UTC`, or to the first configured zone if `UTC` is not in it. * * `NoInfer` so this field cannot narrow `TimeZone`. Without it, an * application that names `Africa/Casablanca` and takes the canonical list * gets a definition typed as accepting *only* Casablanca — the opposite of * what it configured, and a type error at every other zone downstream. */ defaultTimeZone?: NoInfer; /** Defaults to `light`. */ defaultTheme?: NajmMode; /** * Currency codes this application accepts. Omit it entirely unless the * application resolves an institution-owned currency: legacy consumers * without a currency keep no currency state at all, and no package default * (no `MAD`, no locale-derived code) is invented for them. Currency stays * app-owned policy — this list only guards the institution values the * application explicitly passes to `resolveOrdered()`. * * Currency is institution-owned: it is never read from a cookie, a user * record, a locale, or an `Accept-Language` header. This list exists so a * corrupt or hand-edited institution row cannot reach money formatting, * where the failure mode is an amount rendered in the wrong currency. */ currencies?: readonly Currency[]; /** * Defaults to the first configured currency. Requires `currencies`. * * `NoInfer` for the same reason as `defaultTimeZone`: naming the default * must not narrow the accepted list. */ defaultCurrency?: NoInfer; /** Merged over the `najm-ui-*` defaults, per key. */ cookieNames?: Partial; /** Merged over the secure defaults, per key. */ cookieOptions?: Partial; /** Body field names, if this application's client posts something else. */ fields?: Partial>; /** Rejection messages, per preference. The defaults are generic and safe. */ messages?: Partial>; } /** * One ordered preference source. * * `cookie` is the browser's most recent explicit choice, `user` the * authenticated user's stored value, `institution` the institution's default * (for example a school settings row), and `fallback` the typed application * default. Resolution tries each source in order and skips invalid * candidates — an unsupported value never wins the round. */ type NajmPreferenceSource = "cookie" | "user" | "institution" | "fallback"; /** * A preference value together with the order its sources are tried in. * * Additive extension of the existing preference contract: the original * `resolve()` semantics are preserved unchanged, and this descriptor only * describes how `resolveOrdered()` walks the same guards. */ interface NajmOrderedPreference { readonly sources: readonly NajmPreferenceSource[]; readonly guard: (value: unknown) => value is T; readonly fallback: T; } /** * Currency stays institution-owned. * * Refinement note on the frozen ledger sketch (§4.5): the ledger lists only * `sources: ["institution", "fallback"]` for currency, which alone cannot * resolve a value. This keeps that exact `sources` restriction and adds the * `guard` + `fallback` the resolver needs, so currency is expressible as * institution → fallback only and never derives from locale, cookie, or user. */ interface NajmCurrencyPreference { readonly sources: readonly ["institution", "fallback"]; readonly guard: (value: unknown) => value is T; readonly fallback: T; } /** * The ordered descriptors for every preference. * * `currency` exists only when the application explicitly configured a * currency allowlist: legacy definitions carry no currency state, and * `resolveOrdered()` on such a definition returns no `currency` field. */ type NajmInstitutionalPreferences = { readonly language: NajmOrderedPreference; readonly theme: NajmOrderedPreference; readonly timeZone: NajmOrderedPreference; } & ([Currency] extends [never] ? { readonly currency?: undefined; } : { readonly currency: NajmCurrencyPreference; }); /** Per-request user values for ordered resolution. No currency: never user-owned. */ interface NajmOrderedUserValues { readonly language?: unknown; readonly theme?: unknown; readonly timeZone?: unknown; } /** Per-request institution values for ordered resolution. */ interface NajmOrderedInstitutionValues { readonly language?: unknown; readonly theme?: unknown; readonly timeZone?: unknown; readonly currency?: unknown; } /** * Independent per-field source orders. * * Each field walks its own list, so language can be * cookie → user → institution → fallback while currency stays fixed at * institution → fallback. Currency accepts no order override by type. */ interface NajmOrderedPreferenceOrders { readonly language?: readonly NajmPreferenceSource[]; readonly theme?: readonly NajmPreferenceSource[]; readonly timeZone?: readonly NajmPreferenceSource[]; } interface NajmOrderedResolveInput { readonly user?: NajmOrderedUserValues; readonly institution?: NajmOrderedInstitutionValues; /** * The raw `Accept-Language` request header. Tried only at the language * `fallback` step, before the configured default — so Kafil keeps * cookie → user → Accept-Language → default while an institution caller * that passes no header keeps cookie → user → institution → default. */ readonly acceptLanguage?: string | null; readonly orders?: NajmOrderedPreferenceOrders; } /** * Valid-first ordered resolution result. * * Without an explicitly configured currency the snapshot carries exactly the * three display fields; with one it additionally carries the * institution-only `currency`. Either way currency never derives from a * cookie, user value, locale, or `Accept-Language`. */ type NajmOrderedPreferenceSnapshot = [Currency] extends [never] ? { language: Language; theme: NajmMode; timeZone: TimeZone; } : { language: Language; theme: NajmMode; timeZone: TimeZone; currency: Currency; }; /** One preference's POST (write) and DELETE (clear) handlers. */ interface NajmPreferenceRoute { readonly POST: NajmPreferenceHandler; readonly DELETE: NajmPreferenceHandler; } /** * POST and DELETE belong together in `najm-kit/server`. * * `handlers` (POST-only functions) are preserved for backward compatibility: * `routes.language.POST` is the same function as `handlers.language`. */ interface NajmPreferenceRoutes { readonly language: NajmPreferenceRoute; readonly theme: NajmPreferenceRoute; readonly timeZone: NajmPreferenceRoute; } /** Where display-preference DELETEs are sent. Defaults to `/api/ui-*`. */ interface NajmUiPreferenceEndpoints { readonly language: string; readonly theme: string; readonly timeZone: string; } declare const NAJM_UI_PREFERENCE_ENDPOINTS: NajmUiPreferenceEndpoints; interface NajmClearPreferencesOptions { readonly endpoints?: Partial; /** * Injectable for tests. Defaults to the global `fetch`. Called once per * preference with `{ method: "DELETE", credentials: "same-origin" }`. */ readonly fetchFn?: (input: string, init?: RequestInit) => Promise; } interface NajmPreferences { readonly cookieNames: Readonly; readonly cookieOptions: Readonly; readonly timeZones: readonly TimeZone[]; readonly defaultTimeZone: TimeZone; readonly defaultTheme: NajmMode; readonly defaultLanguage: Language; /** * Empty unless the application explicitly configured `currencies`. * Legacy definitions carry no currency state. */ readonly currencies: readonly Currency[]; /** `undefined` unless the application explicitly configured a currency. */ readonly defaultCurrency: [Currency] extends [never] ? undefined : Currency; /** Every preference for this request, resolved from cookies. */ resolve(cookies: NajmCookieReader, options?: NajmPreferenceResolveOptions): NajmPreferenceSnapshot; /** * Valid-first ordered resolution, independently per field. * * Skips invalid candidates; currency reads only the institution value and * never a cookie, user value, locale, or `Accept-Language`. */ resolveOrdered(cookies: NajmCookieReader, input?: NajmOrderedResolveInput): NajmOrderedPreferenceSnapshot; /** Ordered descriptors (guards, fallbacks, default source orders). */ readonly ordered: NajmInstitutionalPreferences; handlers: NajmPreferenceHandlers; routes: NajmPreferenceRoutes; } /** The language of a configured definition, so applications alias nothing. */ type NajmPreferenceLanguage

= P extends NajmPreferences ? Language : never; /** The time zone of a configured definition. */ type NajmPreferenceTimeZone

= P extends NajmPreferences ? TimeZone : never; /** The currency of a configured definition, or `never` when none was configured. */ type NajmPreferenceCurrency

= P extends NajmPreferences ? Currency : never; /** * Configures the preference contract for one application. * * @example Zero configuration beyond the catalog * ```ts * export const preferences = defineNajmPreferences({ i18n: appI18n }); * ``` * * @example An application with published cookie names to keep * ```ts * export const preferences = defineNajmPreferences({ * i18n: appI18n, * defaultTimeZone: "Africa/Casablanca", * cookieNames: { * language: "app-ui-language", * theme: "app-ui-theme", * timeZone: "app-ui-timezone", * }, * }); * ``` */ declare function defineNajmPreferences(config: NajmPreferencesConfig): NajmPreferences; /** * Clear the three display-preference cookies with best-effort semantics. * * Never throws and never short-circuits: each endpoint is attempted inside * its own async boundary, so a synchronously throwing `fetchFn` for one * endpoint cannot prevent attempts to the other two. Every outcome is * settled independently, so a display-cookie failure can never prevent an * auth logout. Callers compose it with their auth logout (see * `logoutWithNajmPreferenceCleanup`) rather than awaiting it as a gate. */ declare function clearNajmUiPreferences(options?: NajmClearPreferencesOptions): Promise; /** * Run an auth logout with best-effort display-preference cleanup. * * Mirrors School's `SignOutButton` + `onSuccess(clearSchoolUiPreferences)` * ordering: the auth logout runs first and its outcome is authoritative. If * it rejects, the identical error propagates and cleanup never runs (there * is no `onSuccess` without a success). If it resolves, cleanup runs * best-effort and its rejection can never replace the successful auth * result — the exact logout value is returned either way. * * Structural on purpose: the logout callback is the app's `najm-auth` call, * so `najm-kit/server` never imports `najm-auth`. */ declare function logoutWithNajmPreferenceCleanup(options: { readonly logout: () => Promise; readonly clearPreferences: () => Promise; }): Promise; export { NAJM_UI_PREFERENCE_ENDPOINTS, type NajmClearPreferencesOptions, type NajmCookieReader, type NajmCurrencyPreference, type NajmInstitutionalPreferences, NajmMode, type NajmOrderedInstitutionValues, type NajmOrderedPreference, type NajmOrderedPreferenceOrders, type NajmOrderedPreferenceSnapshot, type NajmOrderedResolveInput, type NajmOrderedUserValues, type NajmPreferenceCookieNames, type NajmPreferenceCookieOptions, type NajmPreferenceCurrency, type NajmPreferenceHandler, type NajmPreferenceHandlers, type NajmPreferenceI18n, type NajmPreferenceLanguage, type NajmPreferenceResolveOptions, type NajmPreferenceRoute, type NajmPreferenceRoutes, type NajmPreferenceSnapshot, type NajmPreferenceSource, type NajmPreferenceTimeZone, type NajmPreferences, type NajmPreferencesConfig, NajmTimeZone, type NajmUiPreferenceEndpoints, clearNajmUiPreferences, defineNajmPreferences, logoutWithNajmPreferenceCleanup };