From 5a63273b9d3b2fd436e9f3f5d3319ad215671b37 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Tue, 13 Aug 2024 09:30:55 -0700 Subject: [PATCH] Remove generics for event type --- package-lock.json | 27 +++++++++++++++++--- packages/content/package.json | 2 +- packages/domain/package.json | 2 +- packages/domain/src/handler.ts | 16 ++++++------ packages/domain/src/list.ts | 18 +++++++------- packages/domain/src/profile.ts | 26 ++++++++++---------- packages/domain/src/util.ts | 23 +++++++---------- packages/dvm/package.json | 2 +- packages/dvm/src/handler.ts | 10 ++++---- packages/feeds/src/compiler.ts | 16 ++++++------ packages/feeds/src/core.ts | 16 ++++++------ packages/feeds/src/loader.ts | 36 +++++++++++++-------------- packages/net/src/target/Local.ts | 5 ++-- packages/store/src/index.ts | 28 ++++++++++----------- packages/util/package.json | 2 +- packages/util/src/Events.ts | 9 +++++-- packages/util/src/Relay.ts | 10 ++++---- packages/util/src/Repository.ts | 42 ++++++++++++++++---------------- 18 files changed, 154 insertions(+), 136 deletions(-) diff --git a/package-lock.json b/package-lock.json index 26b0ed6..3690ce7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -601,6 +601,10 @@ "resolved": "packages/content", "link": true }, + "node_modules/@welshman/domain": { + "resolved": "packages/domain", + "link": true + }, "node_modules/@welshman/dvm": { "resolved": "packages/dvm", "link": true @@ -3269,11 +3273,26 @@ }, "packages/content": { "name": "@welshman/content", - "version": "0.0.6", + "version": "0.0.7", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.0.2", - "nostr-tools": "^2.7.0" + "nostr-tools": "^2.7.2" + }, + "devDependencies": { + "gts": "^5.0.1", + "tsc-multi": "^1.1.0", + "typescript": "~5.1.6" + } + }, + "packages/domain": { + "name": "@welshman/domain", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "@welshman/lib": "0.0.14", + "@welshman/util": "0.0.25", + "nostr-tools": "^2.7.2" }, "devDependencies": { "gts": "^5.0.1", @@ -3289,7 +3308,7 @@ "@welshman/lib": "0.0.14", "@welshman/net": "0.0.18", "@welshman/util": "0.0.25", - "nostr-tools": "^2.7.0" + "nostr-tools": "^2.7.2" }, "devDependencies": { "gts": "^5.0.1", @@ -3408,7 +3427,7 @@ "license": "MIT", "dependencies": { "@welshman/lib": "0.0.14", - "nostr-tools": "^2.3.2" + "nostr-tools": "^2.7.2" }, "devDependencies": { "gts": "^5.0.1", diff --git a/packages/content/package.json b/packages/content/package.json index 9907ea7..d33951a 100644 --- a/packages/content/package.json +++ b/packages/content/package.json @@ -32,6 +32,6 @@ }, "dependencies": { "@braintree/sanitize-url": "^7.0.2", - "nostr-tools": "^2.7.0" + "nostr-tools": "^2.7.2" } } diff --git a/packages/domain/package.json b/packages/domain/package.json index 9093fbd..7674463 100644 --- a/packages/domain/package.json +++ b/packages/domain/package.json @@ -31,7 +31,7 @@ "typescript": "~5.1.6" }, "dependencies": { - "nostr-tools": "^2.3.2", + "nostr-tools": "^2.7.2", "@welshman/lib": "0.0.14", "@welshman/util": "0.0.25" } diff --git a/packages/domain/src/handler.ts b/packages/domain/src/handler.ts index 87f41cf..4f11a41 100644 --- a/packages/domain/src/handler.ts +++ b/packages/domain/src/handler.ts @@ -1,20 +1,20 @@ import {fromPairs, parseJson} from "@welshman/lib" import {getAddress, Tags} from "@welshman/util" -import type {TrustedEvent} from "@welshman/util" +import type {ExtensibleTrustedEvent} from "@welshman/util" -export type Handler = { +export type Handler = { kind: number name: string about: string image: string identifier: string - event: E + event: ExtensibleTrustedEvent website?: string lud16?: string nip05?: string } -export const readHandlers = (event: E) => { +export const readHandlers = (event: ExtensibleTrustedEvent) => { const {d: identifier} = fromPairs(event.tags) const meta = parseJson(event.content) const normalizedMeta = { @@ -35,14 +35,14 @@ export const readHandlers = (event: E) => { .whereKey("k") .values() .valueOf() - .map(kind => ({...normalizedMeta, kind: parseInt(kind), identifier, event})) as Handler[] + .map(kind => ({...normalizedMeta, kind: parseInt(kind), identifier, event})) as Handler[] } -export const getHandlerKey = (handler: Handler) => `${handler.kind}:${getAddress(handler.event)}` +export const getHandlerKey = (handler: Handler) => `${handler.kind}:${getAddress(handler.event)}` -export const displayHandler = (handler?: Handler, fallback = "") => handler?.name || fallback +export const displayHandler = (handler?: Handler, fallback = "") => handler?.name || fallback -export const getHandlerAddress = (event: E) => { +export const getHandlerAddress = (event: ExtensibleTrustedEvent) => { const tags = Tags.fromEvent(event).whereKey("a") const tag = tags.filter(t => t.last() === "web").first() || tags.first() diff --git a/packages/domain/src/list.ts b/packages/domain/src/list.ts index f58367a..20ddd46 100644 --- a/packages/domain/src/list.ts +++ b/packages/domain/src/list.ts @@ -1,22 +1,22 @@ import {parseJson} from "@welshman/lib" -import {Address, isShareableRelayUrl, TrustedEvent} from "@welshman/util" +import {Address, isShareableRelayUrl} from "@welshman/util" import {Encryptable, DecryptedEvent} from "./util" export type ListParams = { kind: number } -export type List = ListParams & { +export type List = ListParams & { publicTags: string[][] privateTags: string[][] - event?: DecryptedEvent + event?: DecryptedEvent } -export type PublishedList = Omit, "event"> & { - event: DecryptedEvent +export type PublishedList = Omit & { + event: DecryptedEvent } -export const makeList = (list: ListParams & Partial>): List => +export const makeList = (list: ListParams & Partial): List => ({publicTags: [], privateTags: [], ...list}) const isValidTag = (tag: string[]) => { @@ -30,7 +30,7 @@ const isValidTag = (tag: string[]) => { return true } -export const readList = (event: DecryptedEvent): PublishedList => { +export const readList = (event: DecryptedEvent): PublishedList => { const getTags = (tags: string[][]) => (Array.isArray(tags) ? tags.filter(isValidTag) : []) const privateTags = getTags(parseJson(event.plaintext?.content)) const publicTags = getTags(event.tags) @@ -38,8 +38,8 @@ export const readList = (event: DecryptedEvent): Publ return {event, kind: event.kind, publicTags, privateTags} } -export const createList = ({kind, publicTags = [], privateTags = []}: List) => +export const createList = ({kind, publicTags = [], privateTags = []}: List) => new Encryptable({kind, tags: publicTags}, {content: JSON.stringify(privateTags)}) -export const editList = ({kind, publicTags = [], privateTags = []}: PublishedList) => +export const editList = ({kind, publicTags = [], privateTags = []}: PublishedList) => new Encryptable({kind, tags: publicTags}, {content: JSON.stringify(privateTags)}) diff --git a/packages/domain/src/profile.ts b/packages/domain/src/profile.ts index 1ec26e2..cebd28a 100644 --- a/packages/domain/src/profile.ts +++ b/packages/domain/src/profile.ts @@ -1,8 +1,8 @@ import {nip19} from "nostr-tools" import {ellipsize, parseJson} from "@welshman/lib" -import {PROFILE, TrustedEvent} from "@welshman/util" +import {PROFILE, ExtensibleTrustedEvent} from "@welshman/util" -export type Profile = { +export type Profile = { name?: string nip05?: string lud06?: string @@ -12,17 +12,17 @@ export type Profile = { picture?: string website?: string display_name?: string - event?: E + event?: ExtensibleTrustedEvent } -export type PublishedProfile = Omit, "event"> & { - event: E +export type PublishedProfile = Omit & { + event: ExtensibleTrustedEvent } -export const isPublishedProfile = (profile: Profile): profile is PublishedProfile => +export const isPublishedProfile = (profile: Profile): profile is PublishedProfile => Boolean(profile.event) -export const makeProfile = (profile: Partial> = {}): Profile => ({ +export const makeProfile = (profile: Partial = {}): Profile => ({ name: "", nip05: "", lud06: "", @@ -35,18 +35,18 @@ export const makeProfile = (profile: Partial> ...profile, }) -export const readProfile = (event: E) => { +export const readProfile = (event: ExtensibleTrustedEvent) => { const profile = parseJson(event.content) || {} - return {...profile, event} as PublishedProfile + return {...profile, event} as PublishedProfile } -export const createProfile = ({event, ...profile}: Profile) => ({ +export const createProfile = ({event, ...profile}: Profile) => ({ kind: PROFILE, content: JSON.stringify(profile), }) -export const editProfile = ({event, ...profile}: PublishedProfile) => ({ +export const editProfile = ({event, ...profile}: PublishedProfile) => ({ kind: PROFILE, content: JSON.stringify(profile), tags: event.tags, @@ -58,7 +58,7 @@ export const displayPubkey = (pubkey: string) => { return d.slice(0, 8) + "…" + d.slice(-5) } -export const displayProfile = (profile?: Profile, fallback = "") => { +export const displayProfile = (profile?: Profile, fallback = "") => { const {display_name, name, event} = profile || {} if (name) return ellipsize(name, 60) @@ -68,4 +68,4 @@ export const displayProfile = (profile?: Profile, fal return fallback } -export const profileHasName = (profile?: Profile) => Boolean(profile?.name || profile?.display_name) +export const profileHasName = (profile?: Profile) => Boolean(profile?.name || profile?.display_name) diff --git a/packages/domain/src/util.ts b/packages/domain/src/util.ts index 305c68f..a8e8a6e 100644 --- a/packages/domain/src/util.ts +++ b/packages/domain/src/util.ts @@ -1,21 +1,16 @@ -import type {TrustedEvent} from "@welshman/util" +import type {EventContent, ExtensibleTrustedEvent} from "@welshman/util" export type Encrypt = (x: string) => Promise -export type EventContent = { - content?: string - tags?: string[][] +export type DecryptedEvent = ExtensibleTrustedEvent & { + plaintext: Partial } -export type DecryptedEvent = E & { - plaintext: EventContent -} +export const asDecryptedEvent = (event: ExtensibleTrustedEvent, plaintext: Partial) => + ({...event, plaintext}) as DecryptedEvent -export const asDecryptedEvent = (event: E, plaintext: EventContent) => - ({...event, plaintext}) as DecryptedEvent - -export class Encryptable { - constructor(readonly event: Partial, readonly updates: EventContent) {} +export class Encryptable> { + constructor(readonly event: E, readonly updates: E) {} async reconcile(encrypt: Encrypt) { const encryptContent = () => { @@ -41,8 +36,8 @@ export class Encryptable { // Updates are optional. If not provided, fall back to the event's content and tags. return { ...this.event, - tags: tags || this.event.tags, - content: content || this.event.content, + tags: tags || this.event.tags || [], + content: content || this.event.content || "", } } } diff --git a/packages/dvm/package.json b/packages/dvm/package.json index ab90c86..0d2ab48 100644 --- a/packages/dvm/package.json +++ b/packages/dvm/package.json @@ -34,6 +34,6 @@ "@welshman/lib": "0.0.14", "@welshman/net": "0.0.18", "@welshman/util": "0.0.25", - "nostr-tools": "^2.7.0" + "nostr-tools": "^2.7.2" } } diff --git a/packages/dvm/src/handler.ts b/packages/dvm/src/handler.ts index d5c2a76..709f3ad 100644 --- a/packages/dvm/src/handler.ts +++ b/packages/dvm/src/handler.ts @@ -1,12 +1,12 @@ import {hexToBytes} from '@noble/hashes/utils' import {getPublicKey, finalizeEvent} from 'nostr-tools' import {now} from '@welshman/lib' -import type {TrustedEvent, EventTemplate, Filter} from '@welshman/util' +import type {ExtensibleTrustedEvent, EventTemplate, Filter} from '@welshman/util' import {subscribe, publish} from '@welshman/net' export type DVMHandler = { stop?: () => void - handleEvent: (e: TrustedEvent) => AsyncGenerator + handleEvent: (e: ExtensibleTrustedEvent) => AsyncGenerator } export type CreateDVMHandler = (dvm: DVM) => DVMHandler @@ -49,7 +49,7 @@ export class DVM { const filters = [filter] const sub = subscribe({relays, filters}) - sub.emitter.on('event', (url: string, e: TrustedEvent) => this.onEvent(e)) + sub.emitter.on('event', (url: string, e: ExtensibleTrustedEvent) => this.onEvent(e)) sub.emitter.on('complete', () => resolve()) }) } @@ -63,7 +63,7 @@ export class DVM { this.active = false } - async onEvent(request: TrustedEvent) { + async onEvent(request: ExtensibleTrustedEvent) { console.log(request) const {expireAfter = 60 * 60} = this.opts @@ -87,7 +87,7 @@ export class DVM { if (event.kind !== 7000) { event.tags.push(['request', JSON.stringify(request)]) - const inputTag = request.tags.find(t => t[0] === 'i') + const inputTag = request.tags.find((t: string[]) => t[0] === 'i') if (inputTag) { event.tags.push(inputTag) diff --git a/packages/feeds/src/compiler.ts b/packages/feeds/src/compiler.ts index 5e1450e..3650e19 100644 --- a/packages/feeds/src/compiler.ts +++ b/packages/feeds/src/compiler.ts @@ -1,12 +1,12 @@ import {uniq, identity, flatten, pushToMapKey, intersection, tryCatch, now} from '@welshman/lib' -import type {TrustedEvent, Filter} from '@welshman/util' +import type {ExtensibleTrustedEvent, Filter} from '@welshman/util' import {Tags, intersectFilters, matchFilter, getAddress, getIdFilters, unionFilters} from '@welshman/util' import type {CreatedAtItem, RequestItem, ListItem, LabelItem, WOTItem, DVMItem, Scope, Feed, FeedOptions} from './core' import {getFeedArgs, feedsFromTags} from './utils' import {FeedType} from './core' -export class FeedCompiler { - constructor(readonly options: FeedOptions) {} +export class FeedCompiler { + constructor(readonly options: FeedOptions) {} canCompile(feed: Feed): boolean { switch(feed[0]) { @@ -109,7 +109,7 @@ export class FeedCompiler { items.map(({mappings, ...request}) => this.options.requestDVM({ ...request, - onEvent: async (e: E) => { + onEvent: async (e: ExtensibleTrustedEvent) => { const tags = Tags.wrap(await tryCatch(() => JSON.parse(e.content)) || []) for (const feed of feedsFromTags(tags, mappings)) { @@ -215,11 +215,11 @@ export class FeedCompiler { async _compileLists(listItems: ListItem[]): Promise { const addresses = uniq(listItems.flatMap(({addresses}) => addresses)) - const eventsByAddress = new Map() + const eventsByAddress = new Map() await this.options.request({ filters: getIdFilters(addresses), - onEvent: (e: E) => eventsByAddress.set(getAddress(e), e), + onEvent: (e: ExtensibleTrustedEvent) => eventsByAddress.set(getAddress(e), e), }) const feeds = flatten( @@ -246,14 +246,14 @@ export class FeedCompiler { } async _compileLabels(labelItems: LabelItem[]): Promise { - const events: E[] = [] + const events: ExtensibleTrustedEvent[] = [] await Promise.all( labelItems.map(({mappings, relays, ...filter}) => this.options.request({ relays, filters: [{kinds: [1985], ...filter}], - onEvent: (e: E) => events.push(e), + onEvent: (e: ExtensibleTrustedEvent) => events.push(e), }) ) ) diff --git a/packages/feeds/src/core.ts b/packages/feeds/src/core.ts index c5ec273..3558b72 100644 --- a/packages/feeds/src/core.ts +++ b/packages/feeds/src/core.ts @@ -1,4 +1,4 @@ -import type {Filter} from '@welshman/util' +import type {ExtensibleTrustedEvent, Filter} from '@welshman/util' export enum FeedType { Address = "address", @@ -109,8 +109,8 @@ export type RequestItem = { filters?: Filter[] } -export type RequestOpts = RequestItem & { - onEvent: (event: E) => void +export type RequestOpts = RequestItem & { + onEvent: (event: ExtensibleTrustedEvent) => void } export type DVMRequest = { @@ -119,13 +119,13 @@ export type DVMRequest = { relays?: string[], } -export type DVMOpts = DVMRequest & { - onEvent: (event: E) => void +export type DVMOpts = DVMRequest & { + onEvent: (event: ExtensibleTrustedEvent) => void } -export type FeedOptions = { - request: (opts: RequestOpts) => Promise - requestDVM: (opts: DVMOpts) => Promise +export type FeedOptions = { + request: (opts: RequestOpts) => Promise + requestDVM: (opts: DVMOpts) => Promise getPubkeysForScope: (scope: Scope) => string[] getPubkeysForWOTRange: (minWOT: number, maxWOT: number) => string[] } diff --git a/packages/feeds/src/loader.ts b/packages/feeds/src/loader.ts index 576d804..5e8a19e 100644 --- a/packages/feeds/src/loader.ts +++ b/packages/feeds/src/loader.ts @@ -1,26 +1,26 @@ import {inc, max, min, now} from '@welshman/lib' -import type {TrustedEvent, Filter} from '@welshman/util' +import type {ExtensibleTrustedEvent, Filter} from '@welshman/util' import {EPOCH, trimFilters, guessFilterDelta} from '@welshman/util' import type {Feed, RequestItem, FeedOptions} from './core' import {FeedType} from './core' import {FeedCompiler} from './compiler' -export type LoadOpts = { - onEvent?: (event: E) => void +export type LoadOpts = { + onEvent?: (event: ExtensibleTrustedEvent) => void onExhausted?: () => void useWindowing?: boolean } export type Loader = (limit: number) => Promise -export class FeedLoader { - compiler: FeedCompiler +export class FeedLoader { + compiler: FeedCompiler - constructor(readonly options: FeedOptions) { + constructor(readonly options: FeedOptions) { this.compiler = new FeedCompiler(options) } - async getLoader([type, ...feed]: Feed, loadOpts: LoadOpts) { + async getLoader([type, ...feed]: Feed, loadOpts: LoadOpts) { if (this.compiler.canCompile([type, ...feed] as Feed)) { return this.getRequestsLoader(await this.compiler.compile([type, ...feed] as Feed), loadOpts) } @@ -37,7 +37,7 @@ export class FeedLoader { } } - async getRequestsLoader(requests: RequestItem[], loadOpts: LoadOpts) { + async getRequestsLoader(requests: RequestItem[], loadOpts: LoadOpts) { const seen = new Set() const exhausted = new Set() const loaders = await Promise.all( @@ -64,7 +64,7 @@ export class FeedLoader { } } - async _getRequestLoader({relays, filters}: RequestItem, {useWindowing = true, onEvent, onExhausted}: LoadOpts) { + async _getRequestLoader({relays, filters}: RequestItem, {useWindowing = true, onEvent, onExhausted}: LoadOpts) { // Make sure we have some kind of filter to send if we've been given an empty one, as happens with relay feeds if (!filters || filters.length === 0) { filters = [{}] @@ -101,7 +101,7 @@ export class FeedLoader { await this.options.request({ relays, filters: trimFilters(requestFilters), - onEvent: (event: E) => { + onEvent: (event: ExtensibleTrustedEvent) => { count += 1 until = Math.min(until, event.created_at - 1) onEvent?.(event) @@ -127,17 +127,17 @@ export class FeedLoader { } } - async _getDifferenceLoader(feeds: Feed[], {onEvent, onExhausted}: LoadOpts) { + async _getDifferenceLoader(feeds: Feed[], {onEvent, onExhausted}: LoadOpts) { const exhausted = new Set() const skip = new Set() - const events: E[] = [] + const events: ExtensibleTrustedEvent[] = [] const seen = new Set() const loaders = await Promise.all( feeds.map((feed: Feed, i: number) => this.getLoader(feed, { onExhausted: () => exhausted.add(i), - onEvent: (event: E) => { + onEvent: (event: ExtensibleTrustedEvent) => { if (i === 0) { events.push(event) } else { @@ -172,17 +172,17 @@ export class FeedLoader { } } - async _getIntersectionLoader(feeds: Feed[], {onEvent, onExhausted}: LoadOpts) { + async _getIntersectionLoader(feeds: Feed[], {onEvent, onExhausted}: LoadOpts) { const exhausted = new Set() const counts = new Map() - const events: E[] = [] + const events: ExtensibleTrustedEvent[] = [] const seen = new Set() const loaders = await Promise.all( feeds.map((feed: Feed, i: number) => this.getLoader(feed, { onExhausted: () => exhausted.add(i), - onEvent: (event: E) => { + onEvent: (event: ExtensibleTrustedEvent) => { events.push(event) counts.set(event.id, inc(counts.get(event.id))) }, @@ -214,7 +214,7 @@ export class FeedLoader { } } - async _getUnionLoader(feeds: Feed[], {onEvent, onExhausted}: LoadOpts) { + async _getUnionLoader(feeds: Feed[], {onEvent, onExhausted}: LoadOpts) { const exhausted = new Set() const seen = new Set() @@ -222,7 +222,7 @@ export class FeedLoader { feeds.map((feed: Feed, i: number) => this.getLoader(feed, { onExhausted: () => exhausted.add(i), - onEvent: (event: E) => { + onEvent: (event: ExtensibleTrustedEvent) => { if (!seen.has(event.id)) { onEvent?.(event) seen.add(event.id) diff --git a/packages/net/src/target/Local.ts b/packages/net/src/target/Local.ts index ed15ee3..9dfb4fa 100644 --- a/packages/net/src/target/Local.ts +++ b/packages/net/src/target/Local.ts @@ -1,10 +1,9 @@ import {Emitter} from '@welshman/lib' -import type {TrustedEvent} from '@welshman/util' import {Relay, LOCAL_RELAY_URL} from '@welshman/util' import type {Message} from '../Socket' -export class Local extends Emitter { - constructor(readonly relay: Relay) { +export class Local extends Emitter { + constructor(readonly relay: Relay) { super() relay.on('*', this.onMessage) diff --git a/packages/store/src/index.ts b/packages/store/src/index.ts index c2353dc..161209f 100644 --- a/packages/store/src/index.ts +++ b/packages/store/src/index.ts @@ -4,7 +4,7 @@ import type {Readable, Writable} from "svelte/store" import {identity, batch, partition, first} from "@welshman/lib" import type {Repository} from "@welshman/util" import {matchFilters, getIdAndAddress, getIdFilters} from "@welshman/util" -import type {Filter, TrustedEvent} from "@welshman/util" +import type {Filter, ExtensibleTrustedEvent} from "@welshman/util" export const getter = (store: Readable) => { let value: T @@ -68,8 +68,8 @@ export function withGetter(store: Readable | Writable) { export const throttled = (delay: number, store: Readable) => custom(set => store.subscribe(throttle(delay, set))) -export const createEventStore = (repository: Repository) => { - let subs: Sub[] = [] +export const createEventStore = (repository: Repository) => { + let subs: Sub[] = [] const onUpdate = throttle(300, () => { const $events = repository.dump() @@ -81,8 +81,8 @@ export const createEventStore = (repository: Repository< return { get: () => repository.dump(), - set: (events: E[]) => repository.load(events), - subscribe: (f: Sub) => { + set: (events: ExtensibleTrustedEvent[]) => repository.load(events), + subscribe: (f: Sub) => { f(repository.dump()) subs.push(f) @@ -102,7 +102,7 @@ export const createEventStore = (repository: Repository< } } -export const deriveEventsMapped = ({ +export const deriveEventsMapped = ({ filters, repository, eventToItem, @@ -110,9 +110,9 @@ export const deriveEventsMapped = ({ includeDeleted = false, }: { filters: Filter[] - repository: Repository, - eventToItem: (event: E) => T - itemToEvent: (item: T) => E + repository: Repository, + eventToItem: (event: ExtensibleTrustedEvent) => T + itemToEvent: (item: T) => ExtensibleTrustedEvent includeDeleted?: boolean }) => custom(setter => { @@ -120,7 +120,7 @@ export const deriveEventsMapped = ({ setter(data) - const onUpdate = batch(300, (updates: {added: E[]; removed: Set}[]) => { + const onUpdate = batch(300, (updates: {added: ExtensibleTrustedEvent[]; removed: Set}[]) => { const removed = new Set() const added = new Map() @@ -170,15 +170,15 @@ export const deriveEventsMapped = ({ return () => repository.off("update", onUpdate) }) -export const deriveEvents = (repository: Repository, opts: {filters: Filter[]; includeDeleted?: boolean}) => - deriveEventsMapped({ +export const deriveEvents = (repository: Repository, opts: {filters: Filter[]; includeDeleted?: boolean}) => + deriveEventsMapped({ ...opts, repository, eventToItem: identity, itemToEvent: identity, }) -export const deriveEvent = (repository: Repository, idOrAddress: string) => +export const deriveEvent = (repository: Repository, idOrAddress: string) => derived( deriveEvents(repository, { filters: getIdFilters([idOrAddress]), @@ -187,7 +187,7 @@ export const deriveEvent = (repository: Repository, i first ) -export const deriveIsDeletedByAddress = (repository: Repository, event: E) => +export const deriveIsDeletedByAddress = (repository: Repository, event: ExtensibleTrustedEvent) => custom(setter => { setter(repository.isDeletedByAddress(event)) diff --git a/packages/util/package.json b/packages/util/package.json index f9d70a6..d3728e7 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -32,6 +32,6 @@ }, "dependencies": { "@welshman/lib": "0.0.14", - "nostr-tools": "^2.3.2" + "nostr-tools": "^2.7.2" } } diff --git a/packages/util/src/Events.ts b/packages/util/src/Events.ts index 4f204c3..cce8f02 100644 --- a/packages/util/src/Events.ts +++ b/packages/util/src/Events.ts @@ -5,10 +5,13 @@ import {Tags} from './Tags' import {getAddress} from './Address' import {isEphemeralKind, isReplaceableKind, isPlainReplaceableKind, isParameterizedReplaceableKind} from './Kinds' -export type EventTemplate = { - kind: number +export type EventContent = { tags: string[][] content: string +} + +export type EventTemplate = EventContent & { + kind: number created_at: number } @@ -35,6 +38,8 @@ export type TrustedEvent = HashedEvent & { [verifiedSymbol]?: boolean } +export type ExtensibleTrustedEvent = TrustedEvent & Record + export type CreateEventOpts = { content?: string tags?: string[][] diff --git a/packages/util/src/Relay.ts b/packages/util/src/Relay.ts index 69ff02f..1f7de30 100644 --- a/packages/util/src/Relay.ts +++ b/packages/util/src/Relay.ts @@ -2,7 +2,7 @@ import {Emitter, normalizeUrl, sleep, stripProtocol} from '@welshman/lib' import {matchFilters} from './Filters' import type {Repository} from './Repository' import type {Filter} from './Filters' -import type {TrustedEvent} from './Events' +import type {ExtensibleTrustedEvent} from './Events' export const LOCAL_RELAY_URL = "local://welshman.relay" @@ -48,22 +48,22 @@ export const normalizeRelayUrl = (url: string, {allowInsecure = false}: Normaliz return prefix + url } -export class Relay extends Emitter { +export class Relay extends Emitter { subs = new Map() - constructor(readonly repository: Repository) { + constructor(readonly repository: Repository) { super() } send(type: string, ...message: any[]) { switch(type) { - case 'EVENT': return this.handleEVENT(message as [T]) + case 'EVENT': return this.handleEVENT(message as [ExtensibleTrustedEvent]) case 'CLOSE': return this.handleCLOSE(message as [string]) case 'REQ': return this.handleREQ(message as [string, ...Filter[]]) } } - handleEVENT([event]: [T]) { + handleEVENT([event]: [ExtensibleTrustedEvent]) { this.repository.publish(event) // Callers generally expect async relays diff --git a/packages/util/src/Repository.ts b/packages/util/src/Repository.ts index a34f25f..4869a0a 100644 --- a/packages/util/src/Repository.ts +++ b/packages/util/src/Repository.ts @@ -4,19 +4,19 @@ import {EPOCH, matchFilter} from './Filters' import {isReplaceable, isTrustedEvent} from './Events' import {getAddress} from './Address' import type {Filter} from './Filters' -import type {TrustedEvent} from './Events' +import type {ExtensibleTrustedEvent} from './Events' export const DAY = 86400 const getDay = (ts: number) => Math.floor(ts / DAY) -export class Repository extends Emitter { - eventsById = new Map() - eventsByWrap = new Map() - eventsByAddress = new Map() - eventsByTag = new Map() - eventsByDay = new Map() - eventsByAuthor = new Map() +export class Repository extends Emitter { + eventsById = new Map() + eventsByWrap = new Map() + eventsByAddress = new Map() + eventsByTag = new Map() + eventsByDay = new Map() + eventsByAuthor = new Map() deletes = new Map() // Dump/load/clear @@ -25,7 +25,7 @@ export class Repository extends Emitter { return Array.from(this.eventsById.values()) } - load = async (events: T[], chunkSize = 1000) => { + load = async (events: ExtensibleTrustedEvent[], chunkSize = 1000) => { this.clear() const added = [] @@ -69,7 +69,7 @@ export class Repository extends Emitter { : this.eventsById.get(idOrAddress) } - hasEvent = (event: T) => { + hasEvent = (event: ExtensibleTrustedEvent) => { const duplicate = ( this.eventsById.get(event.id) || this.eventsByAddress.get(getAddress(event)) @@ -79,12 +79,12 @@ export class Repository extends Emitter { } query = (filters: Filter[], {includeDeleted = false} = {}) => { - const result: T[][] = [] + const result: ExtensibleTrustedEvent[][] = [] for (let filter of filters) { - let events: T[] = Array.from(this.eventsById.values()) + let events: ExtensibleTrustedEvent[] = Array.from(this.eventsById.values()) if (filter.ids) { - events = filter.ids!.map(id => this.eventsById.get(id)).filter(identity) as T[] + events = filter.ids!.map(id => this.eventsById.get(id)).filter(identity) as ExtensibleTrustedEvent[] filter = omit(['ids'], filter) } else if (filter.authors) { events = uniq(filter.authors!.flatMap(pubkey => this.eventsByAuthor.get(pubkey) || [])) @@ -112,8 +112,8 @@ export class Repository extends Emitter { } } - const chunk: T[] = [] - for (const event of sortBy((e: T) => -e.created_at, events)) { + const chunk: ExtensibleTrustedEvent[] = [] + for (const event of sortBy((e: ExtensibleTrustedEvent) => -e.created_at, events)) { if (filter.limit && chunk.length >= filter.limit) { break } @@ -133,7 +133,7 @@ export class Repository extends Emitter { return uniq(flatten(result)) } - publish = (event: T, {shouldNotify = true} = {}): boolean => { + publish = (event: ExtensibleTrustedEvent, {shouldNotify = true} = {}): boolean => { if (!isTrustedEvent(event)) { throw new Error("Invalid event published to Repository", event) } @@ -203,19 +203,19 @@ export class Repository extends Emitter { return true } - isDeletedByAddress = (event: T) => (this.deletes.get(getAddress(event)) || 0) > event.created_at + isDeletedByAddress = (event: ExtensibleTrustedEvent) => (this.deletes.get(getAddress(event)) || 0) > event.created_at - isDeletedById = (event: T) => (this.deletes.get(event.id) || 0) > event.created_at + isDeletedById = (event: ExtensibleTrustedEvent) => (this.deletes.get(event.id) || 0) > event.created_at - isDeleted = (event: T) => this.isDeletedByAddress(event) || this.isDeletedById(event) + isDeleted = (event: ExtensibleTrustedEvent) => this.isDeletedByAddress(event) || this.isDeletedById(event) // Utilities - _updateIndex(m: Map, k: K, e: T, duplicate?: T) { + _updateIndex(m: Map, k: K, e: ExtensibleTrustedEvent, duplicate?: ExtensibleTrustedEvent) { let a = m.get(k) || [] if (duplicate) { - a = a.filter((x: T) => x !== duplicate) + a = a.filter((x: ExtensibleTrustedEvent) => x !== duplicate) } a.push(e)