@unicitylabs/nostr-js-sdk 0.3.0 → 0.3.1

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 CHANGED
@@ -5,6 +5,7 @@ A TypeScript SDK for Nostr protocol with Unicity extensions. Works in both Node.
5
5
  ## Features
6
6
 
7
7
  - **NIP-17 Private Messages** - Gift-wrapped private direct messages with sender anonymity
8
+ - **NIP-42 Client Authentication** - Automatic relay authentication for protected relays
8
9
  - **NIP-44 Encryption** - Modern ChaCha20-Poly1305 AEAD encryption with HKDF
9
10
  - **BIP-340 Schnorr Signatures** - Full support for secp256k1 Schnorr signatures
10
11
  - **NIP-04 Encryption** - Legacy AES-256-CBC encryption with ECDH key agreement
@@ -470,6 +471,7 @@ const parsed = await PaymentRequestProtocol.parsePaymentRequest(event, keyManage
470
471
  | 14 | CHAT_MESSAGE | Private direct message rumor (NIP-17) |
471
472
  | 15 | READ_RECEIPT | Read receipt rumor (NIP-17) |
472
473
  | 1059 | GIFT_WRAP | Gift-wrapped message (NIP-17) |
474
+ | 22242 | AUTH | Client authentication to relay (NIP-42) |
473
475
  | 30078 | APP_DATA | Application-specific data (nametag bindings) |
474
476
  | 31111 | AGENT_PROFILE | Agent profile information |
475
477
  | 31112 | AGENT_LOCATION | Agent GPS location |
@@ -5585,6 +5585,8 @@ const REACTION = 7;
5585
5585
  const GIFT_WRAP = 1059;
5586
5586
  /** NIP-65: Relay list metadata */
5587
5587
  const RELAY_LIST = 10002;
5588
+ /** NIP-42: Client authentication to relay */
5589
+ const AUTH = 22242;
5588
5590
  /** NIP-78: Application-specific data (parameterized replaceable) */
5589
5591
  const APP_DATA = 30078;
5590
5592
  // ============================================================================
@@ -5698,6 +5700,7 @@ var EventKinds = /*#__PURE__*/Object.freeze({
5698
5700
  AGENT_LOCATION: AGENT_LOCATION,
5699
5701
  AGENT_PROFILE: AGENT_PROFILE,
5700
5702
  APP_DATA: APP_DATA,
5703
+ AUTH: AUTH,
5701
5704
  CHAT_MESSAGE: CHAT_MESSAGE,
5702
5705
  CONTACTS: CONTACTS,
5703
5706
  DELETION: DELETION,
@@ -5998,6 +6001,13 @@ const DEFAULT_QUERY_TIMEOUT_MS = 5000;
5998
6001
  const DEFAULT_RECONNECT_INTERVAL_MS = 1000;
5999
6002
  const DEFAULT_MAX_RECONNECT_INTERVAL_MS = 30000;
6000
6003
  const DEFAULT_PING_INTERVAL_MS = 30000;
6004
+ /**
6005
+ * Delay before resubscribing after NIP-42 authentication.
6006
+ * This gives the relay time to process the AUTH response before we send
6007
+ * subscription requests. Without this delay, some relays may still reject
6008
+ * the subscriptions as the AUTH hasn't been fully processed yet.
6009
+ */
6010
+ const AUTH_RESUBSCRIBE_DELAY_MS = 100;
6001
6011
  /**
6002
6012
  * NostrClient provides the main interface for Nostr protocol operations.
6003
6013
  */
@@ -6342,6 +6352,9 @@ class NostrClient {
6342
6352
  case 'CLOSED':
6343
6353
  this.handleClosedMessage(json);
6344
6354
  break;
6355
+ case 'AUTH':
6356
+ this.handleAuthMessage(_url, json);
6357
+ break;
6345
6358
  }
6346
6359
  }
6347
6360
  catch {
@@ -6422,6 +6435,33 @@ class NostrClient {
6422
6435
  subscription.listener.onError(subscriptionId, `Subscription closed: ${message}`);
6423
6436
  }
6424
6437
  }
6438
+ /**
6439
+ * Handle AUTH message from relay (NIP-42 authentication challenge).
6440
+ */
6441
+ handleAuthMessage(relayUrl, json) {
6442
+ if (json.length < 2)
6443
+ return;
6444
+ const challenge = json[1];
6445
+ const relay = this.relays.get(relayUrl);
6446
+ if (!relay?.socket || !relay.connected)
6447
+ return;
6448
+ // Create and sign the auth event (kind 22242)
6449
+ const authEvent = Event.create(this.keyManager, {
6450
+ kind: AUTH,
6451
+ tags: [
6452
+ ['relay', relayUrl],
6453
+ ['challenge', challenge],
6454
+ ],
6455
+ content: '',
6456
+ });
6457
+ // Send AUTH response
6458
+ const message = JSON.stringify(['AUTH', authEvent.toJSON()]);
6459
+ relay.socket.send(message);
6460
+ // Re-send subscriptions after auth (relay may have ignored pre-auth requests)
6461
+ setTimeout(() => {
6462
+ this.resubscribeAll(relayUrl);
6463
+ }, AUTH_RESUBSCRIBE_DELAY_MS);
6464
+ }
6425
6465
  /**
6426
6466
  * Disconnect from all relays.
6427
6467
  */
@@ -10654,5 +10694,5 @@ function isReadReceipt(message) {
10654
10694
  return message.kind === 15;
10655
10695
  }
10656
10696
 
10657
- export { AGENT_LOCATION, AGENT_PROFILE, APP_DATA, bech32 as Bech32, CHAT_MESSAGE, CLOSED, CLOSING, CONNECTING, CONTACTS, CallbackEventListener, DELETION, ENCRYPTED_DM, Event, EventKinds, FILE_METADATA, Filter, FilterBuilder, GIFT_WRAP, nip04 as NIP04, nip17 as NIP17, nip44 as NIP44, NametagBinding, NametagUtils, NostrClient, NostrKeyManager, OPEN, PAYMENT_REQUEST, PAYMENT_REQUEST_RESPONSE, PROFILE, PaymentRequestProtocol, REACTION, READ_RECEIPT, RECOMMEND_RELAY, RELAY_LIST, SEAL, schnorr as SchnorrSigner, TEXT_NOTE, TOKEN_TRANSFER, TokenTransferProtocol, areSameNametag, createBindingEvent, createGiftWrap, createNametagToPubkeyFilter, createPubkeyToNametagFilter, createReadReceipt, createWebSocket, decode, decodeNpub, decodeNsec, encode, encodeNpub, encodeNsec, extractMessageData, formatForDisplay, getName, getPublicKey, getPublicKeyHex, hashNametag, isChatMessage, isEphemeral, isParameterizedReplaceable, isPhoneNumber, isReadReceipt, isReplaceable, isValidBindingEvent, normalizeNametag, parseAddressFromEvent, parseNametagHashFromEvent, sign, signHex, unwrap, verify, verifyHex };
10697
+ export { AGENT_LOCATION, AGENT_PROFILE, APP_DATA, AUTH, bech32 as Bech32, CHAT_MESSAGE, CLOSED, CLOSING, CONNECTING, CONTACTS, CallbackEventListener, DELETION, ENCRYPTED_DM, Event, EventKinds, FILE_METADATA, Filter, FilterBuilder, GIFT_WRAP, nip04 as NIP04, nip17 as NIP17, nip44 as NIP44, NametagBinding, NametagUtils, NostrClient, NostrKeyManager, OPEN, PAYMENT_REQUEST, PAYMENT_REQUEST_RESPONSE, PROFILE, PaymentRequestProtocol, REACTION, READ_RECEIPT, RECOMMEND_RELAY, RELAY_LIST, SEAL, schnorr as SchnorrSigner, TEXT_NOTE, TOKEN_TRANSFER, TokenTransferProtocol, areSameNametag, createBindingEvent, createGiftWrap, createNametagToPubkeyFilter, createPubkeyToNametagFilter, createReadReceipt, createWebSocket, decode, decodeNpub, decodeNsec, encode, encodeNpub, encodeNsec, extractMessageData, formatForDisplay, getName, getPublicKey, getPublicKeyHex, hashNametag, isChatMessage, isEphemeral, isParameterizedReplaceable, isPhoneNumber, isReadReceipt, isReplaceable, isValidBindingEvent, normalizeNametag, parseAddressFromEvent, parseNametagHashFromEvent, sign, signHex, unwrap, verify, verifyHex };
10658
10698
  //# sourceMappingURL=index.js.map