@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.
@@ -0,0 +1,2 @@
1
+
2
+ $ tsc -p .
@@ -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
+
package/build.sh ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ echo "Building @pioneer-platform/pioneer-subscriptions..."
4
+ pnpm run build
5
+ echo "Build complete!"
6
+