diff --git a/packages/app/src/commands.ts b/packages/app/src/commands.ts index 3390119..e42845f 100644 --- a/packages/app/src/commands.ts +++ b/packages/app/src/commands.ts @@ -1,9 +1,11 @@ import {get} from "svelte/store" -import {addToListPublicly, removeFromList, makeList, FOLLOWS, MUTES, PINS} from "@welshman/util" +import {uniq} from "@welshman/lib" +import {addToListPublicly, EventTemplate, removeFromList, makeList, FOLLOWS, MUTES, PINS} from "@welshman/util" +import {Nip59, stamp} from "@welshman/signer" import {Router, addMaximalFallbacks} from "@welshman/router" import {userFollows, userMutes, userPins} from "./user.js" -import {nip44EncryptToSelf} from "./session.js" -import {publishThunk} from "./thunk.js" +import {nip44EncryptToSelf, signer} from "./session.js" +import {ThunkOptions, MergedThunk, publishThunk} from "./thunk.js" export const unfollow = async (value: string) => { const list = get(userFollows) || makeList({kind: FOLLOWS}) @@ -52,3 +54,24 @@ export const pin = async (tag: string[]) => { return publishThunk({event, relays}) } + +export type SendWrappedOptions = Omit & { + template: EventTemplate + pubkeys: string[] +} + +export const sendWrapped = async ({template, pubkeys, ...options}: SendWrappedOptions) => { + const nip59 = Nip59.fromSigner(signer.get()!) + + return new MergedThunk( + await Promise.all( + uniq(pubkeys).map(async recipient => + publishThunk({ + event: await nip59.wrap(recipient, stamp(template)), + relays: Router.get().PubkeyInbox(recipient).getUrls(), + ...options, + }), + ), + ), + ) +} diff --git a/packages/app/src/index.ts b/packages/app/src/index.ts index a2e71a9..4cde75e 100644 --- a/packages/app/src/index.ts +++ b/packages/app/src/index.ts @@ -20,7 +20,6 @@ export * from "./tags.js" export * from "./thunk.js" export * from "./topics.js" export * from "./user.js" -export * from "./util.js" export * from "./wot.js" export * from "./zappers.js" diff --git a/packages/app/src/util.ts b/packages/app/src/util.ts deleted file mode 100644 index b986c49..0000000 --- a/packages/app/src/util.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {now, int, DAY, HOUR, MINUTE} from "@welshman/lib" - -export const LOCALE = new Intl.DateTimeFormat().resolvedOptions().locale - -export const TIMEZONE = new Date().toString().match(/GMT[^\s]+/)![0] - -export const secondsToDate = (ts: number) => new Date(ts * 1000) - -export const dateToSeconds = (date: Date) => Math.round(date.valueOf() / 1000) - -export const createLocalDate = (dateString: any) => new Date(`${dateString} ${TIMEZONE}`) - -export const timestampFormatter = new Intl.DateTimeFormat(LOCALE, { - dateStyle: "short", - timeStyle: "short", -}) - -export const formatTimestamp = (ts: number) => timestampFormatter.format(secondsToDate(ts)) - -export const dateFormatter = new Intl.DateTimeFormat(LOCALE, { - year: "numeric", - month: "long", - day: "numeric", -}) - -export const formatTimestampAsDate = (ts: number) => dateFormatter.format(secondsToDate(ts)) - -export const timeFormatter = new Intl.DateTimeFormat(LOCALE, { - timeStyle: "short", -}) - -export const formatTimestampAsTime = (ts: number) => timeFormatter.format(secondsToDate(ts)) - -export const formatTimestampRelative = (ts: number) => { - let unit - let delta = now() - ts - if (delta < int(MINUTE)) { - unit = "second" - } else if (delta < int(HOUR)) { - unit = "minute" - delta = Math.round(delta / int(MINUTE)) - } else if (delta < int(DAY, 2)) { - unit = "hour" - delta = Math.round(delta / int(HOUR)) - } else { - unit = "day" - delta = Math.round(delta / int(DAY)) - } - - const locale = new Intl.RelativeTimeFormat().resolvedOptions().locale - const formatter = new Intl.RelativeTimeFormat(locale, { - numeric: "auto", - }) - - return formatter.format(-delta, unit as Intl.RelativeTimeFormatUnit) -} diff --git a/packages/lib/src/Tools.ts b/packages/lib/src/Tools.ts index f9bfd78..b6d15f1 100644 --- a/packages/lib/src/Tools.ts +++ b/packages/lib/src/Tools.ts @@ -227,7 +227,11 @@ export const YEAR = 365 * DAY export const LOCALE = new Intl.DateTimeFormat().resolvedOptions().locale /** User's default timezone */ -export const TIMEZONE = new Date().toString().match(/GMT[^\s]+/)![0] +export const TIMEZONE = (() => { + const [_, sign = "+", offset] = new Date().toString().match(/GMT([-\+]?)(\d+)/)! + + return sign + offset.slice(0, 2) + ":" + offset.slice(2) +})() /** * Multiplies time unit by count @@ -276,7 +280,7 @@ export const dateToSeconds = (date: Date) => Math.round(date.valueOf() / 1000) * @returns timezone-aware Date object */ export const createLocalDate = (dateString: any, timezone = TIMEZONE) => - new Date(`${dateString} ${timezone}`) + new Date(`${dateString} GMT${timezone}`) /** Formatter for date+time */ export const dateTimeFormatter = new Intl.DateTimeFormat(LOCALE, { diff --git a/packages/net/src/request.ts b/packages/net/src/request.ts index 74046b4..9623d99 100644 --- a/packages/net/src/request.ts +++ b/packages/net/src/request.ts @@ -317,7 +317,7 @@ export const makeLoader = (options: LoaderOptions) => }) }) - return allRequests.map(r => resultsByRequest.get(r)!) + return allRequests.map(r => resultsByRequest.get(r) || []) }) export const load = makeLoader({delay: 200, timeout: 3000, threshold: 0.5}) diff --git a/packages/util/src/Kinds.ts b/packages/util/src/Kinds.ts index 2c2f033..a0b7e71 100644 --- a/packages/util/src/Kinds.ts +++ b/packages/util/src/Kinds.ts @@ -24,6 +24,7 @@ export const MESSAGE = 9 export const THREAD = 11 export const SEAL = 13 export const DIRECT_MESSAGE = 14 +export const DIRECT_MESSAGE_FILE = 15 export const GENERIC_REPOST = 16 export const PICTURE_NOTE = 20 export const CHANNEL_CREATE = 40