@fonderie/client 1.5.0 → 1.7.0

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cache.ts","../src/http.ts","../src/modules/audit.ts","../src/modules/auth.ts","../src/modules/billing.ts","../src/modules/customers.ts","../src/modules/media.ts","../src/modules/config.ts","../src/modules/webhooks.ts","../src/modules/workspaces.ts","../src/token-store.ts","../src/client.ts","../src/path.ts","../src/modules/config-admin.ts","../src/modules/admin.ts","../src/modules/auth-admin.ts","../src/modules/billing-admin.ts","../src/modules/audit-admin.ts","../src/modules/courier-admin.ts","../src/types.ts","../src/config-value.ts"],"sourcesContent":["// Optional response cache for FonderieClient. A cache instance is created per\n// client (never module-global) so it is safe on a server — one client per\n// request means no cross-user/tenant leakage. It sweeps lazily on read, so\n// there is no background timer keeping a process alive.\n\nexport interface ICache {\n\t// Returns the cached value if present and still within its TTL, else undefined.\n\tget<T>(key: string): T | undefined;\n\t// Stores a value with a per-entry TTL (ms).\n\tset<T>(key: string, value: T, ttlMs: number): void;\n\t// Deduplicates concurrent in-flight requests for the same key.\n\tdedupe<T>(key: string, fn: () => Promise<T>): Promise<T>;\n\t// Evicts every entry whose key contains `fragment` (and cancels in-flight\n\t// dedupe for those), so a write can bust the reads it affects.\n\tinvalidate(fragment: string): void;\n\tclear(): void;\n}\n\nexport interface IMemoryCacheOptions {\n\t// Default TTL (ms) applied to cached GETs when a call doesn't specify one.\n\tdefaultTtlMs?: number;\n}\n\ninterface Entry {\n\tvalue: unknown;\n\texpiresAt: number;\n}\n\nexport function createMemoryCache(\n\topts: IMemoryCacheOptions = {},\n): ICache & { defaultTtlMs: number } {\n\tconst store = new Map<string, Entry>();\n\tconst inflight = new Map<string, Promise<unknown>>();\n\tconst defaultTtlMs = opts.defaultTtlMs ?? 60_000;\n\n\treturn {\n\t\tdefaultTtlMs,\n\n\t\tget<T>(key: string): T | undefined {\n\t\t\tconst entry = store.get(key);\n\t\t\tif (!entry) return undefined;\n\t\t\tif (Date.now() > entry.expiresAt) {\n\t\t\t\tstore.delete(key); // lazy sweep\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn entry.value as T;\n\t\t},\n\n\t\tset<T>(key: string, value: T, ttlMs: number): void {\n\t\t\tstore.set(key, { value, expiresAt: Date.now() + ttlMs });\n\t\t},\n\n\t\tdedupe<T>(key: string, fn: () => Promise<T>): Promise<T> {\n\t\t\tconst existing = inflight.get(key);\n\t\t\tif (existing) return existing as Promise<T>;\n\t\t\tconst req = fn().finally(() => inflight.delete(key));\n\t\t\tinflight.set(key, req);\n\t\t\treturn req;\n\t\t},\n\n\t\tinvalidate(fragment: string): void {\n\t\t\tfor (const key of store.keys()) if (key.includes(fragment)) store.delete(key);\n\t\t\tfor (const key of inflight.keys()) if (key.includes(fragment)) inflight.delete(key);\n\t\t},\n\n\t\tclear(): void {\n\t\t\tstore.clear();\n\t\t\tinflight.clear();\n\t\t},\n\t};\n}\n","import type { ICache } from './cache';\nimport type { IApiError } from './types';\n\nexport class FonderieApiError extends Error {\n\tconstructor(\n\t\tpublic readonly reason: string,\n\t\tpublic readonly explanation: string,\n\t\tpublic readonly status: number,\n\t\tpublic readonly details?: unknown,\n\t\t// The X-Request-ID for the failed call — quote it in a bug report; it\n\t\t// correlates to the server's logs and audit trail for the same request.\n\t\tpublic readonly requestId?: string,\n\t) {\n\t\tsuper(explanation);\n\t\tthis.name = 'FonderieApiError';\n\t}\n}\n\n// Portable random hex for W3C trace ids — crypto.getRandomValues where available\n// (browser / Node), Math.random fallback for Hermes / older React Native. Not\n// security-sensitive: these are correlation/trace ids, not secrets.\nfunction randHex(bytes: number): string {\n\tconst c = (globalThis as { crypto?: { getRandomValues?: (a: Uint8Array) => Uint8Array } }).crypto;\n\tconst arr = new Uint8Array(bytes);\n\tif (c?.getRandomValues) c.getRandomValues(arr);\n\telse for (let i = 0; i < bytes; i++) arr[i] = Math.floor(Math.random() * 256);\n\tlet out = '';\n\tfor (const b of arr) out += b.toString(16).padStart(2, '0');\n\treturn out;\n}\n\nexport interface IRequestOptions {\n\tmethod: string;\n\tpath: string;\n\tbody?: unknown;\n\ttoken?: string | undefined;\n\tcookie?: string | undefined;\n\t// Resolves the billing subscriber to a workspace (@fonderie/billing's\n\t// resolveSubscriber falls back to the session user when omitted).\n\tworkspaceId?: string | undefined;\n\t// Extra request headers (e.g. the admin surfaces' X-Actor attribution).\n\theaders?: Record<string, string> | undefined;\n\t// Cache control (only applies when the client was given a cache):\n\t// cache: number → cache this GET for that many ms\n\t// cache: false → skip the cache for this GET\n\t// bust: true → ignore any cached value and refresh it\n\t// invalidate → extra key fragments to evict after a successful write\n\tcache?: number | false | undefined;\n\tbust?: boolean | undefined;\n\tinvalidate?: string[] | undefined;\n}\n\nexport interface IHttpDeps {\n\tcache?: ICache | undefined;\n\tdefaultTtlMs?: number | undefined;\n\t// Called once on a 401 (except for /auth/* requests). Returns a fresh access\n\t// token to retry with, or undefined to let the 401 surface. Callers should\n\t// make this single-flight.\n\trefresh?: (() => Promise<string | undefined>) | undefined;\n}\n\nexport class HttpClient {\n\tprivate cache: ICache | undefined;\n\tprivate defaultTtlMs: number;\n\tprivate refresh: (() => Promise<string | undefined>) | undefined;\n\n\tconstructor(\n\t\tprivate baseUrl: string,\n\t\tdeps: IHttpDeps = {},\n\t) {\n\t\tthis.cache = deps.cache;\n\t\tthis.defaultTtlMs = deps.defaultTtlMs ?? 60_000;\n\t\tthis.refresh = deps.refresh;\n\t}\n\n\t// Absolute URL for a path on this client's origin — for endpoints a browser\n\t// navigates to or embeds (e.g. a public `<img src>`) rather than fetches\n\t// through request(). Mirrors the `${baseUrl}${path}` join request() uses.\n\tabsolute(path: string): string {\n\t\treturn `${this.baseUrl}${path}`;\n\t}\n\n\t// Drop all cached responses — sign-out must not leave one session's data\n\t// servable to the next.\n\tclearCache(): void {\n\t\tthis.cache?.clear();\n\t}\n\n\tasync request<T>(opts: IRequestOptions): Promise<T> {\n\t\tconst method = opts.method.toUpperCase();\n\n\t\tconst cache = this.cache;\n\n\t\t// ── Read path: serve/populate cache (GET only, opt-in) ──────────────────\n\t\tif (cache && method === 'GET' && opts.cache !== false) {\n\t\t\tconst key = `GET ${opts.path}::ws=${opts.workspaceId ?? ''}`;\n\t\t\tif (!opts.bust) {\n\t\t\t\tconst hit = cache.get<T>(key);\n\t\t\t\tif (hit !== undefined) return hit;\n\t\t\t}\n\t\t\tconst ttl = typeof opts.cache === 'number' ? opts.cache : this.defaultTtlMs;\n\t\t\treturn cache.dedupe(key, async () => {\n\t\t\t\tconst data = await this.exec<T>(opts);\n\t\t\t\tcache.set(key, data, ttl);\n\t\t\t\treturn data;\n\t\t\t});\n\t\t}\n\n\t\tconst data = await this.exec<T>(opts);\n\n\t\t// ── Write path: bust the reads this mutation affects ────────────────────\n\t\tif (cache && method !== 'GET') {\n\t\t\tconst resource = opts.path.split('?')[0]?.split('/').filter(Boolean)[0];\n\t\t\tif (resource) cache.invalidate(`/${resource}`);\n\t\t\tfor (const fragment of opts.invalidate ?? []) cache.invalidate(fragment);\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tprivate async exec<T>(opts: IRequestOptions, retried = false): Promise<T> {\n\t\t// Start a W3C trace: the trace id doubles as the quotable correlation id\n\t\t// (sent as X-Request-ID and surfaced on FonderieApiError.requestId).\n\t\tconst traceId = randHex(16);\n\t\tconst requestId = traceId;\n\t\tconst headers: Record<string, string> = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\ttraceparent: `00-${traceId}-${randHex(8)}-01`,\n\t\t\t'X-Request-ID': requestId,\n\t\t};\n\t\tif (opts.token) headers['Authorization'] = `Bearer ${opts.token}`;\n\t\tif (opts.cookie) headers['Cookie'] = opts.cookie;\n\t\tif (opts.workspaceId) headers['X-Workspace-ID'] = opts.workspaceId;\n\t\tObject.assign(headers, opts.headers ?? {});\n\n\t\tconst fetchInit: RequestInit = { method: opts.method, headers, credentials: 'include' };\n\t\tif (opts.body !== undefined) fetchInit.body = JSON.stringify(opts.body);\n\n\t\tconst res = await fetch(`${this.baseUrl}${opts.path}`, fetchInit);\n\t\t// The server echoes the id back; prefer it (an intermediary could rewrite\n\t\t// the one we sent), else fall back to what we generated.\n\t\tconst rid = res.headers.get('x-request-id') ?? requestId;\n\n\t\t// Reactive renew: on a 401, refresh once and retry (never for /auth/* to\n\t\t// avoid recursing through the refresh/login endpoints themselves).\n\t\tif (res.status === 401 && this.refresh && !retried && !opts.path.startsWith('/auth/')) {\n\t\t\tconst newToken = await this.refresh();\n\t\t\tif (newToken) return this.exec<T>({ ...opts, token: newToken }, true);\n\t\t}\n\n\t\t// 204 No Content (e.g. some DELETE routes) has no body to parse.\n\t\tif (res.status === 204) {\n\t\t\tif (!res.ok)\n\t\t\t\tthrow new FonderieApiError('unknown', res.statusText, res.status, undefined, rid);\n\t\t\treturn undefined as T;\n\t\t}\n\n\t\tconst data = (await res.json()) as T | IApiError;\n\n\t\tif (!res.ok || res.status === 202) {\n\t\t\tconst err = data as IApiError;\n\t\t\tthrow new FonderieApiError(err.reason, err.explanation, res.status, err.details, rid);\n\t\t}\n\n\t\treturn data as T;\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type { IReadOptions, IApiResponse, IAuditPageResult } from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface IListAuditEventsInput {\n\ttype?: string;\n\tactorId?: string;\n\tfrom?: Date;\n\tto?: Date;\n\tlimit?: number;\n\tcursor?: string;\n}\n\n// ── Audit client ─────────────────────────────────────────────────────────────\n\nexport class AuditClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes the audit query to a workspace (X-Workspace-ID). Falls back to\n\t// the caller's personal workspace when unset, same as billing/workspaces.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\tlistEvents(input: IListAuditEventsInput = {}, opts?: IReadOptions) {\n\t\tconst params = new URLSearchParams();\n\t\tif (input.limit !== undefined) params.set('limit', String(input.limit));\n\t\tif (input.type) params.set('type', input.type);\n\t\tif (input.actorId) params.set('actorId', input.actorId);\n\t\tif (input.from) params.set('from', input.from.toISOString());\n\t\tif (input.to) params.set('to', input.to.toISOString());\n\t\tif (input.cursor) params.set('cursor', input.cursor);\n\t\tconst qs = params.toString();\n\n\t\treturn this.http.request<IApiResponse<IAuditPageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/audit${qs ? `?${qs}` : ''}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIApiResponse,\n\tILoginResult,\n\tIMfaRequiredResult,\n\tIMeResult,\n\tIMfaEnabledResult,\n\tIMfaSetupResult,\n\tIRefreshResult,\n\tIRegisterResult,\n\tIResendVerificationResult,\n\tIVerifyEmailResult,\n\tILoginHistoryPageResult,\n\tISessionsResult,\n\tIAuthProvidersResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\n// NOTE: the server's register/login schemas also accept a { phone } variant\n// (OTP-based phone auth). It is deliberately not surfaced in the typed client\n// yet — doing it properly needs a verifyPhone completion method plus hooks in\n// all three frontend frameworks, which is its own cycle. Tracked in\n// docs/DTO-GAP-AUDIT.md.\nexport interface IRegisterInput {\n\temail: string;\n\tpassword: string;\n\tfirstName?: string;\n\tlastName?: string;\n}\n\nexport interface IGetLoginHistoryInput {\n\toutcome?: 'success' | 'failed';\n\tfrom?: Date;\n\tto?: Date;\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface ILoginInput {\n\temail: string;\n\tpassword: string;\n}\n\n// Native Sign in with Apple: the app obtains an `identityToken` from the native\n// Apple sheet (e.g. expo-apple-authentication) and hands it here — the client\n// only relays it to POST /auth/apple/native. `nonce` is the raw nonce the app\n// passed to the native request, checked server-side against the token claim.\nexport interface IAppleNativeInput {\n\tidentityToken: string;\n\tnonce?: string;\n}\n\nexport interface IResetPasswordInput {\n\t// The 6-digit code emailed by forgotPassword. Matches @fonderie/auth's\n\t// resetPasswordSchema ({ pin, password }); the route is POST /auth/email/reset.\n\tpin: string;\n\tpassword: string;\n}\n\n// User updates are split by @fonderie/auth into dedicated, individually\n// validated routes — there is no combined /users/update endpoint.\nexport interface IUpdateProfileInput {\n\t// Explicit null clears the field server-side (same pattern as\n\t// IUpdateWorkspaceInput); undefined leaves it untouched.\n\tfirstName?: string | null;\n\tlastName?: string | null;\n\tavatarUrl?: string | null;\n}\n\nexport interface IUpdatePreferencesInput {\n\tlocale?: string;\n\ttimezone?: string;\n\t// Replaces the stored notifications object; flags left out fall back to\n\t// the server defaults on read.\n\tnotifications?: { email?: boolean; inApp?: boolean; sms?: boolean; push?: boolean };\n\temailDigest?: string;\n\tdateFormat?: string;\n\ttimeFormat?: string;\n}\n\nexport interface IChangePasswordInput {\n\tcurrentPassword: string;\n\tnewPassword: string;\n}\n\n// ── MFA sub-client ───────────────────────────────────────────────────────────\n\nclass MfaClient {\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate token: () => string | undefined,\n\t) {}\n\n\tsetup() {\n\t\treturn this.http.request<IApiResponse<IMfaSetupResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/setup',\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n\n\tverify(token: string) {\n\t\treturn this.http.request<IApiResponse<IMfaEnabledResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/verify',\n\t\t\tbody: { token },\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n\n\t// MFA-login: complete a login that returned MFA_REQUIRED. Authenticates with\n\t// the temporary `mfaToken` (not the session) and verifies the TOTP `code` —\n\t// same route as `verify`, different auth context. Returns the completed login.\n\tverifyLogin(mfaToken: string, code: string) {\n\t\treturn this.http.request<IApiResponse<ILoginResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/verify',\n\t\t\tbody: { token: code },\n\t\t\ttoken: mfaToken,\n\t\t});\n\t}\n\n\tdisable(token: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/disable',\n\t\t\tbody: { token },\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n\n\t// POST /auth/mfa/backup-codes (mfaTokenSchema { token }) — returns a fresh set.\n\tregenerateBackupCodes(token: string) {\n\t\treturn this.http.request<IApiResponse<{ backupCodes: string[] }>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/backup-codes',\n\t\t\tbody: { token },\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n}\n\n// ── Auth client ──────────────────────────────────────────────────────────────\n\nexport class AuthClient {\n\treadonly mfa: MfaClient;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {\n\t\tthis.mfa = new MfaClient(http, () => this.tokens.get());\n\t}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t\t// Signing out (token → undefined) also drops the shared response cache,\n\t\t// so the hooks' logout paths can't leak one session's data to the next.\n\t\tif (!token) this.http.clearCache();\n\t}\n\n\t// ── Public ─────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Which sign-in methods this deployment can actually honour.\n\t *\n\t * Public — the login screen needs it before anyone has signed in. Ask the\n\t * server rather than shipping a build-time flag: the flag stores the same\n\t * fact twice and lets the two disagree, and the symptom is a user clicking\n\t * a provider the server cannot complete and landing on the provider's own\n\t * error page, which the app cannot explain.\n\t */\n\tproviders() {\n\t\treturn this.http.request<IApiResponse<IAuthProvidersResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/auth/providers',\n\t\t});\n\t}\n\n\t/**\n\t * Disconnect the OAuth provider linked to the signed-in account.\n\t *\n\t * Refused with 409 PASSWORD_REQUIRED when the account has no password:\n\t * removing the only credential is account deletion, not a settings toggle.\n\t * Check `user.hasPassword` before offering the control so the user is asked\n\t * to set a password first rather than shown an error they can't act on.\n\t */\n\tunlinkOauth(provider: string) {\n\t\treturn this.http.request<IApiResponse<null>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/auth/oauth/${encodeURIComponent(provider)}`,\n\t\t});\n\t}\n\n\tregister(input: IRegisterInput) {\n\t\treturn this.http.request<IApiResponse<IRegisterResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/register',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\tlogin(input: ILoginInput) {\n\t\treturn this.http.request<IApiResponse<ILoginResult | IMfaRequiredResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/login',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\t// Complete a native Sign in with Apple. Returns the same token/user envelope\n\t// as login (no MFA branch — OAuth completions don't gate on MFA). Requires\n\t// the API to enable the provider (`providers: ['apple']` + apple config).\n\tappleNative(input: IAppleNativeInput) {\n\t\treturn this.http.request<IApiResponse<ILoginResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/apple/native',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\trefreshTokens(refreshToken?: string) {\n\t\treturn this.http.request<IApiResponse<IRefreshResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/refresh',\n\t\t\tbody: refreshToken ? { refreshToken } : undefined,\n\t\t});\n\t}\n\n\tforgotPassword(email: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/email/forgot',\n\t\t\tbody: { email },\n\t\t});\n\t}\n\n\tresetPassword(input: IResetPasswordInput) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/email/reset',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\tverifyEmail(token: string) {\n\t\t// @fonderie/auth registers this as POST /auth/verify with body { token }\n\t\t// (verifySchema = { token: sixDigitPin }).\n\t\treturn this.http.request<IApiResponse<IVerifyEmailResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/verify',\n\t\t\tbody: { token },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Protected ──────────────────────────────────────────────────────────────\n\n\tlogout(refreshToken?: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/logout',\n\t\t\tbody: refreshToken ? { refreshToken } : undefined,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tsendVerificationEmail() {\n\t\t// @fonderie/auth registers this as GET /auth/send-verification (requireAuth).\n\t\treturn this.http.request<IApiResponse<IResendVerificationResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/auth/send-verification',\n\t\t\ttoken: this.tokens.get(),\n\t\t\t// A send-action on a GET route: never serve it from the cache, or a\n\t\t\t// resend inside the TTL would silently no-op.\n\t\t\tcache: false,\n\t\t});\n\t}\n\n\t// ── Protected + Verified ───────────────────────────────────────────────────\n\n\tgetUser(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IMeResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/users',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateProfile(input: IUpdateProfileInput) {\n\t\treturn this.http.request<IApiResponse<IMeResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/profile',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdatePreferences(input: IUpdatePreferencesInput) {\n\t\treturn this.http.request<IApiResponse<IMeResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/preferences',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdateEmail(email: string) {\n\t\treturn this.http.request<IApiResponse<unknown>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/email',\n\t\t\tbody: { email },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdatePhone(phone: string) {\n\t\treturn this.http.request<IApiResponse<unknown>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/phone',\n\t\t\tbody: { phone },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tchangePassword(input: IChangePasswordInput) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/password',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// GET /users/export — the caller's own data as a portable bundle (SAR).\n\texportData() {\n\t\treturn this.http.request<IApiResponse<unknown>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/users/export',\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tdeleteUser() {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: '/users',\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Security surfaces (login history + active sessions) ─────────────────────\n\n\t// GET /auth/login-history — the caller's own attempts, newest first,\n\t// keyset-paginated (pass the previous page's nextCursor to continue).\n\tgetLoginHistory(input: IGetLoginHistoryInput = {}, opts?: IReadOptions) {\n\t\tconst params = new URLSearchParams();\n\t\tif (input.limit !== undefined) params.set('limit', String(input.limit));\n\t\tif (input.outcome) params.set('outcome', input.outcome);\n\t\tif (input.from) params.set('from', input.from.toISOString());\n\t\tif (input.to) params.set('to', input.to.toISOString());\n\t\tif (input.cursor) params.set('cursor', input.cursor);\n\t\tconst qs = params.toString();\n\t\t// Single-level template (no nested backtick) so the client/route drift\n\t\t// checker can normalise the ${qs…} suffix away and match the server route.\n\t\treturn this.http.request<IApiResponse<ILoginHistoryPageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/auth/login-history${qs ? '?' + qs : ''}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// GET /auth/sessions — the caller's live sessions; one is flagged current.\n\tlistSessions(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ISessionsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/auth/sessions',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// DELETE /auth/sessions/:id — revoke one of the caller's sessions.\n\tterminateSession(id: string) {\n\t\treturn this.http.request<IApiResponse<{ id: string }>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/auth/sessions/${encodeURIComponent(id)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// DELETE /auth/sessions/others — revoke every session except the current one.\n\tterminateOtherSessions() {\n\t\treturn this.http.request<IApiResponse<{ count: number }>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: '/auth/sessions/others',\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIApiResponse,\n\tICancelSubscriptionInput,\n\tICheckoutUrlResult,\n\tIInvoicesResult,\n\tIPaymentMethodResult,\n\tIPlanListResult,\n\tIPlanResult,\n\tIPortalUrlResult,\n\tISavePaymentMethodInput,\n\tISetupIntentResult,\n\tISubscriptionChangeResult,\n\tISubscriptionResult,\n\tIUsageResult,\n\tIWalletCheckoutInput,\n\tIWalletPurchaseInput,\n\tIWalletPurchaseResult,\n\tIWalletResult,\n\tIWalletTransactionsResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ICheckoutInput {\n\tplan: string;\n\tinterval?: 'month' | 'year';\n\t// Optional idempotency key — a retried checkout with the same key dedupes to\n\t// one session (and one subscription) server-side. Generate once per attempt.\n\tidempotencyKey?: string;\n}\n\nexport interface IRecordUsageInput {\n\tmetric: string;\n\tquantity?: number;\n}\n\nexport interface IWalletPreferencesInput {\n\t// When false, a debit stops at the free allowance (402) rather than drawing\n\t// down purchased credits.\n\tspendPurchased: boolean;\n}\n\nexport interface ICreatePlanInput {\n\tname: string;\n\tdescription?: string | null;\n\ttier?: number;\n\tseats?: number | null;\n\ttrialDays?: number;\n\tmonthlyAmount?: number | null;\n\tmonthlyPriceId?: string | null;\n\tyearlyAmount?: number | null;\n\tyearlyPriceId?: string | null;\n\tfeatures?: unknown;\n\tmetadata?: unknown;\n}\n\nexport type IUpdatePlanInput = Partial<ICreatePlanInput>;\n\n// ── Billing client ───────────────────────────────────────────────────────────\n\nexport class BillingClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Subscriber is resolved from this workspace ID (X-Workspace-ID) when set,\n\t// falling back to the session user otherwise — see @fonderie/billing's\n\t// resolveSubscriber. Call with undefined to bill the signed-in user directly.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\t// ── Plans — public read-only ────────────────────────────────────────────────\n\n\tlistPlans(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IPlanListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/plans',\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tgetPlan(planId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IPlanResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/plans/${encodeURIComponent(planId)}`,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// ── Plans — admin write ──────────────────────────────────────────────────────\n\t// Unlike every other write in this client, @fonderie/billing does not gate\n\t// these with requireAuth or an admin token — \"the caller is responsible for\n\t// authorization\" (its own routes.ts comment). Sending the session token is\n\t// harmless (the server ignores it) but does nothing on its own; gate access\n\t// to these calls yourself (an app-level route guard, a reverse-proxy admin\n\t// zone, or similar) before wiring them into a UI.\n\n\tcreatePlan(input: ICreatePlanInput) {\n\t\treturn this.http.request<IApiResponse<IPlanResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/plans',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdatePlan(planId: string, input: IUpdatePlanInput) {\n\t\treturn this.http.request<IApiResponse<IPlanResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/plans/${encodeURIComponent(planId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tdeletePlan(planId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/plans/${encodeURIComponent(planId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Subscription ─────────────────────────────────────────────────────────────\n\n\tgetSubscription(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ISubscriptionResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/subscription',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// First-party cancel — no portal round-trip. Default keeps access until the\n\t// paid-through date; pass { atPeriodEnd: false } to end it immediately. 501\n\t// when the provider has no first-party cancel (the portal remains a fallback).\n\tcancelSubscription(input?: ICancelSubscriptionInput) {\n\t\treturn this.http.request<IApiResponse<ISubscriptionChangeResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/subscription/cancel',\n\t\t\tbody: input ?? {},\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Un-cancel a subscription scheduled to cancel at period end. Idempotent; 409\n\t// when the subscription is already fully canceled (start a new checkout).\n\treactivateSubscription() {\n\t\treturn this.http.request<IApiResponse<ISubscriptionChangeResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/subscription/reactivate',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Checkout / portal ────────────────────────────────────────────────────────\n\n\tcreateCheckoutSession(input: ICheckoutInput) {\n\t\treturn this.http.request<IApiResponse<ICheckoutUrlResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/checkout',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tcreatePortalSession() {\n\t\treturn this.http.request<IApiResponse<IPortalUrlResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/portal',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Usage ────────────────────────────────────────────────────────────────────\n\n\trecordUsage(input: IRecordUsageInput) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/usage',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetUsage(metric: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IUsageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/billing/usage/${encodeURIComponent(metric)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// ── Wallet ─────────────────────────────────────────────────────────────────────\n\n\tgetWallet(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWalletResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/wallet',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tsetWalletPreferences(input: IWalletPreferencesInput) {\n\t\treturn this.http.request<IApiResponse<IWalletResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/wallet/preferences',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Start a one-time credit-pack purchase. Returns a hosted checkout URL to\n\t// redirect the buyer to; the wallet is credited by the payment webhook.\n\tcreateWalletCheckout(input: IWalletCheckoutInput) {\n\t\treturn this.http.request<IApiResponse<ICheckoutUrlResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/wallet/checkout',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Buy a credit pack in-app by charging the saved card — no redirect. Inspect\n\t// `result.status`: 'credited' (done — refresh the wallet), 'checkout_required'\n\t// (no saved card or the card needs 3-D Secure → fall back to\n\t// createWalletCheckout), 'declined', or 'processing' (indeterminate — retry\n\t// with the SAME idempotencyKey). Generate one idempotencyKey per attempt and\n\t// reuse it on retry so a double-submit can't double-charge.\n\tpurchaseWalletPack(input: IWalletPurchaseInput) {\n\t\treturn this.http.request<IApiResponse<IWalletPurchaseResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/wallet/purchase',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// The wallet ledger, newest first — every credit/debit with a running\n\t// balanceAfter. Cursor-paginated: pass the previous result's `nextCursor`.\n\tgetWalletTransactions(opts?: IReadOptions & { cursor?: string; limit?: number }) {\n\t\tconst params = new URLSearchParams();\n\t\tif (opts?.cursor) params.set('cursor', opts.cursor);\n\t\tif (opts?.limit !== undefined) params.set('limit', String(opts.limit));\n\t\tconst qs = params.toString();\n\t\treturn this.http.request<IApiResponse<IWalletTransactionsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/billing/wallet/transactions${qs ? '?' + qs : ''}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// ── Account ──────────────────────────────────────────────────────────────────\n\n\t// The customer's card on file (brand/last4/expiry), or { paymentMethod: null }\n\t// when none is stored. 501 when the provider can't retrieve it.\n\tgetPaymentMethod(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IPaymentMethodResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/payment-method',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// Begin in-app card entry — returns a SetupIntent client secret for the\n\t// provider's embedded card element (Stripe Payment Element); the user never\n\t// leaves the site. 501 when the provider has no in-app card support.\n\tsetupPaymentMethod() {\n\t\treturn this.http.request<IApiResponse<ISetupIntentResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/payment-method/setup',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Save the card after the client confirms the SetupIntent: makes it the\n\t// default and records it. 422 when the card isn't attached to this customer.\n\tsavePaymentMethod(input: ISavePaymentMethodInput) {\n\t\treturn this.http.request<IApiResponse<IPaymentMethodResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/billing/payment-method',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Remove the saved card (detach at the provider + clear the record).\n\tremovePaymentMethod() {\n\t\treturn this.http.request<IApiResponse<IPaymentMethodResult>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: '/billing/payment-method',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// The customer's invoices, newest first — each links out to the hosted\n\t// invoice / PDF. 501 when the provider can't list them.\n\tlistInvoices(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IInvoicesResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/invoices',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tCustomerLabelType,\n\tCustomerSex,\n\tCustomerType,\n\tIApiResponse,\n\tICustomerAddressListResult,\n\tICustomerAddressResult,\n\tICustomerDetailD2DTO,\n\tICustomerDetailDTO,\n\tICustomerEmailListResult,\n\tICustomerEmailResult,\n\tICustomerLabelListResult,\n\tICustomerListResult,\n\tICustomerNoteListResult,\n\tICustomerNoteResult,\n\tICustomerPhoneListResult,\n\tICustomerPhoneResult,\n\tICustomerRelationshipListResult,\n\tICustomerRelationshipResult,\n\tICustomerResult,\n\tICustomerTagListResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface IListCustomersInput {\n\tsearch?: string;\n\tblacklisted?: boolean;\n\tlimit?: number;\n\toffset?: number;\n}\n\nexport interface IGetCustomerInput {\n\tdepth?: 1 | 2;\n}\n\nexport interface ICreateCustomerInput {\n\ttype?: CustomerType;\n\tsex?: CustomerSex;\n\tfirstName?: string | null;\n\tlastName?: string | null;\n\tcompanyName?: string | null;\n\tavatarUrl?: string | null;\n\tlocale?: string | null;\n\treferenceCode?: string | null;\n\treferralCode?: string | null;\n\treferredByCode?: string | null;\n}\n\n// Referral codes are create-time only — the server's update path never\n// writes them, so including them here made updateCustomer({ referralCode })\n// a type-correct 200-OK silent no-op.\nexport type IUpdateCustomerInput = Omit<ICreateCustomerInput, 'referralCode' | 'referredByCode'>;\n\nexport interface IBlacklistCustomerInput {\n\treason?: string;\n}\n\nexport interface IAddEmailInput {\n\temail: string;\n\tlabel?: string;\n\tisPrimary?: boolean;\n}\n\nexport interface IAddPhoneInput {\n\tphone: string;\n\tlabel?: string;\n\tisPrimary?: boolean;\n}\n\nexport interface IAddAddressInput {\n\tcountryIso: string;\n\tzipPostalCode: string;\n\tsubdivision1Iso?: string | null;\n\tsubdivision2Iso?: string | null;\n\tunit?: string | null;\n\tline1?: string | null;\n\tline2?: string | null;\n\tlabel?: string;\n\tisPrimary?: boolean;\n}\n\nexport interface IAddRelationshipInput {\n\trelatedId: string;\n\t// Required — the server rejects relationship-less links with a 422.\n\trelationship: string;\n\tisPrimary?: boolean;\n}\n\n// ── Customers client ─────────────────────────────────────────────────────────\n\nexport class CustomersClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes every request to this workspace (X-Workspace-ID). Falls back to\n\t// the caller's personal workspace when unset, same as billing/workspaces/audit/webhooks.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\t// ── Core customer CRUD ───────────────────────────────────────────────────────\n\n\tlistCustomers(input: IListCustomersInput = {}, opts?: IReadOptions) {\n\t\tconst params = new URLSearchParams();\n\t\tif (input.search !== undefined) params.set('search', input.search);\n\t\tif (input.blacklisted !== undefined) params.set('blacklisted', String(input.blacklisted));\n\t\tif (input.limit !== undefined) params.set('limit', String(input.limit));\n\t\tif (input.offset !== undefined) params.set('offset', String(input.offset));\n\t\tconst qs = params.toString();\n\n\t\treturn this.http.request<IApiResponse<ICustomerListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: qs ? `/customers?${qs}` : '/customers',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateCustomer(input: ICreateCustomerInput = {}) {\n\t\treturn this.http.request<IApiResponse<ICustomerResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/customers',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// depth defaults to 2 server-side; pass { depth: 1 } for one level of\n\t// relationship expansion instead of the D2 (nested-relationships) shape.\n\tgetCustomer(customerId: string, input: IGetCustomerInput = {}, opts?: IReadOptions) {\n\t\tconst qs = input.depth === 1 ? '?depth=1' : '';\n\t\treturn this.http.request<IApiResponse<ICustomerDetailDTO | ICustomerDetailD2DTO>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}${qs}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateCustomer(customerId: string, input: IUpdateCustomerInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tdeleteCustomer(customerId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tblacklistCustomer(customerId: string, input: IBlacklistCustomerInput = {}) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/blacklist`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tunblacklistCustomer(customerId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/unblacklist`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Emails ───────────────────────────────────────────────────────────────────\n\n\tlistEmails(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerEmailListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddEmail(customerId: string, input: IAddEmailInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerEmailResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Only the label is editable — email addresses themselves are immutable\n\t// once added; remove and re-add to change the address.\n\tupdateEmailLabel(customerId: string, emailId: string, label: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerEmailResult>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails/${encodeURIComponent(emailId)}`,\n\t\t\tbody: { label },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryEmail(customerId: string, emailId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails/${encodeURIComponent(emailId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveEmail(customerId: string, emailId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails/${encodeURIComponent(emailId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Phones ───────────────────────────────────────────────────────────────────\n\n\tlistPhones(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerPhoneListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddPhone(customerId: string, input: IAddPhoneInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerPhoneResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Only the label is editable — same as updateEmailLabel.\n\tupdatePhoneLabel(customerId: string, phoneId: string, label: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerPhoneResult>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones/${encodeURIComponent(phoneId)}`,\n\t\t\tbody: { label },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryPhone(customerId: string, phoneId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones/${encodeURIComponent(phoneId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremovePhone(customerId: string, phoneId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones/${encodeURIComponent(phoneId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Addresses ────────────────────────────────────────────────────────────────\n\n\tlistAddresses(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerAddressListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddAddress(customerId: string, input: IAddAddressInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerAddressResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Only the label is editable — same as updateEmailLabel.\n\tupdateAddressLabel(customerId: string, addrId: string, label: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerAddressResult>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses/${encodeURIComponent(addrId)}`,\n\t\t\tbody: { label },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryAddress(customerId: string, addrId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses/${encodeURIComponent(addrId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveAddress(customerId: string, addrId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses/${encodeURIComponent(addrId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Notes ────────────────────────────────────────────────────────────────────\n\n\tlistNotes(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerNoteListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateNote(customerId: string, body: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerNoteResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes`,\n\t\t\tbody: { body },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tupdateNote(customerId: string, noteId: string, body: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerNoteResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes/${encodeURIComponent(noteId)}`,\n\t\t\tbody: { body },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tdeleteNote(customerId: string, noteId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes/${encodeURIComponent(noteId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Tags ─────────────────────────────────────────────────────────────────────\n\n\tlistTags(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerTagListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/tags`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddTag(customerId: string, tag: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/tags`,\n\t\t\tbody: { tag },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveTag(customerId: string, tag: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${customerId}/tags/${encodeURIComponent(tag)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Relationships ────────────────────────────────────────────────────────────\n\n\tlistRelationships(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerRelationshipListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddRelationship(customerId: string, input: IAddRelationshipInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerRelationshipResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryRelationship(customerId: string, relatedId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships/${encodeURIComponent(relatedId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveRelationship(customerId: string, relatedId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships/${encodeURIComponent(relatedId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Labels ───────────────────────────────────────────────────────────────────\n\t// Shared vocabulary across all customers in the workspace — labels are\n\t// looked up/created implicitly by addEmail/addPhone/addAddress's `label`\n\t// string; these two methods are for managing the vocabulary directly\n\t// (e.g. an admin screen listing/pruning unused labels).\n\n\tlistLabels(type: CustomerLabelType, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerLabelListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/labels?type=${encodeURIComponent(type)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tremoveLabel(labelId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/labels/${encodeURIComponent(labelId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type { IApiResponse, IMediaAssetResult } from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\n// Upload an image. `dataBase64` is the RAW base64 payload (no `data:` prefix) —\n// the server sniffs the real type from magic bytes, enforces the byte cap, and\n// rejects SVG (stored-XSS). `purpose` groups assets (e.g. 'avatar'); ownerType\n// /ownerId default server-side to the calling user, so a plain avatar upload\n// needs only `dataBase64`.\nexport interface IUploadMediaInput {\n\tdataBase64: string;\n\tpurpose?: string;\n\townerType?: string;\n\townerId?: string;\n}\n\n// ── Media client ─────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, like auth). NOT\n// workspace-scoped: @fonderie/media keys ownership off ownerType/ownerId in the\n// body, not an X-Workspace-ID header.\n\nexport class MediaClient {\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// POST /media — store an image; returns the asset with its monomorphic\n\t// /media/:id url. requireAuth server-side.\n\tupload(input: IUploadMediaInput) {\n\t\treturn this.http.request<IApiResponse<IMediaAssetResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/media',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// DELETE /media/:id — uploader-only (403 for anyone else).\n\tdelete(id: string) {\n\t\treturn this.http.request<IApiResponse<{ id: string }>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/media/${encodeURIComponent(id)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// Absolute URL for a stored asset — an `<img src>` target. The GET /media/:id\n\t// route is public and cached (it can't carry a Bearer token), so turn an\n\t// upload's `asset.id` into a browser-loadable URL with this, and use it as\n\t// the avatarUrl handed to auth's updateProfile.\n\tassetUrl(id: string): string {\n\t\treturn this.http.absolute(`/media/${encodeURIComponent(id)}`);\n\t}\n\n\t// Inverse of assetUrl: pull the asset id out of one of THIS brick's\n\t// /media/:id URLs (absolute or relative); null for empty/external URLs. Lets\n\t// avatar cleanup delete only assets we minted (matched as a UUID), never a\n\t// placeholder or third-party avatar URL.\n\tassetIdFromUrl(url: string | null | undefined): string | null {\n\t\tif (!url) return null;\n\t\tconst m = url.match(\n\t\t\t/\\/media\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:[/?#]|$)/i,\n\t\t);\n\t\treturn m ? m[1]! : null;\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type { IApiResponse } from '../types';\n\n// ── Public remote config ─────────────────────────────────────────────────────\n// The frontend's read path for feature flags and runtime settings: only the\n// keys the server lists in ConfigModule's `publicKeys`. One snapshot per\n// FonderieClient, shared by every screen and hook that reads it — load it once\n// (typically right after sign-in, or at app start for signed-out flags), then\n// read synchronously anywhere.\n\nexport interface IRemoteConfigState {\n\t/** key → value, as last loaded. Empty until the first load succeeds. */\n\tvalues: Readonly<Record<string, unknown>>;\n\t/** When values were last loaded successfully; null before that. */\n\tloadedAt: Date | null;\n\tisLoading: boolean;\n\t/** The last load's failure, cleared by the next success. Values are kept. */\n\terror: unknown;\n}\n\ntype Listener = (state: IRemoteConfigState) => void;\n\nexport class ConfigClient {\n\tprivate state: IRemoteConfigState = { values: {}, loadedAt: null, isLoading: false, error: null };\n\tprivate listeners = new Set<Listener>();\n\tprivate inFlight: Promise<IRemoteConfigState> | null = null;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\t// GET /config/public — fetch the public values into the shared snapshot.\n\t// Concurrent calls share one request. A failure keeps the previous values\n\t// (a flag that was on does not flicker off because one refresh failed) and\n\t// is reported in `error`; before any success, reads fall back to defaults.\n\tload(): Promise<IRemoteConfigState> {\n\t\tif (this.inFlight) return this.inFlight;\n\t\tthis.set({ isLoading: true });\n\t\tthis.inFlight = this.http\n\t\t\t.request<IApiResponse<{ values: Record<string, unknown> }>>({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: '/config/public',\n\t\t\t\t// Sent when signed in, so per-user values can be served later\n\t\t\t\t// without a client change; the route itself is public.\n\t\t\t\ttoken: this.tokens.get(),\n\t\t\t})\n\t\t\t.then(\n\t\t\t\t(res) => this.set({ values: res.result?.values ?? {}, loadedAt: new Date(), isLoading: false, error: null }),\n\t\t\t\t(error: unknown) => this.set({ isLoading: false, error }),\n\t\t\t)\n\t\t\t.finally(() => {\n\t\t\t\tthis.inFlight = null;\n\t\t\t});\n\t\treturn this.inFlight;\n\t}\n\n\t// One value, with the fallback used when the key is absent — before the\n\t// first load, when it failed, or when the server does not expose the key.\n\t// Pick the SAFE fallback (feature off), not the optimistic one.\n\tget<T>(key: string, fallback: T): T {\n\t\treturn Object.hasOwn(this.state.values, key) ? (this.state.values[key] as T) : fallback;\n\t}\n\n\t// The whole current state (values, loadedAt, isLoading, error).\n\tsnapshot(): IRemoteConfigState {\n\t\treturn this.state;\n\t}\n\n\t// Called with the new state after every change; returns an unsubscribe.\n\tsubscribe(listener: Listener): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\tprivate set(patch: Partial<IRemoteConfigState>): IRemoteConfigState {\n\t\t// A new object each time, so React's useSyncExternalStore and Vue refs\n\t\t// see a change by identity.\n\t\tthis.state = { ...this.state, ...patch };\n\t\tfor (const listener of this.listeners) listener(this.state);\n\t\treturn this.state;\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIApiResponse,\n\tITestWebhookResult,\n\tIWebhookDeliveryListResult,\n\tIWebhookEndpointCreatedDTO,\n\tIWebhookEndpointDTO,\n\tIWebhookEndpointListResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ICreateWebhookEndpointInput {\n\turl: string;\n\tevents?: string[];\n}\n\nexport interface IUpdateWebhookEndpointInput {\n\turl?: string;\n\tevents?: string[];\n\tenabled?: boolean;\n}\n\n// ── Webhooks client ──────────────────────────────────────────────────────────\n\nexport class WebhooksClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes every request to this workspace (X-Workspace-ID). Falls back to\n\t// the caller's personal workspace when unset, same as billing/workspaces/audit.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\tlistEndpoints(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/webhooks',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// The response includes `secret` — shown once, at creation. There is no\n\t// way to retrieve it again afterward; store it or let the caller copy it.\n\tcreateEndpoint(input: ICreateWebhookEndpointInput) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointCreatedDTO>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/webhooks',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetEndpoint(endpointId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointDTO>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateEndpoint(endpointId: string, input: IUpdateWebhookEndpointInput) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointDTO>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tdeleteEndpoint(endpointId: string) {\n\t\treturn this.http.request<undefined>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tlistDeliveries(endpointId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWebhookDeliveryListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}/deliveries`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\ttestEndpoint(endpointId: string) {\n\t\treturn this.http.request<IApiResponse<ITestWebhookResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}/test`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIAcceptInvitationResult,\n\tIApiResponse,\n\tIInvitationListResult,\n\tIInviteResult,\n\tIMemberListResult,\n\tIRoleListResult,\n\tIRoleResult,\n\tIWorkspaceListResult,\n\tIWorkspaceResult,\n\tIWorkspaceSettingsResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ICreateWorkspaceInput {\n\tname: string;\n\tdescription?: string;\n\ttype?: string;\n}\n\nexport interface IUpdateWorkspaceInput {\n\tname?: string;\n\tdescription?: string | null;\n\tmotto?: string | null;\n\tphone?: string | null;\n\tbusinessType?: string | null;\n\taddress?: {\n\t\tline1?: string;\n\t\tline2?: string;\n\t\tcity?: string;\n\t\tstate?: string;\n\t\tzip?: string;\n\t\tcountry?: string;\n\t} | null;\n}\n\nexport interface IInviteEntry {\n\temail: string;\n\troleId?: string;\n}\n\nexport interface IUpdateSettingsInput {\n\tlocale?: string;\n\ttimezone?: string;\n\tcurrency?: string;\n\tdateFormat?: string;\n\ttimeFormat?: string;\n}\n\nexport interface ICreateRoleInput {\n\tname: string;\n\tdescription?: string;\n}\n\nexport interface IUpdateRoleInput {\n\tname?: string;\n\tdescription?: string | null;\n\tactive?: boolean;\n}\n\nexport interface IRolePermissionInput {\n\tpermissionKey: string;\n\tcanCreate?: boolean;\n\tcanRead?: boolean;\n\tcanUpdate?: boolean;\n\tcanDelete?: boolean;\n}\n\nexport interface IRolePermission {\n\tpermissionKey: string;\n\tcanCreate: boolean;\n\tcanRead: boolean;\n\tcanUpdate: boolean;\n\tcanDelete: boolean;\n}\n\nexport interface IRolePermissionsResult {\n\tpermissions: IRolePermission[];\n}\n\n// ── Workspaces client ────────────────────────────────────────────────────────\n\nexport class WorkspacesClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes every subsequent request to this workspace (X-Workspace-ID).\n\t// Falls back to the caller's personal workspace when unset.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\t// ── Workspace creation + listing ─────────────────────────────────────────────\n\n\tlistWorkspaces(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateWorkspace(input: ICreateWorkspaceInput) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tgetWorkspace(id: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/${encodeURIComponent(id)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateWorkspace(input: IUpdateWorkspaceInput) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/workspaces',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Personal workspaces can't be archived — the server returns 403 if you try.\n\tarchiveWorkspace() {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/archive',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\trestoreWorkspace() {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/restore',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Roles ────────────────────────────────────────────────────────────────────\n\n\tlistRoles(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRoleListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/roles',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateRole(input: ICreateRoleInput) {\n\t\treturn this.http.request<IApiResponse<IRoleResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/roles',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetRole(roleId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRoleResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateRole(roleId: string, input: IUpdateRoleInput) {\n\t\treturn this.http.request<IApiResponse<IRoleResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveRole(roleId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetRolePermissions(roleId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRolePermissionsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}/permissions`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tsetRolePermissions(roleId: string, permissions: IRolePermissionInput[]) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}/permissions`,\n\t\t\tbody: { permissions },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Members ──────────────────────────────────────────────────────────────────\n\n\tlistMembers(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IMemberListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/members',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tremoveMember(userId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetMemberRoles(userId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRoleListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}/roles`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddMemberRole(userId: string, roleId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}/roles`,\n\t\t\tbody: { roleId },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveMemberRole(userId: string, roleId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}/roles/${encodeURIComponent(roleId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Invitations ──────────────────────────────────────────────────────────────\n\n\tlistInvitations(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IInvitationListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/invitations',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tinvite(entries: IInviteEntry | IInviteEntry[]) {\n\t\treturn this.http.request<IApiResponse<IInviteResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/invitations',\n\t\t\tbody: entries,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tcancelInvitation(inviteId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/invitations/${encodeURIComponent(inviteId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tacceptInvitation(pin: string) {\n\t\treturn this.http.request<IApiResponse<IAcceptInvitationResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/invitations/accept',\n\t\t\tbody: { pin },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Settings ─────────────────────────────────────────────────────────────────\n\n\tgetSettings(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceSettingsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/settings',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateSettings(input: IUpdateSettingsInput) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceSettingsResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/workspaces/settings',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n}\n","// Shared by every module of a FonderieClient so that setting the access\n// token on one (e.g. AuthClient after login) is immediately visible to all\n// the others (e.g. BillingClient) — they're separate module instances, but\n// one session.\nexport class TokenStore {\n\tprivate token: string | undefined;\n\n\tconstructor(initial?: string) {\n\t\tthis.token = initial;\n\t}\n\n\tget(): string | undefined {\n\t\treturn this.token;\n\t}\n\n\tset(token: string | undefined) {\n\t\tthis.token = token;\n\t}\n}\n","import type { ICache } from './cache';\nimport { HttpClient } from './http';\nimport { AuditClient } from './modules/audit';\nimport { AuthClient } from './modules/auth';\nimport { BillingClient } from './modules/billing';\nimport { CustomersClient } from './modules/customers';\nimport { MediaClient } from './modules/media';\nimport { ConfigClient } from './modules/config';\nimport { WebhooksClient } from './modules/webhooks';\nimport { WorkspacesClient } from './modules/workspaces';\nimport { TokenStore } from './token-store';\nimport type { IApiResponse, ITokens } from './types';\n\n// Reactive token renewal. When set, the client refreshes once on a 401 and\n// retries the request. The app owns where the refresh token lives and where new\n// tokens are persisted.\nexport interface IClientAuthConfig {\n\tgetRefreshToken?: () => string | undefined;\n\tonTokensChanged?: (tokens: ITokens) => void;\n\tonAuthError?: () => void;\n}\n\nexport interface IFonderieClientOptions {\n\tbaseUrl: string;\n\taccessToken?: string;\n\tworkspaceId?: string;\n\t// Opt-in response cache (see createMemoryCache). Omit for no caching.\n\tcache?: ICache;\n\t// Opt-in reactive renew.\n\tauth?: IClientAuthConfig;\n}\n\n// Per-call options for the generic transport.\nexport interface IRequestConfig {\n\tworkspaceId?: string;\n\t// Per-call Bearer override — e.g. the MFA-login step, where a temporary\n\t// mfaToken is used before the session access token exists. Defaults to the\n\t// client's stored token.\n\ttoken?: string;\n\t// Cache this GET for `cache` ms; false to skip; bust to force-refresh.\n\tcache?: number | false;\n\tbust?: boolean;\n\t// Extra cache key fragments to evict after a write.\n\tinvalidate?: string[];\n}\n\nexport class FonderieClient {\n\treadonly auth: AuthClient;\n\treadonly billing: BillingClient;\n\treadonly workspaces: WorkspacesClient;\n\treadonly audit: AuditClient;\n\treadonly webhooks: WebhooksClient;\n\treadonly customers: CustomersClient;\n\treadonly media: MediaClient;\n\t/** Public remote config: flags and settings the server exposes to frontends. */\n\treadonly config: ConfigClient;\n\n\tprivate http: HttpClient;\n\tprivate tokens: TokenStore;\n\tprivate workspaceId: string | undefined;\n\tprivate cache: ICache | undefined;\n\tprivate authConfig: IClientAuthConfig | undefined;\n\tprivate refreshing: Promise<string | undefined> | null = null;\n\n\tconstructor(opts: IFonderieClientOptions) {\n\t\tthis.tokens = new TokenStore(opts.accessToken);\n\t\tthis.workspaceId = opts.workspaceId;\n\t\tthis.cache = opts.cache;\n\t\tthis.authConfig = opts.auth;\n\t\tthis.http = new HttpClient(opts.baseUrl, {\n\t\t\tcache: opts.cache,\n\t\t\tdefaultTtlMs: (opts.cache as { defaultTtlMs?: number } | undefined)?.defaultTtlMs,\n\t\t\trefresh: opts.auth ? () => this.doRefresh() : undefined,\n\t\t});\n\t\tthis.auth = new AuthClient(this.http, this.tokens);\n\t\tthis.billing = new BillingClient(this.http, this.tokens);\n\t\tthis.workspaces = new WorkspacesClient(this.http, this.tokens);\n\t\tthis.audit = new AuditClient(this.http, this.tokens);\n\t\tthis.webhooks = new WebhooksClient(this.http, this.tokens);\n\t\tthis.customers = new CustomersClient(this.http, this.tokens);\n\t\t// Media is per-user (ownership via ownerType/ownerId in the body), so no\n\t\t// setWorkspaceId wiring below — just the shared http + token store.\n\t\tthis.media = new MediaClient(this.http, this.tokens);\n\t\tthis.config = new ConfigClient(this.http, this.tokens);\n\t\t// Route through the setter so the constructor option scopes the\n\t\t// workspace-aware modules exactly like a later setWorkspaceId() call.\n\t\tif (opts.workspaceId !== undefined) this.setWorkspaceId(opts.workspaceId);\n\t}\n\n\t// Single-flight refresh: POST /auth/refresh with the app-supplied refresh\n\t// token, store the new access token, notify the app, return it for the retry.\n\tprivate doRefresh(): Promise<string | undefined> {\n\t\tif (this.refreshing) return this.refreshing;\n\t\tthis.refreshing = (async () => {\n\t\t\tconst refreshToken = this.authConfig?.getRefreshToken?.();\n\t\t\tif (!refreshToken) {\n\t\t\t\tthis.authConfig?.onAuthError?.();\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { result } = await this.auth.refreshTokens(refreshToken);\n\t\t\t\tconst tokens = (result as unknown as { tokens: ITokens }).tokens;\n\t\t\t\tthis.tokens.set(tokens.access);\n\t\t\t\tthis.authConfig?.onTokensChanged?.(tokens);\n\t\t\t\treturn tokens.access;\n\t\t\t} catch {\n\t\t\t\tthis.tokens.set(undefined);\n\t\t\t\tthis.authConfig?.onAuthError?.();\n\t\t\t\treturn undefined;\n\t\t\t} finally {\n\t\t\t\tthis.refreshing = null;\n\t\t\t}\n\t\t})();\n\t\treturn this.refreshing;\n\t}\n\n\t// The JWT used to authenticate every request — the typed modules and the\n\t// generic transport share one token store. Passing undefined signs out and\n\t// clears the cache (so no session's data survives a logout).\n\tsetAccessToken(token: string | undefined): void {\n\t\tthis.tokens.set(token);\n\t\tif (!token) this.clearCache();\n\t}\n\n\t// Drop all cached responses (e.g. on switching accounts).\n\tclearCache(): void {\n\t\tthis.cache?.clear();\n\t}\n\n\t// Default X-Workspace-ID for the generic transport, also propagated to the\n\t// workspace-scoped modules so one call configures the whole client.\n\tsetWorkspaceId(workspaceId: string | undefined): void {\n\t\tthis.workspaceId = workspaceId;\n\t\tthis.billing.setWorkspaceId(workspaceId);\n\t\tthis.workspaces.setWorkspaceId(workspaceId);\n\t\tthis.customers.setWorkspaceId(workspaceId);\n\t\tthis.audit.setWorkspaceId(workspaceId);\n\t\tthis.webhooks.setWorkspaceId(workspaceId);\n\t}\n\n\t// ── Generic transport ──────────────────────────────────────────────────────\n\t// A Fonderie-aware HTTP client for endpoints outside the typed modules (an\n\t// app's own routes on the same backend). It attaches the shared JWT and\n\t// X-Workspace-ID automatically and returns Fonderie's { reason, explanation,\n\t// result } envelope — so you don't hand-roll auth for custom endpoints.\n\n\trequest<T = unknown>(opts: {\n\t\tmethod: string;\n\t\tpath: string;\n\t\tbody?: unknown;\n\t\ttoken?: string | undefined;\n\t\tworkspaceId?: string | undefined;\n\t\tcache?: number | false | undefined;\n\t\tbust?: boolean | undefined;\n\t\tinvalidate?: string[] | undefined;\n\t}): Promise<IApiResponse<T>> {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod: opts.method,\n\t\t\tpath: opts.path,\n\t\t\tbody: opts.body,\n\t\t\ttoken: opts.token ?? this.tokens.get(),\n\t\t\tworkspaceId: opts.workspaceId ?? this.workspaceId,\n\t\t\tcache: opts.cache,\n\t\t\tbust: opts.bust,\n\t\t\tinvalidate: opts.invalidate,\n\t\t});\n\t}\n\n\tget<T = unknown>(path: string, config?: IRequestConfig): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'GET',\n\t\t\tpath,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tcache: config?.cache,\n\t\t\tbust: config?.bust,\n\t\t});\n\t}\n\n\tpost<T = unknown>(\n\t\tpath: string,\n\t\tbody?: unknown,\n\t\tconfig?: IRequestConfig,\n\t): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'POST',\n\t\t\tpath,\n\t\t\tbody,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n\n\tput<T = unknown>(\n\t\tpath: string,\n\t\tbody?: unknown,\n\t\tconfig?: IRequestConfig,\n\t): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath,\n\t\t\tbody,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n\n\tpatch<T = unknown>(\n\t\tpath: string,\n\t\tbody?: unknown,\n\t\tconfig?: IRequestConfig,\n\t): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath,\n\t\t\tbody,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n\n\tdelete<T = unknown>(path: string, config?: IRequestConfig): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n}\n","// Where an admin surface is mounted, as CONFIG: trailing slashes are typing,\n// not meaning, so '/_admin', '/_admin/' and '/_admin//' are one prefix.\n//\n// This duplicates `normalizeMountPath` in @fonderie/core on purpose: this\n// package ships with **zero runtime dependencies** so it can be dropped into\n// any frontend, and importing a server package to strip a slash would end\n// that. One copy here, used by every admin client — not one per client.\nexport const normalizeMountPath = (path: string): string => path.replace(/\\/+$/, '');\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tIApiResponse,\n\tIConfigEntry,\n\tIConfigRevision,\n\tIRevealSecretResult,\n\tISecretEntry,\n\tISecretRevision,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ISetConfigInput {\n\tvalue: unknown;\n\tdescription?: string;\n\t// Deactivated entries stay stored but are excluded from runtime reads.\n\tactive?: boolean;\n\tifVersion?: number;\n\t/** Required to change an existing key's value kind (on/off → text, list → object);\n\t * without it the server answers 409 CONFIG_TYPE_CHANGE. */\n\tallowTypeChange?: boolean;\n}\n\nexport interface ISetSecretInput {\n\tvalue: string;\n\tdescription?: string;\n\t// Deactivated secrets stay stored but are excluded from runtime reads.\n\tactive?: boolean;\n\tifVersion?: number;\n}\n\nexport interface IRollbackInput {\n\ttoVersion: number;\n}\n\nexport interface IConfigAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where the composed surface lives when @fonderie/admin mounts this brick's\n\t// routes — '/_admin' replaces the leading '/admin' of every path. Unset ⇒\n\t// the brick's own standalone routes under '/admin'.\n\tprefix?: string;\n\t// Sent as X-Actor on writes — recorded as updatedBy and in revision\n\t// history (defaults server-side to 'admin-token').\n\tactor?: string;\n}\n\nfunction envQuery(environment?: string): string {\n\treturn environment ? `?environment=${encodeURIComponent(environment)}` : '';\n}\n\n// ── Config admin client ──────────────────────────────────────────────────────\n//\n// Separate from FonderieClient on purpose, for the same reason as\n// CourierAdminClient: @fonderie/config's admin routes (/admin/config/*,\n// /admin/secrets/*) are guarded by a static bearer token configured on the\n// server, not the signed-in user's session. Construct with that token\n// directly; it shares no state with AuthClient/BillingClient/WorkspacesClient.\nexport class ConfigAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string | undefined;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IConfigAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = opts.prefix ? normalizeMountPath(opts.prefix) : undefined;\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\t// The path literals stay on the legacy '/admin/...' so the route table and\n\t// the coverage gate read them; the prefix is applied here at request time.\n\tprivate rebase<T extends { path: string }>(opts: T): T {\n\t\tif (!this.prefix) return opts;\n\t\treturn { ...opts, path: opts.path.replace(/^\\/admin(?=\\/|\\?|$)/, this.prefix) };\n\t}\n\n\t// ── Config ───────────────────────────────────────────────────────────────\n\n\tlistConfig(environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/config${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tgetConfig(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tsetConfig(key: string, input: ISetConfigInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tdeleteConfig(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tlistConfigRevisions(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigRevision[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}/revisions${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\trollbackConfig(key: string, input: IRollbackInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}/rollback${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\t// ── Secrets (masked) ─────────────────────────────────────────────────────\n\n\tlistSecrets(environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/secrets${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tgetSecret(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tsetSecret(key: string, input: ISetSecretInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tdeleteSecret(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tlistSecretRevisions(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretRevision[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}/revisions${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\trollbackSecret(key: string, input: IRollbackInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}/rollback${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\t// POST (not GET) so the decrypted value never lands in a URL or access log.\n\trevealSecret(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IRevealSecretResult>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}/reveal${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tIAdminAttention,\n\tIAdminEnvironmentReport,\n\tIAdminDoctorReport,\n\tIAdminIssuedToken,\n\tIAdminIssueTokenInput,\n\tIAdminLogPage,\n\tIAdminManifest,\n\tIAdminMigrationModule,\n\tIAdminMigrationsReport,\n\tIAdminRoutesReport,\n\tIAdminTokensReport,\n\tIApiResponse,\n} from '../types';\n\nexport interface IAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\nexport interface IAdminLogQuery {\n\tlimit?: number;\n\tbefore?: string;\n}\n\n// Deliberately not on FonderieClient: no user session can reach this surface.\nexport class AdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\tprivate get<T>(suffix: string) {\n\t\treturn this.call<T>('GET', suffix);\n\t}\n\n\tprivate call<T>(method: string, suffix: string, body?: unknown) {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod,\n\t\t\tpath: `${this.prefix}${suffix}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t\t...(body !== undefined ? { body } : {}),\n\t\t});\n\t}\n\n\tattention() {\n\t\treturn this.get<IAdminAttention>('');\n\t}\n\n\tmanifest() {\n\t\treturn this.get<IAdminManifest>('/manifest');\n\t}\n\n\tdoctor() {\n\t\treturn this.get<IAdminDoctorReport>('/doctor');\n\t}\n\n\tenvironment() {\n\t\treturn this.get<IAdminEnvironmentReport>('/environment');\n\t}\n\n\troutes() {\n\t\treturn this.get<IAdminRoutesReport>('/routes');\n\t}\n\n\ttokens() {\n\t\treturn this.get<IAdminTokensReport>('/access/tokens');\n\t}\n\n\tadminLog(query: IAdminLogQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.before) q.set('before', query.before);\n\t\tconst qs = q.toString();\n\t\treturn this.get<IAdminLogPage>(`/activity/admin-log${qs ? `?${qs}` : ''}`);\n\t}\n\n\t// Root token only. The plaintext comes back once.\n\tissueToken(input: IAdminIssueTokenInput) {\n\t\treturn this.call<IAdminIssuedToken>('POST', '/access/tokens', input);\n\t}\n\n\t// Root token only.\n\trevokeToken(id: string) {\n\t\treturn this.call<undefined>('DELETE', `/access/tokens/${encodeURIComponent(id)}`);\n\t}\n\n\t// What each module is waiting on, with every pending file's impact. Empty\n\t// when the deployment did not hand its migration sequence to the surface.\n\tmigrations() {\n\t\treturn this.get<IAdminMigrationsReport>('/migrations');\n\t}\n\n\t/**\n\t * Apply one module's pending migrations — all of them, or none.\n\t *\n\t * `expect` is the pending list you were shown, in order. If it no longer\n\t * matches, the server refuses with 409 MIGRATIONS_CHANGED rather than\n\t * applying something nobody reviewed. Also refuses 409 when an earlier\n\t * module is behind, and 422 when any pending file deletes data.\n\t */\n\tapplyMigrations(module: string, expect: readonly string[]) {\n\t\treturn this.call<IAdminMigrationModule>(\n\t\t\t'POST',\n\t\t\t`/migrations/${encodeURIComponent(module)}/apply`,\n\t\t\t{ expect },\n\t\t);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tIAdminUserDTO,\n\tIAdminUserPageResult,\n\tIApiResponse,\n\tILoginHistoryPageResult,\n\tISessionDTO,\n} from '../types';\n\nexport interface IAuthAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\nexport interface IAdminLoginHistoryQuery {\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface IAdminUsersQuery {\n\tlimit?: number;\n\tcursor?: string;\n}\n\n// @fonderie/auth's operator routes, which exist only through @fonderie/admin.\n// Deliberately not on FonderieClient: no user session can reach them.\nexport class AuthAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IAuthAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\tprivate call<T>(method: string, suffix: string) {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod,\n\t\t\tpath: `${this.prefix}/users${suffix}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t});\n\t}\n\n\t// A page of users, newest first. The same route as findUser — with an email\n\t// it looks one up, without one it lists.\n\tlistUsers(query: IAdminUsersQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.call<IAdminUserPageResult>('GET', qs ? `?${qs}` : '');\n\t}\n\n\tfindUser(email: string) {\n\t\treturn this.call<IAdminUserDTO>('GET', `?email=${encodeURIComponent(email)}`);\n\t}\n\n\tgetUser(id: string) {\n\t\treturn this.call<IAdminUserDTO>('GET', `/${encodeURIComponent(id)}`);\n\t}\n\n\tlistUserSessions(id: string) {\n\t\treturn this.call<ISessionDTO[]>('GET', `/${encodeURIComponent(id)}/sessions`);\n\t}\n\n\t// Signs the user out everywhere.\n\trevokeUserSessions(id: string) {\n\t\treturn this.call<undefined>('DELETE', `/${encodeURIComponent(id)}/sessions`);\n\t}\n\n\tuserLoginHistory(id: string, query: IAdminLoginHistoryQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.call<ILoginHistoryPageResult>(\n\t\t\t'GET',\n\t\t\t`/${encodeURIComponent(id)}/login-history${qs ? `?${qs}` : ''}`,\n\t\t);\n\t}\n\n\tsuspendUser(id: string) {\n\t\treturn this.call<IAdminUserDTO>('POST', `/${encodeURIComponent(id)}/suspend`);\n\t}\n\n\tunsuspendUser(id: string) {\n\t\treturn this.call<IAdminUserDTO>('POST', `/${encodeURIComponent(id)}/unsuspend`);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tIAdminCatalog,\n\tIAdminGrantInput,\n\tIAdminPlanInput,\n\tIAdminSubscriptionDTO,\n\tIAdminSubscriptionPage,\n\tIAdminWalletDTO,\n\tIAdminWalletLedgerPage,\n\tIApiResponse,\n\tIPlanDTO,\n\tSubscriberType,\n} from '../types';\n\nexport interface IBillingAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\nexport interface IAdminSubscriptionsQuery {\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface IAdminLedgerQuery {\n\tcurrency?: string;\n\tlimit?: number;\n\tcursor?: string;\n}\n\n// @fonderie/billing's operator routes, which exist only through @fonderie/admin.\n// Deliberately not on FonderieClient: no user session can reach them.\nexport class BillingAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IBillingAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\tprivate call<T>(method: string, suffix: string, body?: unknown) {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod,\n\t\t\tpath: `${this.prefix}${suffix}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t\t...(body !== undefined ? { body } : {}),\n\t\t});\n\t}\n\n\tprivate sub(type: SubscriberType, id: string) {\n\t\treturn `/${type}/${encodeURIComponent(id)}`;\n\t}\n\n\tcatalog() {\n\t\treturn this.call<IAdminCatalog>('GET', '/catalog');\n\t}\n\n\tcreatePlan(input: IAdminPlanInput & { name: string }) {\n\t\treturn this.call<IPlanDTO>('POST', '/plans', input);\n\t}\n\n\tupdatePlan(planId: string, input: IAdminPlanInput) {\n\t\treturn this.call<IPlanDTO>('PUT', `/plans/${encodeURIComponent(planId)}`, input);\n\t}\n\n\tdeletePlan(planId: string) {\n\t\treturn this.call<undefined>('DELETE', `/plans/${encodeURIComponent(planId)}`);\n\t}\n\n\t// A page of subscribers, newest first. The lookup below still answers for a\n\t// known subscriber; this is for finding one you cannot name.\n\tlistSubscriptions(query: IAdminSubscriptionsQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.call<IAdminSubscriptionPage>('GET', `/subscriptions${qs ? `?${qs}` : ''}`);\n\t}\n\n\tsubscription(type: SubscriberType, id: string) {\n\t\treturn this.call<IAdminSubscriptionDTO>('GET', `/subscriptions${this.sub(type, id)}`);\n\t}\n\n\twallet(type: SubscriberType, id: string, currency?: string) {\n\t\tconst qs = currency ? `?currency=${encodeURIComponent(currency)}` : '';\n\t\treturn this.call<IAdminWalletDTO>('GET', `/wallet${this.sub(type, id)}${qs}`);\n\t}\n\n\twalletLedger(type: SubscriberType, id: string, query: IAdminLedgerQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.currency) q.set('currency', query.currency);\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.call<IAdminWalletLedgerPage>(\n\t\t\t'GET',\n\t\t\t`/wallet${this.sub(type, id)}/ledger${qs ? `?${qs}` : ''}`,\n\t\t);\n\t}\n\n\t// Manual credit — an idempotency key is required by the server.\n\tgrant(input: IAdminGrantInput) {\n\t\treturn this.call<unknown>('POST', '/wallet/grant', input);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type { IApiResponse, IAuditPageResult } from '../types';\n\nexport interface IAuditAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\n// The workspace-scoped filters, plus the workspace itself as a filter.\nexport interface IAdminAuditQuery {\n\tworkspaceId?: string;\n\ttype?: string;\n\tactorId?: string;\n\tfrom?: Date;\n\tto?: Date;\n\tlimit?: number;\n\tcursor?: string;\n}\n\n// @fonderie/audit's operator read, which exists only through @fonderie/admin.\nexport class AuditAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IAuditAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\t// Every workspace unless one is named. Newest first, keyset-paged.\n\tlistAudit(query: IAdminAuditQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.workspaceId) q.set('workspaceId', query.workspaceId);\n\t\tif (query.type) q.set('type', query.type);\n\t\tif (query.actorId) q.set('actorId', query.actorId);\n\t\tif (query.from) q.set('from', query.from.toISOString());\n\t\tif (query.to) q.set('to', query.to.toISOString());\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.http.request<IApiResponse<IAuditPageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `${this.prefix}/audit${qs ? `?${qs}` : ''}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t});\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type { IApiResponse, ITemplateEntry, ITemplateRevision } from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ISetTemplateInput {\n\ttext: string;\n\tsubject?: string;\n\thtml?: string;\n\tactive?: boolean;\n\tifVersion?: number;\n}\n\nexport interface IRollbackTemplateInput {\n\ttoVersion: number;\n}\n\nexport interface IPreviewTemplateInput {\n\ttext: string;\n\tsubject?: string;\n\thtml?: string;\n\t// Values for the template's {{variables}}. Omitted, every variable renders\n\t// empty and every {{#section}} collapses — accurate for layout, misleading\n\t// about content.\n\tdata?: Record<string, unknown>;\n}\n\n// What the renderer produced: no `html` key at all for a text-only template.\nexport interface IRenderedTemplateResult {\n\tsubject?: string;\n\thtml?: string;\n\ttext: string;\n\t// Every {{variable}} this content refers to, reported by the server so the\n\t// editor can offer the right fields without re-implementing the contract.\n\tvariables: string[];\n}\n\nexport interface ICourierAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where the composed surface lives when @fonderie/admin mounts this brick's\n\t// routes — '/_admin' replaces the leading '/admin' of every path. Unset ⇒\n\t// the brick's own standalone routes under '/admin'.\n\tprefix?: string;\n\t// Sent as X-Actor on writes — recorded as updatedBy and in revision\n\t// history (defaults server-side to 'admin-token').\n\tactor?: string;\n}\n\n// ── Courier admin client ─────────────────────────────────────────────────────\n//\n// Separate from FonderieClient on purpose: @fonderie/courier's admin routes\n// (/admin/templates/*) are guarded by a static bearer token configured on the\n// server (CourierModule's adminToken), not the signed-in user's session —\n// the same model @fonderie/config's admin surface uses, and the one the\n// `fonderie template`/`fonderie config` CLI commands already speak to via\n// FONDERIE_ADMIN_URL/FONDERIE_ADMIN_TOKEN. Bundling this into FonderieClient\n// would suggest an end-user's session token can reach it, which it can't —\n// this is an ops/admin-dashboard client, constructed with its own token.\nexport class CourierAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string | undefined;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: ICourierAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = opts.prefix ? normalizeMountPath(opts.prefix) : undefined;\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\t// The path literals stay on the legacy '/admin/...' so the route table and\n\t// the coverage gate read them; the prefix is applied here at request time.\n\tprivate rebase<T extends { path: string }>(opts: T): T {\n\t\tif (!this.prefix) return opts;\n\t\treturn { ...opts, path: opts.path.replace(/^\\/admin(?=\\/|\\?|$)/, this.prefix) };\n\t}\n\n\tlistTemplates() {\n\t\treturn this.http.request<IApiResponse<ITemplateEntry[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: '/admin/templates',\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tgetTemplate(type: string, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}${q}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tsetTemplate(type: string, input: ISetTemplateInput, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}${q}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tdeleteTemplate(type: string, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<undefined>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}${q}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tlistRevisions(type: string, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateRevision[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}/revisions${q}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\trollback(type: string, input: IRollbackTemplateInput, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}/rollback${q}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\t// Renders content you are HOLDING, not what is stored — so an editor can\n\t// show the change before it is saved. Server-side on purpose: the shell and\n\t// the variable substitution are the resolver's, and a preview rendered any\n\t// other way would not be the mail that sends.\n\tpreviewTemplate(type: string, input: IPreviewTemplateInput, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<IRenderedTemplateResult>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}/preview${q}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n}\n","// Per-call read options accepted by the typed sub-clients' GET methods.\nexport interface IReadOptions {\n\t// Ignore any cached value and refresh it (pull-to-refresh semantics).\n\tbust?: boolean | undefined;\n}\n\n// ── Envelope ─────────────────────────────────────────────────────────────────\n\nexport interface IApiResponse<T = undefined> {\n\treason: string;\n\texplanation: string;\n\tresult: T;\n}\n\nexport interface IApiError {\n\treason: string;\n\texplanation: string;\n\tdetails?: unknown;\n}\n\n// ── User ─────────────────────────────────────────────────────────────────────\n\nexport interface IUserPreferences {\n\tlocale: string;\n\ttimezone: string;\n\tnotifications: { email: boolean; inApp: boolean; sms: boolean; push: boolean };\n\temailDigest: string;\n\tdateFormat: string;\n\ttimeFormat: string;\n}\n\nexport interface IUserDTO {\n\tid: string;\n\temail: string;\n\tfirstName: string;\n\tlastName: string;\n\tphone: string;\n\tprofileImageUrl: string;\n\tisActive: boolean;\n\tlastLogin: string;\n\tpreferences: IUserPreferences;\n\tisEmailVerified: boolean;\n\tisPhoneVerified: boolean;\n\tmfaEnabled: boolean;\n\t// OAuth provider linked to this account ('google', 'apple'), or '' if none.\n\tprovider: string;\n\t// Whether a password is set. With `provider`, this is what a settings screen\n\t// needs to render sign-in methods and to know whether unlinkOauth() can\n\t// succeed — an account with no password has no other credential, so the\n\t// server refuses (409 PASSWORD_REQUIRED) rather than locking the user out.\n\thasPassword: boolean;\n\tsuspended: boolean;\n\twhitelist: boolean;\n\tipWhitelist: string[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface ITokens {\n\taccess: string;\n\trefresh: string;\n}\n\n// ── Auth endpoint results ─────────────────────────────────────────────────────\n\n/** What GET /auth/providers answers: the sign-in methods this API can honour. */\nexport interface IAuthProvidersResult {\n\tproviders: string[];\n}\n\nexport interface IRegisterResult {\n\ttokens: ITokens;\n\tuser: IUserDTO;\n\t// True when the account still needs email verification (config-dependent;\n\t// route the user to the verify screen). Absent on phone and MFA/OAuth\n\t// completions, which don't compute it.\n\trequiresVerification?: boolean;\n}\n\nexport interface ILoginResult {\n\ttokens: ITokens;\n\tuser: IUserDTO;\n\t// True when the account still needs email verification (config-dependent;\n\t// route the user to the verify screen). Absent on phone and MFA/OAuth\n\t// completions, which don't compute it.\n\trequiresVerification?: boolean;\n}\n\n// Login response when the account has MFA enabled: no tokens yet — complete\n// the login with auth.mfa.verifyLogin(mfaToken, code).\nexport interface IMfaRequiredResult {\n\tmfaToken: string;\n}\n\nexport function isMfaRequired(\n\tresult: ILoginResult | IMfaRequiredResult,\n): result is IMfaRequiredResult {\n\treturn !('tokens' in result);\n}\n\nexport interface IRefreshResult {\n\ttokens: ITokens;\n}\n\nexport interface IVerifyEmailResult {\n\tverified: boolean;\n\temail: string;\n}\n\n// GET /auth/send-verification: `{ email }` after a resend, `{ verified: true,\n// email }` when the address was already verified, and no result at all on the\n// phone branch — hence both fields optional. The verification pin itself is\n// only ever emailed; it never appears in the response.\nexport interface IResendVerificationResult {\n\temail?: string;\n\tverified?: boolean;\n}\n\nexport interface IMeResult {\n\tuser: IUserDTO;\n}\n\nexport interface IMfaSetupResult {\n\t// Data-URI QR code to scan, plus the one-time backup codes generated at\n\t// setup — matches @fonderie/auth's /auth/mfa/setup response.\n\tqr: string;\n\tbackupCodes: string[];\n}\n\n// POST /auth/mfa/verify with a full session token (setup confirmation). The\n// session token is NOT rotated — MFA is enforced at login, so the existing\n// session stays valid unchanged. The `{ tokens, user }` response only exists\n// on the mfa-pending login path, typed separately as ILoginResult (verifyLogin).\nexport interface IMfaEnabledResult {\n\tmfaEnabled: boolean;\n}\n\n// ── Billing ──────────────────────────────────────────────────────────────────\n\nexport interface IPlanFeature {\n\tname: string;\n\tdescription: string;\n\tenabled: boolean;\n\tlimit?: number;\n}\n\nexport interface IPlanDTO {\n\tid: string;\n\tplanId: string;\n\tname: string;\n\tdescription: string;\n\ttier: number;\n\tseats: number | null;\n\ttrialDays: number;\n\tpricing: {\n\t\tmonthly: number; // in cents, e.g. 1999 = $19.99\n\t\tyearly: number; // in cents\n\t\tcurrency: string; // ISO 4217, e.g. 'USD'\n\t};\n\t/** True when pricing came from a stale cache — a provider outage or a\n\t * transfer window. Show prices as indicative when set. */\n\tpricingStale?: boolean;\n\tfeatures: IPlanFeature[];\n\tmetadata: Record<string, unknown>;\n}\n\nexport type SubscriberType = 'user' | 'workspace';\n\nexport interface ISubscriptionDTO {\n\tid: string;\n\tsubscriberType: SubscriberType;\n\tsubscriberId: string;\n\tplan: string;\n\tinterval: string;\n\tstatus: string;\n\tcancelAtPeriodEnd: boolean;\n\tcurrentPeriodStart: string | null;\n\tcurrentPeriodEnd: string | null;\n\ttrialEndsAt: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IPlanListResult {\n\tplans: IPlanDTO[];\n}\n\nexport interface IPlanResult {\n\tplan: IPlanDTO;\n}\n\nexport interface ISubscriptionResult {\n\tsubscription: ISubscriptionDTO;\n}\n\nexport interface ICheckoutUrlResult {\n\turl: string;\n}\n\nexport interface IPortalUrlResult {\n\turl: string;\n}\n\nexport interface IUsageResult {\n\tmetric: string;\n\ttotal: number;\n\tsince: string;\n}\n\n// Wallet balance snapshot. Money fields are digit strings (server bigint →\n// string); spendPurchased is a real boolean. granted/purchased/spendPurchased/\n// grantedExpiresAt are omitted on a legacy read that predates the bucket split.\nexport interface IWalletDTO {\n\tbalance: string;\n\tcurrency: string;\n\tprecision: number;\n\tgranted?: string;\n\tpurchased?: string;\n\tspendPurchased?: boolean;\n\tgrantedExpiresAt?: string | null;\n}\n\nexport interface IWalletResult {\n\twallet: IWalletDTO;\n}\n\n// One wallet ledger entry. Money fields are digit strings (server bigint →\n// string); `balanceAfter` is the running balance, so a history UI can show a\n// trustworthy per-row balance without re-deriving it.\nexport interface IWalletTransactionDTO {\n\tid: string;\n\ttype: string; // 'purchase' | 'grant' | 'usage' | 'refund' | 'adjustment' | 'expiry'\n\tamount: string; // signed: positive = credit, negative = debit\n\tbalanceAfter: string;\n\tcurrency: string;\n\tdescription: string | null;\n\tproviderTxId: string | null;\n\tmetadata: Record<string, unknown>;\n\tcreatedAt: string;\n}\n\nexport interface IWalletTransactionsResult {\n\ttransactions: IWalletTransactionDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface IWalletCheckoutInput {\n\tpackId: string;\n}\n\nexport interface IWalletPurchaseInput {\n\tpackId: string;\n\t// One per purchase attempt, REUSED on retry: a double-submit or a retry after\n\t// a `processing` result dedupes to the same charge instead of charging twice.\n\tidempotencyKey: string;\n}\n\n// Outcome of an in-app pack purchase charged to the saved card. `status` is the\n// discriminator: 'credited' carries the new balance; 'checkout_required' means\n// fall back to createWalletCheckout (no saved card, or the card needs 3-D\n// Secure); 'declined' is a hard decline; 'processing' is indeterminate — retry\n// with the SAME idempotencyKey (never a fresh hosted checkout, or you'd risk a\n// double-charge).\nexport interface IWalletPurchaseResult {\n\tstatus: 'credited' | 'checkout_required' | 'declined' | 'processing';\n\tbalance?: string;\n\tcurrency?: string;\n\tcredits?: string;\n\tduplicate?: boolean;\n\treason?: 'no_saved_card' | 'authentication_required';\n}\n\nexport interface ICancelSubscriptionInput {\n\t// Default true — keep access until the paid-through date. false ends it now.\n\tatPeriodEnd?: boolean;\n}\n\n// Result of a first-party cancel/reactivate — the subscription's new lifecycle\n// state, read straight back without waiting for the provider webhook.\nexport interface ISubscriptionChangeResult {\n\tatPeriodEnd: boolean;\n\tstatus: string;\n\tcurrentPeriodEnd: string | null;\n}\n\n// The customer's card on file, for display. Never carries the full number —\n// nor the server-side card `fingerprint`, which billing deliberately keeps\n// off the wire (it correlates identity across accounts).\nexport interface IPaymentMethodDTO {\n\tbrand: string;\n\tlast4: string;\n\texpMonth: number;\n\texpYear: number;\n}\n\nexport interface IPaymentMethodResult {\n\tpaymentMethod: IPaymentMethodDTO | null;\n}\n\n// Begin in-app card entry: the provider SetupIntent client secret the embedded\n// card element (Stripe Payment Element) confirms — no hosted-checkout redirect.\nexport interface ISetupIntentResult {\n\tclientSecret: string;\n}\n\n// Save a card after the client confirms the SetupIntent — the provider payment\n// method id the Payment Element produced.\nexport interface ISavePaymentMethodInput {\n\tpaymentMethodId: string;\n}\n\n// One invoice for an in-app history list; `hostedInvoiceUrl`/`invoicePdf` link\n// out to the provider. Amounts are digit strings (smallest currency unit).\nexport interface IInvoiceDTO {\n\tid: string;\n\tnumber: string | null;\n\tamountDue: string;\n\tamountPaid: string;\n\tcurrency: string;\n\tstatus: string;\n\tcreated: string;\n\tdueDate: string | null; // ISO-8601 when the invoice has payment terms; null when paid on charge\n\thostedInvoiceUrl: string | null;\n\tinvoicePdf: string | null;\n}\n\nexport interface IInvoicesResult {\n\tinvoices: IInvoiceDTO[];\n}\n\n// ── Workspaces ───────────────────────────────────────────────────────────────\n\nexport interface IWorkspaceAddressDTO {\n\tline1: string;\n\tline2: string;\n\tcity: string;\n\tstate: string;\n\tzip: string;\n\tcountry: string;\n}\n\nexport interface IWorkspaceDTO {\n\tid: string;\n\tname: string;\n\tslug: string;\n\ttype: string;\n\tdescription: string;\n\tmotto: string;\n\tphone: string;\n\tbusinessType: string;\n\taddress: IWorkspaceAddressDTO;\n\tplan: string;\n\townerId: string;\n\tisPersonal: boolean;\n\tisArchived: boolean;\n\tarchivedAt: string;\n\t// User id that archived the workspace; '' while unarchived.\n\tarchivedBy: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface IRoleDTO {\n\tid: string;\n\tname: string;\n\tisSystem: boolean;\n\tactive: boolean;\n\tdescription: string;\n\tworkspaceId: string;\n}\n\nexport interface IMemberDTO {\n\tuserId: string;\n\tworkspaceId: string;\n\troleId: string;\n\troleName: string;\n\tconfirmed: boolean;\n\tcreatedAt: string;\n\t/** Identity, so a member list can be rendered without a second request. */\n\temail: string;\n\tfirstName: string;\n\tlastName: string;\n\tprofileImageUrl: string;\n}\n\nexport interface IInvitationDTO {\n\tid: string;\n\tworkspaceId: string;\n\temail: string;\n\troleId: string;\n\ttoken: string;\n\tstatus: string;\n\texpiresAt: string;\n\tcreatedAt: string;\n}\n\nexport interface IWorkspaceSettingsDTO {\n\tlocale: string;\n\ttimezone: string;\n\tcurrency: string;\n\tdateFormat: string;\n\ttimeFormat: string;\n}\n\nexport interface IWorkspaceListResult {\n\tworkspaces: IWorkspaceDTO[];\n}\n\nexport interface IWorkspaceResult {\n\tworkspace: IWorkspaceDTO;\n}\n\nexport interface IMemberListResult {\n\tmembers: IMemberDTO[];\n}\n\nexport interface IRoleListResult {\n\troles: IRoleDTO[];\n}\n\nexport interface IRoleResult {\n\trole: IRoleDTO;\n}\n\nexport interface IInvitationListResult {\n\tinvitations: IInvitationDTO[];\n}\n\nexport interface IInviteResult {\n\tinvitations: Array<{ invitationId: string; email: string }>;\n}\n\nexport interface IAcceptInvitationResult {\n\tworkspaceId: string;\n}\n\nexport interface IWorkspaceSettingsResult {\n\tsettings: IWorkspaceSettingsDTO;\n}\n\n// ── Courier admin (template management) ─────────────────────────────────────\n// Admin-token authenticated, not user-session authenticated — see\n// CourierAdminClient. Result shapes here are the raw resource, not wrapped\n// in a named key, matching @fonderie/courier's admin route handlers.\n\nexport interface ITemplateEntry {\n\ttype: string;\n\tlocale: string | null;\n\tsubject: string | null;\n\thtml: string | null;\n\ttext: string;\n\tactive: boolean;\n\tversion: number;\n\tupdatedBy: string | null;\n\tupdatedAt: string;\n}\n\nexport interface ITemplateRevision {\n\ttype: string;\n\tlocale: string | null;\n\tsubject: string | null;\n\thtml: string | null;\n\ttext: string;\n\tversion: number;\n\tactor: string | null;\n\tcreatedAt: string;\n}\n\n// ── Admin (the operator's surface) ───────────────────────────────────────────\n// Admin-token authenticated — see AdminClient. Shapes mirror @fonderie/admin's\n// pages; the client owns its copies, like every other section here.\n\nexport interface IAdminReadinessProblem {\n\tmodule: string;\n\tseverity: 'error' | 'warning';\n\tmessage: string;\n}\n\nexport interface IAdminReadiness {\n\tok: boolean;\n\tproblems: IAdminReadinessProblem[];\n}\n\nexport interface IAdminModuleEntry {\n\tname: string;\n\tversion: string | null;\n\treadiness: IAdminReadiness;\n\tdescribesAdmin: boolean;\n}\n\nexport interface IAdminRouteEntry {\n\tmethod: string;\n\tpath: string;\n\tmodule?: string;\n}\n\nexport interface IAdminManifest {\n\tgeneratedAt: string;\n\tenv: string;\n\t// `host` is null when the surface answers on any hostname.\n\tadmin: { version: string; log: boolean; host: string[] | null };\n\tmodules: IAdminModuleEntry[];\n\treadiness: IAdminReadiness;\n\troutes: IAdminRouteEntry[];\n}\n\nexport interface IAdminCheckResult {\n\tname: string;\n\tmodule: string;\n\tok: boolean;\n\tfindings: string[];\n\tskipped?: string;\n\tdurationMs: number;\n}\n\nexport interface IAdminDoctorReport {\n\tgeneratedAt: string;\n\tok: boolean;\n\tchecks: IAdminCheckResult[];\n}\n\nexport interface IAdminAttentionItem {\n\tsource: string;\n\tseverity: 'error' | 'advice';\n\tmessage: string;\n}\n\nexport interface IAdminAttention {\n\tgeneratedAt: string;\n\tok: boolean;\n\titems: IAdminAttentionItem[];\n}\n\nexport interface IAdminEnvironmentReport {\n\tgeneratedAt: string;\n\treadiness: IAdminReadiness;\n\tmodules: Array<{ name: string; problems: IAdminReadinessProblem[] }>;\n\tenv: Array<{ name: string; set: boolean }>;\n}\n\nexport type AdminRouteGuard = 'admin' | 'probe' | 'app';\n\nexport interface IAdminRoutesReport {\n\tgeneratedAt: string;\n\troutes: Array<IAdminRouteEntry & { guard: AdminRouteGuard }>;\n}\n\nexport type AdminScope = 'read' | 'write' | 'secrets';\n\n// An issued scoped token — never its hash or plaintext.\nexport interface IAdminTokenRecord {\n\tid: string;\n\tname: string;\n\tscopes: AdminScope[];\n\tcreatedBy: string;\n\tcreatedAt: string;\n\texpiresAt: string | null;\n\trevokedAt: string | null;\n\tlastUsedAt: string | null;\n}\n\nexport interface IAdminTokensReport {\n\tgeneratedAt: string;\n\tadmin: { ok: boolean; problems: IAdminReadinessProblem[] };\n\tlegacy: Array<{ module: string; set: boolean }>;\n\t// null when the deployment gave AdminModule no store (issuing is off).\n\tissued: IAdminTokenRecord[] | null;\n}\n\nexport interface IAdminIssueTokenInput {\n\tname: string;\n\tscopes: AdminScope[];\n\texpiresInDays?: number;\n}\n\n// The plaintext is returned once, at issue, and never again.\nexport interface IAdminIssuedToken extends IAdminTokenRecord {\n\ttoken: string;\n}\n\nexport interface IAdminLogEntry {\n\tid: string;\n\tat: string;\n\tactor: string;\n\tmethod: string;\n\tpath: string;\n\troute: string;\n\tmodule: string;\n\tstatus: number;\n\tdurationMs: number;\n\trequestId: string | null;\n\tclientIp: string | null;\n}\n\nexport interface IAdminLogPage {\n\tentries: IAdminLogEntry[];\n\tnext: string | null;\n}\n\n// The operator's view of a user (@fonderie/auth's described admin routes):\n// the app's own DTO plus what support asks about. Never a hash or MFA secret.\nexport interface IAdminUserDTO extends IUserDTO {\n\tdeletedAt: string | null;\n}\n\n// The operator's money reads (@fonderie/billing's described admin routes).\nexport interface IAdminCatalog {\n\t// config.plans as declared; bigint wallet amounts arrive as strings.\n\tconfigured: unknown[];\n\tstored: IPlanDTO[];\n}\n\nexport interface IAdminSubscriptionDTO {\n\tid: string;\n\tsubscriberType: SubscriberType;\n\tsubscriberId: string;\n\tplan: string;\n\tinterval: string;\n\tstatus: string;\n\tproviderCustomerId: string | null;\n\tproviderSubscriptionId: string | null;\n\tcurrentPeriodStart: string | null;\n\tcurrentPeriodEnd: string | null;\n\tcancelAtPeriodEnd: boolean;\n\ttrialEndsAt: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IAdminWalletDTO extends IWalletDTO {\n\tversion: number;\n\tupdatedAt: string | null;\n}\n\nexport interface IAdminSubscriptionPage {\n\tsubscriptions: IAdminSubscriptionDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface IAdminWalletLedgerPage {\n\tcurrency: string;\n\tentries: IWalletTransactionDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface IAdminPlanInput {\n\tname?: string;\n\tdescription?: string | null;\n\ttier?: number;\n\tseats?: number | null;\n\ttrialDays?: number;\n\tmonthlyAmount?: number | null;\n\tmonthlyPriceId?: string | null;\n\tyearlyAmount?: number | null;\n\tyearlyPriceId?: string | null;\n\tfeatures?: unknown;\n\tmetadata?: unknown;\n}\n\nexport interface IAdminGrantInput {\n\tsubscriberType: SubscriberType;\n\tsubscriberId: string;\n\t// Minor units as a digit string (or a number below 2^53).\n\tamount: string | number;\n\tcurrency?: string;\n\tdescription?: string;\n\tidempotencyKey: string;\n}\n\n// ── Config admin (feature flags / remote config + secrets) ──────────────────\n// Admin-token authenticated, not user-session authenticated — see\n// ConfigAdminClient. Result shapes here are the raw resource, matching\n// @fonderie/config's admin route handlers.\n\nexport interface IConfigEntry {\n\tkey: string;\n\tvalue: unknown;\n\tenvironment: string;\n\tdescription: string | null;\n\tactive: boolean;\n\tversion: number;\n\tupdatedBy: string | null;\n\tupdatedAt: string;\n}\n\nexport interface IConfigRevision {\n\tkey: string;\n\tenvironment: string;\n\tvalue: unknown;\n\tversion: number;\n\tactor: string | null;\n\tcreatedAt: string;\n}\n\n// Deliberately has no `value` — admin list/get never return a secret's\n// plaintext, only the explicit reveal path does.\nexport interface ISecretEntry {\n\tkey: string;\n\tenvironment: string;\n\tdescription: string | null;\n\tactive: boolean;\n\tversion: number;\n\tupdatedBy: string | null;\n\tupdatedAt: string;\n}\n\nexport interface ISecretRevision {\n\tkey: string;\n\tenvironment: string;\n\tversion: number;\n\tactor: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IRevealSecretResult {\n\tvalue: string;\n}\n\n// ── Audit ────────────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, scoped via\n// setWorkspaceId like billing/workspaces) — unlike courier-admin/config-admin,\n// which use a standalone admin token. Read-only: @fonderie/audit has one route.\n\nexport interface IAuditEventDTO {\n\tid: string;\n\ttype: string;\n\tactorId: string | null;\n\trequestId: string | null;\n\tpayload: Record<string, unknown>;\n\tcreatedAt: string;\n}\n\nexport interface IAuditPageResult {\n\tevents: IAuditEventDTO[];\n\tnextCursor: string | null;\n}\n\n// ── Login activity (auth security surfaces) ──────────────────────────────────\n// Session-authenticated; the caller's own history + sessions (shares the\n// AuthClient token). Login history is append-only; sessions are the live list.\n\n/** Where an auth event (login attempt, registration, session) came from. Present only when the server configures a\n * location resolver; every field is optional. Country is reliable; region and\n * city are approximate; network fields appear only with an IP-intelligence\n * provider. */\nexport interface IRequestLocationDTO {\n\tcountry?: string; // ISO-3166-1 alpha-2\n\tcountryName?: string;\n\tsubdivision?: string; // ISO-3166-2 region part\n\tsubdivisionName?: string;\n\tcity?: string;\n\tpostalCode?: string; // ZIP / postal code, approximate — not shown by describeLocation\n\tcontinent?: string;\n\ttimeZone?: string;\n\tlatitude?: number;\n\tlongitude?: number;\n\taccuracyRadius?: number; // km — how approximate the point is\n\tgeonameId?: number; // stable, language-neutral place key (GeoNames)\n\tisp?: string;\n\torg?: string;\n\tasn?: string;\n\tmobile?: boolean;\n\tproxy?: boolean;\n\thosting?: boolean;\n}\n\n/**\n * One short line for a login location: \"Mountain View, CA, US\" — most specific first,\n * skipping what is unknown. Pass a country-name formatter to localise the\n * country (e.g. Intl.DisplayNames). null when nothing is known.\n */\nexport function describeLocation(\n\tloc: IRequestLocationDTO | null | undefined,\n\tcountryName?: (code: string) => string | undefined,\n): string | null {\n\tif (!loc) return null;\n\tconst country = loc.country ? (countryName?.(loc.country) ?? loc.country) : (loc.countryName ?? undefined);\n\tconst parts = [loc.city, loc.subdivision ?? loc.subdivisionName, country].filter(\n\t\t(p): p is string => typeof p === 'string' && p.length > 0,\n\t);\n\treturn parts.length > 0 ? parts.join(', ') : null;\n}\n\nexport interface ILoginEventDTO {\n\tid: string;\n\tmethod: string;\n\toutcome: string;\n\tfailureReason: string | null;\n\tipAddress: string | null;\n\tuserAgent: string | null;\n\t/** null when the server has no location resolver, or it knew nothing. */\n\tlocation: IRequestLocationDTO | null;\n\tcreatedAt: string;\n}\n\nexport interface IAdminUserPageResult {\n\tusers: IAdminUserDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface ILoginHistoryPageResult {\n\tevents: ILoginEventDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface ISessionDTO {\n\tid: string;\n\tcurrent: boolean;\n\tipAddress: string | null;\n\tuserAgent: string | null;\n\t/** Where the session was opened from; null without a server-side resolver. */\n\tlocation: IRequestLocationDTO | null;\n\tcreatedAt: string;\n\texpiresAt: string;\n}\n\nexport interface ISessionsResult {\n\tsessions: ISessionDTO[];\n}\n\n// ── Media ────────────────────────────────────────────────────────────────────\n// Session-authenticated image storage (avatars, logos). `url` is the\n// monomorphic, backend-relative /media/:id path; call client.media.assetUrl(id)\n// for an absolute `<img src>`.\n\nexport interface IMediaAssetDTO {\n\tid: string;\n\turl: string;\n\tcontentType: string;\n\tbyteSize: number;\n\townerType: string;\n\townerId: string;\n\tpurpose: string;\n\tcreatedAt: string;\n}\n\nexport interface IMediaAssetResult {\n\tasset: IMediaAssetDTO;\n}\n\n// ── Webhooks ─────────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, scoped via\n// setWorkspaceId like billing/workspaces/audit).\n\nexport interface IWebhookEndpointDTO {\n\tid: string;\n\turl: string;\n\tevents: string[];\n\tenabled: boolean;\n\tcreatedAt: string;\n}\n\n// The signing secret is only ever returned here, at creation — every other\n// read masks it, matching @fonderie/webhooks' own toEndpointDTO/toEndpointCreatedDTO split.\nexport interface IWebhookEndpointCreatedDTO extends IWebhookEndpointDTO {\n\tsecret: string;\n}\n\nexport interface IWebhookDeliveryDTO {\n\tid: string;\n\teventId: string;\n\teventType: string;\n\tstatus: string;\n\tattempts: number;\n\t// The event body that was delivered — what the endpoint received.\n\tpayload: Record<string, unknown>;\n\tresponseStatus: number | null;\n\t// The receiving endpoint's response body (useful when debugging failures).\n\tresponseBody: string | null;\n\t// When the next retry is due; null once delivered or exhausted.\n\tnextAttemptAt: string | null;\n\tdeliveredAt: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IWebhookEndpointListResult {\n\tendpoints: IWebhookEndpointDTO[];\n}\n\nexport interface IWebhookDeliveryListResult {\n\tdeliveries: IWebhookDeliveryDTO[];\n}\n\nexport interface ITestWebhookResult {\n\tstatus: number | null;\n\tok: boolean;\n\terror?: string;\n}\n\n// ── Customers ────────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, scoped via\n// setWorkspaceId like billing/workspaces/audit/webhooks).\n\nexport type CustomerType = 'individual' | 'business';\nexport type CustomerSex = 'UNKNOWN' | 'MALE' | 'FEMALE';\nexport type CustomerLabelType = 'phone' | 'email' | 'address';\n\nexport interface ICustomerDTO {\n\tid: string;\n\ttype: string;\n\tsex: CustomerSex;\n\tfirstName: string;\n\tlastName: string;\n\tcompanyName: string;\n\tavatarUrl: string;\n\tlocale: string;\n\treferenceCode: string;\n\treferralCode: string;\n\treferredBy: string | null;\n\tblacklisted: { status: boolean; reason: string | null };\n\tcreatedBy: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface ICustomerEmailDTO {\n\tid: string;\n\temail: string;\n\tlabel: string;\n\t// Id of the shared label row (see listLabels) — null when unlabeled.\n\tlabelId: string | null;\n\tisPrimary: boolean;\n\tcreatedAt: string;\n}\n\nexport interface ICustomerPhoneDTO {\n\tid: string;\n\tphone: string;\n\tlabel: string;\n\t// Id of the shared label row (see listLabels) — null when unlabeled.\n\tlabelId: string | null;\n\tisPrimary: boolean;\n\tcreatedAt: string;\n}\n\nexport interface IAddressDTO {\n\tcountryIso: string;\n\tsubdivision1Iso: string;\n\tsubdivision2Iso: string;\n\tzipPostalCode: string;\n\tunit: string;\n\tline1: string;\n\tline2: string;\n}\n\nexport interface ICustomerAddressDTO {\n\tid: string;\n\tlabel: string;\n\t// Id of the shared label row (see listLabels) — null when unlabeled.\n\tlabelId: string | null;\n\tisPrimary: boolean;\n\taddress: IAddressDTO;\n}\n\nexport interface ICustomerNoteDTO {\n\tid: string;\n\tauthorId: string;\n\tbody: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface ICustomerRelationshipDTO {\n\tid: string;\n\trelatedId: string;\n\trelationship: string;\n\tisPrimary: boolean;\n\tcreatedAt: string;\n}\n\n// Flat merge: relationship metadata + related customer fields spread at the\n// same level. `id` is the relationship record id; `customerId` is the\n// related customer's id — matches @fonderie/customers' own flattening.\nexport type ICustomerRelationshipExpandedDTO = Omit<ICustomerShallowDTO, 'id'> & {\n\tid: string;\n\tcustomerId: string;\n\trelationship: string;\n\tisPrimary: boolean;\n\t// When the relationship itself was created. The spread customer fields\n\t// include the related CUSTOMER's createdAt/updatedAt — don't sort\n\t// relationships by those.\n\trelationshipCreatedAt: string;\n};\n\nexport type ICustomerRelationshipExpandedD2DTO = ICustomerRelationshipExpandedDTO & {\n\trelationships: ICustomerRelationshipExpandedDTO[];\n};\n\nexport interface ICustomerShallowDTO extends ICustomerDTO {\n\temails: ICustomerEmailDTO[];\n\tphones: ICustomerPhoneDTO[];\n\taddresses: ICustomerAddressDTO[];\n\tnotes: ICustomerNoteDTO[];\n\ttags: string[];\n}\n\nexport interface ICustomerDetailDTO extends ICustomerDTO {\n\temails: ICustomerEmailDTO[];\n\tphones: ICustomerPhoneDTO[];\n\taddresses: ICustomerAddressDTO[];\n\tnotes: ICustomerNoteDTO[];\n\trelationships: ICustomerRelationshipExpandedDTO[];\n\ttags: string[];\n}\n\n// depth=1 (default via getCustomer) — one level of relationship expansion.\n// depth=2 (getCustomer(id, { depth: 2 })) — relationships carry their own\n// relationships array one level deeper. Matches @fonderie/customers' D2 DTOs.\nexport interface ICustomerDetailD2DTO extends Omit<ICustomerDetailDTO, 'relationships'> {\n\trelationships: ICustomerRelationshipExpandedD2DTO[];\n}\n\nexport interface ICustomerLabelDTO {\n\tid: string;\n\ttype: CustomerLabelType;\n\tvalue: string;\n\tcreatedAt: string;\n}\n\nexport interface ICustomerListResult {\n\tcustomers: ICustomerDTO[];\n\t// Total matching rows regardless of limit/offset — for pagination.\n\ttotal: number;\n}\n\nexport interface ICustomerResult {\n\tcustomer: ICustomerDTO;\n}\n\nexport interface ICustomerEmailListResult {\n\temails: ICustomerEmailDTO[];\n}\n\nexport interface ICustomerEmailResult {\n\temail: ICustomerEmailDTO;\n}\n\nexport interface ICustomerPhoneListResult {\n\tphones: ICustomerPhoneDTO[];\n}\n\nexport interface ICustomerPhoneResult {\n\tphone: ICustomerPhoneDTO;\n}\n\nexport interface ICustomerAddressListResult {\n\taddresses: ICustomerAddressDTO[];\n}\n\nexport interface ICustomerAddressResult {\n\taddress: ICustomerAddressDTO;\n}\n\nexport interface ICustomerNoteListResult {\n\tnotes: ICustomerNoteDTO[];\n}\n\nexport interface ICustomerNoteResult {\n\tnote: ICustomerNoteDTO;\n}\n\nexport interface ICustomerTagListResult {\n\ttags: string[];\n}\n\nexport interface ICustomerRelationshipListResult {\n\trelationships: ICustomerRelationshipDTO[];\n}\n\nexport interface ICustomerRelationshipResult {\n\trelationship: ICustomerRelationshipDTO;\n}\n\nexport interface ICustomerLabelListResult {\n\tlabels: ICustomerLabelDTO[];\n}\n\n// ---- admin: migrations ----------------------------------------------------\n\nexport type MigrationImpact = 'additive' | 'destructive';\n\nexport interface IAdminPendingMigration {\n\tfile: string;\n\timpact: MigrationImpact;\n\t// The statements that earned a 'destructive' label, as written.\n\tdestructive: string[];\n}\n\nexport interface IAdminMigrationModule {\n\tname: string;\n\tpending: IAdminPendingMigration[];\n\t// The first EARLIER module that is behind, or null. Migration order is the\n\t// app's and sets depend on each other across it.\n\tblockedBy: string | null;\n\t// Whether the panel will apply this one: something to do, nothing in front\n\t// of it, and nothing in it that deletes data.\n\tappliable: boolean;\n}\n\nexport interface IAdminMigrationsReport {\n\t// False when the database has no fonderie_migrations rows — a first\n\t// install, where \"destructive\" has nothing to destroy.\n\teverApplied: boolean;\n\tmodules: IAdminMigrationModule[];\n}\n","// Typed config values for admin UIs (and, later, feature-flag hooks).\n//\n// Config values are stored as JSON, so a stored `true` stays a boolean and `3`\n// stays a number. What an editor needs on top is: which input to show for a\n// value, and how to turn what the operator typed back into a typed value —\n// with an explanation, not a silent failure, when it doesn't parse.\n\nexport type ConfigValueType = 'string' | 'number' | 'boolean' | 'json';\n\nexport const CONFIG_VALUE_TYPES: readonly ConfigValueType[] = ['string', 'number', 'boolean', 'json'];\n\n/** The editor type for a stored value. Objects, arrays and null are JSON. */\nexport function configValueType(value: unknown): ConfigValueType {\n\tif (typeof value === 'string') return 'string';\n\tif (typeof value === 'number') return 'number';\n\tif (typeof value === 'boolean') return 'boolean';\n\treturn 'json';\n}\n\n/** What an input should show for a stored value of that type. */\nexport function formatConfigValue(value: unknown, type: ConfigValueType = configValueType(value)): string {\n\tif (type === 'string') return typeof value === 'string' ? value : String(value ?? '');\n\tif (type === 'number') return typeof value === 'number' ? String(value) : '';\n\tif (type === 'boolean') return value === true ? 'true' : 'false';\n\treturn JSON.stringify(value ?? null, null, 2);\n}\n\nexport type CastResult = { ok: true; value: unknown } | { ok: false; error: string };\n\n/**\n * Turn what an operator typed into the typed value to store.\n * - string: kept verbatim (an empty string is a valid value)\n * - number: finite numbers only — \"1e3\" and \"-2.5\" are fine, \"12px\" is not\n * - boolean: true/false, also 1/0, yes/no, on/off (case-insensitive)\n * - json: any valid JSON\n */\nexport function castConfigValue(type: ConfigValueType, raw: string): CastResult {\n\tif (type === 'string') return { ok: true, value: raw };\n\tconst t = raw.trim();\n\tif (type === 'number') {\n\t\tif (t === '') return { ok: false, error: 'Enter a number.' };\n\t\tconst n = Number(t);\n\t\treturn Number.isFinite(n) ? { ok: true, value: n } : { ok: false, error: `\"${raw}\" is not a number.` };\n\t}\n\tif (type === 'boolean') {\n\t\tconst v = t.toLowerCase();\n\t\tif (['true', '1', 'yes', 'on'].includes(v)) return { ok: true, value: true };\n\t\tif (['false', '0', 'no', 'off'].includes(v)) return { ok: true, value: false };\n\t\treturn { ok: false, error: 'Use true or false.' };\n\t}\n\ttry {\n\t\treturn { ok: true, value: JSON.parse(t) };\n\t} catch (err) {\n\t\treturn { ok: false, error: `Not valid JSON: ${(err as Error).message}` };\n\t}\n}\n\n/**\n * Config keys: letters, digits, `.`, `_`, `-`; must start with a letter; up to\n * 128 characters. Both styles work — `ENABLE_JOB_LISTING` and `feature.dark-mode`.\n */\nexport const CONFIG_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9._-]{0,127}$/;\n\nexport function configKeyProblem(key: string): string | null {\n\tif (!key) return 'Enter a key.';\n\treturn CONFIG_KEY_PATTERN.test(key)\n\t\t? null\n\t\t: 'Start with a letter; use letters, digits, \".\", \"_\" or \"-\" (max 128).';\n}\n\nexport interface IInferredConfigValue {\n\ttype: ConfigValueType;\n\tvalue: unknown;\n\t/** Human label for the detected shape: Text, Number, On/off, Object, List. */\n\tlabel: string;\n\t/**\n\t * True when the input could equally be meant as text — \"true\", \"42\". The\n\t * editor offers \"save as text instead\" for exactly these, and never needs\n\t * to ask about anything else.\n\t */\n\tambiguous: boolean;\n}\n\n// A number only when writing it back gives the same characters: \"42\" and\n// \"-2.5\" qualify; \"1.10\" (a version), \"0123\" (a postal code), \"1e3\" and\n// 12345678901234567890 (an ID past float precision) do not — they stay text\n// rather than being silently rewritten.\nconst PLAIN_NUMBER = /^-?(0|[1-9]\\d*)(\\.\\d+)?$/;\n\n/** Human label for a stored value's shape. */\nexport function configValueLabel(value: unknown): string {\n\tif (typeof value === 'string') return 'Text';\n\tif (typeof value === 'number') return 'Number';\n\tif (typeof value === 'boolean') return 'On/off';\n\tif (Array.isArray(value)) return 'List';\n\tif (value === null) return 'Empty';\n\treturn 'Object';\n}\n\n/**\n * Work out what an operator typed, without asking. Objects and lists (JSON\n * starting with { or [), on/off (true/false), plain numbers, and text for\n * everything else — including anything that merely resembles a number.\n */\nexport function inferConfigValue(raw: string): IInferredConfigValue {\n\tconst t = raw.trim();\n\tif (t === 'true' || t === 'false') {\n\t\treturn { type: 'boolean', value: t === 'true', label: 'On/off', ambiguous: true };\n\t}\n\tif (PLAIN_NUMBER.test(t)) {\n\t\tconst n = Number(t);\n\t\tif (Number.isFinite(n) && String(n) === t) return { type: 'number', value: n, label: 'Number', ambiguous: true };\n\t}\n\tif (t.startsWith('{') || t.startsWith('[')) {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(t);\n\t\t\tif (parsed !== null && typeof parsed === 'object') {\n\t\t\t\treturn { type: 'json', value: parsed, label: Array.isArray(parsed) ? 'List' : 'Object', ambiguous: false };\n\t\t\t}\n\t\t} catch {\n\t\t\t// not valid JSON — it is text that happens to start with a bracket\n\t\t}\n\t}\n\treturn { type: 'string', value: raw, label: 'Text', ambiguous: false };\n}\n"],"mappings":";AA4BO,SAAS,kBACf,OAA4B,CAAC,GACO;AACpC,QAAM,QAAQ,oBAAI,IAAmB;AACrC,QAAM,WAAW,oBAAI,IAA8B;AACnD,QAAM,eAAe,KAAK,gBAAgB;AAE1C,SAAO;AAAA,IACN;AAAA,IAEA,IAAO,KAA4B;AAClC,YAAM,QAAQ,MAAM,IAAI,GAAG;AAC3B,UAAI,CAAC,MAAO,QAAO;AACnB,UAAI,KAAK,IAAI,IAAI,MAAM,WAAW;AACjC,cAAM,OAAO,GAAG;AAChB,eAAO;AAAA,MACR;AACA,aAAO,MAAM;AAAA,IACd;AAAA,IAEA,IAAO,KAAa,OAAU,OAAqB;AAClD,YAAM,IAAI,KAAK,EAAE,OAAO,WAAW,KAAK,IAAI,IAAI,MAAM,CAAC;AAAA,IACxD;AAAA,IAEA,OAAU,KAAa,IAAkC;AACxD,YAAM,WAAW,SAAS,IAAI,GAAG;AACjC,UAAI,SAAU,QAAO;AACrB,YAAM,MAAM,GAAG,EAAE,QAAQ,MAAM,SAAS,OAAO,GAAG,CAAC;AACnD,eAAS,IAAI,KAAK,GAAG;AACrB,aAAO;AAAA,IACR;AAAA,IAEA,WAAW,UAAwB;AAClC,iBAAW,OAAO,MAAM,KAAK,EAAG,KAAI,IAAI,SAAS,QAAQ,EAAG,OAAM,OAAO,GAAG;AAC5E,iBAAW,OAAO,SAAS,KAAK,EAAG,KAAI,IAAI,SAAS,QAAQ,EAAG,UAAS,OAAO,GAAG;AAAA,IACnF;AAAA,IAEA,QAAc;AACb,YAAM,MAAM;AACZ,eAAS,MAAM;AAAA,IAChB;AAAA,EACD;AACD;;;ACnEO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC3C,YACiB,QACA,aACA,QACA,SAGA,WACf;AACD,UAAM,WAAW;AARD;AACA;AACA;AACA;AAGA;AAGhB,SAAK,OAAO;AAAA,EACb;AAAA,EAViB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAKlB;AAKA,SAAS,QAAQ,OAAuB;AACvC,QAAM,IAAK,WAAgF;AAC3F,QAAM,MAAM,IAAI,WAAW,KAAK;AAChC,MAAI,GAAG,gBAAiB,GAAE,gBAAgB,GAAG;AAAA,MACxC,UAAS,IAAI,GAAG,IAAI,OAAO,IAAK,KAAI,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAC5E,MAAI,MAAM;AACV,aAAW,KAAK,IAAK,QAAO,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC1D,SAAO;AACR;AAgCO,IAAM,aAAN,MAAiB;AAAA,EAKvB,YACS,SACR,OAAkB,CAAC,GAClB;AAFO;AAGR,SAAK,QAAQ,KAAK;AAClB,SAAK,eAAe,KAAK,gBAAgB;AACzC,SAAK,UAAU,KAAK;AAAA,EACrB;AAAA,EANS;AAAA,EALD;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAcR,SAAS,MAAsB;AAC9B,WAAO,GAAG,KAAK,OAAO,GAAG,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA,EAIA,aAAmB;AAClB,SAAK,OAAO,MAAM;AAAA,EACnB;AAAA,EAEA,MAAM,QAAW,MAAmC;AACnD,UAAM,SAAS,KAAK,OAAO,YAAY;AAEvC,UAAM,QAAQ,KAAK;AAGnB,QAAI,SAAS,WAAW,SAAS,KAAK,UAAU,OAAO;AACtD,YAAM,MAAM,OAAO,KAAK,IAAI,QAAQ,KAAK,eAAe,EAAE;AAC1D,UAAI,CAAC,KAAK,MAAM;AACf,cAAM,MAAM,MAAM,IAAO,GAAG;AAC5B,YAAI,QAAQ,OAAW,QAAO;AAAA,MAC/B;AACA,YAAM,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAK;AAC/D,aAAO,MAAM,OAAO,KAAK,YAAY;AACpC,cAAMA,QAAO,MAAM,KAAK,KAAQ,IAAI;AACpC,cAAM,IAAI,KAAKA,OAAM,GAAG;AACxB,eAAOA;AAAA,MACR,CAAC;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,KAAK,KAAQ,IAAI;AAGpC,QAAI,SAAS,WAAW,OAAO;AAC9B,YAAM,WAAW,KAAK,KAAK,MAAM,GAAG,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,CAAC;AACtE,UAAI,SAAU,OAAM,WAAW,IAAI,QAAQ,EAAE;AAC7C,iBAAW,YAAY,KAAK,cAAc,CAAC,EAAG,OAAM,WAAW,QAAQ;AAAA,IACxE;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,MAAc,KAAQ,MAAuB,UAAU,OAAmB;AAGzE,UAAM,UAAU,QAAQ,EAAE;AAC1B,UAAM,YAAY;AAClB,UAAM,UAAkC;AAAA,MACvC,gBAAgB;AAAA,MAChB,aAAa,MAAM,OAAO,IAAI,QAAQ,CAAC,CAAC;AAAA,MACxC,gBAAgB;AAAA,IACjB;AACA,QAAI,KAAK,MAAO,SAAQ,eAAe,IAAI,UAAU,KAAK,KAAK;AAC/D,QAAI,KAAK,OAAQ,SAAQ,QAAQ,IAAI,KAAK;AAC1C,QAAI,KAAK,YAAa,SAAQ,gBAAgB,IAAI,KAAK;AACvD,WAAO,OAAO,SAAS,KAAK,WAAW,CAAC,CAAC;AAEzC,UAAM,YAAyB,EAAE,QAAQ,KAAK,QAAQ,SAAS,aAAa,UAAU;AACtF,QAAI,KAAK,SAAS,OAAW,WAAU,OAAO,KAAK,UAAU,KAAK,IAAI;AAEtE,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,KAAK,IAAI,IAAI,SAAS;AAGhE,UAAM,MAAM,IAAI,QAAQ,IAAI,cAAc,KAAK;AAI/C,QAAI,IAAI,WAAW,OAAO,KAAK,WAAW,CAAC,WAAW,CAAC,KAAK,KAAK,WAAW,QAAQ,GAAG;AACtF,YAAM,WAAW,MAAM,KAAK,QAAQ;AACpC,UAAI,SAAU,QAAO,KAAK,KAAQ,EAAE,GAAG,MAAM,OAAO,SAAS,GAAG,IAAI;AAAA,IACrE;AAGA,QAAI,IAAI,WAAW,KAAK;AACvB,UAAI,CAAC,IAAI;AACR,cAAM,IAAI,iBAAiB,WAAW,IAAI,YAAY,IAAI,QAAQ,QAAW,GAAG;AACjF,aAAO;AAAA,IACR;AAEA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAE7B,QAAI,CAAC,IAAI,MAAM,IAAI,WAAW,KAAK;AAClC,YAAM,MAAM;AACZ,YAAM,IAAI,iBAAiB,IAAI,QAAQ,IAAI,aAAa,IAAI,QAAQ,IAAI,SAAS,GAAG;AAAA,IACrF;AAEA,WAAO;AAAA,EACR;AACD;;;ACrJO,IAAM,cAAN,MAAkB;AAAA,EAGxB,YACS,MACA,QACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD;AAAA,EAOR,eAAe,OAA2B;AACzC,SAAK,OAAO,IAAI,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA,EAIA,eAAe,aAAiC;AAC/C,SAAK,cAAc;AAAA,EACpB;AAAA,EAEA,WAAW,QAA+B,CAAC,GAAG,MAAqB;AAClE,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,MAAM,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACtE,QAAI,MAAM,KAAM,QAAO,IAAI,QAAQ,MAAM,IAAI;AAC7C,QAAI,MAAM,QAAS,QAAO,IAAI,WAAW,MAAM,OAAO;AACtD,QAAI,MAAM,KAAM,QAAO,IAAI,QAAQ,MAAM,KAAK,YAAY,CAAC;AAC3D,QAAI,MAAM,GAAI,QAAO,IAAI,MAAM,MAAM,GAAG,YAAY,CAAC;AACrD,QAAI,MAAM,OAAQ,QAAO,IAAI,UAAU,MAAM,MAAM;AACnD,UAAM,KAAK,OAAO,SAAS;AAE3B,WAAO,KAAK,KAAK,QAAwC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM,SAAS,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,MACjC,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AACD;;;ACqCA,IAAM,YAAN,MAAgB;AAAA,EACf,YACS,MACA,OACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAGT,QAAQ;AACP,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,MAAM;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,OAAO,OAAe;AACrB,WAAO,KAAK,KAAK,QAAyC;AAAA,MACzD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,MAAM;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAAkB,MAAc;AAC3C,WAAO,KAAK,KAAK,QAAoC;AAAA,MACpD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,OAAO,KAAK;AAAA,MACpB,OAAO;AAAA,IACR,CAAC;AAAA,EACF;AAAA,EAEA,QAAQ,OAAe;AACtB,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,MAAM;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,sBAAsB,OAAe;AACpC,WAAO,KAAK,KAAK,QAAiD;AAAA,MACjE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,MAAM;AAAA,IACnB,CAAC;AAAA,EACF;AACD;AAIO,IAAM,aAAN,MAAiB;AAAA,EAGvB,YACS,MACA,QACP;AAFO;AACA;AAER,SAAK,MAAM,IAAI,UAAU,MAAM,MAAM,KAAK,OAAO,IAAI,CAAC;AAAA,EACvD;AAAA,EAJS;AAAA,EACA;AAAA,EAJA;AAAA,EAST,eAAe,OAA2B;AACzC,SAAK,OAAO,IAAI,KAAK;AAGrB,QAAI,CAAC,MAAO,MAAK,KAAK,WAAW;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,YAAY;AACX,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,YAAY,UAAkB;AAC7B,WAAO,KAAK,KAAK,QAA4B;AAAA,MAC5C,QAAQ;AAAA,MACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,IAClD,CAAC;AAAA,EACF;AAAA,EAEA,SAAS,OAAuB;AAC/B,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAAA,EAEA,MAAM,OAAoB;AACzB,WAAO,KAAK,KAAK,QAAyD;AAAA,MACzE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAA0B;AACrC,WAAO,KAAK,KAAK,QAAoC;AAAA,MACpD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAAA,EAEA,cAAc,cAAuB;AACpC,WAAO,KAAK,KAAK,QAAsC;AAAA,MACtD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,eAAe,EAAE,aAAa,IAAI;AAAA,IACzC,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,OAAe;AAC7B,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,MAAM;AAAA,IACf,CAAC;AAAA,EACF;AAAA,EAEA,cAAc,OAA4B;AACzC,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AAAA,EAEA,YAAY,OAAe;AAG1B,WAAO,KAAK,KAAK,QAA0C;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,OAAO,cAAuB;AAC7B,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,eAAe,EAAE,aAAa,IAAI;AAAA,MACxC,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,wBAAwB;AAEvB,WAAO,KAAK,KAAK,QAAiD;AAAA,MACjE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA;AAAA;AAAA,MAGvB,OAAO;AAAA,IACR,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,QAAQ,MAAqB;AAC5B,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,cAAc,OAA4B;AACzC,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,kBAAkB,OAAgC;AACjD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,YAAY,OAAe;AAC1B,WAAO,KAAK,KAAK,QAA+B;AAAA,MAC/C,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,YAAY,OAAe;AAC1B,WAAO,KAAK,KAAK,QAA+B;AAAA,MAC/C,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,OAA6B;AAC3C,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,aAAa;AACZ,WAAO,KAAK,KAAK,QAA+B;AAAA,MAC/C,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,aAAa;AACZ,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,QAA+B,CAAC,GAAG,MAAqB;AACvE,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,MAAM,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACtE,QAAI,MAAM,QAAS,QAAO,IAAI,WAAW,MAAM,OAAO;AACtD,QAAI,MAAM,KAAM,QAAO,IAAI,QAAQ,MAAM,KAAK,YAAY,CAAC;AAC3D,QAAI,MAAM,GAAI,QAAO,IAAI,MAAM,MAAM,GAAG,YAAY,CAAC;AACrD,QAAI,MAAM,OAAQ,QAAO,IAAI,UAAU,MAAM,MAAM;AACnD,UAAM,KAAK,OAAO,SAAS;AAG3B,WAAO,KAAK,KAAK,QAA+C;AAAA,MAC/D,QAAQ;AAAA,MACR,MAAM,sBAAsB,KAAK,MAAM,KAAK,EAAE;AAAA,MAC9C,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,MAAqB;AACjC,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,iBAAiB,IAAY;AAC5B,WAAO,KAAK,KAAK,QAAsC;AAAA,MACtD,QAAQ;AAAA,MACR,MAAM,kBAAkB,mBAAmB,EAAE,CAAC;AAAA,MAC9C,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,yBAAyB;AACxB,WAAO,KAAK,KAAK,QAAyC;AAAA,MACzD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AACD;;;ACrVO,IAAM,gBAAN,MAAoB;AAAA,EAG1B,YACS,MACA,QACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD;AAAA,EAOR,eAAe,OAA2B;AACzC,SAAK,OAAO,IAAI,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,aAAiC;AAC/C,SAAK,cAAc;AAAA,EACpB;AAAA;AAAA,EAIA,UAAU,MAAqB;AAC9B,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,QAAQ,QAAgB,MAAqB;AAC5C,WAAO,KAAK,KAAK,QAAmC;AAAA,MACnD,QAAQ;AAAA,MACR,MAAM,UAAU,mBAAmB,MAAM,CAAC;AAAA,MAC1C,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,WAAW,OAAyB;AACnC,WAAO,KAAK,KAAK,QAAmC;AAAA,MACnD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,QAAgB,OAAyB;AACnD,WAAO,KAAK,KAAK,QAAmC;AAAA,MACnD,QAAQ;AAAA,MACR,MAAM,UAAU,mBAAmB,MAAM,CAAC;AAAA,MAC1C,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,QAAgB;AAC1B,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,UAAU,mBAAmB,MAAM,CAAC;AAAA,MAC1C,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,gBAAgB,MAAqB;AACpC,WAAO,KAAK,KAAK,QAA2C;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,OAAkC;AACpD,WAAO,KAAK,KAAK,QAAiD;AAAA,MACjE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,SAAS,CAAC;AAAA,MAChB,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,yBAAyB;AACxB,WAAO,KAAK,KAAK,QAAiD;AAAA,MACjE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,sBAAsB,OAAuB;AAC5C,WAAO,KAAK,KAAK,QAA0C;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,sBAAsB;AACrB,WAAO,KAAK,KAAK,QAAwC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,YAAY,OAA0B;AACrC,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,SAAS,QAAgB,MAAqB;AAC7C,WAAO,KAAK,KAAK,QAAoC;AAAA,MACpD,QAAQ;AAAA,MACR,MAAM,kBAAkB,mBAAmB,MAAM,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,UAAU,MAAqB;AAC9B,WAAO,KAAK,KAAK,QAAqC;AAAA,MACrD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,qBAAqB,OAAgC;AACpD,WAAO,KAAK,KAAK,QAAqC;AAAA,MACrD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,qBAAqB,OAA6B;AACjD,WAAO,KAAK,KAAK,QAA0C;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmB,OAA6B;AAC/C,WAAO,KAAK,KAAK,QAA6C;AAAA,MAC7D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,sBAAsB,MAA2D;AAChF,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,MAAM,OAAQ,QAAO,IAAI,UAAU,KAAK,MAAM;AAClD,QAAI,MAAM,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC;AACrE,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,KAAK,KAAK,QAAiD;AAAA,MACjE,QAAQ;AAAA,MACR,MAAM,+BAA+B,KAAK,MAAM,KAAK,EAAE;AAAA,MACvD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,MAAqB;AACrC,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB;AACpB,WAAO,KAAK,KAAK,QAA0C;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,kBAAkB,OAAgC;AACjD,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,sBAAsB;AACrB,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,aAAa,MAAqB;AACjC,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AACD;;;ACpPO,IAAM,kBAAN,MAAsB;AAAA,EAG5B,YACS,MACA,QACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD;AAAA,EAOR,eAAe,OAA2B;AACzC,SAAK,OAAO,IAAI,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA,EAIA,eAAe,aAAiC;AAC/C,SAAK,cAAc;AAAA,EACpB;AAAA;AAAA,EAIA,cAAc,QAA6B,CAAC,GAAG,MAAqB;AACnE,UAAM,SAAS,IAAI,gBAAgB;AACnC,QAAI,MAAM,WAAW,OAAW,QAAO,IAAI,UAAU,MAAM,MAAM;AACjE,QAAI,MAAM,gBAAgB,OAAW,QAAO,IAAI,eAAe,OAAO,MAAM,WAAW,CAAC;AACxF,QAAI,MAAM,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACtE,QAAI,MAAM,WAAW,OAAW,QAAO,IAAI,UAAU,OAAO,MAAM,MAAM,CAAC;AACzE,UAAM,KAAK,OAAO,SAAS;AAE3B,WAAO,KAAK,KAAK,QAA2C;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM,KAAK,cAAc,EAAE,KAAK;AAAA,MAChC,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,QAA8B,CAAC,GAAG;AAChD,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,YAAY,YAAoB,QAA2B,CAAC,GAAG,MAAqB;AACnF,UAAM,KAAK,MAAM,UAAU,IAAI,aAAa;AAC5C,WAAO,KAAK,KAAK,QAAiE;AAAA,MACjF,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,GAAG,EAAE;AAAA,MACvD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,YAAoB,OAA6B;AAC/D,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,YAAoB;AAClC,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,kBAAkB,YAAoB,QAAiC,CAAC,GAAG;AAC1E,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,oBAAoB,YAAoB;AACvC,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,WAAW,YAAoB,MAAqB;AACnD,WAAO,KAAK,KAAK,QAAgD;AAAA,MAChE,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,SAAS,YAAoB,OAAuB;AACnD,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,iBAAiB,YAAoB,SAAiB,OAAe;AACpE,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,WAAW,mBAAmB,OAAO,CAAC;AAAA,MACxF,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,gBAAgB,YAAoB,SAAiB;AACpD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,WAAW,mBAAmB,OAAO,CAAC;AAAA,MACxF,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,YAAY,YAAoB,SAAiB;AAChD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,WAAW,mBAAmB,OAAO,CAAC;AAAA,MACxF,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,WAAW,YAAoB,MAAqB;AACnD,WAAO,KAAK,KAAK,QAAgD;AAAA,MAChE,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,SAAS,YAAoB,OAAuB;AACnD,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,iBAAiB,YAAoB,SAAiB,OAAe;AACpE,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,WAAW,mBAAmB,OAAO,CAAC;AAAA,MACxF,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,gBAAgB,YAAoB,SAAiB;AACpD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,WAAW,mBAAmB,OAAO,CAAC;AAAA,MACxF,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,YAAY,YAAoB,SAAiB;AAChD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,WAAW,mBAAmB,OAAO,CAAC;AAAA,MACxF,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,cAAc,YAAoB,MAAqB;AACtD,WAAO,KAAK,KAAK,QAAkD;AAAA,MAClE,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,YAAoB,OAAyB;AACvD,WAAO,KAAK,KAAK,QAA8C;AAAA,MAC9D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB,YAAoB,QAAgB,OAAe;AACrE,WAAO,KAAK,KAAK,QAA8C;AAAA,MAC9D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,cAAc,mBAAmB,MAAM,CAAC;AAAA,MAC1F,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,kBAAkB,YAAoB,QAAgB;AACrD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,cAAc,mBAAmB,MAAM,CAAC;AAAA,MAC1F,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,cAAc,YAAoB,QAAgB;AACjD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,cAAc,mBAAmB,MAAM,CAAC;AAAA,MAC1F,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,UAAU,YAAoB,MAAqB;AAClD,WAAO,KAAK,KAAK,QAA+C;AAAA,MAC/D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,YAAoB,MAAc;AAC5C,WAAO,KAAK,KAAK,QAA2C;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM,EAAE,KAAK;AAAA,MACb,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,YAAoB,QAAgB,MAAc;AAC5D,WAAO,KAAK,KAAK,QAA2C;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,UAAU,mBAAmB,MAAM,CAAC;AAAA,MACtF,MAAM,EAAE,KAAK;AAAA,MACb,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,YAAoB,QAAgB;AAC9C,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,UAAU,mBAAmB,MAAM,CAAC;AAAA,MACtF,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,SAAS,YAAoB,MAAqB;AACjD,WAAO,KAAK,KAAK,QAA8C;AAAA,MAC9D,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,OAAO,YAAoB,KAAa;AACvC,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM,EAAE,IAAI;AAAA,MACZ,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,UAAU,YAAoB,KAAa;AAC1C,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,UAAU,SAAS,mBAAmB,GAAG,CAAC;AAAA,MAC9D,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,kBAAkB,YAAoB,MAAqB;AAC1D,WAAO,KAAK,KAAK,QAAuD;AAAA,MACvE,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,gBAAgB,YAAoB,OAA8B;AACjE,WAAO,KAAK,KAAK,QAAmD;AAAA,MACnE,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC;AAAA,MAClD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,uBAAuB,YAAoB,WAAmB;AAC7D,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,kBAAkB,mBAAmB,SAAS,CAAC;AAAA,MACjG,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,mBAAmB,YAAoB,WAAmB;AACzD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,UAAU,CAAC,kBAAkB,mBAAmB,SAAS,CAAC;AAAA,MACjG,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,MAAyB,MAAqB;AACxD,WAAO,KAAK,KAAK,QAAgD;AAAA,MAChE,QAAQ;AAAA,MACR,MAAM,0BAA0B,mBAAmB,IAAI,CAAC;AAAA,MACxD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,YAAY,SAAiB;AAC5B,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,qBAAqB,mBAAmB,OAAO,CAAC;AAAA,MACtD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AACD;;;AC3cO,IAAM,cAAN,MAAkB;AAAA,EACxB,YACS,MACA,QACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAGT,eAAe,OAA2B;AACzC,SAAK,OAAO,IAAI,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA,EAIA,OAAO,OAA0B;AAChC,WAAO,KAAK,KAAK,QAAyC;AAAA,MACzD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,IAAY;AAClB,WAAO,KAAK,KAAK,QAAsC;AAAA,MACtD,QAAQ;AAAA,MACR,MAAM,UAAU,mBAAmB,EAAE,CAAC;AAAA,MACtC,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,IAAoB;AAC5B,WAAO,KAAK,KAAK,SAAS,UAAU,mBAAmB,EAAE,CAAC,EAAE;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,KAA+C;AAC7D,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,IAAI,IAAI;AAAA,MACb;AAAA,IACD;AACA,WAAO,IAAI,EAAE,CAAC,IAAK;AAAA,EACpB;AACD;;;ACjDO,IAAM,eAAN,MAAmB;AAAA,EAKzB,YACS,MACA,QACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAND,QAA4B,EAAE,QAAQ,CAAC,GAAG,UAAU,MAAM,WAAW,OAAO,OAAO,KAAK;AAAA,EACxF,YAAY,oBAAI,IAAc;AAAA,EAC9B,WAA+C;AAAA;AAAA;AAAA;AAAA;AAAA,EAWvD,OAAoC;AACnC,QAAI,KAAK,SAAU,QAAO,KAAK;AAC/B,SAAK,IAAI,EAAE,WAAW,KAAK,CAAC;AAC5B,SAAK,WAAW,KAAK,KACnB,QAA2D;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM;AAAA;AAAA;AAAA,MAGN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC,EACA;AAAA,MACA,CAAC,QAAQ,KAAK,IAAI,EAAE,QAAQ,IAAI,QAAQ,UAAU,CAAC,GAAG,UAAU,oBAAI,KAAK,GAAG,WAAW,OAAO,OAAO,KAAK,CAAC;AAAA,MAC3G,CAAC,UAAmB,KAAK,IAAI,EAAE,WAAW,OAAO,MAAM,CAAC;AAAA,IACzD,EACC,QAAQ,MAAM;AACd,WAAK,WAAW;AAAA,IACjB,CAAC;AACF,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,IAAO,KAAa,UAAgB;AACnC,WAAO,OAAO,OAAO,KAAK,MAAM,QAAQ,GAAG,IAAK,KAAK,MAAM,OAAO,GAAG,IAAU;AAAA,EAChF;AAAA;AAAA,EAGA,WAA+B;AAC9B,WAAO,KAAK;AAAA,EACb;AAAA;AAAA,EAGA,UAAU,UAAgC;AACzC,SAAK,UAAU,IAAI,QAAQ;AAC3B,WAAO,MAAM;AACZ,WAAK,UAAU,OAAO,QAAQ;AAAA,IAC/B;AAAA,EACD;AAAA,EAEQ,IAAI,OAAwD;AAGnE,SAAK,QAAQ,EAAE,GAAG,KAAK,OAAO,GAAG,MAAM;AACvC,eAAW,YAAY,KAAK,UAAW,UAAS,KAAK,KAAK;AAC1D,WAAO,KAAK;AAAA,EACb;AACD;;;AC1DO,IAAM,iBAAN,MAAqB;AAAA,EAG3B,YACS,MACA,QACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD;AAAA,EAOR,eAAe,OAA2B;AACzC,SAAK,OAAO,IAAI,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA,EAIA,eAAe,aAAiC;AAC/C,SAAK,cAAc;AAAA,EACpB;AAAA,EAEA,cAAc,MAAqB;AAClC,WAAO,KAAK,KAAK,QAAkD;AAAA,MAClE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,eAAe,OAAoC;AAClD,WAAO,KAAK,KAAK,QAAkD;AAAA,MAClE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,YAAY,YAAoB,MAAqB;AACpD,WAAO,KAAK,KAAK,QAA2C;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM,aAAa,mBAAmB,UAAU,CAAC;AAAA,MACjD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,YAAoB,OAAoC;AACtE,WAAO,KAAK,KAAK,QAA2C;AAAA,MAC3D,QAAQ;AAAA,MACR,MAAM,aAAa,mBAAmB,UAAU,CAAC;AAAA,MACjD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,YAAoB;AAClC,WAAO,KAAK,KAAK,QAAmB;AAAA,MACnC,QAAQ;AAAA,MACR,MAAM,aAAa,mBAAmB,UAAU,CAAC;AAAA,MACjD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,YAAoB,MAAqB;AACvD,WAAO,KAAK,KAAK,QAAkD;AAAA,MAClE,QAAQ;AAAA,MACR,MAAM,aAAa,mBAAmB,UAAU,CAAC;AAAA,MACjD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,aAAa,YAAoB;AAChC,WAAO,KAAK,KAAK,QAA0C;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM,aAAa,mBAAmB,UAAU,CAAC;AAAA,MACjD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AACD;;;AC5BO,IAAM,mBAAN,MAAuB;AAAA,EAG7B,YACS,MACA,QACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD;AAAA,EAOR,eAAe,OAA2B;AACzC,SAAK,OAAO,IAAI,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA,EAIA,eAAe,aAAiC;AAC/C,SAAK,cAAc;AAAA,EACpB;AAAA;AAAA,EAIA,eAAe,MAAqB;AACnC,WAAO,KAAK,KAAK,QAA4C;AAAA,MAC5D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,gBAAgB,OAA8B;AAC7C,WAAO,KAAK,KAAK,QAAwC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA,EAEA,aAAa,IAAY,MAAqB;AAC7C,WAAO,KAAK,KAAK,QAAwC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM,eAAe,mBAAmB,EAAE,CAAC;AAAA,MAC3C,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,gBAAgB,OAA8B;AAC7C,WAAO,KAAK,KAAK,QAAwC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB;AAClB,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,mBAAmB;AAClB,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,UAAU,MAAqB;AAC9B,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,OAAyB;AACnC,WAAO,KAAK,KAAK,QAAmC;AAAA,MACnD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,QAAQ,QAAgB,MAAqB;AAC5C,WAAO,KAAK,KAAK,QAAmC;AAAA,MACnD,QAAQ;AAAA,MACR,MAAM,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MACrD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,QAAgB,OAAyB;AACnD,WAAO,KAAK,KAAK,QAAmC;AAAA,MACnD,QAAQ;AAAA,MACR,MAAM,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MACrD,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,WAAW,QAAgB;AAC1B,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MACrD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,mBAAmB,QAAgB,MAAqB;AACvD,WAAO,KAAK,KAAK,QAA8C;AAAA,MAC9D,QAAQ;AAAA,MACR,MAAM,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MACrD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,mBAAmB,QAAgB,aAAqC;AACvE,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,qBAAqB,mBAAmB,MAAM,CAAC;AAAA,MACrD,MAAM,EAAE,YAAY;AAAA,MACpB,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,YAAY,MAAqB;AAChC,WAAO,KAAK,KAAK,QAAyC;AAAA,MACzD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,aAAa,QAAgB;AAC5B,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,uBAAuB,mBAAmB,MAAM,CAAC;AAAA,MACvD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,QAAgB,MAAqB;AACnD,WAAO,KAAK,KAAK,QAAuC;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM,uBAAuB,mBAAmB,MAAM,CAAC;AAAA,MACvD,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,cAAc,QAAgB,QAAgB;AAC7C,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,uBAAuB,mBAAmB,MAAM,CAAC;AAAA,MACvD,MAAM,EAAE,OAAO;AAAA,MACf,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,iBAAiB,QAAgB,QAAgB;AAChD,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,uBAAuB,mBAAmB,MAAM,CAAC,UAAU,mBAAmB,MAAM,CAAC;AAAA,MAC3F,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,gBAAgB,MAAqB;AACpC,WAAO,KAAK,KAAK,QAA6C;AAAA,MAC7D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,OAAO,SAAwC;AAC9C,WAAO,KAAK,KAAK,QAAqC;AAAA,MACrD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,iBAAiB,UAAkB;AAClC,WAAO,KAAK,KAAK,QAAiC;AAAA,MACjD,QAAQ;AAAA,MACR,MAAM,2BAA2B,mBAAmB,QAAQ,CAAC;AAAA,MAC7D,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AAAA,EAEA,iBAAiB,KAAa;AAC7B,WAAO,KAAK,KAAK,QAA+C;AAAA,MAC/D,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,IAAI;AAAA,MACZ,OAAO,KAAK,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA,EAIA,YAAY,MAAqB;AAChC,WAAO,KAAK,KAAK,QAAgD;AAAA,MAChE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,MAAM,MAAM;AAAA,IACb,CAAC;AAAA,EACF;AAAA,EAEA,eAAe,OAA6B;AAC3C,WAAO,KAAK,KAAK,QAAgD;AAAA,MAChE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO,KAAK,OAAO,IAAI;AAAA,MACvB,aAAa,KAAK;AAAA,IACnB,CAAC;AAAA,EACF;AACD;;;ACpVO,IAAM,aAAN,MAAiB;AAAA,EACf;AAAA,EAER,YAAY,SAAkB;AAC7B,SAAK,QAAQ;AAAA,EACd;AAAA,EAEA,MAA0B;AACzB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,IAAI,OAA2B;AAC9B,SAAK,QAAQ;AAAA,EACd;AACD;;;AC4BO,IAAM,iBAAN,MAAqB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EAED;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAiD;AAAA,EAEzD,YAAY,MAA8B;AACzC,SAAK,SAAS,IAAI,WAAW,KAAK,WAAW;AAC7C,SAAK,cAAc,KAAK;AACxB,SAAK,QAAQ,KAAK;AAClB,SAAK,aAAa,KAAK;AACvB,SAAK,OAAO,IAAI,WAAW,KAAK,SAAS;AAAA,MACxC,OAAO,KAAK;AAAA,MACZ,cAAe,KAAK,OAAiD;AAAA,MACrE,SAAS,KAAK,OAAO,MAAM,KAAK,UAAU,IAAI;AAAA,IAC/C,CAAC;AACD,SAAK,OAAO,IAAI,WAAW,KAAK,MAAM,KAAK,MAAM;AACjD,SAAK,UAAU,IAAI,cAAc,KAAK,MAAM,KAAK,MAAM;AACvD,SAAK,aAAa,IAAI,iBAAiB,KAAK,MAAM,KAAK,MAAM;AAC7D,SAAK,QAAQ,IAAI,YAAY,KAAK,MAAM,KAAK,MAAM;AACnD,SAAK,WAAW,IAAI,eAAe,KAAK,MAAM,KAAK,MAAM;AACzD,SAAK,YAAY,IAAI,gBAAgB,KAAK,MAAM,KAAK,MAAM;AAG3D,SAAK,QAAQ,IAAI,YAAY,KAAK,MAAM,KAAK,MAAM;AACnD,SAAK,SAAS,IAAI,aAAa,KAAK,MAAM,KAAK,MAAM;AAGrD,QAAI,KAAK,gBAAgB,OAAW,MAAK,eAAe,KAAK,WAAW;AAAA,EACzE;AAAA;AAAA;AAAA,EAIQ,YAAyC;AAChD,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,SAAK,cAAc,YAAY;AAC9B,YAAM,eAAe,KAAK,YAAY,kBAAkB;AACxD,UAAI,CAAC,cAAc;AAClB,aAAK,YAAY,cAAc;AAC/B,eAAO;AAAA,MACR;AACA,UAAI;AACH,cAAM,EAAE,OAAO,IAAI,MAAM,KAAK,KAAK,cAAc,YAAY;AAC7D,cAAM,SAAU,OAA0C;AAC1D,aAAK,OAAO,IAAI,OAAO,MAAM;AAC7B,aAAK,YAAY,kBAAkB,MAAM;AACzC,eAAO,OAAO;AAAA,MACf,QAAQ;AACP,aAAK,OAAO,IAAI,MAAS;AACzB,aAAK,YAAY,cAAc;AAC/B,eAAO;AAAA,MACR,UAAE;AACD,aAAK,aAAa;AAAA,MACnB;AAAA,IACD,GAAG;AACH,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,OAAiC;AAC/C,SAAK,OAAO,IAAI,KAAK;AACrB,QAAI,CAAC,MAAO,MAAK,WAAW;AAAA,EAC7B;AAAA;AAAA,EAGA,aAAmB;AAClB,SAAK,OAAO,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA,EAIA,eAAe,aAAuC;AACrD,SAAK,cAAc;AACnB,SAAK,QAAQ,eAAe,WAAW;AACvC,SAAK,WAAW,eAAe,WAAW;AAC1C,SAAK,UAAU,eAAe,WAAW;AACzC,SAAK,MAAM,eAAe,WAAW;AACrC,SAAK,SAAS,eAAe,WAAW;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAqB,MASQ;AAC5B,WAAO,KAAK,KAAK,QAAyB;AAAA,MACzC,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,OAAO,KAAK,SAAS,KAAK,OAAO,IAAI;AAAA,MACrC,aAAa,KAAK,eAAe,KAAK;AAAA,MACtC,OAAO,KAAK;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,IAClB,CAAC;AAAA,EACF;AAAA,EAEA,IAAiB,MAAc,QAAmD;AACjF,WAAO,KAAK,QAAW;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,aAAa,QAAQ;AAAA,MACrB,OAAO,QAAQ;AAAA,MACf,MAAM,QAAQ;AAAA,IACf,CAAC;AAAA,EACF;AAAA,EAEA,KACC,MACA,MACA,QAC2B;AAC3B,WAAO,KAAK,QAAW;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,aAAa,QAAQ;AAAA,MACrB,YAAY,QAAQ;AAAA,IACrB,CAAC;AAAA,EACF;AAAA,EAEA,IACC,MACA,MACA,QAC2B;AAC3B,WAAO,KAAK,QAAW;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,aAAa,QAAQ;AAAA,MACrB,YAAY,QAAQ;AAAA,IACrB,CAAC;AAAA,EACF;AAAA,EAEA,MACC,MACA,MACA,QAC2B;AAC3B,WAAO,KAAK,QAAW;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,aAAa,QAAQ;AAAA,MACrB,YAAY,QAAQ;AAAA,IACrB,CAAC;AAAA,EACF;AAAA,EAEA,OAAoB,MAAc,QAAmD;AACpF,WAAO,KAAK,QAAW;AAAA,MACtB,QAAQ;AAAA,MACR;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,aAAa,QAAQ;AAAA,MACrB,YAAY,QAAQ;AAAA,IACrB,CAAC;AAAA,EACF;AACD;;;AClOO,IAAM,qBAAqB,CAAC,SAAyB,KAAK,QAAQ,QAAQ,EAAE;;;ACyCnF,SAAS,SAAS,aAA8B;AAC/C,SAAO,cAAc,gBAAgB,mBAAmB,WAAW,CAAC,KAAK;AAC1E;AASO,IAAM,oBAAN,MAAwB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAAiC;AAC5C,SAAK,OAAO,IAAI,WAAW,KAAK,OAAO;AACvC,SAAK,aAAa,KAAK;AACvB,SAAK,SAAS,KAAK,SAAS,mBAAmB,KAAK,MAAM,IAAI;AAC9D,SAAK,eAAe,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI;AAAA,EAC9D;AAAA;AAAA;AAAA,EAIQ,OAAmC,MAAY;AACtD,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,WAAO,EAAE,GAAG,MAAM,MAAM,KAAK,KAAK,QAAQ,uBAAuB,KAAK,MAAM,EAAE;AAAA,EAC/E;AAAA;AAAA,EAIA,WAAW,aAAsB;AAChC,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,gBAAgB,SAAS,WAAW,CAAC;AAAA,QAC3C,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,UAAU,KAAa,aAAsB;AAC5C,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,iBAAiB,mBAAmB,GAAG,CAAC,GAAG,SAAS,WAAW,CAAC;AAAA,QACtE,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,UAAU,KAAa,OAAwB,aAAsB;AACpE,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,iBAAiB,mBAAmB,GAAG,CAAC,GAAG,SAAS,WAAW,CAAC;AAAA,QACtE,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,aAAa,KAAa,aAAsB;AAC/C,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,iBAAiB,mBAAmB,GAAG,CAAC,GAAG,SAAS,WAAW,CAAC;AAAA,QACtE,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,oBAAoB,KAAa,aAAsB;AACtD,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,iBAAiB,mBAAmB,GAAG,CAAC,aAAa,SAAS,WAAW,CAAC;AAAA,QAChF,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,eAAe,KAAa,OAAuB,aAAsB;AACxE,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,iBAAiB,mBAAmB,GAAG,CAAC,YAAY,SAAS,WAAW,CAAC;AAAA,QAC/E,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA;AAAA,EAIA,YAAY,aAAsB;AACjC,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,iBAAiB,SAAS,WAAW,CAAC;AAAA,QAC5C,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,UAAU,KAAa,aAAsB;AAC5C,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,kBAAkB,mBAAmB,GAAG,CAAC,GAAG,SAAS,WAAW,CAAC;AAAA,QACvE,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,UAAU,KAAa,OAAwB,aAAsB;AACpE,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,kBAAkB,mBAAmB,GAAG,CAAC,GAAG,SAAS,WAAW,CAAC;AAAA,QACvE,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,aAAa,KAAa,aAAsB;AAC/C,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,kBAAkB,mBAAmB,GAAG,CAAC,GAAG,SAAS,WAAW,CAAC;AAAA,QACvE,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,oBAAoB,KAAa,aAAsB;AACtD,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,kBAAkB,mBAAmB,GAAG,CAAC,aAAa,SAAS,WAAW,CAAC;AAAA,QACjF,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,eAAe,KAAa,OAAuB,aAAsB;AACxE,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,kBAAkB,mBAAmB,GAAG,CAAC,YAAY,SAAS,WAAW,CAAC;AAAA,QAChF,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA;AAAA,EAGA,aAAa,KAAa,aAAsB;AAC/C,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,kBAAkB,mBAAmB,GAAG,CAAC,UAAU,SAAS,WAAW,CAAC;AAAA,QAC9E,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AACD;;;AChMO,IAAM,cAAN,MAAkB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAA2B;AACtC,SAAK,OAAO,IAAI,WAAW,KAAK,OAAO;AACvC,SAAK,aAAa,KAAK;AACvB,SAAK,SAAS,mBAAmB,KAAK,UAAU,SAAS;AACzD,SAAK,eAAe,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI;AAAA,EAC9D;AAAA,EAEQ,IAAO,QAAgB;AAC9B,WAAO,KAAK,KAAQ,OAAO,MAAM;AAAA,EAClC;AAAA,EAEQ,KAAQ,QAAgB,QAAgB,MAAgB;AAC/D,WAAO,KAAK,KAAK,QAAyB;AAAA,MACzC;AAAA,MACA,MAAM,GAAG,KAAK,MAAM,GAAG,MAAM;AAAA,MAC7B,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACtC,CAAC;AAAA,EACF;AAAA,EAEA,YAAY;AACX,WAAO,KAAK,IAAqB,EAAE;AAAA,EACpC;AAAA,EAEA,WAAW;AACV,WAAO,KAAK,IAAoB,WAAW;AAAA,EAC5C;AAAA,EAEA,SAAS;AACR,WAAO,KAAK,IAAwB,SAAS;AAAA,EAC9C;AAAA,EAEA,cAAc;AACb,WAAO,KAAK,IAA6B,cAAc;AAAA,EACxD;AAAA,EAEA,SAAS;AACR,WAAO,KAAK,IAAwB,SAAS;AAAA,EAC9C;AAAA,EAEA,SAAS;AACR,WAAO,KAAK,IAAwB,gBAAgB;AAAA,EACrD;AAAA,EAEA,SAAS,QAAwB,CAAC,GAAG;AACpC,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,MAAM,MAAO,GAAE,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACnD,QAAI,MAAM,OAAQ,GAAE,IAAI,UAAU,MAAM,MAAM;AAC9C,UAAM,KAAK,EAAE,SAAS;AACtB,WAAO,KAAK,IAAmB,sBAAsB,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,EAC1E;AAAA;AAAA,EAGA,WAAW,OAA8B;AACxC,WAAO,KAAK,KAAwB,QAAQ,kBAAkB,KAAK;AAAA,EACpE;AAAA;AAAA,EAGA,YAAY,IAAY;AACvB,WAAO,KAAK,KAAgB,UAAU,kBAAkB,mBAAmB,EAAE,CAAC,EAAE;AAAA,EACjF;AAAA;AAAA;AAAA,EAIA,aAAa;AACZ,WAAO,KAAK,IAA4B,aAAa;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,gBAAgB,QAAgB,QAA2B;AAC1D,WAAO,KAAK;AAAA,MACX;AAAA,MACA,eAAe,mBAAmB,MAAM,CAAC;AAAA,MACzC,EAAE,OAAO;AAAA,IACV;AAAA,EACD;AACD;;;AC3FO,IAAM,kBAAN,MAAsB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAA+B;AAC1C,SAAK,OAAO,IAAI,WAAW,KAAK,OAAO;AACvC,SAAK,aAAa,KAAK;AACvB,SAAK,SAAS,mBAAmB,KAAK,UAAU,SAAS;AACzD,SAAK,eAAe,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI;AAAA,EAC9D;AAAA,EAEQ,KAAQ,QAAgB,QAAgB;AAC/C,WAAO,KAAK,KAAK,QAAyB;AAAA,MACzC;AAAA,MACA,MAAM,GAAG,KAAK,MAAM,SAAS,MAAM;AAAA,MACnC,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,IACf,CAAC;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,UAAU,QAA0B,CAAC,GAAG;AACvC,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,MAAM,MAAO,GAAE,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACnD,QAAI,MAAM,OAAQ,GAAE,IAAI,UAAU,MAAM,MAAM;AAC9C,UAAM,KAAK,EAAE,SAAS;AACtB,WAAO,KAAK,KAA2B,OAAO,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,EACjE;AAAA,EAEA,SAAS,OAAe;AACvB,WAAO,KAAK,KAAoB,OAAO,UAAU,mBAAmB,KAAK,CAAC,EAAE;AAAA,EAC7E;AAAA,EAEA,QAAQ,IAAY;AACnB,WAAO,KAAK,KAAoB,OAAO,IAAI,mBAAmB,EAAE,CAAC,EAAE;AAAA,EACpE;AAAA,EAEA,iBAAiB,IAAY;AAC5B,WAAO,KAAK,KAAoB,OAAO,IAAI,mBAAmB,EAAE,CAAC,WAAW;AAAA,EAC7E;AAAA;AAAA,EAGA,mBAAmB,IAAY;AAC9B,WAAO,KAAK,KAAgB,UAAU,IAAI,mBAAmB,EAAE,CAAC,WAAW;AAAA,EAC5E;AAAA,EAEA,iBAAiB,IAAY,QAAiC,CAAC,GAAG;AACjE,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,MAAM,MAAO,GAAE,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACnD,QAAI,MAAM,OAAQ,GAAE,IAAI,UAAU,MAAM,MAAM;AAC9C,UAAM,KAAK,EAAE,SAAS;AACtB,WAAO,KAAK;AAAA,MACX;AAAA,MACA,IAAI,mBAAmB,EAAE,CAAC,iBAAiB,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,IAC9D;AAAA,EACD;AAAA,EAEA,YAAY,IAAY;AACvB,WAAO,KAAK,KAAoB,QAAQ,IAAI,mBAAmB,EAAE,CAAC,UAAU;AAAA,EAC7E;AAAA,EAEA,cAAc,IAAY;AACzB,WAAO,KAAK,KAAoB,QAAQ,IAAI,mBAAmB,EAAE,CAAC,YAAY;AAAA,EAC/E;AACD;;;AC7DO,IAAM,qBAAN,MAAyB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAAkC;AAC7C,SAAK,OAAO,IAAI,WAAW,KAAK,OAAO;AACvC,SAAK,aAAa,KAAK;AACvB,SAAK,SAAS,mBAAmB,KAAK,UAAU,SAAS;AACzD,SAAK,eAAe,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI;AAAA,EAC9D;AAAA,EAEQ,KAAQ,QAAgB,QAAgB,MAAgB;AAC/D,WAAO,KAAK,KAAK,QAAyB;AAAA,MACzC;AAAA,MACA,MAAM,GAAG,KAAK,MAAM,GAAG,MAAM;AAAA,MAC7B,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACtC,CAAC;AAAA,EACF;AAAA,EAEQ,IAAI,MAAsB,IAAY;AAC7C,WAAO,IAAI,IAAI,IAAI,mBAAmB,EAAE,CAAC;AAAA,EAC1C;AAAA,EAEA,UAAU;AACT,WAAO,KAAK,KAAoB,OAAO,UAAU;AAAA,EAClD;AAAA,EAEA,WAAW,OAA2C;AACrD,WAAO,KAAK,KAAe,QAAQ,UAAU,KAAK;AAAA,EACnD;AAAA,EAEA,WAAW,QAAgB,OAAwB;AAClD,WAAO,KAAK,KAAe,OAAO,UAAU,mBAAmB,MAAM,CAAC,IAAI,KAAK;AAAA,EAChF;AAAA,EAEA,WAAW,QAAgB;AAC1B,WAAO,KAAK,KAAgB,UAAU,UAAU,mBAAmB,MAAM,CAAC,EAAE;AAAA,EAC7E;AAAA;AAAA;AAAA,EAIA,kBAAkB,QAAkC,CAAC,GAAG;AACvD,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,MAAM,MAAO,GAAE,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACnD,QAAI,MAAM,OAAQ,GAAE,IAAI,UAAU,MAAM,MAAM;AAC9C,UAAM,KAAK,EAAE,SAAS;AACtB,WAAO,KAAK,KAA6B,OAAO,iBAAiB,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAAA,EACtF;AAAA,EAEA,aAAa,MAAsB,IAAY;AAC9C,WAAO,KAAK,KAA4B,OAAO,iBAAiB,KAAK,IAAI,MAAM,EAAE,CAAC,EAAE;AAAA,EACrF;AAAA,EAEA,OAAO,MAAsB,IAAY,UAAmB;AAC3D,UAAM,KAAK,WAAW,aAAa,mBAAmB,QAAQ,CAAC,KAAK;AACpE,WAAO,KAAK,KAAsB,OAAO,UAAU,KAAK,IAAI,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE;AAAA,EAC7E;AAAA,EAEA,aAAa,MAAsB,IAAY,QAA2B,CAAC,GAAG;AAC7E,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,MAAM,SAAU,GAAE,IAAI,YAAY,MAAM,QAAQ;AACpD,QAAI,MAAM,MAAO,GAAE,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACnD,QAAI,MAAM,OAAQ,GAAE,IAAI,UAAU,MAAM,MAAM;AAC9C,UAAM,KAAK,EAAE,SAAS;AACtB,WAAO,KAAK;AAAA,MACX;AAAA,MACA,UAAU,KAAK,IAAI,MAAM,EAAE,CAAC,UAAU,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,IACzD;AAAA,EACD;AAAA;AAAA,EAGA,MAAM,OAAyB;AAC9B,WAAO,KAAK,KAAc,QAAQ,iBAAiB,KAAK;AAAA,EACzD;AACD;;;AC1FO,IAAM,mBAAN,MAAuB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAAgC;AAC3C,SAAK,OAAO,IAAI,WAAW,KAAK,OAAO;AACvC,SAAK,aAAa,KAAK;AACvB,SAAK,SAAS,mBAAmB,KAAK,UAAU,SAAS;AACzD,SAAK,eAAe,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI;AAAA,EAC9D;AAAA;AAAA,EAGA,UAAU,QAA0B,CAAC,GAAG;AACvC,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,MAAM,YAAa,GAAE,IAAI,eAAe,MAAM,WAAW;AAC7D,QAAI,MAAM,KAAM,GAAE,IAAI,QAAQ,MAAM,IAAI;AACxC,QAAI,MAAM,QAAS,GAAE,IAAI,WAAW,MAAM,OAAO;AACjD,QAAI,MAAM,KAAM,GAAE,IAAI,QAAQ,MAAM,KAAK,YAAY,CAAC;AACtD,QAAI,MAAM,GAAI,GAAE,IAAI,MAAM,MAAM,GAAG,YAAY,CAAC;AAChD,QAAI,MAAM,MAAO,GAAE,IAAI,SAAS,OAAO,MAAM,KAAK,CAAC;AACnD,QAAI,MAAM,OAAQ,GAAE,IAAI,UAAU,MAAM,MAAM;AAC9C,UAAM,KAAK,EAAE,SAAS;AACtB,WAAO,KAAK,KAAK,QAAwC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM,GAAG,KAAK,MAAM,SAAS,KAAK,IAAI,EAAE,KAAK,EAAE;AAAA,MAC/C,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,IACf,CAAC;AAAA,EACF;AACD;;;ACIO,IAAM,qBAAN,MAAyB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,MAAkC;AAC7C,SAAK,OAAO,IAAI,WAAW,KAAK,OAAO;AACvC,SAAK,aAAa,KAAK;AACvB,SAAK,SAAS,KAAK,SAAS,mBAAmB,KAAK,MAAM,IAAI;AAC9D,SAAK,eAAe,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI;AAAA,EAC9D;AAAA;AAAA;AAAA,EAIQ,OAAmC,MAAY;AACtD,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,WAAO,EAAE,GAAG,MAAM,MAAM,KAAK,KAAK,QAAQ,uBAAuB,KAAK,MAAM,EAAE;AAAA,EAC/E;AAAA,EAEA,gBAAgB;AACf,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,YAAY,MAAc,QAAwB;AACjD,UAAM,IAAI,SAAS,WAAW,mBAAmB,MAAM,CAAC,KAAK;AAC7D,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,oBAAoB,mBAAmB,IAAI,CAAC,GAAG,CAAC;AAAA,QACtD,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,YAAY,MAAc,OAA0B,QAAwB;AAC3E,UAAM,IAAI,SAAS,WAAW,mBAAmB,MAAM,CAAC,KAAK;AAC7D,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,oBAAoB,mBAAmB,IAAI,CAAC,GAAG,CAAC;AAAA,QACtD,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,eAAe,MAAc,QAAwB;AACpD,UAAM,IAAI,SAAS,WAAW,mBAAmB,MAAM,CAAC,KAAK;AAC7D,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,oBAAoB,mBAAmB,IAAI,CAAC,GAAG,CAAC;AAAA,QACtD,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,cAAc,MAAc,QAAwB;AACnD,UAAM,IAAI,SAAS,WAAW,mBAAmB,MAAM,CAAC,KAAK;AAC7D,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,oBAAoB,mBAAmB,IAAI,CAAC,aAAa,CAAC;AAAA,QAChE,OAAO,KAAK;AAAA,MACb,CAAC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,SAAS,MAAc,OAA+B,QAAwB;AAC7E,UAAM,IAAI,SAAS,WAAW,mBAAmB,MAAM,CAAC,KAAK;AAC7D,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,oBAAoB,mBAAmB,IAAI,CAAC,YAAY,CAAC;AAAA,QAC/D,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,MAAc,OAA8B,QAAwB;AACnF,UAAM,IAAI,SAAS,WAAW,mBAAmB,MAAM,CAAC,KAAK;AAC7D,WAAO,KAAK,KAAK;AAAA,MAChB,KAAK,OAAO;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,oBAAoB,mBAAmB,IAAI,CAAC,WAAW,CAAC;AAAA,QAC9D,MAAM;AAAA,QACN,OAAO,KAAK;AAAA,QACZ,SAAS,KAAK;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD;AACD;;;ACxEO,SAAS,cACf,QAC+B;AAC/B,SAAO,EAAE,YAAY;AACtB;AA+pBO,SAAS,iBACf,KACA,aACgB;AAChB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,UAAU,IAAI,UAAW,cAAc,IAAI,OAAO,KAAK,IAAI,UAAY,IAAI,eAAe;AAChG,QAAM,QAAQ,CAAC,IAAI,MAAM,IAAI,eAAe,IAAI,iBAAiB,OAAO,EAAE;AAAA,IACzE,CAAC,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS;AAAA,EACzD;AACA,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC9C;;;AClwBO,IAAM,qBAAiD,CAAC,UAAU,UAAU,WAAW,MAAM;AAG7F,SAAS,gBAAgB,OAAiC;AAChE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,SAAO;AACR;AAGO,SAAS,kBAAkB,OAAgB,OAAwB,gBAAgB,KAAK,GAAW;AACzG,MAAI,SAAS,SAAU,QAAO,OAAO,UAAU,WAAW,QAAQ,OAAO,SAAS,EAAE;AACpF,MAAI,SAAS,SAAU,QAAO,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;AAC1E,MAAI,SAAS,UAAW,QAAO,UAAU,OAAO,SAAS;AACzD,SAAO,KAAK,UAAU,SAAS,MAAM,MAAM,CAAC;AAC7C;AAWO,SAAS,gBAAgB,MAAuB,KAAyB;AAC/E,MAAI,SAAS,SAAU,QAAO,EAAE,IAAI,MAAM,OAAO,IAAI;AACrD,QAAM,IAAI,IAAI,KAAK;AACnB,MAAI,SAAS,UAAU;AACtB,QAAI,MAAM,GAAI,QAAO,EAAE,IAAI,OAAO,OAAO,kBAAkB;AAC3D,UAAM,IAAI,OAAO,CAAC;AAClB,WAAO,OAAO,SAAS,CAAC,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE,IAAI,EAAE,IAAI,OAAO,OAAO,IAAI,GAAG,qBAAqB;AAAA,EACtG;AACA,MAAI,SAAS,WAAW;AACvB,UAAM,IAAI,EAAE,YAAY;AACxB,QAAI,CAAC,QAAQ,KAAK,OAAO,IAAI,EAAE,SAAS,CAAC,EAAG,QAAO,EAAE,IAAI,MAAM,OAAO,KAAK;AAC3E,QAAI,CAAC,SAAS,KAAK,MAAM,KAAK,EAAE,SAAS,CAAC,EAAG,QAAO,EAAE,IAAI,MAAM,OAAO,MAAM;AAC7E,WAAO,EAAE,IAAI,OAAO,OAAO,qBAAqB;AAAA,EACjD;AACA,MAAI;AACH,WAAO,EAAE,IAAI,MAAM,OAAO,KAAK,MAAM,CAAC,EAAE;AAAA,EACzC,SAAS,KAAK;AACb,WAAO,EAAE,IAAI,OAAO,OAAO,mBAAoB,IAAc,OAAO,GAAG;AAAA,EACxE;AACD;AAMO,IAAM,qBAAqB;AAE3B,SAAS,iBAAiB,KAA4B;AAC5D,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,mBAAmB,KAAK,GAAG,IAC/B,OACA;AACJ;AAmBA,IAAM,eAAe;AAGd,SAAS,iBAAiB,OAAwB;AACxD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO;AACR;AAOO,SAAS,iBAAiB,KAAmC;AACnE,QAAM,IAAI,IAAI,KAAK;AACnB,MAAI,MAAM,UAAU,MAAM,SAAS;AAClC,WAAO,EAAE,MAAM,WAAW,OAAO,MAAM,QAAQ,OAAO,UAAU,WAAW,KAAK;AAAA,EACjF;AACA,MAAI,aAAa,KAAK,CAAC,GAAG;AACzB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,OAAO,SAAS,CAAC,KAAK,OAAO,CAAC,MAAM,EAAG,QAAO,EAAE,MAAM,UAAU,OAAO,GAAG,OAAO,UAAU,WAAW,KAAK;AAAA,EAChH;AACA,MAAI,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,GAAG;AAC3C,QAAI;AACH,YAAM,SAAkB,KAAK,MAAM,CAAC;AACpC,UAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AAClD,eAAO,EAAE,MAAM,QAAQ,OAAO,QAAQ,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,UAAU,WAAW,MAAM;AAAA,MAC1G;AAAA,IACD,QAAQ;AAAA,IAER;AAAA,EACD;AACA,SAAO,EAAE,MAAM,UAAU,OAAO,KAAK,OAAO,QAAQ,WAAW,MAAM;AACtE;","names":["data"]}
1
+ {"version":3,"sources":["../src/cache.ts","../src/http.ts","../src/modules/audit.ts","../src/modules/auth.ts","../src/modules/billing.ts","../src/modules/customers.ts","../src/modules/media.ts","../src/modules/config.ts","../src/modules/webhooks.ts","../src/modules/workspaces.ts","../src/token-store.ts","../src/client.ts","../src/path.ts","../src/modules/config-admin.ts","../src/modules/admin.ts","../src/modules/auth-admin.ts","../src/modules/billing-admin.ts","../src/modules/audit-admin.ts","../src/modules/courier-admin.ts","../src/types.ts","../src/config-value.ts"],"sourcesContent":["// Optional response cache for FonderieClient. A cache instance is created per\n// client (never module-global) so it is safe on a server — one client per\n// request means no cross-user/tenant leakage. It sweeps lazily on read, so\n// there is no background timer keeping a process alive.\n\nexport interface ICache {\n\t// Returns the cached value if present and still within its TTL, else undefined.\n\tget<T>(key: string): T | undefined;\n\t// Stores a value with a per-entry TTL (ms).\n\tset<T>(key: string, value: T, ttlMs: number): void;\n\t// Deduplicates concurrent in-flight requests for the same key.\n\tdedupe<T>(key: string, fn: () => Promise<T>): Promise<T>;\n\t// Evicts every entry whose key contains `fragment` (and cancels in-flight\n\t// dedupe for those), so a write can bust the reads it affects.\n\tinvalidate(fragment: string): void;\n\tclear(): void;\n}\n\nexport interface IMemoryCacheOptions {\n\t// Default TTL (ms) applied to cached GETs when a call doesn't specify one.\n\tdefaultTtlMs?: number;\n}\n\ninterface Entry {\n\tvalue: unknown;\n\texpiresAt: number;\n}\n\nexport function createMemoryCache(\n\topts: IMemoryCacheOptions = {},\n): ICache & { defaultTtlMs: number } {\n\tconst store = new Map<string, Entry>();\n\tconst inflight = new Map<string, Promise<unknown>>();\n\tconst defaultTtlMs = opts.defaultTtlMs ?? 60_000;\n\n\treturn {\n\t\tdefaultTtlMs,\n\n\t\tget<T>(key: string): T | undefined {\n\t\t\tconst entry = store.get(key);\n\t\t\tif (!entry) return undefined;\n\t\t\tif (Date.now() > entry.expiresAt) {\n\t\t\t\tstore.delete(key); // lazy sweep\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn entry.value as T;\n\t\t},\n\n\t\tset<T>(key: string, value: T, ttlMs: number): void {\n\t\t\tstore.set(key, { value, expiresAt: Date.now() + ttlMs });\n\t\t},\n\n\t\tdedupe<T>(key: string, fn: () => Promise<T>): Promise<T> {\n\t\t\tconst existing = inflight.get(key);\n\t\t\tif (existing) return existing as Promise<T>;\n\t\t\tconst req = fn().finally(() => inflight.delete(key));\n\t\t\tinflight.set(key, req);\n\t\t\treturn req;\n\t\t},\n\n\t\tinvalidate(fragment: string): void {\n\t\t\tfor (const key of store.keys()) if (key.includes(fragment)) store.delete(key);\n\t\t\tfor (const key of inflight.keys()) if (key.includes(fragment)) inflight.delete(key);\n\t\t},\n\n\t\tclear(): void {\n\t\t\tstore.clear();\n\t\t\tinflight.clear();\n\t\t},\n\t};\n}\n","import type { ICache } from './cache';\nimport type { IApiError } from './types';\n\nexport class FonderieApiError extends Error {\n\tconstructor(\n\t\tpublic readonly reason: string,\n\t\tpublic readonly explanation: string,\n\t\tpublic readonly status: number,\n\t\tpublic readonly details?: unknown,\n\t\t// The X-Request-ID for the failed call — quote it in a bug report; it\n\t\t// correlates to the server's logs and audit trail for the same request.\n\t\tpublic readonly requestId?: string,\n\t) {\n\t\tsuper(explanation);\n\t\tthis.name = 'FonderieApiError';\n\t}\n}\n\n// Portable random hex for W3C trace ids — crypto.getRandomValues where available\n// (browser / Node), Math.random fallback for Hermes / older React Native. Not\n// security-sensitive: these are correlation/trace ids, not secrets.\nfunction randHex(bytes: number): string {\n\tconst c = (globalThis as { crypto?: { getRandomValues?: (a: Uint8Array) => Uint8Array } }).crypto;\n\tconst arr = new Uint8Array(bytes);\n\tif (c?.getRandomValues) c.getRandomValues(arr);\n\telse for (let i = 0; i < bytes; i++) arr[i] = Math.floor(Math.random() * 256);\n\tlet out = '';\n\tfor (const b of arr) out += b.toString(16).padStart(2, '0');\n\treturn out;\n}\n\nexport interface IRequestOptions {\n\tmethod: string;\n\tpath: string;\n\tbody?: unknown;\n\ttoken?: string | undefined;\n\tcookie?: string | undefined;\n\t// Resolves the billing subscriber to a workspace (@fonderie/billing's\n\t// resolveSubscriber falls back to the session user when omitted).\n\tworkspaceId?: string | undefined;\n\t// Extra request headers (e.g. the admin surfaces' X-Actor attribution).\n\theaders?: Record<string, string> | undefined;\n\t// Cache control (only applies when the client was given a cache):\n\t// cache: number → cache this GET for that many ms\n\t// cache: false → skip the cache for this GET\n\t// bust: true → ignore any cached value and refresh it\n\t// invalidate → extra key fragments to evict after a successful write\n\tcache?: number | false | undefined;\n\tbust?: boolean | undefined;\n\tinvalidate?: string[] | undefined;\n}\n\nexport interface IHttpDeps {\n\tcache?: ICache | undefined;\n\tdefaultTtlMs?: number | undefined;\n\t// Called once on a 401 (except for /auth/* requests). Returns a fresh access\n\t// token to retry with, or undefined to let the 401 surface. Callers should\n\t// make this single-flight.\n\trefresh?: (() => Promise<string | undefined>) | undefined;\n}\n\nexport class HttpClient {\n\tprivate cache: ICache | undefined;\n\tprivate defaultTtlMs: number;\n\tprivate refresh: (() => Promise<string | undefined>) | undefined;\n\n\tconstructor(\n\t\tprivate baseUrl: string,\n\t\tdeps: IHttpDeps = {},\n\t) {\n\t\tthis.cache = deps.cache;\n\t\tthis.defaultTtlMs = deps.defaultTtlMs ?? 60_000;\n\t\tthis.refresh = deps.refresh;\n\t}\n\n\t// Absolute URL for a path on this client's origin — for endpoints a browser\n\t// navigates to or embeds (e.g. a public `<img src>`) rather than fetches\n\t// through request(). Mirrors the `${baseUrl}${path}` join request() uses.\n\tabsolute(path: string): string {\n\t\treturn `${this.baseUrl}${path}`;\n\t}\n\n\t// Drop all cached responses — sign-out must not leave one session's data\n\t// servable to the next.\n\tclearCache(): void {\n\t\tthis.cache?.clear();\n\t}\n\n\tasync request<T>(opts: IRequestOptions): Promise<T> {\n\t\tconst method = opts.method.toUpperCase();\n\n\t\tconst cache = this.cache;\n\n\t\t// ── Read path: serve/populate cache (GET only, opt-in) ──────────────────\n\t\tif (cache && method === 'GET' && opts.cache !== false) {\n\t\t\tconst key = `GET ${opts.path}::ws=${opts.workspaceId ?? ''}`;\n\t\t\tif (!opts.bust) {\n\t\t\t\tconst hit = cache.get<T>(key);\n\t\t\t\tif (hit !== undefined) return hit;\n\t\t\t}\n\t\t\tconst ttl = typeof opts.cache === 'number' ? opts.cache : this.defaultTtlMs;\n\t\t\treturn cache.dedupe(key, async () => {\n\t\t\t\tconst data = await this.exec<T>(opts);\n\t\t\t\tcache.set(key, data, ttl);\n\t\t\t\treturn data;\n\t\t\t});\n\t\t}\n\n\t\tconst data = await this.exec<T>(opts);\n\n\t\t// ── Write path: bust the reads this mutation affects ────────────────────\n\t\tif (cache && method !== 'GET') {\n\t\t\tconst resource = opts.path.split('?')[0]?.split('/').filter(Boolean)[0];\n\t\t\tif (resource) cache.invalidate(`/${resource}`);\n\t\t\tfor (const fragment of opts.invalidate ?? []) cache.invalidate(fragment);\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tprivate async exec<T>(opts: IRequestOptions, retried = false): Promise<T> {\n\t\t// Start a W3C trace: the trace id doubles as the quotable correlation id\n\t\t// (sent as X-Request-ID and surfaced on FonderieApiError.requestId).\n\t\tconst traceId = randHex(16);\n\t\tconst requestId = traceId;\n\t\tconst headers: Record<string, string> = {\n\t\t\t'Content-Type': 'application/json',\n\t\t\ttraceparent: `00-${traceId}-${randHex(8)}-01`,\n\t\t\t'X-Request-ID': requestId,\n\t\t};\n\t\tif (opts.token) headers['Authorization'] = `Bearer ${opts.token}`;\n\t\tif (opts.cookie) headers['Cookie'] = opts.cookie;\n\t\tif (opts.workspaceId) headers['X-Workspace-ID'] = opts.workspaceId;\n\t\tObject.assign(headers, opts.headers ?? {});\n\n\t\tconst fetchInit: RequestInit = { method: opts.method, headers, credentials: 'include' };\n\t\tif (opts.body !== undefined) fetchInit.body = JSON.stringify(opts.body);\n\n\t\tconst res = await fetch(`${this.baseUrl}${opts.path}`, fetchInit);\n\t\t// The server echoes the id back; prefer it (an intermediary could rewrite\n\t\t// the one we sent), else fall back to what we generated.\n\t\tconst rid = res.headers.get('x-request-id') ?? requestId;\n\n\t\t// Reactive renew: on a 401, refresh once and retry (never for /auth/* to\n\t\t// avoid recursing through the refresh/login endpoints themselves).\n\t\tif (res.status === 401 && this.refresh && !retried && !opts.path.startsWith('/auth/')) {\n\t\t\tconst newToken = await this.refresh();\n\t\t\tif (newToken) return this.exec<T>({ ...opts, token: newToken }, true);\n\t\t}\n\n\t\t// 204 No Content (e.g. some DELETE routes) has no body to parse.\n\t\tif (res.status === 204) {\n\t\t\tif (!res.ok)\n\t\t\t\tthrow new FonderieApiError('unknown', res.statusText, res.status, undefined, rid);\n\t\t\treturn undefined as T;\n\t\t}\n\n\t\tconst data = (await res.json()) as T | IApiError;\n\n\t\tif (!res.ok || res.status === 202) {\n\t\t\tconst err = data as IApiError;\n\t\t\tthrow new FonderieApiError(err.reason, err.explanation, res.status, err.details, rid);\n\t\t}\n\n\t\treturn data as T;\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type { IReadOptions, IApiResponse, IAuditPageResult } from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface IListAuditEventsInput {\n\ttype?: string;\n\tactorId?: string;\n\tfrom?: Date;\n\tto?: Date;\n\tlimit?: number;\n\tcursor?: string;\n}\n\n// ── Audit client ─────────────────────────────────────────────────────────────\n\nexport class AuditClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes the audit query to a workspace (X-Workspace-ID). Falls back to\n\t// the caller's personal workspace when unset, same as billing/workspaces.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\tlistEvents(input: IListAuditEventsInput = {}, opts?: IReadOptions) {\n\t\tconst params = new URLSearchParams();\n\t\tif (input.limit !== undefined) params.set('limit', String(input.limit));\n\t\tif (input.type) params.set('type', input.type);\n\t\tif (input.actorId) params.set('actorId', input.actorId);\n\t\tif (input.from) params.set('from', input.from.toISOString());\n\t\tif (input.to) params.set('to', input.to.toISOString());\n\t\tif (input.cursor) params.set('cursor', input.cursor);\n\t\tconst qs = params.toString();\n\n\t\treturn this.http.request<IApiResponse<IAuditPageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/audit${qs ? `?${qs}` : ''}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIApiResponse,\n\tILoginResult,\n\tIMfaRequiredResult,\n\tIMeResult,\n\tIMfaEnabledResult,\n\tIMfaSetupResult,\n\tIRefreshResult,\n\tIRegisterResult,\n\tIResendVerificationResult,\n\tIVerifyEmailResult,\n\tILoginHistoryPageResult,\n\tISessionsResult,\n\tIAuthProvidersResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\n// NOTE: the server's register/login schemas also accept a { phone } variant\n// (OTP-based phone auth). It is deliberately not surfaced in the typed client\n// yet — doing it properly needs a verifyPhone completion method plus hooks in\n// all three frontend frameworks, which is its own cycle. Tracked in\n// docs/DTO-GAP-AUDIT.md.\nexport interface IRegisterInput {\n\temail: string;\n\tpassword: string;\n\tfirstName?: string;\n\tlastName?: string;\n}\n\nexport interface IGetLoginHistoryInput {\n\toutcome?: 'success' | 'failed';\n\tfrom?: Date;\n\tto?: Date;\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface ILoginInput {\n\temail: string;\n\tpassword: string;\n}\n\n// Native Sign in with Apple: the app obtains an `identityToken` from the native\n// Apple sheet (e.g. expo-apple-authentication) and hands it here — the client\n// only relays it to POST /auth/apple/native. `nonce` is the raw nonce the app\n// passed to the native request, checked server-side against the token claim.\nexport interface IAppleNativeInput {\n\tidentityToken: string;\n\tnonce?: string;\n}\n\nexport interface IResetPasswordInput {\n\t// The 6-digit code emailed by forgotPassword. Matches @fonderie/auth's\n\t// resetPasswordSchema ({ pin, password }); the route is POST /auth/email/reset.\n\tpin: string;\n\tpassword: string;\n}\n\n// User updates are split by @fonderie/auth into dedicated, individually\n// validated routes — there is no combined /users/update endpoint.\nexport interface IUpdateProfileInput {\n\t// Explicit null clears the field server-side (same pattern as\n\t// IUpdateWorkspaceInput); undefined leaves it untouched.\n\tfirstName?: string | null;\n\tlastName?: string | null;\n\tavatarUrl?: string | null;\n}\n\nexport interface IUpdatePreferencesInput {\n\tlocale?: string;\n\ttimezone?: string;\n\t// Replaces the stored notifications object; flags left out fall back to\n\t// the server defaults on read.\n\tnotifications?: { email?: boolean; inApp?: boolean; sms?: boolean; push?: boolean };\n\temailDigest?: string;\n\tdateFormat?: string;\n\ttimeFormat?: string;\n}\n\nexport interface IChangePasswordInput {\n\tcurrentPassword: string;\n\tnewPassword: string;\n}\n\n// ── MFA sub-client ───────────────────────────────────────────────────────────\n\nclass MfaClient {\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate token: () => string | undefined,\n\t) {}\n\n\tsetup() {\n\t\treturn this.http.request<IApiResponse<IMfaSetupResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/setup',\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n\n\tverify(token: string) {\n\t\treturn this.http.request<IApiResponse<IMfaEnabledResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/verify',\n\t\t\tbody: { token },\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n\n\t// MFA-login: complete a login that returned MFA_REQUIRED. Authenticates with\n\t// the temporary `mfaToken` (not the session) and verifies the TOTP `code` —\n\t// same route as `verify`, different auth context. Returns the completed login.\n\tverifyLogin(mfaToken: string, code: string) {\n\t\treturn this.http.request<IApiResponse<ILoginResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/verify',\n\t\t\tbody: { token: code },\n\t\t\ttoken: mfaToken,\n\t\t});\n\t}\n\n\tdisable(token: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/disable',\n\t\t\tbody: { token },\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n\n\t// POST /auth/mfa/backup-codes (mfaTokenSchema { token }) — returns a fresh set.\n\tregenerateBackupCodes(token: string) {\n\t\treturn this.http.request<IApiResponse<{ backupCodes: string[] }>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/mfa/backup-codes',\n\t\t\tbody: { token },\n\t\t\ttoken: this.token(),\n\t\t});\n\t}\n}\n\n// ── Auth client ──────────────────────────────────────────────────────────────\n\nexport class AuthClient {\n\treadonly mfa: MfaClient;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {\n\t\tthis.mfa = new MfaClient(http, () => this.tokens.get());\n\t}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t\t// Signing out (token → undefined) also drops the shared response cache,\n\t\t// so the hooks' logout paths can't leak one session's data to the next.\n\t\tif (!token) this.http.clearCache();\n\t}\n\n\t// ── Public ─────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Which sign-in methods this deployment can actually honour.\n\t *\n\t * Public — the login screen needs it before anyone has signed in. Ask the\n\t * server rather than shipping a build-time flag: the flag stores the same\n\t * fact twice and lets the two disagree, and the symptom is a user clicking\n\t * a provider the server cannot complete and landing on the provider's own\n\t * error page, which the app cannot explain.\n\t */\n\tproviders() {\n\t\treturn this.http.request<IApiResponse<IAuthProvidersResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/auth/providers',\n\t\t});\n\t}\n\n\t/**\n\t * Disconnect the OAuth provider linked to the signed-in account.\n\t *\n\t * Refused with 409 PASSWORD_REQUIRED when the account has no password:\n\t * removing the only credential is account deletion, not a settings toggle.\n\t * Check `user.hasPassword` before offering the control so the user is asked\n\t * to set a password first rather than shown an error they can't act on.\n\t */\n\tunlinkOauth(provider: string) {\n\t\treturn this.http.request<IApiResponse<null>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/auth/oauth/${encodeURIComponent(provider)}`,\n\t\t});\n\t}\n\n\tregister(input: IRegisterInput) {\n\t\treturn this.http.request<IApiResponse<IRegisterResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/register',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\tlogin(input: ILoginInput) {\n\t\treturn this.http.request<IApiResponse<ILoginResult | IMfaRequiredResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/login',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\t// Complete a native Sign in with Apple. Returns the same token/user envelope\n\t// as login (no MFA branch — OAuth completions don't gate on MFA). Requires\n\t// the API to enable the provider (`providers: ['apple']` + apple config).\n\tappleNative(input: IAppleNativeInput) {\n\t\treturn this.http.request<IApiResponse<ILoginResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/apple/native',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\trefreshTokens(refreshToken?: string) {\n\t\treturn this.http.request<IApiResponse<IRefreshResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/refresh',\n\t\t\tbody: refreshToken ? { refreshToken } : undefined,\n\t\t});\n\t}\n\n\tforgotPassword(email: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/email/forgot',\n\t\t\tbody: { email },\n\t\t});\n\t}\n\n\tresetPassword(input: IResetPasswordInput) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/email/reset',\n\t\t\tbody: input,\n\t\t});\n\t}\n\n\tverifyEmail(token: string) {\n\t\t// @fonderie/auth registers this as POST /auth/verify with body { token }\n\t\t// (verifySchema = { token: sixDigitPin }).\n\t\treturn this.http.request<IApiResponse<IVerifyEmailResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/verify',\n\t\t\tbody: { token },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Protected ──────────────────────────────────────────────────────────────\n\n\tlogout(refreshToken?: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/auth/logout',\n\t\t\tbody: refreshToken ? { refreshToken } : undefined,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tsendVerificationEmail() {\n\t\t// @fonderie/auth registers this as GET /auth/send-verification (requireAuth).\n\t\treturn this.http.request<IApiResponse<IResendVerificationResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/auth/send-verification',\n\t\t\ttoken: this.tokens.get(),\n\t\t\t// A send-action on a GET route: never serve it from the cache, or a\n\t\t\t// resend inside the TTL would silently no-op.\n\t\t\tcache: false,\n\t\t});\n\t}\n\n\t// ── Protected + Verified ───────────────────────────────────────────────────\n\n\tgetUser(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IMeResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/users',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateProfile(input: IUpdateProfileInput) {\n\t\treturn this.http.request<IApiResponse<IMeResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/profile',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdatePreferences(input: IUpdatePreferencesInput) {\n\t\treturn this.http.request<IApiResponse<IMeResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/preferences',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdateEmail(email: string) {\n\t\treturn this.http.request<IApiResponse<unknown>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/email',\n\t\t\tbody: { email },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdatePhone(phone: string) {\n\t\treturn this.http.request<IApiResponse<unknown>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/phone',\n\t\t\tbody: { phone },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tchangePassword(input: IChangePasswordInput) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/users/password',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// GET /users/export — the caller's own data as a portable bundle (SAR).\n\texportData() {\n\t\treturn this.http.request<IApiResponse<unknown>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/users/export',\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tdeleteUser() {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: '/users',\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Security surfaces (login history + active sessions) ─────────────────────\n\n\t// GET /auth/login-history — the caller's own attempts, newest first,\n\t// keyset-paginated (pass the previous page's nextCursor to continue).\n\tgetLoginHistory(input: IGetLoginHistoryInput = {}, opts?: IReadOptions) {\n\t\tconst params = new URLSearchParams();\n\t\tif (input.limit !== undefined) params.set('limit', String(input.limit));\n\t\tif (input.outcome) params.set('outcome', input.outcome);\n\t\tif (input.from) params.set('from', input.from.toISOString());\n\t\tif (input.to) params.set('to', input.to.toISOString());\n\t\tif (input.cursor) params.set('cursor', input.cursor);\n\t\tconst qs = params.toString();\n\t\t// Single-level template (no nested backtick) so the client/route drift\n\t\t// checker can normalise the ${qs…} suffix away and match the server route.\n\t\treturn this.http.request<IApiResponse<ILoginHistoryPageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/auth/login-history${qs ? '?' + qs : ''}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// GET /auth/sessions — the caller's live sessions; one is flagged current.\n\tlistSessions(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ISessionsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/auth/sessions',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// DELETE /auth/sessions/:id — revoke one of the caller's sessions.\n\tterminateSession(id: string) {\n\t\treturn this.http.request<IApiResponse<{ id: string }>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/auth/sessions/${encodeURIComponent(id)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// DELETE /auth/sessions/others — revoke every session except the current one.\n\tterminateOtherSessions() {\n\t\treturn this.http.request<IApiResponse<{ count: number }>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: '/auth/sessions/others',\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIApiResponse,\n\tICancelSubscriptionInput,\n\tICheckoutUrlResult,\n\tIInvoicesResult,\n\tIPaymentMethodResult,\n\tIPlanListResult,\n\tIPlanResult,\n\tIPortalUrlResult,\n\tISavePaymentMethodInput,\n\tISetupIntentResult,\n\tISubscriptionChangeResult,\n\tISubscriptionResult,\n\tIUsageResult,\n\tIWalletCheckoutInput,\n\tIWalletPurchaseInput,\n\tIWalletPurchaseResult,\n\tIWalletResult,\n\tIWalletTransactionsResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ICheckoutInput {\n\tplan: string;\n\tinterval?: 'month' | 'year';\n\t// Optional idempotency key — a retried checkout with the same key dedupes to\n\t// one session (and one subscription) server-side. Generate once per attempt.\n\tidempotencyKey?: string;\n}\n\nexport interface IRecordUsageInput {\n\tmetric: string;\n\tquantity?: number;\n}\n\nexport interface IWalletPreferencesInput {\n\t// When false, a debit stops at the free allowance (402) rather than drawing\n\t// down purchased credits.\n\tspendPurchased: boolean;\n}\n\nexport interface ICreatePlanInput {\n\tname: string;\n\tdescription?: string | null;\n\ttier?: number;\n\tseats?: number | null;\n\ttrialDays?: number;\n\tmonthlyAmount?: number | null;\n\tmonthlyPriceId?: string | null;\n\tyearlyAmount?: number | null;\n\tyearlyPriceId?: string | null;\n\tfeatures?: unknown;\n\tmetadata?: unknown;\n}\n\nexport type IUpdatePlanInput = Partial<ICreatePlanInput>;\n\n// ── Billing client ───────────────────────────────────────────────────────────\n\nexport class BillingClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Subscriber is resolved from this workspace ID (X-Workspace-ID) when set,\n\t// falling back to the session user otherwise — see @fonderie/billing's\n\t// resolveSubscriber. Call with undefined to bill the signed-in user directly.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\t// ── Plans — public read-only ────────────────────────────────────────────────\n\n\tlistPlans(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IPlanListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/plans',\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tgetPlan(planId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IPlanResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/plans/${encodeURIComponent(planId)}`,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// ── Plans — admin write ──────────────────────────────────────────────────────\n\t// Unlike every other write in this client, @fonderie/billing does not gate\n\t// these with requireAuth or an admin token — \"the caller is responsible for\n\t// authorization\" (its own routes.ts comment). Sending the session token is\n\t// harmless (the server ignores it) but does nothing on its own; gate access\n\t// to these calls yourself (an app-level route guard, a reverse-proxy admin\n\t// zone, or similar) before wiring them into a UI.\n\n\tcreatePlan(input: ICreatePlanInput) {\n\t\treturn this.http.request<IApiResponse<IPlanResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/plans',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tupdatePlan(planId: string, input: IUpdatePlanInput) {\n\t\treturn this.http.request<IApiResponse<IPlanResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/plans/${encodeURIComponent(planId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tdeletePlan(planId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/plans/${encodeURIComponent(planId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Subscription ─────────────────────────────────────────────────────────────\n\n\tgetSubscription(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ISubscriptionResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/subscription',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// First-party cancel — no portal round-trip. Default keeps access until the\n\t// paid-through date; pass { atPeriodEnd: false } to end it immediately. 501\n\t// when the provider has no first-party cancel (the portal remains a fallback).\n\tcancelSubscription(input?: ICancelSubscriptionInput) {\n\t\treturn this.http.request<IApiResponse<ISubscriptionChangeResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/subscription/cancel',\n\t\t\tbody: input ?? {},\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Un-cancel a subscription scheduled to cancel at period end. Idempotent; 409\n\t// when the subscription is already fully canceled (start a new checkout).\n\treactivateSubscription() {\n\t\treturn this.http.request<IApiResponse<ISubscriptionChangeResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/subscription/reactivate',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Checkout / portal ────────────────────────────────────────────────────────\n\n\tcreateCheckoutSession(input: ICheckoutInput) {\n\t\treturn this.http.request<IApiResponse<ICheckoutUrlResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/checkout',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tcreatePortalSession() {\n\t\treturn this.http.request<IApiResponse<IPortalUrlResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/portal',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Usage ────────────────────────────────────────────────────────────────────\n\n\trecordUsage(input: IRecordUsageInput) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/usage',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetUsage(metric: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IUsageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/billing/usage/${encodeURIComponent(metric)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// ── Wallet ─────────────────────────────────────────────────────────────────────\n\n\tgetWallet(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWalletResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/wallet',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tsetWalletPreferences(input: IWalletPreferencesInput) {\n\t\treturn this.http.request<IApiResponse<IWalletResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/wallet/preferences',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Start a one-time credit-pack purchase. Returns a hosted checkout URL to\n\t// redirect the buyer to; the wallet is credited by the payment webhook.\n\tcreateWalletCheckout(input: IWalletCheckoutInput) {\n\t\treturn this.http.request<IApiResponse<ICheckoutUrlResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/wallet/checkout',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Buy a credit pack in-app by charging the saved card — no redirect. Inspect\n\t// `result.status`: 'credited' (done — refresh the wallet), 'checkout_required'\n\t// (no saved card or the card needs 3-D Secure → fall back to\n\t// createWalletCheckout), 'declined', or 'processing' (indeterminate — retry\n\t// with the SAME idempotencyKey). Generate one idempotencyKey per attempt and\n\t// reuse it on retry so a double-submit can't double-charge.\n\tpurchaseWalletPack(input: IWalletPurchaseInput) {\n\t\treturn this.http.request<IApiResponse<IWalletPurchaseResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/wallet/purchase',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// The wallet ledger, newest first — every credit/debit with a running\n\t// balanceAfter. Cursor-paginated: pass the previous result's `nextCursor`.\n\tgetWalletTransactions(opts?: IReadOptions & { cursor?: string; limit?: number }) {\n\t\tconst params = new URLSearchParams();\n\t\tif (opts?.cursor) params.set('cursor', opts.cursor);\n\t\tif (opts?.limit !== undefined) params.set('limit', String(opts.limit));\n\t\tconst qs = params.toString();\n\t\treturn this.http.request<IApiResponse<IWalletTransactionsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/billing/wallet/transactions${qs ? '?' + qs : ''}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// ── Account ──────────────────────────────────────────────────────────────────\n\n\t// The customer's card on file (brand/last4/expiry), or { paymentMethod: null }\n\t// when none is stored. 501 when the provider can't retrieve it.\n\tgetPaymentMethod(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IPaymentMethodResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/payment-method',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// Begin in-app card entry — returns a SetupIntent client secret for the\n\t// provider's embedded card element (Stripe Payment Element); the user never\n\t// leaves the site. 501 when the provider has no in-app card support.\n\tsetupPaymentMethod() {\n\t\treturn this.http.request<IApiResponse<ISetupIntentResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/billing/payment-method/setup',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Save the card after the client confirms the SetupIntent: makes it the\n\t// default and records it. 422 when the card isn't attached to this customer.\n\tsavePaymentMethod(input: ISavePaymentMethodInput) {\n\t\treturn this.http.request<IApiResponse<IPaymentMethodResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/billing/payment-method',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Remove the saved card (detach at the provider + clear the record).\n\tremovePaymentMethod() {\n\t\treturn this.http.request<IApiResponse<IPaymentMethodResult>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: '/billing/payment-method',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// The customer's invoices, newest first — each links out to the hosted\n\t// invoice / PDF. 501 when the provider can't list them.\n\tlistInvoices(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IInvoicesResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/billing/invoices',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tCustomerLabelType,\n\tCustomerSex,\n\tCustomerType,\n\tIApiResponse,\n\tICustomerAddressListResult,\n\tICustomerAddressResult,\n\tICustomerDetailD2DTO,\n\tICustomerDetailDTO,\n\tICustomerEmailListResult,\n\tICustomerEmailResult,\n\tICustomerLabelListResult,\n\tICustomerListResult,\n\tICustomerNoteListResult,\n\tICustomerNoteResult,\n\tICustomerPhoneListResult,\n\tICustomerPhoneResult,\n\tICustomerRelationshipListResult,\n\tICustomerRelationshipResult,\n\tICustomerResult,\n\tICustomerTagListResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface IListCustomersInput {\n\tsearch?: string;\n\tblacklisted?: boolean;\n\tlimit?: number;\n\toffset?: number;\n}\n\nexport interface IGetCustomerInput {\n\tdepth?: 1 | 2;\n}\n\nexport interface ICreateCustomerInput {\n\ttype?: CustomerType;\n\tsex?: CustomerSex;\n\tfirstName?: string | null;\n\tlastName?: string | null;\n\tcompanyName?: string | null;\n\tavatarUrl?: string | null;\n\tlocale?: string | null;\n\treferenceCode?: string | null;\n\treferralCode?: string | null;\n\treferredByCode?: string | null;\n}\n\n// Referral codes are create-time only — the server's update path never\n// writes them, so including them here made updateCustomer({ referralCode })\n// a type-correct 200-OK silent no-op.\nexport type IUpdateCustomerInput = Omit<ICreateCustomerInput, 'referralCode' | 'referredByCode'>;\n\nexport interface IBlacklistCustomerInput {\n\treason?: string;\n}\n\nexport interface IAddEmailInput {\n\temail: string;\n\tlabel?: string;\n\tisPrimary?: boolean;\n}\n\nexport interface IAddPhoneInput {\n\tphone: string;\n\tlabel?: string;\n\tisPrimary?: boolean;\n}\n\nexport interface IAddAddressInput {\n\tcountryIso: string;\n\tzipPostalCode: string;\n\tsubdivision1Iso?: string | null;\n\tsubdivision2Iso?: string | null;\n\tunit?: string | null;\n\tline1?: string | null;\n\tline2?: string | null;\n\tlabel?: string;\n\tisPrimary?: boolean;\n}\n\nexport interface IAddRelationshipInput {\n\trelatedId: string;\n\t// Required — the server rejects relationship-less links with a 422.\n\trelationship: string;\n\tisPrimary?: boolean;\n}\n\n// ── Customers client ─────────────────────────────────────────────────────────\n\nexport class CustomersClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes every request to this workspace (X-Workspace-ID). Falls back to\n\t// the caller's personal workspace when unset, same as billing/workspaces/audit/webhooks.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\t// ── Core customer CRUD ───────────────────────────────────────────────────────\n\n\tlistCustomers(input: IListCustomersInput = {}, opts?: IReadOptions) {\n\t\tconst params = new URLSearchParams();\n\t\tif (input.search !== undefined) params.set('search', input.search);\n\t\tif (input.blacklisted !== undefined) params.set('blacklisted', String(input.blacklisted));\n\t\tif (input.limit !== undefined) params.set('limit', String(input.limit));\n\t\tif (input.offset !== undefined) params.set('offset', String(input.offset));\n\t\tconst qs = params.toString();\n\n\t\treturn this.http.request<IApiResponse<ICustomerListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: qs ? `/customers?${qs}` : '/customers',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateCustomer(input: ICreateCustomerInput = {}) {\n\t\treturn this.http.request<IApiResponse<ICustomerResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/customers',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// depth defaults to 2 server-side; pass { depth: 1 } for one level of\n\t// relationship expansion instead of the D2 (nested-relationships) shape.\n\tgetCustomer(customerId: string, input: IGetCustomerInput = {}, opts?: IReadOptions) {\n\t\tconst qs = input.depth === 1 ? '?depth=1' : '';\n\t\treturn this.http.request<IApiResponse<ICustomerDetailDTO | ICustomerDetailD2DTO>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}${qs}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateCustomer(customerId: string, input: IUpdateCustomerInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tdeleteCustomer(customerId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tblacklistCustomer(customerId: string, input: IBlacklistCustomerInput = {}) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/blacklist`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tunblacklistCustomer(customerId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/unblacklist`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Emails ───────────────────────────────────────────────────────────────────\n\n\tlistEmails(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerEmailListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddEmail(customerId: string, input: IAddEmailInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerEmailResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Only the label is editable — email addresses themselves are immutable\n\t// once added; remove and re-add to change the address.\n\tupdateEmailLabel(customerId: string, emailId: string, label: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerEmailResult>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails/${encodeURIComponent(emailId)}`,\n\t\t\tbody: { label },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryEmail(customerId: string, emailId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails/${encodeURIComponent(emailId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveEmail(customerId: string, emailId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/emails/${encodeURIComponent(emailId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Phones ───────────────────────────────────────────────────────────────────\n\n\tlistPhones(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerPhoneListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddPhone(customerId: string, input: IAddPhoneInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerPhoneResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Only the label is editable — same as updateEmailLabel.\n\tupdatePhoneLabel(customerId: string, phoneId: string, label: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerPhoneResult>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones/${encodeURIComponent(phoneId)}`,\n\t\t\tbody: { label },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryPhone(customerId: string, phoneId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones/${encodeURIComponent(phoneId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremovePhone(customerId: string, phoneId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/phones/${encodeURIComponent(phoneId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Addresses ────────────────────────────────────────────────────────────────\n\n\tlistAddresses(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerAddressListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddAddress(customerId: string, input: IAddAddressInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerAddressResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Only the label is editable — same as updateEmailLabel.\n\tupdateAddressLabel(customerId: string, addrId: string, label: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerAddressResult>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses/${encodeURIComponent(addrId)}`,\n\t\t\tbody: { label },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryAddress(customerId: string, addrId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses/${encodeURIComponent(addrId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveAddress(customerId: string, addrId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/addresses/${encodeURIComponent(addrId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Notes ────────────────────────────────────────────────────────────────────\n\n\tlistNotes(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerNoteListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateNote(customerId: string, body: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerNoteResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes`,\n\t\t\tbody: { body },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tupdateNote(customerId: string, noteId: string, body: string) {\n\t\treturn this.http.request<IApiResponse<ICustomerNoteResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes/${encodeURIComponent(noteId)}`,\n\t\t\tbody: { body },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tdeleteNote(customerId: string, noteId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/notes/${encodeURIComponent(noteId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Tags ─────────────────────────────────────────────────────────────────────\n\n\tlistTags(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerTagListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/tags`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddTag(customerId: string, tag: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/tags`,\n\t\t\tbody: { tag },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveTag(customerId: string, tag: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${customerId}/tags/${encodeURIComponent(tag)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Relationships ────────────────────────────────────────────────────────────\n\n\tlistRelationships(customerId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerRelationshipListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddRelationship(customerId: string, input: IAddRelationshipInput) {\n\t\treturn this.http.request<IApiResponse<ICustomerRelationshipResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tsetPrimaryRelationship(customerId: string, relatedId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships/${encodeURIComponent(relatedId)}/primary`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveRelationship(customerId: string, relatedId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/${encodeURIComponent(customerId)}/relationships/${encodeURIComponent(relatedId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Labels ───────────────────────────────────────────────────────────────────\n\t// Shared vocabulary across all customers in the workspace — labels are\n\t// looked up/created implicitly by addEmail/addPhone/addAddress's `label`\n\t// string; these two methods are for managing the vocabulary directly\n\t// (e.g. an admin screen listing/pruning unused labels).\n\n\tlistLabels(type: CustomerLabelType, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<ICustomerLabelListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/customers/labels?type=${encodeURIComponent(type)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tremoveLabel(labelId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/customers/labels/${encodeURIComponent(labelId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type { IApiResponse, IMediaAssetResult } from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\n// Upload an image. `dataBase64` is the RAW base64 payload (no `data:` prefix) —\n// the server sniffs the real type from magic bytes, enforces the byte cap, and\n// rejects SVG (stored-XSS). `purpose` groups assets (e.g. 'avatar'); ownerType\n// /ownerId default server-side to the calling user, so a plain avatar upload\n// needs only `dataBase64`.\nexport interface IUploadMediaInput {\n\tdataBase64: string;\n\tpurpose?: string;\n\townerType?: string;\n\townerId?: string;\n}\n\n// ── Media client ─────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, like auth). NOT\n// workspace-scoped: @fonderie/media keys ownership off ownerType/ownerId in the\n// body, not an X-Workspace-ID header.\n\nexport class MediaClient {\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// POST /media — store an image; returns the asset with its monomorphic\n\t// /media/:id url. requireAuth server-side.\n\tupload(input: IUploadMediaInput) {\n\t\treturn this.http.request<IApiResponse<IMediaAssetResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/media',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// DELETE /media/:id — uploader-only (403 for anyone else).\n\tdelete(id: string) {\n\t\treturn this.http.request<IApiResponse<{ id: string }>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/media/${encodeURIComponent(id)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// Absolute URL for a stored asset — an `<img src>` target. The GET /media/:id\n\t// route is public and cached (it can't carry a Bearer token), so turn an\n\t// upload's `asset.id` into a browser-loadable URL with this, and use it as\n\t// the avatarUrl handed to auth's updateProfile.\n\tassetUrl(id: string): string {\n\t\treturn this.http.absolute(`/media/${encodeURIComponent(id)}`);\n\t}\n\n\t// Inverse of assetUrl: pull the asset id out of one of THIS brick's\n\t// /media/:id URLs (absolute or relative); null for empty/external URLs. Lets\n\t// avatar cleanup delete only assets we minted (matched as a UUID), never a\n\t// placeholder or third-party avatar URL.\n\tassetIdFromUrl(url: string | null | undefined): string | null {\n\t\tif (!url) return null;\n\t\tconst m = url.match(\n\t\t\t/\\/media\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:[/?#]|$)/i,\n\t\t);\n\t\treturn m ? m[1]! : null;\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type { IApiResponse } from '../types';\n\n// ── Public remote config ─────────────────────────────────────────────────────\n// The frontend's read path for feature flags and runtime settings: only the\n// keys the server lists in ConfigModule's `publicKeys`. One snapshot per\n// FonderieClient, shared by every screen and hook that reads it — load it once\n// (typically right after sign-in, or at app start for signed-out flags), then\n// read synchronously anywhere.\n\nexport interface IRemoteConfigState {\n\t/** key → value, as last loaded. Empty until the first load succeeds. */\n\tvalues: Readonly<Record<string, unknown>>;\n\t/** When values were last loaded successfully; null before that. */\n\tloadedAt: Date | null;\n\tisLoading: boolean;\n\t/** The last load's failure, cleared by the next success. Values are kept. */\n\terror: unknown;\n}\n\ntype Listener = (state: IRemoteConfigState) => void;\n\nexport class ConfigClient {\n\tprivate state: IRemoteConfigState = { values: {}, loadedAt: null, isLoading: false, error: null };\n\tprivate listeners = new Set<Listener>();\n\tprivate inFlight: Promise<IRemoteConfigState> | null = null;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\t// GET /config/public — fetch the public values into the shared snapshot.\n\t// Concurrent calls share one request. A failure keeps the previous values\n\t// (a flag that was on does not flicker off because one refresh failed) and\n\t// is reported in `error`; before any success, reads fall back to defaults.\n\tload(): Promise<IRemoteConfigState> {\n\t\tif (this.inFlight) return this.inFlight;\n\t\tthis.set({ isLoading: true });\n\t\tthis.inFlight = this.http\n\t\t\t.request<IApiResponse<{ values: Record<string, unknown> }>>({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: '/config/public',\n\t\t\t\t// Sent when signed in, so per-user values can be served later\n\t\t\t\t// without a client change; the route itself is public.\n\t\t\t\ttoken: this.tokens.get(),\n\t\t\t})\n\t\t\t.then(\n\t\t\t\t(res) => this.set({ values: res.result?.values ?? {}, loadedAt: new Date(), isLoading: false, error: null }),\n\t\t\t\t(error: unknown) => this.set({ isLoading: false, error }),\n\t\t\t)\n\t\t\t.finally(() => {\n\t\t\t\tthis.inFlight = null;\n\t\t\t});\n\t\treturn this.inFlight;\n\t}\n\n\t// One value, with the fallback used when the key is absent — before the\n\t// first load, when it failed, or when the server does not expose the key.\n\t// Pick the SAFE fallback (feature off), not the optimistic one.\n\tget<T>(key: string, fallback: T): T {\n\t\treturn Object.hasOwn(this.state.values, key) ? (this.state.values[key] as T) : fallback;\n\t}\n\n\t// The whole current state (values, loadedAt, isLoading, error).\n\tsnapshot(): IRemoteConfigState {\n\t\treturn this.state;\n\t}\n\n\t// Called with the new state after every change; returns an unsubscribe.\n\tsubscribe(listener: Listener): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\tprivate set(patch: Partial<IRemoteConfigState>): IRemoteConfigState {\n\t\t// A new object each time, so React's useSyncExternalStore and Vue refs\n\t\t// see a change by identity.\n\t\tthis.state = { ...this.state, ...patch };\n\t\tfor (const listener of this.listeners) listener(this.state);\n\t\treturn this.state;\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIApiResponse,\n\tITestWebhookResult,\n\tIWebhookDeliveryListResult,\n\tIWebhookEndpointCreatedDTO,\n\tIWebhookEndpointDTO,\n\tIWebhookEndpointListResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ICreateWebhookEndpointInput {\n\turl: string;\n\tevents?: string[];\n}\n\nexport interface IUpdateWebhookEndpointInput {\n\turl?: string;\n\tevents?: string[];\n\tenabled?: boolean;\n}\n\n// ── Webhooks client ──────────────────────────────────────────────────────────\n\nexport class WebhooksClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes every request to this workspace (X-Workspace-ID). Falls back to\n\t// the caller's personal workspace when unset, same as billing/workspaces/audit.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\tlistEndpoints(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/webhooks',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\t// The response includes `secret` — shown once, at creation. There is no\n\t// way to retrieve it again afterward; store it or let the caller copy it.\n\tcreateEndpoint(input: ICreateWebhookEndpointInput) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointCreatedDTO>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/webhooks',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetEndpoint(endpointId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointDTO>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateEndpoint(endpointId: string, input: IUpdateWebhookEndpointInput) {\n\t\treturn this.http.request<IApiResponse<IWebhookEndpointDTO>>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tdeleteEndpoint(endpointId: string) {\n\t\treturn this.http.request<undefined>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tlistDeliveries(endpointId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWebhookDeliveryListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}/deliveries`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\ttestEndpoint(endpointId: string) {\n\t\treturn this.http.request<IApiResponse<ITestWebhookResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/webhooks/${encodeURIComponent(endpointId)}/test`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n}\n","import type { HttpClient } from '../http';\nimport type { TokenStore } from '../token-store';\nimport type {\n\tIReadOptions,\n\tIAcceptInvitationResult,\n\tIApiResponse,\n\tIInvitationListResult,\n\tIInviteResult,\n\tIMemberListResult,\n\tIRoleListResult,\n\tIRoleResult,\n\tIWorkspaceListResult,\n\tIWorkspaceResult,\n\tIWorkspaceSettingsResult,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ICreateWorkspaceInput {\n\tname: string;\n\tdescription?: string;\n\ttype?: string;\n}\n\nexport interface IUpdateWorkspaceInput {\n\tname?: string;\n\tdescription?: string | null;\n\tmotto?: string | null;\n\tphone?: string | null;\n\tbusinessType?: string | null;\n\taddress?: {\n\t\tline1?: string;\n\t\tline2?: string;\n\t\tcity?: string;\n\t\tstate?: string;\n\t\tzip?: string;\n\t\tcountry?: string;\n\t} | null;\n}\n\nexport interface IInviteEntry {\n\temail: string;\n\troleId?: string;\n}\n\nexport interface IUpdateSettingsInput {\n\tlocale?: string;\n\ttimezone?: string;\n\tcurrency?: string;\n\tdateFormat?: string;\n\ttimeFormat?: string;\n}\n\nexport interface ICreateRoleInput {\n\tname: string;\n\tdescription?: string;\n}\n\nexport interface IUpdateRoleInput {\n\tname?: string;\n\tdescription?: string | null;\n\tactive?: boolean;\n}\n\nexport interface IRolePermissionInput {\n\tpermissionKey: string;\n\tcanCreate?: boolean;\n\tcanRead?: boolean;\n\tcanUpdate?: boolean;\n\tcanDelete?: boolean;\n}\n\nexport interface IRolePermission {\n\tpermissionKey: string;\n\tcanCreate: boolean;\n\tcanRead: boolean;\n\tcanUpdate: boolean;\n\tcanDelete: boolean;\n}\n\nexport interface IRolePermissionsResult {\n\tpermissions: IRolePermission[];\n}\n\n// ── Workspaces client ────────────────────────────────────────────────────────\n\nexport class WorkspacesClient {\n\tprivate workspaceId: string | undefined;\n\n\tconstructor(\n\t\tprivate http: HttpClient,\n\t\tprivate tokens: TokenStore,\n\t) {}\n\n\tsetAccessToken(token: string | undefined) {\n\t\tthis.tokens.set(token);\n\t}\n\n\t// Scopes every subsequent request to this workspace (X-Workspace-ID).\n\t// Falls back to the caller's personal workspace when unset.\n\tsetWorkspaceId(workspaceId: string | undefined) {\n\t\tthis.workspaceId = workspaceId;\n\t}\n\n\t// ── Workspace creation + listing ─────────────────────────────────────────────\n\n\tlistWorkspaces(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateWorkspace(input: ICreateWorkspaceInput) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\tgetWorkspace(id: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/${encodeURIComponent(id)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateWorkspace(input: IUpdateWorkspaceInput) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/workspaces',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// Personal workspaces can't be archived — the server returns 403 if you try.\n\tarchiveWorkspace() {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/archive',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\trestoreWorkspace() {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/restore',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Roles ────────────────────────────────────────────────────────────────────\n\n\tlistRoles(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRoleListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/roles',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tcreateRole(input: ICreateRoleInput) {\n\t\treturn this.http.request<IApiResponse<IRoleResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/roles',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetRole(roleId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRoleResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateRole(roleId: string, input: IUpdateRoleInput) {\n\t\treturn this.http.request<IApiResponse<IRoleResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}`,\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveRole(roleId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetRolePermissions(roleId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRolePermissionsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}/permissions`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tsetRolePermissions(roleId: string, permissions: IRolePermissionInput[]) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/workspaces/roles/${encodeURIComponent(roleId)}/permissions`,\n\t\t\tbody: { permissions },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Members ──────────────────────────────────────────────────────────────────\n\n\tlistMembers(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IMemberListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/members',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tremoveMember(userId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tgetMemberRoles(userId: string, opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IRoleListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}/roles`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\taddMemberRole(userId: string, roleId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}/roles`,\n\t\t\tbody: { roleId },\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tremoveMemberRole(userId: string, roleId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/members/${encodeURIComponent(userId)}/roles/${encodeURIComponent(roleId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\t// ── Invitations ──────────────────────────────────────────────────────────────\n\n\tlistInvitations(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IInvitationListResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/invitations',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tinvite(entries: IInviteEntry | IInviteEntry[]) {\n\t\treturn this.http.request<IApiResponse<IInviteResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/invitations',\n\t\t\tbody: entries,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tcancelInvitation(inviteId: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath: `/workspaces/invitations/${encodeURIComponent(inviteId)}`,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n\n\tacceptInvitation(pin: string) {\n\t\treturn this.http.request<IApiResponse<IAcceptInvitationResult>>({\n\t\t\tmethod: 'POST',\n\t\t\tpath: '/workspaces/invitations/accept',\n\t\t\tbody: { pin },\n\t\t\ttoken: this.tokens.get(),\n\t\t});\n\t}\n\n\t// ── Settings ─────────────────────────────────────────────────────────────────\n\n\tgetSettings(opts?: IReadOptions) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceSettingsResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: '/workspaces/settings',\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t\tbust: opts?.bust,\n\t\t});\n\t}\n\n\tupdateSettings(input: IUpdateSettingsInput) {\n\t\treturn this.http.request<IApiResponse<IWorkspaceSettingsResult>>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath: '/workspaces/settings',\n\t\t\tbody: input,\n\t\t\ttoken: this.tokens.get(),\n\t\t\tworkspaceId: this.workspaceId,\n\t\t});\n\t}\n}\n","// Shared by every module of a FonderieClient so that setting the access\n// token on one (e.g. AuthClient after login) is immediately visible to all\n// the others (e.g. BillingClient) — they're separate module instances, but\n// one session.\nexport class TokenStore {\n\tprivate token: string | undefined;\n\n\tconstructor(initial?: string) {\n\t\tthis.token = initial;\n\t}\n\n\tget(): string | undefined {\n\t\treturn this.token;\n\t}\n\n\tset(token: string | undefined) {\n\t\tthis.token = token;\n\t}\n}\n","import type { ICache } from './cache';\nimport { HttpClient } from './http';\nimport { AuditClient } from './modules/audit';\nimport { AuthClient } from './modules/auth';\nimport { BillingClient } from './modules/billing';\nimport { CustomersClient } from './modules/customers';\nimport { MediaClient } from './modules/media';\nimport { ConfigClient } from './modules/config';\nimport { WebhooksClient } from './modules/webhooks';\nimport { WorkspacesClient } from './modules/workspaces';\nimport { TokenStore } from './token-store';\nimport type { IApiResponse, ITokens } from './types';\n\n// Reactive token renewal. When set, the client refreshes once on a 401 and\n// retries the request. The app owns where the refresh token lives and where new\n// tokens are persisted.\nexport interface IClientAuthConfig {\n\tgetRefreshToken?: () => string | undefined;\n\tonTokensChanged?: (tokens: ITokens) => void;\n\tonAuthError?: () => void;\n}\n\nexport interface IFonderieClientOptions {\n\tbaseUrl: string;\n\taccessToken?: string;\n\tworkspaceId?: string;\n\t// Opt-in response cache (see createMemoryCache). Omit for no caching.\n\tcache?: ICache;\n\t// Opt-in reactive renew.\n\tauth?: IClientAuthConfig;\n}\n\n// Per-call options for the generic transport.\nexport interface IRequestConfig {\n\tworkspaceId?: string;\n\t// Per-call Bearer override — e.g. the MFA-login step, where a temporary\n\t// mfaToken is used before the session access token exists. Defaults to the\n\t// client's stored token.\n\ttoken?: string;\n\t// Cache this GET for `cache` ms; false to skip; bust to force-refresh.\n\tcache?: number | false;\n\tbust?: boolean;\n\t// Extra cache key fragments to evict after a write.\n\tinvalidate?: string[];\n}\n\nexport class FonderieClient {\n\treadonly auth: AuthClient;\n\treadonly billing: BillingClient;\n\treadonly workspaces: WorkspacesClient;\n\treadonly audit: AuditClient;\n\treadonly webhooks: WebhooksClient;\n\treadonly customers: CustomersClient;\n\treadonly media: MediaClient;\n\t/** Public remote config: flags and settings the server exposes to frontends. */\n\treadonly config: ConfigClient;\n\n\tprivate http: HttpClient;\n\tprivate tokens: TokenStore;\n\tprivate workspaceId: string | undefined;\n\tprivate cache: ICache | undefined;\n\tprivate authConfig: IClientAuthConfig | undefined;\n\tprivate refreshing: Promise<string | undefined> | null = null;\n\n\tconstructor(opts: IFonderieClientOptions) {\n\t\tthis.tokens = new TokenStore(opts.accessToken);\n\t\tthis.workspaceId = opts.workspaceId;\n\t\tthis.cache = opts.cache;\n\t\tthis.authConfig = opts.auth;\n\t\tthis.http = new HttpClient(opts.baseUrl, {\n\t\t\tcache: opts.cache,\n\t\t\tdefaultTtlMs: (opts.cache as { defaultTtlMs?: number } | undefined)?.defaultTtlMs,\n\t\t\trefresh: opts.auth ? () => this.doRefresh() : undefined,\n\t\t});\n\t\tthis.auth = new AuthClient(this.http, this.tokens);\n\t\tthis.billing = new BillingClient(this.http, this.tokens);\n\t\tthis.workspaces = new WorkspacesClient(this.http, this.tokens);\n\t\tthis.audit = new AuditClient(this.http, this.tokens);\n\t\tthis.webhooks = new WebhooksClient(this.http, this.tokens);\n\t\tthis.customers = new CustomersClient(this.http, this.tokens);\n\t\t// Media is per-user (ownership via ownerType/ownerId in the body), so no\n\t\t// setWorkspaceId wiring below — just the shared http + token store.\n\t\tthis.media = new MediaClient(this.http, this.tokens);\n\t\tthis.config = new ConfigClient(this.http, this.tokens);\n\t\t// Route through the setter so the constructor option scopes the\n\t\t// workspace-aware modules exactly like a later setWorkspaceId() call.\n\t\tif (opts.workspaceId !== undefined) this.setWorkspaceId(opts.workspaceId);\n\t}\n\n\t// Single-flight refresh: POST /auth/refresh with the app-supplied refresh\n\t// token, store the new access token, notify the app, return it for the retry.\n\tprivate doRefresh(): Promise<string | undefined> {\n\t\tif (this.refreshing) return this.refreshing;\n\t\tthis.refreshing = (async () => {\n\t\t\tconst refreshToken = this.authConfig?.getRefreshToken?.();\n\t\t\tif (!refreshToken) {\n\t\t\t\tthis.authConfig?.onAuthError?.();\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { result } = await this.auth.refreshTokens(refreshToken);\n\t\t\t\tconst tokens = (result as unknown as { tokens: ITokens }).tokens;\n\t\t\t\tthis.tokens.set(tokens.access);\n\t\t\t\tthis.authConfig?.onTokensChanged?.(tokens);\n\t\t\t\treturn tokens.access;\n\t\t\t} catch {\n\t\t\t\tthis.tokens.set(undefined);\n\t\t\t\tthis.authConfig?.onAuthError?.();\n\t\t\t\treturn undefined;\n\t\t\t} finally {\n\t\t\t\tthis.refreshing = null;\n\t\t\t}\n\t\t})();\n\t\treturn this.refreshing;\n\t}\n\n\t// The JWT used to authenticate every request — the typed modules and the\n\t// generic transport share one token store. Passing undefined signs out and\n\t// clears the cache (so no session's data survives a logout).\n\tsetAccessToken(token: string | undefined): void {\n\t\tthis.tokens.set(token);\n\t\tif (!token) this.clearCache();\n\t}\n\n\t// Drop all cached responses (e.g. on switching accounts).\n\tclearCache(): void {\n\t\tthis.cache?.clear();\n\t}\n\n\t// Default X-Workspace-ID for the generic transport, also propagated to the\n\t// workspace-scoped modules so one call configures the whole client.\n\tsetWorkspaceId(workspaceId: string | undefined): void {\n\t\tthis.workspaceId = workspaceId;\n\t\tthis.billing.setWorkspaceId(workspaceId);\n\t\tthis.workspaces.setWorkspaceId(workspaceId);\n\t\tthis.customers.setWorkspaceId(workspaceId);\n\t\tthis.audit.setWorkspaceId(workspaceId);\n\t\tthis.webhooks.setWorkspaceId(workspaceId);\n\t}\n\n\t// ── Generic transport ──────────────────────────────────────────────────────\n\t// A Fonderie-aware HTTP client for endpoints outside the typed modules (an\n\t// app's own routes on the same backend). It attaches the shared JWT and\n\t// X-Workspace-ID automatically and returns Fonderie's { reason, explanation,\n\t// result } envelope — so you don't hand-roll auth for custom endpoints.\n\n\trequest<T = unknown>(opts: {\n\t\tmethod: string;\n\t\tpath: string;\n\t\tbody?: unknown;\n\t\ttoken?: string | undefined;\n\t\tworkspaceId?: string | undefined;\n\t\tcache?: number | false | undefined;\n\t\tbust?: boolean | undefined;\n\t\tinvalidate?: string[] | undefined;\n\t}): Promise<IApiResponse<T>> {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod: opts.method,\n\t\t\tpath: opts.path,\n\t\t\tbody: opts.body,\n\t\t\ttoken: opts.token ?? this.tokens.get(),\n\t\t\tworkspaceId: opts.workspaceId ?? this.workspaceId,\n\t\t\tcache: opts.cache,\n\t\t\tbust: opts.bust,\n\t\t\tinvalidate: opts.invalidate,\n\t\t});\n\t}\n\n\tget<T = unknown>(path: string, config?: IRequestConfig): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'GET',\n\t\t\tpath,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tcache: config?.cache,\n\t\t\tbust: config?.bust,\n\t\t});\n\t}\n\n\tpost<T = unknown>(\n\t\tpath: string,\n\t\tbody?: unknown,\n\t\tconfig?: IRequestConfig,\n\t): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'POST',\n\t\t\tpath,\n\t\t\tbody,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n\n\tput<T = unknown>(\n\t\tpath: string,\n\t\tbody?: unknown,\n\t\tconfig?: IRequestConfig,\n\t): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'PUT',\n\t\t\tpath,\n\t\t\tbody,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n\n\tpatch<T = unknown>(\n\t\tpath: string,\n\t\tbody?: unknown,\n\t\tconfig?: IRequestConfig,\n\t): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'PATCH',\n\t\t\tpath,\n\t\t\tbody,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n\n\tdelete<T = unknown>(path: string, config?: IRequestConfig): Promise<IApiResponse<T>> {\n\t\treturn this.request<T>({\n\t\t\tmethod: 'DELETE',\n\t\t\tpath,\n\t\t\ttoken: config?.token,\n\t\t\tworkspaceId: config?.workspaceId,\n\t\t\tinvalidate: config?.invalidate,\n\t\t});\n\t}\n}\n","// Where an admin surface is mounted, as CONFIG: trailing slashes are typing,\n// not meaning, so '/_admin', '/_admin/' and '/_admin//' are one prefix.\n//\n// This duplicates `normalizeMountPath` in @fonderie/core on purpose: this\n// package ships with **zero runtime dependencies** so it can be dropped into\n// any frontend, and importing a server package to strip a slash would end\n// that. One copy here, used by every admin client — not one per client.\nexport const normalizeMountPath = (path: string): string => path.replace(/\\/+$/, '');\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tIApiResponse,\n\tIConfigEntry,\n\tIConfigRevision,\n\tIRevealSecretResult,\n\tISecretEntry,\n\tISecretRevision,\n} from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ISetConfigInput {\n\tvalue: unknown;\n\tdescription?: string;\n\t// Deactivated entries stay stored but are excluded from runtime reads.\n\tactive?: boolean;\n\tifVersion?: number;\n\t/** Required to change an existing key's value kind (on/off → text, list → object);\n\t * without it the server answers 409 CONFIG_TYPE_CHANGE. */\n\tallowTypeChange?: boolean;\n}\n\nexport interface ISetSecretInput {\n\tvalue: string;\n\tdescription?: string;\n\t// Deactivated secrets stay stored but are excluded from runtime reads.\n\tactive?: boolean;\n\tifVersion?: number;\n}\n\nexport interface IRollbackInput {\n\ttoVersion: number;\n}\n\nexport interface IConfigAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where the composed surface lives when @fonderie/admin mounts this brick's\n\t// routes — '/_admin' replaces the leading '/admin' of every path. Unset ⇒\n\t// the brick's own standalone routes under '/admin'.\n\tprefix?: string;\n\t// Sent as X-Actor on writes — recorded as updatedBy and in revision\n\t// history (defaults server-side to 'admin-token').\n\tactor?: string;\n}\n\nfunction envQuery(environment?: string): string {\n\treturn environment ? `?environment=${encodeURIComponent(environment)}` : '';\n}\n\n// ── Config admin client ──────────────────────────────────────────────────────\n//\n// Separate from FonderieClient on purpose, for the same reason as\n// CourierAdminClient: @fonderie/config's admin routes (/admin/config/*,\n// /admin/secrets/*) are guarded by a static bearer token configured on the\n// server, not the signed-in user's session. Construct with that token\n// directly; it shares no state with AuthClient/BillingClient/WorkspacesClient.\nexport class ConfigAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string | undefined;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IConfigAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = opts.prefix ? normalizeMountPath(opts.prefix) : undefined;\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\t// The path literals stay on the legacy '/admin/...' so the route table and\n\t// the coverage gate read them; the prefix is applied here at request time.\n\tprivate rebase<T extends { path: string }>(opts: T): T {\n\t\tif (!this.prefix) return opts;\n\t\treturn { ...opts, path: opts.path.replace(/^\\/admin(?=\\/|\\?|$)/, this.prefix) };\n\t}\n\n\t// ── Config ───────────────────────────────────────────────────────────────\n\n\tlistConfig(environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/config${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tgetConfig(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tsetConfig(key: string, input: ISetConfigInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tdeleteConfig(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tlistConfigRevisions(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigRevision[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}/revisions${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\trollbackConfig(key: string, input: IRollbackInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IConfigEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/config/${encodeURIComponent(key)}/rollback${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\t// ── Secrets (masked) ─────────────────────────────────────────────────────\n\n\tlistSecrets(environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/secrets${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tgetSecret(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tsetSecret(key: string, input: ISetSecretInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tdeleteSecret(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<undefined>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tlistSecretRevisions(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretRevision[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}/revisions${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\trollbackSecret(key: string, input: IRollbackInput, environment?: string) {\n\t\treturn this.http.request<IApiResponse<ISecretEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}/rollback${envQuery(environment)}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\t// POST (not GET) so the decrypted value never lands in a URL or access log.\n\trevealSecret(key: string, environment?: string) {\n\t\treturn this.http.request<IApiResponse<IRevealSecretResult>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/secrets/${encodeURIComponent(key)}/reveal${envQuery(environment)}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tAdminScope,\n\tIAdminAttention,\n\tIAdminCreatedLink,\n\tIAdminEnrollment,\n\tIAdminOperator,\n\tIAdminOperatorsReport,\n\tIAdminSecondFactor,\n\tIAdminSession,\n\tIAdminEnvironmentReport,\n\tIAdminDoctorReport,\n\tIAdminIssuedToken,\n\tIAdminIssueTokenInput,\n\tIAdminLogPage,\n\tIAdminManifest,\n\tIAdminMigrationModule,\n\tIAdminMigrationsReport,\n\tIAdminRoutesReport,\n\tIAdminTokensReport,\n\tIApiResponse,\n} from '../types';\n\nexport interface IAdminClientOptions {\n\tbaseUrl: string;\n\t// A token (machines, the CLI). Omit it in a browser signed in as an\n\t// operator: the session cookie authenticates instead.\n\tadminToken?: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\nexport interface IAdminLogQuery {\n\tlimit?: number;\n\tbefore?: string;\n}\n\n// Deliberately not on FonderieClient: no user session can reach this surface.\nexport class AdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string | undefined;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\tprivate get<T>(suffix: string) {\n\t\treturn this.call<T>('GET', suffix);\n\t}\n\n\tprivate call<T>(method: string, suffix: string, body?: unknown) {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod,\n\t\t\tpath: `${this.prefix}${suffix}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t\t...(body !== undefined ? { body } : {}),\n\t\t});\n\t}\n\n\tattention() {\n\t\treturn this.get<IAdminAttention>('');\n\t}\n\n\tmanifest() {\n\t\treturn this.get<IAdminManifest>('/manifest');\n\t}\n\n\tdoctor() {\n\t\treturn this.get<IAdminDoctorReport>('/doctor');\n\t}\n\n\tenvironment() {\n\t\treturn this.get<IAdminEnvironmentReport>('/environment');\n\t}\n\n\troutes() {\n\t\treturn this.get<IAdminRoutesReport>('/routes');\n\t}\n\n\ttokens() {\n\t\treturn this.get<IAdminTokensReport>('/access/tokens');\n\t}\n\n\tadminLog(query: IAdminLogQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.before) q.set('before', query.before);\n\t\tconst qs = q.toString();\n\t\treturn this.get<IAdminLogPage>(`/activity/admin-log${qs ? `?${qs}` : ''}`);\n\t}\n\n\t// Root token only. The plaintext comes back once.\n\tissueToken(input: IAdminIssueTokenInput) {\n\t\treturn this.call<IAdminIssuedToken>('POST', '/access/tokens', input);\n\t}\n\n\t// Root token only.\n\trevokeToken(id: string) {\n\t\treturn this.call<undefined>('DELETE', `/access/tokens/${encodeURIComponent(id)}`);\n\t}\n\n\t// What each module is waiting on, with every pending file's impact. Empty\n\t// when the deployment did not hand its migration sequence to the surface.\n\tmigrations() {\n\t\treturn this.get<IAdminMigrationsReport>('/migrations');\n\t}\n\n\t/**\n\t * Apply one module's pending migrations — all of them, or none.\n\t *\n\t * `expect` is the pending list you were shown, in order. If it no longer\n\t * matches, the server refuses with 409 MIGRATIONS_CHANGED rather than\n\t * applying something nobody reviewed. Also refuses 409 when an earlier\n\t * module is behind, and 422 when any pending file deletes data.\n\t */\n\tapplyMigrations(module: string, expect: readonly string[]) {\n\t\treturn this.call<IAdminMigrationModule>(\n\t\t\t'POST',\n\t\t\t`/migrations/${encodeURIComponent(module)}/apply`,\n\t\t\t{ expect },\n\t\t);\n\t}\n\t// ── operator sign-in (the served console's gate) ──────────────────────\n\t// Cookie-based: the server sets an HttpOnly session cookie; nothing here\n\t// ever holds it. Omit adminToken on this client — except for claim().\n\n\t/** Who is signed in, and whether the console can still be claimed. */\n\tsession() {\n\t\treturn this.get<IAdminSession>('/session');\n\t}\n\n\t/** The one-time claim. Needs the ROOT token as this client's adminToken. */\n\tclaim(input: { email: string; password: string; name?: string }) {\n\t\treturn this.call<IAdminSession>('POST', '/session/claim', input);\n\t}\n\n\tlogin(input: { email: string; password: string }) {\n\t\treturn this.call<IAdminSession>('POST', '/session/login', input);\n\t}\n\n\t/** The authenticator secret and otpauth URI to scan while enrolling. */\n\tenrollment() {\n\t\treturn this.get<IAdminEnrollment>('/session/enrollment');\n\t}\n\n\t/** Confirms the first code. The response carries the backup codes, once. */\n\tconfirmEnrollment(code: string) {\n\t\treturn this.call<IAdminSession>('POST', '/session/enrollment', { code });\n\t}\n\n\t/** The second factor after the password: an authenticator code or a backup code. */\n\tverify(factor: IAdminSecondFactor) {\n\t\treturn this.call<IAdminSession>('POST', '/session/verify', factor);\n\t}\n\n\t/** A fresh code for the next five minutes of dangerous actions. */\n\tstepUp(factor: IAdminSecondFactor) {\n\t\treturn this.call<{ stepUpFresh: boolean; backupCodesLeft?: number }>(\n\t\t\t'POST',\n\t\t\t'/session/step-up',\n\t\t\tfactor,\n\t\t);\n\t}\n\n\tlogout() {\n\t\treturn this.call<undefined>('DELETE', '/session');\n\t}\n\n\t/** What an invite or recovery link is for, before setting a password. */\n\tinspectLink(token: string) {\n\t\treturn this.call<{ kind: 'invite' | 'recovery'; email: string }>(\n\t\t\t'POST',\n\t\t\t'/session/link/inspect',\n\t\t\t{ token },\n\t\t);\n\t}\n\n\tredeemLink(input: { token: string; password: string; name?: string }) {\n\t\treturn this.call<IAdminSession>('POST', '/session/link', input);\n\t}\n\n\t// ── managing operators ─────────────────────────────────────────────────\n\n\toperators() {\n\t\treturn this.get<IAdminOperatorsReport>('/access/operators');\n\t}\n\n\t/** An invite link, shown once. Needs the highest scope and a fresh code. */\n\tinviteOperator(input: { email: string; scopes: AdminScope[]; expiresInHours?: number }) {\n\t\treturn this.call<IAdminCreatedLink>('POST', '/access/operators/invites', input);\n\t}\n\n\t/** Lost password or authenticator: a single-use link; signs them out everywhere. */\n\trecoverOperator(id: string) {\n\t\treturn this.call<IAdminCreatedLink>(\n\t\t\t'POST',\n\t\t\t`/access/operators/${encodeURIComponent(id)}/recovery`,\n\t\t);\n\t}\n\n\tupdateOperator(id: string, input: { scopes?: AdminScope[]; name?: string; disabled?: boolean }) {\n\t\treturn this.call<IAdminOperator>('PUT', `/access/operators/${encodeURIComponent(id)}`, input);\n\t}\n\n\trevokeOperatorLink(id: string) {\n\t\treturn this.call<undefined>('DELETE', `/access/operators/links/${encodeURIComponent(id)}`);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tIAdminUserDTO,\n\tIAdminUserPageResult,\n\tIApiResponse,\n\tILoginHistoryPageResult,\n\tISessionDTO,\n} from '../types';\n\nexport interface IAuthAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\nexport interface IAdminLoginHistoryQuery {\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface IAdminUsersQuery {\n\tlimit?: number;\n\tcursor?: string;\n\t// true ⇒ only soft-deleted accounts (not yet purged).\n\tdeleted?: boolean;\n}\n\n// @fonderie/auth's operator routes, which exist only through @fonderie/admin.\n// Deliberately not on FonderieClient: no user session can reach them.\nexport class AuthAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IAuthAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\tprivate call<T>(method: string, suffix: string) {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod,\n\t\t\tpath: `${this.prefix}/users${suffix}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t});\n\t}\n\n\t// A page of users, newest first. The same route as findUser — with an email\n\t// it looks one up, without one it lists.\n\tlistUsers(query: IAdminUsersQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tif (query.deleted) q.set('deleted', '1');\n\t\tconst qs = q.toString();\n\t\treturn this.call<IAdminUserPageResult>('GET', qs ? `?${qs}` : '');\n\t}\n\n\tfindUser(email: string) {\n\t\treturn this.call<IAdminUserDTO>('GET', `?email=${encodeURIComponent(email)}`);\n\t}\n\n\tgetUser(id: string) {\n\t\treturn this.call<IAdminUserDTO>('GET', `/${encodeURIComponent(id)}`);\n\t}\n\n\tlistUserSessions(id: string) {\n\t\treturn this.call<ISessionDTO[]>('GET', `/${encodeURIComponent(id)}/sessions`);\n\t}\n\n\t// Signs the user out everywhere.\n\trevokeUserSessions(id: string) {\n\t\treturn this.call<undefined>('DELETE', `/${encodeURIComponent(id)}/sessions`);\n\t}\n\n\tuserLoginHistory(id: string, query: IAdminLoginHistoryQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.call<ILoginHistoryPageResult>(\n\t\t\t'GET',\n\t\t\t`/${encodeURIComponent(id)}/login-history${qs ? `?${qs}` : ''}`,\n\t\t);\n\t}\n\n\tsuspendUser(id: string) {\n\t\treturn this.call<IAdminUserDTO>('POST', `/${encodeURIComponent(id)}/suspend`);\n\t}\n\n\tunsuspendUser(id: string) {\n\t\treturn this.call<IAdminUserDTO>('POST', `/${encodeURIComponent(id)}/unsuspend`);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type {\n\tIAdminCatalog,\n\tIAdminGrantInput,\n\tIAdminPlanInput,\n\tIAdminSubscriptionDTO,\n\tIAdminSubscriptionPage,\n\tIAdminWalletDTO,\n\tIAdminWalletLedgerPage,\n\tIApiResponse,\n\tIPlanDTO,\n\tSubscriberType,\n} from '../types';\n\nexport interface IBillingAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\nexport interface IAdminSubscriptionsQuery {\n\tlimit?: number;\n\tcursor?: string;\n}\n\nexport interface IAdminLedgerQuery {\n\tcurrency?: string;\n\tlimit?: number;\n\tcursor?: string;\n}\n\n// @fonderie/billing's operator routes, which exist only through @fonderie/admin.\n// Deliberately not on FonderieClient: no user session can reach them.\nexport class BillingAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IBillingAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\tprivate call<T>(method: string, suffix: string, body?: unknown) {\n\t\treturn this.http.request<IApiResponse<T>>({\n\t\t\tmethod,\n\t\t\tpath: `${this.prefix}${suffix}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t\t...(body !== undefined ? { body } : {}),\n\t\t});\n\t}\n\n\tprivate sub(type: SubscriberType, id: string) {\n\t\treturn `/${type}/${encodeURIComponent(id)}`;\n\t}\n\n\tcatalog() {\n\t\treturn this.call<IAdminCatalog>('GET', '/catalog');\n\t}\n\n\tcreatePlan(input: IAdminPlanInput & { name: string }) {\n\t\treturn this.call<IPlanDTO>('POST', '/plans', input);\n\t}\n\n\tupdatePlan(planId: string, input: IAdminPlanInput) {\n\t\treturn this.call<IPlanDTO>('PUT', `/plans/${encodeURIComponent(planId)}`, input);\n\t}\n\n\tdeletePlan(planId: string) {\n\t\treturn this.call<undefined>('DELETE', `/plans/${encodeURIComponent(planId)}`);\n\t}\n\n\t// A page of subscribers, newest first. The lookup below still answers for a\n\t// known subscriber; this is for finding one you cannot name.\n\tlistSubscriptions(query: IAdminSubscriptionsQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.call<IAdminSubscriptionPage>('GET', `/subscriptions${qs ? `?${qs}` : ''}`);\n\t}\n\n\tsubscription(type: SubscriberType, id: string) {\n\t\treturn this.call<IAdminSubscriptionDTO>('GET', `/subscriptions${this.sub(type, id)}`);\n\t}\n\n\twallet(type: SubscriberType, id: string, currency?: string) {\n\t\tconst qs = currency ? `?currency=${encodeURIComponent(currency)}` : '';\n\t\treturn this.call<IAdminWalletDTO>('GET', `/wallet${this.sub(type, id)}${qs}`);\n\t}\n\n\twalletLedger(type: SubscriberType, id: string, query: IAdminLedgerQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.currency) q.set('currency', query.currency);\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.call<IAdminWalletLedgerPage>(\n\t\t\t'GET',\n\t\t\t`/wallet${this.sub(type, id)}/ledger${qs ? `?${qs}` : ''}`,\n\t\t);\n\t}\n\n\t// Manual credit — an idempotency key is required by the server.\n\tgrant(input: IAdminGrantInput) {\n\t\treturn this.call<unknown>('POST', '/wallet/grant', input);\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type { IApiResponse, IAuditPageResult } from '../types';\n\nexport interface IAuditAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where AdminModule was mounted, relative to baseUrl. Default '/_admin'.\n\tprefix?: string;\n\t// Recorded as X-Actor in the admin log.\n\tactor?: string;\n}\n\n// The workspace-scoped filters, plus the workspace itself as a filter.\nexport interface IAdminAuditQuery {\n\tworkspaceId?: string;\n\ttype?: string;\n\tactorId?: string;\n\tfrom?: Date;\n\tto?: Date;\n\tlimit?: number;\n\tcursor?: string;\n}\n\n// @fonderie/audit's operator read, which exists only through @fonderie/admin.\nexport class AuditAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: IAuditAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = normalizeMountPath(opts.prefix ?? '/_admin');\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\t// Every workspace unless one is named. Newest first, keyset-paged.\n\tlistAudit(query: IAdminAuditQuery = {}) {\n\t\tconst q = new URLSearchParams();\n\t\tif (query.workspaceId) q.set('workspaceId', query.workspaceId);\n\t\tif (query.type) q.set('type', query.type);\n\t\tif (query.actorId) q.set('actorId', query.actorId);\n\t\tif (query.from) q.set('from', query.from.toISOString());\n\t\tif (query.to) q.set('to', query.to.toISOString());\n\t\tif (query.limit) q.set('limit', String(query.limit));\n\t\tif (query.cursor) q.set('cursor', query.cursor);\n\t\tconst qs = q.toString();\n\t\treturn this.http.request<IApiResponse<IAuditPageResult>>({\n\t\t\tmethod: 'GET',\n\t\t\tpath: `${this.prefix}/audit${qs ? `?${qs}` : ''}`,\n\t\t\ttoken: this.adminToken,\n\t\t\theaders: this.actorHeaders,\n\t\t});\n\t}\n}\n","import { HttpClient } from '../http';\nimport { normalizeMountPath } from '../path';\nimport type { IApiResponse, ITemplateEntry, ITemplateRevision } from '../types';\n\n// ── Input shapes ─────────────────────────────────────────────────────────────\n\nexport interface ISetTemplateInput {\n\ttext: string;\n\tsubject?: string;\n\thtml?: string;\n\tactive?: boolean;\n\tifVersion?: number;\n}\n\nexport interface IRollbackTemplateInput {\n\ttoVersion: number;\n}\n\nexport interface IPreviewTemplateInput {\n\ttext: string;\n\tsubject?: string;\n\thtml?: string;\n\t// Values for the template's {{variables}}. Omitted, every variable renders\n\t// empty and every {{#section}} collapses — accurate for layout, misleading\n\t// about content.\n\tdata?: Record<string, unknown>;\n}\n\n// What the renderer produced: no `html` key at all for a text-only template.\nexport interface IRenderedTemplateResult {\n\tsubject?: string;\n\thtml?: string;\n\ttext: string;\n\t// Every {{variable}} this content refers to, reported by the server so the\n\t// editor can offer the right fields without re-implementing the contract.\n\tvariables: string[];\n}\n\nexport interface ICourierAdminClientOptions {\n\tbaseUrl: string;\n\tadminToken: string;\n\t// Where the composed surface lives when @fonderie/admin mounts this brick's\n\t// routes — '/_admin' replaces the leading '/admin' of every path. Unset ⇒\n\t// the brick's own standalone routes under '/admin'.\n\tprefix?: string;\n\t// Sent as X-Actor on writes — recorded as updatedBy and in revision\n\t// history (defaults server-side to 'admin-token').\n\tactor?: string;\n}\n\n// ── Courier admin client ─────────────────────────────────────────────────────\n//\n// Separate from FonderieClient on purpose: @fonderie/courier's admin routes\n// (/admin/templates/*) are guarded by a static bearer token configured on the\n// server (CourierModule's adminToken), not the signed-in user's session —\n// the same model @fonderie/config's admin surface uses, and the one the\n// `fonderie template`/`fonderie config` CLI commands already speak to via\n// FONDERIE_ADMIN_URL/FONDERIE_ADMIN_TOKEN. Bundling this into FonderieClient\n// would suggest an end-user's session token can reach it, which it can't —\n// this is an ops/admin-dashboard client, constructed with its own token.\nexport class CourierAdminClient {\n\tprivate http: HttpClient;\n\tprivate adminToken: string;\n\tprivate prefix: string | undefined;\n\tprivate actorHeaders: Record<string, string> | undefined;\n\n\tconstructor(opts: ICourierAdminClientOptions) {\n\t\tthis.http = new HttpClient(opts.baseUrl);\n\t\tthis.adminToken = opts.adminToken;\n\t\tthis.prefix = opts.prefix ? normalizeMountPath(opts.prefix) : undefined;\n\t\tthis.actorHeaders = opts.actor ? { 'X-Actor': opts.actor } : undefined;\n\t}\n\n\t// The path literals stay on the legacy '/admin/...' so the route table and\n\t// the coverage gate read them; the prefix is applied here at request time.\n\tprivate rebase<T extends { path: string }>(opts: T): T {\n\t\tif (!this.prefix) return opts;\n\t\treturn { ...opts, path: opts.path.replace(/^\\/admin(?=\\/|\\?|$)/, this.prefix) };\n\t}\n\n\tlistTemplates() {\n\t\treturn this.http.request<IApiResponse<ITemplateEntry[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: '/admin/templates',\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tgetTemplate(type: string, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}${q}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\tsetTemplate(type: string, input: ISetTemplateInput, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}${q}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tdeleteTemplate(type: string, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<undefined>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}${q}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\tlistRevisions(type: string, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateRevision[]>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'GET',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}/revisions${q}`,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t}),\n\t\t);\n\t}\n\n\trollback(type: string, input: IRollbackTemplateInput, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<ITemplateEntry>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}/rollback${q}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n\n\t// Renders content you are HOLDING, not what is stored — so an editor can\n\t// show the change before it is saved. Server-side on purpose: the shell and\n\t// the variable substitution are the resolver's, and a preview rendered any\n\t// other way would not be the mail that sends.\n\tpreviewTemplate(type: string, input: IPreviewTemplateInput, locale?: string | null) {\n\t\tconst q = locale ? `?locale=${encodeURIComponent(locale)}` : '';\n\t\treturn this.http.request<IApiResponse<IRenderedTemplateResult>>(\n\t\t\tthis.rebase({\n\t\t\t\tmethod: 'POST',\n\t\t\t\tpath: `/admin/templates/${encodeURIComponent(type)}/preview${q}`,\n\t\t\t\tbody: input,\n\t\t\t\ttoken: this.adminToken,\n\t\t\t\theaders: this.actorHeaders,\n\t\t\t}),\n\t\t);\n\t}\n}\n","// Per-call read options accepted by the typed sub-clients' GET methods.\nexport interface IReadOptions {\n\t// Ignore any cached value and refresh it (pull-to-refresh semantics).\n\tbust?: boolean | undefined;\n}\n\n// ── Envelope ─────────────────────────────────────────────────────────────────\n\nexport interface IApiResponse<T = undefined> {\n\treason: string;\n\texplanation: string;\n\tresult: T;\n}\n\nexport interface IApiError {\n\treason: string;\n\texplanation: string;\n\tdetails?: unknown;\n}\n\n// ── User ─────────────────────────────────────────────────────────────────────\n\nexport interface IUserPreferences {\n\tlocale: string;\n\ttimezone: string;\n\tnotifications: { email: boolean; inApp: boolean; sms: boolean; push: boolean };\n\temailDigest: string;\n\tdateFormat: string;\n\ttimeFormat: string;\n}\n\nexport interface IUserDTO {\n\tid: string;\n\temail: string;\n\tfirstName: string;\n\tlastName: string;\n\tphone: string;\n\tprofileImageUrl: string;\n\tisActive: boolean;\n\tlastLogin: string;\n\tpreferences: IUserPreferences;\n\tisEmailVerified: boolean;\n\tisPhoneVerified: boolean;\n\tmfaEnabled: boolean;\n\t// OAuth provider linked to this account ('google', 'apple'), or '' if none.\n\tprovider: string;\n\t// Whether a password is set. With `provider`, this is what a settings screen\n\t// needs to render sign-in methods and to know whether unlinkOauth() can\n\t// succeed — an account with no password has no other credential, so the\n\t// server refuses (409 PASSWORD_REQUIRED) rather than locking the user out.\n\thasPassword: boolean;\n\tsuspended: boolean;\n\twhitelist: boolean;\n\tipWhitelist: string[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface ITokens {\n\taccess: string;\n\trefresh: string;\n}\n\n// ── Auth endpoint results ─────────────────────────────────────────────────────\n\n/** What GET /auth/providers answers: the sign-in methods this API can honour. */\nexport interface IAuthProvidersResult {\n\tproviders: string[];\n}\n\nexport interface IRegisterResult {\n\ttokens: ITokens;\n\tuser: IUserDTO;\n\t// True when the account still needs email verification (config-dependent;\n\t// route the user to the verify screen). Absent on phone and MFA/OAuth\n\t// completions, which don't compute it.\n\trequiresVerification?: boolean;\n}\n\nexport interface ILoginResult {\n\ttokens: ITokens;\n\tuser: IUserDTO;\n\t// True when the account still needs email verification (config-dependent;\n\t// route the user to the verify screen). Absent on phone and MFA/OAuth\n\t// completions, which don't compute it.\n\trequiresVerification?: boolean;\n}\n\n// Login response when the account has MFA enabled: no tokens yet — complete\n// the login with auth.mfa.verifyLogin(mfaToken, code).\nexport interface IMfaRequiredResult {\n\tmfaToken: string;\n}\n\nexport function isMfaRequired(\n\tresult: ILoginResult | IMfaRequiredResult,\n): result is IMfaRequiredResult {\n\treturn !('tokens' in result);\n}\n\nexport interface IRefreshResult {\n\ttokens: ITokens;\n}\n\nexport interface IVerifyEmailResult {\n\tverified: boolean;\n\temail: string;\n}\n\n// GET /auth/send-verification: `{ email }` after a resend, `{ verified: true,\n// email }` when the address was already verified, and no result at all on the\n// phone branch — hence both fields optional. The verification pin itself is\n// only ever emailed; it never appears in the response.\nexport interface IResendVerificationResult {\n\temail?: string;\n\tverified?: boolean;\n}\n\nexport interface IMeResult {\n\tuser: IUserDTO;\n}\n\nexport interface IMfaSetupResult {\n\t// Data-URI QR code to scan, plus the one-time backup codes generated at\n\t// setup — matches @fonderie/auth's /auth/mfa/setup response.\n\tqr: string;\n\tbackupCodes: string[];\n}\n\n// POST /auth/mfa/verify with a full session token (setup confirmation). The\n// session token is NOT rotated — MFA is enforced at login, so the existing\n// session stays valid unchanged. The `{ tokens, user }` response only exists\n// on the mfa-pending login path, typed separately as ILoginResult (verifyLogin).\nexport interface IMfaEnabledResult {\n\tmfaEnabled: boolean;\n}\n\n// ── Billing ──────────────────────────────────────────────────────────────────\n\nexport interface IPlanFeature {\n\tname: string;\n\tdescription: string;\n\tenabled: boolean;\n\tlimit?: number;\n}\n\nexport interface IPlanDTO {\n\tid: string;\n\tplanId: string;\n\tname: string;\n\tdescription: string;\n\ttier: number;\n\tseats: number | null;\n\ttrialDays: number;\n\tpricing: {\n\t\tmonthly: number; // in cents, e.g. 1999 = $19.99\n\t\tyearly: number; // in cents\n\t\tcurrency: string; // ISO 4217, e.g. 'USD'\n\t};\n\t/** True when pricing came from a stale cache — a provider outage or a\n\t * transfer window. Show prices as indicative when set. */\n\tpricingStale?: boolean;\n\tfeatures: IPlanFeature[];\n\tmetadata: Record<string, unknown>;\n}\n\nexport type SubscriberType = 'user' | 'workspace';\n\nexport interface ISubscriptionDTO {\n\tid: string;\n\tsubscriberType: SubscriberType;\n\tsubscriberId: string;\n\tplan: string;\n\tinterval: string;\n\tstatus: string;\n\tcancelAtPeriodEnd: boolean;\n\tcurrentPeriodStart: string | null;\n\tcurrentPeriodEnd: string | null;\n\ttrialEndsAt: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IPlanListResult {\n\tplans: IPlanDTO[];\n}\n\nexport interface IPlanResult {\n\tplan: IPlanDTO;\n}\n\nexport interface ISubscriptionResult {\n\tsubscription: ISubscriptionDTO;\n}\n\nexport interface ICheckoutUrlResult {\n\turl: string;\n}\n\nexport interface IPortalUrlResult {\n\turl: string;\n}\n\nexport interface IUsageResult {\n\tmetric: string;\n\ttotal: number;\n\tsince: string;\n}\n\n// Wallet balance snapshot. Money fields are digit strings (server bigint →\n// string); spendPurchased is a real boolean. granted/purchased/spendPurchased/\n// grantedExpiresAt are omitted on a legacy read that predates the bucket split.\nexport interface IWalletDTO {\n\tbalance: string;\n\tcurrency: string;\n\tprecision: number;\n\tgranted?: string;\n\tpurchased?: string;\n\tspendPurchased?: boolean;\n\tgrantedExpiresAt?: string | null;\n}\n\nexport interface IWalletResult {\n\twallet: IWalletDTO;\n}\n\n// One wallet ledger entry. Money fields are digit strings (server bigint →\n// string); `balanceAfter` is the running balance, so a history UI can show a\n// trustworthy per-row balance without re-deriving it.\nexport interface IWalletTransactionDTO {\n\tid: string;\n\ttype: string; // 'purchase' | 'grant' | 'usage' | 'refund' | 'adjustment' | 'expiry'\n\tamount: string; // signed: positive = credit, negative = debit\n\tbalanceAfter: string;\n\tcurrency: string;\n\tdescription: string | null;\n\tproviderTxId: string | null;\n\tmetadata: Record<string, unknown>;\n\tcreatedAt: string;\n}\n\nexport interface IWalletTransactionsResult {\n\ttransactions: IWalletTransactionDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface IWalletCheckoutInput {\n\tpackId: string;\n}\n\nexport interface IWalletPurchaseInput {\n\tpackId: string;\n\t// One per purchase attempt, REUSED on retry: a double-submit or a retry after\n\t// a `processing` result dedupes to the same charge instead of charging twice.\n\tidempotencyKey: string;\n}\n\n// Outcome of an in-app pack purchase charged to the saved card. `status` is the\n// discriminator: 'credited' carries the new balance; 'checkout_required' means\n// fall back to createWalletCheckout (no saved card, or the card needs 3-D\n// Secure); 'declined' is a hard decline; 'processing' is indeterminate — retry\n// with the SAME idempotencyKey (never a fresh hosted checkout, or you'd risk a\n// double-charge).\nexport interface IWalletPurchaseResult {\n\tstatus: 'credited' | 'checkout_required' | 'declined' | 'processing';\n\tbalance?: string;\n\tcurrency?: string;\n\tcredits?: string;\n\tduplicate?: boolean;\n\treason?: 'no_saved_card' | 'authentication_required';\n}\n\nexport interface ICancelSubscriptionInput {\n\t// Default true — keep access until the paid-through date. false ends it now.\n\tatPeriodEnd?: boolean;\n}\n\n// Result of a first-party cancel/reactivate — the subscription's new lifecycle\n// state, read straight back without waiting for the provider webhook.\nexport interface ISubscriptionChangeResult {\n\tatPeriodEnd: boolean;\n\tstatus: string;\n\tcurrentPeriodEnd: string | null;\n}\n\n// The customer's card on file, for display. Never carries the full number —\n// nor the server-side card `fingerprint`, which billing deliberately keeps\n// off the wire (it correlates identity across accounts).\nexport interface IPaymentMethodDTO {\n\tbrand: string;\n\tlast4: string;\n\texpMonth: number;\n\texpYear: number;\n}\n\nexport interface IPaymentMethodResult {\n\tpaymentMethod: IPaymentMethodDTO | null;\n}\n\n// Begin in-app card entry: the provider SetupIntent client secret the embedded\n// card element (Stripe Payment Element) confirms — no hosted-checkout redirect.\nexport interface ISetupIntentResult {\n\tclientSecret: string;\n}\n\n// Save a card after the client confirms the SetupIntent — the provider payment\n// method id the Payment Element produced.\nexport interface ISavePaymentMethodInput {\n\tpaymentMethodId: string;\n}\n\n// One invoice for an in-app history list; `hostedInvoiceUrl`/`invoicePdf` link\n// out to the provider. Amounts are digit strings (smallest currency unit).\nexport interface IInvoiceDTO {\n\tid: string;\n\tnumber: string | null;\n\tamountDue: string;\n\tamountPaid: string;\n\tcurrency: string;\n\tstatus: string;\n\tcreated: string;\n\tdueDate: string | null; // ISO-8601 when the invoice has payment terms; null when paid on charge\n\thostedInvoiceUrl: string | null;\n\tinvoicePdf: string | null;\n}\n\nexport interface IInvoicesResult {\n\tinvoices: IInvoiceDTO[];\n}\n\n// ── Workspaces ───────────────────────────────────────────────────────────────\n\nexport interface IWorkspaceAddressDTO {\n\tline1: string;\n\tline2: string;\n\tcity: string;\n\tstate: string;\n\tzip: string;\n\tcountry: string;\n}\n\nexport interface IWorkspaceDTO {\n\tid: string;\n\tname: string;\n\tslug: string;\n\ttype: string;\n\tdescription: string;\n\tmotto: string;\n\tphone: string;\n\tbusinessType: string;\n\taddress: IWorkspaceAddressDTO;\n\tplan: string;\n\townerId: string;\n\tisPersonal: boolean;\n\tisArchived: boolean;\n\tarchivedAt: string;\n\t// User id that archived the workspace; '' while unarchived.\n\tarchivedBy: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface IRoleDTO {\n\tid: string;\n\tname: string;\n\tisSystem: boolean;\n\tactive: boolean;\n\tdescription: string;\n\tworkspaceId: string;\n}\n\nexport interface IMemberDTO {\n\tuserId: string;\n\tworkspaceId: string;\n\troleId: string;\n\troleName: string;\n\tconfirmed: boolean;\n\tcreatedAt: string;\n\t/** Identity, so a member list can be rendered without a second request. */\n\temail: string;\n\tfirstName: string;\n\tlastName: string;\n\tprofileImageUrl: string;\n}\n\nexport interface IInvitationDTO {\n\tid: string;\n\tworkspaceId: string;\n\temail: string;\n\troleId: string;\n\ttoken: string;\n\tstatus: string;\n\texpiresAt: string;\n\tcreatedAt: string;\n}\n\nexport interface IWorkspaceSettingsDTO {\n\tlocale: string;\n\ttimezone: string;\n\tcurrency: string;\n\tdateFormat: string;\n\ttimeFormat: string;\n}\n\nexport interface IWorkspaceListResult {\n\tworkspaces: IWorkspaceDTO[];\n}\n\nexport interface IWorkspaceResult {\n\tworkspace: IWorkspaceDTO;\n}\n\nexport interface IMemberListResult {\n\tmembers: IMemberDTO[];\n}\n\nexport interface IRoleListResult {\n\troles: IRoleDTO[];\n}\n\nexport interface IRoleResult {\n\trole: IRoleDTO;\n}\n\nexport interface IInvitationListResult {\n\tinvitations: IInvitationDTO[];\n}\n\nexport interface IInviteResult {\n\tinvitations: Array<{ invitationId: string; email: string }>;\n}\n\nexport interface IAcceptInvitationResult {\n\tworkspaceId: string;\n}\n\nexport interface IWorkspaceSettingsResult {\n\tsettings: IWorkspaceSettingsDTO;\n}\n\n// ── Courier admin (template management) ─────────────────────────────────────\n// Admin-token authenticated, not user-session authenticated — see\n// CourierAdminClient. Result shapes here are the raw resource, not wrapped\n// in a named key, matching @fonderie/courier's admin route handlers.\n\nexport interface ITemplateEntry {\n\ttype: string;\n\tlocale: string | null;\n\tsubject: string | null;\n\thtml: string | null;\n\ttext: string;\n\tactive: boolean;\n\tversion: number;\n\tupdatedBy: string | null;\n\tupdatedAt: string;\n}\n\nexport interface ITemplateRevision {\n\ttype: string;\n\tlocale: string | null;\n\tsubject: string | null;\n\thtml: string | null;\n\ttext: string;\n\tversion: number;\n\tactor: string | null;\n\tcreatedAt: string;\n}\n\n// ── Admin (the operator's surface) ───────────────────────────────────────────\n// Admin-token authenticated — see AdminClient. Shapes mirror @fonderie/admin's\n// pages; the client owns its copies, like every other section here.\n\nexport interface IAdminReadinessProblem {\n\tmodule: string;\n\tseverity: 'error' | 'warning';\n\tmessage: string;\n}\n\nexport interface IAdminReadiness {\n\tok: boolean;\n\tproblems: IAdminReadinessProblem[];\n}\n\nexport interface IAdminModuleEntry {\n\tname: string;\n\tversion: string | null;\n\treadiness: IAdminReadiness;\n\tdescribesAdmin: boolean;\n}\n\nexport interface IAdminRouteEntry {\n\tmethod: string;\n\tpath: string;\n\tmodule?: string;\n}\n\nexport interface IAdminManifest {\n\tgeneratedAt: string;\n\tenv: string;\n\t// `host` is null when the surface answers on any hostname.\n\tadmin: { version: string; log: boolean; host: string[] | null };\n\tmodules: IAdminModuleEntry[];\n\treadiness: IAdminReadiness;\n\troutes: IAdminRouteEntry[];\n}\n\nexport interface IAdminCheckResult {\n\tname: string;\n\tmodule: string;\n\tok: boolean;\n\tfindings: string[];\n\tskipped?: string;\n\tdurationMs: number;\n}\n\nexport interface IAdminDoctorReport {\n\tgeneratedAt: string;\n\tok: boolean;\n\tchecks: IAdminCheckResult[];\n}\n\nexport interface IAdminAttentionItem {\n\tsource: string;\n\tseverity: 'error' | 'advice';\n\tmessage: string;\n}\n\nexport interface IAdminAttention {\n\tgeneratedAt: string;\n\tok: boolean;\n\titems: IAdminAttentionItem[];\n}\n\nexport interface IAdminEnvironmentReport {\n\tgeneratedAt: string;\n\treadiness: IAdminReadiness;\n\tmodules: Array<{ name: string; problems: IAdminReadinessProblem[] }>;\n\tenv: Array<{ name: string; set: boolean }>;\n}\n\nexport type AdminRouteGuard = 'admin' | 'probe' | 'app';\n\nexport interface IAdminRoutesReport {\n\tgeneratedAt: string;\n\troutes: Array<IAdminRouteEntry & { guard: AdminRouteGuard }>;\n}\n\nexport type AdminScope = 'read' | 'write' | 'secrets';\n\n// An issued scoped token — never its hash or plaintext.\nexport interface IAdminTokenRecord {\n\tid: string;\n\tname: string;\n\tscopes: AdminScope[];\n\tcreatedBy: string;\n\tcreatedAt: string;\n\texpiresAt: string | null;\n\trevokedAt: string | null;\n\tlastUsedAt: string | null;\n}\n\nexport interface IAdminTokensReport {\n\tgeneratedAt: string;\n\tadmin: { ok: boolean; problems: IAdminReadinessProblem[] };\n\tlegacy: Array<{ module: string; set: boolean }>;\n\t// null when the deployment gave AdminModule no store (issuing is off).\n\tissued: IAdminTokenRecord[] | null;\n}\n\nexport interface IAdminIssueTokenInput {\n\tname: string;\n\tscopes: AdminScope[];\n\texpiresInDays?: number;\n}\n\n// The plaintext is returned once, at issue, and never again.\nexport interface IAdminIssuedToken extends IAdminTokenRecord {\n\ttoken: string;\n}\n\n// ── operators: people who sign in to the admin console ──────────────────\n\n// What the API ever says about an operator — never a hash, secret or code.\nexport interface IAdminOperator {\n\tid: string;\n\temail: string;\n\tname: string | null;\n\tscopes: AdminScope[];\n\t// false until they have scanned the QR code and confirmed a code.\n\tenrolled: boolean;\n\tbackupCodesLeft: number;\n\tlocked: boolean;\n\tcreatedBy: string;\n\tcreatedAt: string;\n\tlastLoginAt: string | null;\n\tdisabledAt: string | null;\n}\n\n// A pending single-use link: an invite, or a recovery for a locked-out operator.\nexport interface IAdminOperatorLink {\n\tid: string;\n\tkind: 'invite' | 'recovery';\n\temail: string;\n\tscopes: AdminScope[];\n\tcreatedBy: string;\n\tcreatedAt: string;\n\texpiresAt: string;\n}\n\nexport interface IAdminOperatorsReport {\n\toperators: IAdminOperator[];\n\tlinks: IAdminOperatorLink[];\n}\n\n// Returned once: the link to hand to the person. `url` points at the console\n// with the token in the hash, so it never reaches a server log.\nexport interface IAdminCreatedLink {\n\tid: string;\n\temail: string;\n\tscopes?: AdminScope[];\n\texpiresAt: string;\n\ttoken: string;\n\turl: string;\n}\n\nexport type AdminSessionState = 'signed-out' | 'needs-2fa' | 'needs-enrollment' | 'signed-in';\n\nexport interface IAdminSession {\n\tstate: AdminSessionState;\n\toperator: IAdminOperator | null;\n\t// true only while no operator exists yet: the root token can claim the console.\n\tclaimable?: boolean;\n\tstepUpFresh?: boolean;\n\t// Present once, right after enrollment. Show them; they are never shown again.\n\tbackupCodes?: string[];\n\t// After signing in with a backup code: how many remain.\n\tbackupCodesLeft?: number;\n}\n\nexport interface IAdminEnrollment {\n\tsecret: string;\n\t// otpauth:// — render as a QR code.\n\turi: string;\n\taccount: string;\n\tissuer: string;\n}\n\nexport type IAdminSecondFactor = { code: string } | { backupCode: string };\n\nexport interface IAdminLogEntry {\n\tid: string;\n\tat: string;\n\tactor: string;\n\tmethod: string;\n\tpath: string;\n\troute: string;\n\tmodule: string;\n\tstatus: number;\n\tdurationMs: number;\n\trequestId: string | null;\n\tclientIp: string | null;\n}\n\nexport interface IAdminLogPage {\n\tentries: IAdminLogEntry[];\n\tnext: string | null;\n}\n\n// The operator's view of a user (@fonderie/auth's described admin routes):\n// the app's own DTO plus what support asks about. Never a hash or MFA secret.\nexport interface IAdminUserDTO extends IUserDTO {\n\tdeletedAt: string | null;\n}\n\n// The operator's money reads (@fonderie/billing's described admin routes).\nexport interface IAdminCatalog {\n\t// config.plans as declared; bigint wallet amounts arrive as strings.\n\tconfigured: unknown[];\n\tstored: IPlanDTO[];\n}\n\nexport interface IAdminSubscriptionDTO {\n\tid: string;\n\tsubscriberType: SubscriberType;\n\tsubscriberId: string;\n\tplan: string;\n\tinterval: string;\n\tstatus: string;\n\tproviderCustomerId: string | null;\n\tproviderSubscriptionId: string | null;\n\tcurrentPeriodStart: string | null;\n\tcurrentPeriodEnd: string | null;\n\tcancelAtPeriodEnd: boolean;\n\ttrialEndsAt: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IAdminWalletDTO extends IWalletDTO {\n\tversion: number;\n\tupdatedAt: string | null;\n}\n\nexport interface IAdminSubscriptionPage {\n\tsubscriptions: IAdminSubscriptionDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface IAdminWalletLedgerPage {\n\tcurrency: string;\n\tentries: IWalletTransactionDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface IAdminPlanInput {\n\tname?: string;\n\tdescription?: string | null;\n\ttier?: number;\n\tseats?: number | null;\n\ttrialDays?: number;\n\tmonthlyAmount?: number | null;\n\tmonthlyPriceId?: string | null;\n\tyearlyAmount?: number | null;\n\tyearlyPriceId?: string | null;\n\tfeatures?: unknown;\n\tmetadata?: unknown;\n}\n\nexport interface IAdminGrantInput {\n\tsubscriberType: SubscriberType;\n\tsubscriberId: string;\n\t// Minor units as a digit string (or a number below 2^53).\n\tamount: string | number;\n\tcurrency?: string;\n\tdescription?: string;\n\tidempotencyKey: string;\n}\n\n// ── Config admin (feature flags / remote config + secrets) ──────────────────\n// Admin-token authenticated, not user-session authenticated — see\n// ConfigAdminClient. Result shapes here are the raw resource, matching\n// @fonderie/config's admin route handlers.\n\nexport interface IConfigEntry {\n\tkey: string;\n\tvalue: unknown;\n\tenvironment: string;\n\tdescription: string | null;\n\tactive: boolean;\n\tversion: number;\n\tupdatedBy: string | null;\n\tupdatedAt: string;\n}\n\nexport interface IConfigRevision {\n\tkey: string;\n\tenvironment: string;\n\tvalue: unknown;\n\tversion: number;\n\tactor: string | null;\n\tcreatedAt: string;\n}\n\n// Deliberately has no `value` — admin list/get never return a secret's\n// plaintext, only the explicit reveal path does.\nexport interface ISecretEntry {\n\tkey: string;\n\tenvironment: string;\n\tdescription: string | null;\n\tactive: boolean;\n\tversion: number;\n\tupdatedBy: string | null;\n\tupdatedAt: string;\n}\n\nexport interface ISecretRevision {\n\tkey: string;\n\tenvironment: string;\n\tversion: number;\n\tactor: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IRevealSecretResult {\n\tvalue: string;\n}\n\n// ── Audit ────────────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, scoped via\n// setWorkspaceId like billing/workspaces) — unlike courier-admin/config-admin,\n// which use a standalone admin token. Read-only: @fonderie/audit has one route.\n\nexport interface IAuditEventDTO {\n\tid: string;\n\ttype: string;\n\tactorId: string | null;\n\trequestId: string | null;\n\tpayload: Record<string, unknown>;\n\tcreatedAt: string;\n}\n\nexport interface IAuditPageResult {\n\tevents: IAuditEventDTO[];\n\tnextCursor: string | null;\n}\n\n// ── Login activity (auth security surfaces) ──────────────────────────────────\n// Session-authenticated; the caller's own history + sessions (shares the\n// AuthClient token). Login history is append-only; sessions are the live list.\n\n/** Where an auth event (login attempt, registration, session) came from. Present only when the server configures a\n * location resolver; every field is optional. Country is reliable; region and\n * city are approximate; network fields appear only with an IP-intelligence\n * provider. */\nexport interface IRequestLocationDTO {\n\tcountry?: string; // ISO-3166-1 alpha-2\n\tcountryName?: string;\n\tsubdivision?: string; // ISO-3166-2 region part\n\tsubdivisionName?: string;\n\tcity?: string;\n\tpostalCode?: string; // ZIP / postal code, approximate — not shown by describeLocation\n\tcontinent?: string;\n\ttimeZone?: string;\n\tlatitude?: number;\n\tlongitude?: number;\n\taccuracyRadius?: number; // km — how approximate the point is\n\tgeonameId?: number; // stable, language-neutral place key (GeoNames)\n\tisp?: string;\n\torg?: string;\n\tasn?: string;\n\tmobile?: boolean;\n\tproxy?: boolean;\n\thosting?: boolean;\n}\n\n/**\n * One short line for a login location: \"Mountain View, CA, US\" — most specific first,\n * skipping what is unknown. Pass a country-name formatter to localise the\n * country (e.g. Intl.DisplayNames). null when nothing is known.\n */\nexport function describeLocation(\n\tloc: IRequestLocationDTO | null | undefined,\n\tcountryName?: (code: string) => string | undefined,\n): string | null {\n\tif (!loc) return null;\n\tconst country = loc.country\n\t\t? (countryName?.(loc.country) ?? loc.country)\n\t\t: (loc.countryName ?? undefined);\n\tconst parts = [loc.city, loc.subdivision ?? loc.subdivisionName, country].filter(\n\t\t(p): p is string => typeof p === 'string' && p.length > 0,\n\t);\n\treturn parts.length > 0 ? parts.join(', ') : null;\n}\n\nexport interface ILoginEventDTO {\n\tid: string;\n\tmethod: string;\n\toutcome: string;\n\tfailureReason: string | null;\n\tipAddress: string | null;\n\tuserAgent: string | null;\n\t/** null when the server has no location resolver, or it knew nothing. */\n\tlocation: IRequestLocationDTO | null;\n\tcreatedAt: string;\n}\n\nexport interface IAdminUserPageResult {\n\tusers: IAdminUserDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface ILoginHistoryPageResult {\n\tevents: ILoginEventDTO[];\n\tnextCursor: string | null;\n}\n\nexport interface ISessionDTO {\n\tid: string;\n\tcurrent: boolean;\n\tipAddress: string | null;\n\tuserAgent: string | null;\n\t/** Where the session was opened from; null without a server-side resolver. */\n\tlocation: IRequestLocationDTO | null;\n\tcreatedAt: string;\n\texpiresAt: string;\n}\n\nexport interface ISessionsResult {\n\tsessions: ISessionDTO[];\n}\n\n// ── Media ────────────────────────────────────────────────────────────────────\n// Session-authenticated image storage (avatars, logos). `url` is the\n// monomorphic, backend-relative /media/:id path; call client.media.assetUrl(id)\n// for an absolute `<img src>`.\n\nexport interface IMediaAssetDTO {\n\tid: string;\n\turl: string;\n\tcontentType: string;\n\tbyteSize: number;\n\townerType: string;\n\townerId: string;\n\tpurpose: string;\n\tcreatedAt: string;\n}\n\nexport interface IMediaAssetResult {\n\tasset: IMediaAssetDTO;\n}\n\n// ── Webhooks ─────────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, scoped via\n// setWorkspaceId like billing/workspaces/audit).\n\nexport interface IWebhookEndpointDTO {\n\tid: string;\n\turl: string;\n\tevents: string[];\n\tenabled: boolean;\n\tcreatedAt: string;\n}\n\n// The signing secret is only ever returned here, at creation — every other\n// read masks it, matching @fonderie/webhooks' own toEndpointDTO/toEndpointCreatedDTO split.\nexport interface IWebhookEndpointCreatedDTO extends IWebhookEndpointDTO {\n\tsecret: string;\n}\n\nexport interface IWebhookDeliveryDTO {\n\tid: string;\n\teventId: string;\n\teventType: string;\n\tstatus: string;\n\tattempts: number;\n\t// The event body that was delivered — what the endpoint received.\n\tpayload: Record<string, unknown>;\n\tresponseStatus: number | null;\n\t// The receiving endpoint's response body (useful when debugging failures).\n\tresponseBody: string | null;\n\t// When the next retry is due; null once delivered or exhausted.\n\tnextAttemptAt: string | null;\n\tdeliveredAt: string | null;\n\tcreatedAt: string;\n}\n\nexport interface IWebhookEndpointListResult {\n\tendpoints: IWebhookEndpointDTO[];\n}\n\nexport interface IWebhookDeliveryListResult {\n\tdeliveries: IWebhookDeliveryDTO[];\n}\n\nexport interface ITestWebhookResult {\n\tstatus: number | null;\n\tok: boolean;\n\terror?: string;\n}\n\n// ── Customers ────────────────────────────────────────────────────────────────\n// Session-authenticated (shares FonderieClient's TokenStore, scoped via\n// setWorkspaceId like billing/workspaces/audit/webhooks).\n\nexport type CustomerType = 'individual' | 'business';\nexport type CustomerSex = 'UNKNOWN' | 'MALE' | 'FEMALE';\nexport type CustomerLabelType = 'phone' | 'email' | 'address';\n\nexport interface ICustomerDTO {\n\tid: string;\n\ttype: string;\n\tsex: CustomerSex;\n\tfirstName: string;\n\tlastName: string;\n\tcompanyName: string;\n\tavatarUrl: string;\n\tlocale: string;\n\treferenceCode: string;\n\treferralCode: string;\n\treferredBy: string | null;\n\tblacklisted: { status: boolean; reason: string | null };\n\tcreatedBy: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface ICustomerEmailDTO {\n\tid: string;\n\temail: string;\n\tlabel: string;\n\t// Id of the shared label row (see listLabels) — null when unlabeled.\n\tlabelId: string | null;\n\tisPrimary: boolean;\n\tcreatedAt: string;\n}\n\nexport interface ICustomerPhoneDTO {\n\tid: string;\n\tphone: string;\n\tlabel: string;\n\t// Id of the shared label row (see listLabels) — null when unlabeled.\n\tlabelId: string | null;\n\tisPrimary: boolean;\n\tcreatedAt: string;\n}\n\nexport interface IAddressDTO {\n\tcountryIso: string;\n\tsubdivision1Iso: string;\n\tsubdivision2Iso: string;\n\tzipPostalCode: string;\n\tunit: string;\n\tline1: string;\n\tline2: string;\n}\n\nexport interface ICustomerAddressDTO {\n\tid: string;\n\tlabel: string;\n\t// Id of the shared label row (see listLabels) — null when unlabeled.\n\tlabelId: string | null;\n\tisPrimary: boolean;\n\taddress: IAddressDTO;\n}\n\nexport interface ICustomerNoteDTO {\n\tid: string;\n\tauthorId: string;\n\tbody: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface ICustomerRelationshipDTO {\n\tid: string;\n\trelatedId: string;\n\trelationship: string;\n\tisPrimary: boolean;\n\tcreatedAt: string;\n}\n\n// Flat merge: relationship metadata + related customer fields spread at the\n// same level. `id` is the relationship record id; `customerId` is the\n// related customer's id — matches @fonderie/customers' own flattening.\nexport type ICustomerRelationshipExpandedDTO = Omit<ICustomerShallowDTO, 'id'> & {\n\tid: string;\n\tcustomerId: string;\n\trelationship: string;\n\tisPrimary: boolean;\n\t// When the relationship itself was created. The spread customer fields\n\t// include the related CUSTOMER's createdAt/updatedAt — don't sort\n\t// relationships by those.\n\trelationshipCreatedAt: string;\n};\n\nexport type ICustomerRelationshipExpandedD2DTO = ICustomerRelationshipExpandedDTO & {\n\trelationships: ICustomerRelationshipExpandedDTO[];\n};\n\nexport interface ICustomerShallowDTO extends ICustomerDTO {\n\temails: ICustomerEmailDTO[];\n\tphones: ICustomerPhoneDTO[];\n\taddresses: ICustomerAddressDTO[];\n\tnotes: ICustomerNoteDTO[];\n\ttags: string[];\n}\n\nexport interface ICustomerDetailDTO extends ICustomerDTO {\n\temails: ICustomerEmailDTO[];\n\tphones: ICustomerPhoneDTO[];\n\taddresses: ICustomerAddressDTO[];\n\tnotes: ICustomerNoteDTO[];\n\trelationships: ICustomerRelationshipExpandedDTO[];\n\ttags: string[];\n}\n\n// depth=1 (default via getCustomer) — one level of relationship expansion.\n// depth=2 (getCustomer(id, { depth: 2 })) — relationships carry their own\n// relationships array one level deeper. Matches @fonderie/customers' D2 DTOs.\nexport interface ICustomerDetailD2DTO extends Omit<ICustomerDetailDTO, 'relationships'> {\n\trelationships: ICustomerRelationshipExpandedD2DTO[];\n}\n\nexport interface ICustomerLabelDTO {\n\tid: string;\n\ttype: CustomerLabelType;\n\tvalue: string;\n\tcreatedAt: string;\n}\n\nexport interface ICustomerListResult {\n\tcustomers: ICustomerDTO[];\n\t// Total matching rows regardless of limit/offset — for pagination.\n\ttotal: number;\n}\n\nexport interface ICustomerResult {\n\tcustomer: ICustomerDTO;\n}\n\nexport interface ICustomerEmailListResult {\n\temails: ICustomerEmailDTO[];\n}\n\nexport interface ICustomerEmailResult {\n\temail: ICustomerEmailDTO;\n}\n\nexport interface ICustomerPhoneListResult {\n\tphones: ICustomerPhoneDTO[];\n}\n\nexport interface ICustomerPhoneResult {\n\tphone: ICustomerPhoneDTO;\n}\n\nexport interface ICustomerAddressListResult {\n\taddresses: ICustomerAddressDTO[];\n}\n\nexport interface ICustomerAddressResult {\n\taddress: ICustomerAddressDTO;\n}\n\nexport interface ICustomerNoteListResult {\n\tnotes: ICustomerNoteDTO[];\n}\n\nexport interface ICustomerNoteResult {\n\tnote: ICustomerNoteDTO;\n}\n\nexport interface ICustomerTagListResult {\n\ttags: string[];\n}\n\nexport interface ICustomerRelationshipListResult {\n\trelationships: ICustomerRelationshipDTO[];\n}\n\nexport interface ICustomerRelationshipResult {\n\trelationship: ICustomerRelationshipDTO;\n}\n\nexport interface ICustomerLabelListResult {\n\tlabels: ICustomerLabelDTO[];\n}\n\n// ---- admin: migrations ----------------------------------------------------\n\nexport type MigrationImpact = 'additive' | 'destructive';\n\nexport interface IAdminPendingMigration {\n\tfile: string;\n\timpact: MigrationImpact;\n\t// The statements that earned a 'destructive' label, as written.\n\tdestructive: string[];\n}\n\nexport interface IAdminMigrationModule {\n\tname: string;\n\tpending: IAdminPendingMigration[];\n\t// The first EARLIER module that is behind, or null. Migration order is the\n\t// app's and sets depend on each other across it.\n\tblockedBy: string | null;\n\t// Whether the panel will apply this one: something to do, nothing in front\n\t// of it, and nothing in it that deletes data.\n\tappliable: boolean;\n}\n\nexport interface IAdminMigrationsReport {\n\t// False when the database has no fonderie_migrations rows — a first\n\t// install, where \"destructive\" has nothing to destroy.\n\teverApplied: boolean;\n\tmodules: IAdminMigrationModule[];\n}\n","// Typed config values for admin UIs (and, later, feature-flag hooks).\n//\n// Config values are stored as JSON, so a stored `true` stays a boolean and `3`\n// stays a number. What an editor needs on top is: which input to show for a\n// value, and how to turn what the operator typed back into a typed value —\n// with an explanation, not a silent failure, when it doesn't parse.\n\nexport type ConfigValueType = 'string' | 'number' | 'boolean' | 'json';\n\nexport const CONFIG_VALUE_TYPES: readonly ConfigValueType[] = ['string', 'number', 'boolean', 'json'];\n\n/** The editor type for a stored value. Objects, arrays and null are JSON. */\nexport function configValueType(value: unknown): ConfigValueType {\n\tif (typeof value === 'string') return 'string';\n\tif (typeof value === 'number') return 'number';\n\tif (typeof value === 'boolean') return 'boolean';\n\treturn 'json';\n}\n\n/** What an input should show for a stored value of that type. */\nexport function formatConfigValue(value: unknown, type: ConfigValueType = configValueType(value)): string {\n\tif (type === 'string') return typeof value === 'string' ? value : String(value ?? '');\n\tif (type === 'number') return typeof value === 'number' ? String(value) : '';\n\tif (type === 'boolean') return value === true ? 'true' : 'false';\n\treturn JSON.stringify(value ?? null, null, 2);\n}\n\nexport type CastResult = { ok: true; value: unknown } | { ok: false; error: string };\n\n/**\n * Turn what an operator typed into the typed value to store.\n * - string: kept verbatim (an empty string is a valid value)\n * - number: finite numbers only — \"1e3\" and \"-2.5\" are fine, \"12px\" is not\n * - boolean: true/false, also 1/0, yes/no, on/off (case-insensitive)\n * - json: any valid JSON\n */\nexport function castConfigValue(type: ConfigValueType, raw: string): CastResult {\n\tif (type === 'string') return { ok: true, value: raw };\n\tconst t = raw.trim();\n\tif (type === 'number') {\n\t\tif (t === '') return { ok: false, error: 'Enter a number.' };\n\t\tconst n = Number(t);\n\t\treturn Number.isFinite(n) ? { ok: true, value: n } : { ok: false, error: `\"${raw}\" is not a number.` };\n\t}\n\tif (type === 'boolean') {\n\t\tconst v = t.toLowerCase();\n\t\tif (['true', '1', 'yes', 'on'].includes(v)) return { ok: true, value: true };\n\t\tif (['false', '0', 'no', 'off'].includes(v)) return { ok: true, value: false };\n\t\treturn { ok: false, error: 'Use true or false.' };\n\t}\n\ttry {\n\t\treturn { ok: true, value: JSON.parse(t) };\n\t} catch (err) {\n\t\treturn { ok: false, error: `Not valid JSON: ${(err as Error).message}` };\n\t}\n}\n\n/**\n * Config keys: letters, digits, `.`, `_`, `-`; must start with a letter; up to\n * 128 characters. Both styles work — `ENABLE_JOB_LISTING` and `feature.dark-mode`.\n */\nexport const CONFIG_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9._-]{0,127}$/;\n\nexport function configKeyProblem(key: string): string | null {\n\tif (!key) return 'Enter a key.';\n\treturn CONFIG_KEY_PATTERN.test(key)\n\t\t? null\n\t\t: 'Start with a letter; use letters, digits, \".\", \"_\" or \"-\" (max 128).';\n}\n\nexport interface IInferredConfigValue {\n\ttype: ConfigValueType;\n\tvalue: unknown;\n\t/** Human label for the detected shape: Text, Number, On/off, Object, List. */\n\tlabel: string;\n\t/**\n\t * True when the input could equally be meant as text — \"true\", \"42\". The\n\t * editor offers \"save as text instead\" for exactly these, and never needs\n\t * to ask about anything else.\n\t */\n\tambiguous: boolean;\n}\n\n// A number only when writing it back gives the same characters: \"42\" and\n// \"-2.5\" qualify; \"1.10\" (a version), \"0123\" (a postal code), \"1e3\" and\n// 12345678901234567890 (an ID past float precision) do not — they stay text\n// rather than being silently rewritten.\nconst PLAIN_NUMBER = /^-?(0|[1-9]\\d*)(\\.\\d+)?$/;\n\n/** Human label for a stored value's shape. */\nexport function configValueLabel(value: unknown): string {\n\tif (typeof value === 'string') return 'Text';\n\tif (typeof value === 'number') return 'Number';\n\tif (typeof value === 'boolean') return 'On/off';\n\tif (Array.isArray(value)) return 'List';\n\tif (value === null) return 'Empty';\n\treturn 'Object';\n}\n\n/**\n * Work out what an operator typed, without asking. Objects and lists (JSON\n * starting with { or [), on/off (true/false), plain numbers, and text for\n * everything else — including anything that merely resembles a number.\n */\nexport function inferConfigValue(raw: string): IInferredConfigValue {\n\tconst t = raw.trim();\n\tif (t === 'true' || t === 'false') {\n\t\treturn { type: 'boolean', value: t === 'true', label: 'On/off', ambiguous: true };\n\t}\n\tif (PLAIN_NUMBER.test(t)) {\n\t\tconst n = Number(t);\n\t\tif (Number.isFinite(n) && String(n) === t) return { type: 'number', value: n, label: 'Number', ambiguous: true };\n\t}\n\tif (t.startsWith('{') || t.startsWith('[')) {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(t);\n\t\t\tif (parsed !== null && typeof parsed === 'object') {\n\t\t\t\treturn { type: 'json', value: parsed, label: Array.isArray(parsed) ? 'List' : 'Object', ambiguous: false };\n\t\t\t}\n\t\t} catch {\n\t\t\t// not valid JSON — it is text that happens to start with a bracket\n\t\t}\n\t}\n\treturn { type: 'string', value: raw, label: 'Text', ambiguous: false };\n}\n"],"mappings":"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","names":["data"]}