@qntx/wallet-engine 0.4.0 → 0.6.0

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.
package/dist/index.d.mts CHANGED
@@ -1,11 +1,19 @@
1
+ import { r as NetworkInfo } from "./registry-9oeWs_yZ.mjs";
1
2
  import { StoreApi } from "zustand/vanilla";
3
+ import "@scure/btc-signer";
2
4
  import { CooperativeExitResult, LightningInvoice, LightningPayment, SparkClient, SparkExitChain, SparkNetwork, SparkPayment, SparkStore, SparkTransfer } from "@qntx/spark";
3
- import { NostrKeyRef, WalletSigner } from "@qntx/wallet/nostr";
4
- import { SparkSigner } from "@qntx/wallet/spark";
5
+ import { decodeEvm } from "@qntx/wallet-chains/evm";
5
6
  import { BackupHeader, BackupInfo, InitialFactor, UnlockFactor, Wallet, WalletInfo } from "@qntx/wallet";
6
- import { Event, Filter, NostrSigner } from "@qntx/nostr";
7
7
  import { LnurlPayRequest, LnurlWithdrawRequest } from "@qntx/spark/lnurl";
8
+ import { Event, Filter, NostrSigner } from "@qntx/nostr";
9
+ import { NostrKeyRef, WalletSigner } from "@qntx/wallet/nostr";
10
+ import { SparkSigner } from "@qntx/wallet/spark";
11
+ import { PublicClient } from "viem";
12
+ import { chains } from "@qntx/wallet/chains";
13
+ import "@solana/kit";
8
14
  import { SparkAccountRef, SparkApproveIntent } from "@qntx/wallet/protocol";
15
+ import "@qntx/wallet-chains";
16
+ import "@scure/btc-signer/psbt.js";
9
17
  //#region src/controller.d.ts
10
18
  type ControllerOptions<S> = {
11
19
  readonly name: string;
@@ -69,27 +77,166 @@ export declare function createMemoryEngineStore(backing?: {
69
77
  readonly collections?: Map<string, Map<string, Uint8Array>>;
70
78
  }): EngineStore;
71
79
  //#endregion
72
- //#region src/meta/doc.d.ts
73
- /**
74
- * Wallet metadata document — the plaintext exchanged over kind-30078 events between this wallet's
75
- * own devices. One document per wallet; entry-level last-writer-wins on `updatedAt`.
76
- */
77
- type MetaDocWallet = {
78
- readonly name?: string;
80
+ //#region src/addresses/normalize.d.ts
81
+ type AddressFamily = "evm" | "solana" | "bitcoin" | "spark";
82
+ //#endregion
83
+ //#region src/addresses/record.d.ts
84
+ type AddressBookEntry = {
85
+ readonly id: string;
86
+ readonly name: string;
87
+ readonly family: AddressFamily;
88
+ readonly address: string;
89
+ readonly note?: string;
90
+ readonly createdAt: number;
79
91
  readonly updatedAt: number;
80
92
  };
81
- type MetaDocGroup = {
82
- readonly index: number;
83
- readonly name?: string;
84
- readonly hidden: boolean;
85
- readonly boundPubkey?: string;
93
+ type AddressBookTombstone = {
94
+ readonly id: string;
95
+ readonly deleted: true;
86
96
  readonly updatedAt: number;
87
97
  };
88
- type MetaDoc = {
89
- readonly v: 1;
90
- readonly wallet: MetaDocWallet;
91
- readonly groups: ReadonlyArray<MetaDocGroup>;
98
+ type AddressBookRecord = AddressBookEntry | AddressBookTombstone;
99
+ //#endregion
100
+ //#region src/addresses/controller.d.ts
101
+ type AddressBookState = {
102
+ /** Live entries only; tombstones stay internal. */
103
+ readonly entries: Record<string, AddressBookEntry>;
104
+ };
105
+ type AddressBookOptions = {
106
+ readonly openStore: () => Promise<EngineStore>;
107
+ readonly random: (n: number) => Uint8Array;
108
+ readonly now: () => number;
109
+ readonly logger: EngineLogger;
110
+ };
111
+ export declare class AddressBookController extends Controller<AddressBookState> {
112
+ private readonly options;
113
+ private engineStore;
114
+ /** Every record, tombstones included, by id. */
115
+ private records;
116
+ constructor(options: AddressBookOptions);
117
+ init(): Promise<void>;
118
+ destroy(): Promise<void>;
119
+ lock(): void;
120
+ /** Entries and tombstones, for the metadata document. */
121
+ syncEntries(): ReadonlyArray<AddressBookRecord>;
122
+ /**
123
+ * Merges records from another device (last writer wins, tombstones win over older entries).
124
+ * Returns whether anything local changed and whether the merged set holds something `remote`
125
+ * lacks, i.e. whether the remote copy needs a newer publish.
126
+ */
127
+ merge(remote: ReadonlyArray<AddressBookRecord>): Promise<{
128
+ readonly changed: boolean;
129
+ readonly localNewer: boolean;
130
+ }>;
131
+ add(params: {
132
+ readonly name: string;
133
+ readonly family: AddressFamily;
134
+ readonly address: string;
135
+ readonly note?: string;
136
+ }): Promise<AddressBookEntry>;
137
+ rename(id: string, name: string): Promise<AddressBookEntry>;
138
+ /** Sets or clears (empty or `undefined`) the note. */
139
+ setNote(id: string, note: string | undefined): Promise<AddressBookEntry>;
140
+ /** Removes the entry, leaving a tombstone so other devices drop it too. */
141
+ remove(id: string): Promise<void>;
142
+ private checkedNote;
143
+ private requireEntry;
144
+ private persist;
145
+ private requireStore;
146
+ }
147
+ //#endregion
148
+ //#region src/addresses/errors.d.ts
149
+ type AddressBookErrorCategory = "invalid-input" | "duplicate" | "not-found" | "locked" | "limit";
150
+ export declare class AddressBookError extends Error {
151
+ readonly category: AddressBookErrorCategory;
152
+ constructor(category: AddressBookErrorCategory, message: string);
153
+ }
154
+ //#endregion
155
+ //#region src/chains/evm.d.ts
156
+ type EvmFeeTier = "slow" | "normal" | "fast";
157
+ //#endregion
158
+ //#region src/chains/bitcoin.d.ts
159
+ type Esplora = {
160
+ readonly get: (path: string) => Promise<unknown>;
161
+ readonly post: (path: string, body: string) => Promise<unknown>;
162
+ };
163
+ //#endregion
164
+ //#region src/networks/controller.d.ts
165
+ type SolanaRpc = {
166
+ readonly call: (method: string, params: unknown[]) => Promise<unknown>;
167
+ };
168
+ /**
169
+ * A host-endpoint-only client for cross-checking pre-signing reads. `not-needed`: the gateway is
170
+ * not this network's first endpoint, so the primary reads already come from the host.
171
+ * `unavailable`: a cross-check is needed but the network has no host endpoint.
172
+ */
173
+ type Independent<T> = {
174
+ readonly kind: "not-needed";
175
+ } | {
176
+ readonly kind: "unavailable";
177
+ } | {
178
+ readonly kind: "available";
179
+ readonly client: T;
180
+ };
181
+ type NetworkControllerState = {
182
+ readonly customRpc: Record<string, ReadonlyArray<string>>;
183
+ };
184
+ type Options$2 = {
185
+ readonly fetch: typeof globalThis.fetch;
186
+ readonly rpc: Readonly<Record<string, ReadonlyArray<string>>>;
187
+ readonly openStore: () => Promise<EngineStore>;
188
+ readonly logger: EngineLogger;
189
+ readonly gateway?: {
190
+ readonly url: string;
191
+ readonly installId: string;
192
+ } | undefined;
92
193
  };
194
+ declare class NetworkController extends Controller<NetworkControllerState> {
195
+ private readonly options;
196
+ private engineStore?;
197
+ private readonly clients;
198
+ private readonly gatewayBase;
199
+ private readonly gatewayOrigin;
200
+ /** Networks the gateway reported at unlock; empty while locked or when the read failed. */
201
+ private gatewayServed;
202
+ constructor(options: Options$2);
203
+ init(): Promise<void>;
204
+ private loadCustomRpc;
205
+ /** Reads the gateway's served networks; any failure leaves the gateway unused until next unlock. */
206
+ private loadGatewayNetworks;
207
+ /** `fetch` that adds the install id to requests bound for the gateway's origin only. */
208
+ private readonly gatewayFetch;
209
+ destroy(): Promise<void>;
210
+ lock(): void;
211
+ /**
212
+ * Ordered endpoints: a network with custom endpoints uses custom → host and never the gateway;
213
+ * otherwise a gateway-served network uses gateway → host; else host only.
214
+ */
215
+ endpoints(network: string): ReadonlyArray<string>;
216
+ info(network: string): NetworkInfo;
217
+ client(network: string): PublicClient;
218
+ /** True when the gateway heads this network's endpoint list (no custom endpoints, gateway-served). */
219
+ private gatewayFirst;
220
+ private independent;
221
+ /** Host-endpoint EVM client for cross-checking reads; never sends the install id. */
222
+ independentClient(network: string): Independent<PublicClient>;
223
+ independentSolanaRpc(network: string): Independent<SolanaRpc>;
224
+ independentEsplora(network: string): Independent<Esplora>;
225
+ /** Networks with at least one configured endpoint or served by the gateway, by family. */
226
+ enabled(family: "evm" | "solana" | "bitcoin"): ReadonlyArray<string>;
227
+ /** Solana JSON-RPC over the ordered endpoint list — kit's transport is single-endpoint. */
228
+ solanaRpc(network: string): SolanaRpc;
229
+ /** Bounded-concurrency + 429-aware ordered-failover Esplora client. */
230
+ esplora(network: string): Esplora;
231
+ /** Validate a custom endpoint's reported chain id, then persist it first in the list. */
232
+ addRpc(network: string, url: string): Promise<void>;
233
+ }
234
+ //#endregion
235
+ //#region src/chains/solana.d.ts
236
+ type SolanaFeeTier = "slow" | "normal" | "fast";
237
+ //#endregion
238
+ //#region src/requests/checks.d.ts
239
+ type RequestCheckCode = "decode-partial" | "nonce-mismatch" | "fee-mismatch" | "reads-unverified" | "fee-above-network" | "fee-exceeds-amount";
93
240
  //#endregion
94
241
  //#region src/spark/notes.d.ts
95
242
  /**
@@ -262,10 +409,467 @@ export declare class SparkController extends Controller<SparkControllerState> {
262
409
  }): Promise<CooperativeExitResult>;
263
410
  }
264
411
  //#endregion
412
+ //#region src/payments/action.d.ts
413
+ /**
414
+ * What the host shows for a Spark, Lightning or exit request; `family` tells it apart from a chain
415
+ * intent.
416
+ */
417
+ type SparkDisplay = {
418
+ readonly family: "spark";
419
+ readonly network: SparkNetwork;
420
+ readonly kind: "transfer" | "lightning" | "exit";
421
+ readonly amountSats: number;
422
+ readonly maxFeeSats?: number;
423
+ /** Spark address, Lightning payee public key (hex) or bitcoin address. */
424
+ readonly receiver: string;
425
+ /** Invoice description or the LNURL metadata text. */
426
+ readonly description?: string;
427
+ };
428
+ type SparkResult = {
429
+ readonly kind: "spark";
430
+ readonly transfer: SparkTransfer;
431
+ } | {
432
+ readonly kind: "lightning";
433
+ readonly payment: LightningPayment;
434
+ } | {
435
+ readonly kind: "withdraw";
436
+ readonly exit: CooperativeExitResult;
437
+ };
438
+ /**
439
+ * A validated, fixed Spark payment: everything that does not need the user's verification has
440
+ * happened (including any LNURL invoice fetch), so approval only re-checks expiry and executes.
441
+ */
442
+ type PreparedSparkAction = {
443
+ readonly display: SparkDisplay;
444
+ readonly checks: ReadonlyArray<RequestCheckCode>;
445
+ /** Why the action can no longer be paid at `now` (an expiring invoice), if so. */
446
+ readonly staleReason: (now: number) => string | undefined;
447
+ /** Runs the controller's approve-first payment call. */
448
+ readonly execute: (spark: SparkController, verify: UnlockFactor) => Promise<SparkResult>;
449
+ };
450
+ //#endregion
451
+ //#region src/payments/parse.d.ts
452
+ type PaymentOption = {
453
+ readonly kind: "spark";
454
+ readonly address: string;
455
+ } | {
456
+ readonly kind: "spark-invoice";
457
+ readonly invoice: string;
458
+ readonly amountSats?: number;
459
+ readonly memo?: string;
460
+ readonly expiresAt?: number;
461
+ } | {
462
+ readonly kind: "lightning";
463
+ readonly invoice: string;
464
+ readonly amountSats?: number;
465
+ readonly paymentHash: string;
466
+ readonly description?: string;
467
+ readonly expiresAt: number;
468
+ } | {
469
+ readonly kind: "lnurl-pay";
470
+ readonly request: LnurlPayRequest;
471
+ readonly address?: string;
472
+ } | {
473
+ readonly kind: "lnurl-withdraw";
474
+ readonly request: LnurlWithdrawRequest;
475
+ } | {
476
+ readonly kind: "bitcoin";
477
+ readonly address: string;
478
+ };
479
+ type PaymentRequest = {
480
+ readonly options: ReadonlyArray<PaymentOption>;
481
+ readonly amountSats?: number;
482
+ readonly label?: string;
483
+ readonly message?: string;
484
+ };
485
+ type PaymentParse = {
486
+ readonly kind: "request";
487
+ readonly request: PaymentRequest;
488
+ } | {
489
+ readonly kind: "lnurl";
490
+ readonly url: string;
491
+ readonly address?: string;
492
+ } | {
493
+ readonly kind: "unsupported";
494
+ readonly format: "bolt12" | "silent-payment" | "lnurl-auth" | "spark-token-invoice" | "nostr-wallet-connect";
495
+ } | {
496
+ readonly kind: "invalid";
497
+ readonly reason: "network" | "expired" | "amount-mismatch" | "malformed";
498
+ } | {
499
+ readonly kind: "unrecognized";
500
+ };
501
+ type ParseOptions = {
502
+ readonly network: SparkNetwork;
503
+ readonly now: number;
504
+ };
505
+ /** `input` → PaymentParse. Never throws: every failure is a structured result. */
506
+ export declare function parsePayment(input: string, options: ParseOptions): PaymentParse;
507
+ //#endregion
508
+ //#region src/payments/pay.d.ts
509
+ type PayParams = {
510
+ readonly account: SparkAccountRef;
511
+ readonly option: PaymentOption;
512
+ /** Caller-supplied amount — required by open invoices, the `spark` option, and LNURL flows. */
513
+ readonly amountSats?: number;
514
+ readonly comment?: string;
515
+ readonly maxFeeSats?: number;
516
+ readonly speed?: "FAST" | "MEDIUM" | "SLOW";
517
+ };
518
+ type WithdrawLnurlParams = {
519
+ readonly account: SparkAccountRef;
520
+ readonly option: Extract<PaymentOption, {
521
+ kind: "lnurl-withdraw";
522
+ }>;
523
+ readonly amountSats: number;
524
+ };
525
+ //#endregion
526
+ //#region src/payments/zap.d.ts
527
+ /** A profile zap names the recipient pubkey; an event zap carries the event it zaps. */
528
+ type ZapRecipient = {
529
+ readonly pubkey: string;
530
+ readonly lightning: string;
531
+ } | {
532
+ readonly event: Event;
533
+ readonly lightning: string;
534
+ };
535
+ type PrepareZapParams = {
536
+ /** Any `NostrSigner` — wallet key, external key, NIP-07/46 — signs the 9734. */
537
+ readonly signer: NostrSigner;
538
+ readonly recipient: ZapRecipient;
539
+ readonly amountSats: number;
540
+ readonly comment?: string | undefined;
541
+ readonly relays: ReadonlyArray<string>;
542
+ readonly network: SparkNetwork;
543
+ };
544
+ type PrepareZapContext = {
545
+ readonly fetch: typeof globalThis.fetch;
546
+ readonly now: () => number;
547
+ };
548
+ /** Everything a payer needs: the signed 9734, the invoice, and the note fields. */
549
+ type PreparedZap = {
550
+ readonly zapRequest: Event;
551
+ readonly invoice: string;
552
+ /** Hex payment hash decoded from the invoice. */
553
+ readonly paymentHash: string;
554
+ /** Millisecond expiry decoded from the invoice. */
555
+ readonly expiresAt: number;
556
+ readonly amountSats: number;
557
+ /** The LNURL service's 9735 signing pubkey. */
558
+ readonly receiptPubkey: string;
559
+ readonly recipientPubkey: string;
560
+ readonly eventId?: string;
561
+ readonly comment?: string;
562
+ /** The lud16 or LNURL as given. */
563
+ readonly lightning: string;
564
+ };
565
+ /** Everything up to payment: resolve LNURL, sign the 9734, request the invoice. */
566
+ export declare function prepareZap(params: PrepareZapParams, context: PrepareZapContext): Promise<PreparedZap>;
567
+ //#endregion
568
+ //#region src/transactions/route.d.ts
569
+ type SignParams = Parameters<ReturnType<typeof chains>["sign"]>[0];
570
+ type AccountRef = SignParams["request"]["account"];
571
+ type DisplayIntent = ReturnType<typeof decodeEvm>;
572
+ type TxState = "draft" | "signed" | "submitted" | "pending" | "confirmed" | "failed" | "rejected" | "dropped" | "replaced";
573
+ type TrackedTransaction = {
574
+ readonly id: string;
575
+ readonly family: "evm" | "solana" | "bitcoin";
576
+ readonly network: string;
577
+ readonly account: string;
578
+ readonly hash: string | undefined;
579
+ readonly state: TxState;
580
+ readonly intent: DisplayIntent | undefined;
581
+ readonly nonce: number;
582
+ /** Solana only — the blockhash expiry that turns an unconfirmed tx `dropped`. */
583
+ readonly lastValidBlockHeight?: number;
584
+ /** EVM replacement — the earlier transaction this one bumps or cancels. */
585
+ readonly replaces?: string;
586
+ /** CPFP — the unconfirmed parent this child pushes. */
587
+ readonly parentId?: string;
588
+ /** Bitcoin build record persisted at send for RBF/CPFP rebuilds. */
589
+ readonly btc?: {
590
+ readonly inputs: ReadonlyArray<{
591
+ readonly txid: string;
592
+ readonly vout: number;
593
+ readonly value: number;
594
+ readonly address: string;
595
+ }>;
596
+ readonly outputs: ReadonlyArray<{
597
+ readonly address: string;
598
+ readonly value: number;
599
+ readonly own: boolean;
600
+ }>;
601
+ readonly vsize: number;
602
+ readonly fee: number;
603
+ readonly feeRate: number;
604
+ };
605
+ readonly submittedAt: number;
606
+ readonly error: string | undefined;
607
+ };
608
+ type SendParams = {
609
+ readonly account: AccountRef;
610
+ readonly network: string;
611
+ readonly to: string;
612
+ readonly amount: bigint;
613
+ /** ERC-20 contract — when set, `to`/`amount` are the transfer recipient/units and value is 0. */
614
+ readonly token?: string;
615
+ readonly fee: EvmFeeTier | SolanaFeeTier;
616
+ /** SPL mint decimals — required when `token` is a Solana mint. */
617
+ readonly decimals?: number;
618
+ readonly verify: SignParams["verify"];
619
+ };
620
+ type PrepareParams = Omit<SendParams, "verify">;
621
+ type ChainRequestMethod = "send" | "speed-up" | "cancel" | "cpfp";
622
+ /** What a request asks for; replacements and CPFP name the original transaction. */
623
+ type ChainRequestInput = ({
624
+ readonly method: "send";
625
+ } & PrepareParams) | {
626
+ readonly method: "speed-up" | "cancel";
627
+ readonly txId: string;
628
+ } | {
629
+ readonly method: "cpfp";
630
+ readonly txId: string;
631
+ readonly feeRate: number;
632
+ };
633
+ /**
634
+ * A fully built, estimated and cross-checked send that has not been signed. The unsigned content
635
+ * lives in the closures and cannot change after `prepare` returns.
636
+ */
637
+ type PreparedRequest = {
638
+ /** Id of the tracked transaction `submit` creates. */
639
+ readonly txId: string;
640
+ readonly account: AccountRef;
641
+ readonly network: string;
642
+ /** The transaction being replaced or accelerated; absent for a plain send. */
643
+ readonly target?: string;
644
+ readonly intent: DisplayIntent;
645
+ readonly checks: ReadonlyArray<RequestCheckCode>;
646
+ /** Why the build can no longer be signed (nonce taken, blockhash expired), if so. */
647
+ readonly staleReason: () => string | undefined | Promise<string | undefined>;
648
+ /** Signs, finalizes, broadcasts and hands the transaction to tracking. */
649
+ readonly submit: (verify: SendParams["verify"]) => Promise<TrackedTransaction>;
650
+ /** Frees what `prepare` reserved; safe to call more than once. */
651
+ readonly release: () => void;
652
+ };
653
+ type Options$1 = {
654
+ readonly wallet: Wallet;
655
+ readonly networks: NetworkController;
656
+ readonly openStore: () => Promise<EngineStore>;
657
+ readonly random: (n: number) => Uint8Array;
658
+ readonly setTimer: (ms: number, fn: () => unknown) => () => void;
659
+ readonly now: () => number;
660
+ readonly logger: EngineLogger;
661
+ readonly pollMs?: number;
662
+ /** Test seam — defaults to the wallet's real chains proxy. */
663
+ readonly chains?: ReturnType<typeof chains>;
664
+ };
665
+ //#endregion
666
+ //#region src/transactions/controller.d.ts
667
+ type TransactionControllerState = {
668
+ readonly txs: Record<string, TrackedTransaction>;
669
+ };
670
+ declare class TransactionController extends Controller<TransactionControllerState> {
671
+ private readonly options;
672
+ private engineStore?;
673
+ private readonly timers;
674
+ private evmRoute;
675
+ private bitcoinRoute;
676
+ private locked;
677
+ constructor(options: Options$1);
678
+ init(): Promise<void>;
679
+ destroy(): Promise<void>;
680
+ lock(): void;
681
+ private persist;
682
+ private transition;
683
+ private routeCtx;
684
+ /**
685
+ * Internal entry for the request pipeline: builds, estimates and cross-checks a send without
686
+ * signing it. Bitcoin outputs it selects stay locked under `requestId` until the returned
687
+ * `release` runs or the broadcast moves them to the transaction.
688
+ */
689
+ prepareSend(params: PrepareParams, requestId: string): Promise<PreparedRequest>;
690
+ /**
691
+ * Internal entry for replacements and CPFP: builds, cross-checks and reserves what the
692
+ * replacement needs without signing it. The original must be `submitted` or `pending`.
693
+ */
694
+ prepareReplacement(input: Exclude<ChainRequestInput, {
695
+ method: "send";
696
+ }>, requestId: string): Promise<PreparedRequest>;
697
+ private track;
698
+ }
699
+ //#endregion
700
+ //#region src/requests/risk.d.ts
701
+ /**
702
+ * Recipient risk, pure: a recipient the wallet has never paid or saved is a `warning`; one that
703
+ * looks like a known address (same first and last four characters, different address) is a `danger`
704
+ * — the shape of an address-poisoning lookalike. Both can apply to one recipient.
705
+ */
706
+ type RiskFinding = {
707
+ readonly code: "first-recipient" | "address-poisoning";
708
+ readonly level: "warning" | "danger";
709
+ };
710
+ //#endregion
711
+ //#region src/requests/sign-log.d.ts
712
+ type SignLogOutcome = "submitted" | "rejected" | "failed" | "expired" | "invalidated";
713
+ type SignLogEntry = {
714
+ readonly id: string;
715
+ readonly at: number;
716
+ readonly origin: {
717
+ readonly kind: "internal";
718
+ };
719
+ readonly method: RequestMethod;
720
+ readonly account: AccountRef | SparkAccountRef;
721
+ readonly network: string;
722
+ readonly summary: string;
723
+ readonly verification: "verified" | "unverifiable";
724
+ readonly checks: ReadonlyArray<RequestCheckCode>;
725
+ readonly risk: ReadonlyArray<RiskFinding>;
726
+ readonly outcome: SignLogOutcome;
727
+ readonly error?: string;
728
+ };
729
+ //#endregion
730
+ //#region src/requests/controller.d.ts
731
+ /** A Spark, Lightning (including LNURL-pay and lightning addresses) or cooperative-exit payment. */
732
+ type PayInput = {
733
+ readonly method: "pay";
734
+ } & PayParams;
735
+ /** A prepared zap; its invoice was fetched by `engine.zaps.prepare` and is paid as-is. */
736
+ type ZapInput = {
737
+ readonly method: "zap";
738
+ readonly account: SparkAccountRef;
739
+ readonly zap: PreparedZap;
740
+ readonly maxFeeSats: number;
741
+ };
742
+ type RequestMethod = ChainRequestMethod | "pay" | "zap";
743
+ type RequestInput = ChainRequestInput | PayInput | ZapInput;
744
+ type RequestStage = "awaiting-approval" | "signing" | "submitted" | "rejected" | "failed" | "expired" | "invalidated";
745
+ type PendingRequest = {
746
+ readonly id: string;
747
+ readonly origin: {
748
+ readonly kind: "internal";
749
+ };
750
+ readonly method: RequestMethod;
751
+ readonly account: AccountRef | SparkAccountRef;
752
+ readonly network: string;
753
+ readonly stage: RequestStage;
754
+ /** Decoded locally from the exact content that will be signed; `family` tells the shapes apart. */
755
+ readonly display: DisplayIntent | SparkDisplay;
756
+ /** `unverifiable` as soon as any check is recorded; the host must ask for explicit confirmation. */
757
+ readonly verification: "verified" | "unverifiable";
758
+ readonly checks: ReadonlyArray<RequestCheckCode>;
759
+ /**
760
+ * Recipient risk; independent of `verification`. A `danger` needs the user's explicit
761
+ * acknowledgement.
762
+ */
763
+ readonly risk: ReadonlyArray<RiskFinding>;
764
+ readonly createdAt: number;
765
+ readonly expiresAt: number;
766
+ /** The transaction being replaced or accelerated; absent for a plain send. */
767
+ readonly target?: string;
768
+ /** The tracked transaction once submitted. */
769
+ readonly txId?: string;
770
+ readonly error?: string;
771
+ };
772
+ type RequestControllerState = {
773
+ readonly requests: Record<string, PendingRequest>;
774
+ };
775
+ type RequestControllerOptions = {
776
+ readonly transactions: TransactionController;
777
+ /** The full controller: its payment methods are reachable only through this pipeline. */
778
+ readonly spark: SparkController;
779
+ readonly addressBook: AddressBookController;
780
+ readonly openStore: () => Promise<EngineStore>;
781
+ readonly fetch: typeof globalThis.fetch;
782
+ readonly random: (n: number) => Uint8Array;
783
+ readonly now: () => number;
784
+ readonly setTimer: (ms: number, fn: () => unknown) => () => void;
785
+ readonly logger: EngineLogger;
786
+ };
787
+ /** Requests expire this long after creation. */
788
+ export declare const REQUEST_TTL_MS: number;
789
+ export declare class RequestController extends Controller<RequestControllerState> {
790
+ private readonly options;
791
+ private readonly entries;
792
+ private readonly log;
793
+ /** Original transaction id → the unfinished request replacing or accelerating it. */
794
+ private readonly targets;
795
+ private locked;
796
+ /** Bumped on every unlock and lock so work that outlives a session never touches the next one. */
797
+ private session;
798
+ constructor(options: RequestControllerOptions);
799
+ init(): Promise<void>;
800
+ destroy(): Promise<void>;
801
+ /** Locking is not consent: every unfinished request becomes `invalidated` and frees its resources. */
802
+ lock(): void;
803
+ /** The signature record, newest first. */
804
+ signLog(): Promise<ReadonlyArray<SignLogEntry>>;
805
+ clearSignLog(): Promise<void>;
806
+ prepare(input: RequestInput): Promise<PendingRequest>;
807
+ private build;
808
+ /**
809
+ * Signs and submits a request. Anything but a live, unexpired `send` request with this id throws
810
+ * before any signing; a stale build (nonce taken, blockhash expired) fails without signing.
811
+ */
812
+ approve(id: string, method: ChainRequestMethod, verify: SendParams["verify"]): Promise<TrackedTransaction>;
813
+ approve(id: string, method: "pay" | "zap", verify: SendParams["verify"]): Promise<SparkResult>;
814
+ /**
815
+ * A cancelled or refused verification is `rejected`; anything after it is `failed`. Chain
816
+ * requests record which step failed on the tracked transaction; for Spark, the approval round is
817
+ * the only source of `WalletError`.
818
+ */
819
+ private failureStage;
820
+ reject(id: string): void;
821
+ private requireRequest;
822
+ private put;
823
+ private unclaim;
824
+ /** Ends a request in a terminal stage and frees what it reserved. */
825
+ private finish;
826
+ /** Appends the final stage to the signature record; a failed write is a warning, not an error. */
827
+ private record;
828
+ private appendLog;
829
+ /**
830
+ * Addresses the wallet already knows for a family: contacts, plus recipients of tracked chain
831
+ * sends (Spark payments are not tracked).
832
+ */
833
+ private knownAddresses;
834
+ private chainRisk;
835
+ /** Only a Spark transfer has a recipient to check; Lightning and exits are not assessed. */
836
+ private sparkRisk;
837
+ }
838
+ //#endregion
839
+ //#region src/meta/doc.d.ts
840
+ /**
841
+ * Wallet metadata document — the plaintext exchanged over kind-30078 events between this wallet's
842
+ * own devices. One document per wallet; entry-level last-writer-wins on `updatedAt`.
843
+ */
844
+ type MetaDocWallet = {
845
+ readonly name?: string;
846
+ readonly updatedAt: number;
847
+ };
848
+ type MetaDocGroup = {
849
+ readonly index: number;
850
+ readonly name?: string;
851
+ readonly hidden: boolean;
852
+ readonly boundPubkey?: string;
853
+ readonly updatedAt: number;
854
+ };
855
+ /** The per-wallet part of the document: this wallet's name and account groups. */
856
+ type MetaDocTree = {
857
+ readonly wallet: MetaDocWallet;
858
+ readonly groups: ReadonlyArray<MetaDocGroup>;
859
+ };
860
+ /** Every wallet's document also carries the whole address book, which is shared across wallets. */
861
+ type MetaDoc = MetaDocTree & {
862
+ readonly v: 2;
863
+ readonly contacts: ReadonlyArray<AddressBookRecord>;
864
+ };
865
+ //#endregion
265
866
  //#region src/accounts/controller.d.ts
266
867
  type AccountGroup = {
267
868
  readonly walletId: string;
268
869
  readonly index: number;
870
+ /** `discoverGroups` result — family key → used; a family error lives under `errors`. */
871
+ readonly used?: Readonly<Record<string, boolean>>;
872
+ readonly errors?: Readonly<Record<string, string>>;
269
873
  readonly name?: string;
270
874
  readonly hidden: boolean;
271
875
  /** A social identity (64 lowercase hex) bound to this group; one identity binds one group. */
@@ -287,21 +891,41 @@ type AccountTreeState = {
287
891
  } | null;
288
892
  readonly totals: Readonly<Record<string, number>>;
289
893
  };
894
+ type DiscoveryNetworks = {
895
+ readonly client: (network: string) => {
896
+ readonly getTransactionCount: (p: {
897
+ readonly address: `0x${string}`;
898
+ readonly blockTag: "latest";
899
+ }) => Promise<number>;
900
+ readonly getBalance: (p: {
901
+ readonly address: `0x${string}`;
902
+ }) => Promise<bigint>;
903
+ };
904
+ readonly solanaRpc: (network: string) => {
905
+ readonly call: (method: string, params: unknown[]) => Promise<unknown>;
906
+ };
907
+ readonly esplora: (network: string) => Esplora;
908
+ readonly enabled: (family: "evm" | "solana" | "bitcoin") => ReadonlyArray<string>;
909
+ };
290
910
  type AccountTreeControllerOptions = {
291
911
  readonly wallet: Wallet;
292
912
  readonly spark: SparkController;
293
913
  readonly sparkNetwork: SparkNetwork;
914
+ readonly networks?: DiscoveryNetworks;
915
+ readonly chains?: {
916
+ readonly account: (params: {
917
+ readonly walletId: string;
918
+ readonly groupIndex: number;
919
+ readonly template: string;
920
+ readonly network: string;
921
+ }) => Promise<{
922
+ readonly address?: string;
923
+ readonly xpub?: string;
924
+ }>;
925
+ };
294
926
  readonly logger: EngineLogger;
295
927
  readonly now: () => number;
296
928
  };
297
- /**
298
- * Declarative account tree: wallets come from the Wallet snapshot (reconciled on unlock and on
299
- * every snapshot change while unlocked), groups/names/hidden/selected/totals persist to the engine
300
- * store under `accounts/tree`. The controller drives `spark.setAccounts` with the selected group
301
- * only — an unselected group needs no live client (incoming transfers are claimed whenever it is
302
- * selected again). The active account's `balanceSats` feeds `totals`, debounced 1 s before
303
- * persist.
304
- */
305
929
  export declare class AccountTreeController extends Controller<AccountTreeState> {
306
930
  private readonly options;
307
931
  private col;
@@ -338,19 +962,25 @@ export declare class AccountTreeController extends Controller<AccountTreeState>
338
962
  groupIndex: number;
339
963
  } | undefined;
340
964
  /** The wallet's metadata document — every group, hidden included. */
341
- exportMeta(walletId: string): MetaDoc;
965
+ exportMeta(walletId: string): MetaDocTree;
342
966
  /**
343
967
  * Entry-level last-writer-wins merge: a newer remote `updatedAt` replaces the local entry, a tie
344
968
  * keeps local; remote-only groups are added. `selected`/hidden rules are re-validated — if the
345
969
  * merge hides the selected group it is re-selected, and a merge may never leave every group
346
970
  * hidden (the selected one stays visible and is re-stamped so the fix propagates).
347
971
  */
348
- mergeMeta(walletId: string, doc: MetaDoc): {
972
+ mergeMeta(walletId: string, doc: MetaDocTree): {
349
973
  changed: boolean;
350
974
  localNewer: boolean;
351
975
  };
352
976
  /** Sequential inspect from 0 upward; index 0 always included; stop after 2 consecutive unused. */
353
977
  discoverSpark(walletId: string): Promise<number[]>;
978
+ /**
979
+ * Per-group chain-family discovery — same stop rule as `discoverSpark`: group 0 always, stop
980
+ * after two consecutive fully-unused groups. A family error is reported on the group and does NOT
981
+ * count as unused (the group stays in `found` — it can't be proven empty).
982
+ */
983
+ discoverGroups(walletId: string): Promise<number[]>;
354
984
  /** Refresh `totals` for every other visible group; per-group failures are logged and skipped. */
355
985
  refreshTotals(): Promise<void>;
356
986
  private onSparkState;
@@ -370,6 +1000,62 @@ export declare class AccountTreeController extends Controller<AccountTreeState>
370
1000
  private flushTotals;
371
1001
  }
372
1002
  //#endregion
1003
+ //#region src/assets/controller.d.ts
1004
+ type TokenBalance = {
1005
+ readonly address: string;
1006
+ readonly symbol: string;
1007
+ readonly decimals: number;
1008
+ readonly balance: string;
1009
+ /** False for user-added tokens until they appear in the built-in table. */
1010
+ readonly verified: boolean;
1011
+ };
1012
+ type AccountBalances = {
1013
+ readonly native: string;
1014
+ readonly tokens: ReadonlyArray<TokenBalance>;
1015
+ /** Bitcoin only — confirmed + own unconfirmed change; frozen 546/330-sat UTXOs shown apart. */
1016
+ readonly unconfirmed?: string;
1017
+ readonly frozen?: string;
1018
+ };
1019
+ type AssetsControllerState = {
1020
+ readonly balances: Record<string, AccountBalances>;
1021
+ };
1022
+ type Options = {
1023
+ readonly networks: NetworkController;
1024
+ readonly openStore: () => Promise<EngineStore>;
1025
+ readonly setTimer: (ms: number, fn: () => unknown) => () => void;
1026
+ readonly logger: EngineLogger;
1027
+ };
1028
+ declare class AssetsController extends Controller<AssetsControllerState> {
1029
+ private readonly options;
1030
+ private engineStore;
1031
+ private readonly bitcoinUtxos;
1032
+ private visible;
1033
+ private cancelPoll;
1034
+ private readonly customTokens;
1035
+ constructor(options: Options);
1036
+ init(): Promise<void>;
1037
+ lock(): void;
1038
+ destroy(): Promise<void>;
1039
+ setVisible(visible: boolean): void;
1040
+ private armPoll;
1041
+ private refreshAll;
1042
+ refresh(address: string, network: string): Promise<void>;
1043
+ /** SOL via getBalance; SPL via getTokenAccountsByOwner (jsonParsed) for known mints. */
1044
+ private refreshSolana;
1045
+ private readTokens;
1046
+ private balanceOfBatch;
1047
+ private balanceOf;
1048
+ private callString;
1049
+ private callNumber;
1050
+ /** Reads symbol/decimals on-chain, marks unverified, persists; throws when the calls fail. */
1051
+ addToken(network: string, address: string): Promise<void>;
1052
+ private persistToken;
1053
+ private rpc;
1054
+ private rpcHex;
1055
+ /** BTC balance = confirmed spendable + own unconfirmed change; frozen 546/330 shown separately. */
1056
+ refreshBitcoin(xpub: string, network: string): Promise<void>;
1057
+ }
1058
+ //#endregion
373
1059
  //#region src/backup/errors.d.ts
374
1060
  /** BackupController error categories — never carry file contents, digests or secrets. */
375
1061
  type BackupErrorCategory = "cloud" | "conflict" | "unavailable";
@@ -493,9 +1179,21 @@ type MetaSyncWalletStatus = {
493
1179
  type MetaSyncState = {
494
1180
  readonly wallets: Readonly<Record<string, MetaSyncWalletStatus>>;
495
1181
  };
1182
+ /** What the sync needs from the address book: its records, a merge, and a change subscription. */
1183
+ type AddressBookSync = {
1184
+ readonly syncEntries: () => ReadonlyArray<AddressBookRecord>;
1185
+ readonly merge: (remote: ReadonlyArray<AddressBookRecord>) => Promise<{
1186
+ readonly changed: boolean;
1187
+ readonly localNewer: boolean;
1188
+ }>;
1189
+ readonly store: {
1190
+ readonly subscribe: (listener: () => void) => () => void;
1191
+ };
1192
+ };
496
1193
  type MetaSyncControllerOptions = {
497
1194
  readonly wallet: Wallet;
498
1195
  readonly accounts: AccountTreeController;
1196
+ readonly addressBook: AddressBookSync;
499
1197
  /** `nostr(wallet)` — the signer is requested per wallet for its group-0 derived key. */
500
1198
  readonly nostr: {
501
1199
  readonly signer: (ref: NostrKeyRef) => WalletSigner;
@@ -519,6 +1217,7 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
519
1217
  private readonly timers;
520
1218
  private readonly inflight;
521
1219
  private accountsUnsubscribe;
1220
+ private addressBookUnsubscribe;
522
1221
  constructor(options: MetaSyncControllerOptions);
523
1222
  /** Unlocked: pull every wallet whose group-0 identity exists, then watch the tree. */
524
1223
  init(): Promise<void>;
@@ -534,6 +1233,8 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
534
1233
  private signerFor;
535
1234
  private setStatus;
536
1235
  private pullOne;
1236
+ /** The wallet's tree plus the shared address book — every wallet's document carries both. */
1237
+ private exportDoc;
537
1238
  private filterFor;
538
1239
  private acceptableEvent;
539
1240
  /** Snapshot the wallet's exported doc — the debounce publishes only on a real change. */
@@ -542,140 +1243,6 @@ export declare class MetaSyncController extends Controller<MetaSyncState> {
542
1243
  private publishNow;
543
1244
  }
544
1245
  //#endregion
545
- //#region src/payments/parse.d.ts
546
- type PaymentOption = {
547
- readonly kind: "spark";
548
- readonly address: string;
549
- } | {
550
- readonly kind: "spark-invoice";
551
- readonly invoice: string;
552
- readonly amountSats?: number;
553
- readonly memo?: string;
554
- readonly expiresAt?: number;
555
- } | {
556
- readonly kind: "lightning";
557
- readonly invoice: string;
558
- readonly amountSats?: number;
559
- readonly paymentHash: string;
560
- readonly description?: string;
561
- readonly expiresAt: number;
562
- } | {
563
- readonly kind: "lnurl-pay";
564
- readonly request: LnurlPayRequest;
565
- readonly address?: string;
566
- } | {
567
- readonly kind: "lnurl-withdraw";
568
- readonly request: LnurlWithdrawRequest;
569
- } | {
570
- readonly kind: "bitcoin";
571
- readonly address: string;
572
- };
573
- type PaymentRequest = {
574
- readonly options: ReadonlyArray<PaymentOption>;
575
- readonly amountSats?: number;
576
- readonly label?: string;
577
- readonly message?: string;
578
- };
579
- type PaymentParse = {
580
- readonly kind: "request";
581
- readonly request: PaymentRequest;
582
- } | {
583
- readonly kind: "lnurl";
584
- readonly url: string;
585
- readonly address?: string;
586
- } | {
587
- readonly kind: "unsupported";
588
- readonly format: "bolt12" | "silent-payment" | "lnurl-auth" | "spark-token-invoice" | "nostr-wallet-connect";
589
- } | {
590
- readonly kind: "invalid";
591
- readonly reason: "network" | "expired" | "amount-mismatch" | "malformed";
592
- } | {
593
- readonly kind: "unrecognized";
594
- };
595
- type ParseOptions = {
596
- readonly network: SparkNetwork;
597
- readonly now: number;
598
- };
599
- /** `input` → PaymentParse. Never throws: every failure is a structured result. */
600
- export declare function parsePayment(input: string, options: ParseOptions): PaymentParse;
601
- //#endregion
602
- //#region src/payments/pay.d.ts
603
- type PayParams = {
604
- readonly account: SparkAccountRef;
605
- readonly option: PaymentOption;
606
- /** Caller-supplied amount — required by open invoices, the `spark` option, and LNURL flows. */
607
- readonly amountSats?: number;
608
- readonly comment?: string;
609
- readonly maxFeeSats?: number;
610
- readonly speed?: "FAST" | "MEDIUM" | "SLOW";
611
- readonly verify: UnlockFactor;
612
- };
613
- type PayResult = {
614
- readonly kind: "spark";
615
- readonly transfer: SparkTransfer;
616
- } | {
617
- readonly kind: "lightning";
618
- readonly payment: LightningPayment;
619
- } | {
620
- readonly kind: "withdraw";
621
- readonly exit: CooperativeExitResult;
622
- } | {
623
- readonly kind: "lnurl-withdraw";
624
- readonly invoice: LightningInvoice;
625
- };
626
- //#endregion
627
- //#region src/payments/zap.d.ts
628
- /** A profile zap names the recipient pubkey; an event zap carries the event it zaps. */
629
- type ZapRecipient = {
630
- readonly pubkey: string;
631
- readonly lightning: string;
632
- } | {
633
- readonly event: Event;
634
- readonly lightning: string;
635
- };
636
- type PrepareZapParams = {
637
- /** Any `NostrSigner` — wallet key, external key, NIP-07/46 — signs the 9734. */
638
- readonly signer: NostrSigner;
639
- readonly recipient: ZapRecipient;
640
- readonly amountSats: number;
641
- readonly comment?: string | undefined;
642
- readonly relays: ReadonlyArray<string>;
643
- readonly network: SparkNetwork;
644
- };
645
- type PrepareZapContext = {
646
- readonly fetch: typeof globalThis.fetch;
647
- readonly now: () => number;
648
- };
649
- /** Everything a payer needs: the signed 9734, the invoice, and the note fields. */
650
- type PreparedZap = {
651
- readonly zapRequest: Event;
652
- readonly invoice: string;
653
- /** Hex payment hash decoded from the invoice. */
654
- readonly paymentHash: string;
655
- /** Millisecond expiry decoded from the invoice. */
656
- readonly expiresAt: number;
657
- readonly amountSats: number;
658
- /** The LNURL service's 9735 signing pubkey. */
659
- readonly receiptPubkey: string;
660
- readonly recipientPubkey: string;
661
- readonly eventId?: string;
662
- readonly comment?: string;
663
- /** The lud16 or LNURL as given. */
664
- readonly lightning: string;
665
- };
666
- type PayZapOptions = {
667
- readonly maxFeeSats: number;
668
- readonly verify: UnlockFactor;
669
- readonly now: () => number;
670
- };
671
- /** Everything up to payment: resolve LNURL, sign the 9734, request the invoice. */
672
- export declare function prepareZap(params: PrepareZapParams, context: PrepareZapContext): Promise<PreparedZap>;
673
- /**
674
- * Pays a prepared zap through the controller's approve-first path. A nearly-expired invoice is
675
- * rejected before approval — the user may have sat on the confirm screen since `prepareZap`.
676
- */
677
- export declare function payZap(spark: SparkController, account: SparkAccountRef, prepared: PreparedZap, options: PayZapOptions): Promise<LightningPayment>;
678
- //#endregion
679
1246
  //#region src/engine.d.ts
680
1247
  type EngineOptions = {
681
1248
  readonly wallet: Wallet;
@@ -688,24 +1255,48 @@ type EngineOptions = {
688
1255
  readonly openStore: () => Promise<EngineStore>;
689
1256
  /** Cloud file transport for the backup controller; absent → `unavailable`. */
690
1257
  readonly cloud?: CloudStore;
1258
+ /**
1259
+ * Host endpoints per network (CAIP-2), ordered by preference, for all three chain families: EVM
1260
+ * and Solana JSON-RPC URLs, and for Bitcoin the Esplora base URL.
1261
+ */
1262
+ readonly rpc?: Readonly<Record<string, ReadonlyArray<string>>>;
1263
+ /**
1264
+ * The wallet gateway: tried first for the networks it serves (read at each unlock) unless a
1265
+ * network has custom endpoints. The install id is sent only to the gateway's origin.
1266
+ */
1267
+ readonly gateway?: {
1268
+ readonly url: string;
1269
+ readonly installId: string;
1270
+ };
1271
+ /** Injected timer for transaction polling; defaults to setTimeout. */
1272
+ readonly setTimer?: (ms: number, fn: () => void) => () => void;
691
1273
  /** Kind-30078 wallet-metadata sync; absent → every wallet reports `unavailable`. */
692
1274
  readonly metaSync?: MetaSyncConfig;
693
1275
  /** Test seam — defaults to the wallet's real spark proxy. */
694
1276
  readonly sparkApis?: SparkControllerOptions["spark"];
695
1277
  };
696
1278
  type WalletEngine = {
697
- readonly spark: SparkController;
1279
+ readonly networks: NetworkController;
1280
+ readonly assets: AssetsController;
1281
+ readonly transactions: TransactionController;
1282
+ readonly requests: RequestController;
1283
+ readonly addressBook: AddressBookController;
1284
+ /** Read and receive surface; every payment goes through `requests`. */
1285
+ readonly spark: Omit<SparkController, "send" | "payInvoice" | "paySparkInvoice" | "withdraw">;
698
1286
  readonly accounts: AccountTreeController;
699
1287
  readonly metaSync: MetaSyncController;
700
1288
  readonly backup: BackupController;
701
1289
  readonly zaps: {
702
1290
  readonly prepare: (params: PrepareZapParams) => Promise<PreparedZap>;
703
- readonly pay: (account: SparkAccountRef, prepared: PreparedZap, options: Omit<PayZapOptions, "now">) => Promise<LightningPayment>;
704
1291
  };
705
1292
  readonly payments: {
706
1293
  readonly parse: (input: string, network: SparkNetwork) => PaymentParse;
707
1294
  readonly resolve: (input: string, network: SparkNetwork) => Promise<PaymentParse>;
708
- readonly pay: (params: PayParams) => Promise<unknown>;
1295
+ /** Receives funds from an LNURL-withdraw service; needs no verification factor. */
1296
+ readonly withdrawLnurl: (params: WithdrawLnurlParams) => Promise<{
1297
+ readonly kind: "lnurl-withdraw";
1298
+ readonly invoice: LightningInvoice;
1299
+ }>;
709
1300
  };
710
1301
  readonly unsubscribe: () => void;
711
1302
  };
@@ -754,5 +1345,5 @@ export declare function resolvePayment(input: string, options: ResolveOptions):
754
1345
  export declare function encodeExitChain(chain: SparkExitChain): Uint8Array;
755
1346
  export declare function decodeExitChain(bytes: Uint8Array): SparkExitChain;
756
1347
  //#endregion
757
- export type { AccountGroup, AccountTreeState, BackupControllerState, BackupErrorCategory, CloudStore, ControllerOptions, EngineCollection, EngineErrorCode, EngineLogger, EngineOptions, EngineStore, EventBus, MetaDoc, MetaDocGroup, MetaDocWallet, MetaSyncConfig, MetaSyncRelayPort, MetaSyncState, MetaSyncWalletStatus, PayResult, PayZapOptions, PaymentNote, PaymentOption, PaymentParse, PaymentRequest, PrepareZapContext, PrepareZapParams, PreparedZap, SparkAccountState, SparkActivity, SparkClientFactory, SparkControllerOptions, SparkControllerState, SparkErrorCategory, WalletEngine, ZapRecipient };
1348
+ export type { AccountGroup, AccountTreeState, AddressBookEntry, AddressBookErrorCategory, AddressBookState, AddressFamily, BackupControllerState, BackupErrorCategory, CloudStore, ControllerOptions, EngineCollection, EngineErrorCode, EngineLogger, EngineOptions, EngineStore, EventBus, MetaDoc, MetaDocGroup, MetaDocTree, MetaDocWallet, MetaSyncConfig, MetaSyncRelayPort, MetaSyncState, MetaSyncWalletStatus, PayInput, PayParams, PaymentNote, PaymentOption, PaymentParse, PaymentRequest, PendingRequest, PrepareZapContext, PrepareZapParams, PreparedSparkAction, PreparedZap, RequestCheckCode, RequestControllerState, RequestInput, RequestMethod, RequestStage, RiskFinding, SignLogEntry, SignLogOutcome, SparkAccountState, SparkActivity, SparkClientFactory, SparkControllerOptions, SparkControllerState, SparkDisplay, SparkErrorCategory, SparkResult, WalletEngine, WithdrawLnurlParams, ZapRecipient };
758
1349
  //# sourceMappingURL=index.d.mts.map