web_lib

Common web application libraries
git clone https://radroots.dev/git/web_lib.git
Log | Files | Refs | LICENSE

lib.ts (3663B)


      1 import { schnorr } from "@noble/curves/secp256k1";
      2 import { hexToBytes } from "@noble/hashes/utils";
      3 import { makeEvent } from "@welshman/util";
      4 import { KIND_POST } from "@radroots/events-bindings";
      5 import { time_now_ms, time_now_s, uuidv4 } from "@radroots/utils";
      6 import {
      7     finalizeEvent,
      8     getEventHash,
      9     nip19,
     10     type NostrEvent as NostrToolsEvent,
     11 } from "nostr-tools";
     12 import { NostrEventSign, NostrEventTags, NostrNeventEncode } from "../types/lib.js";
     13 import type { NostrEvent, NostrEventFigure, NostrSignedEvent } from "../types/nostr.js";
     14 import { nostr_tag_client } from "../utils/tags.js";
     15 import type { NostrEventBasis } from "./subscription.js";
     16 
     17 export const get_event_tag = (tags: NostrEventTags, key: string): string =>
     18     tags.find(t => t[0] === key)?.[1] ?? "";
     19 
     20 export const get_event_tags = (tags: NostrEventTags, key: string): NostrEventTags =>
     21     tags.filter(t => t[0] === key);
     22 
     23 export const parse_nostr_event_basis = <T extends number>(
     24     event: NostrEvent,
     25     kind: T,
     26 ): NostrEventBasis<T> | undefined => {
     27     if (!event || typeof event.created_at !== "number" || event.kind !== kind) return undefined;
     28     return {
     29         id: event.id,
     30         published_at: event.created_at,
     31         author: event.pubkey,
     32         kind: event.kind as T,
     33     };
     34 };
     35 
     36 export const nostr_event_verify = (event: NostrToolsEvent): boolean => {
     37     const hash = getEventHash(event);
     38     if (hash !== event.id) return false;
     39     const valid = schnorr.verify(event.sig, hash, event.pubkey);
     40     return valid;
     41 };
     42 
     43 export const nostr_event_sign = (opts: NostrEventSign): NostrToolsEvent => {
     44     return finalizeEvent(opts.event, hexToBytes(opts.secret_key));
     45 };
     46 
     47 export const nostr_event_sign_attest = (secret_key: string): NostrToolsEvent => {
     48     return nostr_event_sign({
     49         secret_key,
     50         event: {
     51             kind: KIND_POST,
     52             created_at: time_now_s(),
     53             tags: [],
     54             content: uuidv4(),
     55         },
     56     });
     57 };
     58 
     59 export const nostr_event_verify_serialized = async (
     60     event_serialized: string,
     61 ): Promise<{ public_key: string } | undefined> => {
     62     try {
     63         const event = JSON.parse(event_serialized) as NostrToolsEvent;
     64         const hash = getEventHash(event);
     65         if (hash !== event.id) return undefined;
     66         const valid = schnorr.verify(event.sig, hash, event.pubkey);
     67         if (valid) return { public_key: String(event.pubkey) };
     68         return undefined;
     69     } catch {
     70         return undefined;
     71     }
     72 };
     73 
     74 export const nostr_nevent_encode = (opts: NostrNeventEncode): string => {
     75     return nip19.neventEncode(opts);
     76 };
     77 
     78 export const nostr_event_create = async (
     79     opts: NostrEventFigure<{
     80         basis: {
     81             kind: number;
     82             content: string;
     83             tags?: NostrEventTags;
     84         };
     85     }>,
     86 ): Promise<NostrSignedEvent | undefined> => {
     87     try {
     88         const time_now = time_now_ms();
     89         const published_at = opts.date_published
     90             ? Math.floor(opts.date_published.getTime() / 1000).toString()
     91             : time_now.toString();
     92         const tags: NostrEventTags = [["published_at", published_at]];
     93         if (opts.basis.tags?.length) tags.push(...opts.basis.tags);
     94         if (opts.client) {
     95             const d_tag = tags.find(tag => tag[0] === "d")?.[1]
     96                 ?? tags.find(tag => tag[0] === "d_tag")?.[1];
     97             tags.push(nostr_tag_client(opts.client, d_tag));
     98         }
     99         const ev = makeEvent(opts.basis.kind, {
    100             content: opts.basis.content,
    101             tags,
    102             created_at: time_now,
    103         });
    104         return await opts.signer.sign(ev);
    105     } catch {
    106         return undefined;
    107     }
    108 };