applesauce-wallet 0.0.0-next-20251220152312 → 0.0.0-next-20251231055351

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,3 +2,4 @@ export * from "./wallet.js";
2
2
  export * from "./tokens.js";
3
3
  export * from "./nutzaps.js";
4
4
  export * from "./nutzap-info.js";
5
+ export * from "./mint-recomendation.js";
@@ -2,3 +2,4 @@ export * from "./wallet.js";
2
2
  export * from "./tokens.js";
3
3
  export * from "./nutzaps.js";
4
4
  export * from "./nutzap-info.js";
5
+ export * from "./mint-recomendation.js";
@@ -0,0 +1,30 @@
1
+ import { Wallet } from "@cashu/cashu-ts";
2
+ import { Action } from "applesauce-actions";
3
+ import { NostrEvent } from "applesauce-core/helpers/event";
4
+ import "../casts/__register__.js";
5
+ /**
6
+ * Options for reviewing a mint
7
+ */
8
+ export type ReviewMintOptions = {
9
+ /** Optional review/comment content */
10
+ comment?: string;
11
+ /** Optional relays to publish to */
12
+ relays?: string[];
13
+ };
14
+ /**
15
+ * An action that creates and publishes a mint recommendation event.
16
+ * Can accept a mint URL, Wallet instance, or MintInfo event.
17
+ */
18
+ export declare function RecommendMint(input: string | Wallet | NostrEvent, options?: ReviewMintOptions): Action;
19
+ /**
20
+ * Options for updating a mint recommendation
21
+ */
22
+ export type UpdateMintRecommendationOptions = {
23
+ /** Optional relays to publish to */
24
+ relays?: string[];
25
+ };
26
+ /**
27
+ * An action that updates the comment on an existing mint recommendation event.
28
+ * Can accept a mint pubkey (to find the recommendation) or the recommendation event directly.
29
+ */
30
+ export declare function UpdateMintRecommendation(input: string | NostrEvent, comment: string, options?: UpdateMintRecommendationOptions): Action;
@@ -0,0 +1,96 @@
1
+ import { Wallet } from "@cashu/cashu-ts";
2
+ import { MintRecommendationBlueprint } from "../blueprints/mint-recommendation.js";
3
+ import { getCashuMintPubkey, getCashuMintURL, isValidCashuMintInfo } from "../helpers/mint-info.js";
4
+ import { MINT_RECOMMENDATION_KIND, getRecommendationMintPubkey, isValidMintRecommendation, } from "../helpers/mint-recommendation.js";
5
+ import { setComment } from "../operations/mint-recommendation.js";
6
+ // Helper function to fetch mint pubkey from URL
7
+ async function fetchMintPubkey(mintUrl) {
8
+ // Fetch mint info directly from the /v1/info endpoint
9
+ const infoUrl = new URL("/v1/info", mintUrl).toString();
10
+ const response = await fetch(infoUrl);
11
+ if (!response.ok) {
12
+ throw new Error(`Failed to fetch mint info from ${mintUrl}: ${response.statusText}`);
13
+ }
14
+ const mintInfo = (await response.json());
15
+ return mintInfo.pubkey;
16
+ }
17
+ // Make sure the mint recommendation cast is registered
18
+ import "../casts/__register__.js";
19
+ /**
20
+ * An action that creates and publishes a mint recommendation event.
21
+ * Can accept a mint URL, Wallet instance, or MintInfo event.
22
+ */
23
+ export function RecommendMint(input, options) {
24
+ return async ({ factory, sign, publish }) => {
25
+ let mintPubkey;
26
+ let url;
27
+ let addressPointer = undefined;
28
+ // Handle different input types
29
+ if (typeof input === "string") {
30
+ if (!URL.canParse(input))
31
+ throw new Error("Invalid mint URL");
32
+ // Input is a mint URL - fetch info directly
33
+ url = input;
34
+ mintPubkey = await fetchMintPubkey(url);
35
+ }
36
+ else if (input instanceof Wallet) {
37
+ const info = input.getMintInfo();
38
+ mintPubkey = info.pubkey;
39
+ }
40
+ else {
41
+ // Input is a MintInfo event (kind:38172)
42
+ if (!isValidCashuMintInfo(input))
43
+ throw new Error("Invalid mint info event. Expected kind:38172 with required `d` and `u` tags.");
44
+ mintPubkey = getCashuMintPubkey(input);
45
+ url = getCashuMintURL(input);
46
+ // Use the event itself as address pointer (blueprint will convert it)
47
+ addressPointer = input;
48
+ }
49
+ // Create the mint recommendation event
50
+ const recommendation = await factory
51
+ .create(MintRecommendationBlueprint, {
52
+ mintPubkey,
53
+ url,
54
+ addressPointer,
55
+ comment: options?.comment,
56
+ })
57
+ .then(sign);
58
+ // Publish the event
59
+ await publish(recommendation, options?.relays);
60
+ };
61
+ }
62
+ /**
63
+ * An action that updates the comment on an existing mint recommendation event.
64
+ * Can accept a mint pubkey (to find the recommendation) or the recommendation event directly.
65
+ */
66
+ export function UpdateMintRecommendation(input, comment, options) {
67
+ return async ({ events, factory, self, sign, publish }) => {
68
+ let recommendation;
69
+ // Handle different input types
70
+ if (typeof input === "string") {
71
+ // Input is a mint pubkey - find the recommendation event
72
+ const recommendations = events.getTimeline({ kinds: [MINT_RECOMMENDATION_KIND], authors: [self] });
73
+ recommendation = recommendations.find((rec) => {
74
+ if (!isValidMintRecommendation(rec))
75
+ return false;
76
+ const recMintPubkey = getRecommendationMintPubkey(rec);
77
+ return recMintPubkey === input;
78
+ });
79
+ if (!recommendation)
80
+ throw new Error(`No mint recommendation found for mint pubkey: ${input}`);
81
+ }
82
+ else {
83
+ // Input is a recommendation event
84
+ if (!isValidMintRecommendation(input))
85
+ throw new Error("Invalid mint recommendation event");
86
+ // Verify the event belongs to the current user
87
+ if (input.pubkey !== self)
88
+ throw new Error("Cannot update a mint recommendation that belongs to another user");
89
+ recommendation = input;
90
+ }
91
+ // Update the comment
92
+ const updated = await factory.modify(recommendation, setComment(comment)).then(sign);
93
+ // Publish the updated event
94
+ await publish(updated, options?.relays);
95
+ };
96
+ }
@@ -2,3 +2,4 @@ export * from "./history.js";
2
2
  export * from "./tokens.js";
3
3
  export * from "./wallet.js";
4
4
  export * from "./zaps.js";
5
+ export * from "./mint-recommendation.js";
@@ -2,3 +2,4 @@ export * from "./history.js";
2
2
  export * from "./tokens.js";
3
3
  export * from "./wallet.js";
4
4
  export * from "./zaps.js";
5
+ export * from "./mint-recommendation.js";
@@ -0,0 +1,16 @@
1
+ import { EventBlueprint } from "applesauce-core/event-factory";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { AddressPointer } from "applesauce-core/helpers/pointers";
4
+ /** Options for creating a mint recommendation */
5
+ export type MintRecommendationOptions = {
6
+ /** The mint's pubkey (from the kind:38172 event's `d` tag) - required */
7
+ mintPubkey: string;
8
+ /** Optional URL to connect to the cashu mint */
9
+ url?: string;
10
+ /** Optional address pointer to the kind:38172 event */
11
+ addressPointer?: AddressPointer | NostrEvent | string;
12
+ /** Optional review/comment content */
13
+ comment?: string;
14
+ };
15
+ /** A blueprint to create a kind:38000 mint recommendation event */
16
+ export declare function MintRecommendationBlueprint(options: MintRecommendationOptions): EventBlueprint;
@@ -0,0 +1,11 @@
1
+ import { blueprint } from "applesauce-core/event-factory";
2
+ import { skip } from "applesauce-core/helpers";
3
+ import { MINT_RECOMMENDATION_KIND } from "../helpers/mint-recommendation.js";
4
+ import { CASHU_MINT_INFO_KIND } from "../helpers/mint-info.js";
5
+ import { setAddressPointer, setComment, setKind, setMintPubkey, setURL } from "../operations/mint-recommendation.js";
6
+ /** A blueprint to create a kind:38000 mint recommendation event */
7
+ export function MintRecommendationBlueprint(options) {
8
+ const { mintPubkey, url, addressPointer, comment } = options;
9
+ return blueprint(MINT_RECOMMENDATION_KIND, setKind(CASHU_MINT_INFO_KIND), // Always 38172 for cashu mints
10
+ setMintPubkey(mintPubkey), url ? setURL(url) : skip(), addressPointer ? setAddressPointer(addressPointer) : skip(), comment ? setComment(comment) : skip());
11
+ }
@@ -2,10 +2,12 @@ import { ChainableObservable } from "applesauce-common/observable";
2
2
  import { NutzapInfo } from "./nutzap-info.js";
3
3
  import { Nutzap } from "./nutzap.js";
4
4
  import { Wallet } from "./wallet.js";
5
+ import { MintRecommendation } from "./mint-recommendation.js";
5
6
  declare module "applesauce-common/casts/user" {
6
7
  interface User {
7
8
  readonly wallet$: ChainableObservable<Wallet | undefined>;
8
9
  readonly nutzap$: ChainableObservable<NutzapInfo | undefined>;
10
+ readonly mintRecommendation$: ChainableObservable<MintRecommendation | undefined>;
9
11
  }
10
12
  }
11
13
  declare module "applesauce-common/casts/stream" {
@@ -9,6 +9,8 @@ import { NUTZAP_INFO_KIND } from "../helpers/nutzap-info.js";
9
9
  import { NutzapInfo } from "./nutzap-info.js";
10
10
  import { Nutzap } from "./nutzap.js";
11
11
  import { Wallet } from "./wallet.js";
12
+ import { MintRecommendation } from "./mint-recommendation.js";
13
+ import { MINT_RECOMMENDATION_KIND } from "../helpers/mint-recommendation.js";
12
14
  Object.defineProperty(User.prototype, "wallet$", {
13
15
  get: function () {
14
16
  return this.$$ref("wallet$", (store) => this.outboxes$.pipe(switchMap((outboxes) => store
@@ -25,6 +27,15 @@ Object.defineProperty(User.prototype, "nutzap$", {
25
27
  enumerable: true,
26
28
  configurable: false,
27
29
  });
30
+ Object.defineProperty(User.prototype, "mintRecommendation$", {
31
+ get: function () {
32
+ return this.$$ref("mintRecommendation$", (store) => store
33
+ .timeline({ kinds: [MINT_RECOMMENDATION_KIND], authors: [this.pubkey] })
34
+ .pipe(castTimelineStream(MintRecommendation, store)));
35
+ },
36
+ enumerable: true,
37
+ configurable: false,
38
+ });
28
39
  Note.prototype.nutzaps$ = function () {
29
40
  return this.$$ref("nutzaps$", (store) => store
30
41
  .timeline(buildCommonEventRelationFilters({ kinds: [NUTZAP_KIND] }, this.event))
@@ -1,3 +1,5 @@
1
+ export * from "./mint-info.js";
2
+ export * from "./mint-recommendation.js";
1
3
  export * from "./nutzap-info.js";
2
4
  export * from "./nutzap.js";
3
5
  export * from "./wallet-history.js";
@@ -1,3 +1,5 @@
1
+ export * from "./mint-info.js";
2
+ export * from "./mint-recommendation.js";
1
3
  export * from "./nutzap-info.js";
2
4
  export * from "./nutzap.js";
3
5
  export * from "./wallet-history.js";
@@ -0,0 +1,18 @@
1
+ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { CashuMintInfoEvent } from "../helpers/mint-info.js";
4
+ import { MintRecommendation } from "./mint-recommendation.js";
5
+ export declare class MintInfo extends EventCast<CashuMintInfoEvent> {
6
+ constructor(event: NostrEvent, store: CastRefEventStore);
7
+ /** The mint's pubkey (from the `d` tag) */
8
+ get mintPubkey(): string | undefined;
9
+ /** The URL to the cashu mint (from the `u` tag) */
10
+ get url(): string;
11
+ /** The supported nuts (comma-separated list of nut numbers) */
12
+ get nuts(): number[];
13
+ /** The network type (mainnet, testnet, signet, or regtest) */
14
+ get network(): import("../helpers/mint-info.js").NetworkType | undefined;
15
+ /** Optional metadata content (kind:0-style JSON object) */
16
+ get metadata(): Record<string, any> | undefined;
17
+ get recomendations$(): import("applesauce-common/observable").ChainableObservable<MintRecommendation[]>;
18
+ }
@@ -0,0 +1,42 @@
1
+ import { EventCast } from "applesauce-common/casts";
2
+ import { castTimelineStream } from "applesauce-common/observable";
3
+ import { getCashuMintMetadata, getCashuMintNetwork, getCashuMintNuts, getCashuMintPubkey, getCashuMintURL, isValidCashuMintInfo, } from "../helpers/mint-info.js";
4
+ import { MINT_RECOMMENDATION_KIND } from "../helpers/mint-recommendation.js";
5
+ import { MintRecommendation } from "./mint-recommendation.js";
6
+ export class MintInfo extends EventCast {
7
+ constructor(event, store) {
8
+ if (!isValidCashuMintInfo(event))
9
+ throw new Error("Invalid cashu mint info event");
10
+ super(event, store);
11
+ }
12
+ /** The mint's pubkey (from the `d` tag) */
13
+ get mintPubkey() {
14
+ return getCashuMintPubkey(this.event);
15
+ }
16
+ /** The URL to the cashu mint (from the `u` tag) */
17
+ get url() {
18
+ return getCashuMintURL(this.event);
19
+ }
20
+ /** The supported nuts (comma-separated list of nut numbers) */
21
+ get nuts() {
22
+ return getCashuMintNuts(this.event);
23
+ }
24
+ /** The network type (mainnet, testnet, signet, or regtest) */
25
+ get network() {
26
+ return getCashuMintNetwork(this.event);
27
+ }
28
+ /** Optional metadata content (kind:0-style JSON object) */
29
+ get metadata() {
30
+ return getCashuMintMetadata(this.event);
31
+ }
32
+ get recomendations$() {
33
+ return this.$$ref("recomendations$", (store) => store
34
+ .timeline([
35
+ // Based on the mint URL
36
+ { kinds: [MINT_RECOMMENDATION_KIND], "#u": [this.url] },
37
+ // Based on the mint pubkey
38
+ this.mintPubkey ? { kinds: [MINT_RECOMMENDATION_KIND], "#d": [this.mintPubkey] } : undefined,
39
+ ].filter((f) => !!f))
40
+ .pipe(castTimelineStream(MintRecommendation, store)));
41
+ }
42
+ }
@@ -0,0 +1,16 @@
1
+ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { MintRecommendationEvent } from "../helpers/mint-recommendation.js";
4
+ export declare class MintRecommendation extends EventCast<MintRecommendationEvent> {
5
+ constructor(event: NostrEvent, store: CastRefEventStore);
6
+ /** The recommended event kind (should be 38172 for cashu mints) */
7
+ get kind(): number;
8
+ /** The mint's pubkey (from the `d` tag) */
9
+ get mintPubkey(): string | undefined;
10
+ /** Optional URL to connect to the cashu mint (from the `u` tag) */
11
+ get url(): string | undefined;
12
+ /** Optional address pointer to the kind:38172 event (from the `a` tag) */
13
+ get addressPointer(): import("nostr-tools/nip19").AddressPointer | undefined;
14
+ /** Optional review content */
15
+ get comment(): string;
16
+ }
@@ -0,0 +1,29 @@
1
+ import { EventCast } from "applesauce-common/casts";
2
+ import { getRecommendationAddressPointer, getRecommendationMintPubkey, getRecommendationKind, getRecommendationURL, isValidMintRecommendation, } from "../helpers/mint-recommendation.js";
3
+ export class MintRecommendation extends EventCast {
4
+ constructor(event, store) {
5
+ if (!isValidMintRecommendation(event))
6
+ throw new Error("Invalid mint recommendation event");
7
+ super(event, store);
8
+ }
9
+ /** The recommended event kind (should be 38172 for cashu mints) */
10
+ get kind() {
11
+ return getRecommendationKind(this.event);
12
+ }
13
+ /** The mint's pubkey (from the `d` tag) */
14
+ get mintPubkey() {
15
+ return getRecommendationMintPubkey(this.event);
16
+ }
17
+ /** Optional URL to connect to the cashu mint (from the `u` tag) */
18
+ get url() {
19
+ return getRecommendationURL(this.event);
20
+ }
21
+ /** Optional address pointer to the kind:38172 event (from the `a` tag) */
22
+ get addressPointer() {
23
+ return getRecommendationAddressPointer(this.event);
24
+ }
25
+ /** Optional review content */
26
+ get comment() {
27
+ return this.event.content;
28
+ }
29
+ }
@@ -8,3 +8,5 @@ export * from "./cashu.js";
8
8
  export * from "./couch.js";
9
9
  export * from "./local-storage-couch.js";
10
10
  export * from "./indexed-db-couch.js";
11
+ export * from "./mint-info.js";
12
+ export * from "./mint-recommendation.js";
@@ -8,3 +8,5 @@ export * from "./cashu.js";
8
8
  export * from "./couch.js";
9
9
  export * from "./local-storage-couch.js";
10
10
  export * from "./indexed-db-couch.js";
11
+ export * from "./mint-info.js";
12
+ export * from "./mint-recommendation.js";
@@ -0,0 +1,40 @@
1
+ import { KnownEvent } from "applesauce-core/helpers";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ export declare const CASHU_MINT_INFO_KIND = 38172;
4
+ export type CashuMintInfoEvent = KnownEvent<typeof CASHU_MINT_INFO_KIND>;
5
+ export type NetworkType = "mainnet" | "testnet" | "signet" | "regtest";
6
+ export declare const CashuMintPubkeySymbol: unique symbol;
7
+ export declare const CashuMintURLSymbol: unique symbol;
8
+ export declare const CashuMintNutsSymbol: unique symbol;
9
+ export declare const CashuMintNetworkSymbol: unique symbol;
10
+ /**
11
+ * Returns the mint's pubkey from a kind:38172 cashu mint info event
12
+ * This is found in the `d` tag and is the pubkey from the mint's `/v1/info` endpoint
13
+ */
14
+ export declare function getCashuMintPubkey(event: NostrEvent): string | undefined;
15
+ /**
16
+ * Returns the mint URL from a kind:38172 cashu mint info event
17
+ * This is the URL to the cashu mint (from the `u` tag)
18
+ */
19
+ export declare function getCashuMintURL(event: CashuMintInfoEvent): string;
20
+ export declare function getCashuMintURL(event: NostrEvent): string | undefined;
21
+ /**
22
+ * Returns the supported nuts from a kind:38172 cashu mint info event
23
+ * This is a comma-separated list of nut numbers (e.g., "1,2,3,4,5,6,7")
24
+ */
25
+ export declare function getCashuMintNuts(event: NostrEvent): number[];
26
+ /**
27
+ * Returns the network type from a kind:38172 cashu mint info event
28
+ * Should be one of: mainnet, testnet, signet, or regtest
29
+ */
30
+ export declare function getCashuMintNetwork(event: NostrEvent): NetworkType | undefined;
31
+ /**
32
+ * Returns the optional metadata content from a kind:38172 cashu mint info event
33
+ * This is a kind:0-style metadata JSON object, useful when the pubkey is not a normal user
34
+ */
35
+ export declare function getCashuMintMetadata(event: NostrEvent): Record<string, any> | undefined;
36
+ /**
37
+ * Validates that an event is a proper kind:38172 cashu mint info event
38
+ * Checks that the event is kind 38172 and has the required `d` and `u` tags
39
+ */
40
+ export declare function isValidCashuMintInfo(event?: NostrEvent): event is CashuMintInfoEvent;
@@ -0,0 +1,80 @@
1
+ import { getOrComputeCachedValue, getTagValue, isHex, safeParse } from "applesauce-core/helpers";
2
+ import { getReplaceableIdentifier } from "applesauce-core/helpers/event";
3
+ // NIP-87 Cashu Mint Information Event Kind
4
+ export const CASHU_MINT_INFO_KIND = 38172;
5
+ // Symbols for caching computed values
6
+ export const CashuMintPubkeySymbol = Symbol.for("cashu-mint-pubkey");
7
+ export const CashuMintURLSymbol = Symbol.for("cashu-mint-url");
8
+ export const CashuMintNutsSymbol = Symbol.for("cashu-mint-nuts");
9
+ export const CashuMintNetworkSymbol = Symbol.for("cashu-mint-network");
10
+ // ============================================================================
11
+ // Cashu Mint Information Event (kind:38172) Helpers
12
+ // ============================================================================
13
+ /**
14
+ * Returns the mint's pubkey from a kind:38172 cashu mint info event
15
+ * This is found in the `d` tag and is the pubkey from the mint's `/v1/info` endpoint
16
+ */
17
+ export function getCashuMintPubkey(event) {
18
+ return getOrComputeCachedValue(event, CashuMintPubkeySymbol, () => {
19
+ const identifier = getReplaceableIdentifier(event);
20
+ // Only return hex pubkeys
21
+ if (!isHex(identifier))
22
+ return undefined;
23
+ return identifier || undefined;
24
+ });
25
+ }
26
+ export function getCashuMintURL(event) {
27
+ return getOrComputeCachedValue(event, CashuMintURLSymbol, () => {
28
+ const url = getTagValue(event, "u");
29
+ return url && URL.canParse(url) ? url : undefined;
30
+ });
31
+ }
32
+ /**
33
+ * Returns the supported nuts from a kind:38172 cashu mint info event
34
+ * This is a comma-separated list of nut numbers (e.g., "1,2,3,4,5,6,7")
35
+ */
36
+ export function getCashuMintNuts(event) {
37
+ return getOrComputeCachedValue(event, CashuMintNutsSymbol, () => {
38
+ const nutsStr = getTagValue(event, "nuts");
39
+ if (!nutsStr)
40
+ return [];
41
+ return nutsStr
42
+ .split(",")
43
+ .map((n) => parseInt(n.trim(), 10))
44
+ .filter((n) => !isNaN(n));
45
+ });
46
+ }
47
+ /**
48
+ * Returns the network type from a kind:38172 cashu mint info event
49
+ * Should be one of: mainnet, testnet, signet, or regtest
50
+ */
51
+ export function getCashuMintNetwork(event) {
52
+ return getOrComputeCachedValue(event, CashuMintNetworkSymbol, () => {
53
+ const network = getTagValue(event, "n");
54
+ if (!network)
55
+ return undefined;
56
+ const validNetworks = ["mainnet", "testnet", "signet", "regtest"];
57
+ return validNetworks.includes(network) ? network : undefined;
58
+ });
59
+ }
60
+ /**
61
+ * Returns the optional metadata content from a kind:38172 cashu mint info event
62
+ * This is a kind:0-style metadata JSON object, useful when the pubkey is not a normal user
63
+ */
64
+ export function getCashuMintMetadata(event) {
65
+ if (!event.content)
66
+ return undefined;
67
+ return safeParse(event.content);
68
+ }
69
+ /**
70
+ * Validates that an event is a proper kind:38172 cashu mint info event
71
+ * Checks that the event is kind 38172 and has the required `d` and `u` tags
72
+ */
73
+ export function isValidCashuMintInfo(event) {
74
+ if (!event)
75
+ return false;
76
+ if (event.kind !== CASHU_MINT_INFO_KIND)
77
+ return false;
78
+ const url = getCashuMintURL(event);
79
+ return url !== undefined;
80
+ }
@@ -0,0 +1,41 @@
1
+ import { KnownEvent } from "applesauce-core/helpers";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { AddressPointer } from "applesauce-core/helpers/pointers";
4
+ export declare const MINT_RECOMMENDATION_KIND = 38000;
5
+ export type MintRecommendationEvent = KnownEvent<typeof MINT_RECOMMENDATION_KIND>;
6
+ export declare const RecommendationKindSymbol: unique symbol;
7
+ export declare const RecommendationURLSymbol: unique symbol;
8
+ export declare const RecommendationAddressPointerSymbol: unique symbol;
9
+ /**
10
+ * Returns the recommended event kind from a kind:38000 recommendation event
11
+ * This should be 38172 for cashu mints
12
+ */
13
+ export declare function getRecommendationKind(event: MintRecommendationEvent): number;
14
+ export declare function getRecommendationKind(event: NostrEvent): number | undefined;
15
+ /**
16
+ * Returns the d-identifier from a kind:38000 recommendation event
17
+ * This is the kind:38172 event identifier this event is recommending
18
+ */
19
+ export declare function getRecommendationMintPubkey(event: NostrEvent): string | undefined;
20
+ /**
21
+ * Returns the URL from a kind:38000 recommendation event
22
+ * This is an optional `u` tag that provides a recommended way to connect to the cashu mint
23
+ * Each recommendation event recommends a single mint, so there is at most one `u` tag
24
+ */
25
+ export declare function getRecommendationURL(event: MintRecommendationEvent): string | undefined;
26
+ export declare function getRecommendationURL(event: NostrEvent): string | undefined;
27
+ /**
28
+ * Returns the address pointer from a kind:38000 recommendation event
29
+ * This `a` tag points to the kind:38172 event of the cashu mint
30
+ * The first value is the event identifier, the second value is a relay hint
31
+ * Each recommendation event recommends a single mint, so there is at most one `a` tag
32
+ */
33
+ export declare function getRecommendationAddressPointer(event: MintRecommendationEvent): AddressPointer | undefined;
34
+ export declare function getRecommendationAddressPointer(event: NostrEvent): AddressPointer | undefined;
35
+ /**
36
+ * Validates that an event is a proper kind:38000 recommendation event
37
+ * Checks that the event is kind 38000, has the required `k` and `d` tags,
38
+ * and that the `k` tag is 38172 (cashu mint kind)
39
+ * Each recommendation event recommends a single cashu mint
40
+ */
41
+ export declare function isValidMintRecommendation(event?: NostrEvent): event is MintRecommendationEvent;
@@ -0,0 +1,54 @@
1
+ import { getAddressPointerFromATag, getOrComputeCachedValue, getTagValue, isATag, isHex, } from "applesauce-core/helpers";
2
+ import { getReplaceableIdentifier } from "applesauce-core/helpers/event";
3
+ import { CASHU_MINT_INFO_KIND } from "./mint-info.js";
4
+ // NIP-87 Recommendation Event Kind
5
+ export const MINT_RECOMMENDATION_KIND = 38000;
6
+ // Symbols for caching computed values
7
+ export const RecommendationKindSymbol = Symbol.for("mint-recommendation-kind");
8
+ export const RecommendationURLSymbol = Symbol.for("mint-recommendation-url");
9
+ export const RecommendationAddressPointerSymbol = Symbol.for("mint-recommendation-address-pointer");
10
+ export function getRecommendationKind(event) {
11
+ return getOrComputeCachedValue(event, RecommendationKindSymbol, () => {
12
+ const kindStr = getTagValue(event, "k");
13
+ if (!kindStr)
14
+ return undefined;
15
+ const kind = parseInt(kindStr, 10);
16
+ return isNaN(kind) ? undefined : kind;
17
+ });
18
+ }
19
+ /**
20
+ * Returns the d-identifier from a kind:38000 recommendation event
21
+ * This is the kind:38172 event identifier this event is recommending
22
+ */
23
+ export function getRecommendationMintPubkey(event) {
24
+ const identifier = getReplaceableIdentifier(event);
25
+ if (!isHex(identifier))
26
+ return undefined;
27
+ return identifier || undefined;
28
+ }
29
+ export function getRecommendationURL(event) {
30
+ return getOrComputeCachedValue(event, RecommendationURLSymbol, () => {
31
+ return getTagValue(event, "u");
32
+ });
33
+ }
34
+ export function getRecommendationAddressPointer(event) {
35
+ return getOrComputeCachedValue(event, RecommendationAddressPointerSymbol, () => {
36
+ const tag = event.tags.find(isATag);
37
+ return tag ? (getAddressPointerFromATag(tag) ?? undefined) : undefined;
38
+ });
39
+ }
40
+ /**
41
+ * Validates that an event is a proper kind:38000 recommendation event
42
+ * Checks that the event is kind 38000, has the required `k` and `d` tags,
43
+ * and that the `k` tag is 38172 (cashu mint kind)
44
+ * Each recommendation event recommends a single cashu mint
45
+ */
46
+ export function isValidMintRecommendation(event) {
47
+ if (!event)
48
+ return false;
49
+ if (event.kind !== MINT_RECOMMENDATION_KIND)
50
+ return false;
51
+ const kind = getRecommendationKind(event);
52
+ // Only cashu mints (kind 38172) are supported
53
+ return kind === CASHU_MINT_INFO_KIND;
54
+ }
@@ -3,3 +3,4 @@ export * as Tokens from "./tokens.js";
3
3
  export * as Wallet from "./wallet.js";
4
4
  export * as ZapInfo from "./nutzap-info.js";
5
5
  export * as NutZap from "./nutzap.js";
6
+ export * as MintRecommendation from "./mint-recommendation.js";
@@ -3,3 +3,4 @@ export * as Tokens from "./tokens.js";
3
3
  export * as Wallet from "./wallet.js";
4
4
  export * as ZapInfo from "./nutzap-info.js";
5
5
  export * as NutZap from "./nutzap.js";
6
+ export * as MintRecommendation from "./mint-recommendation.js";
@@ -0,0 +1,13 @@
1
+ import { EventOperation } from "applesauce-core";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { AddressPointer } from "applesauce-core/helpers/pointers";
4
+ /** Sets the recommended event kind (should be 38172 for cashu mints) */
5
+ export declare function setKind(kind: number): EventOperation;
6
+ /** Sets the mint's pubkey (the `d` tag, which is the replaceable identifier) */
7
+ export declare function setMintPubkey(pubkey: string): EventOperation;
8
+ /** Sets the optional URL to connect to the cashu mint (the `u` tag) */
9
+ export declare function setURL(url: string): EventOperation;
10
+ /** Sets the optional address pointer to the kind:38172 event (the `a` tag) */
11
+ export declare function setAddressPointer(pointer: AddressPointer | NostrEvent | string): EventOperation;
12
+ /** Sets the optional review/comment content */
13
+ export declare function setComment(comment: string): EventOperation;
@@ -0,0 +1,26 @@
1
+ import { modifyPublicTags } from "applesauce-core/operations";
2
+ import { setContent } from "applesauce-core/operations/content";
3
+ import { addAddressPointerTag, setSingletonTag } from "applesauce-core/operations/tag/common";
4
+ /** Sets the recommended event kind (should be 38172 for cashu mints) */
5
+ export function setKind(kind) {
6
+ return modifyPublicTags(setSingletonTag(["k", kind.toString()]));
7
+ }
8
+ /** Sets the mint's pubkey (the `d` tag, which is the replaceable identifier) */
9
+ export function setMintPubkey(pubkey) {
10
+ return modifyPublicTags(setSingletonTag(["d", pubkey]));
11
+ }
12
+ /** Sets the optional URL to connect to the cashu mint (the `u` tag) */
13
+ export function setURL(url) {
14
+ // Enforce valid URL for cashu mints
15
+ if (url && !URL.canParse(url))
16
+ throw new Error("Invalid URL");
17
+ return modifyPublicTags(setSingletonTag(["u", url]));
18
+ }
19
+ /** Sets the optional address pointer to the kind:38172 event (the `a` tag) */
20
+ export function setAddressPointer(pointer) {
21
+ return modifyPublicTags(addAddressPointerTag(pointer, true));
22
+ }
23
+ /** Sets the optional review/comment content */
24
+ export function setComment(comment) {
25
+ return setContent(comment);
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-wallet",
3
- "version": "0.0.0-next-20251220152312",
3
+ "version": "0.0.0-next-20251231055351",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,83 +16,83 @@
16
16
  ],
17
17
  "exports": {
18
18
  ".": {
19
+ "types": "./dist/index.d.ts",
19
20
  "import": "./dist/index.js",
20
- "require": "./dist/index.js",
21
- "types": "./dist/index.d.ts"
21
+ "require": "./dist/index.js"
22
22
  },
23
23
  "./helpers": {
24
+ "types": "./dist/helpers/index.d.ts",
24
25
  "import": "./dist/helpers/index.js",
25
- "require": "./dist/helpers/index.js",
26
- "types": "./dist/helpers/index.d.ts"
26
+ "require": "./dist/helpers/index.js"
27
27
  },
28
28
  "./helpers/*": {
29
+ "types": "./dist/helpers/*.d.ts",
29
30
  "import": "./dist/helpers/*.js",
30
- "require": "./dist/helpers/*.js",
31
- "types": "./dist/helpers/*.d.ts"
31
+ "require": "./dist/helpers/*.js"
32
32
  },
33
33
  "./models": {
34
+ "types": "./dist/models/index.d.ts",
34
35
  "import": "./dist/models/index.js",
35
- "require": "./dist/models/index.js",
36
- "types": "./dist/models/index.d.ts"
36
+ "require": "./dist/models/index.js"
37
37
  },
38
38
  "./models/*": {
39
+ "types": "./dist/models/*.d.ts",
39
40
  "import": "./dist/models/*.js",
40
- "require": "./dist/models/*.js",
41
- "types": "./dist/models/*.d.ts"
41
+ "require": "./dist/models/*.js"
42
42
  },
43
43
  "./casts": {
44
+ "types": "./dist/casts/index.d.ts",
44
45
  "import": "./dist/casts/index.js",
45
- "require": "./dist/casts/index.js",
46
- "types": "./dist/casts/index.d.ts"
46
+ "require": "./dist/casts/index.js"
47
47
  },
48
48
  "./casts/*": {
49
+ "types": "./dist/casts/*.d.ts",
49
50
  "import": "./dist/casts/*.js",
50
- "require": "./dist/casts/*.js",
51
- "types": "./dist/casts/*.d.ts"
51
+ "require": "./dist/casts/*.js"
52
52
  },
53
53
  "./blueprints": {
54
+ "types": "./dist/blueprints/index.d.ts",
54
55
  "import": "./dist/blueprints/index.js",
55
- "require": "./dist/blueprints/index.js",
56
- "types": "./dist/blueprints/index.d.ts"
56
+ "require": "./dist/blueprints/index.js"
57
57
  },
58
58
  "./blueprints/*": {
59
+ "types": "./dist/blueprints/*.d.ts",
59
60
  "import": "./dist/blueprints/*.js",
60
- "require": "./dist/blueprints/*.js",
61
- "types": "./dist/blueprints/*.d.ts"
61
+ "require": "./dist/blueprints/*.js"
62
62
  },
63
63
  "./operations": {
64
+ "types": "./dist/operations/index.d.ts",
64
65
  "import": "./dist/operations/index.js",
65
- "require": "./dist/operations/index.js",
66
- "types": "./dist/operations/index.d.ts"
66
+ "require": "./dist/operations/index.js"
67
67
  },
68
68
  "./operations/*": {
69
+ "types": "./dist/operations/*.d.ts",
69
70
  "import": "./dist/operations/*.js",
70
- "require": "./dist/operations/*.js",
71
- "types": "./dist/operations/*.d.ts"
71
+ "require": "./dist/operations/*.js"
72
72
  },
73
73
  "./actions": {
74
+ "types": "./dist/actions/index.d.ts",
74
75
  "import": "./dist/actions/index.js",
75
- "require": "./dist/actions/index.js",
76
- "types": "./dist/actions/index.d.ts"
76
+ "require": "./dist/actions/index.js"
77
77
  },
78
78
  "./actions/*": {
79
+ "types": "./dist/actions/*.d.ts",
79
80
  "import": "./dist/actions/*.js",
80
- "require": "./dist/actions/*.js",
81
- "types": "./dist/actions/*.d.ts"
81
+ "require": "./dist/actions/*.js"
82
82
  }
83
83
  },
84
84
  "dependencies": {
85
85
  "@cashu/cashu-ts": "^3.1.1",
86
86
  "@gandlaf21/bc-ur": "^1.1.12",
87
- "applesauce-actions": "0.0.0-next-20251220152312",
88
- "applesauce-common": "0.0.0-next-20251220152312",
89
- "applesauce-core": "0.0.0-next-20251220152312",
87
+ "applesauce-actions": "0.0.0-next-20251231055351",
88
+ "applesauce-common": "0.0.0-next-20251231055351",
89
+ "applesauce-core": "0.0.0-next-20251231055351",
90
90
  "rxjs": "^7.8.1"
91
91
  },
92
92
  "devDependencies": {
93
93
  "@hirez_io/observer-spy": "^2.2.0",
94
94
  "@types/debug": "^4.1.12",
95
- "applesauce-signers": "0.0.0-next-20251220152312",
95
+ "applesauce-signers": "0.0.0-next-20251231055351",
96
96
  "rimraf": "^6.0.1",
97
97
  "typescript": "^5.8.3",
98
98
  "vitest": "^4.0.15"