chore: cleanup login state
This commit is contained in:
@ -37,6 +37,7 @@ export default function useLoginFeed() {
|
|||||||
}, [pubKey]);
|
}, [pubKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.debug("UserState: start init from LoginFeed", login.state.didInit);
|
||||||
login.state.init(publisher?.signer, system).catch(console.error);
|
login.state.init(publisher?.signer, system).catch(console.error);
|
||||||
}, [login, publisher, system]);
|
}, [login, publisher, system]);
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@ export interface LoginSession {
|
|||||||
*/
|
*/
|
||||||
publicKey?: HexKey;
|
publicKey?: HexKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login state for the current user
|
||||||
|
*/
|
||||||
state: UserState<SnortAppData>;
|
state: UserState<SnortAppData>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,7 +7,6 @@ import {
|
|||||||
EventPublisher,
|
EventPublisher,
|
||||||
HexKey,
|
HexKey,
|
||||||
KeyStorage,
|
KeyStorage,
|
||||||
NotEncrypted,
|
|
||||||
RelaySettings,
|
RelaySettings,
|
||||||
UserState,
|
UserState,
|
||||||
UserStateObject,
|
UserStateObject,
|
||||||
@ -63,6 +62,7 @@ const LoggedOut = {
|
|||||||
|
|
||||||
export class MultiAccountStore extends ExternalStore<LoginSession> {
|
export class MultiAccountStore extends ExternalStore<LoginSession> {
|
||||||
#activeAccount?: HexKey;
|
#activeAccount?: HexKey;
|
||||||
|
#saveDebounce?: ReturnType<typeof setTimeout>;
|
||||||
#accounts: Map<string, LoginSession> = new Map();
|
#accounts: Map<string, LoginSession> = new Map();
|
||||||
#publishers = new Map<string, EventPublisher>();
|
#publishers = new Map<string, EventPublisher>();
|
||||||
|
|
||||||
@ -109,6 +109,10 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
|||||||
);
|
);
|
||||||
stateClass.checkIsStandardList(EventKind.StorageServerList); // track nip96 list
|
stateClass.checkIsStandardList(EventKind.StorageServerList); // track nip96 list
|
||||||
stateClass.on("change", () => this.#save());
|
stateClass.on("change", () => this.#save());
|
||||||
|
if (v.state instanceof UserState) {
|
||||||
|
v.state.destroy();
|
||||||
|
}
|
||||||
|
console.debug("UserState assign = ", stateClass);
|
||||||
v.state = stateClass;
|
v.state = stateClass;
|
||||||
|
|
||||||
// always activate signer
|
// always activate signer
|
||||||
@ -117,7 +121,6 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
|||||||
this.#publishers.set(v.id, signer);
|
this.#publishers.set(v.id, signer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.#loadIrisKeyIfExists();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getSessions() {
|
getSessions() {
|
||||||
@ -191,8 +194,8 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
|||||||
stalker: stalker ?? false,
|
stalker: stalker ?? false,
|
||||||
} as LoginSession;
|
} as LoginSession;
|
||||||
|
|
||||||
newSession.state.checkIsStandardList(EventKind.StorageServerList); // track nip96 list
|
newSession.state!.checkIsStandardList(EventKind.StorageServerList); // track nip96 list
|
||||||
newSession.state.on("change", () => this.#save());
|
newSession.state!.on("change", () => this.#save());
|
||||||
const pub = createPublisher(newSession);
|
const pub = createPublisher(newSession);
|
||||||
if (pub) {
|
if (pub) {
|
||||||
this.#publishers.set(newSession.id, pub);
|
this.#publishers.set(newSession.id, pub);
|
||||||
@ -240,8 +243,8 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
|||||||
appdataId: "snort",
|
appdataId: "snort",
|
||||||
}),
|
}),
|
||||||
} as LoginSession;
|
} as LoginSession;
|
||||||
newSession.state.checkIsStandardList(EventKind.StorageServerList); // track nip96 list
|
newSession.state!.checkIsStandardList(EventKind.StorageServerList); // track nip96 list
|
||||||
newSession.state.on("change", () => this.#save());
|
newSession.state!.on("change", () => this.#save());
|
||||||
|
|
||||||
if ("nostr_os" in window && window?.nostr_os) {
|
if ("nostr_os" in window && window?.nostr_os) {
|
||||||
window?.nostr_os.saveKey(key.value);
|
window?.nostr_os.saveKey(key.value);
|
||||||
@ -280,22 +283,6 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
|||||||
return { ...s };
|
return { ...s };
|
||||||
}
|
}
|
||||||
|
|
||||||
#loadIrisKeyIfExists() {
|
|
||||||
try {
|
|
||||||
const irisKeyJSON = window.localStorage.getItem("iris.myKey");
|
|
||||||
if (irisKeyJSON) {
|
|
||||||
const irisKeyObj = JSON.parse(irisKeyJSON);
|
|
||||||
if (irisKeyObj.priv) {
|
|
||||||
const privateKey = new NotEncrypted(irisKeyObj.priv);
|
|
||||||
this.loginWithPrivateKey(privateKey);
|
|
||||||
window.localStorage.removeItem("iris.myKey");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to load iris key", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#migrate() {
|
#migrate() {
|
||||||
let didMigrate = false;
|
let didMigrate = false;
|
||||||
|
|
||||||
@ -367,6 +354,11 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#save() {
|
#save() {
|
||||||
|
if (this.#saveDebounce !== undefined) {
|
||||||
|
clearTimeout(this.#saveDebounce);
|
||||||
|
}
|
||||||
|
this.notifyChange();
|
||||||
|
this.#saveDebounce = setTimeout(() => {
|
||||||
if (!this.#activeAccount && this.#accounts.size > 0) {
|
if (!this.#activeAccount && this.#accounts.size > 0) {
|
||||||
this.#activeAccount = this.#accounts.keys().next().value;
|
this.#activeAccount = this.#accounts.keys().next().value;
|
||||||
}
|
}
|
||||||
@ -388,6 +380,7 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
|||||||
|
|
||||||
console.debug("Trying to save", toSave);
|
console.debug("Trying to save", toSave);
|
||||||
window.localStorage.setItem(AccountStoreKey, JSON.stringify(toSave));
|
window.localStorage.setItem(AccountStoreKey, JSON.stringify(toSave));
|
||||||
this.notifyChange();
|
this.#saveDebounce = undefined;
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,11 +238,13 @@ export function isOffline() {
|
|||||||
return !("navigator" in globalThis && globalThis.navigator.onLine);
|
return !("navigator" in globalThis && globalThis.navigator.onLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isHex(s: string) {
|
export function isHex(s?: string) {
|
||||||
|
if (!s) return false;
|
||||||
// 48-57 = 0-9
|
// 48-57 = 0-9
|
||||||
// 65-90 = A-Z
|
// 65-90 = A-Z
|
||||||
// 97-122 = a-z
|
// 97-122 = a-z
|
||||||
return [...s]
|
return s.length % 2 == 0 &&
|
||||||
|
[...s]
|
||||||
.map(v => v.charCodeAt(0))
|
.map(v => v.charCodeAt(0))
|
||||||
.every(v => (v >= 48 && v <= 57) || (v >= 65 && v <= 90) || v >= 97 || v <= 122);
|
.every(v => (v >= 48 && v <= 57) || (v >= 65 && v <= 90) || v >= 97 || v <= 122);
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ export class NostrLink implements ToNostrEventTag {
|
|||||||
const ifSetCheck = <T>(a: T | undefined, b: T) => {
|
const ifSetCheck = <T>(a: T | undefined, b: T) => {
|
||||||
return !Boolean(a) || a === b;
|
return !Boolean(a) || a === b;
|
||||||
};
|
};
|
||||||
return ifSetCheck(this.id, ev.id) && ifSetCheck(this.author, ev.pubkey) && ifSetCheck(this.kind, ev.kind);
|
return (EventExt.isReplaceable(ev.kind) || ifSetCheck(this.id, ev.id)) && ifSetCheck(this.author, ev.pubkey) && ifSetCheck(this.kind, ev.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,7 +2,7 @@ import { v4 as uuid } from "uuid";
|
|||||||
import { appendDedupe, dedupe, removeUndefined, sanitizeRelayUrl, unwrap } from "@snort/shared";
|
import { appendDedupe, dedupe, removeUndefined, sanitizeRelayUrl, unwrap } from "@snort/shared";
|
||||||
|
|
||||||
import EventKind from "./event-kind";
|
import EventKind from "./event-kind";
|
||||||
import { NostrLink, NostrPrefix, ToNostrEventTag } from ".";
|
import { EventExt, NostrLink, NostrPrefix, ToNostrEventTag } from ".";
|
||||||
import { ReqFilter, u256, HexKey, TaggedNostrEvent } from "./nostr";
|
import { ReqFilter, u256, HexKey, TaggedNostrEvent } from "./nostr";
|
||||||
import { RequestRouter } from "./request-router";
|
import { RequestRouter } from "./request-router";
|
||||||
|
|
||||||
@ -208,7 +208,8 @@ export class RequestFilterBuilder {
|
|||||||
.kinds([unwrap(link.kind)])
|
.kinds([unwrap(link.kind)])
|
||||||
.authors([unwrap(link.author)]);
|
.authors([unwrap(link.author)]);
|
||||||
} else {
|
} else {
|
||||||
if (link.id) {
|
// dont use id if link is replaceable kind
|
||||||
|
if (link.id && (link.kind === undefined || !EventExt.isReplaceable(link.kind))) {
|
||||||
this.ids([link.id]);
|
this.ids([link.id]);
|
||||||
}
|
}
|
||||||
if (link.author) {
|
if (link.author) {
|
||||||
|
@ -50,11 +50,11 @@ export interface UserStateEvents {
|
|||||||
*/
|
*/
|
||||||
export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
||||||
#log = debug("UserState");
|
#log = debug("UserState");
|
||||||
#profile: JsonEventSync<UserMetadata | undefined>; // kind 0
|
#profile?: JsonEventSync<UserMetadata | undefined>; // kind 0
|
||||||
#contacts: DiffSyncTags; // kind 3
|
#contacts?: DiffSyncTags; // kind 3
|
||||||
#relays: DiffSyncTags; // kind 10_003
|
#relays?: DiffSyncTags; // kind 10_003
|
||||||
#appdata?: JsonEventSync<TAppData>; // kind 30_0078
|
#appdata?: JsonEventSync<TAppData>; // kind 30_0078
|
||||||
#standardLists: Map<EventKind, DiffSyncTags>; // NIP-51 lists
|
#standardLists?: Map<EventKind, DiffSyncTags>; // NIP-51 lists
|
||||||
|
|
||||||
// init vars
|
// init vars
|
||||||
#signer?: EventSigner;
|
#signer?: EventSigner;
|
||||||
@ -72,15 +72,15 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.#stateObj = stateObj;
|
this.#stateObj = stateObj;
|
||||||
this.#standardLists = new Map();
|
this.#standardLists = pubkey ? new Map() : undefined;
|
||||||
|
|
||||||
this.#profile = new JsonEventSync<UserMetadata | undefined>(
|
this.#profile = pubkey ? new JsonEventSync<UserMetadata | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
new NostrLink(NostrPrefix.Event, "", EventKind.SetMetadata, pubkey),
|
new NostrLink(NostrPrefix.Event, pubkey, EventKind.SetMetadata, pubkey),
|
||||||
false,
|
false,
|
||||||
);
|
) : undefined;
|
||||||
this.#contacts = new DiffSyncTags(new NostrLink(NostrPrefix.Event, "", EventKind.ContactList, pubkey), false);
|
this.#contacts = pubkey ? new DiffSyncTags(new NostrLink(NostrPrefix.Event, pubkey, EventKind.ContactList, pubkey), false) : undefined;
|
||||||
this.#relays = new DiffSyncTags(new NostrLink(NostrPrefix.Event, "", EventKind.Relays, pubkey), false);
|
this.#relays = pubkey ? new DiffSyncTags(new NostrLink(NostrPrefix.Event, pubkey, EventKind.Relays, pubkey), false) : undefined;
|
||||||
if (options?.appdataId && options.initAppdata) {
|
if (options?.appdataId && options.initAppdata) {
|
||||||
const link = new NostrLink(NostrPrefix.Address, options.appdataId, EventKind.AppData, pubkey);
|
const link = new NostrLink(NostrPrefix.Address, options.appdataId, EventKind.AppData, pubkey);
|
||||||
this.#appdata = new JsonEventSync<TAppData>(options.initAppdata, link, options.encryptAppdata ?? false);
|
this.#appdata = new JsonEventSync<TAppData>(options.initAppdata, link, options.encryptAppdata ?? false);
|
||||||
@ -90,12 +90,21 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
// always track mute list
|
// always track mute list
|
||||||
this.checkIsStandardList(EventKind.MuteList);
|
this.checkIsStandardList(EventKind.MuteList);
|
||||||
|
|
||||||
this.#profile.on("change", () => this.emit("change", UserStateChangeType.Profile));
|
this.#profile?.on("change", () => this.emit("change", UserStateChangeType.Profile));
|
||||||
this.#contacts.on("change", () => this.emit("change", UserStateChangeType.Contacts));
|
this.#contacts?.on("change", () => this.emit("change", UserStateChangeType.Contacts));
|
||||||
this.#relays.on("change", () => this.emit("change", UserStateChangeType.Relays));
|
this.#relays?.on("change", () => this.emit("change", UserStateChangeType.Relays));
|
||||||
this.on("change", () => this.#version++);
|
this.on("change", () => this.#version++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get didInit() {
|
||||||
|
return this.#didInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.#log("Shutdown");
|
||||||
|
this.removeAllListeners();
|
||||||
|
}
|
||||||
|
|
||||||
async init(signer: EventSigner | undefined, system: SystemInterface) {
|
async init(signer: EventSigner | undefined, system: SystemInterface) {
|
||||||
if (this.#didInit) {
|
if (this.#didInit) {
|
||||||
return;
|
return;
|
||||||
@ -105,35 +114,37 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
this.#signer = signer;
|
this.#signer = signer;
|
||||||
this.#system = system;
|
this.#system = system;
|
||||||
const tasks = [
|
const tasks = [
|
||||||
this.#profile.sync(signer, system),
|
this.#profile?.sync(signer, system),
|
||||||
this.#contacts.sync(signer, system),
|
this.#contacts?.sync(signer, system),
|
||||||
this.#relays.sync(signer, system),
|
this.#relays?.sync(signer, system),
|
||||||
];
|
];
|
||||||
if (this.#appdata) {
|
if (this.#appdata) {
|
||||||
tasks.push(this.#appdata.sync(signer, system));
|
tasks.push(this.#appdata.sync(signer, system));
|
||||||
}
|
}
|
||||||
|
if (this.#standardLists) {
|
||||||
for (const list of this.#standardLists.values()) {
|
for (const list of this.#standardLists.values()) {
|
||||||
tasks.push(list.sync(signer, system));
|
tasks.push(list.sync(signer, system));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
await Promise.all(tasks);
|
await Promise.all(tasks);
|
||||||
this.#log(
|
this.#log(
|
||||||
"Init results: signer=%s, profile=%O, contacts=%O, relays=%O, appdata=%O, lists=%O",
|
"Init results: signer=%s, profile=%O, contacts=%O, relays=%O, appdata=%O, lists=%O",
|
||||||
signer ? "yes" : "no",
|
signer ? "yes" : "no",
|
||||||
this.#profile.json,
|
this.#profile?.json,
|
||||||
this.#contacts.value,
|
this.#contacts?.value,
|
||||||
this.#relays.value,
|
this.#relays?.value,
|
||||||
this.#appdata?.json,
|
this.#appdata?.json,
|
||||||
[...this.#standardLists.values()].map(a => [a.value, a.encryptedTags]),
|
[...(this.#standardLists?.values() ?? [])].map(a => [a.link.kind, a.value, a.encryptedTags]),
|
||||||
);
|
);
|
||||||
|
|
||||||
// update relay metadata with value from contact list if not found
|
// update relay metadata with value from contact list if not found
|
||||||
if (this.#relays.value === undefined && this.#contacts.value?.content !== undefined && signer) {
|
if (this.#relays?.value === undefined && this.#contacts?.value?.content !== undefined && signer) {
|
||||||
this.#log("Saving relays to NIP-65 relay list using %O", this.relays);
|
this.#log("Saving relays to NIP-65 relay list using %O", this.relays);
|
||||||
for (const r of this.relays ?? []) {
|
for (const r of this.relays ?? []) {
|
||||||
await this.addRelay(r.url, r.settings, false);
|
await this.addRelay(r.url, r.settings, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.#relays.persist(signer, system);
|
await this.#relays?.persist(signer, system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,16 +160,16 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
* Users profile
|
* Users profile
|
||||||
*/
|
*/
|
||||||
get profile() {
|
get profile() {
|
||||||
return this.#profile.json ?? this.#stateObj?.profile;
|
return this.#profile?.json ?? this.#stateObj?.profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Users configured relays
|
* Users configured relays
|
||||||
*/
|
*/
|
||||||
get relays() {
|
get relays() {
|
||||||
if (this.#relays.value) {
|
if (this.#relays?.value) {
|
||||||
return parseRelayTags(this.#relays.tags);
|
return parseRelayTags(this.#relays.tags);
|
||||||
} else if (this.#contacts.value) {
|
} else if (this.#contacts?.value) {
|
||||||
return parseRelaysFromKind(this.#contacts.value);
|
return parseRelaysFromKind(this.#contacts.value);
|
||||||
} else {
|
} else {
|
||||||
return this.#stateObj?.relays;
|
return this.#stateObj?.relays;
|
||||||
@ -169,7 +180,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
* Followed pubkeys
|
* Followed pubkeys
|
||||||
*/
|
*/
|
||||||
get follows() {
|
get follows() {
|
||||||
if (this.#contacts.value) {
|
if (this.#contacts?.value) {
|
||||||
const pTags = this.#contacts.tags.filter(a => a[0] === "p" && a[1].length === 64).map(a => a[1]) ?? [];
|
const pTags = this.#contacts.tags.filter(a => a[0] === "p" && a[1].length === 64).map(a => a[1]) ?? [];
|
||||||
return dedupe(pTags);
|
return dedupe(pTags);
|
||||||
} else {
|
} else {
|
||||||
@ -188,7 +199,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
* Get the standard mute list
|
* Get the standard mute list
|
||||||
*/
|
*/
|
||||||
get muted() {
|
get muted() {
|
||||||
const list = this.#standardLists.get(EventKind.MuteList);
|
const list = this.#standardLists?.get(EventKind.MuteList);
|
||||||
if (list) {
|
if (list) {
|
||||||
return NostrLink.fromAllTags(list.encryptedTags);
|
return NostrLink.fromAllTags(list.encryptedTags);
|
||||||
}
|
}
|
||||||
@ -202,12 +213,12 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tag = link.toEventTag();
|
const tag = link.toEventTag();
|
||||||
if (tag) {
|
if (tag && this.#contacts) {
|
||||||
this.#contacts.add(tag);
|
this.#contacts.add(tag);
|
||||||
if (autoCommit) {
|
if (autoCommit) {
|
||||||
await this.saveContacts();
|
await this.saveContacts();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!tag) {
|
||||||
throw new Error("Invalid link");
|
throw new Error("Invalid link");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,12 +230,12 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tag = link.toEventTag();
|
const tag = link.toEventTag();
|
||||||
if (tag) {
|
if (tag && this.#contacts) {
|
||||||
this.#contacts.remove(tag);
|
this.#contacts.remove(tag);
|
||||||
if (autoCommit) {
|
if (autoCommit) {
|
||||||
await this.saveContacts();
|
await this.saveContacts();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!tag) {
|
||||||
throw new Error("Invalid link");
|
throw new Error("Invalid link");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,12 +246,14 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
throw new Error("Cannot follow this type of link");
|
throw new Error("Cannot follow this type of link");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.#contacts) {
|
||||||
const tags = removeUndefined(links.map(link => link.toEventTag()));
|
const tags = removeUndefined(links.map(link => link.toEventTag()));
|
||||||
this.#contacts.replace(tags);
|
this.#contacts.replace(tags);
|
||||||
if (autoCommit) {
|
if (autoCommit) {
|
||||||
await this.saveContacts();
|
await this.saveContacts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manually save contact list changes
|
* Manually save contact list changes
|
||||||
@ -250,7 +263,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
async saveContacts() {
|
async saveContacts() {
|
||||||
this.#checkInit();
|
this.#checkInit();
|
||||||
const content = JSON.stringify(this.#relaysObject());
|
const content = JSON.stringify(this.#relaysObject());
|
||||||
await this.#contacts.persist(this.#signer!, this.#system!, content);
|
await this.#contacts?.persist(this.#signer!, this.#system!, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addRelay(addr: string, settings: RelaySettings, autoCommit = false) {
|
async addRelay(addr: string, settings: RelaySettings, autoCommit = false) {
|
||||||
@ -260,12 +273,12 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
url: addr,
|
url: addr,
|
||||||
settings,
|
settings,
|
||||||
});
|
});
|
||||||
if (tag) {
|
if (tag && this.#relays) {
|
||||||
this.#relays.add(tag);
|
this.#relays.add(tag);
|
||||||
if (autoCommit) {
|
if (autoCommit) {
|
||||||
await this.saveRelays();
|
await this.saveRelays();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!tag) {
|
||||||
throw new Error("Invalid relay options");
|
throw new Error("Invalid relay options");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,12 +287,12 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
this.#checkInit();
|
this.#checkInit();
|
||||||
|
|
||||||
const url = sanitizeRelayUrl(addr);
|
const url = sanitizeRelayUrl(addr);
|
||||||
if (url) {
|
if (url && this.#relays) {
|
||||||
this.#relays.remove(["r", url]);
|
this.#relays.remove(["r", url]);
|
||||||
if (autoCommit) {
|
if (autoCommit) {
|
||||||
await this.saveRelays();
|
await this.saveRelays();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!url) {
|
||||||
throw new Error("Invalid relay options");
|
throw new Error("Invalid relay options");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,12 +305,12 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
settings,
|
settings,
|
||||||
});
|
});
|
||||||
const url = sanitizeRelayUrl(addr);
|
const url = sanitizeRelayUrl(addr);
|
||||||
if (url && tag) {
|
if (url && tag && this.#relays) {
|
||||||
this.#relays.update(tag);
|
this.#relays.update(tag);
|
||||||
if (autoCommit) {
|
if (autoCommit) {
|
||||||
await this.saveRelays();
|
await this.saveRelays();
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!url && !tag) {
|
||||||
throw new Error("Invalid relay options");
|
throw new Error("Invalid relay options");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,7 +322,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
*/
|
*/
|
||||||
async saveRelays() {
|
async saveRelays() {
|
||||||
this.#checkInit();
|
this.#checkInit();
|
||||||
await this.#relays.persist(this.#signer!, this.#system!);
|
await this.#relays?.persist(this.#signer!, this.#system!);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setAppData(data: TAppData) {
|
async setAppData(data: TAppData) {
|
||||||
@ -336,7 +349,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
) {
|
) {
|
||||||
this.checkIsStandardList(kind);
|
this.checkIsStandardList(kind);
|
||||||
this.#checkInit();
|
this.#checkInit();
|
||||||
const list = this.#standardLists.get(kind);
|
const list = this.#standardLists?.get(kind);
|
||||||
const tags = removeUndefined(Array.isArray(links) ? links.map(a => a.toEventTag()) : [links.toEventTag()]);
|
const tags = removeUndefined(Array.isArray(links) ? links.map(a => a.toEventTag()) : [links.toEventTag()]);
|
||||||
if (list && tags.length > 0) {
|
if (list && tags.length > 0) {
|
||||||
list.add(tags, encrypted);
|
list.add(tags, encrypted);
|
||||||
@ -361,7 +374,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
) {
|
) {
|
||||||
this.checkIsStandardList(kind);
|
this.checkIsStandardList(kind);
|
||||||
this.#checkInit();
|
this.#checkInit();
|
||||||
const list = this.#standardLists.get(kind);
|
const list = this.#standardLists?.get(kind);
|
||||||
const tags = removeUndefined(Array.isArray(links) ? links.map(a => a.toEventTag()) : [links.toEventTag()]);
|
const tags = removeUndefined(Array.isArray(links) ? links.map(a => a.toEventTag()) : [links.toEventTag()]);
|
||||||
if (list && tags.length > 0) {
|
if (list && tags.length > 0) {
|
||||||
list.remove(tags, encrypted);
|
list.remove(tags, encrypted);
|
||||||
@ -377,7 +390,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
* used with `autocommit = false`
|
* used with `autocommit = false`
|
||||||
*/
|
*/
|
||||||
async saveList(kind: EventKind, content?: string) {
|
async saveList(kind: EventKind, content?: string) {
|
||||||
const list = this.#standardLists.get(kind);
|
const list = this.#standardLists?.get(kind);
|
||||||
await list?.persist(this.#signer!, this.#system!, content);
|
await list?.persist(this.#signer!, this.#system!, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +403,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isOnList(kind: EventKind, link: ToNostrEventTag) {
|
isOnList(kind: EventKind, link: ToNostrEventTag) {
|
||||||
const list = this.#standardLists.get(kind);
|
const list = this.#standardLists?.get(kind);
|
||||||
const tag = link.toEventTag();
|
const tag = link.toEventTag();
|
||||||
if (list && tag) {
|
if (list && tag) {
|
||||||
return list.tags.some(a => a[0] === tag[0] && a[1] === tag[1]);
|
return list.tags.some(a => a[0] === tag[0] && a[1] === tag[1]);
|
||||||
@ -399,7 +412,7 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getList(kind: EventKind): Array<ToNostrEventTag> {
|
getList(kind: EventKind): Array<ToNostrEventTag> {
|
||||||
const list = this.#standardLists.get(kind);
|
const list = this.#standardLists?.get(kind);
|
||||||
return NostrLink.fromAllTags(list?.tags ?? []);
|
return NostrLink.fromAllTags(list?.tags ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,12 +427,12 @@ export class UserState<TAppData> extends EventEmitter<UserStateEvents> {
|
|||||||
|
|
||||||
checkIsStandardList(kind: EventKind) {
|
checkIsStandardList(kind: EventKind) {
|
||||||
if (!(kind >= 10_000 && kind < 20_000)) {
|
if (!(kind >= 10_000 && kind < 20_000)) {
|
||||||
throw new Error("Not a standar list");
|
throw new Error("Not a standard list");
|
||||||
}
|
}
|
||||||
if (!this.#standardLists.has(kind)) {
|
if (this.#standardLists?.has(kind) === false) {
|
||||||
const list = new DiffSyncTags(new NostrLink(NostrPrefix.Event, "", kind, this.pubkey), true);
|
const list = new DiffSyncTags(new NostrLink(NostrPrefix.Event, this.pubkey, kind, this.pubkey), true);
|
||||||
list.on("change", () => this.emit("change", UserStateChangeType.GenericList));
|
list.on("change", () => this.emit("change", UserStateChangeType.GenericList));
|
||||||
this.#standardLists.set(kind, list);
|
this.#standardLists?.set(kind, list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user