nostr-websocket-utils 0.3.17 → 0.3.18
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/README.md +2 -2
- package/dist/browser/nostr-websocket-utils.min.js +2 -2
- package/dist/browser/nostr-websocket-utils.min.js.map +7 -1
- package/dist/browser/report.html +1 -1
- package/dist/cjs/nips/index.d.ts +2 -0
- package/dist/cjs/nips/index.d.ts.map +1 -1
- package/dist/cjs/nips/index.js +5 -1
- package/dist/cjs/nips/index.js.map +1 -1
- package/dist/cjs/nips/nip-26.d.ts.map +1 -1
- package/dist/cjs/nips/nip-26.js +3 -7
- package/dist/cjs/nips/nip-26.js.map +1 -1
- package/dist/cjs/nips/nip-44.d.ts +69 -0
- package/dist/cjs/nips/nip-44.d.ts.map +1 -0
- package/dist/cjs/nips/nip-44.js +143 -0
- package/dist/cjs/nips/nip-44.js.map +1 -0
- package/dist/cjs/nips/nip-46.d.ts +112 -0
- package/dist/cjs/nips/nip-46.d.ts.map +1 -0
- package/dist/cjs/nips/nip-46.js +123 -0
- package/dist/cjs/nips/nip-46.js.map +1 -0
- package/dist/nips/index.d.ts +2 -0
- package/dist/nips/index.d.ts.map +1 -1
- package/dist/nips/index.js +5 -1
- package/dist/nips/index.js.map +1 -1
- package/dist/nips/nip-26.d.ts.map +1 -1
- package/dist/nips/nip-26.js +4 -8
- package/dist/nips/nip-26.js.map +1 -1
- package/dist/nips/nip-44.d.ts +69 -0
- package/dist/nips/nip-44.d.ts.map +1 -0
- package/dist/nips/nip-44.js +134 -0
- package/dist/nips/nip-44.js.map +1 -0
- package/dist/nips/nip-46.d.ts +112 -0
- package/dist/nips/nip-46.d.ts.map +1 -0
- package/dist/nips/nip-46.js +119 -0
- package/dist/nips/nip-46.js.map +1 -0
- package/package.json +5 -9
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file NIP-44: Versioned Encrypted Payloads
|
|
3
|
+
* @module nips/nip-44
|
|
4
|
+
* @see https://github.com/nostr-protocol/nips/blob/master/44.md
|
|
5
|
+
*
|
|
6
|
+
* NIP-44 replaces NIP-04 with a modern encryption scheme using
|
|
7
|
+
* ChaCha20 + HMAC-SHA256. This module provides DM-level helpers
|
|
8
|
+
* that parallel the NIP-04 module (nip-04.ts).
|
|
9
|
+
*/
|
|
10
|
+
import { nip44, hexToBytes, getPublicKeySync } from 'nostr-crypto-utils';
|
|
11
|
+
/**
|
|
12
|
+
* Kind value for NIP-44 encrypted direct messages (gift-wrapped DMs use kind 14,
|
|
13
|
+
* but for parity with NIP-04 kind 4 usage, callers may choose their own kind).
|
|
14
|
+
* NIP-44 itself is a payload format, not a kind — the kind depends on the use case.
|
|
15
|
+
* We default to kind 44 as a convenience constant; callers should override as needed.
|
|
16
|
+
*/
|
|
17
|
+
export const ENCRYPTED_DM_KIND_44 = 44;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a NIP-44 conversation key from a sender's private key and recipient's public key.
|
|
20
|
+
* This key is symmetric and reusable for all messages in the conversation.
|
|
21
|
+
* @param senderPrivkeyHex - Sender's private key in hex
|
|
22
|
+
* @param recipientPubkeyHex - Recipient's public key in hex
|
|
23
|
+
* @returns Conversation key as Uint8Array
|
|
24
|
+
*/
|
|
25
|
+
export function getConversationKey(senderPrivkeyHex, recipientPubkeyHex) {
|
|
26
|
+
const privkeyBytes = hexToBytes(senderPrivkeyHex);
|
|
27
|
+
return nip44.getConversationKey(privkeyBytes, recipientPubkeyHex);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Encrypts a message using NIP-44
|
|
31
|
+
* @param plaintext - Message content to encrypt
|
|
32
|
+
* @param senderPrivkeyHex - Sender's private key in hex
|
|
33
|
+
* @param recipientPubkeyHex - Recipient's public key in hex
|
|
34
|
+
* @returns Encrypted payload string (base64)
|
|
35
|
+
*/
|
|
36
|
+
export function encryptNip44(plaintext, senderPrivkeyHex, recipientPubkeyHex) {
|
|
37
|
+
const conversationKey = getConversationKey(senderPrivkeyHex, recipientPubkeyHex);
|
|
38
|
+
return nip44.encrypt(plaintext, conversationKey);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Decrypts a NIP-44 encrypted payload
|
|
42
|
+
* @param payload - Encrypted payload string (base64)
|
|
43
|
+
* @param recipientPrivkeyHex - Recipient's private key in hex
|
|
44
|
+
* @param senderPubkeyHex - Sender's public key in hex
|
|
45
|
+
* @returns Decrypted plaintext
|
|
46
|
+
*/
|
|
47
|
+
export function decryptNip44(payload, recipientPrivkeyHex, senderPubkeyHex) {
|
|
48
|
+
const conversationKey = getConversationKey(recipientPrivkeyHex, senderPubkeyHex);
|
|
49
|
+
return nip44.decrypt(payload, conversationKey);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Creates an encrypted direct message event using NIP-44
|
|
53
|
+
* @param content - Message content to encrypt
|
|
54
|
+
* @param recipientPubkey - Recipient's public key (hex)
|
|
55
|
+
* @param senderPrivkey - Sender's private key (hex)
|
|
56
|
+
* @param tags - Additional tags for the event
|
|
57
|
+
* @param kind - Event kind (defaults to ENCRYPTED_DM_KIND_44)
|
|
58
|
+
* @returns Encrypted message event as NostrWSMessage
|
|
59
|
+
*/
|
|
60
|
+
export function createEncryptedDM44(content, recipientPubkey, senderPrivkey, tags = [], kind = ENCRYPTED_DM_KIND_44) {
|
|
61
|
+
try {
|
|
62
|
+
const encryptedContent = encryptNip44(content, senderPrivkey, recipientPubkey);
|
|
63
|
+
const senderPubkey = getPublicKeySync(senderPrivkey);
|
|
64
|
+
return ['EVENT', {
|
|
65
|
+
kind,
|
|
66
|
+
pubkey: senderPubkey,
|
|
67
|
+
content: encryptedContent,
|
|
68
|
+
tags: [
|
|
69
|
+
['p', recipientPubkey],
|
|
70
|
+
...tags
|
|
71
|
+
]
|
|
72
|
+
}];
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
76
|
+
throw new Error(`Failed to create NIP-44 encrypted DM: ${errorMessage}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Decrypts a received direct message event encrypted with NIP-44
|
|
81
|
+
* @param message - Received message
|
|
82
|
+
* @param recipientPrivkey - Recipient's private key (hex)
|
|
83
|
+
* @param senderPubkey - Sender's public key (hex)
|
|
84
|
+
* @param logger - Logger instance
|
|
85
|
+
* @returns Decrypted message content
|
|
86
|
+
*/
|
|
87
|
+
export function decryptDM44(message, recipientPrivkey, senderPubkey, logger) {
|
|
88
|
+
try {
|
|
89
|
+
if (!Array.isArray(message) || message[0] !== 'EVENT') {
|
|
90
|
+
throw new Error('Invalid message format');
|
|
91
|
+
}
|
|
92
|
+
const event = message[1];
|
|
93
|
+
return decryptNip44(event.content, recipientPrivkey, senderPubkey);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
97
|
+
logger.error('Failed to decrypt NIP-44 DM:', errorMessage);
|
|
98
|
+
throw new Error(`Failed to decrypt NIP-44 DM: ${errorMessage}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validates a NIP-44 encrypted DM event format
|
|
103
|
+
* @param message - Message to validate
|
|
104
|
+
* @param logger - Logger instance
|
|
105
|
+
* @returns True if message follows NIP-44 encrypted DM format
|
|
106
|
+
*/
|
|
107
|
+
export function validateEncryptedDM44(message, logger) {
|
|
108
|
+
try {
|
|
109
|
+
if (!Array.isArray(message) || message[0] !== 'EVENT') {
|
|
110
|
+
logger.debug('Invalid message format');
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const event = message[1];
|
|
114
|
+
if (!event.content || typeof event.content !== 'string') {
|
|
115
|
+
logger.debug('Missing or invalid content');
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (!Array.isArray(event.tags)) {
|
|
119
|
+
logger.debug('Missing tags array');
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const recipientTag = event.tags.find((tag) => Array.isArray(tag) && tag[0] === 'p' && tag[1]);
|
|
123
|
+
if (!recipientTag) {
|
|
124
|
+
logger.debug('Missing recipient tag');
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
logger.error('Error validating NIP-44 encrypted DM:', error);
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=nip-44.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip-44.js","sourceRoot":"","sources":["../../src/nips/nip-44.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAIzE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,gBAAwB,EACxB,kBAA0B;IAE1B,MAAM,YAAY,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAClD,OAAO,KAAK,CAAC,kBAAkB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAiB,EACjB,gBAAwB,EACxB,kBAA0B;IAE1B,MAAM,eAAe,GAAG,kBAAkB,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IACjF,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAe,EACf,mBAA2B,EAC3B,eAAuB;IAEvB,MAAM,eAAe,GAAG,kBAAkB,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IACjF,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AACjD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,eAAuB,EACvB,aAAqB,EACrB,OAAmB,EAAE,EACrB,OAAe,oBAAoB;IAEnC,IAAI,CAAC;QACH,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC;QAC/E,MAAM,YAAY,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAAC;QACrD,OAAO,CAAC,OAAO,EAAE;gBACf,IAAI;gBACJ,MAAM,EAAE,YAAY;gBACpB,OAAO,EAAE,gBAAgB;gBACzB,IAAI,EAAE;oBACJ,CAAC,GAAG,EAAE,eAAe,CAAC;oBACtB,GAAG,IAAI;iBACR;aACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QAC9E,MAAM,IAAI,KAAK,CAAC,yCAAyC,YAAY,EAAE,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,OAAuB,EACvB,gBAAwB,EACxB,YAAoB,EACpB,MAAc;IAEd,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAe,CAAC;QACvC,OAAO,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QAC9E,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,YAAY,CAAC,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,gCAAgC,YAAY,EAAE,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAuB,EACvB,MAAc;IAEd,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;YACtD,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACvC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAe,CAAC;QAEvC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACxD,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC3C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACnC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAa,EAAE,EAAE,CACrD,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAC/C,CAAC;QAEF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACtC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file NIP-46: Nostr Connect / Remote Signing Transport
|
|
3
|
+
* @module nips/nip-46
|
|
4
|
+
* @see https://github.com/nostr-protocol/nips/blob/master/46.md
|
|
5
|
+
*
|
|
6
|
+
* nostr-crypto-utils provides the NIP-46 protocol layer (crypto, encoding,
|
|
7
|
+
* message formatting) but has no I/O. This module adds the WebSocket relay
|
|
8
|
+
* transport on top — subscribing for kind 24133 responses, publishing
|
|
9
|
+
* wrapped requests, and correlating request/response pairs.
|
|
10
|
+
*/
|
|
11
|
+
import { nip46 } from 'nostr-crypto-utils';
|
|
12
|
+
import type { Nip46Session, Nip46Request, Nip46Response, SignedNostrEvent, BunkerURI } from 'nostr-crypto-utils';
|
|
13
|
+
import { NostrWSClient } from '../core/client.js';
|
|
14
|
+
import type { NostrWSMessage } from '../types/messages.js';
|
|
15
|
+
/**
|
|
16
|
+
* Options for creating a NIP-46 transport
|
|
17
|
+
*/
|
|
18
|
+
export interface Nip46TransportOptions {
|
|
19
|
+
/** Timeout for waiting for a response (ms). Defaults to 60000 (60s). */
|
|
20
|
+
timeout?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Result of sending a NIP-46 request
|
|
24
|
+
*/
|
|
25
|
+
export interface Nip46TransportResult {
|
|
26
|
+
/** The JSON-RPC response from the remote signer */
|
|
27
|
+
response: Nip46Response;
|
|
28
|
+
/** The raw kind 24133 event that carried the response */
|
|
29
|
+
rawEvent: SignedNostrEvent;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A thin transport layer that bridges nostr-crypto-utils NIP-46 protocol
|
|
33
|
+
* with the WebSocket relay infrastructure in this library.
|
|
34
|
+
*
|
|
35
|
+
* Usage:
|
|
36
|
+
* ```ts
|
|
37
|
+
* const client = new NostrWSClient(['wss://relay.example.com']);
|
|
38
|
+
* await client.connect();
|
|
39
|
+
*
|
|
40
|
+
* const session = nip46.createSession(remotePubkey);
|
|
41
|
+
* const transport = new Nip46Transport(client, session);
|
|
42
|
+
*
|
|
43
|
+
* // Send a connect request
|
|
44
|
+
* const connectReq = nip46.connectRequest(remotePubkey, secret);
|
|
45
|
+
* const result = await transport.sendRequest(connectReq);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare class Nip46Transport {
|
|
49
|
+
private client;
|
|
50
|
+
private session;
|
|
51
|
+
private timeout;
|
|
52
|
+
constructor(client: NostrWSClient, session: Nip46Session, options?: Nip46TransportOptions);
|
|
53
|
+
/**
|
|
54
|
+
* Subscribe for NIP-46 response events addressed to our ephemeral pubkey.
|
|
55
|
+
* This sends a REQ message to the relay with the appropriate filter.
|
|
56
|
+
* @param subscriptionId - Subscription ID for the REQ message
|
|
57
|
+
* @param since - Optional since timestamp for the filter
|
|
58
|
+
* @returns The subscription message that was sent
|
|
59
|
+
*/
|
|
60
|
+
subscribe(subscriptionId: string, since?: number): Promise<NostrWSMessage>;
|
|
61
|
+
/**
|
|
62
|
+
* Wrap and publish a NIP-46 request as a kind 24133 event.
|
|
63
|
+
* @param request - NIP-46 JSON-RPC request
|
|
64
|
+
* @returns The signed kind 24133 event that was published
|
|
65
|
+
*/
|
|
66
|
+
publishRequest(request: Nip46Request): Promise<SignedNostrEvent>;
|
|
67
|
+
/**
|
|
68
|
+
* Attempt to unwrap a kind 24133 event into a NIP-46 request or response.
|
|
69
|
+
* Returns null if the event is not kind 24133 or decryption fails.
|
|
70
|
+
* @param event - A signed Nostr event
|
|
71
|
+
* @returns Decrypted NIP-46 payload, or null on failure
|
|
72
|
+
*/
|
|
73
|
+
unwrapEvent(event: SignedNostrEvent): Nip46Request | Nip46Response | null;
|
|
74
|
+
/**
|
|
75
|
+
* Get the NIP-46 response filter for this session.
|
|
76
|
+
* Useful for manual subscription management.
|
|
77
|
+
* @param since - Optional since timestamp
|
|
78
|
+
* @returns Filter object for kind 24133 events tagged to our pubkey
|
|
79
|
+
*/
|
|
80
|
+
getResponseFilter(since?: number): {
|
|
81
|
+
kinds: number[];
|
|
82
|
+
'#p': string[];
|
|
83
|
+
since?: number;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Get the current session (read-only info).
|
|
87
|
+
* @returns The session's client and remote pubkeys
|
|
88
|
+
*/
|
|
89
|
+
getSessionInfo(): {
|
|
90
|
+
clientPubkey: string;
|
|
91
|
+
remotePubkey: string;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Parse a bunker:// URI */
|
|
95
|
+
export declare const parseBunkerURI: (uri: string) => BunkerURI;
|
|
96
|
+
/** Create a bunker:// URI */
|
|
97
|
+
export declare const createBunkerURI: (remotePubkey: string, relays: string[], secret?: string) => string;
|
|
98
|
+
/** Validate a bunker:// URI */
|
|
99
|
+
export declare const validateBunkerURI: typeof nip46.validateBunkerURI;
|
|
100
|
+
/** Create a new NIP-46 session */
|
|
101
|
+
export declare const createNip46Session: typeof nip46.createSession;
|
|
102
|
+
/** Restore a NIP-46 session */
|
|
103
|
+
export declare const restoreNip46Session: typeof nip46.restoreSession;
|
|
104
|
+
/** Create a 'connect' request */
|
|
105
|
+
export declare const connectRequest: typeof nip46.connectRequest;
|
|
106
|
+
/** Create a 'ping' request */
|
|
107
|
+
export declare const pingRequest: typeof nip46.pingRequest;
|
|
108
|
+
/** Create a 'get_public_key' request */
|
|
109
|
+
export declare const getPublicKeyRequest: typeof nip46.getPublicKeyRequest;
|
|
110
|
+
/** Create a 'sign_event' request */
|
|
111
|
+
export declare const signEventRequest: typeof nip46.signEventRequest;
|
|
112
|
+
//# sourceMappingURL=nip-46.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip-46.d.ts","sourceRoot":"","sources":["../../src/nips/nip-46.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,SAAS,EACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,QAAQ,EAAE,aAAa,CAAC;IACxB,yDAAyD;IACzD,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAS;gBAGtB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,YAAY,EACrB,OAAO,GAAE,qBAA0B;IAOrC;;;;;;OAMG;IACG,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAWhF;;;;OAIG;IACG,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAatE;;;;;OAKG;IACH,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,GAAG,aAAa,GAAG,IAAI;IAUzE;;;;;OAKG;IACH,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAItF;;;OAGG;IACH,cAAc,IAAI;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE;CAGjE;AAKD,4BAA4B;AAC5B,eAAO,MAAM,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,SAAgC,CAAC;AAE/E,6BAA6B;AAC7B,eAAO,MAAM,eAAe,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAA8B,CAAC;AAE1H,+BAA+B;AAC/B,eAAO,MAAM,iBAAiB,EAAE,OAAO,KAAK,CAAC,iBAA2C,CAAC;AAEzF,kCAAkC;AAClC,eAAO,MAAM,kBAAkB,EAAE,OAAO,KAAK,CAAC,aAAmC,CAAC;AAElF,+BAA+B;AAC/B,eAAO,MAAM,mBAAmB,EAAE,OAAO,KAAK,CAAC,cAAqC,CAAC;AAErF,iCAAiC;AACjC,eAAO,MAAM,cAAc,EAAE,OAAO,KAAK,CAAC,cAAqC,CAAC;AAEhF,8BAA8B;AAC9B,eAAO,MAAM,WAAW,EAAE,OAAO,KAAK,CAAC,WAA+B,CAAC;AAEvE,wCAAwC;AACxC,eAAO,MAAM,mBAAmB,EAAE,OAAO,KAAK,CAAC,mBAA+C,CAAC;AAE/F,oCAAoC;AACpC,eAAO,MAAM,gBAAgB,EAAE,OAAO,KAAK,CAAC,gBAAyC,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file NIP-46: Nostr Connect / Remote Signing Transport
|
|
3
|
+
* @module nips/nip-46
|
|
4
|
+
* @see https://github.com/nostr-protocol/nips/blob/master/46.md
|
|
5
|
+
*
|
|
6
|
+
* nostr-crypto-utils provides the NIP-46 protocol layer (crypto, encoding,
|
|
7
|
+
* message formatting) but has no I/O. This module adds the WebSocket relay
|
|
8
|
+
* transport on top — subscribing for kind 24133 responses, publishing
|
|
9
|
+
* wrapped requests, and correlating request/response pairs.
|
|
10
|
+
*/
|
|
11
|
+
import { nip46 } from 'nostr-crypto-utils';
|
|
12
|
+
import { getLogger } from '../utils/logger.js';
|
|
13
|
+
const logger = getLogger('NIP-46');
|
|
14
|
+
/**
|
|
15
|
+
* A thin transport layer that bridges nostr-crypto-utils NIP-46 protocol
|
|
16
|
+
* with the WebSocket relay infrastructure in this library.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* ```ts
|
|
20
|
+
* const client = new NostrWSClient(['wss://relay.example.com']);
|
|
21
|
+
* await client.connect();
|
|
22
|
+
*
|
|
23
|
+
* const session = nip46.createSession(remotePubkey);
|
|
24
|
+
* const transport = new Nip46Transport(client, session);
|
|
25
|
+
*
|
|
26
|
+
* // Send a connect request
|
|
27
|
+
* const connectReq = nip46.connectRequest(remotePubkey, secret);
|
|
28
|
+
* const result = await transport.sendRequest(connectReq);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export class Nip46Transport {
|
|
32
|
+
constructor(client, session, options = {}) {
|
|
33
|
+
this.client = client;
|
|
34
|
+
this.session = session;
|
|
35
|
+
this.timeout = options.timeout ?? 60000;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Subscribe for NIP-46 response events addressed to our ephemeral pubkey.
|
|
39
|
+
* This sends a REQ message to the relay with the appropriate filter.
|
|
40
|
+
* @param subscriptionId - Subscription ID for the REQ message
|
|
41
|
+
* @param since - Optional since timestamp for the filter
|
|
42
|
+
* @returns The subscription message that was sent
|
|
43
|
+
*/
|
|
44
|
+
async subscribe(subscriptionId, since) {
|
|
45
|
+
const filter = nip46.createResponseFilter(this.session.clientPubkey, since);
|
|
46
|
+
const message = ['REQ', {
|
|
47
|
+
subscription_id: subscriptionId,
|
|
48
|
+
filters: [filter]
|
|
49
|
+
}];
|
|
50
|
+
await this.client.sendMessage(message);
|
|
51
|
+
logger.debug({ subscriptionId, filter }, 'Subscribed for NIP-46 responses');
|
|
52
|
+
return message;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Wrap and publish a NIP-46 request as a kind 24133 event.
|
|
56
|
+
* @param request - NIP-46 JSON-RPC request
|
|
57
|
+
* @returns The signed kind 24133 event that was published
|
|
58
|
+
*/
|
|
59
|
+
async publishRequest(request) {
|
|
60
|
+
const event = await nip46.wrapEvent(request, this.session, this.session.remotePubkey);
|
|
61
|
+
const message = ['EVENT', event];
|
|
62
|
+
await this.client.sendMessage(message);
|
|
63
|
+
logger.debug({ requestId: request.id, method: request.method }, 'Published NIP-46 request');
|
|
64
|
+
return event;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Attempt to unwrap a kind 24133 event into a NIP-46 request or response.
|
|
68
|
+
* Returns null if the event is not kind 24133 or decryption fails.
|
|
69
|
+
* @param event - A signed Nostr event
|
|
70
|
+
* @returns Decrypted NIP-46 payload, or null on failure
|
|
71
|
+
*/
|
|
72
|
+
unwrapEvent(event) {
|
|
73
|
+
try {
|
|
74
|
+
return nip46.unwrapEvent(event, this.session);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
78
|
+
logger.debug({ error: errorMessage }, 'Failed to unwrap NIP-46 event');
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get the NIP-46 response filter for this session.
|
|
84
|
+
* Useful for manual subscription management.
|
|
85
|
+
* @param since - Optional since timestamp
|
|
86
|
+
* @returns Filter object for kind 24133 events tagged to our pubkey
|
|
87
|
+
*/
|
|
88
|
+
getResponseFilter(since) {
|
|
89
|
+
return nip46.createResponseFilter(this.session.clientPubkey, since);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the current session (read-only info).
|
|
93
|
+
* @returns The session's client and remote pubkeys
|
|
94
|
+
*/
|
|
95
|
+
getSessionInfo() {
|
|
96
|
+
return nip46.getSessionInfo(this.session);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// ─── Convenience re-exports from nostr-crypto-utils ─────────────────────────
|
|
100
|
+
// These let consumers access NIP-46 protocol helpers without a separate import.
|
|
101
|
+
/** Parse a bunker:// URI */
|
|
102
|
+
export const parseBunkerURI = nip46.parseBunkerURI;
|
|
103
|
+
/** Create a bunker:// URI */
|
|
104
|
+
export const createBunkerURI = nip46.createBunkerURI;
|
|
105
|
+
/** Validate a bunker:// URI */
|
|
106
|
+
export const validateBunkerURI = nip46.validateBunkerURI;
|
|
107
|
+
/** Create a new NIP-46 session */
|
|
108
|
+
export const createNip46Session = nip46.createSession;
|
|
109
|
+
/** Restore a NIP-46 session */
|
|
110
|
+
export const restoreNip46Session = nip46.restoreSession;
|
|
111
|
+
/** Create a 'connect' request */
|
|
112
|
+
export const connectRequest = nip46.connectRequest;
|
|
113
|
+
/** Create a 'ping' request */
|
|
114
|
+
export const pingRequest = nip46.pingRequest;
|
|
115
|
+
/** Create a 'get_public_key' request */
|
|
116
|
+
export const getPublicKeyRequest = nip46.getPublicKeyRequest;
|
|
117
|
+
/** Create a 'sign_event' request */
|
|
118
|
+
export const signEventRequest = nip46.signEventRequest;
|
|
119
|
+
//# sourceMappingURL=nip-46.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nip-46.js","sourceRoot":"","sources":["../../src/nips/nip-46.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nostr-websocket-utils",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
4
4
|
"description": "Robust WebSocket utilities for Nostr applications with automatic reconnection, supporting both ESM and CommonJS. Features channel-based messaging, heartbeat monitoring, message queueing, and comprehensive error handling with type-safe handlers.",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "npm run build:ts && npm run build:browser",
|
|
24
24
|
"build:ts": "tsc && tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
|
|
25
|
-
"build:browser": "
|
|
25
|
+
"build:browser": "node esbuild.browser.mjs",
|
|
26
26
|
"test": "vitest run",
|
|
27
27
|
"test:watch": "vitest",
|
|
28
28
|
"test:coverage": "vitest run --coverage",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"homepage": "https://github.com/HumanjavaEnterprises/nostr-websocket-utils#readme",
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@types/uuid": "^10.0.0",
|
|
64
|
-
"nostr-crypto-utils": "^0.
|
|
64
|
+
"nostr-crypto-utils": "^0.5.1",
|
|
65
65
|
"pino": "^8.21.0",
|
|
66
66
|
"uuid": "^11.1.0",
|
|
67
67
|
"ws": "^8.19.0"
|
|
@@ -73,16 +73,12 @@
|
|
|
73
73
|
"@typescript-eslint/eslint-plugin": "^8.56.0",
|
|
74
74
|
"@typescript-eslint/parser": "^8.56.0",
|
|
75
75
|
"@vitest/coverage-v8": "^3.2.4",
|
|
76
|
+
"esbuild": "^0.27.3",
|
|
76
77
|
"eslint": "^10.0.0",
|
|
77
|
-
"terser-webpack-plugin": "^5.3.16",
|
|
78
|
-
"ts-loader": "^9.5.4",
|
|
79
78
|
"typedoc": "^0.28.17",
|
|
80
79
|
"typedoc-plugin-markdown": "^4.10.0",
|
|
81
80
|
"typescript": "^5.9.3",
|
|
82
|
-
"vitest": "^3.2.4"
|
|
83
|
-
"webpack": "^5.105.2",
|
|
84
|
-
"webpack-bundle-analyzer": "^4.10.1",
|
|
85
|
-
"webpack-cli": "^5.1.4"
|
|
81
|
+
"vitest": "^3.2.4"
|
|
86
82
|
},
|
|
87
83
|
"files": [
|
|
88
84
|
"dist",
|