From 28daebabeeb5245fe5cf25c05cf6848a4e4d5916 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Tue, 6 Aug 2024 15:55:05 -0700 Subject: [PATCH] Add some utils, kinds --- packages/lib/src/Tools.ts | 44 +++++++++++++++++++++++++++++++++++++ packages/util/src/Events.ts | 2 ++ packages/util/src/Kinds.ts | 19 ++++++++++++---- packages/util/src/Tags.ts | 43 ++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/packages/lib/src/Tools.ts b/packages/lib/src/Tools.ts index 1966168..6daf1d0 100644 --- a/packages/lib/src/Tools.ts +++ b/packages/lib/src/Tools.ts @@ -353,6 +353,50 @@ export const pushToMapKey = (m: Map, k: K, v: T) => { export const switcher = (k: string, m: Record) => m[k] === undefined ? m.default : m[k] +// Fetch + +type FetchOpts = { + method?: string + headers?: Record + body?: string | FormData +} + +export const fetchJson = async (url: string, opts: FetchOpts = {}) => { + if (!opts.headers) { + opts.headers = {} + } + + opts.headers["Accept"] = "application/json" + + const res = await fetch(url, opts as RequestInit) + const json = await res.json() + + return json +} + +export const postJson = async (url: string, data: T, opts: FetchOpts = {}) => { + if (!opts.method) { + opts.method = "POST" + } + + if (!opts.headers) { + opts.headers = {} + } + + opts.headers["Content-Type"] = "application/json" + opts.body = JSON.stringify(data) + + return fetchJson(url, opts) +} + +export const uploadFile = (url: string, fileObj: File) => { + const body = new FormData() + + body.append("file", fileObj) + + return fetchJson(url, {method: "POST", body}) +} + // Random obscure stuff export const hexToBech32 = (prefix: string, url: string) => diff --git a/packages/util/src/Events.ts b/packages/util/src/Events.ts index d3d485a..4f204c3 100644 --- a/packages/util/src/Events.ts +++ b/packages/util/src/Events.ts @@ -98,6 +98,8 @@ export const hasValidSignature = cached({ }, }) +export const getIdentifier = (e: EventTemplate) => e.tags.find(t => t[0] === 'd')?.[1] + export const getIdOrAddress = (e: HashedEvent) => isReplaceable(e) ? getAddress(e) : e.id export const getIdAndAddress = (e: HashedEvent) => isReplaceable(e) ? [e.id, getAddress(e)] : [e.id] diff --git a/packages/util/src/Kinds.ts b/packages/util/src/Kinds.ts index 69a2bba..62ff0ba 100644 --- a/packages/util/src/Kinds.ts +++ b/packages/util/src/Kinds.ts @@ -14,10 +14,10 @@ export const DELETE = 5 export const REPOST = 6 export const REACTION = 7 export const BADGE_AWARD = 8 -export const GROUP_CHAT_MESSAGE = 9 -export const GROUP_CHAT_REPLY = 10 -export const GROUP_CHAT_THREAD = 11 -export const GROUP_CHAT_THREAD_REPLY = 12 +export const CHAT_MESSAGE = 9 +export const CHAT_REPLY = 10 +export const GROUP_NOTE = 11 +export const GROUP_REPLY = 12 export const SEAL = 13 export const DIRECT_MESSAGE = 14 export const GENERIC_REPOST = 16 @@ -84,6 +84,15 @@ export const DVM_RESPONSE_OTS = 6900 export const DVM_RESPONSE_OP_RETURN = 6901 export const DVM_RESPONSE_PUBLISH_SCHEDULE = 6905 export const DVM_FEEDBACK = 7000 +export const GROUP_ADD_USER = 9000 +export const GROUP_REMOVE_USER = 9001 +export const GROUP_EDIT_META = 9002 +export const GROUP_ADD_PERM = 9003 +export const GROUP_REMOVE_PERM = 9004 +export const GROUP_DELETE_EVENT = 9005 +export const GROUP_EDIT_STATUS = 9006 +export const GROUP_CREATE = 9007 +export const GROUP_JOIN = 9021 export const ZAP_GOAL = 9041 export const ZAP_REQUEST = 9734 export const ZAP_RESPONSE = 9735 @@ -146,6 +155,8 @@ export const HANDLER_RECOMMENDATION = 31989 export const HANDLER_INFORMATION = 31990 export const COMMUNITY = 34550 export const GROUP = 35834 +export const GROUP_META = 39000 +export const GROUP_ADMINS = 39001 export const DEPRECATED_RELAY_RECOMMENDATION = 2 export const DEPRECATED_DIRECT_MESSAGE = 4 diff --git a/packages/util/src/Tags.ts b/packages/util/src/Tags.ts index c596ffa..226e94e 100644 --- a/packages/util/src/Tags.ts +++ b/packages/util/src/Tags.ts @@ -2,6 +2,7 @@ import {EventTemplate} from 'nostr-tools' import type {OmitStatics} from '@welshman/lib' import {Fluent, ensurePlural} from '@welshman/lib' import {isShareableRelayUrl, normalizeRelayUrl} from './Relay' +import {Address, isContextAddress} from './Address' import {GROUP, COMMUNITY} from './Kinds' export class Tag extends (Fluent as OmitStatics, 'from'>) { @@ -204,3 +205,45 @@ export class Tags extends (Fluent as OmitStatics, 'from' setIMeta = (imeta: Tags[]) => this.removeIMeta().addIMeta(imeta) } + +// 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 getTagValues = (types: string[], testValue?: (v: string) => boolean) => { + const _getTags = getTags(types, testValue) + + return (tags: string[][]) => _getTags(tags).map(t => 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 getContextTagValues = (tags: string[][]) => + getAddressTagValues(tags).filter(isContextAddress) + +export const getPubkeyTags = getTags(["p"], pk => pk.length === 64) + +export const getPubkeyTagValues = getTagValues(["p"], pk => pk.length === 64) + +export const getRelayTags = getTags(["r", "relay"], isShareableRelayUrl) + +export const getRelayTagValues = getTagValues(["r", "relay"], isShareableRelayUrl) + +export const getGroupTags = getTags(["h", "group"], h => Boolean(h.match(/^(.+)'(.+)$/))) + +export const getGroupTagValues = getTagValues(["h", "group"], h => Boolean(h.match(/^(.+)'(.+)$/)))