@pioneer-platform/pioneer-subscriptions 1.0.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.
- package/.turbo/turbo-build.log +2 -0
- package/IMPLEMENTATION.md +275 -0
- package/README.md +233 -0
- package/__tests__/test-module.js +83 -0
- package/build.sh +6 -0
- package/lib/index.d.ts +122 -0
- package/lib/index.js +333 -0
- package/package.json +28 -0
- package/src/index.ts +422 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Blockbook Subscription Implementation
|
|
2
|
+
|
|
3
|
+
## What We Built
|
|
4
|
+
|
|
5
|
+
A clean, focused, **session-based subscription system** for real-time blockchain payment notifications.
|
|
6
|
+
|
|
7
|
+
### Clean Architecture ✅
|
|
8
|
+
|
|
9
|
+
**Before**: Bloated 1101-line WebSocketHandler doing everything
|
|
10
|
+
**After**: Modular design with separation of concerns
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
modules/pioneer/pioneer-subscriptions/
|
|
14
|
+
├── package.json # Clean dependencies
|
|
15
|
+
├── tsconfig.json # TypeScript config
|
|
16
|
+
├── build.sh # Build script
|
|
17
|
+
├── README.md # Full documentation
|
|
18
|
+
├── IMPLEMENTATION.md # This file
|
|
19
|
+
├── src/
|
|
20
|
+
│ └── index.ts # ~450 lines, focused, clean
|
|
21
|
+
└── __tests__/
|
|
22
|
+
└── test-module.js # Complete test suite
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## How It Works
|
|
26
|
+
|
|
27
|
+
### 1. Session-Based Subscriptions
|
|
28
|
+
|
|
29
|
+
User connects → Sends addresses → We subscribe to blockbook → On disconnect, we cleanup
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// User connects via WebSocket
|
|
33
|
+
socket.on('subscribe_addresses', async (data) => {
|
|
34
|
+
await subscriptionManager.subscribe({
|
|
35
|
+
sessionId: socket.id,
|
|
36
|
+
username: 'user123',
|
|
37
|
+
coin: 'BTC',
|
|
38
|
+
addresses: ['bc1q...', '3...']
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Payment happens on blockchain
|
|
43
|
+
// → Blockbook notifies us
|
|
44
|
+
// → We push to user's socket
|
|
45
|
+
subscriptionManager.onPayment((notification) => {
|
|
46
|
+
io.to(notification.sessionId).emit('payment', notification);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// User disconnects
|
|
50
|
+
socket.on('disconnect', async () => {
|
|
51
|
+
await subscriptionManager.unsubscribe(socket.id);
|
|
52
|
+
// All addresses automatically unsubscribed
|
|
53
|
+
// No memory leaks!
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. Architecture
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
┌─────────────┐
|
|
61
|
+
│ Client │ WebSocket connection
|
|
62
|
+
└──────┬──────┘
|
|
63
|
+
│
|
|
64
|
+
├─ connect
|
|
65
|
+
├─ subscribe_addresses { coin, addresses[] }
|
|
66
|
+
├─ disconnect
|
|
67
|
+
│
|
|
68
|
+
▼
|
|
69
|
+
┌──────────────────────┐
|
|
70
|
+
│ WebSocketHandler │ Lean & focused
|
|
71
|
+
│ (pioneer-server) │ - Handles connections
|
|
72
|
+
└──────┬───────────────┘ - Routes messages
|
|
73
|
+
│ - Auth & state
|
|
74
|
+
│
|
|
75
|
+
│ Uses
|
|
76
|
+
▼
|
|
77
|
+
┌───────────────────────┐
|
|
78
|
+
│ SubscriptionManager │ Clean module
|
|
79
|
+
│ (pioneer-subscriptions)│ - Subscribe/unsubscribe
|
|
80
|
+
│ │ - Session management
|
|
81
|
+
│ - Sessions Map │ - Payment callbacks
|
|
82
|
+
│ - Address → Sessions │ - Auto cleanup
|
|
83
|
+
│ - Callbacks │
|
|
84
|
+
└──────┬────────────────┘
|
|
85
|
+
│
|
|
86
|
+
│ Subscribes to
|
|
87
|
+
▼
|
|
88
|
+
┌───────────────────────┐
|
|
89
|
+
│ Blockbook WebSocket │ Per-chain sockets
|
|
90
|
+
│ (BTC, LTC, DOGE...) │ - Address subscriptions
|
|
91
|
+
└──────┬────────────────┘ - TX notifications
|
|
92
|
+
│
|
|
93
|
+
│ Monitors
|
|
94
|
+
▼
|
|
95
|
+
┌───────────────────────┐
|
|
96
|
+
│ Blockchain Nodes │ Real blockchain
|
|
97
|
+
└───────────────────────┘
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Next Steps
|
|
101
|
+
|
|
102
|
+
### Test the Module
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
cd /Users/highlander/WebstormProjects/keepkey-stack/projects/pioneer/modules/pioneer/pioneer-subscriptions
|
|
106
|
+
|
|
107
|
+
# Install dependencies
|
|
108
|
+
pnpm install
|
|
109
|
+
|
|
110
|
+
# Build
|
|
111
|
+
pnpm run build
|
|
112
|
+
|
|
113
|
+
# Test
|
|
114
|
+
pnpm test
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Expected output:
|
|
118
|
+
```
|
|
119
|
+
🧪 Testing Pioneer Subscriptions Module
|
|
120
|
+
|
|
121
|
+
Test 1: Initializing Subscription Manager...
|
|
122
|
+
✅ Manager initialized
|
|
123
|
+
Available coins: BTC, LTC, DOGE, DASH, ...
|
|
124
|
+
|
|
125
|
+
Test 2: Registering payment callback...
|
|
126
|
+
✅ Callback registered
|
|
127
|
+
|
|
128
|
+
Test 3: Subscribing to Bitcoin addresses...
|
|
129
|
+
Subscribe result: { success: true, message: 'Subscribed to 2 addresses on BTC' }
|
|
130
|
+
|
|
131
|
+
Test 4: Getting subscription stats...
|
|
132
|
+
Stats: {
|
|
133
|
+
"totalSessions": 1,
|
|
134
|
+
"totalAddresses": 2,
|
|
135
|
+
...
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
✅ All tests passed!
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Integrate with Pioneer-Server
|
|
142
|
+
|
|
143
|
+
Once tests pass, integrate into pioneer-server:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// services/pioneer-server/src/app.ts
|
|
147
|
+
import { SubscriptionManager } from '@pioneer-platform/pioneer-subscriptions';
|
|
148
|
+
|
|
149
|
+
// Initialize
|
|
150
|
+
const subscriptionManager = new SubscriptionManager();
|
|
151
|
+
await subscriptionManager.init();
|
|
152
|
+
|
|
153
|
+
// Setup payment forwarding
|
|
154
|
+
subscriptionManager.onPayment((notification) => {
|
|
155
|
+
wsHandler.emitToSocket(notification.sessionId, 'payment', notification);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// In WebSocketHandler.handleConnection()
|
|
159
|
+
socket.on('subscribe_addresses', async (msg) => {
|
|
160
|
+
const username = this.state.usersBySocketId[socket.id];
|
|
161
|
+
if (!username) {
|
|
162
|
+
socket.emit('error', { error: 'Not authenticated' });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const result = await subscriptionManager.subscribe({
|
|
167
|
+
sessionId: socket.id,
|
|
168
|
+
username,
|
|
169
|
+
coin: msg.coin,
|
|
170
|
+
addresses: msg.addresses
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
socket.emit('subscribe_result', result);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// In WebSocketHandler.handleDisconnect()
|
|
177
|
+
await subscriptionManager.unsubscribe(socket.id);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Client Usage
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// Connect to pioneer-server
|
|
184
|
+
const socket = io('wss://pioneers.dev');
|
|
185
|
+
|
|
186
|
+
// Authenticate
|
|
187
|
+
socket.emit('authenticate', { username: 'user123', queryKey: 'key...' });
|
|
188
|
+
|
|
189
|
+
// Subscribe to addresses
|
|
190
|
+
socket.emit('subscribe_addresses', {
|
|
191
|
+
coin: 'BTC',
|
|
192
|
+
addresses: [
|
|
193
|
+
'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
|
|
194
|
+
'3J98t1WpEZ73CNmYviecrnyiWrnqRhWNLy'
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Listen for payments
|
|
199
|
+
socket.on('payment', (notification) => {
|
|
200
|
+
console.log('💰 Payment received!', notification);
|
|
201
|
+
// {
|
|
202
|
+
// coin: 'BTC',
|
|
203
|
+
// address: 'bc1q...',
|
|
204
|
+
// txid: 'abc123...',
|
|
205
|
+
// amount: '50000', // satoshis
|
|
206
|
+
// confirmations: 0,
|
|
207
|
+
// timestamp: 1234567890
|
|
208
|
+
// }
|
|
209
|
+
|
|
210
|
+
// Show notification to user
|
|
211
|
+
showToast(`Received ${notification.amount} sats!`);
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Benefits
|
|
216
|
+
|
|
217
|
+
### ✅ Clean Code
|
|
218
|
+
- **450 lines** vs 1101 lines
|
|
219
|
+
- Single responsibility
|
|
220
|
+
- Easy to test
|
|
221
|
+
- Easy to maintain
|
|
222
|
+
|
|
223
|
+
### ✅ Modular
|
|
224
|
+
- Separate package
|
|
225
|
+
- Reusable
|
|
226
|
+
- Versionable
|
|
227
|
+
- Independent deployment
|
|
228
|
+
|
|
229
|
+
### ✅ No Memory Leaks
|
|
230
|
+
- Automatic cleanup on disconnect
|
|
231
|
+
- Session-based lifecycle
|
|
232
|
+
- Proper unsubscribe from blockbook
|
|
233
|
+
|
|
234
|
+
### ✅ Observable
|
|
235
|
+
- Statistics API
|
|
236
|
+
- Track sessions, addresses, users
|
|
237
|
+
- Monitor subscription health
|
|
238
|
+
|
|
239
|
+
### ✅ Type-Safe
|
|
240
|
+
- Full TypeScript types
|
|
241
|
+
- Clear interfaces
|
|
242
|
+
- Great IDE support
|
|
243
|
+
|
|
244
|
+
## Testing Checklist
|
|
245
|
+
|
|
246
|
+
- [ ] Build module: `pnpm run build`
|
|
247
|
+
- [ ] Run tests: `pnpm test`
|
|
248
|
+
- [ ] Verify blockbook connection
|
|
249
|
+
- [ ] Subscribe to test addresses
|
|
250
|
+
- [ ] Trigger test payment (testnet)
|
|
251
|
+
- [ ] Verify notification received
|
|
252
|
+
- [ ] Test disconnect/cleanup
|
|
253
|
+
- [ ] Check memory usage
|
|
254
|
+
- [ ] Integrate with pioneer-server
|
|
255
|
+
- [ ] End-to-end test with real client
|
|
256
|
+
|
|
257
|
+
## Support
|
|
258
|
+
|
|
259
|
+
For issues or questions:
|
|
260
|
+
- Check logs with `@pioneer-platform/loggerdog`
|
|
261
|
+
- Review `getStats()` for subscription state
|
|
262
|
+
- Verify blockbook connectivity: `getAvailableCoins()`
|
|
263
|
+
- Test with testnet addresses first
|
|
264
|
+
|
|
265
|
+
## Future Enhancements
|
|
266
|
+
|
|
267
|
+
- [ ] Support for xpub subscriptions (derive & monitor all addresses)
|
|
268
|
+
- [ ] Batch subscription API
|
|
269
|
+
- [ ] Subscription persistence (Redis)
|
|
270
|
+
- [ ] Rate limiting
|
|
271
|
+
- [ ] Subscription filters (min amount, confirmations)
|
|
272
|
+
- [ ] Historical transaction notifications
|
|
273
|
+
- [ ] Multi-node failover
|
|
274
|
+
- [ ] Metrics & monitoring
|
|
275
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# @pioneer-platform/pioneer-subscriptions
|
|
2
|
+
|
|
3
|
+
Session-based blockchain address subscription manager for real-time payment notifications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔔 **Real-time notifications** - Receive instant alerts when addresses receive payments
|
|
8
|
+
- 🔄 **Session-based** - Subscriptions automatically tied to client connection lifecycle
|
|
9
|
+
- 🧹 **Auto-cleanup** - Subscriptions removed when clients disconnect
|
|
10
|
+
- ⛓️ **Multi-chain** - Support for all blockbook-enabled blockchains (BTC, LTC, DOGE, DASH, etc.)
|
|
11
|
+
- 🎯 **Event-driven** - Simple callback API for handling payment notifications
|
|
12
|
+
- 📊 **Statistics** - Track active subscriptions and sessions
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @pioneer-platform/pioneer-subscriptions
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Basic Setup
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { SubscriptionManager } from '@pioneer-platform/pioneer-subscriptions';
|
|
26
|
+
|
|
27
|
+
// Initialize
|
|
28
|
+
const manager = new SubscriptionManager();
|
|
29
|
+
await manager.init();
|
|
30
|
+
|
|
31
|
+
// Register callback for payment notifications
|
|
32
|
+
manager.onPayment((notification) => {
|
|
33
|
+
console.log('Payment received:', notification);
|
|
34
|
+
// {
|
|
35
|
+
// sessionId: 'socket-123',
|
|
36
|
+
// username: 'user1',
|
|
37
|
+
// coin: 'BTC',
|
|
38
|
+
// address: 'bc1q...',
|
|
39
|
+
// txid: 'abc123...',
|
|
40
|
+
// amount: '50000',
|
|
41
|
+
// confirmations: 0,
|
|
42
|
+
// timestamp: 1234567890
|
|
43
|
+
// }
|
|
44
|
+
|
|
45
|
+
// Push to client via WebSocket
|
|
46
|
+
io.to(notification.sessionId).emit('payment:notification', notification);
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Subscribe to Addresses
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// When client connects and sends addresses to monitor
|
|
54
|
+
const result = await manager.subscribe({
|
|
55
|
+
sessionId: socket.id,
|
|
56
|
+
username: 'user123',
|
|
57
|
+
coin: 'BTC',
|
|
58
|
+
addresses: [
|
|
59
|
+
'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
|
|
60
|
+
'3J98t1WpEZ73CNmYviecrnyiWrnqRhWNLy'
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log(result);
|
|
65
|
+
// { success: true, message: 'Subscribed to 2 addresses on BTC' }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Unsubscribe on Disconnect
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// When client disconnects
|
|
72
|
+
socket.on('disconnect', async () => {
|
|
73
|
+
await manager.unsubscribe(socket.id);
|
|
74
|
+
console.log('Session cleaned up');
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Get Statistics
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const stats = manager.getStats();
|
|
82
|
+
console.log(stats);
|
|
83
|
+
// {
|
|
84
|
+
// totalSessions: 5,
|
|
85
|
+
// totalAddresses: 12,
|
|
86
|
+
// sessionsByUsername: { 'user1': 2, 'user2': 3 },
|
|
87
|
+
// addressesByCoin: { 'BTC': 8, 'LTC': 4 },
|
|
88
|
+
// sessions: [...]
|
|
89
|
+
// }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## WebSocket Integration Example
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { SubscriptionManager } from '@pioneer-platform/pioneer-subscriptions';
|
|
96
|
+
import { Server } from 'socket.io';
|
|
97
|
+
|
|
98
|
+
const io = new Server(server);
|
|
99
|
+
const subscriptionManager = new SubscriptionManager();
|
|
100
|
+
await subscriptionManager.init();
|
|
101
|
+
|
|
102
|
+
// Setup payment notification forwarding
|
|
103
|
+
subscriptionManager.onPayment((notification) => {
|
|
104
|
+
// Send to specific session
|
|
105
|
+
io.to(notification.sessionId).emit('payment', notification);
|
|
106
|
+
|
|
107
|
+
// Also log for monitoring
|
|
108
|
+
console.log(`💰 Payment: ${notification.amount} ${notification.coin} to ${notification.address}`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Handle client connections
|
|
112
|
+
io.on('connection', (socket) => {
|
|
113
|
+
console.log('Client connected:', socket.id);
|
|
114
|
+
|
|
115
|
+
// Client sends addresses to monitor
|
|
116
|
+
socket.on('subscribe_addresses', async (data) => {
|
|
117
|
+
const { coin, addresses } = data;
|
|
118
|
+
const username = socket.data.username; // From auth
|
|
119
|
+
|
|
120
|
+
const result = await subscriptionManager.subscribe({
|
|
121
|
+
sessionId: socket.id,
|
|
122
|
+
username,
|
|
123
|
+
coin,
|
|
124
|
+
addresses
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
socket.emit('subscribe_result', result);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Cleanup on disconnect
|
|
131
|
+
socket.on('disconnect', async () => {
|
|
132
|
+
await subscriptionManager.unsubscribe(socket.id);
|
|
133
|
+
console.log('Client disconnected and unsubscribed:', socket.id);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## API
|
|
139
|
+
|
|
140
|
+
### `SubscriptionManager`
|
|
141
|
+
|
|
142
|
+
#### Methods
|
|
143
|
+
|
|
144
|
+
- **`init(): Promise<void>`** - Initialize the manager and connect to blockbook
|
|
145
|
+
- **`subscribe(request): Promise<{success, message}>`** - Subscribe a session to addresses
|
|
146
|
+
- **`unsubscribe(sessionId): Promise<void>`** - Unsubscribe a session and cleanup
|
|
147
|
+
- **`onPayment(callback): void`** - Register a payment notification callback
|
|
148
|
+
- **`offPayment(callback): void`** - Remove a payment callback
|
|
149
|
+
- **`getStats(): SubscriptionStats`** - Get subscription statistics
|
|
150
|
+
- **`getAvailableCoins(): string[]`** - Get list of supported coins
|
|
151
|
+
- **`isReady(): boolean`** - Check if manager is initialized
|
|
152
|
+
- **`shutdown(): Promise<void>`** - Cleanup and shutdown
|
|
153
|
+
|
|
154
|
+
#### Types
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
interface SubscriptionRequest {
|
|
158
|
+
sessionId: string; // Unique session/socket ID
|
|
159
|
+
username: string; // Username for tracking
|
|
160
|
+
coin: string; // Coin symbol (BTC, LTC, etc.)
|
|
161
|
+
addresses: string[]; // Array of addresses to monitor
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface PaymentNotification {
|
|
165
|
+
sessionId: string;
|
|
166
|
+
username: string;
|
|
167
|
+
coin: string;
|
|
168
|
+
address: string;
|
|
169
|
+
txid: string;
|
|
170
|
+
amount: string; // In satoshis/smallest unit
|
|
171
|
+
confirmations: number;
|
|
172
|
+
timestamp: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
interface SubscriptionStats {
|
|
176
|
+
totalSessions: number;
|
|
177
|
+
totalAddresses: number;
|
|
178
|
+
sessionsByUsername: Record<string, number>;
|
|
179
|
+
addressesByCoin: Record<string, number>;
|
|
180
|
+
sessions: SessionSubscription[];
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Architecture
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
┌─────────────┐
|
|
188
|
+
│ Client │
|
|
189
|
+
│ (Browser) │
|
|
190
|
+
└──────┬──────┘
|
|
191
|
+
│ WebSocket
|
|
192
|
+
│ subscribe_addresses
|
|
193
|
+
▼
|
|
194
|
+
┌─────────────────┐
|
|
195
|
+
│ WebSocket │
|
|
196
|
+
│ Server │
|
|
197
|
+
└────────┬────────┘
|
|
198
|
+
│
|
|
199
|
+
│ manager.subscribe()
|
|
200
|
+
▼
|
|
201
|
+
┌─────────────────────┐
|
|
202
|
+
│ SubscriptionManager │
|
|
203
|
+
│ │
|
|
204
|
+
│ - Sessions Map │
|
|
205
|
+
│ - Address Map │
|
|
206
|
+
│ - Callbacks │
|
|
207
|
+
└──────────┬──────────┘
|
|
208
|
+
│
|
|
209
|
+
│ subscribeAddresses()
|
|
210
|
+
▼
|
|
211
|
+
┌─────────────────────┐
|
|
212
|
+
│ Blockbook WS │
|
|
213
|
+
│ (per chain) │
|
|
214
|
+
└──────────┬──────────┘
|
|
215
|
+
│
|
|
216
|
+
│ TX notifications
|
|
217
|
+
▼
|
|
218
|
+
┌─────────────────────┐
|
|
219
|
+
│ Blockchain Node │
|
|
220
|
+
└─────────────────────┘
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Testing
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
pnpm run build
|
|
227
|
+
pnpm test
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT
|
|
233
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Pioneer Subscriptions Module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { SubscriptionManager } = require('../lib/index');
|
|
6
|
+
|
|
7
|
+
async function runTest() {
|
|
8
|
+
console.log('🧪 Testing Pioneer Subscriptions Module\n');
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
// Test 1: Initialize
|
|
12
|
+
console.log('Test 1: Initializing Subscription Manager...');
|
|
13
|
+
const manager = new SubscriptionManager();
|
|
14
|
+
await manager.init();
|
|
15
|
+
console.log('✅ Manager initialized');
|
|
16
|
+
console.log('Available coins:', manager.getAvailableCoins().join(', '));
|
|
17
|
+
console.log('');
|
|
18
|
+
|
|
19
|
+
// Test 2: Register payment callback
|
|
20
|
+
console.log('Test 2: Registering payment callback...');
|
|
21
|
+
manager.onPayment((notification) => {
|
|
22
|
+
console.log('💰 Payment notification received:', notification);
|
|
23
|
+
});
|
|
24
|
+
console.log('✅ Callback registered');
|
|
25
|
+
console.log('');
|
|
26
|
+
|
|
27
|
+
// Test 3: Subscribe to addresses
|
|
28
|
+
console.log('Test 3: Subscribing to Bitcoin addresses...');
|
|
29
|
+
const result = await manager.subscribe({
|
|
30
|
+
sessionId: 'test-session-1',
|
|
31
|
+
username: 'test-user',
|
|
32
|
+
coin: 'BTC',
|
|
33
|
+
addresses: [
|
|
34
|
+
'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', // Example BTC address
|
|
35
|
+
'1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' // Genesis block address
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
console.log('Subscribe result:', result);
|
|
39
|
+
console.log('');
|
|
40
|
+
|
|
41
|
+
// Test 4: Get stats
|
|
42
|
+
console.log('Test 4: Getting subscription stats...');
|
|
43
|
+
const stats = manager.getStats();
|
|
44
|
+
console.log('Stats:', JSON.stringify(stats, null, 2));
|
|
45
|
+
console.log('');
|
|
46
|
+
|
|
47
|
+
// Test 5: Subscribe another session
|
|
48
|
+
console.log('Test 5: Subscribing another session...');
|
|
49
|
+
await manager.subscribe({
|
|
50
|
+
sessionId: 'test-session-2',
|
|
51
|
+
username: 'test-user-2',
|
|
52
|
+
coin: 'BTC',
|
|
53
|
+
addresses: [
|
|
54
|
+
'3J98t1WpEZ73CNmYviecrnyiWrnqRhWNLy'
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
console.log('✅ Second session subscribed');
|
|
58
|
+
console.log('Updated stats:', JSON.stringify(manager.getStats(), null, 2));
|
|
59
|
+
console.log('');
|
|
60
|
+
|
|
61
|
+
// Test 6: Unsubscribe
|
|
62
|
+
console.log('Test 6: Unsubscribing first session...');
|
|
63
|
+
await manager.unsubscribe('test-session-1');
|
|
64
|
+
console.log('✅ Session unsubscribed');
|
|
65
|
+
console.log('Stats after unsubscribe:', JSON.stringify(manager.getStats(), null, 2));
|
|
66
|
+
console.log('');
|
|
67
|
+
|
|
68
|
+
// Test 7: Cleanup
|
|
69
|
+
console.log('Test 7: Shutting down...');
|
|
70
|
+
await manager.shutdown();
|
|
71
|
+
console.log('✅ Manager shut down');
|
|
72
|
+
console.log('');
|
|
73
|
+
|
|
74
|
+
console.log('✅ All tests passed!');
|
|
75
|
+
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('❌ Test failed:', error);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
runTest();
|
|
83
|
+
|