Files
eranos/src/hooks/useCurrentUser.ts
T
2026-05-17 01:00:49 -07:00

89 lines
2.9 KiB
TypeScript

import { useNostr } from '@nostrify/react';
import { type NLoginType, NUser, useNostrLogin } from '@nostrify/react/login';
import { NRelay1, NSecSigner } from '@nostrify/nostrify';
import { nip19 } from 'nostr-tools';
import { useCallback, useMemo } from 'react';
import { useAuthor } from './useAuthor.ts';
import { NSecSignerBtc, NBrowserSignerBtc, NConnectSignerBtc } from '@/lib/bitcoin-signers';
import { signerWithNudge } from '@/lib/signerWithNudge';
export function useCurrentUser() {
const { nostr } = useNostr();
const { logins } = useNostrLogin();
const loginToUser = useCallback((login: NLoginType): NUser => {
let user: NUser;
let isBunkerConnected: (() => boolean) | undefined;
switch (login.type) {
case 'nsec': {
const sk = nip19.decode(login.data.nsec) as { type: 'nsec'; data: Uint8Array };
user = new NUser(login.type, login.pubkey, new NSecSignerBtc(sk.data));
break;
}
case 'bunker': {
const clientSk = nip19.decode(login.data.clientNsec) as { type: 'nsec'; data: Uint8Array };
const clientSigner = new NSecSigner(clientSk.data);
const bunkerRelays = login.data.relays;
user = new NUser(
login.type,
login.pubkey,
new NConnectSignerBtc({
relay: nostr.group(bunkerRelays),
pubkey: login.data.bunkerPubkey,
signer: clientSigner,
timeout: 60_000,
}),
);
// Called at nudge time to check whether any of the bunker's relay
// WebSockets are OPEN. Relay instances are shared with the main pool
// so pool.relays will contain them once they have been opened.
isBunkerConnected = () => bunkerRelays.some((url) => {
const relay = nostr.relay(url);
return relay instanceof NRelay1 && relay.socket.readyState === WebSocket.OPEN;
});
break;
}
case 'extension':
user = new NUser(login.type, login.pubkey, new NBrowserSignerBtc());
break;
// Other login types can be defined here
default:
throw new Error(`Unsupported login type: ${login.type}`);
}
return new NUser(user.method, user.pubkey, signerWithNudge(user.signer, isBunkerConnected));
}, [nostr]);
const users = useMemo(() => {
const users: NUser[] = [];
for (const login of logins) {
try {
const user = loginToUser(login);
users.push(user);
} catch (error) {
console.warn("Skipped invalid login", login.id, error);
}
}
return users;
}, [logins, loginToUser]);
const user = users[0] as NUser | undefined;
// The current user's kind 0 profile is served from useAuthor, which
// may resolve instantly if pre-cached by useFeed. Otherwise it fetches
// from relays in the background.
const author = useAuthor(user?.pubkey);
return {
user,
users,
...author.data,
isLoading: author.isLoading,
};
}