web_lib

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

commit 4a3a17f9a2827c76f8d862229c70c497e98cf414
parent 8262fb08ca3dbe172633e9e67f3cfbbc43941ed1
Author: triesap <137732411+triesap@users.noreply.github.com>
Date:   Sat,  9 Aug 2025 17:25:34 +0000

utils-nostr: add `follow` nip-02 schemas, types, event parsing utils

Diffstat:
Mutils-nostr/package.json | 2+-
Autils-nostr/src/events/follow/lib.ts | 19+++++++++++++++++++
Autils-nostr/src/events/follow/parse.ts | 15+++++++++++++++
Mutils-nostr/src/events/listing/lib.ts | 2+-
Mutils-nostr/src/events/subscription.ts | 10+++++++++-
Mutils-nostr/src/index.ts | 4++++
Mutils-nostr/src/schemas/lib.ts | 10++++++++++
Mutils-nostr/src/types/lib.ts | 28+++++++++++++++-------------
Mutils-nostr/src/utils/tags.ts | 11++++++++++-
Mutils-nostr/tsconfig.cjs.json | 10++++++++--
Autils-nostr/tsconfig.esm.json | 13+++++++++++++
Mutils-nostr/tsconfig.json | 8+-------
12 files changed, 106 insertions(+), 26 deletions(-)

diff --git a/utils-nostr/package.json b/utils-nostr/package.json @@ -4,7 +4,7 @@ "private": true, "license": "GPLv3", "type": "module", - "main": "./dist/cjs/index.cjs", + "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/types/index.d.ts", "exports": { diff --git a/utils-nostr/src/events/follow/lib.ts b/utils-nostr/src/events/follow/lib.ts @@ -0,0 +1,18 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { NostrEventFollow } from "../../types/lib.js"; +import { NDKEventFigure } from "../../types/ndk.js"; +import { tags_follow_list } from "../../utils/tags.js"; +import { ndk_event } from "../lib.js"; + +export const ndk_event_follows = async (opts: NDKEventFigure<{ data: NostrEventFollow; }>): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data } = opts; + return await ndk_event({ + ndk, + ndk_user, + basis: { + kind: 3, + content: ``, + tags: tags_follow_list(data.list), + }, + }); +}; +\ No newline at end of file diff --git a/utils-nostr/src/events/follow/parse.ts b/utils-nostr/src/events/follow/parse.ts @@ -0,0 +1,15 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { nostr_event_follow_schema } from "../../schemas/lib.js"; +import { NostrEventFollow } from "../../types/lib.js"; + +export const parse_nostr_follow_event = (event: NDKEvent): NostrEventFollow | undefined => { + if (!event || typeof event.content !== 'string' || event.kind !== 3) return undefined; + + try { + const parsed = JSON.parse(event.content); + const result = nostr_event_follow_schema.parse(parsed); + return result; + } catch { + return undefined; + } +}; diff --git a/utils-nostr/src/events/listing/lib.ts b/utils-nostr/src/events/listing/lib.ts @@ -1,6 +1,6 @@ import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk"; import { NostrEventListing } from "../../types/lib.js"; -import { NDKEventFigure } from "../../types/ndk"; +import { NDKEventFigure } from "../../types/ndk.js"; import { tags_classified } from "../../utils/tags.js"; import { ndk_event } from "../lib.js"; diff --git a/utils-nostr/src/events/subscription.ts b/utils-nostr/src/events/subscription.ts @@ -1,6 +1,7 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { NostrEventComment, NostrEventListing, NostrEventReaction, type NostrEventMetadata } from "../types/lib.js"; +import { NostrEventComment, NostrEventFollow, NostrEventListing, NostrEventReaction, type NostrEventMetadata } from "../types/lib.js"; import { parse_nostr_comment_event } from "./comment/parse.js"; +import { parse_nostr_follow_event } from "./follow/parse.js"; import { parse_nostr_listing_event } from "./listing/parse.js"; import { parse_nostr_metadata_event } from "./metadata/parse.js"; import { parse_nostr_reaction_event } from "./reaction/parse.js"; @@ -10,6 +11,8 @@ export type NdkEventPayload = | { kind: 30402; listing: NostrEventListing; } | { kind: 1111; comment: NostrEventComment; } | { kind: 7; reaction: NostrEventReaction; } + | { kind: 3; follow: NostrEventFollow; } + export const on_ndk_event = (event: NDKEvent): NdkEventPayload | undefined => { if (!event || typeof event.kind !== 'number') return undefined; @@ -35,6 +38,11 @@ export const on_ndk_event = (event: NDKEvent): NdkEventPayload | undefined => { if (!data) return; return { kind: event.kind, reaction: data }; }; + case 3: { + const data = parse_nostr_follow_event(event); + if (!data) return; + return { kind: event.kind, follow: data }; + }; default: return undefined; } diff --git a/utils-nostr/src/index.ts b/utils-nostr/src/index.ts @@ -1,8 +1,12 @@ +export * from "./events/comment/lib.js" +export * from "./events/comment/parse.js" export * from "./events/lib.js" export * from "./events/listing/lib.js" export * from "./events/listing/parse.js" export * from "./events/metadata/lib.js" export * from "./events/metadata/parse.js" +export * from "./events/reaction/lib.js" +export * from "./events/reaction/parse.js" export * from "./events/subscription.js" export * from "./keys/lib.js" export * from "./schemas/lib.js" diff --git a/utils-nostr/src/schemas/lib.ts b/utils-nostr/src/schemas/lib.ts @@ -128,3 +128,13 @@ export const nostr_event_reaction_schema = z.object({ ref_event: nostr_event_referenced_schema, content: z.string().min(1), }); + +export const nostr_follow_list_schema = z.object({ + public_key: z.string(), + relay_url: z.url().optional(), + contact_name: z.string().optional() +}); + +export const nostr_event_follow_schema = z.object({ + list: z.array(nostr_follow_list_schema) +}); diff --git a/utils-nostr/src/types/lib.ts b/utils-nostr/src/types/lib.ts @@ -1,18 +1,20 @@ import { z } from 'zod'; -import { nostr_event_comment_schema, nostr_event_listing_schema, nostr_event_metadata_schema, nostr_event_reaction_schema, nostr_event_referenced_schema, nostr_tag_client_schema, nostr_tag_discount_schema, nostr_tag_image_schema, nostr_tag_listing_schema, nostr_tag_location_schema, nostr_tag_price_schema, nostr_tag_quantity_schema } from "../schemas/lib.js"; +import { nostr_event_comment_schema, nostr_event_follow_schema, nostr_event_listing_schema, nostr_event_metadata_schema, nostr_event_reaction_schema, nostr_event_referenced_schema, nostr_follow_list_schema, nostr_tag_client_schema, nostr_tag_discount_schema, nostr_tag_image_schema, nostr_tag_listing_schema, nostr_tag_location_schema, nostr_tag_price_schema, nostr_tag_quantity_schema } from "../schemas/lib.js"; -export type NostrEventMetadata = z.infer<typeof nostr_event_metadata_schema>; -export type NostrEventListing = z.infer<typeof nostr_event_listing_schema> -export type NostrTagClient = z.infer<typeof nostr_tag_client_schema> -export type NostrTagMediaUpload = z.infer<typeof nostr_tag_image_schema> -export type NostrTagLocation = z.infer<typeof nostr_tag_location_schema> -export type NostrTagPriceDiscount = z.infer<typeof nostr_tag_discount_schema> -export type NostrTagPrice = z.infer<typeof nostr_tag_price_schema> -export type NostrTagQuantity = z.infer<typeof nostr_tag_quantity_schema> -export type NostrTagListing = z.infer<typeof nostr_tag_listing_schema> -export type NostrEventComment = z.infer<typeof nostr_event_comment_schema> -export type NostrEventReferenced = z.infer<typeof nostr_event_referenced_schema> -export type NostrEventReaction = z.infer<typeof nostr_event_reaction_schema> +export type NostrEventMetadata = z.infer<typeof nostr_event_metadata_schema>;; +export type NostrEventListing = z.infer<typeof nostr_event_listing_schema>; +export type NostrTagClient = z.infer<typeof nostr_tag_client_schema>; +export type NostrTagMediaUpload = z.infer<typeof nostr_tag_image_schema>; +export type NostrTagLocation = z.infer<typeof nostr_tag_location_schema>; +export type NostrTagPriceDiscount = z.infer<typeof nostr_tag_discount_schema>; +export type NostrTagPrice = z.infer<typeof nostr_tag_price_schema>; +export type NostrTagQuantity = z.infer<typeof nostr_tag_quantity_schema>; +export type NostrTagListing = z.infer<typeof nostr_tag_listing_schema>; +export type NostrEventComment = z.infer<typeof nostr_event_comment_schema>; +export type NostrEventReferenced = z.infer<typeof nostr_event_referenced_schema>; +export type NostrEventReaction = z.infer<typeof nostr_event_reaction_schema>; +export type NostrEventFollow = z.infer<typeof nostr_event_follow_schema>; +export type NostrFollowList = z.infer<typeof nostr_follow_list_schema>; export type NostrEventTag = string[]; export type NostrEventTags = NostrEventTag[]; diff --git a/utils-nostr/src/utils/tags.ts b/utils-nostr/src/utils/tags.ts @@ -1,5 +1,5 @@ import ngeotags, { type InputData as NostrGeotagsInputData } from "nostr-geotags"; -import { NostrEventComment, NostrEventListing, NostrEventReaction, NostrEventTag, NostrEventTagClient, NostrEventTagImage, NostrEventTagLocation, NostrEventTagPrice, NostrEventTagPriceDiscount, NostrEventTagQuantity, NostrEventTags } from "../types/lib.js"; +import { NostrEventComment, NostrEventListing, NostrEventReaction, NostrEventTag, NostrEventTagClient, NostrEventTagImage, NostrEventTagLocation, NostrEventTagPrice, NostrEventTagPriceDiscount, NostrEventTagQuantity, NostrEventTags, NostrFollowList } from "../types/lib.js"; export const tag_client = (opts: NostrEventTagClient, d_tag?: string): NostrEventTag => { const tag = [`client`, opts.name]; @@ -120,4 +120,13 @@ export const tags_reaction = (opts: NostrEventReaction): NostrEventTags => { ]; if (ref_event.d_tag) tags.push([`a`, `${ref_kind}:${ref_author}:${ref_event.d_tag}`, ...ref_event.relays || ``]) return tags; +}; + +export const tags_follow_list = (list: NostrFollowList[]): NostrEventTags => { + return list.map(({ public_key, relay_url, contact_name }) => { + const entry = [`p`, public_key]; + if (relay_url) entry.push(relay_url); + if (contact_name) entry.push(contact_name); + return entry; + }); }; \ No newline at end of file diff --git a/utils-nostr/tsconfig.cjs.json b/utils-nostr/tsconfig.cjs.json @@ -1,8 +1,14 @@ { - "extends": "@radroots/tsconfig/tsconfig.cjs.json", + "extends": "@radroots/tsconfig/tsconfig.esm.json", "compilerOptions": { + "module": "CommonJS", + "moduleResolution": "Node", "rootDir": "./src", - "outDir": "dist/cjs" + "outDir": "dist/cjs", + "declaration": false, + "declarationMap": false, + "emitDeclarationOnly": false, + "tsBuildInfoFile": "node_modules/.cache/tsc.utils-nostr.cjs.tsbuildinfo" }, "include": ["src"], "exclude": ["node_modules", "dist"] diff --git a/utils-nostr/tsconfig.esm.json b/utils-nostr/tsconfig.esm.json @@ -0,0 +1,13 @@ +{ + "extends": "@radroots/tsconfig/tsconfig.esm.json", + "compilerOptions": { + "moduleResolution": "nodenext", + "rootDir": "./src", + "outDir": "dist/esm", + "declaration": true, + "declarationMap": true, + "declarationDir": "dist/types" + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/utils-nostr/tsconfig.json b/utils-nostr/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "@radroots/tsconfig/tsconfig.esm.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "dist/esm" - }, - "include": ["src"], - "exclude": ["node_modules", "dist"] + "extends": "./tsconfig.esm.json" }