@@ -129,6 +129,32 @@ export interface NWCOptions {
129
129
secret ?: string ;
130
130
}
131
131
132
+ export class Nip47Error extends Error {
133
+ /**
134
+ * @deprecated please use message. Deprecated since v3.3.2. Will be removed in v4.0.0.
135
+ */
136
+ error : string ;
137
+ code : string ;
138
+ constructor ( message : string , code : string ) {
139
+ super ( message ) ;
140
+ this . error = message ;
141
+ this . code = code ;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * A NIP-47 response was received, but with an error code (see https://github.com/nostr-protocol/nips/blob/master/47.md#error-codes)
147
+ */
148
+ export class Nip47WalletError extends Nip47Error { }
149
+
150
+ export class Nip47TimeoutError extends Nip47Error { }
151
+ export class Nip47PublishTimeoutError extends Nip47TimeoutError { }
152
+ export class Nip47ReplyTimeoutError extends Nip47TimeoutError { }
153
+ export class Nip47PublishError extends Nip47Error { }
154
+ export class Nip47ResponseDecodingError extends Nip47Error { }
155
+ export class Nip47ResponseValidationError extends Nip47Error { }
156
+ export class Nip47UnexpectedResponseError extends Nip47Error { }
157
+
132
158
export const NWCs : Record < string , NWCOptions > = {
133
159
alby : {
134
160
authorizationUrl : "https://nwc.getalby.com/apps/new" ,
@@ -331,15 +357,15 @@ export class NWCClient {
331
357
`height=${ height } ,width=${ width } ,top=${ top } ,left=${ left } ` ,
332
358
) ;
333
359
if ( ! popup ) {
334
- reject ( ) ;
360
+ reject ( new Error ( "failed to execute window.open" ) ) ;
335
361
return ;
336
- } // only for TS?
362
+ }
337
363
338
364
const checkForPopup = ( ) => {
339
365
if ( popup && popup . closed ) {
340
- reject ( ) ;
341
366
clearInterval ( popupChecker ) ;
342
367
window . removeEventListener ( "message" , onMessage ) ;
368
+ reject ( new Error ( "Popup closed" ) ) ;
343
369
}
344
370
} ;
345
371
@@ -466,7 +492,7 @@ export class NWCClient {
466
492
errors : [ ] ,
467
493
} ;
468
494
} catch ( error ) {
469
- console . error ( "Failed to request multi_pay_keysend " , error ) ;
495
+ console . error ( "Failed to request multi_pay_invoice " , error ) ;
470
496
throw error ;
471
497
}
472
498
}
@@ -590,10 +616,12 @@ export class NWCClient {
590
616
function replyTimeout ( ) {
591
617
sub . unsub ( ) ;
592
618
//console.error(`Reply timeout: event ${event.id} `);
593
- reject ( {
594
- error : `reply timeout: event ${ event . id } ` ,
595
- code : "INTERNAL" ,
596
- } ) ;
619
+ reject (
620
+ new Nip47ReplyTimeoutError (
621
+ `reply timeout: event ${ event . id } ` ,
622
+ "INTERNAL" ,
623
+ ) ,
624
+ ) ;
597
625
}
598
626
599
627
const replyTimeoutCheck = setTimeout ( replyTimeout , 60000 ) ;
@@ -611,32 +639,64 @@ export class NWCClient {
611
639
try {
612
640
response = JSON . parse ( decryptedContent ) ;
613
641
} catch ( e ) {
614
- reject ( { error : "invalid response" , code : "INTERNAL" } ) ;
642
+ clearTimeout ( replyTimeoutCheck ) ;
643
+ sub . unsub ( ) ;
644
+ reject (
645
+ new Nip47ResponseDecodingError (
646
+ "failed to deserialize response" ,
647
+ "INTERNAL" ,
648
+ ) ,
649
+ ) ;
615
650
return ;
616
651
}
617
- if ( event . kind == 23195 && response . result ) {
618
- // console.info("NIP-47 result", response.result);
619
- if ( resultValidator ( response . result ) ) {
620
- resolve ( response . result ) ;
652
+ if ( event . kind == 23195 ) {
653
+ if ( response . result ) {
654
+ // console.info("NIP-47 result", response.result);
655
+ if ( resultValidator ( response . result ) ) {
656
+ resolve ( response . result ) ;
657
+ } else {
658
+ clearTimeout ( replyTimeoutCheck ) ;
659
+ sub . unsub ( ) ;
660
+ reject (
661
+ new Nip47ResponseValidationError (
662
+ "response from NWC failed validation: " +
663
+ JSON . stringify ( response . result ) ,
664
+ "INTERNAL" ,
665
+ ) ,
666
+ ) ;
667
+ }
621
668
} else {
622
- reject ( {
623
- error :
624
- "Response from NWC failed validation: " +
625
- JSON . stringify ( response . result ) ,
626
- code : "INTERNAL" ,
627
- } ) ;
669
+ clearTimeout ( replyTimeoutCheck ) ;
670
+ sub . unsub ( ) ;
671
+ // console.error("Wallet error", response.error);
672
+ reject (
673
+ new Nip47WalletError (
674
+ response . error ?. message || "unknown Error" ,
675
+ response . error ?. code || "INTERNAL" ,
676
+ ) ,
677
+ ) ;
628
678
}
629
679
} else {
630
- reject ( {
631
- error : response . error ?. message ,
632
- code : response . error ?. code ,
633
- } ) ;
680
+ clearTimeout ( replyTimeoutCheck ) ;
681
+ sub . unsub ( ) ;
682
+ reject (
683
+ new Nip47UnexpectedResponseError (
684
+ response . error ?. message || "unknown Error" ,
685
+ response . error ?. code || "INTERNAL" ,
686
+ ) ,
687
+ ) ;
634
688
}
635
689
} ) ;
636
690
637
691
function publishTimeout ( ) {
692
+ sub . unsub ( ) ;
638
693
//console.error(`Publish timeout: event ${event.id}`);
639
- reject ( { error : `Publish timeout: event ${ event . id } ` } ) ;
694
+ reject (
695
+ new Nip47PublishTimeoutError (
696
+ `publish timeout: ${ event . id } ` ,
697
+ "INTERNAL" ,
698
+ ) ,
699
+ ) ;
640
700
}
641
701
const publishTimeoutCheck = setTimeout ( publishTimeout , 5000 ) ;
642
702
@@ -647,7 +707,9 @@ export class NWCClient {
647
707
} catch ( error ) {
648
708
//console.error(`Failed to publish to ${this.relay.url}`, error);
649
709
clearTimeout ( publishTimeoutCheck ) ;
650
- reject ( { error : `Failed to publish request: ${ error } ` } ) ;
710
+ reject (
711
+ new Nip47PublishError ( `failed to publish: ${ error } ` , "INTERNAL" ) ,
712
+ ) ;
651
713
}
652
714
} ) ( ) ;
653
715
} ) ;
@@ -696,10 +758,12 @@ export class NWCClient {
696
758
function replyTimeout ( ) {
697
759
sub . unsub ( ) ;
698
760
//console.error(`Reply timeout: event ${event.id} `);
699
- reject ( {
700
- error : `reply timeout: event ${ event . id } ` ,
701
- code : "INTERNAL" ,
702
- } ) ;
761
+ reject (
762
+ new Nip47ReplyTimeoutError (
763
+ `reply timeout: event ${ event . id } ` ,
764
+ "INTERNAL" ,
765
+ ) ,
766
+ ) ;
703
767
}
704
768
705
769
const replyTimeoutCheck = setTimeout ( replyTimeout , 60000 ) ;
@@ -716,24 +780,42 @@ export class NWCClient {
716
780
try {
717
781
response = JSON . parse ( decryptedContent ) ;
718
782
} catch ( e ) {
719
- console . error ( e ) ;
783
+ // console.error(e);
720
784
clearTimeout ( replyTimeoutCheck ) ;
721
785
sub . unsub ( ) ;
722
- reject ( { error : "invalid response" , code : "INTERNAL" } ) ;
723
- return ;
786
+ reject (
787
+ new Nip47ResponseDecodingError (
788
+ "failed to deserialize response" ,
789
+ "INTERNAL" ,
790
+ ) ,
791
+ ) ;
724
792
}
725
- if ( event . kind == 23195 && response . result ) {
726
- // console.info("NIP-47 result", response.result);
727
- try {
793
+ if ( event . kind == 23195 ) {
794
+ if ( response . result ) {
795
+ // console.info("NIP-47 result", response.result);
728
796
if ( ! resultValidator ( response . result ) ) {
729
- throw new Error (
730
- "Response from NWC failed validation: " +
731
- JSON . stringify ( response . result ) ,
797
+ clearTimeout ( replyTimeoutCheck ) ;
798
+ sub . unsub ( ) ;
799
+ reject (
800
+ new Nip47ResponseValidationError (
801
+ "Response from NWC failed validation: " +
802
+ JSON . stringify ( response . result ) ,
803
+ "INTERNAL" ,
804
+ ) ,
732
805
) ;
806
+ return ;
733
807
}
734
808
const dTag = event . tags . find ( ( tag ) => tag [ 0 ] === "d" ) ?. [ 1 ] ;
735
809
if ( dTag === undefined ) {
736
- throw new Error ( "No d tag found in response event" ) ;
810
+ clearTimeout ( replyTimeoutCheck ) ;
811
+ sub . unsub ( ) ;
812
+ reject (
813
+ new Nip47ResponseValidationError (
814
+ "No d tag found in response event" ,
815
+ "INTERNAL" ,
816
+ ) ,
817
+ ) ;
818
+ return ;
737
819
}
738
820
results . push ( {
739
821
...response . result ,
@@ -745,28 +827,38 @@ export class NWCClient {
745
827
//console.log("Received results", results);
746
828
resolve ( results ) ;
747
829
}
748
- } catch ( error ) {
749
- console . error ( error ) ;
830
+ } else {
750
831
clearTimeout ( replyTimeoutCheck ) ;
751
832
sub . unsub ( ) ;
752
- reject ( {
753
- error : ( error as Error ) . message ,
754
- code : "INTERNAL" ,
755
- } ) ;
833
+ // console.error("Wallet error", response.error);
834
+ reject (
835
+ new Nip47WalletError (
836
+ response . error ?. message ,
837
+ response . error ?. code ,
838
+ ) ,
839
+ ) ;
756
840
}
757
841
} else {
758
842
clearTimeout ( replyTimeoutCheck ) ;
759
843
sub . unsub ( ) ;
760
- reject ( {
761
- error : response . error ?. message ,
762
- code : response . error ?. code ,
763
- } ) ;
844
+ reject (
845
+ new Nip47UnexpectedResponseError (
846
+ response . error ?. message ,
847
+ response . error ?. code ,
848
+ ) ,
849
+ ) ;
764
850
}
765
851
} ) ;
766
852
767
853
function publishTimeout ( ) {
854
+ sub . unsub ( ) ;
768
855
//console.error(`Publish timeout: event ${event.id}`);
769
- reject ( { error : `Publish timeout: event ${ event . id } ` } ) ;
856
+ reject (
857
+ new Nip47PublishTimeoutError (
858
+ `Publish timeout: ${ event . id } ` ,
859
+ "INTERNAL" ,
860
+ ) ,
861
+ ) ;
770
862
}
771
863
const publishTimeoutCheck = setTimeout ( publishTimeout , 5000 ) ;
772
864
@@ -777,7 +869,9 @@ export class NWCClient {
777
869
} catch ( error ) {
778
870
//console.error(`Failed to publish to ${this.relay.url}`, error);
779
871
clearTimeout ( publishTimeoutCheck ) ;
780
- reject ( { error : `Failed to publish request: ${ error } ` } ) ;
872
+ reject (
873
+ new Nip47PublishError ( `Failed to publish: ${ error } ` , "INTERNAL" ) ,
874
+ ) ;
781
875
}
782
876
} ) ( ) ;
783
877
} ) ;
0 commit comments