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
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 MaiQR Platform
3
+ Copyright (c) 2024 Humanjava Enterprises
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,25 +1,77 @@
1
- # Nostr Websocket Utils
1
+ # nostr-websocket-utils
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/nostr-websocket-utils.svg)](https://www.npmjs.com/package/nostr-websocket-utils)
4
- [![License](https://img.shields.io/npm/l/nostr-websocket-utils.svg)](https://github.com/HumanjavaEnterprises/nostr-websocket-utils/blob/main/LICENSE)
3
+ [![npm version](https://img.shields.io/npm/v/@humanjavaenterprises/nostr-websocket-utils.svg)](https://www.npmjs.com/package/@humanjavaenterprises/nostr-websocket-utils)
4
+ [![License](https://img.shields.io/npm/l/@humanjavaenterprises/nostr-websocket-utils.svg)](https://github.com/HumanjavaEnterprises/nostr-websocket-utils/blob/main/LICENSE)
5
5
  [![Build Status](https://github.com/HumanjavaEnterprises/nostr-websocket-utils/workflows/CI/badge.svg)](https://github.com/HumanjavaEnterprises/nostr-websocket-utils/actions)
6
+ [![Documentation](https://github.com/HumanjavaEnterprises/nostr-websocket-utils/workflows/Documentation/badge.svg)](https://humanjavaenterprises.github.io/nostr-websocket-utils/)
6
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org)
7
8
  [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
8
9
 
9
- A TypeScript library providing WebSocket utilities for Nostr applications, focusing on robust connection handling, automatic reconnection, and channel-based messaging. This library has been streamlined to remove any DOM-related code, enhancing performance and maintainability.
10
+ A TypeScript library for building Nostr protocol WebSocket clients and servers.
10
11
 
11
12
  ## Features
12
13
 
13
- - 🔄 Automatic reconnection with configurable attempts
14
- - 💓 Heartbeat monitoring with configurable intervals
15
- - 📨 Message queueing during disconnections
16
- - 📢 Channel-based broadcasting with filtered subscriptions
17
- - 🔒 Type-safe message handling with required handlers
18
- - 📝 Built-in logging with Winston integration
19
- - 🛡️ Comprehensive error handling and validation
20
- - 🧪 100% test coverage with Jest
21
- - 📦 Zero DOM dependencies
22
- - 🔍 Full TypeScript type safety
14
+ - 🚀 Full Nostr protocol support
15
+ - 🔒 Secure WebSocket connections
16
+ - ♥️ Heartbeat mechanism for connection health
17
+ - 🔄 Automatic reconnection handling
18
+ - 📝 Comprehensive logging
19
+ - 🎯 Type-safe message handling
20
+ - 📦 Easy to use API
21
+
22
+ ## NIPs Support Status
23
+
24
+ 🟢 Fully implemented 🟡 Partially implemented 🔴 Not implemented
25
+
26
+ | NIP | Status | Description |
27
+ |-----|--------|-------------|
28
+ | 01 | 🟢 | Basic protocol flow & WebSocket connections |
29
+ | 02 | 🟢 | Contact List and Petnames |
30
+ | 11 | 🟢 | Relay Information Document |
31
+ | 15 | 🟢 | End of Stored Events Notice |
32
+ | 16 | 🟢 | Event Treatment |
33
+ | 20 | 🟢 | Command Results |
34
+ | 42 | 🟢 | Authentication of clients to relays |
35
+
36
+ ### WebSocket Protocol Implementation Details
37
+
38
+ This package implements the Nostr WebSocket protocol with full support for the core NIPs that define WebSocket behavior. Here's how it works:
39
+
40
+ #### Key Features & Compliance
41
+
42
+ 1. **Protocol Implementation**:
43
+ - Full implementation of Nostr WebSocket protocol
44
+ - Support for all standard message types (EVENT, REQ, CLOSE, etc.)
45
+ - Robust error handling and status reporting
46
+
47
+ 2. **Connection Management**:
48
+ - Automatic reconnection with configurable backoff
49
+ - Heartbeat mechanism for connection health
50
+ - Connection pooling and load balancing
51
+
52
+ 3. **Message Handling**:
53
+ - Type-safe message processing
54
+ - Support for subscription management
55
+ - Efficient event filtering
56
+
57
+ 4. **Security & Best Practices**:
58
+ - Secure WebSocket connections (WSS)
59
+ - Implementation of authentication protocols
60
+ - Rate limiting and protection mechanisms
61
+
62
+ #### Interoperability
63
+
64
+ This implementation ensures compatibility with:
65
+ - All major Nostr relays
66
+ - Other Nostr clients and libraries
67
+ - Standard WebSocket tooling and infrastructure
68
+
69
+ #### Validation & Testing
70
+
71
+ The package includes:
72
+ - Comprehensive test suites for protocol compliance
73
+ - Connection reliability testing
74
+ - Performance benchmarks for message handling
23
75
 
24
76
  ## Installation
25
77
 
@@ -27,118 +79,114 @@ A TypeScript library providing WebSocket utilities for Nostr applications, focus
27
79
  npm install nostr-websocket-utils
28
80
  ```
29
81
 
30
- ## Breaking Changes in v0.2.4
82
+ ## Quick Start
83
+
84
+ ### Creating a Nostr WebSocket Client
85
+
86
+ ```typescript
87
+ import { NostrWSClient } from 'nostr-websocket-utils';
31
88
 
32
- - 🆕 Added dedicated Nostr WebSocket server implementation
33
- - 📝 Enhanced TypeScript type definitions for Nostr messages
34
- - 🔄 Improved message handling with strict type checking
35
- - 🧪 Added comprehensive test suite for Nostr server
36
- - 🛡️ Strengthened type safety with `unknown` types
37
- - 🔌 Added support for Nostr EVENT and REQ messages
89
+ const client = new NostrWSClient('wss://relay.example.com', {
90
+ logger: console,
91
+ heartbeatInterval: 30000,
92
+ handlers: {
93
+ message: async (msg) => console.log('Received:', msg),
94
+ error: (err) => console.error('Error:', err),
95
+ close: () => console.log('Connection closed')
96
+ }
97
+ });
38
98
 
39
- ## Usage
99
+ await client.connect();
100
+ ```
40
101
 
41
- ### Nostr Server Example
102
+ ### Creating a Nostr WebSocket Server
42
103
 
43
104
  ```typescript
44
- import { NostrWSServer, createWSServer } from 'nostr-websocket-utils';
45
- import { NostrWSMessageType, NostrWSEvent } from 'nostr-websocket-utils/types/nostr';
105
+ import { createNostrServer } from '@humanjavaenterprises/nostr-websocket-utils';
46
106
 
47
- // Create Nostr WebSocket server
48
- const server = createWSServer({
49
- port: 8080,
50
- heartbeatInterval: 30000, // Optional: 30 seconds
107
+ const server = await createNostrServer(8080, {
108
+ logger: console,
109
+ heartbeatInterval: 30000,
51
110
  handlers: {
52
- // Required: Handle incoming messages
53
- message: async (socket, message) => {
54
- switch (message[0]) {
55
- case NostrWSMessageType.EVENT:
56
- const event = message[1] as NostrWSEvent;
57
- // Handle Nostr event
58
- break;
59
- case NostrWSMessageType.REQ:
60
- const [_type, subscriptionId, filter] = message;
61
- // Handle subscription request
62
- break;
63
- }
64
- },
65
- // Optional: Handle errors
66
- error: (socket, error) => {
67
- console.error('WebSocket error:', error);
68
- },
69
- // Optional: Handle client disconnection
70
- close: (socket) => {
71
- console.info('Client disconnected');
111
+ message: async (ws, msg) => {
112
+ console.log('Received message:', msg);
113
+ // Handle the message
72
114
  }
73
115
  }
74
116
  });
75
-
76
- // Start listening
77
- server.listen();
78
117
  ```
79
118
 
80
- ### Types
119
+ ## Dependencies
120
+
121
+ This package relies on:
122
+ - [nostr-crypto-utils](https://github.com/HumanjavaEnterprises/nostr-crypto-utils) - For all cryptographic operations
123
+ - [ws](https://github.com/websockets/ws) - For WebSocket functionality
124
+ - [pino](https://github.com/pinojs/pino) - For logging
125
+ - [uuid](https://github.com/uuidjs/uuid) - For unique identifiers
126
+
127
+ ## Documentation
128
+
129
+ Comprehensive API documentation is available in our [documentation site](https://humanjavaenterprises.github.io/nostr-websocket-utils/). Here's what you'll find:
130
+
131
+ ### Core Components
132
+ - [NostrWSClient](docs/classes/NostrWSClient.md) - WebSocket client implementation
133
+ - [NostrWSServer](docs/classes/NostrWSServer.md) - WebSocket server implementation
134
+ - [NostrServer](docs/classes/NostrServer.md) - High-level Nostr server
135
+
136
+ ### Types and Interfaces
137
+ - [NostrWSMessage](docs/interfaces/NostrWSMessage.md) - Message structure
138
+ - [NostrWSOptions](docs/interfaces/NostrWSOptions.md) - Configuration options
139
+ - [NostrWSSubscription](docs/interfaces/NostrWSSubscription.md) - Subscription interface
140
+ - [ExtendedWebSocket](docs/interfaces/ExtendedWebSocket.md) - Enhanced WebSocket interface
141
+
142
+ ### Utility Functions
143
+ - [createServer](docs/functions/createServer.md) - Server creation helper
144
+ - [getLogger](docs/functions/getLogger.md) - Logging utility
145
+
146
+ ### Type Definitions
147
+ - [MessageType](docs/enumerations/NostrWSMessageType.md) - Message type enumeration
148
+ - [Global Types](docs/globals.md) - Global type definitions
149
+
150
+ ## Examples
151
+
152
+ ### Subscribe to a Channel
81
153
 
82
154
  ```typescript
83
- // Nostr Event Type
84
- interface NostrWSEvent {
85
- id: string;
86
- pubkey: string;
87
- created_at: number;
88
- kind: number;
89
- tags: string[][];
90
- content: string;
91
- sig: string;
92
- }
93
-
94
- // Nostr Filter Type
95
- interface NostrWSFilter {
96
- ids?: string[];
97
- authors?: string[];
98
- kinds?: number[];
99
- '#e'?: string[];
100
- '#p'?: string[];
101
- since?: number;
102
- until?: number;
103
- limit?: number;
104
- }
105
-
106
- // Message Types
107
- enum NostrWSMessageType {
108
- EVENT = 'EVENT',
109
- REQ = 'REQ',
110
- CLOSE = 'CLOSE',
111
- NOTICE = 'NOTICE',
112
- AUTH = 'AUTH',
113
- EOSE = 'EOSE'
114
- }
155
+ client.subscribe('my-channel', {
156
+ filter: {
157
+ authors: ['pubkey1', 'pubkey2'],
158
+ kinds: [1]
159
+ }
160
+ });
115
161
  ```
116
162
 
117
- ## Advanced Configuration
118
-
119
- ### Server Options
163
+ ### Broadcast a Message
120
164
 
121
165
  ```typescript
122
- interface NostrWSServerOptions {
123
- port: number;
124
- heartbeatInterval?: number;
125
- maxPayloadSize?: number;
126
- cors?: {
127
- origin?: string | string[];
128
- methods?: string[];
129
- };
130
- handlers: {
131
- message: MessageHandler;
132
- error?: ErrorHandler;
133
- close?: CloseHandler;
134
- };
135
- }
166
+ server.broadcast({
167
+ type: 'event',
168
+ data: {
169
+ content: 'Hello everyone!',
170
+ kind: 1
171
+ }
172
+ });
136
173
  ```
137
174
 
138
175
  ## Contributing
139
176
 
140
- Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
177
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
141
178
 
142
179
  ## License
143
180
 
144
181
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
182
+
183
+ ## Related Projects
184
+
185
+ - [nostr-protocol](https://github.com/nostr-protocol/nostr)
186
+
187
+ ## Support
188
+
189
+ If you have any questions or need help, please:
190
+
191
+ 1. Check the [documentation](https://humanjavaenterprises.github.io/nostr-websocket-utils/)
192
+ 2. Open an [issue](https://github.com/HumanjavaEnterprises/nostr-websocket-utils/issues)
@@ -0,0 +1,35 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ import { EventEmitter } from 'events';
5
+ export declare class ExtendedWsMock extends EventEmitter {
6
+ readonly CONNECTING: 0;
7
+ readonly OPEN: 1;
8
+ readonly CLOSING: 2;
9
+ readonly CLOSED: 3;
10
+ readyState: 0 | 1 | 2 | 3;
11
+ protocol: string;
12
+ url: string;
13
+ bufferedAmount: number;
14
+ extensions: string;
15
+ binaryType: 'nodebuffer' | 'arraybuffer' | 'fragments';
16
+ isPaused: boolean;
17
+ onopen: ((event: any) => void) | null;
18
+ onclose: ((event: any) => void) | null;
19
+ onerror: ((event: any) => void) | null;
20
+ onmessage: ((event: any) => void) | null;
21
+ constructor();
22
+ private bindMethods;
23
+ private createWsEvent;
24
+ addEventListener(type: string, listener: (event: any) => void): void;
25
+ removeEventListener(type: string, listener: (event: any) => void): void;
26
+ send: import("@vitest/spy").Mock<[data: any], this>;
27
+ ping: import("@vitest/spy").Mock<[data?: Buffer | Uint8Array | undefined], this>;
28
+ pong: import("@vitest/spy").Mock<[data?: Buffer | Uint8Array | undefined], this>;
29
+ close: import("@vitest/spy").Mock<[code?: number | undefined, reason?: string | undefined], this>;
30
+ terminate: import("@vitest/spy").Mock<[], this>;
31
+ pause(): this;
32
+ resume(): this;
33
+ setMaxListeners(n: number): this;
34
+ }
35
+ export declare const mockWebSocket: ExtendedWsMock;
@@ -0,0 +1,156 @@
1
+ import { vi } from 'vitest';
2
+ import { EventEmitter } from 'events';
3
+ export class ExtendedWsMock extends EventEmitter {
4
+ constructor() {
5
+ super();
6
+ // WebSocket state constants
7
+ this.CONNECTING = 0;
8
+ this.OPEN = 1;
9
+ this.CLOSING = 2;
10
+ this.CLOSED = 3;
11
+ // Required WebSocket properties
12
+ this.readyState = 1;
13
+ this.protocol = '';
14
+ this.url = 'ws://test.com';
15
+ this.bufferedAmount = 0;
16
+ this.extensions = '';
17
+ this.binaryType = 'nodebuffer';
18
+ this.isPaused = false;
19
+ // Event handlers
20
+ this.onopen = null;
21
+ this.onclose = null;
22
+ this.onerror = null;
23
+ this.onmessage = null;
24
+ this.send = vi.fn((data) => {
25
+ if (this.isPaused)
26
+ return this;
27
+ const isBinary = !(typeof data === 'string');
28
+ const event = this.createWsEvent('message', {
29
+ data: data
30
+ });
31
+ this.emit('message', data, isBinary);
32
+ this.onmessage?.apply(this, [event]);
33
+ return this;
34
+ });
35
+ this.ping = vi.fn((data) => {
36
+ if (!this.isPaused) {
37
+ this.emit('ping', data);
38
+ }
39
+ return this;
40
+ });
41
+ this.pong = vi.fn((data) => {
42
+ if (!this.isPaused) {
43
+ this.emit('pong', data);
44
+ }
45
+ return this;
46
+ });
47
+ this.close = vi.fn((code, reason) => {
48
+ this.readyState = this.CLOSED;
49
+ const event = this.createWsEvent('close', {
50
+ code,
51
+ reason,
52
+ wasClean: true
53
+ });
54
+ this.emit('close', code, Buffer.from(reason || ''));
55
+ this.onclose?.apply(this, [event]);
56
+ return this;
57
+ });
58
+ this.terminate = vi.fn(() => {
59
+ this.readyState = this.CLOSED;
60
+ const event = this.createWsEvent('close', {
61
+ code: 1006,
62
+ reason: 'Connection terminated',
63
+ wasClean: false
64
+ });
65
+ this.emit('close', 1006, Buffer.from('Connection terminated'));
66
+ this.onclose?.apply(this, [event]);
67
+ return this;
68
+ });
69
+ this.bindMethods();
70
+ }
71
+ bindMethods() {
72
+ // Bind all methods that need 'this' context
73
+ this.send = this.send.bind(this);
74
+ this.ping = this.ping.bind(this);
75
+ this.pong = this.pong.bind(this);
76
+ this.close = this.close.bind(this);
77
+ this.terminate = this.terminate.bind(this);
78
+ this.pause = this.pause.bind(this);
79
+ this.resume = this.resume.bind(this);
80
+ }
81
+ createWsEvent(type, data) {
82
+ const event = {
83
+ type,
84
+ target: this,
85
+ currentTarget: this,
86
+ ...data
87
+ };
88
+ return event;
89
+ }
90
+ addEventListener(type, listener) {
91
+ const boundListener = ((event) => {
92
+ listener.apply(this, [event]);
93
+ });
94
+ this.on(type, boundListener);
95
+ }
96
+ removeEventListener(type, listener) {
97
+ this.removeListener(type, listener);
98
+ }
99
+ pause() {
100
+ this.isPaused = true;
101
+ return this;
102
+ }
103
+ resume() {
104
+ this.isPaused = false;
105
+ return this;
106
+ }
107
+ // Additional required methods
108
+ setMaxListeners(n) {
109
+ super.setMaxListeners(n);
110
+ return this;
111
+ }
112
+ }
113
+ // Create mock event classes for Node.js environment
114
+ class MockEvent {
115
+ constructor(type, target) {
116
+ this.type = type;
117
+ this.target = target || mockWebSocket;
118
+ this.currentTarget = this.target;
119
+ }
120
+ }
121
+ class MockMessageEvent extends MockEvent {
122
+ constructor(type, init) {
123
+ super(type, init?.target);
124
+ this.data = init?.data ?? '';
125
+ this.isBinary = init?.isBinary ?? false;
126
+ }
127
+ }
128
+ class MockCloseEvent extends MockEvent {
129
+ constructor(type, init) {
130
+ super(type, init?.target);
131
+ this.code = init?.code ?? 1000;
132
+ this.reason = init?.reason ?? '';
133
+ this.wasClean = init?.wasClean ?? true;
134
+ }
135
+ }
136
+ class MockErrorEvent extends MockEvent {
137
+ constructor(type, init) {
138
+ super(type, init?.target);
139
+ this.error = init?.error ?? new Error('WebSocket Error');
140
+ this.message = init?.message ?? 'WebSocket Error';
141
+ }
142
+ }
143
+ if (typeof Event === 'undefined') {
144
+ global.Event = MockEvent;
145
+ }
146
+ if (typeof MessageEvent === 'undefined') {
147
+ global.MessageEvent = MockMessageEvent;
148
+ }
149
+ if (typeof CloseEvent === 'undefined') {
150
+ global.CloseEvent = MockCloseEvent;
151
+ }
152
+ if (typeof ErrorEvent === 'undefined') {
153
+ global.ErrorEvent = MockErrorEvent;
154
+ }
155
+ // Export a singleton instance
156
+ export const mockWebSocket = new ExtendedWsMock();
@@ -0,0 +1,9 @@
1
+ type LoggerFunction = (message: string, ...args: unknown[]) => void;
2
+ interface MockLogger {
3
+ debug: LoggerFunction;
4
+ info: LoggerFunction;
5
+ warn: LoggerFunction;
6
+ error: LoggerFunction;
7
+ }
8
+ export declare const getLogger: (_name: string) => MockLogger;
9
+ export {};
@@ -0,0 +1,6 @@
1
+ export const getLogger = (_name) => ({
2
+ debug: () => { },
3
+ info: () => { },
4
+ warn: () => { },
5
+ error: () => { },
6
+ });
@@ -0,0 +1,41 @@
1
+ import type { Logger, ChildLoggerOptions, Bindings } from 'pino';
2
+ export declare class MockPinoLogger implements Partial<Logger> {
3
+ level: string;
4
+ levelVal: number;
5
+ version: string;
6
+ LOG_VERSION: number;
7
+ useLevelLabels: boolean;
8
+ useOnlyCustomLevels: boolean;
9
+ customLevels: {};
10
+ debug: import("@vitest/spy").Mock<any, any>;
11
+ info: import("@vitest/spy").Mock<any, any>;
12
+ warn: import("@vitest/spy").Mock<any, any>;
13
+ error: import("@vitest/spy").Mock<any, any>;
14
+ fatal: import("@vitest/spy").Mock<any, any>;
15
+ trace: import("@vitest/spy").Mock<any, any>;
16
+ silent: import("@vitest/spy").Mock<any, any>;
17
+ levels: {
18
+ values: {
19
+ fatal: number;
20
+ error: number;
21
+ warn: number;
22
+ info: number;
23
+ debug: number;
24
+ trace: number;
25
+ };
26
+ labels: {
27
+ 10: string;
28
+ 20: string;
29
+ 30: string;
30
+ 40: string;
31
+ 50: string;
32
+ 60: string;
33
+ };
34
+ };
35
+ bindings: () => {};
36
+ flush: () => Promise<void>;
37
+ isLevelEnabled: () => boolean;
38
+ child<ChildCustomLevels extends string = never>(_bindings: Bindings, _options?: ChildLoggerOptions<ChildCustomLevels>): Logger<ChildCustomLevels>;
39
+ static create(): Logger;
40
+ }
41
+ export declare const createMockLogger: () => Logger;
@@ -0,0 +1,47 @@
1
+ import { vi } from 'vitest';
2
+ export class MockPinoLogger {
3
+ constructor() {
4
+ this.level = 'debug';
5
+ this.levelVal = 20;
6
+ this.version = '8.0.0';
7
+ this.LOG_VERSION = 1;
8
+ this.useLevelLabels = true;
9
+ this.useOnlyCustomLevels = false;
10
+ this.customLevels = {};
11
+ this.debug = vi.fn();
12
+ this.info = vi.fn();
13
+ this.warn = vi.fn();
14
+ this.error = vi.fn();
15
+ this.fatal = vi.fn();
16
+ this.trace = vi.fn();
17
+ this.silent = vi.fn();
18
+ this.levels = {
19
+ values: {
20
+ fatal: 60,
21
+ error: 50,
22
+ warn: 40,
23
+ info: 30,
24
+ debug: 20,
25
+ trace: 10
26
+ },
27
+ labels: {
28
+ 10: 'trace',
29
+ 20: 'debug',
30
+ 30: 'info',
31
+ 40: 'warn',
32
+ 50: 'error',
33
+ 60: 'fatal'
34
+ }
35
+ };
36
+ this.bindings = () => ({});
37
+ this.flush = () => Promise.resolve();
38
+ this.isLevelEnabled = () => true;
39
+ }
40
+ child(_bindings, _options) {
41
+ return new MockPinoLogger();
42
+ }
43
+ static create() {
44
+ return new MockPinoLogger();
45
+ }
46
+ }
47
+ export const createMockLogger = () => MockPinoLogger.create();
@@ -0,0 +1,31 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ /// <reference types="node" />
6
+ import { EventEmitter } from 'events';
7
+ import type { NostrWSMessage } from '../types/messages';
8
+ import type { NostrWSSocket } from '../types/socket';
9
+ import type { IncomingMessage } from 'http';
10
+ import type { Socket } from 'net';
11
+ import type { WebSocket } from 'ws';
12
+ interface MockServerOptions {
13
+ port?: number;
14
+ host?: string;
15
+ [key: string]: unknown;
16
+ }
17
+ export declare class MockServer extends EventEmitter {
18
+ clients: Set<NostrWSSocket>;
19
+ options: MockServerOptions;
20
+ path: string;
21
+ address: string;
22
+ constructor(options?: MockServerOptions);
23
+ listen(port: number, cb?: () => void): void;
24
+ handleConnection: import("@vitest/spy").Mock<[socket: NostrWSSocket], void>;
25
+ handleMessage: import("@vitest/spy").Mock<[socket: NostrWSSocket, message: NostrWSMessage], void>;
26
+ handleClose: import("@vitest/spy").Mock<[socket: NostrWSSocket], void>;
27
+ broadcast: import("@vitest/spy").Mock<[message: NostrWSMessage], void>;
28
+ handleUpgrade: import("@vitest/spy").Mock<[request: IncomingMessage, socket: Socket, head: Buffer, callback: (ws: WebSocket) => void], void>;
29
+ shouldHandle: import("@vitest/spy").Mock<[_request: IncomingMessage], boolean>;
30
+ }
31
+ export {};
@@ -0,0 +1,39 @@
1
+ import { vi } from 'vitest';
2
+ import { EventEmitter } from 'events';
3
+ import { ExtendedWsMock } from './extendedWsMock';
4
+ export class MockServer extends EventEmitter {
5
+ constructor(options) {
6
+ super();
7
+ this.clients = new Set();
8
+ this.handleConnection = vi.fn((socket) => {
9
+ this.clients.add(socket);
10
+ this.emit('connection', socket);
11
+ });
12
+ this.handleMessage = vi.fn((socket, message) => {
13
+ this.emit('message', socket, message);
14
+ });
15
+ this.handleClose = vi.fn((socket) => {
16
+ this.clients.delete(socket);
17
+ this.emit('close', socket);
18
+ });
19
+ this.broadcast = vi.fn((message) => {
20
+ this.clients.forEach(client => {
21
+ client.send(JSON.stringify(message));
22
+ });
23
+ });
24
+ this.handleUpgrade = vi.fn((request, socket, head, callback) => {
25
+ const ws = new ExtendedWsMock();
26
+ callback(ws);
27
+ });
28
+ this.shouldHandle = vi.fn((_request) => {
29
+ return true;
30
+ });
31
+ this.options = options || {};
32
+ this.path = '/';
33
+ this.address = 'localhost';
34
+ }
35
+ listen(port, cb) {
36
+ if (cb)
37
+ cb();
38
+ }
39
+ }