applesauce-wallet 0.0.0-next-20251209200210 → 0.0.0-next-20251220152312

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 (75) 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 +2 -2
  4. package/dist/actions/index.js +2 -2
  5. package/dist/actions/{zap-info.d.ts → nutzap-info.d.ts} +20 -3
  6. package/dist/actions/nutzap-info.js +117 -0
  7. package/dist/actions/nutzaps.d.ts +24 -0
  8. package/dist/actions/nutzaps.js +154 -0
  9. package/dist/actions/tokens.d.ts +77 -7
  10. package/dist/actions/tokens.js +332 -69
  11. package/dist/actions/wallet.d.ts +18 -3
  12. package/dist/actions/wallet.js +74 -32
  13. package/dist/blueprints/history.d.ts +1 -1
  14. package/dist/blueprints/history.js +1 -1
  15. package/dist/blueprints/wallet.d.ts +5 -1
  16. package/dist/blueprints/wallet.js +6 -3
  17. package/dist/casts/__register__.d.ts +20 -0
  18. package/dist/casts/__register__.js +41 -0
  19. package/dist/casts/index.d.ts +6 -0
  20. package/dist/casts/index.js +6 -0
  21. package/dist/casts/nutzap-info.d.ts +14 -0
  22. package/dist/casts/nutzap-info.js +22 -0
  23. package/dist/casts/nutzap.d.ts +16 -0
  24. package/dist/casts/nutzap.js +37 -0
  25. package/dist/casts/wallet-history.d.ts +16 -0
  26. package/dist/casts/wallet-history.js +40 -0
  27. package/dist/casts/wallet-token.d.ts +29 -0
  28. package/dist/casts/wallet-token.js +52 -0
  29. package/dist/casts/wallet.d.ts +27 -0
  30. package/dist/casts/wallet.js +62 -0
  31. package/dist/helpers/cashu.d.ts +21 -0
  32. package/dist/helpers/cashu.js +105 -0
  33. package/dist/helpers/couch.d.ts +11 -0
  34. package/dist/helpers/couch.js +1 -0
  35. package/dist/helpers/history.d.ts +5 -1
  36. package/dist/helpers/history.js +13 -4
  37. package/dist/helpers/index.d.ts +5 -1
  38. package/dist/helpers/index.js +5 -1
  39. package/dist/helpers/indexed-db-couch.d.ts +34 -0
  40. package/dist/helpers/indexed-db-couch.js +119 -0
  41. package/dist/helpers/local-storage-couch.d.ts +29 -0
  42. package/dist/helpers/local-storage-couch.js +78 -0
  43. package/dist/helpers/{zap-info.d.ts → nutzap-info.d.ts} +10 -1
  44. package/dist/helpers/{zap-info.js → nutzap-info.js} +22 -10
  45. package/dist/helpers/nutzap.d.ts +15 -0
  46. package/dist/helpers/nutzap.js +57 -3
  47. package/dist/helpers/tokens.d.ts +9 -18
  48. package/dist/helpers/tokens.js +64 -94
  49. package/dist/helpers/wallet.d.ts +16 -6
  50. package/dist/helpers/wallet.js +40 -14
  51. package/dist/index.d.ts +1 -0
  52. package/dist/index.js +1 -0
  53. package/dist/models/history.d.ts +1 -1
  54. package/dist/models/history.js +7 -10
  55. package/dist/models/index.d.ts +0 -1
  56. package/dist/models/index.js +0 -1
  57. package/dist/models/nutzap.d.ts +2 -0
  58. package/dist/models/nutzap.js +8 -0
  59. package/dist/models/tokens.d.ts +2 -2
  60. package/dist/models/tokens.js +14 -17
  61. package/dist/operations/history.js +1 -1
  62. package/dist/operations/index.d.ts +1 -1
  63. package/dist/operations/index.js +1 -1
  64. package/dist/operations/nutzap-info.d.ts +21 -0
  65. package/dist/operations/nutzap-info.js +71 -0
  66. package/dist/operations/wallet.d.ts +10 -1
  67. package/dist/operations/wallet.js +33 -3
  68. package/package.json +15 -6
  69. package/dist/actions/zap-info.js +0 -83
  70. package/dist/actions/zaps.d.ts +0 -8
  71. package/dist/actions/zaps.js +0 -30
  72. package/dist/models/wallet.d.ts +0 -13
  73. package/dist/models/wallet.js +0 -21
  74. package/dist/operations/zap-info.d.ts +0 -10
  75. package/dist/operations/zap-info.js +0 -17
@@ -1,9 +1,12 @@
1
1
  import { blueprint } from "applesauce-core";
2
+ import { modifyHiddenTags } from "applesauce-core/operations";
2
3
  import { WALLET_BACKUP_KIND, WALLET_KIND } from "../helpers/wallet.js";
3
- import { setBackupContent, setMints, setPrivateKey } from "../operations/wallet.js";
4
+ import { setBackupContent, setMintTags, setPrivateKeyTag, setRelayTags } from "../operations/wallet.js";
4
5
  /** A blueprint to create a new 17375 wallet */
5
- export function WalletBlueprint(mints, privateKey) {
6
- return blueprint(WALLET_KIND, setMints(mints), privateKey ? setPrivateKey(privateKey) : undefined);
6
+ export function WalletBlueprint({ mints, privateKey, relays, }) {
7
+ return blueprint(WALLET_KIND,
8
+ // Use top level modifyHiddenTags to avoid multiple encryption operations
9
+ modifyHiddenTags(setMintTags(mints), privateKey ? setPrivateKeyTag(privateKey) : undefined, relays ? setRelayTags(relays) : undefined));
7
10
  }
8
11
  /** A blueprint that creates a new 375 wallet backup event */
9
12
  export function WalletBackupBlueprint(wallet) {
@@ -0,0 +1,20 @@
1
+ import { ChainableObservable } from "applesauce-common/observable";
2
+ import { NutzapInfo } from "./nutzap-info.js";
3
+ import { Nutzap } from "./nutzap.js";
4
+ import { Wallet } from "./wallet.js";
5
+ declare module "applesauce-common/casts/user" {
6
+ interface User {
7
+ readonly wallet$: ChainableObservable<Wallet | undefined>;
8
+ readonly nutzap$: ChainableObservable<NutzapInfo | undefined>;
9
+ }
10
+ }
11
+ declare module "applesauce-common/casts/stream" {
12
+ interface Stream {
13
+ readonly nutzaps$: ChainableObservable<Nutzap[]>;
14
+ }
15
+ }
16
+ declare module "applesauce-common/casts/note" {
17
+ interface Note {
18
+ nutzaps$(): ChainableObservable<Nutzap[]>;
19
+ }
20
+ }
@@ -0,0 +1,41 @@
1
+ import { Note, Stream } from "applesauce-common/casts";
2
+ import { User } from "applesauce-common/casts/user";
3
+ import { castEventStream, castTimelineStream } from "applesauce-common/observable";
4
+ import { buildCommonEventRelationFilters } from "applesauce-core/helpers";
5
+ import { switchMap } from "rxjs";
6
+ import { NUTZAP_KIND } from "../helpers/nutzap.js";
7
+ import { WALLET_KIND } from "../helpers/wallet.js";
8
+ import { NUTZAP_INFO_KIND } from "../helpers/nutzap-info.js";
9
+ import { NutzapInfo } from "./nutzap-info.js";
10
+ import { Nutzap } from "./nutzap.js";
11
+ import { Wallet } from "./wallet.js";
12
+ Object.defineProperty(User.prototype, "wallet$", {
13
+ get: function () {
14
+ return this.$$ref("wallet$", (store) => this.outboxes$.pipe(switchMap((outboxes) => store
15
+ .replaceable({ kind: WALLET_KIND, pubkey: this.pubkey, relays: outboxes })
16
+ .pipe(castEventStream(Wallet, store)))));
17
+ },
18
+ enumerable: true,
19
+ configurable: false,
20
+ });
21
+ Object.defineProperty(User.prototype, "nutzap$", {
22
+ get: function () {
23
+ return this.$$ref("nutzap$", (store) => store.replaceable(NUTZAP_INFO_KIND, this.pubkey).pipe(castEventStream(NutzapInfo, store)));
24
+ },
25
+ enumerable: true,
26
+ configurable: false,
27
+ });
28
+ Note.prototype.nutzaps$ = function () {
29
+ return this.$$ref("nutzaps$", (store) => store
30
+ .timeline(buildCommonEventRelationFilters({ kinds: [NUTZAP_KIND] }, this.event))
31
+ .pipe(castTimelineStream(Nutzap, store)));
32
+ };
33
+ Object.defineProperty(Stream.prototype, "nutzaps$", {
34
+ get: function () {
35
+ return this.$$ref("nutzaps$", (store) => store
36
+ .timeline(buildCommonEventRelationFilters({ kinds: [NUTZAP_KIND] }, this.event))
37
+ .pipe(castTimelineStream(Nutzap, store)));
38
+ },
39
+ enumerable: true,
40
+ configurable: false,
41
+ });
@@ -0,0 +1,6 @@
1
+ export * from "./nutzap-info.js";
2
+ export * from "./nutzap.js";
3
+ export * from "./wallet-history.js";
4
+ export * from "./wallet-token.js";
5
+ export * from "./wallet.js";
6
+ import "./__register__.js";
@@ -0,0 +1,6 @@
1
+ export * from "./nutzap-info.js";
2
+ export * from "./nutzap.js";
3
+ export * from "./wallet-history.js";
4
+ export * from "./wallet-token.js";
5
+ export * from "./wallet.js";
6
+ import "./__register__.js";
@@ -0,0 +1,14 @@
1
+ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { NutzapInfoEvent } from "../helpers/nutzap-info.js";
4
+ export declare class NutzapInfo extends EventCast<NutzapInfoEvent> {
5
+ constructor(event: NostrEvent, store: CastRefEventStore);
6
+ get relays(): string[];
7
+ get mints(): {
8
+ mint: string;
9
+ units?: string[];
10
+ }[];
11
+ /** The p2pk public key to use when zapping */
12
+ get publicKey(): string | undefined;
13
+ get p2pk(): string | undefined;
14
+ }
@@ -0,0 +1,22 @@
1
+ import { EventCast } from "applesauce-common/casts";
2
+ import { getNutzapInfoMints, getNutzapInfoPubkey, getNutzapInfoRelays, isValidNutzapInfo, } from "../helpers/nutzap-info.js";
3
+ export class NutzapInfo extends EventCast {
4
+ constructor(event, store) {
5
+ if (!isValidNutzapInfo(event))
6
+ throw new Error("Invalid nutzap info");
7
+ super(event, store);
8
+ }
9
+ get relays() {
10
+ return getNutzapInfoRelays(this.event);
11
+ }
12
+ get mints() {
13
+ return getNutzapInfoMints(this.event);
14
+ }
15
+ /** The p2pk public key to use when zapping */
16
+ get publicKey() {
17
+ return getNutzapInfoPubkey(this.event);
18
+ }
19
+ get p2pk() {
20
+ return this.publicKey;
21
+ }
22
+ }
@@ -0,0 +1,16 @@
1
+ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
+ import { NostrEvent } from "applesauce-core/helpers/event";
3
+ import { NutzapEvent } from "../helpers/nutzap.js";
4
+ export declare class Nutzap extends EventCast<NutzapEvent> {
5
+ constructor(event: NostrEvent, store: CastRefEventStore);
6
+ get proofs(): import("@cashu/cashu-ts").Proof[];
7
+ get mint(): string;
8
+ get amount(): number;
9
+ get recipient(): import("applesauce-common/casts").User;
10
+ get sender(): import("applesauce-common/casts").User;
11
+ get comment(): string | undefined;
12
+ /** The pointer to the event that was zapped */
13
+ get pointer(): import("nostr-tools/nip19").EventPointer | import("nostr-tools/nip19").AddressPointer | undefined;
14
+ /** The event that was zapped */
15
+ get zapped$(): import("applesauce-common/observable").ChainableObservable<import("nostr-tools").Event | undefined>;
16
+ }
@@ -0,0 +1,37 @@
1
+ import { EventCast } from "applesauce-common/casts";
2
+ import { castUser } from "applesauce-common/casts/user";
3
+ import { of } from "rxjs";
4
+ import { getNutzapAddressPointer, getNutzapAmount, getNutzapComment, getNutzapEventPointer, getNutzapMint, getNutzapProofs, getNutzapRecipient, isValidNutzap, } from "../helpers/nutzap.js";
5
+ export class Nutzap extends EventCast {
6
+ constructor(event, store) {
7
+ if (!isValidNutzap(event))
8
+ throw new Error("Invalid nutzap");
9
+ super(event, store);
10
+ }
11
+ get proofs() {
12
+ return getNutzapProofs(this.event);
13
+ }
14
+ get mint() {
15
+ return getNutzapMint(this.event);
16
+ }
17
+ get amount() {
18
+ return getNutzapAmount(this.event);
19
+ }
20
+ get recipient() {
21
+ return castUser(getNutzapRecipient(this.event), this.store);
22
+ }
23
+ get sender() {
24
+ return this.author;
25
+ }
26
+ get comment() {
27
+ return getNutzapComment(this.event);
28
+ }
29
+ /** The pointer to the event that was zapped */
30
+ get pointer() {
31
+ return getNutzapAddressPointer(this.event) ?? getNutzapEventPointer(this.event);
32
+ }
33
+ /** The event that was zapped */
34
+ get zapped$() {
35
+ return this.$$ref("zapped$", (store) => (this.pointer ? store.event(this.pointer) : of(undefined)));
36
+ }
37
+ }
@@ -0,0 +1,16 @@
1
+ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
+ import { HiddenContentSigner } from "applesauce-core/helpers";
3
+ import { NostrEvent } from "applesauce-core/helpers/event";
4
+ import { WalletHistoryEvent } from "../helpers/history.js";
5
+ export declare class WalletHistory extends EventCast<WalletHistoryEvent> {
6
+ constructor(event: NostrEvent, store: CastRefEventStore);
7
+ /** The embedded history metadata */
8
+ get meta(): import("../helpers/history.js").HistoryContent | undefined;
9
+ get direction(): import("../helpers/history.js").HistoryDirection | undefined;
10
+ get amount(): number | undefined;
11
+ get redeemed(): string[];
12
+ get unlocked(): boolean;
13
+ unlock(signer: HiddenContentSigner): Promise<import("../helpers/history.js").HistoryContent>;
14
+ get meta$(): import("applesauce-common/observable").ChainableObservable<import("../helpers/history.js").HistoryContent | undefined>;
15
+ get amount$(): import("applesauce-common/observable").ChainableObservable<number | undefined>;
16
+ }
@@ -0,0 +1,40 @@
1
+ import { EventCast } from "applesauce-common/casts";
2
+ import { watchEventUpdates } from "applesauce-core/observable";
3
+ import { of } from "rxjs";
4
+ import { map } from "rxjs/operators";
5
+ import { getHistoryContent, getHistoryRedeemed, isHistoryContentUnlocked, isValidWalletHistory, unlockHistoryContent, } from "../helpers/history.js";
6
+ export class WalletHistory extends EventCast {
7
+ constructor(event, store) {
8
+ if (!isValidWalletHistory(event))
9
+ throw new Error("Invalid wallet history");
10
+ super(event, store);
11
+ }
12
+ /** The embedded history metadata */
13
+ get meta() {
14
+ return getHistoryContent(this.event);
15
+ }
16
+ // Direct getters (return undefined if locked)
17
+ get direction() {
18
+ return this.meta?.direction;
19
+ }
20
+ get amount() {
21
+ return this.meta?.amount;
22
+ }
23
+ get redeemed() {
24
+ return getHistoryRedeemed(this.event);
25
+ }
26
+ // Unlocking pattern
27
+ get unlocked() {
28
+ return isHistoryContentUnlocked(this.event);
29
+ }
30
+ async unlock(signer) {
31
+ return unlockHistoryContent(this.event, signer);
32
+ }
33
+ // Observable that emits when history is unlocked
34
+ get meta$() {
35
+ return this.$$ref("meta$", (store) => of(this.event).pipe(watchEventUpdates(store), map((event) => event && getHistoryContent(event))));
36
+ }
37
+ get amount$() {
38
+ return this.$$ref("amount$", () => this.meta$.pipe(map((meta) => meta?.amount)));
39
+ }
40
+ }
@@ -0,0 +1,29 @@
1
+ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
+ import { HiddenContentSigner } from "applesauce-core/helpers";
3
+ import { NostrEvent } from "applesauce-core/helpers/event";
4
+ import { WalletTokenEvent } from "../helpers/tokens.js";
5
+ export declare class WalletToken extends EventCast<WalletTokenEvent> {
6
+ constructor(event: NostrEvent, store: CastRefEventStore);
7
+ get meta(): import("../helpers/tokens.js").TokenContent | undefined;
8
+ get proofs(): {
9
+ amount: number;
10
+ secret: string;
11
+ C: string;
12
+ id: string;
13
+ }[] | undefined;
14
+ get mint(): string | undefined;
15
+ get amount(): number | undefined;
16
+ get deleted(): string[] | undefined;
17
+ get unlocked(): boolean;
18
+ unlock(signer: HiddenContentSigner): Promise<import("../helpers/tokens.js").TokenContent>;
19
+ get meta$(): import("applesauce-common/observable").ChainableObservable<import("../helpers/tokens.js").TokenContent>;
20
+ get mint$(): import("applesauce-common/observable").ChainableObservable<string>;
21
+ get proofs$(): import("applesauce-common/observable").ChainableObservable<{
22
+ amount: number;
23
+ secret: string;
24
+ C: string;
25
+ id: string;
26
+ }[]>;
27
+ get amount$(): import("applesauce-common/observable").ChainableObservable<number>;
28
+ get deleted$(): import("applesauce-common/observable").ChainableObservable<string[]>;
29
+ }
@@ -0,0 +1,52 @@
1
+ import { sumProofs } from "@cashu/cashu-ts";
2
+ import { EventCast } from "applesauce-common/casts";
3
+ import { defined, watchEventUpdates } from "applesauce-core/observable";
4
+ import { of } from "rxjs";
5
+ import { map } from "rxjs/operators";
6
+ import { getTokenContent, isTokenContentUnlocked, isValidWalletToken, unlockTokenContent, } from "../helpers/tokens.js";
7
+ export class WalletToken extends EventCast {
8
+ constructor(event, store) {
9
+ if (!isValidWalletToken(event))
10
+ throw new Error("Invalid wallet token");
11
+ super(event, store);
12
+ }
13
+ get meta() {
14
+ return getTokenContent(this.event);
15
+ }
16
+ // Direct getters (return undefined if locked)
17
+ get proofs() {
18
+ return this.meta?.proofs;
19
+ }
20
+ get mint() {
21
+ return this.meta?.mint;
22
+ }
23
+ get amount() {
24
+ return this.proofs && sumProofs(this.proofs);
25
+ }
26
+ get deleted() {
27
+ return this.meta?.del;
28
+ }
29
+ // Unlocking pattern
30
+ get unlocked() {
31
+ return isTokenContentUnlocked(this.event);
32
+ }
33
+ async unlock(signer) {
34
+ return unlockTokenContent(this.event, signer);
35
+ }
36
+ // Observable that emits when token is unlocked
37
+ get meta$() {
38
+ return this.$$ref("meta$", (store) => of(this.event).pipe(watchEventUpdates(store), map((event) => event && getTokenContent(event)), defined()));
39
+ }
40
+ get mint$() {
41
+ return this.$$ref("mint$", () => this.meta$.pipe(map((meta) => meta?.mint)));
42
+ }
43
+ get proofs$() {
44
+ return this.$$ref("proofs$", () => this.meta$.pipe(map((meta) => meta?.proofs)));
45
+ }
46
+ get amount$() {
47
+ return this.$$ref("amount$", () => this.proofs$.pipe(map(sumProofs)));
48
+ }
49
+ get deleted$() {
50
+ return this.$$ref("deleted$", () => this.meta$.pipe(map((meta) => meta?.del)));
51
+ }
52
+ }
@@ -0,0 +1,27 @@
1
+ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
+ import { HiddenContentSigner } from "applesauce-core/helpers";
3
+ import { NostrEvent } from "applesauce-core/helpers/event";
4
+ import { WalletEvent } from "../helpers/wallet.js";
5
+ import { WalletHistory } from "./wallet-history.js";
6
+ import { WalletToken } from "./wallet-token.js";
7
+ export declare class Wallet extends EventCast<WalletEvent> {
8
+ constructor(event: NostrEvent, store: CastRefEventStore);
9
+ get mints(): string[];
10
+ get relays(): string[] | undefined;
11
+ get privateKey(): Uint8Array<ArrayBufferLike> | null | undefined;
12
+ get unlocked(): boolean;
13
+ unlock(signer: HiddenContentSigner): Promise<{
14
+ mints: string[];
15
+ privateKey: Uint8Array | null;
16
+ relays: string[];
17
+ }>;
18
+ get mints$(): import("applesauce-common/observable").ChainableObservable<string[] | undefined>;
19
+ get relays$(): import("applesauce-common/observable").ChainableObservable<string[] | undefined>;
20
+ get balance$(): import("applesauce-common/observable").ChainableObservable<Record<string, number>>;
21
+ /** The p2pk locking private key for this wallet */
22
+ get privateKey$(): import("applesauce-common/observable").ChainableObservable<Uint8Array<ArrayBufferLike> | null | undefined>;
23
+ get tokens$(): import("applesauce-common/observable").ChainableObservable<WalletToken[]>;
24
+ get history$(): import("applesauce-common/observable").ChainableObservable<WalletHistory[]>;
25
+ get backups$(): import("applesauce-common/observable").ChainableObservable<import("nostr-tools").Event[]>;
26
+ get received$(): import("applesauce-common/observable").ChainableObservable<string[]>;
27
+ }
@@ -0,0 +1,62 @@
1
+ import { EventCast } from "applesauce-common/casts";
2
+ import { castTimelineStream } from "applesauce-common/observable";
3
+ import { watchEventUpdates } from "applesauce-core/observable";
4
+ import { of } from "rxjs";
5
+ import { map } from "rxjs/operators";
6
+ import { getWalletMints, getWalletPrivateKey, getWalletRelays, isValidWallet, isWalletUnlocked, unlockWallet, WALLET_BACKUP_KIND, } from "../helpers/wallet.js";
7
+ import { WalletHistoryModel } from "../models/history.js";
8
+ import { WalletBalanceModel, WalletTokensModel } from "../models/tokens.js";
9
+ import { WalletHistory } from "./wallet-history.js";
10
+ import { WalletToken } from "./wallet-token.js";
11
+ import { ReceivedNutzapsModel } from "../models/nutzap.js";
12
+ export class Wallet extends EventCast {
13
+ constructor(event, store) {
14
+ if (!isValidWallet(event))
15
+ throw new Error("Invalid wallet event");
16
+ super(event, store);
17
+ }
18
+ // Direct getters (return undefined if locked)
19
+ get mints() {
20
+ return getWalletMints(this.event);
21
+ }
22
+ get relays() {
23
+ return getWalletRelays(this.event);
24
+ }
25
+ get privateKey() {
26
+ return getWalletPrivateKey(this.event);
27
+ }
28
+ // Unlocking pattern
29
+ get unlocked() {
30
+ return isWalletUnlocked(this.event);
31
+ }
32
+ async unlock(signer) {
33
+ return unlockWallet(this.event, signer);
34
+ }
35
+ // Observable that emits when wallet is unlocked
36
+ get mints$() {
37
+ return this.$$ref("mints$", (store) => of(this.event).pipe(watchEventUpdates(store), map((event) => event && getWalletMints(event))));
38
+ }
39
+ get relays$() {
40
+ return this.$$ref("relays$", (store) => of(this.event).pipe(watchEventUpdates(store), map((event) => event && getWalletRelays(event))));
41
+ }
42
+ get balance$() {
43
+ return this.$$ref("balance$", (store) => store.model(WalletBalanceModel, this.event.pubkey));
44
+ }
45
+ /** The p2pk locking private key for this wallet */
46
+ get privateKey$() {
47
+ return this.$$ref("privateKey$", (store) => of(this.event).pipe(watchEventUpdates(store), map((event) => event && getWalletPrivateKey(event))));
48
+ }
49
+ // Observables for related events
50
+ get tokens$() {
51
+ return this.$$ref("tokens$", (store) => store.model(WalletTokensModel, this.event.pubkey).pipe(castTimelineStream(WalletToken, store)));
52
+ }
53
+ get history$() {
54
+ return this.$$ref("history$", (store) => store.model(WalletHistoryModel, this.event.pubkey).pipe(castTimelineStream(WalletHistory, store)));
55
+ }
56
+ get backups$() {
57
+ return this.$$ref("backups$", (store) => store.timeline({ kinds: [WALLET_BACKUP_KIND], authors: [this.event.pubkey] }));
58
+ }
59
+ get received$() {
60
+ return this.$$ref("received$", (store) => store.model(ReceivedNutzapsModel, this.event.pubkey));
61
+ }
62
+ }
@@ -0,0 +1,21 @@
1
+ import { Proof, Token } from "@cashu/cashu-ts";
2
+ /** Internal method for creating a unique id for each proof */
3
+ export declare function getProofUID(proof: Proof): string;
4
+ /**
5
+ * Extracts the P2PK locking pubkey from a proof's secret
6
+ * @param proof the cashu proof to extract the pubkey from
7
+ * @returns the pubkey, or undefined if not P2PK locked
8
+ */
9
+ export declare function getProofP2PKPubkey(proof: Proof): string | undefined;
10
+ /** Internal method to filter out duplicate proofs */
11
+ export declare function ignoreDuplicateProofs(seen?: Set<string>): (proof: Proof) => boolean;
12
+ /**
13
+ * Returns a decoded cashu token inside an unicode emoji
14
+ * @see https://github.com/cashubtc/cashu.me/blob/1194a7b9ee2f43305e38304de7bef8839601ff4d/src/components/ReceiveTokenDialog.vue#L387
15
+ */
16
+ export declare function decodeTokenFromEmojiString(str: string): Token | undefined;
17
+ /**
18
+ * Encodes a token into an emoji char
19
+ * @see https://github.com/cashubtc/cashu.me/blob/1194a7b9ee2f43305e38304de7bef8839601ff4d/src/components/SendTokenDialog.vue#L710
20
+ */
21
+ export declare function encodeTokenToEmoji(token: Token | string, emoji?: string): string;
@@ -0,0 +1,105 @@
1
+ import { getDecodedToken, getEncodedToken } from "@cashu/cashu-ts";
2
+ import { safeParse } from "applesauce-core/helpers";
3
+ /** Internal method for creating a unique id for each proof */
4
+ export function getProofUID(proof) {
5
+ return proof.id + proof.amount + proof.C + proof.secret;
6
+ }
7
+ /**
8
+ * Extracts the P2PK locking pubkey from a proof's secret
9
+ * @param proof the cashu proof to extract the pubkey from
10
+ * @returns the pubkey, or undefined if not P2PK locked
11
+ */
12
+ export function getProofP2PKPubkey(proof) {
13
+ const secret = safeParse(proof.secret);
14
+ if (!secret)
15
+ return;
16
+ if (!Array.isArray(secret))
17
+ return;
18
+ if (secret[0] !== "P2PK")
19
+ return;
20
+ const proofPubkey = secret[1]?.data;
21
+ if (!proofPubkey || typeof proofPubkey !== "string")
22
+ return;
23
+ return proofPubkey;
24
+ }
25
+ /** Internal method to filter out duplicate proofs */
26
+ export function ignoreDuplicateProofs(seen = new Set()) {
27
+ return (proof) => {
28
+ const id = getProofUID(proof);
29
+ if (seen.has(id))
30
+ return false;
31
+ else {
32
+ seen.add(id);
33
+ return true;
34
+ }
35
+ };
36
+ }
37
+ /**
38
+ * Returns a decoded cashu token inside an unicode emoji
39
+ * @see https://github.com/cashubtc/cashu.me/blob/1194a7b9ee2f43305e38304de7bef8839601ff4d/src/components/ReceiveTokenDialog.vue#L387
40
+ */
41
+ export function decodeTokenFromEmojiString(str) {
42
+ try {
43
+ let decoded = [];
44
+ const chars = Array.from(str);
45
+ if (!chars.length)
46
+ return undefined;
47
+ const fromVariationSelector = function (char) {
48
+ const codePoint = char.codePointAt(0);
49
+ if (codePoint === undefined)
50
+ return null;
51
+ // Handle Variation Selectors (VS1-VS16): U+FE00 to U+FE0F
52
+ if (codePoint >= 0xfe00 && codePoint <= 0xfe0f) {
53
+ // Maps FE00->0, FE01->1, ..., FE0F->15
54
+ const byteValue = codePoint - 0xfe00;
55
+ return String.fromCharCode(byteValue);
56
+ }
57
+ // Handle Variation Selectors Supplement (VS17-VS256): U+E0100 to U+E01EF
58
+ if (codePoint >= 0xe0100 && codePoint <= 0xe01ef) {
59
+ // Maps E0100->16, E0101->17, ..., E01EF->255
60
+ const byteValue = codePoint - 0xe0100 + 16;
61
+ return String.fromCharCode(byteValue);
62
+ }
63
+ // No Variation Selector
64
+ return null;
65
+ };
66
+ // Check all input chars for peanut data
67
+ for (const char of chars) {
68
+ let byte = fromVariationSelector(char);
69
+ if (byte === null && decoded.length > 0) {
70
+ break;
71
+ }
72
+ else if (byte === null) {
73
+ continue;
74
+ }
75
+ decoded.push(byte); // got some
76
+ }
77
+ // Switch out token if we found peanut data
78
+ let decodedString = decoded.join("");
79
+ return getDecodedToken(decodedString);
80
+ }
81
+ catch (error) {
82
+ return undefined;
83
+ }
84
+ }
85
+ /**
86
+ * Encodes a token into an emoji char
87
+ * @see https://github.com/cashubtc/cashu.me/blob/1194a7b9ee2f43305e38304de7bef8839601ff4d/src/components/SendTokenDialog.vue#L710
88
+ */
89
+ export function encodeTokenToEmoji(token, emoji = "🥜") {
90
+ return (emoji +
91
+ Array.from(typeof token === "string" ? token : getEncodedToken(token))
92
+ .map((char) => {
93
+ const byteValue = char.charCodeAt(0);
94
+ // For byte values 0-15, use Variation Selectors (VS1-VS16): U+FE00 to U+FE0F
95
+ if (byteValue >= 0 && byteValue <= 15) {
96
+ return String.fromCodePoint(0xfe00 + byteValue);
97
+ }
98
+ // For byte values 16-255, use Variation Selectors Supplement (VS17-VS256): U+E0100 to U+E01EF
99
+ if (byteValue >= 16 && byteValue <= 255) {
100
+ return String.fromCodePoint(0xe0100 + (byteValue - 16));
101
+ }
102
+ return "";
103
+ })
104
+ .join(""));
105
+ }
@@ -0,0 +1,11 @@
1
+ import { Token } from "@cashu/cashu-ts";
2
+ type ClearMethod = () => void | Promise<void>;
3
+ export interface Couch {
4
+ /** Store a token in the couch */
5
+ store(token: Token): ClearMethod | Promise<ClearMethod>;
6
+ /** Clear all tokens from the couch */
7
+ clear(): void | Promise<void>;
8
+ /** Get all tokens currently stored in the couch */
9
+ getAll(): Token[] | Promise<Token[]>;
10
+ }
11
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,10 @@
1
1
  import { HiddenContentSigner, UnlockedHiddenTags } from "applesauce-core/helpers";
2
- import { NostrEvent } from "applesauce-core/helpers/event";
2
+ import { KnownEvent, NostrEvent } from "applesauce-core/helpers/event";
3
3
  export declare const WALLET_HISTORY_KIND = 7376;
4
+ /** Validated wallet history event */
5
+ export type WalletHistoryEvent = KnownEvent<typeof WALLET_HISTORY_KIND>;
6
+ /** Checks if an event is a valid wallet history event */
7
+ export declare function isValidWalletHistory(event: NostrEvent): event is WalletHistoryEvent;
4
8
  export type HistoryDirection = "in" | "out";
5
9
  export type HistoryContent = {
6
10
  /** The direction of the transaction, in = received, out = sent */
@@ -1,5 +1,9 @@
1
- import { getHiddenTags, isETag, isHiddenTagsUnlocked, lockHiddenTags, notifyEventUpdate, setHiddenTagsEncryptionMethod, unlockHiddenTags, } from "applesauce-core/helpers";
1
+ import { getHiddenTags, hasHiddenTags, isETag, isHiddenTagsUnlocked, lockHiddenTags, notifyEventUpdate, setHiddenTagsEncryptionMethod, unlockHiddenTags, } from "applesauce-core/helpers";
2
2
  export const WALLET_HISTORY_KIND = 7376;
3
+ /** Checks if an event is a valid wallet history event */
4
+ export function isValidWalletHistory(event) {
5
+ return event.kind === WALLET_HISTORY_KIND && hasHiddenTags(event);
6
+ }
3
7
  // Enable hidden content for wallet history kind
4
8
  setHiddenTagsEncryptionMethod(WALLET_HISTORY_KIND, "nip44");
5
9
  export const HistoryContentSymbol = Symbol.for("history-content");
@@ -9,11 +13,16 @@ export function getHistoryRedeemed(history) {
9
13
  }
10
14
  /** Checks if the history contents are locked */
11
15
  export function isHistoryContentUnlocked(history) {
12
- return isHiddenTagsUnlocked(history) && Reflect.has(history, HistoryContentSymbol) === true;
16
+ // Wrap in try catch to avoid throwing validation errors
17
+ try {
18
+ return (HistoryContentSymbol in history || (isHiddenTagsUnlocked(history) && getHistoryContent(history) !== undefined));
19
+ }
20
+ catch { }
21
+ return false;
13
22
  }
14
23
  export function getHistoryContent(history) {
15
24
  // Return cached value if it exists
16
- if (isHistoryContentUnlocked(history))
25
+ if (HistoryContentSymbol in history)
17
26
  return history[HistoryContentSymbol];
18
27
  // Get hidden tags
19
28
  const tags = getHiddenTags(history);
@@ -41,7 +50,7 @@ export function getHistoryContent(history) {
41
50
  /** Decrypts a wallet history event */
42
51
  export async function unlockHistoryContent(history, signer) {
43
52
  // Return cached value if it exists
44
- if (isHistoryContentUnlocked(history))
53
+ if (HistoryContentSymbol in history)
45
54
  return history[HistoryContentSymbol];
46
55
  // Unlock hidden tags if needed
47
56
  await unlockHiddenTags(history, signer);
@@ -2,5 +2,9 @@ export * from "./animated-qr.js";
2
2
  export * from "./history.js";
3
3
  export * from "./tokens.js";
4
4
  export * from "./wallet.js";
5
- export * from "./zap-info.js";
5
+ export * from "./nutzap-info.js";
6
6
  export * from "./nutzap.js";
7
+ export * from "./cashu.js";
8
+ export * from "./couch.js";
9
+ export * from "./local-storage-couch.js";
10
+ export * from "./indexed-db-couch.js";
@@ -2,5 +2,9 @@ export * from "./animated-qr.js";
2
2
  export * from "./history.js";
3
3
  export * from "./tokens.js";
4
4
  export * from "./wallet.js";
5
- export * from "./zap-info.js";
5
+ export * from "./nutzap-info.js";
6
6
  export * from "./nutzap.js";
7
+ export * from "./cashu.js";
8
+ export * from "./couch.js";
9
+ export * from "./local-storage-couch.js";
10
+ export * from "./indexed-db-couch.js";