import type { AccountStorage } from "../interfaces/AccountStorage"; import type { AccountMap } from "../store/slices/accountsSlice"; interface StorageSlot { storage: AccountStorage; projectId: string; } /** * Raised when a second provider mounts for a DIFFERENT project. * * One project per app is the supported shape. Everything under this module is * process-global — the slot below holds one handle, and `config/authGate` holds * one token — so a second project's provider does not get its own world: it * takes over the shared one. The non-last project then silently breaks. Its * switcher stops working, and the mint path's rotated successor is refused at * the persist guard AFTER the exchange has already revoked the presented token, * which locks that account out permanently. * * Failing at mount converts that into a mistake the developer hits on the first * render, before any credential exists to corrupt. */ export declare class AccountStorageMultiProjectError extends Error { constructor(registered: string, incoming: string); } /** * Registers the storage handle an `AccountManager` mounted. Last mount wins; * there is no deregistration by design (see the header). * * **Refuses a second project.** Keyed on the projectId rather than on the * handle, which is what separates the unsupported configuration from the * ordinary ones: a remount, a development hot reload and a second provider for * the SAME project all arrive here with a fresh handle and the same id, and all * three must keep working. Only a different id is the configuration that * corrupts credentials, and it is the only one that throws. * * (There is no deregistration to relax this with. Unmounting deliberately * leaves the slot in place — clearing it would turn a surviving provider's * awaited persist into a silent no-op — so "unmount the first, then mount the * second" is not a supported sequence either, and the message does not offer * it.) */ export declare function registerAccountStorage(storage: AccountStorage, projectId: string): void; /** Test seam — the module state above is shared across a whole run. */ export declare function resetAccountStorage(): void; /** What is registered right now, or `null` when no platform package mounted. */ export declare function getRegisteredAccountStorage(): StorageSlot | null; /** * Runs `op` with exclusive access to `projectId`'s storage. * * The queue survives failures: a rejected op still lets the next one run, and * the rejection is delivered to *its own* caller only. */ export declare function runAccountStorageOp(projectId: string, op: () => Promise): Promise; /** * Raised when a caller's project and the registered slot's project disagree. * A distinct type so the callers that must not proceed on a bad write can tell * "wrong project" apart from "the adapter failed". */ export declare class AccountStorageProjectMismatchError extends Error { constructor(expected: string, registered: string); } /** * Persists a map through the mutex, using the registered handle — for callers * that must not proceed until the write has actually landed. * * Rejects when the underlying write fails, which is only meaningful because the * `AccountStorage` write contract now rejects too. Every adapter used to catch, * log and resolve `void`, so awaiting one succeeded on a failed write and any * guarantee built on the await was fictional. * * With nothing registered — `@sublay/core` used directly with no platform * package, a genuinely storage-less configuration — this resolves immediately. * A clean no-op, never a hang and never a throw. * * **The `projectId` argument is a guard, not a convenience.** The slot is * last-mount-wins across the whole process (see the header), but only among * providers for the SAME project: `registerAccountStorage` throws * `AccountStorageMultiProjectError` when a second provider mounts for a * different one, so the slot never comes to hold a project the app did not * mount for. This check is the backstop behind that one, covering the ways a * caller can still arrive with a mismatched id — a subtree mounted for another * project whose writes were already in flight when the mount-time throw tore it * down, and the `resetAccountStorage` test seam, which re-points the slot with * no mount at all. * * Writing to the slot's project unconditionally would be harmless for * `useAccountSync` — which passes its own handle and catches anyway — but not * for the mint path: a mint that landed its rotated successor under another * project's key would report success while leaving a server-revoked token live * on disk, destroying that account's token family on the next attempt. That is * the single unrecoverable outcome in this surface, so a mismatch rejects * loudly. A storage-LESS configuration is supported; a MISMATCHED one is a bug. * * (An unguarded `persistAccountMap(map)` existed briefly alongside this and was * removed: it ended up with no production caller, and the only thing separating * it from this function was the missing guard.) */ export declare function persistAccountMapFor(projectId: string, map: AccountMap): Promise; export {};