7
7
* @see https://github.com/nostr-protocol/nips/blob/master/19.md
8
8
*/
9
9
10
- import { bech32 } from '@scure/base' ;
11
- import { bytesToHex , hexToBytes } from '@noble/hashes/utils' ;
12
- import { sha256 } from '@noble/hashes/sha256' ;
13
10
import { logger } from '../utils/logger.js' ;
14
- import type { Bech32Result } from '../types/index.js' ;
15
-
16
- /**
17
- * Valid bech32 prefix types for Nostr entities
18
- * @typedef {('npub1' | 'nsec1' | 'note1') } Bech32Prefix
19
- */
20
- type Bech32Prefix = 'npub1' | 'nsec1' | 'note1' ;
21
-
22
- /**
23
- * Ensures the input string has a valid bech32 format by adding '1' if missing
24
- * @param {string } str - Input string to format
25
- * @returns {string } Properly formatted bech32 string
26
- * @example
27
- * ensureBech32Format('npub') // returns 'npub1'
28
- * ensureBech32Format('npub1abc') // returns 'npub1abc'
29
- */
30
- function ensureBech32Format ( str : string ) : `${string } 1${string } ` {
31
- return str . includes ( '1' ) ? str as `${string } 1${string } ` : `${ str } 1` ;
32
- }
11
+ import { npubEncode , nsecEncode , noteEncode , decode as nip19Decode } from 'nostr-crypto-utils' ;
12
+ import type { Nip19Data } from 'nostr-crypto-utils' ;
33
13
34
14
/**
35
15
* Encodes a public key into npub format
@@ -38,17 +18,14 @@ function ensureBech32Format(str: string): `${string}1${string}` {
38
18
* @throws {Error } If encoding fails
39
19
* @example
40
20
* const npub = hexToNpub('3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d');
41
- * // returns 'npub1...'
21
+ * returns 'npub1...'
42
22
*/
43
23
export function hexToNpub ( hex : string ) : string {
44
24
try {
45
- const bytes = hexToBytes ( hex ) ;
46
- const words = bech32 . toWords ( bytes ) ;
47
- const encoded = bech32 . encode ( 'npub1' as Bech32Prefix , words ) ;
48
- return encoded ;
25
+ return npubEncode ( hex ) ;
49
26
} catch ( error ) {
50
- logger . error ( 'Failed to encode npub:' , error ) ;
51
- throw new Error ( 'Failed to encode npub' ) ;
27
+ logger . error ( { error , hex } , 'Failed to encode public key to npub' ) ;
28
+ throw error ;
52
29
}
53
30
}
54
31
@@ -60,17 +37,14 @@ export function hexToNpub(hex: string): string {
60
37
* @security This function handles sensitive private key data
61
38
* @example
62
39
* const nsec = hexToNsec('3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d');
63
- * // returns 'nsec1...'
40
+ * returns 'nsec1...'
64
41
*/
65
42
export function hexToNsec ( hex : string ) : string {
66
43
try {
67
- const bytes = hexToBytes ( hex ) ;
68
- const words = bech32 . toWords ( bytes ) ;
69
- const encoded = bech32 . encode ( 'nsec1' as Bech32Prefix , words ) ;
70
- return encoded ;
44
+ return nsecEncode ( hex ) ;
71
45
} catch ( error ) {
72
- logger . error ( 'Failed to encode nsec:' , error ) ;
73
- throw new Error ( 'Failed to encode nsec' ) ;
46
+ logger . error ( { error , hex } , 'Failed to encode private key to nsec' ) ;
47
+ throw error ;
74
48
}
75
49
}
76
50
@@ -81,38 +55,32 @@ export function hexToNsec(hex: string): string {
81
55
* @throws {Error } If encoding fails
82
56
* @example
83
57
* const note = hexToNote('3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d');
84
- * // returns 'note1...'
58
+ * returns 'note1...'
85
59
*/
86
60
export function hexToNote ( hex : string ) : string {
87
61
try {
88
- const bytes = hexToBytes ( hex ) ;
89
- const words = bech32 . toWords ( bytes ) ;
90
- const encoded = bech32 . encode ( 'note1' as Bech32Prefix , words ) ;
91
- return encoded ;
62
+ return noteEncode ( hex ) ;
92
63
} catch ( error ) {
93
- logger . error ( 'Failed to encode note:' , error ) ;
94
- throw new Error ( 'Failed to encode note' ) ;
64
+ logger . error ( { error , hex } , 'Failed to encode event ID to note' ) ;
65
+ throw error ;
95
66
}
96
67
}
97
68
98
69
/**
99
70
* Decodes a bech32-encoded Nostr entity
100
71
* @param {string } str - The bech32-encoded string (npub1, nsec1, or note1)
101
- * @returns {Bech32Result } Object containing the decoded type and data
72
+ * @returns {Nip19Data } Object containing the decoded type and data
102
73
* @throws {Error } If decoding fails
103
74
* @example
104
75
* const result = decode('npub1...');
105
- * // returns { type: 'npub', data: Uint8Array }
76
+ * returns { type: 'npub', data: '...' }
106
77
*/
107
- export function decode ( str : string ) : Bech32Result {
78
+ export function decode ( str : string ) : Nip19Data {
108
79
try {
109
- const formattedStr = ensureBech32Format ( str ) ;
110
- const { prefix, words } = bech32 . decode ( formattedStr ) ;
111
- const data = new Uint8Array ( bech32 . fromWords ( words ) ) ;
112
- return { type : prefix . replace ( / 1 $ / , '' ) , data } ;
80
+ return nip19Decode ( str ) ;
113
81
} catch ( error ) {
114
- logger . error ( 'Failed to decode bech32:' , error ) ;
115
- throw new Error ( 'Failed to decode bech32' ) ;
82
+ logger . error ( { error , str } , 'Failed to decode bech32-encoded string' ) ;
83
+ throw error ;
116
84
}
117
85
}
118
86
@@ -124,18 +92,18 @@ export function decode(str: string): Bech32Result {
124
92
* @security This function handles sensitive private key data
125
93
* @example
126
94
* const hex = nsecToHex('nsec1...');
127
- * // returns '3bf0c63f...'
95
+ * returns '3bf0c63f...'
128
96
*/
129
97
export function nsecToHex ( nsec : string ) : string {
130
98
try {
131
- const { type , data } = decode ( nsec ) ;
132
- if ( type !== 'nsec' ) {
133
- throw new Error ( ' Invalid nsec format' ) ;
99
+ const decoded = decode ( nsec ) ;
100
+ if ( decoded . type !== 'nsec' ) {
101
+ throw new Error ( ` Invalid nsec format: ${ nsec } ` ) ;
134
102
}
135
- return bytesToHex ( data ) ;
103
+ return decoded . data ;
136
104
} catch ( error ) {
137
- logger . error ( 'Failed to convert nsec to hex:' , error ) ;
138
- throw new Error ( 'Failed to convert nsec to hex' ) ;
105
+ logger . error ( { error , nsec } , 'Failed to convert nsec to hex' ) ;
106
+ throw error ;
139
107
}
140
108
}
141
109
@@ -146,17 +114,17 @@ export function nsecToHex(nsec: string): string {
146
114
* @throws {Error } If conversion fails or input is invalid
147
115
* @example
148
116
* const hex = npubToHex('npub1...');
149
- * // returns '3bf0c63f...'
117
+ * returns '3bf0c63f...'
150
118
*/
151
119
export function npubToHex ( npub : string ) : string {
152
120
try {
153
- const { type , data } = decode ( npub ) ;
154
- if ( type !== 'npub' ) {
155
- throw new Error ( ' Invalid npub format' ) ;
121
+ const decoded = decode ( npub ) ;
122
+ if ( decoded . type !== 'npub' ) {
123
+ throw new Error ( ` Invalid npub format: ${ npub } ` ) ;
156
124
}
157
- return bytesToHex ( data ) ;
125
+ return decoded . data ;
158
126
} catch ( error ) {
159
- logger . error ( 'Failed to convert npub to hex:' , error ) ;
160
- throw new Error ( 'Failed to convert npub to hex' ) ;
127
+ logger . error ( { error , npub } , 'Failed to convert npub to hex' ) ;
128
+ throw error ;
161
129
}
162
130
}
0 commit comments