nostr-websocket-utils 0.2.4 → 0.3.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.
Files changed (111) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +151 -103
  3. package/dist/__mocks__/extendedWsMock.d.ts +35 -0
  4. package/dist/__mocks__/extendedWsMock.js +156 -0
  5. package/dist/__mocks__/logger.d.ts +9 -0
  6. package/dist/__mocks__/logger.js +6 -0
  7. package/dist/__mocks__/mockLogger.d.ts +41 -0
  8. package/dist/__mocks__/mockLogger.js +47 -0
  9. package/dist/__mocks__/mockserver.d.ts +31 -0
  10. package/dist/__mocks__/mockserver.js +39 -0
  11. package/dist/__mocks__/wsMock.d.ts +26 -0
  12. package/dist/__mocks__/wsMock.js +120 -0
  13. package/dist/client.d.ts +105 -0
  14. package/dist/client.js +105 -0
  15. package/dist/core/client.d.ts +94 -0
  16. package/dist/core/client.js +360 -0
  17. package/dist/core/nostr-server.d.ts +27 -0
  18. package/dist/core/nostr-server.js +95 -0
  19. package/dist/core/queue.d.ts +61 -0
  20. package/dist/core/queue.js +108 -0
  21. package/dist/core/server.d.ts +27 -0
  22. package/dist/core/server.js +114 -0
  23. package/dist/crypto/bech32.d.ts +26 -0
  24. package/dist/crypto/bech32.js +163 -0
  25. package/dist/crypto/handlers.d.ts +11 -0
  26. package/dist/crypto/handlers.js +36 -0
  27. package/dist/crypto/index.d.ts +5 -0
  28. package/dist/crypto/index.js +5 -0
  29. package/dist/crypto/schnorr.d.ts +16 -0
  30. package/dist/crypto/schnorr.js +51 -0
  31. package/dist/endpoints/metrics.d.ts +29 -0
  32. package/dist/endpoints/metrics.js +101 -0
  33. package/dist/index.d.ts +11 -6
  34. package/dist/index.js +16 -4
  35. package/dist/nips/index.d.ts +19 -0
  36. package/dist/nips/index.js +34 -0
  37. package/dist/nips/nip-01.d.ts +34 -0
  38. package/dist/nips/nip-01.js +145 -0
  39. package/dist/nips/nip-02.d.ts +83 -0
  40. package/dist/nips/nip-02.js +123 -0
  41. package/dist/nips/nip-04.d.ts +36 -0
  42. package/dist/nips/nip-04.js +105 -0
  43. package/dist/nips/nip-05.d.ts +86 -0
  44. package/dist/nips/nip-05.js +151 -0
  45. package/dist/nips/nip-09.d.ts +92 -0
  46. package/dist/nips/nip-09.js +190 -0
  47. package/dist/nips/nip-11.d.ts +64 -0
  48. package/dist/nips/nip-11.js +154 -0
  49. package/dist/nips/nip-13.d.ts +73 -0
  50. package/dist/nips/nip-13.js +128 -0
  51. package/dist/nips/nip-15.d.ts +83 -0
  52. package/dist/nips/nip-15.js +101 -0
  53. package/dist/nips/nip-16.d.ts +88 -0
  54. package/dist/nips/nip-16.js +150 -0
  55. package/dist/nips/nip-19.d.ts +28 -0
  56. package/dist/nips/nip-19.js +103 -0
  57. package/dist/nips/nip-20.d.ts +59 -0
  58. package/dist/nips/nip-20.js +95 -0
  59. package/dist/nips/nip-22.d.ts +89 -0
  60. package/dist/nips/nip-22.js +142 -0
  61. package/dist/nips/nip-26.d.ts +52 -0
  62. package/dist/nips/nip-26.js +139 -0
  63. package/dist/nips/nip-28.d.ts +103 -0
  64. package/dist/nips/nip-28.js +170 -0
  65. package/dist/nips/nip-33.d.ts +94 -0
  66. package/dist/nips/nip-33.js +133 -0
  67. package/dist/nostr-server.d.ts +23 -0
  68. package/dist/nostr-server.js +44 -0
  69. package/dist/server.d.ts +13 -3
  70. package/dist/server.js +60 -33
  71. package/dist/transport/base.d.ts +54 -0
  72. package/dist/transport/base.js +104 -0
  73. package/dist/transport/websocket.d.ts +22 -0
  74. package/dist/transport/websocket.js +122 -0
  75. package/dist/types/events.d.ts +63 -0
  76. package/dist/types/events.js +5 -0
  77. package/dist/types/filters.d.ts +19 -0
  78. package/dist/types/filters.js +5 -0
  79. package/dist/types/handlers.d.ts +80 -0
  80. package/dist/types/handlers.js +5 -0
  81. package/dist/types/index.d.ts +118 -39
  82. package/dist/types/index.js +21 -1
  83. package/dist/types/logger.d.ts +40 -0
  84. package/dist/types/logger.js +5 -0
  85. package/dist/types/messages.d.ts +135 -0
  86. package/dist/types/messages.js +40 -0
  87. package/dist/types/nostr.d.ts +120 -39
  88. package/dist/types/nostr.js +5 -10
  89. package/dist/types/options.d.ts +154 -0
  90. package/dist/types/options.js +5 -0
  91. package/dist/types/relays.d.ts +26 -0
  92. package/dist/types/relays.js +5 -0
  93. package/dist/types/scoring.d.ts +47 -0
  94. package/dist/types/scoring.js +29 -0
  95. package/dist/types/socket.d.ts +99 -0
  96. package/dist/types/socket.js +5 -0
  97. package/dist/types/transport.d.ts +97 -0
  98. package/dist/types/transport.js +5 -0
  99. package/dist/types/validation.d.ts +50 -0
  100. package/dist/types/validation.js +5 -0
  101. package/dist/types/websocket.d.ts +172 -0
  102. package/dist/types/websocket.js +5 -0
  103. package/dist/utils/http.d.ts +10 -0
  104. package/dist/utils/http.js +24 -0
  105. package/dist/utils/logger.d.ts +11 -2
  106. package/dist/utils/logger.js +18 -13
  107. package/dist/utils/metrics.d.ts +81 -0
  108. package/dist/utils/metrics.js +206 -0
  109. package/dist/utils/rate-limiter.d.ts +85 -0
  110. package/dist/utils/rate-limiter.js +175 -0
  111. package/package.json +18 -21
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @file NIP-01: Basic protocol flow implementation
3
+ * @module nips/nip-01
4
+ */
5
+ import type { NostrWSMessage } from '../types/messages';
6
+ interface NostrEventValidationResult {
7
+ valid: boolean;
8
+ error?: string;
9
+ }
10
+ /**
11
+ * Validates a message according to NIP-01 specifications
12
+ */
13
+ export declare function validateMessage(message: NostrWSMessage): boolean;
14
+ /**
15
+ * Creates an EVENT message
16
+ */
17
+ export declare function createEventMessage(event: Record<string, unknown>): NostrWSMessage;
18
+ /**
19
+ * Creates a REQ message
20
+ */
21
+ export declare function createReqMessage(subscriptionId: string, filters: Array<Record<string, unknown>>): NostrWSMessage;
22
+ /**
23
+ * Creates a CLOSE message
24
+ */
25
+ export declare function createCloseMessage(subscriptionId: string): NostrWSMessage;
26
+ /**
27
+ * Creates a NOTICE message
28
+ */
29
+ export declare function createNoticeMessage(message: string): NostrWSMessage;
30
+ /**
31
+ * Validates a Nostr event according to NIP-01
32
+ */
33
+ export declare function validateEvent(event: unknown): NostrEventValidationResult;
34
+ export {};
@@ -0,0 +1,145 @@
1
+ /**
2
+ * @file NIP-01: Basic protocol flow implementation
3
+ * @module nips/nip-01
4
+ */
5
+ import { getLogger } from '../utils/logger';
6
+ import { MESSAGE_TYPES } from '../types/messages';
7
+ const logger = getLogger('NIP-01');
8
+ /**
9
+ * Validates a message according to NIP-01 specifications
10
+ */
11
+ export function validateMessage(message) {
12
+ if (!message || typeof message !== 'object') {
13
+ logger.debug('Invalid message format');
14
+ return false;
15
+ }
16
+ if (!message.type || !Object.values(MESSAGE_TYPES).includes(message.type)) {
17
+ logger.debug(`Invalid message type: ${message.type}`);
18
+ return false;
19
+ }
20
+ if (!message.data || typeof message.data !== 'object') {
21
+ logger.debug('Invalid message data');
22
+ return false;
23
+ }
24
+ // Message type specific validation
25
+ if (message.type === MESSAGE_TYPES.EVENT) {
26
+ if (!validateEvent(message.data).valid) {
27
+ return false;
28
+ }
29
+ }
30
+ if (message.type === MESSAGE_TYPES.REQ) {
31
+ if (!validateReqMessage(message)) {
32
+ return false;
33
+ }
34
+ }
35
+ if (message.type === MESSAGE_TYPES.CLOSE) {
36
+ if (!validateCloseMessage(message)) {
37
+ return false;
38
+ }
39
+ }
40
+ return true;
41
+ }
42
+ /**
43
+ * Creates an EVENT message
44
+ */
45
+ export function createEventMessage(event) {
46
+ return {
47
+ type: MESSAGE_TYPES.EVENT,
48
+ data: event
49
+ };
50
+ }
51
+ /**
52
+ * Creates a REQ message
53
+ */
54
+ export function createReqMessage(subscriptionId, filters) {
55
+ return {
56
+ type: MESSAGE_TYPES.REQ,
57
+ data: {
58
+ subscription_id: subscriptionId,
59
+ filters
60
+ }
61
+ };
62
+ }
63
+ /**
64
+ * Creates a CLOSE message
65
+ */
66
+ export function createCloseMessage(subscriptionId) {
67
+ return {
68
+ type: MESSAGE_TYPES.CLOSE,
69
+ data: {
70
+ subscription_id: subscriptionId
71
+ }
72
+ };
73
+ }
74
+ /**
75
+ * Creates a NOTICE message
76
+ */
77
+ export function createNoticeMessage(message) {
78
+ return {
79
+ type: MESSAGE_TYPES.NOTICE,
80
+ data: {
81
+ message
82
+ }
83
+ };
84
+ }
85
+ /**
86
+ * Validates a Nostr event according to NIP-01
87
+ */
88
+ export function validateEvent(event) {
89
+ if (typeof event !== 'object' || !event) {
90
+ return { valid: false, error: 'Event must be an object' };
91
+ }
92
+ const typedEvent = event;
93
+ if (!typedEvent.id || typeof typedEvent.id !== 'string') {
94
+ return { valid: false, error: 'Event must have a string id' };
95
+ }
96
+ if (!typedEvent.pubkey || typeof typedEvent.pubkey !== 'string') {
97
+ return { valid: false, error: 'Event must have a string pubkey' };
98
+ }
99
+ if (!typedEvent.created_at || typeof typedEvent.created_at !== 'number') {
100
+ return { valid: false, error: 'Event must have a number created_at' };
101
+ }
102
+ if (!typedEvent.kind || typeof typedEvent.kind !== 'number') {
103
+ return { valid: false, error: 'Event must have a number kind' };
104
+ }
105
+ if (!Array.isArray(typedEvent.tags)) {
106
+ return { valid: false, error: 'Event must have an array of tags' };
107
+ }
108
+ if (!typedEvent.content || typeof typedEvent.content !== 'string') {
109
+ return { valid: false, error: 'Event must have a string content' };
110
+ }
111
+ if (!typedEvent.sig || typeof typedEvent.sig !== 'string') {
112
+ return { valid: false, error: 'Event must have a string sig' };
113
+ }
114
+ // Validate tag structure
115
+ for (const tag of typedEvent.tags) {
116
+ if (!Array.isArray(tag) || tag.length === 0) {
117
+ return { valid: false, error: 'Each tag must be a non-empty array' };
118
+ }
119
+ if (typeof tag[0] !== 'string') {
120
+ return { valid: false, error: 'Tag identifier must be a string' };
121
+ }
122
+ }
123
+ return { valid: true };
124
+ }
125
+ // Private helper functions
126
+ function validateReqMessage(message) {
127
+ const { subscription_id, filters } = message.data;
128
+ if (!subscription_id || typeof subscription_id !== 'string') {
129
+ logger.debug('Invalid subscription_id');
130
+ return false;
131
+ }
132
+ if (!Array.isArray(filters)) {
133
+ logger.debug('Invalid filters format');
134
+ return false;
135
+ }
136
+ return true;
137
+ }
138
+ function validateCloseMessage(message) {
139
+ const { subscription_id } = message.data;
140
+ if (!subscription_id || typeof subscription_id !== 'string') {
141
+ logger.debug('Invalid subscription_id');
142
+ return false;
143
+ }
144
+ return true;
145
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @file NIP-02: Contact List and Petnames
3
+ * @module nips/nip-02
4
+ * @see https://github.com/nostr-protocol/nips/blob/master/02.md
5
+ */
6
+ import type { NostrWSMessage } from '../types/messages';
7
+ import type { Logger } from '../types/logger';
8
+ /**
9
+ * Contact list event kind
10
+ */
11
+ export declare const CONTACT_LIST_KIND = 3;
12
+ /**
13
+ * Contact entry structure
14
+ */
15
+ export interface Contact {
16
+ pubkey: string;
17
+ relay?: string;
18
+ petname?: string;
19
+ metadata?: Record<string, unknown>;
20
+ }
21
+ /**
22
+ * Creates a contact list event
23
+ * @param contacts - List of contacts
24
+ * @param metadata - Optional metadata for the contact list
25
+ * @returns {NostrWSMessage} Contact list event
26
+ */
27
+ export declare function createContactListEvent(contacts: Contact[], metadata?: Record<string, unknown>): NostrWSMessage;
28
+ /**
29
+ * Extracts contacts from a contact list event
30
+ * @param message - Contact list message
31
+ * @param _logger - Logger instance
32
+ * @returns {Contact[]} Array of contacts
33
+ */
34
+ export declare function extractContacts(message: NostrWSMessage, _logger: Logger): Contact[];
35
+ /**
36
+ * Creates a contact list subscription message
37
+ * @param pubkey - Public key to subscribe to
38
+ * @returns {NostrWSMessage} Subscription message
39
+ */
40
+ export declare function createContactListSubscription(pubkey: string): NostrWSMessage;
41
+ /**
42
+ * Contact list manager interface
43
+ */
44
+ export interface ContactListManager {
45
+ /**
46
+ * Adds or updates a contact
47
+ * @param contact - Contact to add/update
48
+ */
49
+ addContact(contact: Contact): void;
50
+ /**
51
+ * Removes a contact
52
+ * @param pubkey - Public key of contact to remove
53
+ */
54
+ removeContact(pubkey: string): void;
55
+ /**
56
+ * Gets a contact by public key
57
+ * @param pubkey - Public key to look up
58
+ * @returns {Contact | undefined} Contact if found
59
+ */
60
+ getContact(pubkey: string): Contact | undefined;
61
+ /**
62
+ * Gets all contacts
63
+ * @returns {Contact[]} Array of all contacts
64
+ */
65
+ getAllContacts(): Contact[];
66
+ /**
67
+ * Updates contact metadata
68
+ * @param pubkey - Public key of contact
69
+ * @param metadata - New metadata
70
+ */
71
+ updateContactMetadata(pubkey: string, metadata: Record<string, unknown>): void;
72
+ /**
73
+ * Creates a contact list event
74
+ * @returns {NostrWSMessage} Contact list event
75
+ */
76
+ createEvent(): NostrWSMessage;
77
+ }
78
+ /**
79
+ * Creates a contact list manager
80
+ * @param _logger - Logger instance
81
+ * @returns {ContactListManager} Contact list manager
82
+ */
83
+ export declare function createContactListManager(_logger: Logger): ContactListManager;
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @file NIP-02: Contact List and Petnames
3
+ * @module nips/nip-02
4
+ * @see https://github.com/nostr-protocol/nips/blob/master/02.md
5
+ */
6
+ /**
7
+ * Contact list event kind
8
+ */
9
+ export const CONTACT_LIST_KIND = 3;
10
+ /**
11
+ * Creates a contact list event
12
+ * @param contacts - List of contacts
13
+ * @param metadata - Optional metadata for the contact list
14
+ * @returns {NostrWSMessage} Contact list event
15
+ */
16
+ export function createContactListEvent(contacts, metadata = {}) {
17
+ const tags = contacts.map(contact => {
18
+ const tag = ['p', contact.pubkey];
19
+ if (contact.relay)
20
+ tag.push(contact.relay);
21
+ if (contact.petname)
22
+ tag.push(contact.petname);
23
+ return tag;
24
+ });
25
+ return {
26
+ type: 'EVENT',
27
+ data: {
28
+ kind: CONTACT_LIST_KIND,
29
+ tags,
30
+ content: JSON.stringify(metadata)
31
+ }
32
+ };
33
+ }
34
+ /**
35
+ * Extracts contacts from a contact list event
36
+ * @param message - Contact list message
37
+ * @param _logger - Logger instance
38
+ * @returns {Contact[]} Array of contacts
39
+ */
40
+ export function extractContacts(message, _logger) {
41
+ try {
42
+ if (message.type !== 'EVENT' || !message.data) {
43
+ return [];
44
+ }
45
+ const event = message.data;
46
+ if (event.kind !== CONTACT_LIST_KIND || !Array.isArray(event.tags)) {
47
+ return [];
48
+ }
49
+ let metadata = {};
50
+ try {
51
+ metadata = JSON.parse(event.content);
52
+ }
53
+ catch (error) {
54
+ _logger.debug('Failed to parse contact list metadata');
55
+ }
56
+ return event.tags
57
+ .filter(tag => Array.isArray(tag) && tag[0] === 'p' && tag[1])
58
+ .map(tag => ({
59
+ pubkey: tag[1],
60
+ relay: tag[2],
61
+ petname: tag[3],
62
+ metadata
63
+ }));
64
+ }
65
+ catch (error) {
66
+ _logger.error('Error extracting contacts:', error);
67
+ return [];
68
+ }
69
+ }
70
+ /**
71
+ * Creates a contact list subscription message
72
+ * @param pubkey - Public key to subscribe to
73
+ * @returns {NostrWSMessage} Subscription message
74
+ */
75
+ export function createContactListSubscription(pubkey) {
76
+ return {
77
+ type: 'REQ',
78
+ data: {
79
+ filter: {
80
+ authors: [pubkey],
81
+ kinds: [CONTACT_LIST_KIND],
82
+ limit: 1
83
+ }
84
+ }
85
+ };
86
+ }
87
+ /**
88
+ * Creates a contact list manager
89
+ * @param _logger - Logger instance
90
+ * @returns {ContactListManager} Contact list manager
91
+ */
92
+ export function createContactListManager(_logger) {
93
+ const contacts = new Map();
94
+ return {
95
+ addContact(contact) {
96
+ contacts.set(contact.pubkey, contact);
97
+ },
98
+ removeContact(pubkey) {
99
+ contacts.delete(pubkey);
100
+ },
101
+ getContact(pubkey) {
102
+ return contacts.get(pubkey);
103
+ },
104
+ getAllContacts() {
105
+ return Array.from(contacts.values());
106
+ },
107
+ updateContactMetadata(pubkey, metadata) {
108
+ const contact = contacts.get(pubkey);
109
+ if (contact) {
110
+ contacts.set(pubkey, {
111
+ ...contact,
112
+ metadata: {
113
+ ...contact.metadata,
114
+ ...metadata
115
+ }
116
+ });
117
+ }
118
+ },
119
+ createEvent() {
120
+ return createContactListEvent(Array.from(contacts.values()));
121
+ }
122
+ };
123
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @file NIP-04: Encrypted Direct Message Support
3
+ * @module nips/nip-04
4
+ * @see https://github.com/nostr-protocol/nips/blob/master/04.md
5
+ */
6
+ import type { NostrWSMessage } from '../types/messages';
7
+ import type { Logger } from '../types/logger';
8
+ /**
9
+ * Kind value for encrypted direct messages
10
+ */
11
+ export declare const ENCRYPTED_DM_KIND = 4;
12
+ /**
13
+ * Creates an encrypted direct message event
14
+ * @param content - Message content to encrypt
15
+ * @param recipientPubkey - Recipient's public key
16
+ * @param senderPrivkey - Sender's private key
17
+ * @param tags - Additional tags for the event
18
+ * @returns {Promise<NostrWSMessage>} Encrypted message event
19
+ */
20
+ export declare function createEncryptedDM(content: string, recipientPubkey: string, senderPrivkey: string, tags?: string[][]): Promise<NostrWSMessage>;
21
+ /**
22
+ * Decrypts a received direct message event
23
+ * @param message - Received message
24
+ * @param recipientPrivkey - Recipient's private key
25
+ * @param senderPubkey - Sender's public key
26
+ * @param logger - Logger instance
27
+ * @returns {Promise<string>} Decrypted message content
28
+ */
29
+ export declare function decryptDM(message: NostrWSMessage, recipientPrivkey: string, senderPubkey: string, logger: Logger): Promise<string>;
30
+ /**
31
+ * Validates an encrypted DM event format
32
+ * @param message - Message to validate
33
+ * @param logger - Logger instance
34
+ * @returns {boolean} True if message follows NIP-04 format
35
+ */
36
+ export declare function validateEncryptedDM(message: NostrWSMessage, logger: Logger): boolean;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @file NIP-04: Encrypted Direct Message Support
3
+ * @module nips/nip-04
4
+ * @see https://github.com/nostr-protocol/nips/blob/master/04.md
5
+ */
6
+ import { encryptMessage, decryptMessage } from 'nostr-crypto-utils';
7
+ /**
8
+ * Kind value for encrypted direct messages
9
+ */
10
+ export const ENCRYPTED_DM_KIND = 4;
11
+ /**
12
+ * Creates an encrypted direct message event
13
+ * @param content - Message content to encrypt
14
+ * @param recipientPubkey - Recipient's public key
15
+ * @param senderPrivkey - Sender's private key
16
+ * @param tags - Additional tags for the event
17
+ * @returns {Promise<NostrWSMessage>} Encrypted message event
18
+ */
19
+ export async function createEncryptedDM(content, recipientPubkey, senderPrivkey, tags = []) {
20
+ try {
21
+ const encryptedContent = await encryptMessage(content, recipientPubkey, senderPrivkey);
22
+ return {
23
+ type: 'EVENT',
24
+ data: {
25
+ kind: ENCRYPTED_DM_KIND,
26
+ content: encryptedContent,
27
+ tags: [
28
+ ['p', recipientPubkey],
29
+ ...tags
30
+ ]
31
+ }
32
+ };
33
+ }
34
+ catch (error) {
35
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
36
+ throw new Error(`Failed to create encrypted DM: ${errorMessage}`);
37
+ }
38
+ }
39
+ /**
40
+ * Decrypts a received direct message event
41
+ * @param message - Received message
42
+ * @param recipientPrivkey - Recipient's private key
43
+ * @param senderPubkey - Sender's public key
44
+ * @param logger - Logger instance
45
+ * @returns {Promise<string>} Decrypted message content
46
+ */
47
+ export async function decryptDM(message, recipientPrivkey, senderPubkey, logger) {
48
+ try {
49
+ if (message.type !== 'EVENT' || !message.data) {
50
+ throw new Error('Invalid message format');
51
+ }
52
+ const event = message.data;
53
+ if (event.kind !== ENCRYPTED_DM_KIND) {
54
+ throw new Error('Not an encrypted DM event');
55
+ }
56
+ const content = event.content;
57
+ if (!content) {
58
+ throw new Error('No encrypted content found');
59
+ }
60
+ return await decryptMessage(content, senderPubkey, recipientPrivkey);
61
+ }
62
+ catch (error) {
63
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
64
+ logger.error(`Failed to decrypt DM: ${errorMessage}`);
65
+ throw new Error(errorMessage);
66
+ }
67
+ }
68
+ /**
69
+ * Validates an encrypted DM event format
70
+ * @param message - Message to validate
71
+ * @param logger - Logger instance
72
+ * @returns {boolean} True if message follows NIP-04 format
73
+ */
74
+ export function validateEncryptedDM(message, logger) {
75
+ try {
76
+ if (message.type !== 'EVENT' || !message.data) {
77
+ logger.debug('Not an event message');
78
+ return false;
79
+ }
80
+ const event = message.data;
81
+ if (event.kind !== ENCRYPTED_DM_KIND) {
82
+ logger.debug('Not an encrypted DM event');
83
+ return false;
84
+ }
85
+ if (!event.content || typeof event.content !== 'string') {
86
+ logger.debug('Invalid or missing content');
87
+ return false;
88
+ }
89
+ if (!Array.isArray(event.tags)) {
90
+ logger.debug('Missing tags array');
91
+ return false;
92
+ }
93
+ const pTag = event.tags.find(tag => Array.isArray(tag) && tag[0] === 'p' && tag[1]);
94
+ if (!pTag) {
95
+ logger.debug('Missing recipient pubkey tag');
96
+ return false;
97
+ }
98
+ return true;
99
+ }
100
+ catch (error) {
101
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
102
+ logger.error(`Error validating encrypted DM: ${errorMessage}`);
103
+ return false;
104
+ }
105
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @file NIP-05: DNS-Based Verification
3
+ * @module nips/nip-05
4
+ * @see https://github.com/nostr-protocol/nips/blob/master/05.md
5
+ */
6
+ /**
7
+ * NIP-05 verification result
8
+ */
9
+ export interface NIP05VerificationResult {
10
+ valid: boolean;
11
+ pubkey?: string;
12
+ relays?: string[];
13
+ error?: string;
14
+ }
15
+ /**
16
+ * Verifies a NIP-05 identifier
17
+ * @param identifier - Internet identifier (user@domain.com)
18
+ * @param pubkey - Public key to verify
19
+ * @param logger - Logger instance
20
+ * @returns {Promise<NIP05VerificationResult>} Verification result
21
+ */
22
+ export declare function verifyNIP05Identifier(identifier: string, pubkey: string, logger: any): Promise<NIP05VerificationResult>;
23
+ /**
24
+ * Creates metadata event with NIP-05 identifier
25
+ * @param identifier - Internet identifier
26
+ * @param metadata - Additional metadata
27
+ * @returns {Record<string, unknown>} Metadata event content
28
+ */
29
+ export declare function createNIP05Metadata(identifier: string, metadata?: Record<string, unknown>): Record<string, unknown>;
30
+ /**
31
+ * NIP-05 verification cache interface
32
+ */
33
+ export interface NIP05VerificationCache {
34
+ /**
35
+ * Gets cached verification result
36
+ * @param identifier - Internet identifier
37
+ * @param pubkey - Public key
38
+ * @returns {NIP05VerificationResult | undefined} Cached result
39
+ */
40
+ get(identifier: string, pubkey: string): NIP05VerificationResult | undefined;
41
+ /**
42
+ * Sets verification result in cache
43
+ * @param identifier - Internet identifier
44
+ * @param pubkey - Public key
45
+ * @param result - Verification result
46
+ * @param ttl - Time to live in seconds
47
+ */
48
+ set(identifier: string, pubkey: string, result: NIP05VerificationResult, ttl: number): void;
49
+ /**
50
+ * Clears expired entries
51
+ */
52
+ cleanup(): void;
53
+ }
54
+ /**
55
+ * Creates a NIP-05 verification cache
56
+ * @param defaultTTL - Default TTL in seconds
57
+ * @returns {NIP05VerificationCache} Verification cache
58
+ */
59
+ export declare function createNIP05VerificationCache(defaultTTL?: number): NIP05VerificationCache;
60
+ /**
61
+ * Batch verification interface for multiple identifiers
62
+ */
63
+ export interface NIP05BatchVerifier {
64
+ /**
65
+ * Adds identifier to verification queue
66
+ * @param identifier - Internet identifier
67
+ * @param pubkey - Public key
68
+ */
69
+ addToQueue(identifier: string, pubkey: string): void;
70
+ /**
71
+ * Verifies all queued identifiers
72
+ * @returns {Promise<Map<string, NIP05VerificationResult>>} Verification results
73
+ */
74
+ verifyAll(): Promise<Map<string, NIP05VerificationResult>>;
75
+ /**
76
+ * Clears verification queue
77
+ */
78
+ clearQueue(): void;
79
+ }
80
+ /**
81
+ * Creates a NIP-05 batch verifier
82
+ * @param logger - Logger instance
83
+ * @param cache - Optional verification cache
84
+ * @returns {NIP05BatchVerifier} Batch verifier
85
+ */
86
+ export declare function createNIP05BatchVerifier(logger: any, cache?: NIP05VerificationCache): NIP05BatchVerifier;