web_lib

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

commit 6694d39692f20dc6d2d2a2d74a84db2b3449599e
parent e86b22e408fd76ac5a976600af98784ef1130e05
Author: triesap <triesap@radroots.dev>
Date:   Mon,  3 Nov 2025 07:28:33 +0000

utils-nostr: introduce trade listing workflow primitives with request and result builders, add job event helpers and tagging utilities, migrate types to events bindings with per-event tag modules, expand public exports, remove an obsolete dependency, and retire legacy price and quantity types

Diffstat:
Mutils-nostr/package.json | 1-
Autils-nostr/src/domain/trade/lib.ts | 25+++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/accept/lib.ts | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/conveyance/lib.ts | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/fulfillment/lib.ts | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/invoice/lib.ts | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/order/lib.ts | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/payment/lib.ts | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/receipt/lib.ts | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/domain/trade/listing/tags.ts | 14++++++++++++++
Autils-nostr/src/domain/trade/tags.ts | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutils-nostr/src/events/comment/lib.ts | 4++--
Mutils-nostr/src/events/comment/parse.ts | 2+-
Autils-nostr/src/events/comment/tags.ts | 38++++++++++++++++++++++++++++++++++++++
Mutils-nostr/src/events/follow/lib.ts | 4++--
Mutils-nostr/src/events/follow/parse.ts | 2+-
Autils-nostr/src/events/follow/tags.ts | 12++++++++++++
Autils-nostr/src/events/job/lib.ts | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/events/job/tags.ts | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils-nostr/src/events/job/utils.ts | 34++++++++++++++++++++++++++++++++++
Mutils-nostr/src/events/listing/lib.ts | 6+++---
Mutils-nostr/src/events/listing/parse.ts | 2+-
Autils-nostr/src/events/listing/tags.ts | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutils-nostr/src/events/profile/lib.ts | 2+-
Mutils-nostr/src/events/profile/parse.ts | 2+-
Mutils-nostr/src/events/reaction/lib.ts | 4++--
Mutils-nostr/src/events/reaction/parse.ts | 2+-
Autils-nostr/src/events/reaction/tags.ts | 16++++++++++++++++
Mutils-nostr/src/index.ts | 17+++++++++++++++++
Mutils-nostr/src/types/lib.ts | 16++--------------
Mutils-nostr/src/utils/tags.ts | 130+++----------------------------------------------------------------------------
31 files changed, 963 insertions(+), 156 deletions(-)

diff --git a/utils-nostr/package.json b/utils-nostr/package.json @@ -36,7 +36,6 @@ "@noble/curves": "^1.6.0", "@noble/hashes": "^1.4.0", "@nostr-dev-kit/ndk": "2.14.33", - "@radroots/radroots-common-bindings": "*", "nostr-geotags": "*", "nostr-tools": "^2.10.4" } diff --git a/utils-nostr/src/domain/trade/lib.ts b/utils-nostr/src/domain/trade/lib.ts @@ -0,0 +1,25 @@ +import { KIND_TRADE_LISTING_ACCEPT_REQ, KIND_TRADE_LISTING_ACCEPT_RES, KIND_TRADE_LISTING_CANCEL_REQ, KIND_TRADE_LISTING_CANCEL_RES, KIND_TRADE_LISTING_CONVEYANCE_REQ, KIND_TRADE_LISTING_CONVEYANCE_RES, KIND_TRADE_LISTING_FULFILL_REQ, KIND_TRADE_LISTING_FULFILL_RES, KIND_TRADE_LISTING_INVOICE_REQ, KIND_TRADE_LISTING_INVOICE_RES, KIND_TRADE_LISTING_ORDER_REQ, KIND_TRADE_LISTING_ORDER_RES, KIND_TRADE_LISTING_PAYMENT_REQ, KIND_TRADE_LISTING_PAYMENT_RES, KIND_TRADE_LISTING_RECEIPT_REQ, KIND_TRADE_LISTING_RECEIPT_RES, KIND_TRADE_LISTING_REFUND_REQ, KIND_TRADE_LISTING_REFUND_RES } from "@radroots/trade-bindings"; + +export const REQUEST_KINDS: Record<string, number> = { + order: KIND_TRADE_LISTING_ORDER_REQ, + accept: KIND_TRADE_LISTING_ACCEPT_REQ, + conveyance: KIND_TRADE_LISTING_CONVEYANCE_REQ, + invoice: KIND_TRADE_LISTING_INVOICE_REQ, + payment: KIND_TRADE_LISTING_PAYMENT_REQ, + fulfillment: KIND_TRADE_LISTING_FULFILL_REQ, + receipt: KIND_TRADE_LISTING_RECEIPT_REQ, + cancel: KIND_TRADE_LISTING_CANCEL_REQ, + refund: KIND_TRADE_LISTING_REFUND_REQ, +}; + +export const RESULT_KINDS: Record<string, number> = { + order: KIND_TRADE_LISTING_ORDER_RES, + accept: KIND_TRADE_LISTING_ACCEPT_RES, + conveyance: KIND_TRADE_LISTING_CONVEYANCE_RES, + invoice: KIND_TRADE_LISTING_INVOICE_RES, + payment: KIND_TRADE_LISTING_PAYMENT_RES, + fulfillment: KIND_TRADE_LISTING_FULFILL_RES, + receipt: KIND_TRADE_LISTING_RECEIPT_RES, + cancel: KIND_TRADE_LISTING_CANCEL_RES, + refund: KIND_TRADE_LISTING_REFUND_RES, +}; diff --git a/utils-nostr/src/domain/trade/listing/accept/lib.ts b/utils-nostr/src/domain/trade/listing/accept/lib.ts @@ -0,0 +1,62 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { RadrootsJobInput } from "@radroots/events-bindings"; +import { KIND_TRADE_LISTING_ACCEPT_REQ, KIND_TRADE_LISTING_ACCEPT_RES, MARKER_LISTING, MARKER_PREVIOUS, TradeListingAcceptRequest, TradeListingAcceptResult } from "@radroots/trade-bindings"; +import { ndk_event } from "../../../../events/lib.js"; +import { NDKEventFigure } from "../../../../types/ndk.js"; +import { + build_request_tags, + build_result_tags, + CommonRequestOpts, + CommonResultOpts, + make_event_input +} from "../../tags.js"; +import { tags_trade_listing_chain } from "../tags.js"; + +export const ndk_event_trade_listing_accept_request = async ( + opts: NDKEventFigure<{ data: TradeListingAcceptRequest; options?: CommonRequestOpts }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data, options } = opts; + + const inputs: RadrootsJobInput[] = [ + make_event_input(data.order_result_event_id, MARKER_PREVIOUS), + make_event_input(data.listing_event_id, MARKER_LISTING), + ]; + + const tags = build_request_tags(KIND_TRADE_LISTING_ACCEPT_REQ, inputs, options); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_ACCEPT_REQ, content: "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; + +export const ndk_event_trade_listing_accept_result = async ( + opts: NDKEventFigure<{ + request_event_id: string; + content: TradeListingAcceptResult | string; + options?: CommonResultOpts; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, content, options } = opts; + + const base_tags = build_result_tags( + KIND_TRADE_LISTING_ACCEPT_RES, + request_event_id, + options + ); + const tags = options?.chain + ? [...base_tags, ...tags_trade_listing_chain(options.chain)] + : base_tags; + + const content_body = typeof content === "string" ? content : JSON.stringify(content); + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_ACCEPT_RES, content: content_body, tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; diff --git a/utils-nostr/src/domain/trade/listing/conveyance/lib.ts b/utils-nostr/src/domain/trade/listing/conveyance/lib.ts @@ -0,0 +1,63 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { RadrootsJobInput } from "@radroots/events-bindings"; +import { KIND_TRADE_LISTING_CONVEYANCE_REQ, KIND_TRADE_LISTING_CONVEYANCE_RES, MARKER_ACCEPT_RESULT, MARKER_PAYLOAD, TradeListingConveyanceRequest, TradeListingConveyanceResult } from "@radroots/trade-bindings"; +import { ndk_event } from "../../../../events/lib.js"; +import { NDKEventFigure } from "../../../../types/ndk.js"; +import { + build_request_tags, + build_result_tags, + CommonRequestOpts, + CommonResultOpts, + make_event_input, + make_text_input, +} from "../../tags.js"; +import { tags_trade_listing_chain } from "../tags.js"; + +export const ndk_event_trade_listing_conveyance_request = async ( + opts: NDKEventFigure<{ data: TradeListingConveyanceRequest; options?: CommonRequestOpts }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data, options } = opts; + + const inputs: RadrootsJobInput[] = [ + make_event_input(data.accept_result_event_id, MARKER_ACCEPT_RESULT), + make_text_input({ method: data.method }, MARKER_PAYLOAD), + ]; + + const tags = build_request_tags(KIND_TRADE_LISTING_CONVEYANCE_REQ, inputs, options); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_CONVEYANCE_REQ, content: "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; + +export const ndk_event_trade_listing_conveyance_result = async ( + opts: NDKEventFigure<{ + request_event_id: string; + content: TradeListingConveyanceResult | string; + options?: CommonResultOpts; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, content, options } = opts; + + const base_tags = build_result_tags( + KIND_TRADE_LISTING_CONVEYANCE_RES, + request_event_id, + options + ); + const tags = options?.chain + ? [...base_tags, ...tags_trade_listing_chain(options.chain)] + : base_tags; + + const content_body = typeof content === "string" ? content : JSON.stringify(content); + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_CONVEYANCE_RES, content: content_body, tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; +\ No newline at end of file diff --git a/utils-nostr/src/domain/trade/listing/fulfillment/lib.ts b/utils-nostr/src/domain/trade/listing/fulfillment/lib.ts @@ -0,0 +1,61 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { RadrootsJobInput } from "@radroots/events-bindings"; +import { KIND_TRADE_LISTING_FULFILL_REQ, KIND_TRADE_LISTING_FULFILL_RES, MARKER_PREVIOUS, TradeListingFulfillmentRequest, TradeListingFulfillmentState } from "@radroots/trade-bindings"; +import { ndk_event } from "../../../../events/lib.js"; +import { NDKEventFigure } from "../../../../types/ndk.js"; +import { + build_request_tags, + build_result_tags, + CommonRequestOpts, + CommonResultOpts, + make_event_input +} from "../../tags.js"; +import { tags_trade_listing_chain } from "../tags.js"; + +export const ndk_event_trade_listing_fulfillment_request = async ( + opts: NDKEventFigure<{ data: TradeListingFulfillmentRequest; options?: CommonRequestOpts }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data, options } = opts; + + const inputs: RadrootsJobInput[] = [ + make_event_input(data.payment_result_event_id, MARKER_PREVIOUS), + ]; + + const tags = build_request_tags(KIND_TRADE_LISTING_FULFILL_REQ, inputs, options); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_FULFILL_REQ, content: "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; + +export const ndk_event_trade_listing_fulfillment_result = async ( + opts: NDKEventFigure<{ + request_event_id: string; + content: TradeListingFulfillmentState | string; + options?: CommonResultOpts; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, content, options } = opts; + + const base_tags = build_result_tags( + KIND_TRADE_LISTING_FULFILL_RES, + request_event_id, + options + ); + const tags = options?.chain + ? [...base_tags, ...tags_trade_listing_chain(options.chain)] + : base_tags; + + const content_body = typeof content === "string" ? content : JSON.stringify(content); + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_FULFILL_RES, content: content_body, tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; +\ No newline at end of file diff --git a/utils-nostr/src/domain/trade/listing/invoice/lib.ts b/utils-nostr/src/domain/trade/listing/invoice/lib.ts @@ -0,0 +1,73 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { RadrootsJobInput } from "@radroots/events-bindings"; +import { KIND_TRADE_LISTING_INVOICE_REQ, KIND_TRADE_LISTING_INVOICE_RES, MARKER_ACCEPT_RESULT, TradeListingInvoiceRequest, TradeListingInvoiceResult } from "@radroots/trade-bindings"; +import { ndk_event } from "../../../../events/lib.js"; +import { NDKEventFigure } from "../../../../types/ndk.js"; +import { + build_request_tags, + build_result_tags, + CommonRequestOpts, + CommonResultOpts, + make_event_input +} from "../../tags.js"; +import { tags_trade_listing_chain } from "../tags.js"; + +export const ndk_event_trade_listing_invoice_request = async ( + opts: NDKEventFigure<{ data: TradeListingInvoiceRequest; options?: CommonRequestOpts }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data, options } = opts; + + const inputs: RadrootsJobInput[] = [ + make_event_input(data.accept_result_event_id, MARKER_ACCEPT_RESULT), + ]; + + const tags = build_request_tags(KIND_TRADE_LISTING_INVOICE_REQ, inputs, options); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_INVOICE_REQ, content: "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; + +export const ndk_event_trade_listing_invoice_result = async ( + opts: NDKEventFigure<{ + request_event_id: string; + content: TradeListingInvoiceResult | string; + options?: Omit<CommonResultOpts, "payment_sat" | "payment_bolt11"> & { + chain?: { e_root: string; d?: string; e_prev?: string }; + }; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, content, options } = opts; + + const parsed: TradeListingInvoiceResult | undefined = + typeof content === "string" ? undefined : (content as TradeListingInvoiceResult); + + const base_tags = build_result_tags( + KIND_TRADE_LISTING_INVOICE_RES, + request_event_id, + options, + parsed + ? { + payment_sat: parsed.total_sat, + payment_bolt11: parsed.bolt11, + } + : undefined + ); + + const tags = options?.chain + ? [...base_tags, ...tags_trade_listing_chain(options.chain)] + : base_tags; + + const content_body = typeof content === "string" ? content : JSON.stringify(content); + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_INVOICE_RES, content: content_body, tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; +\ No newline at end of file diff --git a/utils-nostr/src/domain/trade/listing/order/lib.ts b/utils-nostr/src/domain/trade/listing/order/lib.ts @@ -0,0 +1,70 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { RadrootsJobInput } from "@radroots/events-bindings"; +import { KIND_TRADE_LISTING_ORDER_REQ, KIND_TRADE_LISTING_ORDER_RES, MARKER_LISTING, MARKER_PAYLOAD, TradeListingOrderResult, type TradeListingOrderRequest } from "@radroots/trade-bindings"; +import { ndk_event } from "../../../../events/lib.js"; +import { NDKEventFigure } from "../../../../types/ndk.js"; +import { + build_request_tags, + build_result_tags, + CommonRequestOpts, + CommonResultOpts, + make_event_input, + make_text_input, +} from "../../tags.js"; +import { tags_trade_listing_chain } from "../tags.js"; + +export const ndk_event_trade_listing_order_request = async ( + opts: NDKEventFigure<{ data: TradeListingOrderRequest; options?: CommonRequestOpts }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data, options } = opts; + + const inputs: RadrootsJobInput[] = [ + make_event_input(data.event.id, MARKER_LISTING), + make_text_input(data.payload, MARKER_PAYLOAD), + ]; + + const tags = build_request_tags(KIND_TRADE_LISTING_ORDER_REQ, inputs, options); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_ORDER_REQ, content: "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; + +export const ndk_event_trade_listing_order_result = async ( + opts: NDKEventFigure<{ + request_event_id: string; + content: TradeListingOrderResult | string; + options?: CommonResultOpts; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, content, options } = opts; + + const include_inputs = + options?.include_inputs && !options.encrypted + ? options.include_inputs.map(s => make_text_input(s, MARKER_PAYLOAD)) + : []; + + const base_tags = build_result_tags( + KIND_TRADE_LISTING_ORDER_RES, + request_event_id, + options, + { inputs: include_inputs } + ); + + const tags = options?.chain + ? [...base_tags, ...tags_trade_listing_chain(options.chain)] + : base_tags; + + const content_body = typeof content === "string" ? content : JSON.stringify(content); + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_ORDER_RES, content: content_body, tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; diff --git a/utils-nostr/src/domain/trade/listing/payment/lib.ts b/utils-nostr/src/domain/trade/listing/payment/lib.ts @@ -0,0 +1,63 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { RadrootsJobInput } from "@radroots/events-bindings"; +import { KIND_TRADE_LISTING_PAYMENT_REQ, KIND_TRADE_LISTING_PAYMENT_RES, MARKER_INVOICE_RESULT, MARKER_PROOF, TradeListingPaymentProofRequest, TradeListingPaymentResult } from "@radroots/trade-bindings"; +import { ndk_event } from "../../../../events/lib.js"; +import { NDKEventFigure } from "../../../../types/ndk.js"; +import { + build_request_tags, + build_result_tags, + CommonRequestOpts, + CommonResultOpts, + make_event_input, + make_text_input, +} from "../../tags.js"; +import { tags_trade_listing_chain } from "../tags.js"; + +export const ndk_event_trade_listing_payment_request = async ( + opts: NDKEventFigure<{ data: TradeListingPaymentProofRequest; options?: CommonRequestOpts }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data, options } = opts; + + const inputs: RadrootsJobInput[] = [ + make_event_input(data.invoice_result_event_id, MARKER_INVOICE_RESULT), + make_text_input(data.proof, MARKER_PROOF), + ]; + + const tags = build_request_tags(KIND_TRADE_LISTING_PAYMENT_REQ, inputs, options); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_PAYMENT_REQ, content: "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; + +export const ndk_event_trade_listing_payment_result = async ( + opts: NDKEventFigure<{ + request_event_id: string; + content: TradeListingPaymentResult | string; + options?: CommonResultOpts; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, content, options } = opts; + + const base_tags = build_result_tags( + KIND_TRADE_LISTING_PAYMENT_RES, + request_event_id, + options + ); + const tags = options?.chain + ? [...base_tags, ...tags_trade_listing_chain(options.chain)] + : base_tags; + + const content_body = typeof content === "string" ? content : JSON.stringify(content); + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_PAYMENT_RES, content: content_body, tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; diff --git a/utils-nostr/src/domain/trade/listing/receipt/lib.ts b/utils-nostr/src/domain/trade/listing/receipt/lib.ts @@ -0,0 +1,63 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { RadrootsJobInput } from "@radroots/events-bindings"; +import { KIND_TRADE_LISTING_RECEIPT_REQ, KIND_TRADE_LISTING_RECEIPT_RES, MARKER_FULFILLMENT_RESULT, MARKER_PAYLOAD, TradeListingReceiptRequest, TradeListingReceiptResult } from "@radroots/trade-bindings"; +import { ndk_event } from "../../../../events/lib.js"; +import { NDKEventFigure } from "../../../../types/ndk.js"; +import { + build_request_tags, + build_result_tags, + CommonRequestOpts, + CommonResultOpts, + make_event_input, + make_text_input, +} from "../../tags.js"; +import { tags_trade_listing_chain } from "../tags.js"; + +export const ndk_event_trade_listing_receipt_request = async ( + opts: NDKEventFigure<{ data: TradeListingReceiptRequest; options?: CommonRequestOpts }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data, options } = opts; + + const inputs: RadrootsJobInput[] = [ + make_event_input(data.fulfillment_result_event_id, MARKER_FULFILLMENT_RESULT), + ...(data.note ? [make_text_input({ note: data.note }, MARKER_PAYLOAD)] : []), + ]; + + const tags = build_request_tags(KIND_TRADE_LISTING_RECEIPT_REQ, inputs, options); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_RECEIPT_REQ, content: "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; + +export const ndk_event_trade_listing_receipt_result = async ( + opts: NDKEventFigure<{ + request_event_id: string; + content: TradeListingReceiptResult | string; + options?: CommonResultOpts; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, content, options } = opts; + + const base_tags = build_result_tags( + KIND_TRADE_LISTING_RECEIPT_RES, + request_event_id, + options + ); + const tags = options?.chain + ? [...base_tags, ...tags_trade_listing_chain(options.chain)] + : base_tags; + + const content_body = typeof content === "string" ? content : JSON.stringify(content); + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_TRADE_LISTING_RECEIPT_RES, content: content_body, tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; diff --git a/utils-nostr/src/domain/trade/listing/tags.ts b/utils-nostr/src/domain/trade/listing/tags.ts @@ -0,0 +1,14 @@ +import { TAG_D, TAG_E_PREV, TAG_E_ROOT } from "@radroots/events-bindings"; +import { NostrEventTags } from "../../../types/lib.js"; + +export const tags_trade_listing_chain = (opts: { + e_root: string; + d?: string; + e_prev?: string; +}): NostrEventTags => { + const tags: NostrEventTags = []; + tags.push([TAG_E_ROOT, opts.e_root]); + if (opts.e_prev) tags.push([TAG_E_PREV, opts.e_prev]); + if (opts.d) tags.push([TAG_D, opts.d]); + return tags; +}; diff --git a/utils-nostr/src/domain/trade/tags.ts b/utils-nostr/src/domain/trade/tags.ts @@ -0,0 +1,88 @@ +import { JobInputType, RadrootsJobInput } from "@radroots/events-bindings"; +import { tags_job_request, tags_job_result } from "../../events/job/tags.js"; + +export type CommonRequestOpts = { + output?: string; + bid_sat?: number; + relays?: string[]; + providers?: string[]; + topics?: string[]; + encrypted?: boolean; + params?: Array<{ key: string; value: string }>; +}; + +export type CommonResultOpts = { + request_relay_hint?: string; + request_json?: string; + customer_pubkey?: string; + payment_sat?: number; + payment_bolt11?: string; + encrypted?: boolean; + include_inputs?: string[]; + chain?: { e_root: string; d?: string; e_prev?: string }; +}; + +export const make_event_input = ( + id: string, + marker: string, + relay?: string +): RadrootsJobInput => ({ + data: id, + input_type: JobInputType.Event, + ...(relay ? { relay } : {}), + marker, +}); + +export const make_text_input = ( + payload: unknown, + marker: string +): RadrootsJobInput => ({ + data: typeof payload === "string" ? payload : JSON.stringify(payload), + input_type: JobInputType.Text, + marker, +}); + +export const build_request_tags = ( + kind: number, + inputs: RadrootsJobInput[], + opts?: CommonRequestOpts +) => + tags_job_request({ + kind, + inputs, + output: opts?.output, + params: opts?.params ?? [], + bid_sat: opts?.bid_sat, + relays: opts?.relays ?? [], + providers: opts?.providers ?? [], + topics: opts?.topics ?? [], + encrypted: !!opts?.encrypted, + }); + +export const build_result_tags = ( + kind: number, + request_event_id: string, + opts?: CommonResultOpts, + extra?: { + inputs?: RadrootsJobInput[]; + payment_sat?: number; + payment_bolt11?: string; + } +) => + tags_job_result({ + kind, + request_event: { + id: request_event_id, + ...(opts?.request_relay_hint ? { relays: opts.request_relay_hint } : {}), + }, + request_json: opts?.request_json, + inputs: !opts?.encrypted && extra?.inputs?.length ? extra.inputs : [], + customer_pubkey: opts?.customer_pubkey, + payment: + extra?.payment_sat !== undefined + ? { amount_sat: extra.payment_sat, bolt11: extra.payment_bolt11 } + : opts?.payment_sat !== undefined + ? { amount_sat: opts.payment_sat, bolt11: opts.payment_bolt11 } + : undefined, + encrypted: !!opts?.encrypted, + }); diff --git a/utils-nostr/src/events/comment/lib.ts b/utils-nostr/src/events/comment/lib.ts @@ -1,8 +1,8 @@ import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk"; -import { type RadrootsComment, } from "@radroots/radroots-common-bindings"; +import { RadrootsComment } from "@radroots/events-bindings"; import { NDKEventFigure } from "../../types/ndk.js"; -import { tags_comment } from "../../utils/tags.js"; import { ndk_event } from "../lib.js"; +import { tags_comment } from "./tags.js"; export const KIND_RADROOTS_COMMENT = 1111; export type KindRadrootsComment = typeof KIND_RADROOTS_COMMENT; diff --git a/utils-nostr/src/events/comment/parse.ts b/utils-nostr/src/events/comment/parse.ts @@ -1,5 +1,5 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { type RadrootsComment, radroots_comment_schema } from "@radroots/radroots-common-bindings"; +import { radroots_comment_schema, RadrootsComment } from "@radroots/events-bindings"; import { parse_nostr_event_basis } from "../lib.js"; import { NdkEventBasis } from "../subscription.js"; import { KIND_RADROOTS_COMMENT, type KindRadrootsComment } from "./lib.js"; diff --git a/utils-nostr/src/events/comment/tags.ts b/utils-nostr/src/events/comment/tags.ts @@ -0,0 +1,37 @@ +import { RadrootsComment } from "@radroots/events-bindings"; +import { NostrEventTags } from "../../types/lib.js"; + +export const tags_comment = (opts: RadrootsComment): NostrEventTags => { + const { root: root_event, parent: parent_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 = (parent_event && parent_event.id) + ? { + kind: parent_event.kind.toString(), + author: parent_event.author, + id: parent_event.id, + d_tag: parent_event.d_tag, + relays: parent_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/events/follow/lib.ts b/utils-nostr/src/events/follow/lib.ts @@ -1,8 +1,8 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { type RadrootsFollow } from "@radroots/radroots-common-bindings"; +import { RadrootsFollow } from "@radroots/events-bindings"; import { NDKEventFigure } from "../../types/ndk.js"; -import { tags_follow_list } from "../../utils/tags.js"; import { ndk_event } from "../lib.js"; +import { tags_follow_list } from "./tags.js"; export const KIND_RADROOTS_FOLLOW = 3; export type KindRadrootsFollow = typeof KIND_RADROOTS_FOLLOW; diff --git a/utils-nostr/src/events/follow/parse.ts b/utils-nostr/src/events/follow/parse.ts @@ -1,5 +1,5 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { type RadrootsFollow, radroots_follow_schema } from "@radroots/radroots-common-bindings"; +import { RadrootsFollow, radroots_follow_schema } from "@radroots/events-bindings"; import { parse_nostr_event_basis } from "../lib.js"; import { NdkEventBasis } from "../subscription.js"; import { KIND_RADROOTS_FOLLOW, type KindRadrootsFollow } from "./lib.js"; diff --git a/utils-nostr/src/events/follow/tags.ts b/utils-nostr/src/events/follow/tags.ts @@ -0,0 +1,11 @@ +import { RadrootsFollowProfile } from "@radroots/events-bindings"; +import { NostrEventTags } from "../../types/lib.js"; + +export const tags_follow_list = (list: RadrootsFollowProfile[]): 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/src/events/job/lib.ts b/utils-nostr/src/events/job/lib.ts @@ -0,0 +1,95 @@ +import { NDKEvent } from "@nostr-dev-kit/ndk"; +import { JobFeedbackStatus, KIND_JOB_FEEDBACK, RadrootsJobFeedback, RadrootsJobRequest, RadrootsJobResult } from "@radroots/events-bindings"; +import { NDKEventFigure } from "../../types/ndk.js"; +import { ndk_event } from "../lib.js"; +import { tags_job_feedback, tags_job_request, tags_job_result } from "./tags.js"; + +export const ndk_event_job_request = async (opts: NDKEventFigure<{ data: RadrootsJobRequest; }>): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data } = opts; + return await ndk_event({ + ndk, + ndk_user, + basis: { + kind: data.kind, + content: "", + tags: tags_job_request(data), + }, + }); +}; + +export const ndk_event_job_result = async (opts: NDKEventFigure<{ data: RadrootsJobResult; }>): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data } = opts; + return await ndk_event({ + ndk, + ndk_user, + basis: { + kind: data.kind, + content: data.content || "", + tags: tags_job_result(data), + }, + }); +}; + +export const ndk_event_job_feedback = async (opts: NDKEventFigure<{ data: RadrootsJobFeedback; }>): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, data } = opts; + return await ndk_event({ + ndk, + ndk_user, + basis: { + kind: data.kind, + content: data.content || "", + tags: tags_job_feedback(data), + }, + }); +}; + +export const ndk_event_job_feedback_todo = async ( + opts: NDKEventFigure<{ + request_event_id: string; + status: + | JobFeedbackStatus + | "payment-required" + | "processing" + | "error" + | "success" + | "partial"; + content?: string; + options?: { + request_relay_hint?: string; + extra_info?: string; + customer_pubkey?: string; + amount_sat?: number; + bolt11?: string; + encrypted?: boolean; + }; + }> +): Promise<NDKEvent | undefined> => { + const { ndk, ndk_user, request_event_id, status, content, options } = opts; + + const fb: RadrootsJobFeedback = { + kind: KIND_JOB_FEEDBACK, + status: status as JobFeedbackStatus, + extra_info: options?.extra_info, + request_event: { + id: request_event_id, + ...(options?.request_relay_hint ? { relays: options.request_relay_hint } : {}), + }, + customer_pubkey: options?.customer_pubkey, + payment: + options?.amount_sat !== undefined + ? { amount_sat: options.amount_sat, bolt11: options?.bolt11 } + : undefined, + content, + encrypted: !!options?.encrypted, + }; + + const tags = tags_job_feedback(fb); + + return await ndk_event({ + ndk, + ndk_user, + basis: { kind: KIND_JOB_FEEDBACK, content: content ?? "", tags }, + client: opts.client, + date_published: opts.date_published, + }); +}; +\ No newline at end of file diff --git a/utils-nostr/src/events/job/tags.ts b/utils-nostr/src/events/job/tags.ts @@ -0,0 +1,75 @@ +import { RadrootsJobFeedback, RadrootsJobInput, RadrootsJobRequest, RadrootsJobResult } from "@radroots/events-bindings"; +import { NostrEventTag, NostrEventTags } from "../../types/lib.js"; + +export const tag_job_input = (input: RadrootsJobInput): NostrEventTag => { + const t: NostrEventTag = ["i", input.data, input.input_type]; + if (input.relay) t.push(input.relay); + if (input.marker) t.push(input.marker); + return t; +}; + +export const tag_job_output = (mime: string): NostrEventTag => ["output", mime]; + +export const tag_job_param = (key: string, value: string): NostrEventTag => ["param", key, value]; + +export const tag_job_bid = (sat: number): NostrEventTag => ["bid", String(sat)]; + +export const tags_job_relays = (relays: string[]): NostrEventTags => + relays.map(r => ["relays", r]); + +export const tags_job_providers = (pubkeys: string[]): NostrEventTags => + pubkeys.map(p => ["p", p]); + +export const tags_job_topics = (topics: string[]): NostrEventTags => + topics.map(t => ["t", t]); + +export const tag_job_amount = (msat: number, bolt11?: string): NostrEventTag => + bolt11 ? ["amount", String(msat), bolt11] : ["amount", String(msat)]; + +export const tag_job_encrypted = (): NostrEventTag => ["encrypted"]; + +export const tags_job_request = (opts: RadrootsJobRequest): NostrEventTags => { + const tags: NostrEventTags = []; + for (const input of opts.inputs) tags.push(tag_job_input(input)); + if (opts.output) tags.push(tag_job_output(opts.output)); + if (opts.params) for (const p of opts.params) tags.push(tag_job_param(p.key, p.value)); + if (typeof opts.bid_sat === "number") tags.push(tag_job_bid(opts.bid_sat)); + if (opts.relays?.length) tags.push(...tags_job_relays(opts.relays)); + if (opts.providers?.length) tags.push(...tags_job_providers(opts.providers)); + if (opts.topics?.length) tags.push(...tags_job_topics(opts.topics)); + if (opts.encrypted) tags.push(tag_job_encrypted()); + return tags; +}; + +export const tags_job_result = (opts: RadrootsJobResult): NostrEventTags => { + const tags: NostrEventTags = []; + const event_tag: NostrEventTag = ["e", opts.request_event.id]; + if (opts.request_event.relays) event_tag.push(opts.request_event.relays); + tags.push(event_tag); + if (opts.request_json) tags.push(["request", opts.request_json]); + if (!opts.encrypted && opts.inputs?.length) for (const input of opts.inputs) tags.push(tag_job_input(input)); + if (opts.customer_pubkey) tags.push(["p", opts.customer_pubkey]); + if (opts.payment?.amount_sat !== undefined) { + const msat = Math.round(Number(opts.payment.amount_sat) * 1000); + tags.push(tag_job_amount(msat, opts.payment.bolt11)); + } + if (opts.encrypted) tags.push(tag_job_encrypted()); + return tags; +} + +export const tags_job_feedback = (opts: RadrootsJobFeedback): NostrEventTags => { + const tags: NostrEventTags = []; + const status_tag: NostrEventTag = ["status", String(opts.status)]; + if (opts.extra_info) status_tag.push(opts.extra_info); + tags.push(status_tag); + if (opts.payment?.amount_sat !== undefined) { + const msat = Math.round(Number(opts.payment.amount_sat) * 1000); + tags.push(tag_job_amount(msat, opts.payment.bolt11)); + } + const event_tag: NostrEventTag = ["e", opts.request_event.id]; + if (opts.request_event.relays) event_tag.push(opts.request_event.relays); + tags.push(event_tag); + if (opts.customer_pubkey) tags.push(["p", opts.customer_pubkey]); + if (opts.encrypted) tags.push(tag_job_encrypted()); + return tags; +} +\ No newline at end of file diff --git a/utils-nostr/src/events/job/utils.ts b/utils-nostr/src/events/job/utils.ts @@ -0,0 +1,34 @@ +import { JobInputType, KIND_JOB_FEEDBACK } from "@radroots/events-bindings"; +import { TradeListingStage } from "@radroots/trade-bindings"; +import { + REQUEST_KINDS, + RESULT_KINDS, +} from "../../domain/trade/lib.js"; +import type { NostrEventTags } from "../../types/lib.js"; + +export function get_job_input_data_for_marker( + tags: NostrEventTags, + marker: string, + input_type: JobInputType = JobInputType.Event +): string | undefined { + for (const t of tags) { + if (t[0] !== "i") continue; + if (t[2] !== input_type) continue; + const tag_marker = t.length >= 5 ? t[4] : t.length >= 4 ? t[3] : undefined; + if (tag_marker === marker) return t[1]; + } + return undefined; +} + +export function get_trade_listing_stage_from_event_kind( + kind: number +): TradeListingStage | undefined { + for (const key of Object.keys(REQUEST_KINDS) as TradeListingStage[]) { + if (REQUEST_KINDS[key] === kind) return key; + } + for (const key of Object.keys(RESULT_KINDS) as TradeListingStage[]) { + if (RESULT_KINDS[key] === kind) return key; + } + if (kind === KIND_JOB_FEEDBACK) return TradeListingStage.Order; + return undefined; +} diff --git a/utils-nostr/src/events/listing/lib.ts b/utils-nostr/src/events/listing/lib.ts @@ -1,8 +1,8 @@ import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk"; -import { type RadrootsListing } from "@radroots/radroots-common-bindings"; +import { type RadrootsListing } from "@radroots/events-bindings"; import { NDKEventFigure } from "../../types/ndk.js"; -import { tags_classified } from "../../utils/tags.js"; import { ndk_event } from "../lib.js"; +import { tags_listing } from "./tags.js"; export const KIND_RADROOTS_LISTING = 30402; export type KindRadrootsListing = typeof KIND_RADROOTS_LISTING; @@ -15,7 +15,7 @@ export const ndk_event_classified = async (opts: NDKEventFigure<{ data: Radroots basis: { kind: NDKKind.Classified, content: ``, - tags: tags_classified(data), + tags: tags_listing(data), }, }); }; \ No newline at end of file diff --git a/utils-nostr/src/events/listing/parse.ts b/utils-nostr/src/events/listing/parse.ts @@ -1,5 +1,5 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { type RadrootsListing, radroots_listing_location_schema, radroots_listing_price_schema, radroots_listing_product_schema, radroots_listing_quantity_schema, radroots_listing_schema } from "@radroots/radroots-common-bindings"; +import { type RadrootsListing, radroots_listing_location_schema, radroots_listing_price_schema, radroots_listing_product_schema, radroots_listing_quantity_schema, radroots_listing_schema } from "@radroots/events-bindings"; import { get_event_tag, get_event_tags, parse_nostr_event_basis } from "../lib.js"; import { NdkEventBasis } from "../subscription.js"; import { KIND_RADROOTS_LISTING, type KindRadrootsListing } from "./lib.js"; diff --git a/utils-nostr/src/events/listing/tags.ts b/utils-nostr/src/events/listing/tags.ts @@ -0,0 +1,67 @@ +import { RadrootsListingDiscount, RadrootsListingPrice, RadrootsListingQuantity, type RadrootsListing } from "@radroots/events-bindings"; +import ngeotags, { type InputData as NostrGeotagsInputData } from "nostr-geotags"; +import { NostrEventTag, NostrEventTagImage, NostrEventTagLocation, NostrEventTags } from "../../types/lib.js"; + +const tags_map = (tag: any[]) => tag.map(i => String(i).toLowerCase()); + +export const tag_listing_quantity = (opts: RadrootsListingQuantity): NostrEventTag => { + const tag = [`quantity`, opts.value.amount, opts.value.unit]; + if (opts.label) tag.push(opts.label); + return tags_map(tag); +}; + +export const tag_listing_price = (price: RadrootsListingPrice): NostrEventTag => { + const tag = [`price`, price.amount, price.amount.amount, price.quantity.amount, price.quantity.unit, price.quantity.label || ``]; + return tags_map(tag); +}; + +export const tag_listing_price_discount = (discount: RadrootsListingDiscount): NostrEventTag => { + const tag = [`price-discount-${Object.keys(discount)[0]}`]; + for (const [key, value] of Object.entries(discount.amount)) tag.push(`${key}:${value}`); + return tags_map(tag); +}; + +export const tag_listing_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_listing_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 tag_listing_image = (opts: NostrEventTagImage): NostrEventTag => { + const tag = [`image`, opts.url]; + if (opts.size) tag.push(`${opts.size.w}x${opts.size.h}`) + return tag; +}; + +export const tags_listing = (opts: RadrootsListing): NostrEventTags => { + const { d_tag, product, quantities, prices } = opts; + const tags: NostrEventTags = [[`d`, d_tag]]; + for (const [k, v] of Object.entries(product)) if (v) tags.push([k, v]); + for (const quantity of quantities) { + tags.push(tag_listing_quantity(quantity)); + } + for (const price of prices) { + tags.push(tag_listing_price(price)); + } + for (const discount of opts.discounts || []) { + tags.push(tag_listing_price_discount(discount)); + } + if (opts.location) { + tags.push(tag_listing_location(opts.location)); + tags.push(...tags_listing_location_geotags(opts.location)); + } + if (opts.images) for (const image_tags of opts.images) tags.push(tag_listing_image(image_tags)); + return tags; +}; +\ No newline at end of file diff --git a/utils-nostr/src/events/profile/lib.ts b/utils-nostr/src/events/profile/lib.ts @@ -1,5 +1,5 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { RadrootsProfile } from "@radroots/radroots-common-bindings"; +import { type RadrootsProfile } from "@radroots/events-bindings"; import { NDKEventFigure } from "../../types/ndk.js"; import { ndk_event } from "../lib.js"; diff --git a/utils-nostr/src/events/profile/parse.ts b/utils-nostr/src/events/profile/parse.ts @@ -1,5 +1,5 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { type RadrootsProfile, radroots_profile_schema } from "@radroots/radroots-common-bindings"; +import { type RadrootsProfile, radroots_profile_schema } from "@radroots/events-bindings"; import { parse_nostr_event_basis } from "../lib.js"; import { NdkEventBasis } from "../subscription.js"; import { KIND_RADROOTS_PROFILE, type KindRadrootsProfile } from "./lib.js"; diff --git a/utils-nostr/src/events/reaction/lib.ts b/utils-nostr/src/events/reaction/lib.ts @@ -1,8 +1,8 @@ import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk"; -import { type RadrootsReaction, } from "@radroots/radroots-common-bindings"; +import { RadrootsReaction } from "@radroots/events-bindings"; import { NDKEventFigure } from "../../types/ndk.js"; -import { tags_reaction } from "../../utils/tags.js"; import { ndk_event } from "../lib.js"; +import { tags_reaction } from "./tags.js"; export const KIND_RADROOTS_REACTION = 7; export type KindRadrootsReaction = typeof KIND_RADROOTS_REACTION; diff --git a/utils-nostr/src/events/reaction/parse.ts b/utils-nostr/src/events/reaction/parse.ts @@ -1,5 +1,5 @@ import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { type RadrootsReaction, radroots_reaction_schema } from "@radroots/radroots-common-bindings"; +import { RadrootsReaction, radroots_reaction_schema } from "@radroots/events-bindings"; import { parse_nostr_event_basis } from "../lib.js"; import { NdkEventBasis } from "../subscription.js"; import { KIND_RADROOTS_REACTION, type KindRadrootsReaction } from "./lib.js"; diff --git a/utils-nostr/src/events/reaction/tags.ts b/utils-nostr/src/events/reaction/tags.ts @@ -0,0 +1,15 @@ +import { RadrootsReaction } from "@radroots/events-bindings"; +import { NostrEventTags } from "../../types/lib.js"; + +export const tags_reaction = (opts: RadrootsReaction): NostrEventTags => { + const { root } = opts; + const ref_kind = root.kind.toString(); + const ref_author = root.author; + const tags: NostrEventTags = [ + [`e`, root.id, ...root.relays || ``], + [`p`, ref_author], + [`k`, ref_kind], + ]; + if (root.d_tag) tags.push([`a`, `${ref_kind}:${ref_author}:${root.d_tag}`, ...root.relays || ``]) + return tags; +}; +\ No newline at end of file diff --git a/utils-nostr/src/index.ts b/utils-nostr/src/index.ts @@ -1,14 +1,31 @@ +export * from "./domain/trade/lib.js" +export * from "./domain/trade/listing/accept/lib.js" +export * from "./domain/trade/listing/conveyance/lib.js" +export * from "./domain/trade/listing/fulfillment/lib.js" +export * from "./domain/trade/listing/invoice/lib.js" +export * from "./domain/trade/listing/order/lib.js" +export * from "./domain/trade/listing/payment/lib.js" +export * from "./domain/trade/listing/receipt/lib.js" +export * from "./domain/trade/listing/tags.js" +export * from "./domain/trade/tags.js" export * from "./events/comment/lib.js" export * from "./events/comment/parse.js" +export * from "./events/comment/tags.js" export * from "./events/follow/lib.js" export * from "./events/follow/parse.js" +export * from "./events/follow/tags.js" +export * from "./events/job/lib.js" +export * from "./events/job/tags.js" +export * from "./events/job/utils.js" export * from "./events/lib.js" export * from "./events/listing/lib.js" export * from "./events/listing/parse.js" +export * from "./events/listing/tags.js" export * from "./events/profile/lib.js" export * from "./events/profile/parse.js" export * from "./events/reaction/lib.js" export * from "./events/reaction/parse.js" +export * from "./events/reaction/tags.js" export * from "./events/subscription.js" export * from "./keys/lib.js" export * from "./relay/lib.js" diff --git a/utils-nostr/src/types/lib.ts b/utils-nostr/src/types/lib.ts @@ -12,20 +12,7 @@ export type NostrEventTagClient = { relay: string; }; -export type NostrEventTagQuantity = { - amt: string; - unit: string; - label?: string; -}; - -export type NostrEventTagPrice = { - amt: string; - currency: string; - qty_amt: string; - qty_unit: string; - qty_key: string; -}; - +/* export type NostrEventTagPriceDiscount = ( { quantity: { @@ -60,6 +47,7 @@ export type NostrEventTagPriceDiscount = ( } } ); +*/ export type NostrEventTagLocation = { primary: string; diff --git a/utils-nostr/src/utils/tags.ts b/utils-nostr/src/utils/tags.ts @@ -1,6 +1,7 @@ -import { RadrootsComment, RadrootsFollowProfile, RadrootsListing, RadrootsReaction, } from "@radroots/radroots-common-bindings"; -import ngeotags, { type InputData as NostrGeotagsInputData } from "nostr-geotags"; -import { NostrEventTag, NostrEventTagClient, NostrEventTagImage, NostrEventTagLocation, NostrEventTagPrice, NostrEventTagPriceDiscount, NostrEventTagQuantity, NostrEventTags } from "../types/lib.js"; +import { NostrEventTag, NostrEventTagClient } from "../types/lib.js"; + +export const TAG_E = 'e'; +export const TAG_I = 'i'; export const tag_client = (opts: NostrEventTagClient, d_tag?: string): NostrEventTag => { const tag = [`client`, opts.name]; @@ -8,125 +9,3 @@ export const tag_client = (opts: NostrEventTagClient, d_tag?: string): NostrEven tag.push(opts.relay); return tag; }; - -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 = (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_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_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 tag_classified_image = (opts: NostrEventTagImage): NostrEventTag => { - const tag = [`image`, opts.url]; - if (opts.size) tag.push(`${opts.size.w}x${opts.size.h}`) - return tag; -}; - -export const tags_classified = (opts: RadrootsListing): NostrEventTags => { - const { d_tag, product, quantities, prices } = opts; - const tags: NostrEventTags = [[`d`, d_tag]]; - for (const [k, v] of Object.entries(product)) 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_comment = (opts: RadrootsComment): NostrEventTags => { - const { root: root_event, parent: parent_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 = (parent_event && parent_event.id) - ? { - kind: parent_event.kind.toString(), - author: parent_event.author, - id: parent_event.id, - d_tag: parent_event.d_tag, - relays: parent_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; -}; - -export const tags_reaction = (opts: RadrootsReaction): NostrEventTags => { - const { root } = opts; - const ref_kind = root.kind.toString(); - const ref_author = root.author; - const tags: NostrEventTags = [ - [`e`, root.id, ...root.relays || ``], - [`p`, ref_author], - [`k`, ref_kind], - ]; - if (root.d_tag) tags.push([`a`, `${ref_kind}:${ref_author}:${root.d_tag}`, ...root.relays || ``]) - return tags; -}; - -export const tags_follow_list = (list: RadrootsFollowProfile[]): 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