Hooks Reference
The package exports exactly three hooks: useIdentity, useSecret, and useP47h. All must be used inside a <P47hProvider>.
Identity & Session
useIdentity()
Authentication state and actions — register, login, logout, recover.
const {
did, // string | null — the current DID
isAuthenticated, // boolean
isLoading, // boolean — an auth operation is in progress
error, // Error | null
storedIdentities, // string[] — DIDs available locally
register, // (password: string) => Promise<{ did: string; recoveryCode: string }>
login, // (password: string, did?: string) => Promise<void>
logout, // () => void
recover, // (recoveryCode: string, newPassword: string) => Promise<void>
} = useIdentity();
Behavior:
registercreates a new identity and returns itsdidand a one-timerecoveryCode. Store the code offline.loginderives the master key and unlocks the vault.logoutlocks the vault and zeroizes keys from WASM memory.- State updates trigger re-renders automatically.
Encrypted State
useSecret(key)
Read and write a single encrypted value. Returns an object (not a tuple).
const {
value, // string | null — decrypted value, null if absent or locked
set, // (value: string) => void — encrypts + persists (debounced)
status, // 'idle' | 'loading' | 'saving' | 'error'
exists, // boolean — value !== null
locked, // boolean — true when no identity is unlocked
error, // Error | null
} = useSecret("stripe_key");
Behavior:
- Auto-loads when the vault unlocks;
valueisnullwhilelocked. setis debounced to avoid excessive writes during typing.- Each key is independent and cached.
Vault Lifecycle
useP47h()
Low-level access to the full vault context. Prefer useIdentity / useSecret; reach for
this only when they don’t cover your case.
const {
state, // current vault state (init / ready / locked / unlocked …)
did, // string | null
isAuthenticated, // boolean
isLoading, // boolean
error, // Error | null
// …plus the same identity actions exposed by useIdentity
} = useP47h();
Warning: this is the raw context. For reactive secret values, prefer useSecret.
There is no
useSecrets,useVault, oruseVaultStatushook, and no policy hook (can/require). Those are not part of the published package.
Common Patterns
Conditional rendering based on auth
function App() {
const { isAuthenticated, isLoading } = useIdentity();
if (isLoading) return <Spinner />;
if (!isAuthenticated) return <LoginForm />;
return <Dashboard />;
}
Storing an API key
function ApiKeyInput() {
const { value, set, status } = useSecret("openai_key");
return (
<input
value={value ?? ""}
onChange={(e) => set(e.target.value)}
disabled={status === "loading"}
placeholder="sk-..."
/>
);
}
Auto-lock on inactivity
function AutoLock({ timeout = 300000 }) {
const { logout, isAuthenticated } = useIdentity();
useEffect(() => {
if (!isAuthenticated) return;
let timer: number;
const reset = () => {
clearTimeout(timer);
timer = window.setTimeout(logout, timeout);
};
window.addEventListener("mousemove", reset);
window.addEventListener("keypress", reset);
reset();
return () => {
clearTimeout(timer);
window.removeEventListener("mousemove", reset);
window.removeEventListener("keypress", reset);
};
}, [isAuthenticated, logout, timeout]);
return null;
}
Failure Modes
Wrong password
login() rejects with an AuthenticationError. The vault stays locked; no data is
corrupted.
try {
await login(password);
} catch (e) {
// e is an AuthenticationError
}
Locked vault
While locked, useSecret(...).value is null and locked is true. Gate your UI on
locked rather than assuming a value.
WASM load failure
If the WASM core fails to load, the provider surfaces the error: useP47h().error is set
and the vault never becomes ready. <P47hProvider errorFallback={…}> lets you render a
fallback. Common causes: a strict CSP blocking wasm-unsafe-eval, or the WASM asset not
served at the expected path.
For cryptographic details, see Security Model.