Files
boris/node_modules/applesauce-accounts/dist/manager.js
Gigi 5d53a827e0 feat: initialize markr nostr bookmark client
- Add project structure with TypeScript, React, and Vite
- Implement nostr authentication using browser extension (NIP-07)
- Add NIP-51 compliant bookmark fetching and display
- Create minimal UI with login and bookmark components
- Integrate applesauce-core and applesauce-react libraries
- Add responsive styling with dark/light mode support
- Include comprehensive README with setup instructions

This is a minimal MVP for a nostr bookmark client that allows users to
view their bookmarks according to NIP-51 specification.
2025-10-02 07:17:07 +02:00

159 lines
5.4 KiB
JavaScript

import { BehaviorSubject } from "rxjs";
import { ProxySigner } from "./proxy-signer.js";
export class AccountManager {
types = new Map();
active$ = new BehaviorSubject(undefined);
get active() {
return this.active$.value;
}
accounts$ = new BehaviorSubject([]);
get accounts() {
return this.accounts$.value;
}
/** Proxy signer for currently active account */
signer;
/** Disable request queueing for any accounts added to this manager */
disableQueue;
constructor() {
this.signer = new ProxySigner(this.active$, "No active account");
}
// Account type CRUD
/** Add account type class */
registerType(accountType) {
if (!accountType.type)
throw new Error(`Account class missing static "type" field`);
if (this.types.has(accountType.type))
throw new Error(`An account type of ${accountType.type} already exists`);
this.types.set(accountType.type, accountType);
}
/** Remove account type */
unregisterType(type) {
this.types.delete(type);
}
// Accounts CRUD
/** gets an account in the manager */
getAccount(id) {
if (typeof id === "string")
return this.accounts$.value.find((a) => a.id === id);
else if (this.accounts$.value.includes(id))
return id;
else
return undefined;
}
/** Return the first account for a pubkey */
getAccountForPubkey(pubkey) {
return Object.values(this.accounts$.value).find((account) => account.pubkey === pubkey);
}
/** Returns all accounts for a pubkey */
getAccountsForPubkey(pubkey) {
return Object.values(this.accounts$.value).filter((account) => account.pubkey === pubkey);
}
/** adds an account to the manager */
addAccount(account) {
if (this.getAccount(account.id))
return;
// copy the disableQueue flag only if its set
if (this.disableQueue !== undefined && account.disableQueue !== undefined) {
account.disableQueue = this.disableQueue;
}
this.accounts$.next([...this.accounts$.value, account]);
}
/** Removes an account from the manager */
removeAccount(account) {
const id = typeof account === "string" ? account : account.id;
this.accounts$.next(this.accounts$.value.filter((a) => a.id !== id));
// if the removed account was active, clear the active account
if (this.active$.value?.id === id)
this.active$.next(undefined);
}
/** Replaces an account with another */
replaceAccount(old, account) {
this.addAccount(account);
// if the old account was active, switch to the new one
const id = typeof account === "string" ? account : account.id;
if (this.active$.value?.id === id)
this.setActive(account);
this.removeAccount(old);
}
// Active account methods
/** Returns the currently active account */
getActive() {
return this.active$.value;
}
/** Sets the currently active account */
setActive(id) {
const account = this.getAccount(id);
if (!account)
throw new Error("Cant find account with that ID");
if (this.active$.value?.id !== account.id) {
this.active$.next(account);
}
}
/** Clears the currently active account */
clearActive() {
this.active$.next(undefined);
}
// Metadata CRUD
/** sets the metadata on an account */
setAccountMetadata(id, metadata) {
const account = this.getAccount(id);
if (!account)
throw new Error("Cant find account with that ID");
account.metadata = metadata;
}
/** sets the metadata on an account */
getAccountMetadata(id) {
const account = this.getAccount(id);
if (!account)
throw new Error("Cant find account with that ID");
return account.metadata;
}
/** Removes all metadata on the account */
clearAccountMetadata(id) {
const account = this.getAccount(id);
if (!account)
throw new Error("Cant find account with that ID");
account.metadata = undefined;
}
// Serialize / Deserialize
/** Returns an array of serialized accounts */
toJSON(quite = false) {
const accounts = [];
for (const account of this.accounts) {
try {
accounts.push(account.toJSON());
}
catch (error) {
if (!quite)
throw error;
}
}
return accounts;
}
/**
* Restores all accounts from an array of serialized accounts
* NOTE: this will clear all existing accounts
*/
fromJSON(accounts, quite = false) {
for (const json of accounts) {
try {
const AccountType = this.types.get(json.type);
if (!AccountType) {
if (!quite)
throw new Error(`Missing account type ${json.type}`);
else
continue;
}
const account = AccountType.fromJSON(json);
this.addAccount(account);
}
catch (error) {
if (!quite)
throw error;
else
console.log(`Failed to load account`, error);
}
}
}
}