@cendarsoss/pusher-js 8.4.11 → 8.4.13

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,263 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Trident Delta Test</title>
7
+ <style>
8
+ body {
9
+ font-family: monospace;
10
+ max-width: 1200px;
11
+ margin: 0 auto;
12
+ padding: 20px;
13
+ background: #1a1a2e;
14
+ color: #eee;
15
+ }
16
+ .container {
17
+ background: #16213e;
18
+ padding: 20px;
19
+ border-radius: 8px;
20
+ margin-bottom: 20px;
21
+ }
22
+ h1 { color: #00ff88; margin-top: 0; }
23
+ .status {
24
+ padding: 8px 15px;
25
+ border-radius: 4px;
26
+ display: inline-block;
27
+ font-weight: bold;
28
+ }
29
+ .status.connected { background: #00ff88; color: #000; }
30
+ .status.disconnected { background: #ff4757; color: #fff; }
31
+ .status.connecting { background: #ffa502; color: #000; }
32
+ .log {
33
+ background: #0f0f23;
34
+ border: 1px solid #333;
35
+ border-radius: 4px;
36
+ padding: 15px;
37
+ max-height: 500px;
38
+ overflow-y: auto;
39
+ font-size: 12px;
40
+ line-height: 1.4;
41
+ }
42
+ .log-entry { padding: 3px 0; border-bottom: 1px solid #222; }
43
+ .log-time { color: #666; }
44
+ .log-delta { color: #ff6b6b; }
45
+ .log-full { color: #00ff88; }
46
+ .log-error { color: #ff4757; font-weight: bold; }
47
+ .stats {
48
+ display: grid;
49
+ grid-template-columns: repeat(4, 1fr);
50
+ gap: 10px;
51
+ margin: 15px 0;
52
+ }
53
+ .stat-box {
54
+ background: #0f3460;
55
+ padding: 10px;
56
+ border-radius: 4px;
57
+ text-align: center;
58
+ }
59
+ .stat-label { font-size: 10px; color: #888; }
60
+ .stat-value { font-size: 18px; color: #00ff88; font-weight: bold; }
61
+ button {
62
+ background: #00ff88;
63
+ color: #000;
64
+ border: none;
65
+ padding: 10px 20px;
66
+ border-radius: 4px;
67
+ cursor: pointer;
68
+ font-weight: bold;
69
+ margin-right: 10px;
70
+ }
71
+ button:hover { background: #00cc6a; }
72
+ button:disabled { background: #444; color: #888; cursor: not-allowed; }
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <div class="container">
77
+ <h1>Trident Delta Compression Test</h1>
78
+ <p>Channel: <code>trident_swaps_v1-501_9FvUQNw2Y7zSpxyh7BvxVKwx3iNrjwQ5X6XwEFeZpump</code></p>
79
+
80
+ <div style="margin: 15px 0;">
81
+ <button id="connect-btn">Connect</button>
82
+ <button id="disconnect-btn" disabled>Disconnect</button>
83
+ Status: <span id="status" class="status disconnected">Disconnected</span>
84
+ </div>
85
+
86
+ <div class="stats">
87
+ <div class="stat-box">
88
+ <div class="stat-label">Total Messages</div>
89
+ <div class="stat-value" id="total-messages">0</div>
90
+ </div>
91
+ <div class="stat-box">
92
+ <div class="stat-label">Delta Messages</div>
93
+ <div class="stat-value" id="delta-messages">0</div>
94
+ </div>
95
+ <div class="stat-box">
96
+ <div class="stat-label">Full Messages</div>
97
+ <div class="stat-value" id="full-messages">0</div>
98
+ </div>
99
+ <div class="stat-box">
100
+ <div class="stat-label">Bandwidth Saved</div>
101
+ <div class="stat-value" id="bandwidth-saved">0%</div>
102
+ </div>
103
+ </div>
104
+ </div>
105
+
106
+ <div class="container">
107
+ <h2 style="color: #00ff88; margin-top: 0;">Message Log</h2>
108
+ <div id="log" class="log">
109
+ <div class="log-entry">Waiting for connection...</div>
110
+ </div>
111
+ </div>
112
+
113
+ <!-- Fossil Delta Library -->
114
+ <script src="https://cdn.jsdelivr.net/npm/fossil-delta@1.0.2/fossil-delta.min.js"></script>
115
+
116
+ <!-- Pusher JS - use local build -->
117
+ <script type="module">
118
+ import Pusher from '../dist/web/pusher.mjs';
119
+
120
+ const CHANNEL_NAME = 'trident_swaps_v1-501_9FvUQNw2Y7zSpxyh7BvxVKwx3iNrjwQ5X6XwEFeZpump';
121
+ const EVENT_NAME = 'e';
122
+
123
+ let pusher = null;
124
+ let channel = null;
125
+
126
+ const connectBtn = document.getElementById('connect-btn');
127
+ const disconnectBtn = document.getElementById('disconnect-btn');
128
+ const statusEl = document.getElementById('status');
129
+ const logEl = document.getElementById('log');
130
+
131
+ function log(message, type = 'info') {
132
+ const time = new Date().toLocaleTimeString();
133
+ const entry = document.createElement('div');
134
+ entry.className = 'log-entry';
135
+
136
+ let typeClass = '';
137
+ if (type === 'delta') typeClass = 'log-delta';
138
+ if (type === 'full') typeClass = 'log-full';
139
+ if (type === 'error') typeClass = 'log-error';
140
+
141
+ entry.innerHTML = `<span class="log-time">[${time}]</span> <span class="${typeClass}">${message}</span>`;
142
+ logEl.appendChild(entry);
143
+ logEl.scrollTop = logEl.scrollHeight;
144
+ }
145
+
146
+ function updateStats() {
147
+ if (!pusher) return;
148
+ const stats = pusher.getDeltaStats();
149
+ if (!stats) return;
150
+
151
+ document.getElementById('total-messages').textContent = stats.totalMessages;
152
+ document.getElementById('delta-messages').textContent = stats.deltaMessages;
153
+ document.getElementById('full-messages').textContent = stats.fullMessages;
154
+ document.getElementById('bandwidth-saved').textContent = stats.bandwidthSavedPercent.toFixed(1) + '%';
155
+ }
156
+
157
+ function updateStatus(status, text) {
158
+ statusEl.className = `status ${status}`;
159
+ statusEl.textContent = text;
160
+ }
161
+
162
+ function connect() {
163
+ log('Connecting to stream-v2.projectscylla.com...');
164
+ updateStatus('connecting', 'Connecting');
165
+
166
+ pusher = new Pusher('knife-library-likely', {
167
+ cluster: 'a',
168
+ wsHost: 'stream-v2.projectscylla.com',
169
+ wssPort: 443,
170
+ forceTLS: true,
171
+ disableStats: true,
172
+ enabledTransports: ['ws', 'wss'],
173
+ deltaCompression: {
174
+ enabled: true,
175
+ algorithms: ['fossil', 'xdelta3'],
176
+ debug: true,
177
+ onStats: (stats) => {
178
+ console.log('Delta Stats:', stats);
179
+ updateStats();
180
+ },
181
+ onError: (error) => {
182
+ console.error('Delta Error:', error);
183
+ log('DELTA ERROR: ' + JSON.stringify(error), 'error');
184
+ }
185
+ }
186
+ });
187
+
188
+ pusher.connection.bind('connected', () => {
189
+ log('Connected! Socket ID: ' + pusher.connection.socket_id);
190
+ updateStatus('connected', 'Connected');
191
+ connectBtn.disabled = true;
192
+ disconnectBtn.disabled = false;
193
+ subscribe();
194
+ });
195
+
196
+ pusher.connection.bind('disconnected', () => {
197
+ log('Disconnected');
198
+ updateStatus('disconnected', 'Disconnected');
199
+ connectBtn.disabled = false;
200
+ disconnectBtn.disabled = true;
201
+ });
202
+
203
+ pusher.connection.bind('error', (err) => {
204
+ log('Connection error: ' + JSON.stringify(err), 'error');
205
+ console.error('Pusher error:', err);
206
+ });
207
+
208
+ pusher.bind('pusher:delta_compression_enabled', (data) => {
209
+ log('Delta compression enabled: ' + JSON.stringify(data));
210
+ });
211
+ }
212
+
213
+ function subscribe() {
214
+ log('Subscribing to: ' + CHANNEL_NAME);
215
+
216
+ channel = pusher.subscribe(CHANNEL_NAME);
217
+
218
+ channel.bind('pusher:subscription_succeeded', () => {
219
+ log('Subscribed successfully!');
220
+ });
221
+
222
+ channel.bind('pusher:subscription_error', (status) => {
223
+ log('Subscription error: ' + JSON.stringify(status), 'error');
224
+ });
225
+
226
+ channel.bind('pusher:delta_cache_sync', (data) => {
227
+ log('Cache sync received');
228
+ console.log('Cache sync data:', data);
229
+ });
230
+
231
+ channel.bind(EVENT_NAME, (data) => {
232
+ const stats = pusher.getDeltaStats();
233
+ const msgNum = stats ? stats.totalMessages : '?';
234
+
235
+ // Try to extract some info from the data
236
+ let info = '';
237
+ if (data && typeof data === 'object') {
238
+ if (data.token) info = `token: ${data.token.substring(0, 8)}...`;
239
+ else if (data.mint) info = `mint: ${data.mint.substring(0, 8)}...`;
240
+ else info = Object.keys(data).slice(0, 3).join(', ');
241
+ }
242
+
243
+ log(`[#${msgNum}] Event received - ${info}`, 'full');
244
+ console.log('Event data: ' + typeof data, data);
245
+ updateStats();
246
+ });
247
+ }
248
+
249
+ function disconnect() {
250
+ if (pusher) {
251
+ pusher.disconnect();
252
+ pusher = null;
253
+ channel = null;
254
+ }
255
+ }
256
+
257
+ connectBtn.addEventListener('click', connect);
258
+ disconnectBtn.addEventListener('click', disconnect);
259
+
260
+ log('Ready. Click Connect to start.');
261
+ </script>
262
+ </body>
263
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cendarsoss/pusher-js",
3
- "version": "8.4.11",
3
+ "version": "8.4.13",
4
4
  "description": "Pusher Channels JavaScript library for browsers, React Native, NodeJS and web workers",
5
5
  "types": "index.d.ts",
6
6
  "main": "dist/node/pusher.js",
@@ -198,30 +198,43 @@ export default class DeltaCompressionManager {
198
198
  baseMessage = channelState.getBaseMessage(conflationKey, baseIndex);
199
199
  if (!baseMessage) {
200
200
  this.error(
201
- `No base message for channel ${channel}, key ${conflationKey}, index ${baseIndex}`,
202
- );
203
- if (this.options.debug) {
204
- this.log('Current conflation cache snapshot', {
201
+ `No base message (conflation path) for channel ${channel}`,
202
+ {
203
+ path: 'conflation',
205
204
  channel,
206
- conflationKey: channelState.conflationKey,
207
- cacheSizes: Array.from(
205
+ deltaConflationKey: conflationKey,
206
+ deltaBaseIndex: baseIndex,
207
+ deltaSeq: sequence,
208
+ channelStateConflationKey: channelState.conflationKey,
209
+ channelStateBaseMessage: channelState.baseMessage ? 'exists' : null,
210
+ channelStateBaseSequence: channelState.baseSequence,
211
+ channelStateLastSequence: channelState.lastSequence,
212
+ conflationCacheKeys: Array.from(channelState.conflationCaches.keys()),
213
+ conflationCacheSizes: Array.from(
208
214
  channelState.conflationCaches.entries(),
209
215
  ).map(([key, cache]) => ({ key, size: cache.length })),
210
- });
211
- }
216
+ },
217
+ );
212
218
  this.requestResync(channel);
213
219
  return null;
214
220
  }
215
221
  } else {
216
222
  baseMessage = channelState.baseMessage;
217
223
  if (!baseMessage) {
218
- this.error(`No base message for channel ${channel}`);
219
- if (this.options.debug) {
220
- this.log('Channel state missing base', {
224
+ this.error(
225
+ `No base message (legacy path) for channel ${channel}`,
226
+ {
227
+ path: 'legacy',
221
228
  channel,
222
- lastSequence: channelState.lastSequence,
223
- });
224
- }
229
+ deltaConflationKey: conflationKey,
230
+ deltaBaseIndex: baseIndex,
231
+ deltaSeq: sequence,
232
+ channelStateConflationKey: channelState.conflationKey,
233
+ channelStateBaseMessage: null,
234
+ channelStateBaseSequence: channelState.baseSequence,
235
+ channelStateLastSequence: channelState.lastSequence,
236
+ },
237
+ );
225
238
  this.requestResync(channel);
226
239
  return null;
227
240
  }
@@ -284,10 +297,20 @@ export default class DeltaCompressionManager {
284
297
  // Parse and return the reconstructed event
285
298
  try {
286
299
  const parsedMessage = JSON.parse(reconstructedMessage);
300
+ let data = parsedMessage.data || parsedMessage;
301
+ // Try to parse data if it's a string (Pusher protocol double-encodes data)
302
+ // This matches the behavior in protocol.ts decodeMessage
303
+ if (typeof data === 'string') {
304
+ try {
305
+ data = JSON.parse(data);
306
+ } catch (e) {
307
+ // Keep as string if not valid JSON
308
+ }
309
+ }
287
310
  return {
288
311
  event: event,
289
312
  channel: channel,
290
- data: parsedMessage.data || parsedMessage,
313
+ data: data,
291
314
  };
292
315
  } catch (e) {
293
316
  // If not JSON, return as-is