Fix encryptable, fix async deriveEventsMapped

This commit is contained in:
Jon Staab
2024-08-13 17:58:12 -07:00
parent 149c29472c
commit 2c32817ed3
6 changed files with 70 additions and 53 deletions
+1 -1
View File
@@ -100,7 +100,7 @@ export class ConnectionMeta {
if (ok) {
this.authStatus = AuthStatus.Ok
} else if (notice?.startsWith('auth-required:')) {
// Re-enqueue pending reqs when auth challenge is received
// Re-enqueue pending events when auth challenge is received
const pub = this.pendingPublishes.get(eventId)
if (pub) {
+3 -2
View File
@@ -3,7 +3,7 @@ import {hexToBytes} from '@noble/hashes/utils'
import {Emitter, tryCatch, randomId, sleep, equals, now} from "@welshman/lib"
import {createEvent, TrustedEvent, EventTemplate, NOSTR_CONNECT} from "@welshman/util"
import {subscribe, publish, Subscription} from "@welshman/net"
import {ISigner, decrypt} from '../util'
import {ISigner, decrypt, hash, own} from '../util'
import {Nip01Signer} from './nip01'
export type Nip46Handler = {
@@ -168,7 +168,8 @@ export class Nip46Signer implements ISigner {
getPubkey = async () => this.broker.pubkey
sign = (event: EventTemplate) => this.broker.signEvent(event)
sign = (template: EventTemplate) =>
this.broker.signEvent(hash(own(this.broker.pubkey, template)))
nip04 = {
encrypt: this.broker.nip04Encrypt,
+31 -16
View File
@@ -110,18 +110,46 @@ export const deriveEventsMapped = <T>({
repository,
eventToItem,
itemToEvent,
throttle = 300,
includeDeleted = false,
}: {
filters: Filter[]
repository: Repository,
eventToItem: (event: CustomEvent) => T | Promise<T>
itemToEvent: (item: T) => CustomEvent
throttle?: number
includeDeleted?: boolean
}) =>
custom<T[]>(setter => {
let data = repository.query(filters, {includeDeleted}).map(eventToItem).filter(identity) as T[]
let data: T[] = []
const deferred = new Set()
const defer = (event: CustomEvent, item: Promise<T>) => {
deferred.add(event.id)
item.then($item => {
if (deferred.has(event.id)) {
deferred.delete(event.id)
data.push($item)
setter(data)
}
})
}
for (const event of repository.query(filters, {includeDeleted})) {
const item = eventToItem(event)
if (!item) {
continue
}
if (item instanceof Promise) {
defer(event, item)
} else {
data.push(item)
}
}
setter(data)
const onUpdate = batch(300, (updates: {added: CustomEvent[]; removed: Set<string>}[]) => {
@@ -147,18 +175,7 @@ export const deriveEventsMapped = <T>({
const item = eventToItem(event)
if (item instanceof Promise) {
// If it's a promise, resolve it before adding it to data
deferred.add(event.id)
// Wait for the promise to resolve. If it hasn't since been removed,
// we're clear to add it
item.then($item => {
if (deferred.has(event.id)) {
deferred.delete(event.id)
data.push($item)
setter(data)
}
})
defer(event, item)
} else if (item) {
dirty = true
data.push(item as T)
@@ -186,9 +203,7 @@ export const deriveEventsMapped = <T>({
repository.on("update", onUpdate)
return () => repository.off("update", onUpdate)
}, {
throttle: 300,
})
}, {throttle})
export const deriveEvents = (opts: {repository: Repository, filters: Filter[], includeDeleted?: boolean}) =>
deriveEventsMapped<CustomEvent>({
+15 -3
View File
@@ -2,6 +2,18 @@ import type {EventContent, CustomEvent} from './Events'
export type Encrypt = (x: string) => Promise<string>
export type EncryptableParams = {
kind: number,
tags?: string[][]
content?: string
}
export type EncryptableResult = {
kind: number,
tags: string[][]
content: string
}
export type DecryptedEvent = CustomEvent & {
plaintext: Partial<EventContent>
}
@@ -9,10 +21,10 @@ export type DecryptedEvent = CustomEvent & {
export const asDecryptedEvent = (event: CustomEvent, plaintext: Partial<EventContent>) =>
({...event, plaintext}) as DecryptedEvent
export class Encryptable<E extends Partial<EventContent>> {
constructor(readonly event: E, readonly updates: E) {}
export class Encryptable {
constructor(readonly event: EncryptableParams, readonly updates: Partial<EventContent>) {}
async reconcile(encrypt: Encrypt) {
async reconcile(encrypt: Encrypt): Promise<EncryptableResult> {
const encryptContent = () => {
if (!this.updates.content) return null
+1 -1
View File
@@ -33,7 +33,7 @@ export const readHandlers = (event: CustomEvent) => {
}
return getKindTagValues(event.tags)
.map(kind => ({...normalizedMeta, kind: parseInt(kind), identifier, event})) as Handler[]
.map(kind => ({...normalizedMeta, kind, identifier, event})) as Handler[]
}
export const getHandlerKey = (handler: Handler) => `${handler.kind}:${getAddress(handler.event)}`
+19 -30
View File
@@ -1,6 +1,6 @@
import {EventTemplate} from 'nostr-tools'
import type {OmitStatics} from '@welshman/lib'
import {Fluent, ensurePlural} from '@welshman/lib'
import {Fluent, nth, ensurePlural} from '@welshman/lib'
import {isRelayUrl, normalizeRelayUrl} from './Relay'
import {Address, isContextAddress} from './Address'
import {GROUP, COMMUNITY} from './Kinds'
@@ -208,46 +208,35 @@ export class Tags extends (Fluent<Tag> as OmitStatics<typeof Fluent<Tag>, 'from'
// New, simpler version
export const getTags =
(types: string[], testValue?: (v: string) => boolean) =>
(tags: string[][]) =>
tags.filter(t => types.includes(t[0]) && (!testValue || testValue(t[1] || "")))
export const getEventTags = (tags: string[][]) =>
tags.filter(t => ["e"].includes(t[0]) && t[1].length === 64)
export const getTagValues = (types: string[], testValue?: (v: string) => boolean) => {
const _getTags = getTags(types, testValue)
export const getEventTagValues = (tags: string[][]) => getEventTags(tags).map(nth(1))
return (tags: string[][]) => _getTags(tags).map(t => t[1] || "")
}
export const getAddressTags = (tags: string[][]) =>
tags.filter(t => ["a"].includes(t[0]) && Address.isAddress(t[1]))
export const getTagValue = (types: string[], testValue?: (v: string) => boolean) => {
const _getTagValues = getTagValues(types, testValue)
return (tags: string[][]) => _getTagValues(tags)[0]
}
export const getEventTags = getTags(["e"], id => id.length === 64)
export const getEventTagValues = getTagValues(["e"], id => id.length === 64)
export const getAddressTags = getTags(["a"], Address.isAddress)
export const getAddressTagValues = getTagValues(["a"], Address.isAddress)
export const getAddressTagValues = (tags: string[][]) => getAddressTags(tags).map(nth(1))
export const getContextTagValues = (tags: string[][]) =>
getAddressTagValues(tags).filter(isContextAddress)
export const getPubkeyTags = getTags(["p"], pk => pk.length === 64)
export const getPubkeyTags = (tags: string[][]) =>
tags.filter(t => ["p"].includes(t[0]) && t[1].length === 64)
export const getPubkeyTagValues = getTagValues(["p"], pk => pk.length === 64)
export const getPubkeyTagValues = (tags: string[][]) => getPubkeyTags(tags).map(nth(1))
export const getRelayTags = getTags(["r", "relay"], isRelayUrl)
export const getRelayTags = (tags: string[][]) =>
tags.filter(t => ["r", "relay"].includes(t[0]) && isRelayUrl(t[1]))
export const getRelayTagValues = getTagValues(["r", "relay"], isRelayUrl)
export const getRelayTagValues = (tags: string[][]) => getRelayTags(tags).map(nth(1))
export const getGroupTags = getTags(["h", "group"], h => Boolean(h.match(/^(.+)'(.+)$/)))
export const getGroupTags = (tags: string[][]) =>
tags.filter(t => ["h", "group"].includes(t[0]) && t[1] && isRelayUrl(t[2]))
export const getGroupTagValues = getTagValues(["h", "group"], h => Boolean(h.match(/^(.+)'(.+)$/)))
export const getGroupTagValues = (tags: string[][]) => getGroupTags(tags).map(nth(1))
export const getKindTags = getTags(["k"], h => Boolean(h.match(/^\d+$/)))
export const getKindTags = (tags: string[][]) =>
tags.filter(t => ["k"].includes(t[0]) && t[1].match(/^\d+$/))
export const getKindTagValues = getTagValues(["k"], h => Boolean(h.match(/^\d+$/)))
export const getKindTagValues = (tags: string[][]) => getKindTags(tags).map(t => parseInt(t[1]))