commit 9c6fc86afab20c81118be10bd873999478435439
parent 5759ef7b4f3b7beaae75c930dd3a1c2a9b803c2e
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Thu, 7 Aug 2025 16:03:55 +0000
utils-nostr: restructure library modules. update build process to use tsc with targets for esm and cjs outputs
Diffstat:
28 files changed, 215 insertions(+), 976 deletions(-)
diff --git a/utils-nostr/.gitignore b/utils-nostr/.gitignore
@@ -43,5 +43,8 @@ vite.config.ts.timestamp-*
.vscode
notes*.txt
notes*.md
-git-diff.txt
+notes*.json
+git-diff*.txt
+prompt*.txt
+tree*.txt
justfile
\ No newline at end of file
diff --git a/utils-nostr/package.json b/utils-nostr/package.json
@@ -1,25 +1,29 @@
{
"name": "@radroots/utils-nostr",
- "version": "0.0.0",
+ "version": "0.0.1",
"private": true,
"type": "module",
- "main": "dist/index.js",
- "module": "dist/index.js",
- "types": "dist/index.d.ts",
+ "main": "./dist/cjs/index.cjs",
+ "module": "./dist/esm/index.js",
+ "types": "./dist/types/index.d.ts",
"exports": {
".": {
- "import": "./dist/index.js",
- "require": "./dist/index.cjs"
+ "types": "./dist/types/index.d.ts",
+ "import": "./dist/esm/index.js",
+ "require": "./dist/cjs/index.js"
}
},
"scripts": {
- "build": "tsup",
- "dev": "tsup --watch",
+ "build:esm": "tsc -p tsconfig.esm.json",
+ "build:cjs": "tsc -p tsconfig.cjs.json",
+ "build": "npm run clean && npm run build:esm && npm run build:cjs",
+ "prebuild": "npm run clean",
+ "clean": "rimraf dist && rimraf tsconfig.tsbuildinfo",
+ "dev": "npm run watch",
"watch": "tsc -w"
},
"devDependencies": {
- "@types/uuid": "^10.0.0",
- "tsup": "^6.2.3",
+ "rimraf": "^6.0.1",
"typescript": "5.8.3"
},
"publishConfig": {
@@ -28,10 +32,9 @@
"dependencies": {
"@noble/curves": "^1.6.0",
"@noble/hashes": "^1.4.0",
- "@nostr-dev-kit/ndk": "^2.11.0",
+ "@nostr-dev-kit/ndk": "2.14.33",
"@radroots/radroots-common-bindings": "*",
"nostr-geotags": "*",
- "nostr-tools": "^2.10.4",
- "uuid": "^10.0.0"
+ "nostr-tools": "^2.10.4"
}
}
\ No newline at end of file
diff --git a/utils-nostr/src/events/lib.ts b/utils-nostr/src/events/lib.ts
@@ -0,0 +1,4 @@
+import { NDKTag } from "@nostr-dev-kit/ndk";
+
+export const get_event_tag = (tags: NDKTag[], key: string): string => tags.find(t => t[0] === key)?.[1] ?? '';
+export const get_event_tags = (tags: NDKTag[], key: string): NDKTag[] => tags.filter(t => t[0] === key);
diff --git a/utils-nostr/src/events/parse.ts b/utils-nostr/src/events/parse.ts
@@ -0,0 +1,17 @@
+import { NDKEvent } from "@nostr-dev-kit/ndk";
+import { nostr_event_metadata_schema } from "../schemas/lib.js";
+import { type NostrEventMetadata } from "../types/lib.js";
+
+export const parse_nostr_metadata_event = (event: NDKEvent): NostrEventMetadata | undefined => {
+ if (!event || typeof event.content !== 'string' || event.kind !== 0) return undefined;
+
+ try {
+ const parsed = JSON.parse(event.content);
+ const result = nostr_event_metadata_schema.parse(parsed);
+ return result;
+ } catch {
+ return undefined;
+ }
+};
+
+
diff --git a/utils-nostr/src/events/subscription.ts b/utils-nostr/src/events/subscription.ts
@@ -0,0 +1,22 @@
+import { NDKEvent } from "@nostr-dev-kit/ndk";
+import { type NostrEventMetadata } from "../types/lib.js";
+import { parse_nostr_metadata_event } from "./parse.js";
+
+export type NdkEventPayload =
+ | { kind: 0; metadata: NostrEventMetadata; }
+
+export const on_ndk_event = (event: NDKEvent): NdkEventPayload | undefined => {
+ if (!event || typeof event.kind !== 'number') return undefined;
+
+ switch (event.kind) {
+ case 0: {
+ const data = parse_nostr_metadata_event(event);
+ if (!data) return;
+ return { kind: event.kind, metadata: data };
+ };
+
+ default: return undefined;
+ }
+};
+
+
diff --git a/utils-nostr/src/index.ts b/utils-nostr/src/index.ts
@@ -1,14 +1,6 @@
-export * from "./lib/events"
-export * from "./lib/keys"
-export * from "./lib/ndk"
-export * from "./lib/relay"
-export * from "./lib/tags"
-export * from "./lib/types"
-export * from "./services/events/lib"
-export * from "./services/events/types"
-export * from "./services/keys/lib"
-export * from "./services/keys/types"
-export * from "./services/relay/lib"
-export * from "./services/relay/types"
-export * from "./types"
-export * from "./util"
+export * from "./events/lib.js"
+export * from "./events/parse.js"
+export * from "./events/subscription.js"
+export * from "./keys/lib.js"
+export * from "./schemas/lib.js"
+export * from "./types/lib.js"
diff --git a/utils-nostr/src/keys/lib.ts b/utils-nostr/src/keys/lib.ts
@@ -0,0 +1,94 @@
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
+import { generateSecretKey, getPublicKey, nip19 } from "nostr-tools";
+
+export const regex_nostr_key = /^[a-f0-9]{64}$/;
+
+export const lib_nostr_get_key_bytes = (hex: string): Uint8Array => {
+ return hexToBytes(hex);
+};
+
+export const lib_nostr_get_key_hex = (bytes: Uint8Array): string => {
+ return bytesToHex(bytes);
+};
+
+export const lib_nostr_key_generate = (): string => {
+ const bytes = generateSecretKey();
+ return lib_nostr_get_key_hex(bytes);
+};
+
+export const lib_nostr_npub_encode = (public_key_hex?: string): string | undefined => {
+ try {
+ if (!public_key_hex) return undefined;
+ const npub = nip19.npubEncode(public_key_hex)
+ return npub;
+ } catch {
+ return undefined;
+ }
+};
+
+export const lib_nostr_npub_decode = (npub?: string): string | undefined => {
+ try {
+ if (!npub) return undefined;
+ const { type, data } = nip19.decode(npub);
+ if (type === `npub` && data) return data;
+ } catch {
+ return undefined;
+ }
+};
+
+export const lib_nostr_nsec_encode = (secret_key_hex?: string): string | undefined => {
+ try {
+ if (!secret_key_hex) return undefined;
+ const bytes = lib_nostr_get_key_bytes(secret_key_hex);
+ return nip19.nsecEncode(bytes);
+ } catch {
+ return undefined;
+ }
+};
+
+export const lib_nostr_nsec_decode = (nsec?: string): string | undefined => {
+ try {
+ if (!nsec) return undefined;
+ const decode = nip19.decode(nsec);
+ if (decode && decode.type === `nsec` && decode.data) return bytesToHex(decode.data);
+ return undefined;
+ } catch {
+ return undefined;
+ }
+};
+
+export const lib_nostr_nprofile_encode = (public_key_hex: string, relays: string[]): string | undefined => {
+ try {
+ if (!public_key_hex || !relays.length) return undefined;
+ const nprofile = nip19.nprofileEncode({ pubkey: public_key_hex, relays })
+ return nprofile;
+ } catch {
+ return undefined;
+ }
+
+};
+
+export const lib_nostr_nprofile_decode = (nprofile?: string): nip19.ProfilePointer | undefined => {
+ try {
+ if (!nprofile) return undefined;
+ const { type, data } = nip19.decode(nprofile);
+ if (type === `nprofile` && data) return data;
+ } catch {
+ return undefined;
+ }
+};
+
+export const lib_nostr_public_key = (secret_key_hex: string): string => {
+ const bytes = lib_nostr_get_key_bytes(secret_key_hex);
+ return getPublicKey(bytes);
+};
+
+export const lib_nostr_secret_key_validate = (secret_key: string): string | undefined => {
+ try {
+ const signer = new NDKPrivateKeySigner(secret_key);
+ return signer.privateKey;
+ } catch {
+ return undefined;
+ }
+};
+\ No newline at end of file
diff --git a/utils-nostr/src/lib/events.ts b/utils-nostr/src/lib/events.ts
@@ -1,45 +0,0 @@
-import { INostrEventServiceNeventEncode, uuidv4, type INostrEventEventSign } from "$root";
-import { schnorr } from "@noble/curves/secp256k1";
-import { hexToBytes } from "@noble/hashes/utils";
-import { finalizeEvent, getEventHash, nip19, type NostrEvent as NostrToolsEvent } from "nostr-tools";
-
-export const lib_nostr_event_verify = (event: NostrToolsEvent): boolean => {
- const hash = getEventHash(event);
- if (hash !== event.id) return false
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
- return valid;
-};
-
-export const lib_nostr_event_sign = (opts: INostrEventEventSign): NostrToolsEvent => {
- return finalizeEvent(opts.event, hexToBytes(opts.secret_key))
-};
-
-export const lib_nostr_event_sign_attest = (secret_key: string): NostrToolsEvent => {
- return lib_nostr_event_sign({
- secret_key,
- event: {
- kind: 1,
- created_at: Math.floor(Date.now() / 1000),
- tags: [],
- content: uuidv4(),
- },
- });
-};
-
-
-export const lib_nostr_event_verify_serialized = async (event_serialized: string): Promise<{ public_key: string } | undefined> => {
- try {
- const event = JSON.parse(event_serialized);
- const hash = getEventHash(event);
- if (hash !== event.id) return undefined;
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
- if (valid) return { public_key: String(event.pubkey) };
- return undefined;
- } catch {
- return undefined;
- }
-};
-
-export const lib_nostr_nevent_encode = (opts: INostrEventServiceNeventEncode): string => {
- return nip19.neventEncode(opts);
-};
-\ No newline at end of file
diff --git a/utils-nostr/src/lib/keys.ts b/utils-nostr/src/lib/keys.ts
@@ -1,67 +0,0 @@
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
-import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
-import { generateSecretKey, getPublicKey, nip19 } from "nostr-tools";
-
-export const lib_nostr_get_key_bytes = (hex: string): Uint8Array => {
- return hexToBytes(hex);
-};
-
-export const lib_nostr_get_key_hex = (bytes: Uint8Array): string => {
- return bytesToHex(bytes);
-};
-
-export const lib_nostr_key_generate = (): string => {
- const bytes = generateSecretKey();
- return lib_nostr_get_key_hex(bytes);
-};
-
-export const lib_nostr_npub_encode = (public_key_hex?: string): string | undefined => {
- if (!public_key_hex) return undefined;
- const npub = nip19.npubEncode(public_key_hex)
- return npub;
-};
-
-export const lib_nostr_npub_decode = (npub?: string): string | undefined => {
- if (!npub) return undefined;
- const { type, data } = nip19.decode(npub)
- if (type === `npub` && data) return data
-};
-
-export const lib_nostr_nsec_encode = (secret_key_hex?: string): string | undefined => {
- if (!secret_key_hex) return undefined;
- const bytes = lib_nostr_get_key_bytes(secret_key_hex);
- return nip19.nsecEncode(bytes);
-};
-
-export const lib_nostr_nsec_decode = (nsec?: string): string | undefined => {
- if (!nsec) return undefined;
- const decode = nip19.decode(nsec);
- if (decode && decode.type === `nsec` && decode.data) return bytesToHex(decode.data);
- return undefined;
-};
-
-export const lib_nostr_nprofile_encode = (public_key_hex: string, relays: string[]): string | undefined => {
- if (!public_key_hex || !relays.length) return undefined;
- const nprofile = nip19.nprofileEncode({ pubkey: public_key_hex,relays })
- return nprofile;
-};
-
-export const lib_nostr_nprofile_decode = (nprofile?: string): nip19.ProfilePointer | undefined => {
- if (!nprofile) return undefined;
- const { type, data } = nip19.decode(nprofile)
- if (type === `nprofile` && data) return data
-};
-
-export const lib_nostr_public_key = (secret_key_hex: string): string => {
- const bytes = lib_nostr_get_key_bytes(secret_key_hex);
- return getPublicKey(bytes);
-};
-
-export const lib_nostr_secret_key_validate = (secret_key: string): string | undefined => {
- try {
- const signer = new NDKPrivateKeySigner(secret_key);
- return signer.privateKey;
- } catch {
- return undefined;
- }
-};
-\ No newline at end of file
diff --git a/utils-nostr/src/lib/ndk.ts b/utils-nostr/src/lib/ndk.ts
@@ -1,157 +0,0 @@
-import { INostrClassified, INostrComment, INostrFollow, INostrJobRequest, INostrReaction, NostrEventTags, tags_classified, tags_comment, tags_follow_list, tags_job_request, tags_reaction, time_now_ms, type INostrMetadata } from '$root';
-import NDK, { NDKCacheAdapter, NDKEvent, NDKKind, NDKPrivateKeySigner, NDKUser } from '@nostr-dev-kit/ndk';
-
-export type NDKEventFigure<T extends object> = {
- ndk: NDK;
- ndk_user: NDKUser;
- date_published?: Date;
-} & T;
-
-export const create_ndk = (explicitRelayUrls: string[], cacheAdapter?: NDKCacheAdapter): NDK => {
- return new NDK({
- explicitRelayUrls,
- enableOutboxModel: false,
- cacheAdapter
- });
-};
-
-export const create_ndk_signer = (secret_key: string): NDKPrivateKeySigner => {
- return new NDKPrivateKeySigner(secret_key);
-};
-
-export const ndk_init = async (opts: {
- ndk: NDK;
- secret_key: string;
-}): Promise<NDKUser | undefined> => {
- try {
- const { ndk, secret_key } = opts;
- const signer = new NDKPrivateKeySigner(secret_key);
- ndk.signer = signer;
- const user = await signer.user();
- if (user) {
- user.ndk = ndk;
- return user;
- }
- } catch (e) {
- console.log(`(error) ndk_init `, e);
- };
-};
-
-export const ndk_event = async (opts: NDKEventFigure<{
- basis: {
- kind: number;
- content: string;
- tags?: NostrEventTags;
- }
-}>): Promise<NDKEvent | undefined> => {
- try {
- const { ndk: ndk, ndk_user: ndk_user, basis } = opts;
- const time_now = time_now_ms();
- const published_at = opts.date_published ? Math.floor(opts.date_published.getTime() / 1000).toString()
- : time_now.toString()
- const tags: NostrEventTags = [
- ['published_at', published_at],
- ];
- if (basis.tags?.length) tags.push(...basis.tags);
- const ev = new NDKEvent(ndk, {
- kind: basis.kind,
- pubkey: ndk_user.pubkey,
- content: basis.content,
- created_at: time_now,
- tags
- });
- return ev;
- } catch (e) {
- console.log(`(error) ndk_event `, e);
- };
-};
-
-export const ndk_event_metadata = async (opts: NDKEventFigure<{
- data: INostrMetadata
-}>): Promise<NDKEvent | undefined> => {
- const { ndk, ndk_user, data } = opts;
- return await ndk_event({
- ndk,
- ndk_user,
- basis: {
- kind: 0,
- content: JSON.stringify(data),
- },
- });
-};
-
-export const ndk_event_follows = async (opts: NDKEventFigure<{
- data: INostrFollow;
-}>): 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),
- },
- });
-};
-
-export const ndk_event_classified = async (opts: NDKEventFigure<{
- data: INostrClassified;
-}>): Promise<NDKEvent | undefined> => {
- const { ndk, ndk_user, data } = opts;
- return await ndk_event({
- ndk,
- ndk_user,
- basis: {
- kind: NDKKind.Classified,
- content: ``,
- tags: tags_classified(data),
- },
- });
-};
-
-export const ndk_event_job_request = async (opts: NDKEventFigure<{
- data: INostrJobRequest;
-}>): Promise<NDKEvent | undefined> => {
- const { ndk, ndk_user, data } = opts;
- return await ndk_event({
- ndk,
- ndk_user,
- basis: {
- kind: NDKKind.DVMReqDiscoveryNostrContent,
- content: ``,
- tags: tags_job_request(data)
- },
- });
-};
-
-export const ndk_event_reaction = async (opts: NDKEventFigure<{
- data: INostrReaction;
-}>): Promise<NDKEvent | undefined> => {
- const { ndk, ndk_user, data } = opts;
- return await ndk_event({
- ndk,
- ndk_user,
- basis: {
- kind: NDKKind.Reaction,
- content: data.content,
- tags: tags_reaction(data)
- },
- });
-};
-
-export const ndk_event_comment = async (opts: NDKEventFigure<{
- data: INostrComment;
-}>): Promise<NDKEvent | undefined> => {
- const { ndk, ndk_user, data } = opts;
- return await ndk_event({
- ndk,
- ndk_user,
- basis: {
- kind: NDKKind.GenericReply,
- content: data.content,
- tags: tags_comment(data)
- },
- });
-};
-
diff --git a/utils-nostr/src/lib/relay.ts b/utils-nostr/src/lib/relay.ts
@@ -1,45 +0,0 @@
-export type NostrRelayInformationDocument = {
- id?: string;
- name?: string;
- description?: string;
- pubkey?: string;
- contact?: string;
- supported_nips?: number[];
- software?: string;
- version?: string;
- limitation_payment_required?: string;
- limitation_restricted_writes?: boolean;
-}
-
-export type NostrRelayInformationDocumentFields = { [K in keyof NostrRelayInformationDocument]: string; };
-
-export const lib_nostr_relay_parse_information_document = (data: any): NostrRelayInformationDocument | undefined => {
- const obj = typeof data === `string` ? JSON.parse(data) : data;
- return {
- id: typeof obj.id === 'string' ? obj.id : undefined,
- name: typeof obj.name === 'string' ? obj.name : undefined,
- description: typeof obj.description === 'string' ? obj.description : undefined,
- pubkey: typeof obj.pubkey === 'string' ? obj.pubkey : undefined,
- contact: typeof obj.contact === 'string' ? obj.contact : undefined,
- supported_nips: Array.isArray(obj.supported_nips) && obj.supported_nips.every((nip: any) => typeof nip === 'number')
- ? obj.supported_nips
- : undefined,
- software: typeof obj.software === 'string' ? obj.software : undefined,
- version: typeof obj.version === 'string' ? obj.version : undefined,
- limitation_payment_required: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.payment_required === 'string' ? obj.limitation.payment_required : undefined,
- limitation_restricted_writes: obj.limitation && typeof obj.limitation === 'object' && typeof obj.limitation.restricted_writes === 'boolean' ? obj.limitation.restricted_writes : undefined,
- };
-};
-
-export const lib_nostr_relay_build_information_document = (data: any): NostrRelayInformationDocumentFields | undefined => {
- const doc = lib_nostr_relay_parse_information_document(data);
- if (!doc) return;
- const result: Partial<NostrRelayInformationDocumentFields> = {};
- Object.entries(doc).forEach(([key, value]) => {
- if (typeof value === 'boolean') result[key as keyof NostrRelayInformationDocument] = value ? '1' : '0';
- else if (Array.isArray(value)) result[key as keyof NostrRelayInformationDocument] = value.join(', ');
- else if (value === null || value === undefined) result[key as keyof NostrRelayInformationDocument] = '';
- else result[key as keyof NostrRelayInformationDocument] = String(value);
- });
- return result;
-};
-\ No newline at end of file
diff --git a/utils-nostr/src/lib/tags.ts b/utils-nostr/src/lib/tags.ts
@@ -1,150 +0,0 @@
-import { INostrClassified, INostrComment, INostrFollowList, INostrJobRequest, INostrReaction, NostrEventTagClient, NostrEventTagLocation, NostrEventTagMediaUpload, NostrEventTagPrice, NostrEventTagPriceDiscount, NostrEventTagQuantity, type NostrEventTag, type NostrEventTags } from "$root";
-import ngeotags, { type InputData as NostrGeotagsInputData } from "nostr-geotags";
-
-export const tag_client = (opts: NostrEventTagClient, d_tag?: string): NostrEventTag => {
- const tag = [`client`, opts.name];
- if (d_tag) tag.push(`31990:${opts.pubkey}:${d_tag}`);
- tag.push(opts.relay);
- return tag;
-};
-
-export const tags_follow_list = (list: INostrFollowList[]): 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;
- });
-};
-
-export const tag_classified_quantity = (opts: NostrEventTagQuantity): NostrEventTag => {
- const tag = [`quantity`, opts.amt, opts.unit];
- if (opts.label) tag.push(opts.label);
- return tag.map(i => i.toLowerCase());
-};
-
-export const tag_classified_price_discount = (discount: NostrEventTagPriceDiscount): NostrEventTag => {
- const tag = [`price-discount-${Object.keys(discount)[0]}`];
- if (`mass` in discount) tag.push(...Object.values(discount.mass));
- else if (`quantity` in discount) tag.push(...Object.values(discount.quantity));
- else if (`subtotal` in discount) tag.push(...Object.values(discount.subtotal));
- else if (`total` in discount) tag.push(...Object.values(discount.total));
- return tag.map(i => i.toLowerCase());
-};
-
-export const tag_classified_price = (price: NostrEventTagPrice): NostrEventTag => {
- const tag = [`price`, price.amt, price.currency, price.qty_amt, price.qty_unit, price.qty_key];
- return tag.map(i => i.toLowerCase());
-};
-
-export const tag_classified_image = (opts: NostrEventTagMediaUpload): NostrEventTag => {
- const tag = [`image`, opts.url];
- if (opts.size) tag.push(`${opts.size.w}x${opts.size.h}`)
- return tag;
-};
-
-export const tag_classified_location = (opts: NostrEventTagLocation): NostrEventTag => {
- if (!opts.primary) return [];
- const tag = [`location`, opts.primary];
- if (opts.city) tag.push(opts.city);
- if (opts.region) tag.push(opts.region);
- if (opts.country) tag.push(opts.country);
- return tag;
-};
-
-export const tags_classified_location_geotags = (opts: NostrEventTagLocation): NostrEventTags => {
- const { lat, lng: lon, city, region: regionName, country } = opts;
- const country_raw = country || ``;
- const countryCode = country_raw && country_raw?.length <= 3 ? country_raw : undefined;
- const countryName = country_raw && country_raw?.length > 3 ? country_raw : undefined;
- return ngeotags({ lat, lon, city, regionName, countryCode, countryName } satisfies NostrGeotagsInputData, { geohash: true, gps: true, city: true, iso31662: true });
-};
-
-export const tags_classified = (opts: INostrClassified): NostrEventTags => {
- const { d_tag, listing, quantities, prices } = opts;
- const tags: NostrEventTags = [[`d`, d_tag]];
- if (opts.client) tags.push(tag_client(opts.client, opts.d_tag));
- for (const [k, v] of Object.entries(listing)) if (v) tags.push([k, v]);
- for (const quantity of quantities) {
- tags.push(tag_classified_quantity(quantity));
- }
- for (const price of prices) {
- tags.push(tag_classified_price(price));
- }
- for (const discount of opts.discounts || []) {
- tags.push(tag_classified_price_discount(discount));
- }
- if (opts.location) {
- tags.push(tag_classified_location(opts.location));
- tags.push(...tags_classified_location_geotags(opts.location));
- }
- if (opts.images) for (const image_tags of opts.images) tags.push(tag_classified_image(image_tags));
- return tags;
-};
-
-export const tags_job_request = (opts: INostrJobRequest): NostrEventTags => {
- const tag_i: string[] = [`i`];
- if (`classified` in opts.input && opts.input?.classified) {
- const { classified: event_request } = opts.input;
- let marker = `*`;
- let data = `*`;
- if (event_request.marker && `order` in event_request.marker) {
- marker = `order`;
- data = JSON.stringify({ event: { id: event_request.id }, order: event_request.marker.order });
- }
- tag_i.push(...[data, `text`, event_request.relay, marker]);
- tag_i.push(...(opts.input.tags || []))
- }
-
- const tags: NostrEventTags = [tag_i];
- tags.push(...(opts.tags || []))
- return tags;
-};
-
-export const tags_reaction = (opts: INostrReaction): NostrEventTags => {
- const { ref_event } = opts;
- const ref_kind = ref_event.kind.toString();
- const ref_author = ref_event.author;
- const tags: NostrEventTags = [
- [`e`, ref_event.id, ...ref_event.relays || ``],
- [`p`, ref_author],
- [`k`, ref_kind],
- ];
- if (ref_event.d_tag) tags.push([`a`, `${ref_kind}:${ref_author}:${ref_event.d_tag}`, ...ref_event.relays || ``])
- return tags;
-};
-
-export const tags_comment = (opts: INostrComment): NostrEventTags => {
- const { root_event, ref_event } = opts;
-
- const root = {
- kind: root_event.kind.toString(),
- author: root_event.author,
- id: root_event.id,
- d_tag: root_event.d_tag,
- relays: root_event.relays || [],
- };
-
- const parent = (ref_event && ref_event.id)
- ? {
- kind: ref_event.kind.toString(),
- author: ref_event.author,
- id: ref_event.id,
- d_tag: ref_event.d_tag,
- relays: ref_event.relays || [],
- }
- : root;
-
- const tags: NostrEventTags = [
- ["E", root.id, ...root.relays],
- ["P", root.author],
- ["K", root.kind],
- ...(root.d_tag ? [["A", `${root.kind}:${root.author}:${root.d_tag}`, ...root.relays]] : []),
- ["e", parent.id, ...parent.relays],
- ["p", parent.author],
- ["k", parent.kind],
- ...(parent.d_tag ? [["a", `${parent.kind}:${parent.author}:${parent.d_tag}`, ...parent.relays]] : []),
- ];
-
- return tags;
-};
-\ No newline at end of file
diff --git a/utils-nostr/src/lib/types.ts b/utils-nostr/src/lib/types.ts
@@ -1,156 +0,0 @@
-import { NostrEventReferenced } from "$root";
-import { ListingOrder } from "@radroots/radroots-common-bindings";
-import { type EventTemplate as NostrToolsEventTemplate } from "nostr-tools";
-
-export type INostrMetadata = {
- name?: string;
- display_name?: string;
- about?: string;
- website?: string;
- picture?: string;
- banner?: string;
- nip05?: string;
- lud06?: string;
- lud16?: string;
- bot?: boolean;
-};
-
-export type INostrFollowList = {
- public_key: string;
- relay_url?: string;
- contact_name?: string;
-};
-
-export type INostrFollow = {
- list: INostrFollowList[]
-};
-
-export type NostrEventTagQuantity = {
- amt: string;
- unit: string;
- label?: string;
-};
-
-export type NostrEventTagPriceDiscount = (
- {
- quantity: {
- ref_quantity: string;
- threshold: string;
- value: string;
- currency: string;
- }
- } |
- {
- mass: {
- unit: string;
- threshold: string;
- threshold_unit: string;
- value: string;
- currency: string;
- }
- } |
- {
- subtotal: {
- threshold: string;
- currency: string;
- value: string;
- measure: string;
- }
- } |
- {
- total: {
- total_min: string;
- value: string;
- measure: string;
- }
- }
-);
-
-export type NostrEventTagPrice = {
- amt: string;
- currency: string;
- qty_amt: string;
- qty_unit: string;
- qty_key: string;
-};
-
-export type INostrClassified = {
- d_tag: string;
- listing: NostrEventTagListing;
- quantities: NostrEventTagQuantity[];
- prices: NostrEventTagPrice[];
- discounts?: NostrEventTagPriceDiscount[];
- location?: NostrEventTagLocation;
- images?: NostrEventTagMediaUpload[];
- client?: NostrEventTagClient;
-};
-
-export type NostrJobRequestMassUnit = 'g' | 'kg' | 'lb';
-
-export type INostrJobRequestInput = {
- tags?: string[];
-} & ({
- classified: {
- id: string;
- relay: string;
- marker?: ({
- order: ListingOrder;
- });
- }
-})
-
-export type INostrJobRequest = {
- input: INostrJobRequestInput;
- tags?: string[][];
-};
-
-export type INostrEventEventSign = {
- secret_key: string;
- event: NostrToolsEventTemplate;
-}
-
-export type NostrEventTagListing = {
- key: string;
- title: string;
- category: string;
- summary?: string;
- process?: string;
- lot?: string;
- location?: string;
- profile?: string;
- year?: string;
-};
-
-export type NostrEventTagLocation = {
- primary: string;
- city?: string;
- region?: string;
- country?: string;
- lat?: number;
- lng?: number;
-};
-
-export type NostrEventTagMediaUpload = {
- url: string;
- size?: {
- w: number;
- h: number;
- };
-};
-
-export type NostrEventTagClient = {
- name: string;
- pubkey: string;
- relay: string;
-};
-
-export type INostrReaction = {
- ref_event: NostrEventReferenced;
- content: string;
-};
-
-export type INostrComment = {
- root_event: NostrEventReferenced;
- ref_event?: NostrEventReferenced;
- content: string;
-};
-\ No newline at end of file
diff --git a/utils-nostr/src/schemas/lib.ts b/utils-nostr/src/schemas/lib.ts
@@ -0,0 +1,14 @@
+import { z } from 'zod';
+
+export const nostr_event_metadata_schema = z.object({
+ name: z.string(),
+ display_name: z.string().optional(),
+ about: z.string().optional(),
+ website: z.url().optional(),
+ picture: z.url().optional(),
+ banner: z.url().optional(),
+ nip05: z.string().optional(),
+ lud06: z.string().optional(),
+ lud16: z.string().optional(),
+ bot: z.boolean().optional(),
+});
diff --git a/utils-nostr/src/services/events/lib.ts b/utils-nostr/src/services/events/lib.ts
@@ -1,79 +0,0 @@
-import { err_msg, ErrorMessage, INostrClassified, INostrEventEventSign, INostrEventService, INostrEventServiceEventResolve, INostrEventServiceNeventEncode, INostrFollow, INostrMetadata, lib_nostr_event_sign, lib_nostr_event_sign_attest, lib_nostr_event_verify, lib_nostr_event_verify_serialized, lib_nostr_nevent_encode, ndk_event, ndk_event_classified, ndk_event_follows } from "$root";
-import NDK, { NDKKind, NDKUser, type NDKEvent } from "@nostr-dev-kit/ndk";
-import { type NostrEvent as NostrToolsEvent } from "nostr-tools";
-
-export class NostrEventService implements INostrEventService {
- private resolve_ndk_user = async (ndk: NDK): Promise<NDKUser | ErrorMessage<string>> => {
- const user = await ndk.signer?.user();
- if (!user) return err_msg(`error.ndk.user_undefined`);
- return user;
- }
-
- private resolve_ndk_event = (ev?: NDKEvent) => {
- if (!ev) return err_msg(`error.event_undefined`);
- return ev;
- }
-
- public first_tag_value = (event: NDKEvent, tag_name: string): string => {
- const tag = event.getMatchingTags(tag_name)[0];
- return tag ? tag[1] : "";
- }
-
- public nostr_event_sign = (opts: INostrEventEventSign): NostrToolsEvent => {
- return lib_nostr_event_sign(opts);
- };
-
- public nostr_event_sign_attest = (secret_key: string): NostrToolsEvent => {
- return lib_nostr_event_sign_attest(secret_key);
- };
-
- public nostr_event_verify = (event: NostrToolsEvent): boolean => {
- return lib_nostr_event_verify(event);
- };
-
- public nostr_event_verify_serialized = (event_serialized: string): boolean => {
- const result = lib_nostr_event_verify_serialized(event_serialized);
- return !!result;
- };
-
- public nevent_encode = (opts: INostrEventServiceNeventEncode): string => {
- return lib_nostr_nevent_encode(opts);
- };
-
- public metadata = async (ndk: NDK, opts: INostrMetadata): Promise<INostrEventServiceEventResolve> => {
- const ndk_user = await this.resolve_ndk_user(ndk);
- if (`err` in ndk_user) return ndk_user;
- const ev = await ndk_event({
- ndk,
- ndk_user,
- basis: {
- kind: NDKKind.Metadata,
- content: JSON.stringify(opts),
- },
- });
- return this.resolve_ndk_event(ev);
- }
-
- public follows = async (ndk: NDK, data: INostrFollow): Promise<INostrEventServiceEventResolve> => {
- const ndk_user = await this.resolve_ndk_user(ndk);
- if (`err` in ndk_user) return ndk_user;
- const ev = await ndk_event_follows({
- ndk,
- ndk_user,
- data
- });
- return this.resolve_ndk_event(ev);
- }
-
- public classified = async (ndk: NDK, data: INostrClassified): Promise<INostrEventServiceEventResolve> => {
- const ndk_user = await this.resolve_ndk_user(ndk);
- if (`err` in ndk_user) return ndk_user;
- const ev = await ndk_event_classified({
- ndk,
- ndk_user,
- data
- });
- return this.resolve_ndk_event(ev);
- }
-}
-
diff --git a/utils-nostr/src/services/events/types.ts b/utils-nostr/src/services/events/types.ts
@@ -1,24 +0,0 @@
-import type { INostrClassified, INostrEventEventSign, INostrFollow, INostrMetadata, ResolveError } from "$root";
-import NDK, { NDKEvent } from "@nostr-dev-kit/ndk";
-import { type NostrEvent as NostrToolsEvent } from "nostr-tools";
-
-export type INostrEventServiceNeventEncode = {
- id: string;
- relays: string[];
- author: string;
- kind: number;
-};
-
-export type INostrEventServiceEventResolve = ResolveError<NDKEvent>;
-
-export type INostrEventService = {
- first_tag_value(event: NDKEvent, tag_name: string): string;
- nostr_event_sign: (opts: INostrEventEventSign) => NostrToolsEvent;
- nostr_event_sign_attest: (secret_key: string) => NostrToolsEvent;
- nostr_event_verify_serialized: (event_serialized: string) => boolean;
- nostr_event_verify: (event: NostrToolsEvent) => boolean;
- nevent_encode: (opts: INostrEventServiceNeventEncode) => string;
- metadata: (ndk: NDK, opts: INostrMetadata) => Promise<INostrEventServiceEventResolve>;
- follows: (ndk: NDK, opts: INostrFollow) => Promise<INostrEventServiceEventResolve>;
- classified: (ndk: NDK, opts: INostrClassified) => Promise<INostrEventServiceEventResolve>;
-};
diff --git a/utils-nostr/src/services/keys/lib.ts b/utils-nostr/src/services/keys/lib.ts
@@ -1,120 +0,0 @@
-import { type INostrKeyService, lib_nostr_get_key_bytes, lib_nostr_key_generate, lib_nostr_nsec_decode, lib_nostr_nsec_encode } from '$root';
-import { getPublicKey, nip19 } from 'nostr-tools';
-
-export class NostrKeyService implements INostrKeyService {
- /**
- *
- * @returns nostr secret key hex
- */
- public generate_key(): string {
- return lib_nostr_key_generate();
- };
-
-
- /**
- *
- * @returns nostr public key hex from secret key
- */
- public public_key(secret_key_hex: string | undefined): string {
- try {
- if (!secret_key_hex) return ``;
- const bytes = lib_nostr_get_key_bytes(secret_key_hex);
- const hex = getPublicKey(bytes)
- return hex;
- } catch (e) {
- return ``
- }
- }
-
- /**
- *
- * @returns nostr secret key to public key hex
- */
- public publickey_decode(secret_key_hex?: string): string | undefined {
- try {
- if (secret_key_hex) {
- return getPublicKey(lib_nostr_get_key_bytes(secret_key_hex))
- }
- return undefined;
- } catch (e) {
- return undefined;
- }
- }
-
- /**
- *
- * @returns nostr public key npub
- */
- public npub(public_key_hex: string | undefined, fallback_to_hex?: boolean): string {
- if (!public_key_hex) return ``;
- const npub = nip19.npubEncode(public_key_hex);
- return npub ? npub : fallback_to_hex ? public_key_hex : ``;
- }
-
- /**
- *
- * @returns public key hex from npub
- */
- public npub_decode(npub: string): string {
- const decode = nip19.decode(npub);
- if (decode && decode.type === `npub` && decode.data) return decode.data
- return ``;
- }
-
- /**
- *
- * @returns nostr secret key nsec
- */
- public nsec(secret_key_hex?: string): string | undefined {
- return lib_nostr_nsec_encode(secret_key_hex);
- }
-
- /**
- *
- * @returns nostr secret key hex from nsec
- */
- public nsec_decode(nsec: string): string | undefined {
- return lib_nostr_nsec_decode(nsec);
- }
-
- /**
- *
- * @returns
- */
- public nevent(event_pointer: nip19.EventPointer, relays: string[]): string {
- return nip19.neventEncode(event_pointer)
- }
-
- /**
- *
- * @returns nostr public key nprofile
- */
- public nprofile(public_key_hex: string, relays: string[]): string {
- if (!public_key_hex || !relays.length) return ``;
- return nip19.nprofileEncode({ pubkey: public_key_hex, relays })
- }
-
- /**
- *
- * @returns nostr public key nprofile
- */
- public nprofile_decode(nprofile: string): [string, string[]] | undefined {
- if (!nprofile) return undefined;
- const decode = nip19.decode(nprofile);
- if (decode && decode.type === `nprofile` && decode.data && decode.data.pubkey && decode.data.relays) return [decode.data.pubkey, decode.data.relays]
- return undefined;
- }
-
- /**
- *
- * @returns
- */
- public secretkey_to_publickey(nsec_or_hex: string): string | undefined {
- if (nsec_or_hex.startsWith(`nsec1`)) {
- return this.nsec_decode(nsec_or_hex);
- } else if (nsec_or_hex.length === 64) {
- return this.publickey_decode(nsec_or_hex)
- }
- return undefined;
- }
-};
diff --git a/utils-nostr/src/services/keys/types.ts b/utils-nostr/src/services/keys/types.ts
@@ -1,11 +0,0 @@
-export type INostrKeyService = {
- generate_key(): string;
- public_key(secret_key_hex: string | undefined): string;
- npub(public_key_hex: string | undefined): string;
- npub_decode(npub: string): string;
- nsec(secret_key_hex: string | undefined): string | undefined;
- nsec_decode(nsec: string): string | undefined;
- nprofile(public_key_hex: string, relays: string[]): string;
- nprofile_decode(nprofile: string): [string, string[]] | undefined;
- secretkey_to_publickey(nsec_or_hex: string): string | undefined;
-};
diff --git a/utils-nostr/src/services/relay/lib.ts b/utils-nostr/src/services/relay/lib.ts
@@ -1,16 +0,0 @@
-import { lib_nostr_relay_parse_information_document, type INostrRelayService, type NostrRelayInformationDocument, type NostrRelayInformationDocumentFields } from "$root";
-
-export class NostrRelayService implements INostrRelayService {
- public parse_information_document = (data: any): NostrRelayInformationDocumentFields | undefined => {
- const doc = lib_nostr_relay_parse_information_document(data);
- if (!doc) return;
- const result: Partial<NostrRelayInformationDocumentFields> = {};
- Object.entries(doc).forEach(([key, value]) => {
- if (typeof value === 'boolean') result[key as keyof NostrRelayInformationDocument] = value ? '1' : '0';
- else if (Array.isArray(value)) result[key as keyof NostrRelayInformationDocument] = value.join(', ');
- else if (value === null || value === undefined) result[key as keyof NostrRelayInformationDocument] = '';
- else result[key as keyof NostrRelayInformationDocument] = String(value);
- });
- return result;
- };
-}
-\ No newline at end of file
diff --git a/utils-nostr/src/services/relay/types.ts b/utils-nostr/src/services/relay/types.ts
@@ -1,6 +0,0 @@
-import { type NostrRelayInformationDocumentFields } from "$root";
-
-export type INostrRelayService = {
- parse_information_document: (data: any) => NostrRelayInformationDocumentFields | undefined;
-};
-
diff --git a/utils-nostr/src/types.ts b/utils-nostr/src/types.ts
@@ -1,14 +0,0 @@
-import { NDKEvent } from "@nostr-dev-kit/ndk";
-
-export type NostrNdkEvent = NDKEvent;
-export type NostrEventTag = string[];
-export type NostrEventTags = NostrEventTag[];
-export type ErrorMessage<T extends string> = { err: T };
-export type ResolveError<T> = T | ErrorMessage<string>;
-export type NostrEventReferenced = {
- id: string;
- kind: number;
- author: string;
- relays?: string[];
- d_tag?: string;
-}
-\ No newline at end of file
diff --git a/utils-nostr/src/types/lib.ts b/utils-nostr/src/types/lib.ts
@@ -0,0 +1,4 @@
+import { z } from 'zod';
+import { nostr_event_metadata_schema } from "../schemas/lib.js";
+
+export type NostrEventMetadata = z.infer<typeof nostr_event_metadata_schema>;
diff --git a/utils-nostr/src/util.ts b/utils-nostr/src/util.ts
@@ -1,10 +0,0 @@
-import { type ErrorMessage } from "$root";
-import { v4 } from "uuid";
-
-export const time_now_ms = (): number => Math.floor(new Date().getTime() / 1000);
-
-export const uuidv4 = (): string => v4();
-
-export const err_msg = <T extends string>(err: T): ErrorMessage<T> => {
- return { err };
-};
-\ No newline at end of file
diff --git a/utils-nostr/tsconfig.base.json b/utils-nostr/tsconfig.base.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "target": "ES2019",
+ "strict": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "skipLibCheck": true,
+ "sourceMap": false,
+ "rootDir": "src"
+ }
+}
diff --git a/utils-nostr/tsconfig.cjs.json b/utils-nostr/tsconfig.cjs.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "./dist/cjs",
+ "module": "CommonJS",
+ "declaration": false,
+ "moduleResolution": "Node"
+ },
+ "include": ["src"]
+}
diff --git a/utils-nostr/tsconfig.esm.json b/utils-nostr/tsconfig.esm.json
@@ -0,0 +1,12 @@
+{
+ "extends": "./tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "./dist/esm",
+ "module": "NodeNext",
+ "declaration": true,
+ "declarationDir": "./dist/types",
+ "moduleResolution": "NodeNext",
+ "emitDeclarationOnly": false
+ },
+ "include": ["src"]
+}
diff --git a/utils-nostr/tsconfig.json b/utils-nostr/tsconfig.json
@@ -1,28 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "target": "es2021",
- "lib": [
- "es2021",
- "dom"
- ],
- "module": "ESNext",
- "moduleResolution": "node",
- "declaration": true,
- "declarationMap": true,
- "outDir": "./dist",
- "esModuleInterop": true,
- "skipLibCheck": true,
- "baseUrl": ".",
- "paths": {
- "$root": ["src/index.js"]
- }
- },
- "include": [
- "src"
- ],
- "exclude": [
- "node_modules",
- "dist"
- ],
-}
-\ No newline at end of file
diff --git a/utils-nostr/tsup.config.ts b/utils-nostr/tsup.config.ts
@@ -1,11 +0,0 @@
-import { defineConfig } from "tsup";
-
-export default defineConfig({
- entry: ['src/index.ts'],
- format: ['esm', 'cjs'],
- dts: true,
- outDir: 'dist',
- splitting: false,
- clean: true,
- sourcemap: true,
-});