@nostr-dev-kit/ndk-svelte
Version:
This package provides convenience functionalities to make usage of NDK with Svelte nicer.
196 lines (195 loc) • 5.84 kB
JavaScript
// src/index.ts
import NDK, {
NDKEvent,
NDKKind,
NDKRepost
} from "@nostr-dev-kit/ndk";
import { writable } from "svelte/store";
var NDKSvelte = class extends NDK {
createEventStore(filters) {
const store = writable([]);
return {
id: Math.random().toString(36).substring(7),
refCount: 0,
filters,
skipDeleted: true,
subscription: void 0,
eosed: false,
set: store.set,
update: store.update,
subscribe: store.subscribe,
unsubscribe: () => {
},
onEose: (_cb) => {
},
onEvent: (_cb) => {
},
startSubscription: () => {
throw new Error("not implemented");
},
ref: () => {
throw new Error("not implemented");
},
unref: () => {
throw new Error("not implemented");
},
empty: () => {
throw new Error("not implemented");
},
changeFilters: (_filters) => {
throw new Error("not implemented");
}
};
}
eventIsRepost(event) {
return [NDKKind.Repost, NDKKind.GenericRepost].includes(event.kind);
}
storeSubscribe(filters, opts, klass) {
let events = /* @__PURE__ */ new Map();
const store = this.createEventStore(Array.isArray(filters) ? filters : [filters]);
const autoStart = opts?.autoStart ?? true;
const relaySet = opts?.relaySet;
const skipDeleted = opts?.skipDeleted ?? true;
const deletedPRETimestamps = /* @__PURE__ */ new Map();
const getEventArrayFromMap = () => {
return Array.from(events.values());
};
const handleEventReposts = (event) => {
const _repostEvent = NDKRepost.from(event);
_repostEvent.ndk = this;
const addRepostToExistingEvent = (repostedEvent) => {
if (repostedEvent.repostedByEvents) {
repostedEvent.repostedByEvents.push(event);
} else {
repostedEvent.repostedByEvents = [event];
}
store.set(getEventArrayFromMap());
};
for (const repostedEventId of _repostEvent.repostedEventIds()) {
const repostedEvent = events.get(repostedEventId);
if (repostedEvent) {
addRepostToExistingEvent(repostedEvent);
} else {
_repostEvent.repostedEvents(klass, {
subId: "reposted-event-fetch",
groupable: true,
groupableDelay: 1500,
groupableDelayType: "at-least"
}).then((fetchedEvents) => {
for (const e of fetchedEvents) {
if (e instanceof NDKEvent) {
handleEvent(e);
}
}
});
}
}
};
const handleEvent = (event) => {
if (opts?.repostsFilters && this.eventIsRepost(event)) {
handleEventReposts(event);
return;
}
let e = event;
if (klass) {
const ev = klass.from(event);
if (!ev) return;
e = ev;
e.relay = event.relay;
}
e.ndk = this;
const dedupKey = event.deduplicationKey();
if (events.has(dedupKey)) {
const prevEvent = events.get(dedupKey);
if (prevEvent.created_at > event.created_at) return;
if (prevEvent.created_at === event.created_at) {
if (prevEvent.id === event.id) return;
console.warn("Received event with same created_at but different id", {
prevId: prevEvent.id,
newId: event.id,
prev: prevEvent.rawEvent(),
new: event.rawEvent()
});
}
}
if (skipDeleted && event.isParamReplaceable()) {
const currentDeletedTimestamp = deletedPRETimestamps.get(dedupKey);
if (currentDeletedTimestamp && currentDeletedTimestamp > event.created_at) return;
const isDeleted = event.hasTag("deleted");
if (isDeleted) {
deletedPRETimestamps.set(dedupKey, event.created_at);
return;
}
deletedPRETimestamps.delete(dedupKey);
}
events.set(dedupKey, e);
store.set(getEventArrayFromMap());
};
store.ref = () => {
store.refCount++;
if (store.refCount === 1) {
store.startSubscription();
}
return store.refCount;
};
store.unref = () => {
if (--store.refCount > 0) return store.refCount;
if (opts?.unrefUnsubscribeTimeout) {
setTimeout(() => {
if (store.refCount === 0) {
store.unsubscribe();
}
}, opts.unrefUnsubscribeTimeout);
} else {
store.unsubscribe();
}
return store.refCount;
};
store.empty = () => {
store.set([]);
events = /* @__PURE__ */ new Map();
store.unsubscribe();
};
store.changeFilters = (filters2) => {
store.filters = filters2;
store.empty();
if (store.refCount > 0) store.startSubscription();
};
store.startSubscription = () => {
if (!store.filters) {
throw new Error("no filters");
}
const filters2 = store.filters;
if (opts?.repostsFilters) {
filters2.push(...opts.repostsFilters);
}
store.subscription = this.subscribe(filters2, { ...opts, relaySet }, false);
store.subscription.on("event", (event, relay) => {
handleEvent(event);
if (opts?.onEvent) opts.onEvent(event, relay);
});
store.subscription.start();
store.unsubscribe = () => {
store.subscription?.stop();
store.subscription = void 0;
};
store.onEose = (cb) => {
store.subscription?.on("eose", () => {
store.eosed = true;
cb();
});
};
if (opts?.onEose) {
store.onEose(opts.onEose);
}
};
if (autoStart) {
store.startSubscription();
}
return store;
}
};
var index_default = NDKSvelte;
export {
index_default as default
};