Add some common commands
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
import {get} from 'svelte/store'
|
||||||
|
import {ctx} from '@welshman/lib'
|
||||||
|
import {addToListPublicly, removeFromList, makeList, FOLLOWS, MUTES} from '@welshman/util'
|
||||||
|
import {userFollows, userMutes} from './user'
|
||||||
|
import {nip44EncryptToSelf} from './session'
|
||||||
|
import {publishThunk} from './thunk'
|
||||||
|
|
||||||
|
export const unfollow = async (value: string) => {
|
||||||
|
const list = get(userFollows) || makeList({kind: FOLLOWS})
|
||||||
|
const event = await removeFromList(list, value).reconcile(nip44EncryptToSelf)
|
||||||
|
|
||||||
|
return publishThunk({event, relays: ctx.app.router.WriteRelays().getUrls()})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const follow = async (tag: string[]) => {
|
||||||
|
const list = get(userFollows) || makeList({kind: FOLLOWS})
|
||||||
|
const event = await addToListPublicly(list, tag).reconcile(nip44EncryptToSelf)
|
||||||
|
|
||||||
|
return publishThunk({event, relays: ctx.app.router.WriteRelays().getUrls()})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const unmute = async (value: string) => {
|
||||||
|
const list = get(userMutes) || makeList({kind: MUTES})
|
||||||
|
const event = await removeFromList(list, value).reconcile(nip44EncryptToSelf)
|
||||||
|
|
||||||
|
return publishThunk({event, relays: ctx.app.router.WriteRelays().getUrls()})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mute = async (tag: string[]) => {
|
||||||
|
const list = get(userMutes) || makeList({kind: MUTES})
|
||||||
|
const event = await addToListPublicly(list, tag).reconcile(nip44EncryptToSelf)
|
||||||
|
|
||||||
|
return publishThunk({event, relays: ctx.app.router.WriteRelays().getUrls()})
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from './context'
|
export * from './context'
|
||||||
export * from './core'
|
export * from './core'
|
||||||
export * from './collection'
|
export * from './collection'
|
||||||
|
export * from './commands'
|
||||||
export * from './freshness'
|
export * from './freshness'
|
||||||
export * from './follows'
|
export * from './follows'
|
||||||
export * from './handles'
|
export * from './handles'
|
||||||
|
|||||||
@@ -82,3 +82,14 @@ export const onAuth = async (url: string, challenge: string) => {
|
|||||||
|
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const nip44EncryptToSelf = (payload: string) => {
|
||||||
|
const $pubkey = pubkey.get()
|
||||||
|
const $signer = signer.get()
|
||||||
|
|
||||||
|
if (!$signer) {
|
||||||
|
throw new Error("Unable to encrypt to self without valid signer")
|
||||||
|
}
|
||||||
|
|
||||||
|
return $signer.nip44.encrypt($pubkey!, payload)
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,12 +20,9 @@ export type PublishStatusDataByUrlById = Record<string, PublishStatusDataByUrl>
|
|||||||
|
|
||||||
export const publishStatusData = writable<PublishStatusDataByUrlById>({})
|
export const publishStatusData = writable<PublishStatusDataByUrlById>({})
|
||||||
|
|
||||||
export type Thunk = {
|
export type ThunkWithResolve = {
|
||||||
event: TrustedEvent
|
event: TrustedEvent
|
||||||
relays: string[]
|
relays: string[]
|
||||||
}
|
|
||||||
|
|
||||||
export type ThunkWithResolve = Thunk & {
|
|
||||||
resolve: (data: PublishStatusDataByUrl) => void
|
resolve: (data: PublishStatusDataByUrl) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,13 +100,17 @@ export const prepEvent = (event: ThunkEvent) => {
|
|||||||
return event as TrustedEvent
|
return event as TrustedEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeThunk = ({event, relays}: {event: ThunkEvent, relays: string[]}) =>
|
export type ThunkParams = {
|
||||||
({event, relays})
|
event: ThunkEvent
|
||||||
|
relays: string[]
|
||||||
|
}
|
||||||
|
|
||||||
export const publishThunk = ({event, relays}: Thunk) =>
|
export const makeThunk = (params: ThunkParams) => params
|
||||||
|
|
||||||
|
export const publishThunk = (params: ThunkParams) =>
|
||||||
new Promise<PublishStatusDataByUrl>(resolve => {
|
new Promise<PublishStatusDataByUrl>(resolve => {
|
||||||
event = prepEvent(event)
|
const event = prepEvent(params.event)
|
||||||
|
|
||||||
thunkWorker.push({event, relays, resolve})
|
thunkWorker.push({...params, event, resolve})
|
||||||
repository.publish(event)
|
repository.publish(event)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,21 +1,9 @@
|
|||||||
import type {EventContent, TrustedEvent} from './Events'
|
import type {EventContent, TrustedEvent, EventTemplate} from './Events'
|
||||||
|
|
||||||
export type Encrypt = (x: string) => Promise<string>
|
export type Encrypt = (x: string) => Promise<string>
|
||||||
|
|
||||||
export type EncryptableParams = {
|
|
||||||
kind: number,
|
|
||||||
tags?: string[][]
|
|
||||||
content?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EncryptableUpdates = Partial<EventContent>
|
export type EncryptableUpdates = Partial<EventContent>
|
||||||
|
|
||||||
export type EncryptableResult = {
|
|
||||||
kind: number,
|
|
||||||
tags: string[][]
|
|
||||||
content: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DecryptedEvent = TrustedEvent & {
|
export type DecryptedEvent = TrustedEvent & {
|
||||||
plaintext: EncryptableUpdates
|
plaintext: EncryptableUpdates
|
||||||
}
|
}
|
||||||
@@ -26,7 +14,7 @@ export const asDecryptedEvent = (event: TrustedEvent, plaintext: EncryptableUpda
|
|||||||
/**
|
/**
|
||||||
* Represents an encryptable event with optional updates.
|
* Represents an encryptable event with optional updates.
|
||||||
*/
|
*/
|
||||||
export class Encryptable {
|
export class Encryptable<T extends EventTemplate> {
|
||||||
/**
|
/**
|
||||||
* Creates an instance of Encryptable.
|
* Creates an instance of Encryptable.
|
||||||
* @param event - An EventTemplate with optional tags and content.
|
* @param event - An EventTemplate with optional tags and content.
|
||||||
@@ -39,14 +27,14 @@ export class Encryptable {
|
|||||||
* const eventTemplate = await encryptable.reconcile(myEncryptFunction)
|
* const eventTemplate = await encryptable.reconcile(myEncryptFunction)
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
constructor(readonly event: EncryptableParams, readonly updates: EncryptableUpdates) {}
|
constructor(readonly event: Partial<T>, readonly updates: EncryptableUpdates) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts plaintext updates and merges them into the event template.
|
* Encrypts plaintext updates and merges them into the event template.
|
||||||
* @param encrypt - The encryption function to be used.
|
* @param encrypt - The encryption function to be used.
|
||||||
* @returns A promise that resolves to the reconciled and encrypted event.
|
* @returns A promise that resolves to the reconciled and encrypted event.
|
||||||
*/
|
*/
|
||||||
async reconcile(encrypt: Encrypt): Promise<EncryptableResult> {
|
async reconcile(encrypt: Encrypt) {
|
||||||
const encryptContent = () => {
|
const encryptContent = () => {
|
||||||
if (!this.updates.content) return null
|
if (!this.updates.content) return null
|
||||||
|
|
||||||
@@ -72,6 +60,6 @@ export class Encryptable {
|
|||||||
...this.event,
|
...this.event,
|
||||||
tags: tags || this.event.tags || [],
|
tags: tags || this.event.tags || [],
|
||||||
content: content || this.event.content || "",
|
content: content || this.event.content || "",
|
||||||
}
|
} as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {parseJson, append, nthNe, nthEq} from "@welshman/lib"
|
import {parseJson, append, nthEq} from "@welshman/lib"
|
||||||
import {Address} from "./Address"
|
import {Address} from "./Address"
|
||||||
import {uniqTags} from "./Tags"
|
import {uniqTags} from "./Tags"
|
||||||
import {isShareableRelayUrl} from "./Relay"
|
import {isShareableRelayUrl} from "./Relay"
|
||||||
@@ -44,22 +44,25 @@ export const readList = (event: DecryptedEvent): PublishedList => {
|
|||||||
export const getListTags = (list: List | undefined) =>
|
export const getListTags = (list: List | undefined) =>
|
||||||
[...list?.publicTags || [], ...list?.privateTags || []]
|
[...list?.publicTags || [], ...list?.privateTags || []]
|
||||||
|
|
||||||
export const removeFromList = (list: List, value: string) => {
|
export const removeFromListByPredicate = (list: List, pred: (t: string[]) => boolean) => {
|
||||||
const plaintext: EncryptableUpdates = {}
|
const plaintext: EncryptableUpdates = {}
|
||||||
const template = {
|
const template = {
|
||||||
kind: list.kind,
|
kind: list.kind,
|
||||||
content: list.event?.content || "",
|
content: list.event?.content || "",
|
||||||
tags: list.publicTags.filter(nthNe(1, value)),
|
tags: list.publicTags.filter(t => !pred(t)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid redundant encrypt calls if possible
|
// Avoid redundant encrypt calls if possible
|
||||||
if (list.privateTags.some(nthEq(1, value))) {
|
if (list.privateTags.some(t => pred(t))) {
|
||||||
plaintext.content = JSON.stringify(list.privateTags.filter(nthNe(1, value)))
|
plaintext.content = JSON.stringify(list.privateTags.filter(t => !pred(t)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Encryptable(template, plaintext)
|
return new Encryptable(template, plaintext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const removeFromList = (list: List, value: string) =>
|
||||||
|
removeFromListByPredicate(list, nthEq(1, value))
|
||||||
|
|
||||||
export const addToListPublicly = (list: List, tag: string[]) => {
|
export const addToListPublicly = (list: List, tag: string[]) => {
|
||||||
const template = {
|
const template = {
|
||||||
kind: list.kind,
|
kind: list.kind,
|
||||||
|
|||||||
Reference in New Issue
Block a user