Skip to content

Commit e92c3b9

Browse files
committed
chore: upgrade to v0.3.1 - Switch to Vitest, remove nostr-tools dependency, fix type issues
1 parent 60c4f78 commit e92c3b9

33 files changed

+907
-965
lines changed

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
## [0.3.1] - 2024-12-30
6+
7+
### Changed
8+
- Switched testing framework from Jest to Vitest
9+
- Removed nostr-tools dependency
10+
- Updated pino logger to version 8.17.2
11+
- Fixed TypeScript type issues and linting errors
12+
- Improved type safety across the codebase
13+
14+
### Removed
15+
- Removed nostr-tools peer dependency
16+
- Removed Jest-related dependencies
17+
18+
## [0.3.0] - 2024-12-30
19+
20+
### Added
21+
- Comprehensive TypeScript type definitions
22+
- Enhanced WebSocket connection management
23+
- Improved message queue implementation
24+
- Better error handling and logging
25+
26+
### Changed
27+
- Updated to nostr-crypto-utils 0.4.2
28+
- Refactored core functionality for better type safety
29+
- Enhanced documentation

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ A TypeScript library for building Nostr protocol WebSocket clients and servers.
1111

1212
## Features
1313

14-
- 🚀 Full Nostr protocol support
14+
- 🚀 Full Nostr protocol support with nostr-crypto-utils integration
1515
- 🔒 Secure WebSocket connections
1616
- ♥️ Heartbeat mechanism for connection health
1717
- 🔄 Automatic reconnection handling
18-
- 📝 Comprehensive logging
18+
- 📝 Comprehensive logging with Pino v8
1919
- 🎯 Type-safe message handling
2020
- 📦 Easy to use API
21+
- 🧪 Vitest-powered test suite
2122

2223
## NIPs Support Status
2324

@@ -118,11 +119,11 @@ const server = await createNostrServer(8080, {
118119

119120
## Dependencies
120121

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
122+
This package uses:
123+
- nostr-crypto-utils (^0.4.2) for cryptographic operations
124+
- pino (^8.17.2) for logging
125+
- ws (^8.16.0) for WebSocket functionality
126+
- uuid (^9.0.0) for unique identifiers
126127

127128
## Documentation
128129

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nostr-websocket-utils",
3-
"version": "0.3.0",
3+
"version": "0.3.1",
44
"description": "Robust WebSocket utilities for Nostr applications with automatic reconnection, channel-based messaging, and type-safe handlers. Features heartbeat monitoring, message queueing, and comprehensive error handling.",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/__mocks__/extendedWsMock.ts

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
11
import { vi } from 'vitest';
22
import { EventEmitter } from 'events';
33

4+
// WebSocket event interfaces
5+
interface WebSocketEventBase {
6+
type: string;
7+
target: WebSocket;
8+
currentTarget: WebSocket;
9+
}
10+
11+
interface WebSocketMessageEvent extends WebSocketEventBase {
12+
data: string | Buffer;
13+
isBinary: boolean;
14+
}
15+
16+
interface WebSocketCloseEvent extends WebSocketEventBase {
17+
code: number;
18+
reason: string;
19+
wasClean: boolean;
20+
}
21+
22+
interface WebSocketErrorEvent extends WebSocketEventBase {
23+
error: Error;
24+
message: string;
25+
}
26+
427
export class ExtendedWsMock extends EventEmitter {
528
// WebSocket state constants
629
public readonly CONNECTING = 0 as const;
@@ -18,10 +41,10 @@ export class ExtendedWsMock extends EventEmitter {
1841
public isPaused = false;
1942

2043
// Event handlers
21-
onopen: ((event: any) => void) | null = null;
22-
onclose: ((event: any) => void) | null = null;
23-
onerror: ((event: any) => void) | null = null;
24-
onmessage: ((event: any) => void) | null = null;
44+
onopen: ((event: WebSocketEventBase) => void) | null = null;
45+
onclose: ((event: WebSocketCloseEvent) => void) | null = null;
46+
onerror: ((event: WebSocketErrorEvent) => void) | null = null;
47+
onmessage: ((event: WebSocketMessageEvent) => void) | null = null;
2548

2649
constructor() {
2750
super();
@@ -39,36 +62,36 @@ export class ExtendedWsMock extends EventEmitter {
3962
this.resume = this.resume.bind(this);
4063
}
4164

42-
private createWsEvent(type: string, data: any): any {
43-
const event = {
65+
private createWsEvent<T extends WebSocketEventBase>(type: string, data: Partial<T>): T {
66+
return {
4467
type,
45-
target: this,
46-
currentTarget: this,
68+
target: this as unknown as WebSocket,
69+
currentTarget: this as unknown as WebSocket,
4770
...data
48-
};
49-
return event;
71+
} as T;
5072
}
5173

52-
addEventListener(type: string, listener: (event: any) => void): void {
53-
const boundListener = ((event: any) => {
74+
addEventListener(type: string, listener: (event: WebSocketEventBase) => void): void {
75+
const boundListener = ((event: WebSocketEventBase) => {
5476
listener.apply(this, [event]);
5577
});
5678
this.on(type, boundListener);
5779
}
5880

59-
removeEventListener(type: string, listener: (event: any) => void): void {
81+
removeEventListener(type: string, listener: (event: WebSocketEventBase) => void): void {
6082
this.removeListener(type, listener);
6183
}
6284

63-
public send = vi.fn((data: any): this => {
85+
public send = vi.fn((data: string | Buffer): this => {
6486
if (this.isPaused) return this;
6587

6688
const isBinary = !(typeof data === 'string');
67-
const event = this.createWsEvent('message', {
68-
data: data
89+
const event = this.createWsEvent<WebSocketMessageEvent>('message', {
90+
data: data,
91+
isBinary: isBinary
6992
});
7093

71-
this.emit('message', data, isBinary);
94+
this.emit('message', event);
7295
this.onmessage?.apply(this, [event]);
7396

7497
return this;
@@ -90,27 +113,27 @@ export class ExtendedWsMock extends EventEmitter {
90113

91114
public close = vi.fn((code?: number, reason?: string): this => {
92115
this.readyState = this.CLOSED;
93-
const event = this.createWsEvent('close', {
116+
const event = this.createWsEvent<WebSocketCloseEvent>('close', {
94117
code,
95118
reason,
96119
wasClean: true
97120
});
98121

99-
this.emit('close', code, Buffer.from(reason || ''));
122+
this.emit('close', event);
100123
this.onclose?.apply(this, [event]);
101124

102125
return this;
103126
});
104127

105128
public terminate = vi.fn((): this => {
106129
this.readyState = this.CLOSED;
107-
const event = this.createWsEvent('close', {
130+
const event = this.createWsEvent<WebSocketCloseEvent>('close', {
108131
code: 1006,
109132
reason: 'Connection terminated',
110133
wasClean: false
111134
});
112135

113-
this.emit('close', 1006, Buffer.from('Connection terminated'));
136+
this.emit('close', event);
114137
this.onclose?.apply(this, [event]);
115138

116139
return this;
@@ -134,64 +157,64 @@ export class ExtendedWsMock extends EventEmitter {
134157
}
135158

136159
// Create mock event classes for Node.js environment
137-
class MockEvent {
160+
class MockEvent implements WebSocketEventBase {
138161
readonly type: string;
139-
readonly target: any;
140-
readonly currentTarget: any;
162+
readonly target: WebSocket;
163+
readonly currentTarget: WebSocket;
141164

142-
constructor(type: string, target?: any) {
165+
constructor(type: string, target?: WebSocket) {
143166
this.type = type;
144-
this.target = target || (mockWebSocket as any);
167+
this.target = target || (mockWebSocket as unknown as WebSocket);
145168
this.currentTarget = this.target;
146169
}
147170
}
148171

149-
class MockMessageEvent extends MockEvent {
150-
readonly data: any;
172+
class MockMessageEvent extends MockEvent implements WebSocketMessageEvent {
173+
readonly data: string | Buffer;
151174
readonly isBinary: boolean;
152175

153-
constructor(type: string, init?: { data?: any; isBinary?: boolean; target?: any }) {
176+
constructor(type: string, init?: { data?: string | Buffer; isBinary?: boolean; target?: WebSocket }) {
154177
super(type, init?.target);
155178
this.data = init?.data ?? '';
156179
this.isBinary = init?.isBinary ?? false;
157180
}
158181
}
159182

160-
class MockCloseEvent extends MockEvent {
183+
class MockCloseEvent extends MockEvent implements WebSocketCloseEvent {
161184
readonly code: number;
162185
readonly reason: string;
163186
readonly wasClean: boolean;
164187

165-
constructor(type: string, init?: { code?: number; reason?: string; wasClean?: boolean; target?: any }) {
188+
constructor(type: string, init?: { code?: number; reason?: string; wasClean?: boolean; target?: WebSocket }) {
166189
super(type, init?.target);
167190
this.code = init?.code ?? 1000;
168191
this.reason = init?.reason ?? '';
169192
this.wasClean = init?.wasClean ?? true;
170193
}
171194
}
172195

173-
class MockErrorEvent extends MockEvent {
196+
class MockErrorEvent extends MockEvent implements WebSocketErrorEvent {
174197
readonly error: Error;
175198
readonly message: string;
176199

177-
constructor(type: string, init?: { error?: Error; message?: string; target?: any }) {
200+
constructor(type: string, init?: { error?: Error; message?: string; target?: WebSocket }) {
178201
super(type, init?.target);
179202
this.error = init?.error ?? new Error('WebSocket Error');
180203
this.message = init?.message ?? 'WebSocket Error';
181204
}
182205
}
183206

184207
if (typeof Event === 'undefined') {
185-
(global as { Event?: typeof MockEvent }).Event = MockEvent;
208+
(global as any).Event = MockEvent;
186209
}
187210
if (typeof MessageEvent === 'undefined') {
188-
(global as unknown as { MessageEvent: typeof MockMessageEvent }).MessageEvent = MockMessageEvent;
211+
(global as any).MessageEvent = MockMessageEvent;
189212
}
190213
if (typeof CloseEvent === 'undefined') {
191-
(global as { CloseEvent?: typeof MockCloseEvent }).CloseEvent = MockCloseEvent;
214+
(global as any).CloseEvent = MockCloseEvent;
192215
}
193216
if (typeof ErrorEvent === 'undefined') {
194-
(global as { ErrorEvent?: typeof MockErrorEvent }).ErrorEvent = MockErrorEvent;
217+
(global as any).ErrorEvent = MockErrorEvent;
195218
}
196219

197220
// Export a singleton instance

src/__tests__/client.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ describe('NostrWSClient', () => {
7777
const messageHandler = vi.fn();
7878
client.on('message', messageHandler);
7979

80-
const testMessage: NostrWSMessage = { type: 'EVENT', content: { id: 'test' } };
80+
const testMessage: NostrWSMessage = ['EVENT', { id: 'test' }];
8181
client.send(testMessage);
8282

8383
await vi.waitFor(() => expect(messageHandler).toHaveBeenCalledWith(testMessage));

src/__tests__/nostr-types.test.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { describe, it, expect } from 'vitest';
2-
import { NostrWSEvent, NostrWSFilter, NostrWSMessage } from '../types/messages';
2+
import { NostrEvent, NostrWSFilter, NostrWSMessage } from '../types/messages';
33
import { MESSAGE_TYPES } from '../types/messages';
44

55
describe('Nostr WebSocket Types', () => {
6-
describe('NostrWSEvent', () => {
6+
describe('NostrEvent', () => {
77
it('should validate a valid event', () => {
8-
const event: NostrWSEvent = {
8+
const event: NostrEvent = {
99
id: 'test-id',
1010
pubkey: 'test-pubkey',
1111
created_at: Date.now(),
@@ -30,8 +30,10 @@ describe('Nostr WebSocket Types', () => {
3030
ids: ['test-id-1', 'test-id-2'],
3131
authors: ['test-pubkey-1', 'test-pubkey-2'],
3232
kinds: [1, 2, 3],
33-
'#e': ['test-event-1', 'test-event-2'],
34-
'#p': ['test-pubkey-1', 'test-pubkey-2'],
33+
tags: {
34+
'e': ['test-event-1', 'test-event-2'],
35+
'p': ['test-pubkey-1', 'test-pubkey-2']
36+
},
3537
since: now - 3600, // 1 hour ago
3638
until: now,
3739
limit: 100,
@@ -40,8 +42,8 @@ describe('Nostr WebSocket Types', () => {
4042
expect(filter.ids).toBeInstanceOf(Array);
4143
expect(filter.authors).toBeInstanceOf(Array);
4244
expect(filter.kinds).toBeInstanceOf(Array);
43-
expect(filter['#e']).toBeInstanceOf(Array);
44-
expect(filter['#p']).toBeInstanceOf(Array);
45+
expect(filter.tags?.e).toBeInstanceOf(Array);
46+
expect(filter.tags?.p).toBeInstanceOf(Array);
4547
expect(typeof filter.since).toBe('number');
4648
expect(typeof filter.until).toBe('number');
4749
expect(typeof filter.limit).toBe('number');
@@ -50,18 +52,17 @@ describe('Nostr WebSocket Types', () => {
5052

5153
describe('NostrWSMessage', () => {
5254
it('should validate a valid message', () => {
53-
const message: NostrWSMessage = {
54-
type: MESSAGE_TYPES.EVENT,
55-
content: {
56-
id: 'test-id',
57-
pubkey: 'test-pubkey',
58-
created_at: Date.now(),
59-
kind: 1,
60-
tags: [],
61-
content: 'test content'
62-
}
55+
const event: NostrEvent = {
56+
id: 'test-id',
57+
pubkey: 'test-pubkey',
58+
created_at: Date.now(),
59+
kind: 1,
60+
tags: [],
61+
content: 'test content'
6362
};
64-
expect(message).toBeDefined();
63+
const message: NostrWSMessage = [MESSAGE_TYPES.EVENT, event];
64+
expect(message[0]).toBe(MESSAGE_TYPES.EVENT);
65+
expect(message[1]).toEqual(event);
6566
});
6667
});
6768

0 commit comments

Comments
 (0)