applesauce-wallet 0.0.0-next-20251209200210 → 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.
Files changed (91) hide show
  1. package/dist/actions/common.d.ts +4 -0
  2. package/dist/actions/common.js +15 -0
  3. package/dist/actions/index.d.ts +3 -2
  4. package/dist/actions/index.js +3 -2
  5. package/dist/actions/mint-recomendation.d.ts +30 -0
  6. package/dist/actions/mint-recomendation.js +96 -0
  7. package/dist/actions/{zap-info.d.ts → nutzap-info.d.ts} +20 -3
  8. package/dist/actions/nutzap-info.js +117 -0
  9. package/dist/actions/nutzaps.d.ts +24 -0
  10. package/dist/actions/nutzaps.js +154 -0
  11. package/dist/actions/tokens.d.ts +77 -7
  12. package/dist/actions/tokens.js +332 -69
  13. package/dist/actions/wallet.d.ts +18 -3
  14. package/dist/actions/wallet.js +74 -32
  15. package/dist/blueprints/history.d.ts +1 -1
  16. package/dist/blueprints/history.js +1 -1
  17. package/dist/blueprints/index.d.ts +1 -0
  18. package/dist/blueprints/index.js +1 -0
  19. package/dist/blueprints/mint-recommendation.d.ts +16 -0
  20. package/dist/blueprints/mint-recommendation.js +11 -0
  21. package/dist/blueprints/wallet.d.ts +5 -1
  22. package/dist/blueprints/wallet.js +6 -3
  23. package/dist/casts/__register__.d.ts +22 -0
  24. package/dist/casts/__register__.js +52 -0
  25. package/dist/casts/index.d.ts +8 -0
  26. package/dist/casts/index.js +8 -0
  27. package/dist/casts/mint-info.d.ts +18 -0
  28. package/dist/casts/mint-info.js +42 -0
  29. package/dist/casts/mint-recommendation.d.ts +16 -0
  30. package/dist/casts/mint-recommendation.js +29 -0
  31. package/dist/casts/nutzap-info.d.ts +14 -0
  32. package/dist/casts/nutzap-info.js +22 -0
  33. package/dist/casts/nutzap.d.ts +16 -0
  34. package/dist/casts/nutzap.js +37 -0
  35. package/dist/casts/wallet-history.d.ts +16 -0
  36. package/dist/casts/wallet-history.js +40 -0
  37. package/dist/casts/wallet-token.d.ts +29 -0
  38. package/dist/casts/wallet-token.js +52 -0
  39. package/dist/casts/wallet.d.ts +27 -0
  40. package/dist/casts/wallet.js +62 -0
  41. package/dist/helpers/cashu.d.ts +21 -0
  42. package/dist/helpers/cashu.js +105 -0
  43. package/dist/helpers/couch.d.ts +11 -0
  44. package/dist/helpers/couch.js +1 -0
  45. package/dist/helpers/history.d.ts +5 -1
  46. package/dist/helpers/history.js +13 -4
  47. package/dist/helpers/index.d.ts +7 -1
  48. package/dist/helpers/index.js +7 -1
  49. package/dist/helpers/indexed-db-couch.d.ts +34 -0
  50. package/dist/helpers/indexed-db-couch.js +119 -0
  51. package/dist/helpers/local-storage-couch.d.ts +29 -0
  52. package/dist/helpers/local-storage-couch.js +78 -0
  53. package/dist/helpers/mint-info.d.ts +40 -0
  54. package/dist/helpers/mint-info.js +80 -0
  55. package/dist/helpers/mint-recommendation.d.ts +41 -0
  56. package/dist/helpers/mint-recommendation.js +54 -0
  57. package/dist/helpers/{zap-info.d.ts → nutzap-info.d.ts} +10 -1
  58. package/dist/helpers/{zap-info.js → nutzap-info.js} +22 -10
  59. package/dist/helpers/nutzap.d.ts +15 -0
  60. package/dist/helpers/nutzap.js +57 -3
  61. package/dist/helpers/tokens.d.ts +9 -18
  62. package/dist/helpers/tokens.js +64 -94
  63. package/dist/helpers/wallet.d.ts +16 -6
  64. package/dist/helpers/wallet.js +40 -14
  65. package/dist/index.d.ts +1 -0
  66. package/dist/index.js +1 -0
  67. package/dist/models/history.d.ts +1 -1
  68. package/dist/models/history.js +7 -10
  69. package/dist/models/index.d.ts +0 -1
  70. package/dist/models/index.js +0 -1
  71. package/dist/models/nutzap.d.ts +2 -0
  72. package/dist/models/nutzap.js +8 -0
  73. package/dist/models/tokens.d.ts +2 -2
  74. package/dist/models/tokens.js +14 -17
  75. package/dist/operations/history.js +1 -1
  76. package/dist/operations/index.d.ts +2 -1
  77. package/dist/operations/index.js +2 -1
  78. package/dist/operations/mint-recommendation.d.ts +13 -0
  79. package/dist/operations/mint-recommendation.js +26 -0
  80. package/dist/operations/nutzap-info.d.ts +21 -0
  81. package/dist/operations/nutzap-info.js +71 -0
  82. package/dist/operations/wallet.d.ts +10 -1
  83. package/dist/operations/wallet.js +33 -3
  84. package/package.json +37 -28
  85. package/dist/actions/zap-info.js +0 -83
  86. package/dist/actions/zaps.d.ts +0 -8
  87. package/dist/actions/zaps.js +0 -30
  88. package/dist/models/wallet.d.ts +0 -13
  89. package/dist/models/wallet.js +0 -21
  90. package/dist/operations/zap-info.d.ts +0 -10
  91. package/dist/operations/zap-info.js +0 -17
@@ -1,4 +1,4 @@
1
- import { combineLatest, filter, map, scan, startWith } from "rxjs";
1
+ import { identity, map, scan } from "rxjs";
2
2
  import { getHistoryRedeemed, isHistoryContentUnlocked, WALLET_HISTORY_KIND } from "../helpers/history.js";
3
3
  /** A model that returns an array of redeemed event ids for a wallet */
4
4
  export function WalletRedeemedModel(pubkey) {
@@ -7,15 +7,12 @@ export function WalletRedeemedModel(pubkey) {
7
7
  .pipe(scan((ids, history) => [...ids, ...getHistoryRedeemed(history)], []));
8
8
  }
9
9
  /** A model that returns a timeline of wallet history events */
10
- export function WalletHistoryModel(pubkey, locked) {
10
+ export function WalletHistoryModel(pubkey, unlocked) {
11
11
  return (events) => {
12
- const updates = events.update$.pipe(filter((e) => e.kind === WALLET_HISTORY_KIND && e.pubkey === pubkey), startWith(undefined));
13
- const timeline = events.timeline({ kinds: [WALLET_HISTORY_KIND], authors: [pubkey] });
14
- return combineLatest([updates, timeline]).pipe(map(([_, history]) => {
15
- if (locked === undefined)
16
- return history;
17
- else
18
- return history.filter((entry) => isHistoryContentUnlocked(entry) === locked);
19
- }));
12
+ return events
13
+ .timeline({ kinds: [WALLET_HISTORY_KIND], authors: [pubkey] })
14
+ .pipe(unlocked !== undefined
15
+ ? map((events) => events.filter((e) => isHistoryContentUnlocked(e) === unlocked))
16
+ : identity);
20
17
  };
21
18
  }
@@ -1,4 +1,3 @@
1
1
  export * from "./history.js";
2
2
  export * from "./tokens.js";
3
- export * from "./wallet.js";
4
3
  export * from "./nutzap.js";
@@ -1,4 +1,3 @@
1
1
  export * from "./history.js";
2
2
  export * from "./tokens.js";
3
- export * from "./wallet.js";
4
3
  export * from "./nutzap.js";
@@ -6,3 +6,5 @@ import { NUTZAP_KIND } from "../helpers/nutzap.js";
6
6
  export declare function EventNutZapzModel(event: NostrEvent): Model<KnownEvent<typeof NUTZAP_KIND>[]>;
7
7
  /** A model that returns all nutzaps for a users profile */
8
8
  export declare function ProfileNutZapzModel(pubkey: string): Model<KnownEvent<typeof NUTZAP_KIND>[]>;
9
+ /** A model that returns all nutzap event ids received by a user */
10
+ export declare function ReceivedNutzapsModel(pubkey: string): Model<string[]>;
@@ -1,6 +1,8 @@
1
1
  import { map } from "rxjs";
2
2
  import { buildCommonEventRelationFilters } from "applesauce-core/helpers/model";
3
+ import { getHistoryRedeemed } from "../helpers/history.js";
3
4
  import { getNutzapPointer, isValidNutzap, NUTZAP_KIND } from "../helpers/nutzap.js";
5
+ import { WalletHistoryModel } from "./history.js";
4
6
  /** A model that returns all nutzap events for an event */
5
7
  export function EventNutZapzModel(event) {
6
8
  return (events) => events.timeline(buildCommonEventRelationFilters({ kinds: [NUTZAP_KIND] }, event)).pipe(map((events) =>
@@ -15,3 +17,9 @@ export function ProfileNutZapzModel(pubkey) {
15
17
  // filter out nutzaps that are for events
16
18
  map((zaps) => zaps.filter((zap) => getNutzapPointer(zap) === undefined)));
17
19
  }
20
+ /** A model that returns all nutzap event ids received by a user */
21
+ export function ReceivedNutzapsModel(pubkey) {
22
+ return (events) => events
23
+ .model(WalletHistoryModel, pubkey, true)
24
+ .pipe(map((entries) => Array.from(new Set(entries.flatMap(getHistoryRedeemed)))));
25
+ }
@@ -1,6 +1,6 @@
1
1
  import { Model } from "applesauce-core";
2
2
  import { NostrEvent } from "applesauce-core/helpers/event";
3
- /** A model that subscribes to all token events for a wallet, passing locked will filter by token locked status */
4
- export declare function WalletTokensModel(pubkey: string, locked?: boolean | undefined): Model<NostrEvent[]>;
3
+ /** A model that subscribes to all token events for a wallet, passing unlocked will filter by token unlocked status */
4
+ export declare function WalletTokensModel(pubkey: string, unlocked?: boolean | undefined): Model<NostrEvent[]>;
5
5
  /** A model that returns the visible balance of a wallet for each mint */
6
6
  export declare function WalletBalanceModel(pubkey: string): Model<Record<string, number>>;
@@ -1,5 +1,7 @@
1
- import { combineLatest, filter, map, startWith } from "rxjs";
2
- import { getTokenContent, ignoreDuplicateProofs, isTokenContentUnlocked, WALLET_TOKEN_KIND, } from "../helpers/tokens.js";
1
+ import { watchEventsUpdates } from "applesauce-core";
2
+ import { identity, map } from "rxjs";
3
+ import { ignoreDuplicateProofs } from "../helpers/cashu.js";
4
+ import { getTokenContent, isTokenContentUnlocked, WALLET_TOKEN_KIND } from "../helpers/tokens.js";
3
5
  /** removes deleted events from sorted array */
4
6
  function filterDeleted(tokens) {
5
7
  const deleted = new Set();
@@ -10,7 +12,7 @@ function filterDeleted(tokens) {
10
12
  if (deleted.has(token.id))
11
13
  return false;
12
14
  // add ids to deleted array
13
- if (!isTokenContentUnlocked(token)) {
15
+ if (isTokenContentUnlocked(token)) {
14
16
  const details = getTokenContent(token);
15
17
  for (const id of details.del)
16
18
  deleted.add(id);
@@ -19,19 +21,12 @@ function filterDeleted(tokens) {
19
21
  })
20
22
  .reverse();
21
23
  }
22
- /** A model that subscribes to all token events for a wallet, passing locked will filter by token locked status */
23
- export function WalletTokensModel(pubkey, locked) {
24
+ /** A model that subscribes to all token events for a wallet, passing unlocked will filter by token unlocked status */
25
+ export function WalletTokensModel(pubkey, unlocked) {
24
26
  return (events) => {
25
- const updates = events.update$.pipe(filter((e) => e.kind === WALLET_TOKEN_KIND && e.pubkey === pubkey), startWith(undefined));
26
- const timeline = events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] });
27
- return combineLatest([updates, timeline]).pipe(
27
+ return events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] }).pipe(
28
28
  // filter out locked tokens
29
- map(([_, tokens]) => {
30
- if (locked === undefined)
31
- return tokens;
32
- else
33
- return tokens.filter((t) => isTokenContentUnlocked(t) === locked);
34
- }),
29
+ unlocked !== undefined ? map((tokens) => tokens.filter((t) => isTokenContentUnlocked(t) === unlocked)) : identity,
35
30
  // remove deleted events
36
31
  map(filterDeleted));
37
32
  };
@@ -39,9 +34,11 @@ export function WalletTokensModel(pubkey, locked) {
39
34
  /** A model that returns the visible balance of a wallet for each mint */
40
35
  export function WalletBalanceModel(pubkey) {
41
36
  return (events) => {
42
- const updates = events.update$.pipe(filter((e) => e.kind === WALLET_TOKEN_KIND && e.pubkey === pubkey), startWith(undefined));
43
- const timeline = events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] });
44
- return combineLatest([updates, timeline]).pipe(map(([_, tokens]) => tokens.filter((t) => !isTokenContentUnlocked(t))),
37
+ return events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] }).pipe(
38
+ // Watch for updates to the tokens
39
+ watchEventsUpdates(events),
40
+ // Ignore locked tokens
41
+ map((tokens) => tokens.filter((t) => isTokenContentUnlocked(t))),
45
42
  // filter out deleted tokens
46
43
  map(filterDeleted),
47
44
  // map tokens to totals
@@ -17,7 +17,7 @@ export function setHistoryContent(content) {
17
17
  setSingletonTag(["amount", String(content.amount)], true),
18
18
  includeHistoryCreatedTags(content.created),
19
19
  ];
20
- if (content.fee !== undefined)
20
+ if (content.fee !== undefined && content.fee > 0)
21
21
  operations.push(setSingletonTag(["fee", String(content.fee)], true));
22
22
  if (content.mint !== undefined)
23
23
  operations.push(setSingletonTag(["mint", content.mint], true));
@@ -1,5 +1,6 @@
1
1
  export * as History from "./history.js";
2
2
  export * as Tokens from "./tokens.js";
3
3
  export * as Wallet from "./wallet.js";
4
- export * as ZapInfo from "./zap-info.js";
4
+ export * as ZapInfo from "./nutzap-info.js";
5
5
  export * as NutZap from "./nutzap.js";
6
+ export * as MintRecommendation from "./mint-recommendation.js";
@@ -1,5 +1,6 @@
1
1
  export * as History from "./history.js";
2
2
  export * as Tokens from "./tokens.js";
3
3
  export * as Wallet from "./wallet.js";
4
- export * as ZapInfo from "./zap-info.js";
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
+ }
@@ -0,0 +1,21 @@
1
+ import { EventOperation } from "applesauce-core";
2
+ /** Sets the relays for a nutzap info event, replacing all existing relay tags */
3
+ export declare function setNutzapInfoRelays(relays: string[]): EventOperation;
4
+ /** Sets the mints for a nutzap info event, replacing all existing mint tags */
5
+ export declare function setNutzapInfoMints(mints: Array<{
6
+ url: string;
7
+ units?: string[];
8
+ }>): EventOperation;
9
+ /** Adds a relay tag to a nutzap info event */
10
+ export declare function addNutzapInfoRelay(url: string | URL): EventOperation;
11
+ /** Removes a relay tag from a nutzap info event */
12
+ export declare function removeNutzapInfoRelay(url: string | URL): EventOperation;
13
+ /** Adds a mint tag to a nutzap info event */
14
+ export declare function addNutzapInfoMint(mint: {
15
+ url: string;
16
+ units?: string[];
17
+ }): EventOperation;
18
+ /** Removes a mint tag from a nutzap info event */
19
+ export declare function removeNutzapInfoMint(url: string): EventOperation;
20
+ /** Sets the pubkey for a nutzap info event */
21
+ export declare function setNutzapInfoPubkey(key: Uint8Array): EventOperation;
@@ -0,0 +1,71 @@
1
+ import { modifyPublicTags } from "applesauce-core/operations";
2
+ import { removeNameValueTag, setSingletonTag } from "applesauce-core/operations/tag/common";
3
+ import { addRelayTag, removeRelayTag } from "applesauce-core/operations/tag/relay";
4
+ import { normalizeURL } from "applesauce-core/helpers/url";
5
+ import { createNutzapInfoPubkeyTag } from "../helpers/nutzap-info.js";
6
+ /** Sets the relays for a nutzap info event, replacing all existing relay tags */
7
+ export function setNutzapInfoRelays(relays) {
8
+ return modifyPublicTags((tags) => [
9
+ // remove all existing relay tags
10
+ ...tags.filter((t) => t[0] !== "relay"),
11
+ // add new relay tags
12
+ ...relays.map((relay) => ["relay", relay]),
13
+ ]);
14
+ }
15
+ /** Sets the mints for a nutzap info event, replacing all existing mint tags */
16
+ export function setNutzapInfoMints(mints) {
17
+ return modifyPublicTags((tags) => [
18
+ // remove all existing mint tags
19
+ ...tags.filter((t) => t[0] !== "mint"),
20
+ // add new mint tags
21
+ ...mints.map((mint) => {
22
+ return mint.units ? ["mint", mint.url, ...mint.units] : ["mint", mint.url];
23
+ }),
24
+ ]);
25
+ }
26
+ /** Adds a relay tag to a nutzap info event */
27
+ export function addNutzapInfoRelay(url) {
28
+ url = normalizeURL(url).toString();
29
+ return modifyPublicTags(addRelayTag(url, "relay", false));
30
+ }
31
+ /** Removes a relay tag from a nutzap info event */
32
+ export function removeNutzapInfoRelay(url) {
33
+ url = normalizeURL(url).toString();
34
+ return modifyPublicTags(removeRelayTag(url, "relay"));
35
+ }
36
+ /** Adds a mint tag to a nutzap info event */
37
+ export function addNutzapInfoMint(mint) {
38
+ return modifyPublicTags((tags) => {
39
+ // Find existing mint tag with the same URL
40
+ const existingIndex = tags.findIndex((t) => t[0] === "mint" && t[1] === mint.url);
41
+ if (existingIndex !== -1) {
42
+ // Merge units if mint tag already exists
43
+ const existingTag = tags[existingIndex];
44
+ const existingUnits = existingTag.slice(2); // Get units from existing tag (everything after ["mint", url])
45
+ const newUnits = mint.units || [];
46
+ // Merge units, removing duplicates while preserving order
47
+ const mergedUnits = [...existingUnits];
48
+ for (const unit of newUnits) {
49
+ if (!mergedUnits.includes(unit)) {
50
+ mergedUnits.push(unit);
51
+ }
52
+ }
53
+ // Replace existing tag with merged tag
54
+ const mergedTag = mergedUnits.length > 0 ? ["mint", mint.url, ...mergedUnits] : ["mint", mint.url];
55
+ return tags.map((t, i) => (i === existingIndex ? mergedTag : t));
56
+ }
57
+ else {
58
+ // Add new tag if it doesn't exist
59
+ const tag = mint.units ? ["mint", mint.url, ...mint.units] : ["mint", mint.url];
60
+ return [...tags, tag];
61
+ }
62
+ });
63
+ }
64
+ /** Removes a mint tag from a nutzap info event */
65
+ export function removeNutzapInfoMint(url) {
66
+ return modifyPublicTags(removeNameValueTag(["mint", url]));
67
+ }
68
+ /** Sets the pubkey for a nutzap info event */
69
+ export function setNutzapInfoPubkey(key) {
70
+ return modifyPublicTags(setSingletonTag(createNutzapInfoPubkeyTag(key), true));
71
+ }
@@ -1,8 +1,17 @@
1
- import { EventOperation } from "applesauce-core/event-factory";
1
+ import { EventOperation, TagOperation } from "applesauce-core/event-factory";
2
2
  import { NostrEvent } from "applesauce-core/helpers/event";
3
3
  /** Sets the content of a kind 375 wallet backup event */
4
4
  export declare function setBackupContent(wallet: NostrEvent): EventOperation;
5
5
  /** Sets the "mint" tags in a wallet event */
6
+ export declare function setMintTags(mints: string[]): TagOperation;
6
7
  export declare function setMints(mints: string[]): EventOperation;
7
8
  /** Sets the "privkey" tag on a wallet event */
9
+ export declare function setPrivateKeyTag(privateKey: Uint8Array): TagOperation;
8
10
  export declare function setPrivateKey(privateKey: Uint8Array): EventOperation;
11
+ /** Adds a relay tag to a wallet event */
12
+ export declare function addWalletRelay(url: string | URL): EventOperation;
13
+ /** Removes a relay tag from a wallet event */
14
+ export declare function removeWalletRelay(url: string | URL): EventOperation;
15
+ /** Sets the relay tags on a wallet event, replacing all existing relay tags */
16
+ export declare function setRelayTags(relays: (string | URL)[]): TagOperation;
17
+ export declare function setRelays(relays: (string | URL)[]): EventOperation;
@@ -1,5 +1,7 @@
1
1
  import { bytesToHex } from "applesauce-core/helpers/event";
2
+ import { normalizeURL } from "applesauce-core/helpers/url";
2
3
  import { setSingletonTag } from "applesauce-core/operations/tag/common";
4
+ import { addRelayTag, removeRelayTag } from "applesauce-core/operations/tag/relay";
3
5
  import { modifyHiddenTags } from "applesauce-core/operations/tags";
4
6
  import { WALLET_KIND } from "../helpers/wallet.js";
5
7
  /** Sets the content of a kind 375 wallet backup event */
@@ -16,15 +18,43 @@ export function setBackupContent(wallet) {
16
18
  };
17
19
  }
18
20
  /** Sets the "mint" tags in a wallet event */
19
- export function setMints(mints) {
20
- return modifyHiddenTags((tags) => [
21
+ export function setMintTags(mints) {
22
+ return (tags) => [
21
23
  // remove all existing mint tags
22
24
  ...tags.filter((t) => t[0] !== "mint"),
23
25
  // add new mint tags
24
26
  ...mints.map((mint) => ["mint", mint]),
25
- ]);
27
+ ];
28
+ }
29
+ export function setMints(mints) {
30
+ return modifyHiddenTags(setMintTags(mints));
26
31
  }
27
32
  /** Sets the "privkey" tag on a wallet event */
33
+ export function setPrivateKeyTag(privateKey) {
34
+ return setSingletonTag(["privkey", bytesToHex(privateKey)]);
35
+ }
28
36
  export function setPrivateKey(privateKey) {
29
37
  return modifyHiddenTags(setSingletonTag(["privkey", bytesToHex(privateKey)], true));
30
38
  }
39
+ /** Adds a relay tag to a wallet event */
40
+ export function addWalletRelay(url) {
41
+ url = normalizeURL(url).toString();
42
+ return modifyHiddenTags(addRelayTag(url, "relay", true));
43
+ }
44
+ /** Removes a relay tag from a wallet event */
45
+ export function removeWalletRelay(url) {
46
+ url = normalizeURL(url).toString();
47
+ return modifyHiddenTags(removeRelayTag(url, "relay"));
48
+ }
49
+ /** Sets the relay tags on a wallet event, replacing all existing relay tags */
50
+ export function setRelayTags(relays) {
51
+ return (tags) => [
52
+ // remove all existing relay tags
53
+ ...tags.filter((t) => t[0] !== "relay"),
54
+ // add new relay tags
55
+ ...relays.map((relay) => ["relay", normalizeURL(relay).toString()]),
56
+ ];
57
+ }
58
+ export function setRelays(relays) {
59
+ return modifyHiddenTags(setRelayTags(relays));
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-wallet",
3
- "version": "0.0.0-next-20251209200210",
3
+ "version": "0.0.0-next-20251231055351",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,74 +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
+ },
43
+ "./casts": {
44
+ "types": "./dist/casts/index.d.ts",
45
+ "import": "./dist/casts/index.js",
46
+ "require": "./dist/casts/index.js"
47
+ },
48
+ "./casts/*": {
49
+ "types": "./dist/casts/*.d.ts",
50
+ "import": "./dist/casts/*.js",
51
+ "require": "./dist/casts/*.js"
42
52
  },
43
53
  "./blueprints": {
54
+ "types": "./dist/blueprints/index.d.ts",
44
55
  "import": "./dist/blueprints/index.js",
45
- "require": "./dist/blueprints/index.js",
46
- "types": "./dist/blueprints/index.d.ts"
56
+ "require": "./dist/blueprints/index.js"
47
57
  },
48
58
  "./blueprints/*": {
59
+ "types": "./dist/blueprints/*.d.ts",
49
60
  "import": "./dist/blueprints/*.js",
50
- "require": "./dist/blueprints/*.js",
51
- "types": "./dist/blueprints/*.d.ts"
61
+ "require": "./dist/blueprints/*.js"
52
62
  },
53
63
  "./operations": {
64
+ "types": "./dist/operations/index.d.ts",
54
65
  "import": "./dist/operations/index.js",
55
- "require": "./dist/operations/index.js",
56
- "types": "./dist/operations/index.d.ts"
66
+ "require": "./dist/operations/index.js"
57
67
  },
58
68
  "./operations/*": {
69
+ "types": "./dist/operations/*.d.ts",
59
70
  "import": "./dist/operations/*.js",
60
- "require": "./dist/operations/*.js",
61
- "types": "./dist/operations/*.d.ts"
71
+ "require": "./dist/operations/*.js"
62
72
  },
63
73
  "./actions": {
74
+ "types": "./dist/actions/index.d.ts",
64
75
  "import": "./dist/actions/index.js",
65
- "require": "./dist/actions/index.js",
66
- "types": "./dist/actions/index.d.ts"
76
+ "require": "./dist/actions/index.js"
67
77
  },
68
78
  "./actions/*": {
79
+ "types": "./dist/actions/*.d.ts",
69
80
  "import": "./dist/actions/*.js",
70
- "require": "./dist/actions/*.js",
71
- "types": "./dist/actions/*.d.ts"
81
+ "require": "./dist/actions/*.js"
72
82
  }
73
83
  },
74
84
  "dependencies": {
75
85
  "@cashu/cashu-ts": "^3.1.1",
76
86
  "@gandlaf21/bc-ur": "^1.1.12",
77
- "@noble/hashes": "^1.7.1",
78
- "applesauce-actions": "0.0.0-next-20251209200210",
79
- "applesauce-common": "0.0.0-next-20251209200210",
80
- "applesauce-core": "0.0.0-next-20251209200210",
87
+ "applesauce-actions": "0.0.0-next-20251231055351",
88
+ "applesauce-common": "0.0.0-next-20251231055351",
89
+ "applesauce-core": "0.0.0-next-20251231055351",
81
90
  "rxjs": "^7.8.1"
82
91
  },
83
92
  "devDependencies": {
84
93
  "@hirez_io/observer-spy": "^2.2.0",
85
94
  "@types/debug": "^4.1.12",
86
- "applesauce-signers": "0.0.0-next-20251209200210",
95
+ "applesauce-signers": "0.0.0-next-20251231055351",
87
96
  "rimraf": "^6.0.1",
88
97
  "typescript": "^5.8.3",
89
98
  "vitest": "^4.0.15"
@@ -1,83 +0,0 @@
1
- import { modifyPublicTags } from "applesauce-core/operations/tags";
2
- import { addNameValueTag, removeNameValueTag, setSingletonTag } from "applesauce-core/operations/tag/common";
3
- import { NUTZAP_INFO_KIND } from "../helpers/zap-info.js";
4
- import { setNutzapInfoMints, setNutzapInfoPubkey, setNutzapInfoRelays } from "../operations/zap-info.js";
5
- /** An action to add a relay to the kind 10019 nutzap info event */
6
- export function AddNutzapInfoRelay(relay) {
7
- return async function* ({ events, factory, self }) {
8
- if (typeof relay === "string")
9
- relay = [relay];
10
- const operations = relay.map((r) => addNameValueTag(["relay", r], false));
11
- const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
12
- const draft = nutzapInfo
13
- ? await factory.modifyTags(nutzapInfo, ...operations)
14
- : await factory.build({ kind: NUTZAP_INFO_KIND }, modifyPublicTags(...operations));
15
- const signed = await factory.sign(draft);
16
- yield signed;
17
- };
18
- }
19
- /** An action to remove a relay from the kind 10019 nutzap info event */
20
- export function RemoveNutzapInfoRelay(relay) {
21
- return async function* ({ events, factory, self }) {
22
- if (typeof relay === "string")
23
- relay = [relay];
24
- const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
25
- if (!nutzapInfo)
26
- return;
27
- const draft = await factory.modifyTags(nutzapInfo, ...relay.map((r) => removeNameValueTag(["relay", r])));
28
- const signed = await factory.sign(draft);
29
- yield signed;
30
- };
31
- }
32
- /** An action to add a mint to the kind 10019 nutzap info event */
33
- export function AddNutzapInfoMint(mint) {
34
- return async function* ({ events, factory, self }) {
35
- const mints = Array.isArray(mint) ? mint : [mint];
36
- const operations = mints.map((m) => {
37
- const tag = m.units ? ["mint", m.url, ...m.units] : ["mint", m.url];
38
- return addNameValueTag(tag, false);
39
- });
40
- const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
41
- const draft = nutzapInfo
42
- ? await factory.modifyTags(nutzapInfo, ...operations)
43
- : await factory.build({ kind: NUTZAP_INFO_KIND }, modifyPublicTags(...operations));
44
- const signed = await factory.sign(draft);
45
- yield signed;
46
- };
47
- }
48
- /** An action to remove a mint from the kind 10019 nutzap info event */
49
- export function RemoveNutzapInfoMint(mint) {
50
- return async function* ({ events, factory, self }) {
51
- if (typeof mint === "string")
52
- mint = [mint];
53
- const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
54
- if (!nutzapInfo)
55
- return;
56
- const draft = await factory.modifyTags(nutzapInfo, ...mint.map((m) => removeNameValueTag(["mint", m])));
57
- const signed = await factory.sign(draft);
58
- yield signed;
59
- };
60
- }
61
- /** An action to set the pubkey for the kind 10019 nutzap info event */
62
- export function SetNutzapInfoPubkey(pubkey) {
63
- return async function* ({ events, factory, self }) {
64
- const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
65
- const draft = nutzapInfo
66
- ? await factory.modifyTags(nutzapInfo, setSingletonTag(["pubkey", pubkey], true))
67
- : await factory.build({ kind: NUTZAP_INFO_KIND }, modifyPublicTags(setSingletonTag(["pubkey", pubkey], true)));
68
- const signed = await factory.sign(draft);
69
- yield signed;
70
- };
71
- }
72
- /** An action to update the entire nutzap info event */
73
- export function UpdateNutzapInfo(relays, mints, pubkey) {
74
- return async function* ({ events, factory, self }) {
75
- const operations = [setNutzapInfoRelays(relays), setNutzapInfoMints(mints), setNutzapInfoPubkey(pubkey)];
76
- const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
77
- const draft = nutzapInfo
78
- ? await factory.modify(nutzapInfo, ...operations)
79
- : await factory.build({ kind: NUTZAP_INFO_KIND }, ...operations);
80
- const signed = await factory.sign(draft);
81
- yield signed;
82
- };
83
- }
@@ -1,8 +0,0 @@
1
- import { Token } from "@cashu/cashu-ts";
2
- import { Action } from "applesauce-actions";
3
- import { NostrEvent } from "applesauce-core/helpers/event";
4
- import { ProfilePointer } from "applesauce-core/helpers/pointers";
5
- /** Creates a NIP-61 nutzap event for an event with a token */
6
- export declare function NutzapEvent(event: NostrEvent, token: Token, comment?: string): Action;
7
- /** Creates a NIP-61 nutzap event to a users profile */
8
- export declare function NutzapProfile(user: string | ProfilePointer, token: Token, comment?: string): Action;
@@ -1,30 +0,0 @@
1
- import { NutzapBlueprint, ProfileNutzapBlueprint } from "../blueprints/zaps.js";
2
- import { NUTZAP_INFO_KIND, verifyProofsLocked } from "../helpers/zap-info.js";
3
- /** Creates a NIP-61 nutzap event for an event with a token */
4
- export function NutzapEvent(event, token, comment) {
5
- return async function* ({ events, factory }) {
6
- const recipient = event.pubkey;
7
- const info = events.getReplaceable(NUTZAP_INFO_KIND, recipient);
8
- if (!info)
9
- throw new Error("Nutzap info not found");
10
- // Verify all tokens are p2pk locked
11
- verifyProofsLocked(token.proofs, info);
12
- // NOTE: Disabled because mints and units should be checked by the app before
13
- // const mints = getNutzapInfoMints(info);
14
- // if (!mints.some((m) => m.mint === token.mint)) throw new Error("Token mint not found in nutzap info");
15
- const nutzap = await factory.sign(await factory.create(NutzapBlueprint, event, token, comment || token.memo));
16
- yield nutzap;
17
- };
18
- }
19
- /** Creates a NIP-61 nutzap event to a users profile */
20
- export function NutzapProfile(user, token, comment) {
21
- return async function* ({ events, factory }) {
22
- const info = events.getReplaceable(NUTZAP_INFO_KIND, typeof user === "string" ? user : user.pubkey);
23
- if (!info)
24
- throw new Error("Nutzap info not found");
25
- // Verify all tokens are p2pk locked
26
- verifyProofsLocked(token.proofs, info);
27
- const nutzap = await factory.sign(await factory.create(ProfileNutzapBlueprint, user, token, comment || token.memo));
28
- yield nutzap;
29
- };
30
- }
@@ -1,13 +0,0 @@
1
- import { Model } from "applesauce-core";
2
- import { NostrEvent } from "applesauce-core/helpers/event";
3
- export type WalletInfo = {
4
- locked: true;
5
- event: NostrEvent;
6
- } | {
7
- locked: false;
8
- event: NostrEvent;
9
- privateKey?: Uint8Array;
10
- mints: string[];
11
- };
12
- /** A model to get the state of a NIP-60 wallet */
13
- export declare function WalletModel(pubkey: string): Model<WalletInfo | undefined>;