diff --git a/src/app/commands.ts b/src/app/commands.ts index 5a10642..5c94187 100644 --- a/src/app/commands.ts +++ b/src/app/commands.ts @@ -8,6 +8,7 @@ import { editList, makeList, createList, + createEvent, } from "@welshman/util" import {pk, signer, repository, INDEXER_RELAYS} from "@app/base" import { @@ -17,8 +18,10 @@ import { loadProfile, loadFollows, loadMutes, + getRelaySelectionsByPubkey, loadRelaySelections, - publish, + makeThunk, + publishThunk, ensurePlaintext, } from "@app/state" @@ -49,30 +52,15 @@ export const updateList = async (kind: number, modifyTags: ModifyTags) => { const $pk = pk.get()! const $signer = signer.get()! const [prev] = repository.query([{kinds: [kind], authors: [$pk]}]) + const userRelays = getRelaySelectionsByPubkey().get($pk) + const relays = [...INDEXER_RELAYS, ...getWriteRelayUrls(userRelays)] - // Preserve content instead of use encrypted tags because kind 3 content is used for - // relay selections in many places. Content isn't supported for mutes or relays so this is ok - const relays = [...INDEXER_RELAYS, ...getWriteRelayUrls(await loadRelaySelections($pk))] - const encrypt = (content: string) => $signer.nip44.encrypt($pk, content) + // Preserve content if we have it + const event = prev + ? {...prev, tags: modifyTags(prev.tags)} + : createEvent(kind, {tags: modifyTags([])}) - let encryptable - if (prev) { - const content = await ensurePlaintext(prev) - const list = readList(asDecryptedEvent(prev, {content})) - const publicTags = modifyTags(list.publicTags) - - encryptable = editList({...list, publicTags}) - } else { - const list = makeList({kind}) - const publicTags = modifyTags(list.publicTags) - - encryptable = createList({...list, publicTags}) - } - - const template = await encryptable.reconcile(encrypt) - const event = await $signer.sign({...template, created_at: now()}) - - await publish({event, relays}) + publishThunk(makeThunk({event, relays})) } export const addGroupMemberships = (newTags: string[][]) => diff --git a/src/app/state.ts b/src/app/state.ts index 12517e2..4cd9f32 100644 --- a/src/app/state.ts +++ b/src/app/state.ts @@ -15,6 +15,7 @@ import { assoc, indexBy, now, + Worker, } from "@welshman/lib" import { getIdFilters, @@ -34,10 +35,10 @@ import { GROUP_JOIN, GROUP_ADD_USER, } from "@welshman/util" -import type {SignedEvent, CustomEvent, PublishedProfile, PublishedList} from "@welshman/util" -import type {SubscribeRequest, PublishRequest} from "@welshman/net" +import type {SignedEvent, HashedEvent, EventTemplate, CustomEvent, PublishedProfile, PublishedList} from "@welshman/util" +import type {SubscribeRequest, PublishRequest, PublishStatus} from "@welshman/net" import {publish as basePublish, subscribe as baseSubscribe} from "@welshman/net" -import {decrypt} from "@welshman/signer" +import {decrypt, stamp, own, hash} from "@welshman/signer" import {deriveEvents, deriveEventsMapped, getter, withGetter} from "@welshman/store" import {createSearch} from "@lib/util" import type {Handle, Relay} from "@app/types" @@ -117,12 +118,59 @@ export const deriveEvent = (idOrAddress: string, hints: string[] = []) => { ) } -export const publish = (request: PublishRequest) => { - repository.publish(request.event) +// Publish - return basePublish(request) +export type Thunk = { + event: HashedEvent + relays: string[] } +export const thunkWorker = new Worker() + +thunkWorker.addGlobalHandler(async ({event, relays}: Thunk) => { + const session = getSession(event.pubkey) + + if (!session) { + return console.warn(`No session found for ${event.pubkey}`) + } + + const signedEvent = await getSigner(session)!.sign(event) + const savedEvent = repository.getEvent(signedEvent.id) + const pub = basePublish({event: signedEvent, relays}) + + // Copy the signature over since we had deferred it + if (savedEvent) { + savedEvent.sig = signedEvent.sig + } + + // Watch for failures + pub.emitter.on('*', (status: PublishStatus, url: string) => { + console.log('pub status', status, url) + }) +}) + +export type ThunkParams = { + event: EventTemplate + relays: string[] +} + +export const makeThunk = ({event, relays}: ThunkParams) => { + const $pk = get(pk) + + if (!$pk) { + throw new Error("Unable to make thunk if no user is logged in") + } + + return {event: hash(own(stamp(event), $pk)), relays} +} + +export const publishThunk = (thunk: Thunk) => { + thunkWorker.push(thunk) + repository.publish(thunk.event) +} + +// Subscribe + export const subscribe = (request: SubscribeRequest) => { const sub = baseSubscribe({delay: 50, ...request})